📄 cdu31a.c
字号:
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 intscd_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 voidscd_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 };voidget_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 longcdu31a_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 + -