📄 cdu31a.c
字号:
/* For points that do not exist, move the data over them to the right location. */ if (single_toc.pointb0 != 0xb0) { memmove(((char *) &single_toc) + 27, ((char *) &single_toc) + 18, res_size - 18); res_size += 9; } else if (res_size > 18) { sony_toc.lead_out_start_msf[0] = bcd_to_int(single_toc. max_start_outer_leadout_msf [0]); sony_toc.lead_out_start_msf[1] = bcd_to_int(single_toc. max_start_outer_leadout_msf [1]); sony_toc.lead_out_start_msf[2] = bcd_to_int(single_toc. max_start_outer_leadout_msf [2]); sony_toc.lead_out_start_lba = msf_to_log(sony_toc. lead_out_start_msf); } if (single_toc.pointb1 != 0xb1) { memmove(((char *) &single_toc) + 36, ((char *) &single_toc) + 27, res_size - 27); res_size += 9; } if (single_toc.pointb2 != 0xb2) { memmove(((char *) &single_toc) + 45, ((char *) &single_toc) + 36, res_size - 36); res_size += 9; } if (single_toc.pointb3 != 0xb3) { memmove(((char *) &single_toc) + 54, ((char *) &single_toc) + 45, res_size - 45); res_size += 9; } if (single_toc.pointb4 != 0xb4) { memmove(((char *) &single_toc) + 63, ((char *) &single_toc) + 54, res_size - 54); res_size += 9; } if (single_toc.pointc0 != 0xc0) { memmove(((char *) &single_toc) + 72, ((char *) &single_toc) + 63, res_size - 63); res_size += 9; }#if DEBUG printk ("start track lba %u, leadout start lba %u\n", single_toc.start_track_lba, single_toc.lead_out_start_lba); { int i; for (i = 0; i < 1 + bcd_to_int(single_toc.last_track_num) - bcd_to_int(single_toc. first_track_num); i++) { printk ("trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n", i, single_toc.tracks[i].address, single_toc.tracks[i].control, bcd_to_int(single_toc. tracks[i].track), bcd_to_int(single_toc. tracks[i]. track_start_msf [0]), bcd_to_int(single_toc. tracks[i]. track_start_msf [1]), bcd_to_int(single_toc. tracks[i]. track_start_msf [2])); if (mint > bcd_to_int(single_toc. tracks[i].track)) mint = bcd_to_int(single_toc. tracks[i]. track); if (maxt < bcd_to_int(single_toc. tracks[i].track)) maxt = bcd_to_int(single_toc. tracks[i]. track); } printk ("min track number %d, max track number %d\n", mint, maxt); }#endif /* prepare a special table of contents for a CD-I disc. They don't have one. */ if (single_toc.disk_type == 0x10 && single_toc.first_track_num == 2 && single_toc.last_track_num == 2 /* CD-I */ ) { sony_toc.tracks[totaltracks].address = 1; sony_toc.tracks[totaltracks].control = 4; /* force data tracks */ sony_toc.tracks[totaltracks].track = 1; sony_toc.tracks[totaltracks]. track_start_msf[0] = 0; sony_toc.tracks[totaltracks]. track_start_msf[1] = 2; sony_toc.tracks[totaltracks]. track_start_msf[2] = 0; mint = maxt = 1; totaltracks++; } else /* gather track entries from this session */ { int i; for (i = 0; i < 1 + bcd_to_int(single_toc.last_track_num) - bcd_to_int(single_toc. first_track_num); i++, totaltracks++) { sony_toc.tracks[totaltracks]. address = single_toc.tracks[i].address; sony_toc.tracks[totaltracks]. control = single_toc.tracks[i].control; sony_toc.tracks[totaltracks]. track = bcd_to_int(single_toc. tracks[i].track); sony_toc.tracks[totaltracks]. track_start_msf[0] = bcd_to_int(single_toc. tracks[i]. track_start_msf[0]); sony_toc.tracks[totaltracks]. track_start_msf[1] = bcd_to_int(single_toc. tracks[i]. track_start_msf[1]); sony_toc.tracks[totaltracks]. track_start_msf[2] = bcd_to_int(single_toc. tracks[i]. track_start_msf[2]); if (i == 0) single_toc. start_track_lba = msf_to_log(sony_toc. tracks [totaltracks]. track_start_msf); if (mint > sony_toc.tracks[totaltracks]. track) mint = sony_toc. tracks[totaltracks]. track; if (maxt < sony_toc.tracks[totaltracks]. track) maxt = sony_toc. tracks[totaltracks]. track; } } sony_toc.first_track_num = mint; sony_toc.last_track_num = maxt; /* Disk type of last session wins. For example: CD-Extra has disk type 0 for the first session, so a dumb HiFi CD player thinks it is a plain audio CD. We are interested in the disk type of the last session, which is 0x20 (XA) for CD-Extra, so we can access the data track ... */ sony_toc.disk_type = single_toc.disk_type; sony_toc.sessions = session; /* don't believe everything :-) */ if (session == 1) single_toc.start_track_lba = 0; sony_toc.start_track_lba = single_toc.start_track_lba; if (session > 1 && single_toc.pointb0 == 0xb0 && sony_toc.lead_out_start_lba == single_toc.lead_out_start_lba) { break; } /* Let's not get carried away... */ if (session > 40) { printk("cdu31a: too many sessions: %d\n", session); break; } session++; } sony_toc.track_entries = totaltracks; /* add one entry for the LAST track with track number CDROM_LEADOUT */ sony_toc.tracks[totaltracks].address = single_toc.address2; sony_toc.tracks[totaltracks].control = single_toc.control2; sony_toc.tracks[totaltracks].track = CDROM_LEADOUT; sony_toc.tracks[totaltracks].track_start_msf[0] = sony_toc.lead_out_start_msf[0]; sony_toc.tracks[totaltracks].track_start_msf[1] = sony_toc.lead_out_start_msf[1]; sony_toc.tracks[totaltracks].track_start_msf[2] = sony_toc.lead_out_start_msf[2]; sony_toc_read = 1;#undef DEBUG#if DEBUG printk ("Disk session %d, start track: %d, stop track: %d\n", session, single_toc.start_track_lba, single_toc.lead_out_start_lba);#endif }#if DEBUG printk("Leaving sony_get_toc\n");#endif}/* * Uniform cdrom interface function * return multisession offset and sector information */static int scd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info){ if (ms_info == NULL) return 1; if (!sony_toc_read) sony_get_toc(); ms_info->addr_format = CDROM_LBA; ms_info->addr.lba = sony_toc.start_track_lba; ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE || sony_toc.disk_type == 0x10 /* CDI */ ; return 0;}/* * Search for a specific track in the table of contents. */static int find_track(int track){ int i; for (i = 0; i <= sony_toc.track_entries; i++) { if (sony_toc.tracks[i].track == track) { return i; } } return -1;}/* * Read the subcode and put it in last_sony_subcode for future use. */static int read_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] & 0xf0) == 0x20)) { printk("Sony CDROM error %s (read_subcode)\n", translate_error(last_sony_subcode.exec_status[1])); return -EIO; } last_sony_subcode.track_num = bcd_to_int(last_sony_subcode.track_num); last_sony_subcode.index_num = bcd_to_int(last_sony_subcode.index_num); last_sony_subcode.abs_msf[0] = bcd_to_int(last_sony_subcode.abs_msf[0]); last_sony_subcode.abs_msf[1] = bcd_to_int(last_sony_subcode.abs_msf[1]); last_sony_subcode.abs_msf[2] = bcd_to_int(last_sony_subcode.abs_msf[2]); last_sony_subcode.rel_msf[0] = bcd_to_int(last_sony_subcode.rel_msf[0]); last_sony_subcode.rel_msf[1] = bcd_to_int(last_sony_subcode.rel_msf[1]); last_sony_subcode.rel_msf[2] = bcd_to_int(last_sony_subcode.rel_msf[2]); return 0;}/* * Uniform cdrom interface function * return the media catalog number found on some older audio cds */static intscd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn){ unsigned char resbuffer[2 + 14]; unsigned char *mcnp = mcn->medium_catalog_number; unsigned char *resp = resbuffer + 3; unsigned int res_size; memset(mcn->medium_catalog_number, 0, 14); do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD, NULL, 0, resbuffer, &res_size); if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20)); else { /* packed bcd to single ASCII digits */ *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; *mcnp++ = (*resp++ & 0x0f) + '0'; *mcnp++ = (*resp >> 4) + '0'; } *mcnp = '\0'; 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 int sony_get_subchnl_info(struct cdrom_subchnl *schi){ /* Get attention stuff */ while (handle_sony_cd_attention()); sony_get_toc(); if (!sony_toc_read) { return -EIO; } switch (sony_audio_status) { case CDROM_AUDIO_NO_STATUS: case CDROM_AUDIO_PLAY: if (read_subcode() < 0) { return -EIO; } break; case CDROM_AUDIO_PAUSED: case CDROM_AUDIO_COMPLETED: break;#if 0 case CDROM_AUDIO_NO_STATUS: schi->cdsc_audiostatus = sony_audio_status; return 0; break;#endif 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 = last_sony_subcode.track_num; schi->cdsc_ind = last_sony_subcode.index_num; if (schi->cdsc_format == CDROM_MSF) { schi->cdsc_absaddr.msf.minute = last_sony_subcode.abs_msf[0]; schi->cdsc_absaddr.msf.second = last_sony_subcode.abs_msf[1]; schi->cdsc_absaddr.msf.frame = last_sony_subcode.abs_msf[2]; schi->cdsc_reladdr.msf.minute = last_sony_subcode.rel_msf[0]; schi->cdsc_reladdr.msf.second = last_sony_subcode.rel_msf[1]; schi->cdsc_reladdr.msf.frame = 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); } return 0;}/* Get audio data from the drive. This is fairly complex because I am looking for status and data at the same time, but if I get status then I just look for data. I need to get the status immediately so the switch from audio to data tracks will happen quickly. */static voidread_audio_data(char *buffer, unsigned char res_reg[], int *res_size){ unsigned int retry_count; int result_read; res_reg[0] = 0; res_reg[1] = 0; *res_size = 0; result_read = 0; /* Wait for the drive to tell us we have something */ retry_count = jiffies + SONY_JIFFIES_TIMEOUT; continue_read_audio_wait: while (time_before(jiffies, retry_count) && !(is_data_ready()) && !(is_result_ready() || result_read)) { while (handle_sony_cd_attention()); sony_sleep(); } if (!(is_data_ready())) { if (is_result_ready() && !result_read) { get_result(res_reg, res_size); /* Read block status and continue waiting for data. */ if ((res_reg[0] & 0xf0) == 0x50) { result_read = 1; goto continue_read_audio_wait; } /* Invalid data from the drive. Shut down the operation. */ else 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 { clear_data_ready(); /* If data block, then get 2340 bytes offset by 12. */ if (sony_raw_data_mode) { insb(sony_cd_read_reg, buffer + CD_XA_HEAD, CD_FRAMESIZE_RAW1); } else { /* Audio gets the whole 2352 bytes. */ insb(sony_cd_read_reg, buffer, CD_FRAMESIZE_RAW); } /* If I haven't already gotten the result, get it now. */ if (!result_read) { /* Wait for the drive to tell us we have something */ retry_count
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -