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

📄 cdu31a.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 4 页
字号:
{   log = log + LOG_START_OFFSET;   msf[0] = int_to_bcd(log / 4500);   log = log % 4500;   msf[1] = int_to_bcd(log / 75);   msf[2] = int_to_bcd(log % 75);}/* * Convert an MSF format to a logical sector. */static unsigned intmsf_to_log(unsigned char *msf){   unsigned int log;   log = bcd_to_int(msf[2]);   log += bcd_to_int(msf[1]) * 75;   log += bcd_to_int(msf[0]) * 4500;   log = log - LOG_START_OFFSET;   return log;}/* * Take in integer size value and put it into a buffer like * the drive would want to see a number-of-sector value. */static voidsize_to_buf(unsigned int size,            unsigned char *buf){   buf[0] = size / 65536;   size = size % 65536;   buf[1] = size / 256;   buf[2] = size % 256;}/* * 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;   unsigned int dev;   int nsect;   unsigned char params[10];   unsigned char res_reg[2];   unsigned int res_size;   int copyoff;   int spin_up_retry;   unsigned int read_size;   if (!sony_spun_up)   {      scd_open (NULL,NULL);   }   while (1)   {cdu31a_request_startover:      /*       * The beginning here is stolen from the hard disk driver.  I hope       * its right.       */      if (!(CURRENT) || CURRENT->dev < 0)      {         return;      }      INIT_REQUEST;      dev = MINOR(CURRENT->dev);      block = CURRENT->sector;      nsect = CURRENT->nr_sectors;      if (dev != 0)      {         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 ((block / 4) >= sony_toc->lead_out_start_lba)         {            end_request(0);            goto cdu31a_request_startover;         }         if (((block + nsect) / 4) >= sony_toc->lead_out_start_lba)         {            end_request(0);            goto cdu31a_request_startover;         }         while (nsect > 0)         {            /*             * If the requested sector is not currently in the read-ahead buffer,             * it must be read in.             */            if ((block < sony_first_block) || (block > sony_last_block))            {               sony_first_block = (block / 4) * 4;               log_to_msf(block/4, params);               /*                * If the full read-ahead would go beyond the end of the media, trim                * it back to read just till the end of the media.                */               if (((block / 4) + sony_buffer_sectors) >= sony_toc->lead_out_start_lba)               {                  read_size = sony_toc->lead_out_start_lba - (block / 4);               }               else               {                  read_size = sony_buffer_sectors;               }               size_to_buf(read_size, &params[3]);               /*                * Read the data.  If the drive was not spinning, spin it up and try                * once more.  I know, the goto is ugly, but I am too lazy to fix it.                */               spin_up_retry = 0;try_read_again:               sony_last_block =   sony_first_block                                 + (get_data(sony_buffer,                                             params,                                             (read_size * 2048),                                             res_reg,                                             &res_size) * 4) - 1;               if ((res_size < 2) || (res_reg[0] != 0))               {                  if ((res_reg[1] == SONY_NOT_SPIN_ERR) && (!spin_up_retry))                  {                     do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);                     spin_up_retry = 1;                     goto try_read_again;                  }                  printk("Sony CDROM Read error: 0x%2.2x\n", res_reg[1]);                  sony_first_block = -1;                  sony_last_block = -1;                  end_request(0);                  goto cdu31a_request_startover;               }            }               /*             * The data is in memory now, copy it to the buffer and advance to the             * next block to read.             */            copyoff = (block - sony_first_block) * 512;            memcpy(CURRENT->buffer, sony_buffer+copyoff, 512);                           block += 1;            nsect -= 1;            CURRENT->buffer += 512;         }                        end_request(1);         break;                  case WRITE:         end_request(0);         break;                  default:         panic("Unkown SONY CD cmd");      }   }}/* * Read the table of contents from the drive and set sony_toc_read if * successful. */static voidsony_get_toc(void){   unsigned int res_size;   if (!sony_toc_read)   {      do_sony_cd_cmd(SONY_REQ_TOC_DATA_CMD,                     NULL,                     0,                      (unsigned char *) sony_toc,                      &res_size);      if ((res_size < 2) || ((sony_toc->exec_status[0] & 0x20) == 0x20))      {         return;      }      sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf);      sony_toc_read = 1;   }}/* * Search for a specific track in the table of contents. */static intfind_track(int track){   int i;   int num_tracks;   num_tracks = sony_toc->last_track_num + sony_toc->first_track_num + 1;   for (i = 0; i < num_tracks; i++)   {      if (sony_toc->tracks[i].track == track)      {         return i;      }   }   return -1;}/* * Read the subcode and put it int last_sony_subcode for future use. */static intread_subcode(void){   unsigned int res_size;   do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD,                  NULL,                  0,                   (unsigned char *) last_sony_subcode,                   &res_size);   if ((res_size < 2) || ((last_sony_subcode->exec_status[0] & 0x20) == 0x20))   {      printk("Sony CDROM error 0x%2.2x (read_subcode)\n",             last_sony_subcode->exec_status[1]);      return -EIO;   }   return 0;}/* * Get the subchannel info like the CDROMSUBCHNL command wants to see it.  If * the drive is playing, the subchannel needs to be read (since it would be * changing).  If the drive is paused or completed, the subcode information has * already been stored, just use that.  The ioctl call wants things in decimal * (not BCD), so all the conversions are done. */static intsony_get_subchnl_info(long arg){   struct cdrom_subchnl schi;   /* Get attention stuff */   while (handle_sony_cd_attention())      ;   sony_get_toc();   if (!sony_toc_read)   {      return -EIO;   }   verify_area(VERIFY_READ, (char *) arg, sizeof(schi));   verify_area(VERIFY_WRITE, (char *) arg, sizeof(schi));   memcpy_fromfs(&schi, (char *) arg, sizeof(schi));      switch (sony_audio_status)   {   case CDROM_AUDIO_PLAY:      if (read_subcode() < 0)      {         return -EIO;      }      break;   case CDROM_AUDIO_PAUSED:   case CDROM_AUDIO_COMPLETED:      break;   case CDROM_AUDIO_NO_STATUS:      schi.cdsc_audiostatus = sony_audio_status;      memcpy_tofs((char *) arg, &schi, sizeof(schi));      return 0;      break;   case CDROM_AUDIO_INVALID:   case CDROM_AUDIO_ERROR:   default:      return -EIO;   }   schi.cdsc_audiostatus = sony_audio_status;   schi.cdsc_adr = last_sony_subcode->address;   schi.cdsc_ctrl = last_sony_subcode->control;   schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num);   schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num);   if (schi.cdsc_format == CDROM_MSF)   {      schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]);      schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]);      schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]);      schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]);      schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]);      schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]);   }   else if (schi.cdsc_format == CDROM_LBA)   {      schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);      schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);   }      memcpy_tofs((char *) arg, &schi, sizeof(schi));   return 0;}/* * The big ugly ioctl handler. */static intscd_ioctl(struct inode *inode,          struct file  *file,          unsigned int  cmd,          unsigned long arg){   unsigned int dev;   unsigned char res_reg[2];   unsigned int res_size;   unsigned char params[7];   int i;   if (!inode)   {      return -EINVAL;   }   dev = MINOR(inode->i_rdev) >> 6;   if (dev != 0)   {      return -EINVAL;   }   switch (cmd)   {   case CDROMSTART:     /* Spin up the drive */      do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);      if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))      {         printk("Sony CDROM error 0x%2.2x (CDROMSTART)\n", res_reg[1]);         return -EIO;      }      return 0;      break;         case CDROMSTOP:      /* Spin down the drive */      do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);      /*       * Spin the drive down, ignoring the error if the disk was       * already not spinning.       */      sony_audio_status = CDROM_AUDIO_NO_STATUS;      do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);      if (   ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))          && (res_reg[1] != SONY_NOT_SPIN_ERR))      {         printk("Sony CDROM error 0x%2.2x (CDROMSTOP)\n", res_reg[1]);         return -EIO;      }            return 0;      break;   case CDROMPAUSE:     /* Pause the drive */      do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);      if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))      {         printk("Sony CDROM error 0x%2.2x (CDROMPAUSE)\n", res_reg[1]);         return -EIO;      }      /* Get the current position and save it for resuming */      if (read_subcode() < 0)      {         return -EIO;      }      cur_pos_msf[0] = last_sony_subcode->abs_msf[0];      cur_pos_msf[1] = last_sony_subcode->abs_msf[1];      cur_pos_msf[2] = last_sony_subcode->abs_msf[2];      sony_audio_status = CDROM_AUDIO_PAUSED;      return 0;      break;   case CDROMRESUME:    /* Start the drive after being paused */      if (sony_audio_status != CDROM_AUDIO_PAUSED)      {         return -EINVAL;      }            do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);            /* Start the drive at the saved position. */      params[1] = cur_pos_msf[0];      params[2] = cur_pos_msf[1];      params[3] = cur_pos_msf[2];      params[4] = final_pos_msf[0];      params[5] = final_pos_msf[1];      params[6] = final_pos_msf[2];      params[0] = 0x03;      do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);      if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))      {         printk("Sony CDROM error 0x%2.2x (CDROMRESUME)\n", res_reg[1]);         return -EIO;      }      sony_audio_status = CDROM_AUDIO_PLAY;      return 0;      break;   case CDROMPLAYMSF:   /* Play starting at the given MSF address. */      verify_area(VERIFY_READ, (char *) arg, 6);      do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);      memcpy_fromfs(&(params[1]), (void *) arg, 6);            /* The parameters are given in int, must be converted */      for (i=1; i<7; i++)      {         params[i] = int_to_bcd(params[i]);      }      params[0] = 0x03;      do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);      if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))      {         printk("Sony CDROM error 0x%2.2x (CDROMPLAYMSF)\n", res_reg[1]);         return -EIO;      }            /* Save the final position for pauses and resumes */

⌨️ 快捷键说明

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