📄 cdu31a.c
字号:
{ end_request(1); } break; case WRITE: end_request(0); break; default: panic("CDU31A: Unknown cmd"); } }end_do_cdu31a_request: spin_lock_irq(&io_request_lock);#if 0 /* After finished, cancel any pending operations. */ abort_read();#else /* Start a timer to time out after a while to disable the read. */ cdu31a_abort_timer.expires = jiffies + 2*HZ; /* Wait 2 seconds */ add_timer(&cdu31a_abort_timer);#endif has_cd_task = NULL; sony_inuse = 0; wake_up_interruptible(&sony_wait); restore_flags(flags);#if DEBUG printk("Leaving do_cdu31a_request at %d\n", __LINE__);#endif}/* * Read the table of contents from the drive and set up TOC if * successful. */static voidsony_get_toc(void){ unsigned char res_reg[2]; unsigned int res_size; unsigned char parms[1]; int session; int num_spin_ups; int totaltracks = 0; int mint = 99; int maxt = 0;#if DEBUG printk("Entering sony_get_toc\n");#endif num_spin_ups = 0; if (!sony_toc_read) {respinup_on_gettoc: /* Ignore the result, since it might error if spinning already. */ do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); 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, it's ok. */ if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) || (res_reg[1] == 0)) { goto gettoc_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_gettoc; } printk("cdu31a: Error reading TOC: %x %s\n", res_reg[0], translate_error(res_reg[1])); return; }gettoc_drive_spinning: /* The idea here is we keep asking for sessions until the command fails. Then we know what the last valid session on the disk is. No need to check session 0, since session 0 is the same as session 1; the command returns different information if you give it 0. */#if DEBUG memset(&sony_toc, 0x0e, sizeof(sony_toc)); memset(&single_toc, 0x0f, sizeof(single_toc));#endif session = 1; while (1) {/* This seems to slow things down enough to make it work. This * appears to be a problem in do_sony_cd_cmd. This printk seems * to address the symptoms... -Erik */#if 1 printk("cdu31a: Trying session %d\n", session);#endif parms[0] = session; do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD, parms, 1, res_reg, &res_size);#if DEBUG printk("%2.2x %2.2x\n", res_reg[0], res_reg[1]);#endif if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { /* An error reading the TOC, this must be past the last session. */ if (session == 1) printk("Yikes! Couldn't read any sessions!"); break; }#if DEBUG printk("Reading session %d\n", session);#endif parms[0] = session; do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD, parms, 1, (unsigned char *) &single_toc, &res_size); if ((res_size < 2) || ((single_toc.exec_status[0] & 0xf0) == 0x20)) { printk("cdu31a: Error reading session %d: %x %s\n", session, single_toc.exec_status[0], translate_error(single_toc.exec_status[1])); /* An error reading the TOC. Return without sony_toc_read set. */ return; }#if DEBUG printk("add0 %01x, con0 %01x, poi0 %02x, 1st trk %d, dsktyp %x, dum0 %x\n", single_toc.address0, single_toc.control0, single_toc.point0, bcd_to_int(single_toc.first_track_num), single_toc.disk_type, single_toc.dummy0); printk("add1 %01x, con1 %01x, poi1 %02x, lst trk %d, dummy1 %x, dum2 %x\n", single_toc.address1, single_toc.control1, single_toc.point1, bcd_to_int(single_toc.last_track_num), single_toc.dummy1, single_toc.dummy2); printk("add2 %01x, con2 %01x, poi2 %02x leadout start min %d, sec %d, frame %d\n", single_toc.address2, single_toc.control2, single_toc.point2, bcd_to_int(single_toc.lead_out_start_msf[0]), bcd_to_int(single_toc.lead_out_start_msf[1]), bcd_to_int(single_toc.lead_out_start_msf[2])); if (res_size > 18 && single_toc.pointb0 > 0xaf) printk("addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n" "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n", single_toc.addressb0, single_toc.controlb0, single_toc.pointb0, bcd_to_int(single_toc.next_poss_prog_area_msf[0]), bcd_to_int(single_toc.next_poss_prog_area_msf[1]), bcd_to_int(single_toc.next_poss_prog_area_msf[2]), single_toc.num_mode_5_pointers, bcd_to_int(single_toc.max_start_outer_leadout_msf[0]), bcd_to_int(single_toc.max_start_outer_leadout_msf[1]), bcd_to_int(single_toc.max_start_outer_leadout_msf[2])); if (res_size > 27 && single_toc.pointb1 > 0xaf) printk("addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n", single_toc.addressb1, single_toc.controlb1, single_toc.pointb1, single_toc.dummyb0_1[0], single_toc.dummyb0_1[1], single_toc.dummyb0_1[2], single_toc.dummyb0_1[3], single_toc.num_skip_interval_pointers, single_toc.num_skip_track_assignments, single_toc.dummyb0_2); if (res_size > 36 && single_toc.pointb2 > 0xaf) printk("addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n", single_toc.addressb2, single_toc.controlb2, single_toc.pointb2, single_toc.tracksb2[0], single_toc.tracksb2[1], single_toc.tracksb2[2], single_toc.tracksb2[3], single_toc.tracksb2[4], single_toc.tracksb2[5], single_toc.tracksb2[6]); if (res_size > 45 && single_toc.pointb3 > 0xaf) printk("addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n", single_toc.addressb3, single_toc.controlb3, single_toc.pointb3, single_toc.tracksb3[0], single_toc.tracksb3[1], single_toc.tracksb3[2], single_toc.tracksb3[3], single_toc.tracksb3[4], single_toc.tracksb3[5], single_toc.tracksb3[6]); if (res_size > 54 && single_toc.pointb4 > 0xaf) printk("addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n", single_toc.addressb4, single_toc.controlb4, single_toc.pointb4, single_toc.tracksb4[0], single_toc.tracksb4[1], single_toc.tracksb4[2], single_toc.tracksb4[3], single_toc.tracksb4[4], single_toc.tracksb4[5], single_toc.tracksb4[6]); if (res_size > 63 && single_toc.pointc0 > 0xaf) printk("addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n", single_toc.addressc0, single_toc.controlc0, single_toc.pointc0, single_toc.dummyc0[0], single_toc.dummyc0[1], single_toc.dummyc0[2], single_toc.dummyc0[3], single_toc.dummyc0[4], single_toc.dummyc0[5], single_toc.dummyc0[6]);#endif#undef DEBUG#define DEBUG 0 sony_toc.lead_out_start_msf[0] = bcd_to_int(single_toc.lead_out_start_msf[0]); sony_toc.lead_out_start_msf[1] = bcd_to_int(single_toc.lead_out_start_msf[1]); sony_toc.lead_out_start_msf[2] = bcd_to_int(single_toc.lead_out_start_msf[2]); sony_toc.lead_out_start_lba = single_toc.lead_out_start_lba = msf_to_log(sony_toc.lead_out_start_msf); /* 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 intfind_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 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] & 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(l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -