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

📄 cdu31a.c

📁 基于linux1.0内核的linux源码
💻 C
📖 第 1 页 / 共 4 页
字号:
      final_pos_msf[0] = params[4];
      final_pos_msf[1] = params[5];
      final_pos_msf[2] = params[6];
      sony_audio_status = CDROM_AUDIO_PLAY;
      return 0;
      break;

   case CDROMREADTOCHDR:        /* Read the table of contents header */
      {
         struct cdrom_tochdr *hdr;
         struct cdrom_tochdr loc_hdr;
         
         sony_get_toc();
         if (!sony_toc_read)
         {
            return -EIO;
         }
         
         hdr = (struct cdrom_tochdr *) arg;
         verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
         loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
         loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
         memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr));
      }
      return 0;
      break;

   case CDROMREADTOCENTRY:      /* Read a given table of contents entry */
      {
         struct cdrom_tocentry *entry;
         struct cdrom_tocentry loc_entry;
         int track_idx;
         unsigned char *msf_val = NULL;
         
         sony_get_toc();
         if (!sony_toc_read)
         {
            return -EIO;
         }
         
         entry = (struct cdrom_tocentry *) arg;
         verify_area(VERIFY_READ, entry, sizeof(*entry));
         verify_area(VERIFY_WRITE, entry, sizeof(*entry));
         
         memcpy_fromfs(&loc_entry, entry, sizeof(loc_entry));
         
         /* Lead out is handled separately since it is special. */
         if (loc_entry.cdte_track == CDROM_LEADOUT)
         {
            loc_entry.cdte_adr = sony_toc->address2;
            loc_entry.cdte_ctrl = sony_toc->control2;
            msf_val = sony_toc->lead_out_start_msf;
         }
         else
         {
            track_idx = find_track(int_to_bcd(loc_entry.cdte_track));
            if (track_idx < 0)
            {
               return -EINVAL;
            }
            
            loc_entry.cdte_adr = sony_toc->tracks[track_idx].address;
            loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control;
            msf_val = sony_toc->tracks[track_idx].track_start_msf;
         }
         
         /* Logical buffer address or MSF format requested? */
         if (loc_entry.cdte_format == CDROM_LBA)
         {
            loc_entry.cdte_addr.lba = msf_to_log(msf_val);
         }
         else if (loc_entry.cdte_format == CDROM_MSF)
         {
            loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val);
            loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val+1));
            loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val+2));
         }
         memcpy_tofs(entry, &loc_entry, sizeof(*entry));
      }
      return 0;
      break;

   case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
      {
         struct cdrom_ti ti;
         int track_idx;
         
         sony_get_toc();
         if (!sony_toc_read)
         {
            return -EIO;
         }
         
         verify_area(VERIFY_READ, (char *) arg, sizeof(ti));
         
         memcpy_fromfs(&ti, (char *) arg, sizeof(ti));
         if (   (ti.cdti_trk0 < sony_toc->first_track_num)
             || (ti.cdti_trk0 > sony_toc->last_track_num)
             || (ti.cdti_trk1 < ti.cdti_trk0))
         {
            return -EINVAL;
         }
         
         track_idx = find_track(int_to_bcd(ti.cdti_trk0));
         if (track_idx < 0)
         {
            return -EINVAL;
         }
         params[1] = sony_toc->tracks[track_idx].track_start_msf[0];
         params[2] = sony_toc->tracks[track_idx].track_start_msf[1];
         params[3] = sony_toc->tracks[track_idx].track_start_msf[2];
         
         /*
          * If we want to stop after the last track, use the lead-out
          * MSF to do that.
          */
         if (ti.cdti_trk1 >= bcd_to_int(sony_toc->last_track_num))
         {
            log_to_msf(msf_to_log(sony_toc->lead_out_start_msf)-1,
                       &(params[4]));
         }
         else
         {
            track_idx = find_track(int_to_bcd(ti.cdti_trk1+1));
            if (track_idx < 0)
            {
               return -EINVAL;
            }
            log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf)-1,
                       &(params[4]));
         }
         params[0] = 0x03;
         
         do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
         
         do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
         if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
         {
            printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1],
                   params[2], params[3], params[4], params[5], params[6]);
            printk("Sony CDROM error 0x%2.2x (CDROMPLAYTRKIND\n", res_reg[1]);
            return -EIO;
         }
         
         /* Save the final position for pauses and resumes */
         final_pos_msf[0] = params[4];
         final_pos_msf[1] = params[5];
         final_pos_msf[2] = params[6];
         sony_audio_status = CDROM_AUDIO_PLAY;
         return 0;
      }
     
   case CDROMSUBCHNL:   /* Get subchannel info */
      return sony_get_subchnl_info(arg);

   case CDROMVOLCTRL:   /* Volume control.  What volume does this change, anyway? */
      {
         struct cdrom_volctrl volctrl;
         
         verify_area(VERIFY_READ, (char *) arg, sizeof(volctrl));
         
         memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
         params[0] = SONY_SD_AUDIO_VOLUME;
         params[1] = volctrl.channel0;
         params[2] = volctrl.channel1;
         do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, params, 3, res_reg, &res_size);
         if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
         {
            printk("Sony CDROM error 0x%2.2x (CDROMVOLCTRL)\n", res_reg[1]);
            return -EIO;
         }
      }
      return 0;

   case CDROMEJECT:     /* Eject the drive */
      do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
      do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);

      sony_audio_status = CDROM_AUDIO_INVALID;
      do_sony_cd_cmd(SONY_EJECT_CMD, NULL, 0, res_reg, &res_size);
      if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
      {
         printk("Sony CDROM error 0x%2.2x (CDROMEJECT)\n", res_reg[1]);
         return -EIO;
      }
      return 0;
      break;
     
   default:
      return -EINVAL;
   }
}


/*
 * Open the drive for operations.  Spin the drive up and read the table of
 * contents if these have not already been done.
 */
static int
scd_open(struct inode *inode,
         struct file *filp)
{
   unsigned char res_reg[2];
   unsigned int res_size;
   int num_spin_ups;


   if (!sony_spun_up)
   {
      num_spin_ups = 0;

respinup_on_open:
      do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);

      /* The drive sometimes returns error 0.  I don't know why, but ignore
         it.  It seems to mean the drive has already done the operation. */
      if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
      {
         printk("Sony CDROM error 0x%2.2x (scd_open, spin up)\n", res_reg[1]);
         return -EIO;
      }
      
      do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);

      /* The drive sometimes returns error 0.  I don't know why, but ignore
         it.  It seems to mean the drive has already done the operation. */
      if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
      {
         /* If the drive is already playing, its ok.  */
         if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) || (res_reg[1] == 0))
         {
            goto drive_spinning;
         }

         /* If the drive says it is not spun up (even though we just did it!)
            then retry the operation at least a few times. */
         if (   (res_reg[1] == SONY_NOT_SPIN_ERR)
             && (num_spin_ups < MAX_CDU31A_RETRIES))
         {
            num_spin_ups++;
            goto respinup_on_open;
         }

         printk("Sony CDROM error 0x%2.2x (scd_open, read toc)\n", res_reg[1]);
         do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
         
         return -EIO;
      }

      sony_get_toc();
      if (!sony_toc_read)
      {
         do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
         return -EIO;
      }

      sony_spun_up = 1;
   }

drive_spinning:

   if (inode)
   {
      check_disk_change(inode->i_rdev);
   }

   sony_usage++;

   return 0;
}


/*
 * Close the drive.  Spin it down if no task is using it.  The spin
 * down will fail if playing audio, so audio play is OK.
 */
static void
scd_release(struct inode *inode,
         struct file *filp)
{
   unsigned char res_reg[2];
   unsigned int  res_size;


   if (sony_usage > 0)
   {
      sony_usage--;
   }
   if (sony_usage == 0)
   {
      sync_dev(inode->i_rdev);
      do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);

      sony_spun_up = 0;
   }
}


static struct file_operations scd_fops = {
   NULL,                   /* lseek - default */
   block_read,             /* read - general block-dev read */
   block_write,            /* write - general block-dev write */
   NULL,                   /* readdir - bad */
   NULL,                   /* select */
   scd_ioctl,              /* ioctl */
   NULL,                   /* mmap */
   scd_open,               /* open */
   scd_release,            /* release */
   NULL                    /* fsync */
};


/* The different types of disc loading mechanisms supported */
static char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };

/* Read-ahead buffer sizes for different drives.  These are just arbitrary
   values, I don't know what is really optimum. */
static unsigned int mem_size[] = { 16384, 16384, 16384, 2048 };

void
get_drive_configuration(unsigned short base_io,
                        unsigned char res_reg[],
                        unsigned int *res_size)
{
   int retry_count;


   /* Set the base address */
   sony_cd_base_io = base_io;

   /* Set up all the register locations */
   sony_cd_cmd_reg = sony_cd_base_io + SONY_CMD_REG_OFFSET;
   sony_cd_param_reg = sony_cd_base_io + SONY_PARAM_REG_OFFSET;
   sony_cd_write_reg = sony_cd_base_io + SONY_WRITE_REG_OFFSET;
   sony_cd_control_reg = sony_cd_base_io + SONY_CONTROL_REG_OFFSET;
   sony_cd_status_reg = sony_cd_base_io + SONY_STATUS_REG_OFFSET;
   sony_cd_result_reg = sony_cd_base_io + SONY_RESULT_REG_OFFSET;
   sony_cd_read_reg = sony_cd_base_io + SONY_READ_REG_OFFSET;
   sony_cd_fifost_reg = sony_cd_base_io + SONY_FIFOST_REG_OFFSET;

   /*
    * Check to see if anything exists at the status register location.
    * I don't know if this is a good way to check, but it seems to work
    * ok for me.
    */
   if (read_status_register() != 0xff)
   {
      /*
       * Reset the drive and wait for attention from it (to say its reset).
       * If you don't wait, the next operation will probably fail.
       */
      reset_drive();
      retry_count = jiffies + SONY_RESET_TIMEOUT;
      while ((retry_count > jiffies) && (!is_attention()))
      {
         sony_sleep();
      }

      /* If attention is never seen probably not a CDU31a present */
      if (!is_attention())
      {
         res_reg[0] = 0x20;
         return;
      }

      /*
       * Get the drive configuration.
       */
      do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD,
                     NULL,
                     0,
                     (unsigned char *) res_reg,
                     res_size);
      return;
   }

   /* Return an error */
   res_reg[0] = 0x20;
}


/*
 * Initialize the driver.
 */
unsigned long
cdu31a_init(unsigned long mem_start, unsigned long mem_end)
{
   struct s_sony_drive_config drive_config;
   unsigned int res_size;
   int i;
   int drive_found;


   /*
    * According to Alex Freed (freed@europa.orion.adobe.com), this is
    * required for the Fusion CD-16 package.  If the sound driver is
    * loaded, it should work fine, but just in case...
    *
    * The following turn on the CD-ROM interface for a Fusion CD-16.
    */
   outb(0xbc, 0x9a01);
   outb(0xe2, 0x9a01);

   i = 0;
   drive_found = 0;
   while (   (cdu31a_addresses[i] != 0)
          && (!drive_found))
   {
      if (check_region(cdu31a_addresses[i], 4)) {
	  i++;
	  continue;
      }
      get_drive_configuration(cdu31a_addresses[i],
                               drive_config.exec_status,
                               &res_size);
      if ((res_size > 2) && ((drive_config.exec_status[0] & 0x20) == 0x00))
      {
         drive_found = 1;
	 snarf_region(cdu31a_addresses[i], 4);

         if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
         {
            printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
            return mem_start;
         }

         sony_buffer_size = mem_size[SONY_HWC_GET_BUF_MEM_SIZE(drive_config)];
         sony_buffer_sectors = sony_buffer_size / 2048;

         printk("Sony I/F CDROM : %8.8s %16.16s %8.8s with %s load mechanism\n",
                drive_config.vendor_id,
                drive_config.product_id,
                drive_config.product_rev_level,
                load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
         printk("  using %d byte buffer", sony_buffer_size);
         if (SONY_HWC_AUDIO_PLAYBACK(drive_config))
         {
            printk(", capable of audio playback");
         }
         printk("\n");

         set_drive_params();

         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
         read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */

         sony_toc = (struct s_sony_toc *) mem_start;
         mem_start += sizeof(*sony_toc);
         last_sony_subcode = (struct s_sony_subcode *) mem_start;
         mem_start += sizeof(*last_sony_subcode);
         sony_buffer = (unsigned char *) mem_start;
         mem_start += sony_buffer_size;
      }

      i++;
   }
   
   return mem_start;
}

⌨️ 快捷键说明

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