⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdu31a.c

📁 powerpc内核 mpc8241芯片 linux系统下cdrom驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
   clear_data_ready();   if (bytesleft == 2048) /* 2048 byte direct buffer transfer */   {      insb(sony_cd_read_reg, buffer, 2048);      readahead_dataleft = 0;   }   else   {      /* If the input read did not align with the beginning of the block,	 skip the necessary bytes. */      if (skip != 0)      {         insb(sony_cd_read_reg, readahead_buffer, skip);      }      /* Get the data into the buffer. */      insb(sony_cd_read_reg, &buffer[offset], bytesleft);      /* Get the rest of the data into the readahead buffer at the	 proper location. */      readahead_dataleft = (2048 - skip) - bytesleft;      insb(sony_cd_read_reg,           readahead_buffer + bytesleft,           readahead_dataleft);   }   sony_blocks_left -= nblocks;   sony_next_block += nblocks;    /* If an XA disk, we have to clear out the rest of the unused      error correction data. */   if (sony_xa_mode)   {      for(i=0; i<CD_XA_TAIL; i++)      {         val = read_data_register();      }   }#if DEBUG   printk("Leaving input_data at %d\n", __LINE__);#endif}/* read data from the drive.  Note the nsect must be <= 4. */static voidread_data_block(char          *buffer,                unsigned int  block,                unsigned int  nblocks,                unsigned char res_reg[],                int           *res_size){   unsigned int retry_count;   unsigned int bytesleft;   unsigned int offset;   unsigned int skip;#if DEBUG   printk("Entering read_data_block\n");#endif   res_reg[0] = 0;   res_reg[1] = 0;   *res_size = 0;   bytesleft = nblocks * 512;   offset = 0;   /* If the data in the read-ahead does not match the block offset,      then fix things up. */   if (((block % 4) * 512) != ((2048 - readahead_dataleft) % 2048))   {      sony_next_block += block % 4;      sony_blocks_left -= block % 4;      skip = (block % 4) * 512;   }   else   {      skip = 0;   }   /* We have readahead data in the buffer, get that first before we      decide if a read is necessary. */   if (readahead_dataleft != 0)   {      if (bytesleft > readahead_dataleft)      {	 /* The readahead will not fill the requested buffer, but	    get the data out of the readahead into the buffer. */         memcpy(buffer,                readahead_buffer + (2048 - readahead_dataleft),                readahead_dataleft);         readahead_dataleft = 0;         bytesleft -= readahead_dataleft;         offset += readahead_dataleft;      }      else      {	 /* The readahead will fill the whole buffer, get the data	    and return. */         memcpy(buffer,                readahead_buffer + (2048 - readahead_dataleft),                bytesleft);         readahead_dataleft -= bytesleft;         bytesleft = 0;         sony_blocks_left -= nblocks;         sony_next_block += nblocks;	 /* If the data in the readahead is bad, return an error so the	    driver will abort the buffer. */         if (readahead_bad)         {            res_reg[0] = 0x20;            res_reg[1] = SONY_BAD_DATA_ERR;            *res_size = 2;         }         if (readahead_dataleft == 0)         {            readahead_bad = 0;         }         /* Final transfer is done for read command, get final result. */         if (sony_blocks_left == 0)         {            get_result(res_reg, res_size);         }#if DEBUG         printk("Leaving read_data_block at %d\n", __LINE__);#endif         return;      }   }   /* Wait for the drive to tell us we have something */   retry_count = jiffies + SONY_JIFFIES_TIMEOUT;   while (time_before(jiffies, retry_count) && !(is_data_ready()))   {      while (handle_sony_cd_attention())         ;      sony_sleep();   }   if (!(is_data_ready()))   {      if (is_result_ready())      {         get_result(res_reg, res_size);         if ((res_reg[0] & 0xf0) != 0x20)         {            printk("CDU31A: Got result that should have been error: %d\n",                   res_reg[0]);            res_reg[0] = 0x20;            res_reg[1] = SONY_BAD_DATA_ERR;            *res_size = 2;         }         abort_read();      }      else      {#if DEBUG         printk("CDU31A timeout out %d\n", __LINE__);#endif         res_reg[0] = 0x20;         res_reg[1] = SONY_TIMEOUT_OP_ERR;         *res_size = 2;         abort_read();      }   }   else   {      input_data(buffer, bytesleft, nblocks, offset, skip);      /* Wait for the status from the drive. */      retry_count = jiffies + SONY_JIFFIES_TIMEOUT;      while (time_before(jiffies, retry_count) && !(is_result_ready()))      {         while (handle_sony_cd_attention())            ;         sony_sleep();      }      if (!is_result_ready())      {#if DEBUG         printk("CDU31A timeout out %d\n", __LINE__);#endif         res_reg[0] = 0x20;         res_reg[1] = SONY_TIMEOUT_OP_ERR;         *res_size = 2;         abort_read();      }      else      {         get_result(res_reg, res_size);	 /* If we got a buffer status, handle that. */         if ((res_reg[0] & 0xf0) == 0x50)         {            if (   (res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT)                || (res_reg[0] == SONY_NO_LECC_ERR_BLK_STAT)                || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT))            {	       /* The data was successful, but if data was read from		  the readahead  and it was bad, set the whole		  buffer as bad. */               if (readahead_bad)               {                  readahead_bad = 0;                  res_reg[0] = 0x20;                  res_reg[1] = SONY_BAD_DATA_ERR;                  *res_size = 2;               }            }            else            {               printk("CDU31A: Data block error: 0x%x\n", res_reg[0]);               res_reg[0] = 0x20;               res_reg[1] = SONY_BAD_DATA_ERR;               *res_size = 2;               /* Data is in the readahead buffer but an error was returned.                  Make sure future requests don't use the data. */               if (bytesleft != 2048)               {                  readahead_bad = 1;               }            }            /* Final transfer is done for read command, get final result. */            if (sony_blocks_left == 0)            {               get_result(res_reg, res_size);            }         }         else if ((res_reg[0] & 0xf0) != 0x20)         {            /* The drive gave me bad status, I don't know what to do.               Reset the driver and return an error. */            printk("CDU31A: Invalid block status: 0x%x\n", res_reg[0]);            restart_on_error();            res_reg[0] = 0x20;            res_reg[1] = SONY_BAD_DATA_ERR;            *res_size = 2;         }      }   }#if DEBUG   printk("Leaving read_data_block at %d\n", __LINE__);#endif}/* * The OS calls this to perform a read or write operation to the drive. * Write obviously fail.  Reads to a read ahead of sony_buffer_size * bytes to help speed operations.  This especially helps since the OS * uses 1024 byte blocks and the drive uses 2048 byte blocks.  Since most * data access on a CD is done sequentially, this saves a lot of operations. */static voiddo_cdu31a_request(void){   int block;   int nblock;   unsigned char res_reg[12];   unsigned int res_size;   int num_retries;   unsigned long flags;#if DEBUG         printk("Entering do_cdu31a_request\n");#endif   /*     * Make sure no one else is using the driver; wait for them    * to finish if it is so.    */   save_flags(flags);   cli();   while (sony_inuse)   {      interruptible_sleep_on(&sony_wait);      if (signal_pending(current))      {         restore_flags(flags);         if (CURRENT && CURRENT->rq_status != RQ_INACTIVE)         {            end_request(0);         }         restore_flags(flags);#if DEBUG         printk("Leaving do_cdu31a_request at %d\n", __LINE__);#endif         return;      }   }   sony_inuse = 1;   has_cd_task = current;   /* Get drive status before doing anything. */   while (handle_sony_cd_attention())      ;   /* Make sure we have a valid TOC. */   sony_get_toc();    spin_unlock_irq(&io_request_lock);   /* Make sure the timer is cancelled. */   del_timer(&cdu31a_abort_timer);   while (1)   {cdu31a_request_startover:      /*       * The beginning here is stolen from the hard disk driver.  I hope       * it's right.       */      if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE)      {         goto end_do_cdu31a_request;      }      if (!sony_spun_up)      {         scd_spinup();      }      /* I don't use INIT_REQUEST because it calls return, which would         return without unlocking the device.  It shouldn't matter,         but just to be safe... */      if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)      {	 panic(DEVICE_NAME ": request list destroyed");      }      if (CURRENT->bh)      {	 if (!buffer_locked(CURRENT->bh))         {	    panic(DEVICE_NAME ": block not locked");         }      }      block = CURRENT->sector;      nblock = CURRENT->nr_sectors;      if (!sony_toc_read)      {	 printk("CDU31A: TOC not read\n");	 end_request(0);	 goto cdu31a_request_startover;      }      switch(CURRENT->cmd)      {      case READ:         /*          * If the block address is invalid or the request goes beyond the end of          * the media, return an error.          */#if 0	 if ((block / 4) < sony_toc.start_track_lba)	 {            printk("CDU31A: Request before beginning of media\n");            end_request(0);            goto cdu31a_request_startover;	 }#endif         if ((block / 4) >= sony_toc.lead_out_start_lba)         {            printk("CDU31A: Request past end of media\n");            end_request(0);            goto cdu31a_request_startover;         }         if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba)         {            printk("CDU31A: Request past end of media\n");            end_request(0);            goto cdu31a_request_startover;         }         num_retries = 0;try_read_again:         while (handle_sony_cd_attention())            ;         if (!sony_toc_read)         {	    printk("CDU31A: TOC not read\n");	    end_request(0);	    goto cdu31a_request_startover;         }	 /* If no data is left to be read from the drive, start the	    next request. */         if (sony_blocks_left == 0)         {            if (start_request(block / 4, CDU31A_READAHEAD / 4, 0))            {               end_request(0);               goto cdu31a_request_startover;            }         }	 /* If the requested block is not the next one waiting in	    the driver, abort the current operation and start a	    new one. */         else if (block != sony_next_block)         {#if DEBUG            printk("CDU31A Warning: Read for block %d, expected %d\n",                   block,                   sony_next_block);#endif            abort_read();            if (!sony_toc_read)            {	       printk("CDU31A: TOC not read\n");	       end_request(0);               goto cdu31a_request_startover;            }            if (start_request(block / 4, CDU31A_READAHEAD / 4, 0))            {               printk("CDU31a: start request failed\n");               end_request(0);               goto cdu31a_request_startover;            }         }         read_data_block(CURRENT->buffer, block, nblock, res_reg, &res_size);         if (res_reg[0] == 0x20)         {            if (num_retries > MAX_CDU31A_RETRIES)            {               end_request(0);               goto cdu31a_request_startover;            }            num_retries++;            if (res_reg[1] == SONY_NOT_SPIN_ERR)            {               do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);            }            else            {               printk("CDU31A: %s error for block %d, nblock %d\n", translate_error(res_reg[1]), block, nblock);            }            goto try_read_again;         }         else         {            end_request(1);         }         break;                  case WRITE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -