📄 ide-cd.c
字号:
/* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; return 0;}static intcdrom_read_subchannel (ide_drive_t *drive, int format, char *buf, int buflen, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.buffer = buf; pc.buflen = buflen; pc.c[0] = SCMD_READ_SUBCHANNEL; pc.c[1] = 2; /* MSF addressing */ pc.c[2] = 0x40; /* request subQ data */ pc.c[3] = format, pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); return cdrom_queue_packet_command (drive, &pc);}/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */static intcdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag, char *buf, int buflen, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.buffer = buf; pc.buflen = buflen; pc.c[0] = MODE_SENSE_10; pc.c[2] = pageno | (modeflag << 6); pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); return cdrom_queue_packet_command (drive, &pc);}static intcdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.buffer = buf; pc.buflen = - buflen; pc.c[0] = MODE_SELECT_10; pc.c[1] = 0x10; pc.c[2] = pageno; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); return cdrom_queue_packet_command (drive, &pc);}static intcdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = SCMD_PLAYAUDIO_MSF; lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd) { pc.c[3] = bin2bcd (pc.c[3]); pc.c[4] = bin2bcd (pc.c[4]); pc.c[5] = bin2bcd (pc.c[5]); pc.c[6] = bin2bcd (pc.c[6]); pc.c[7] = bin2bcd (pc.c[7]); pc.c[8] = bin2bcd (pc.c[8]); }#endif /* not STANDARD_ATAPI */ return cdrom_queue_packet_command (drive, &pc);}/* Play audio starting at LBA LBA_START and finishing with the LBA before LBA_END. */static intcdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end, struct atapi_request_sense *reqbuf){ int i, stat; struct atapi_request_sense my_reqbuf; if (reqbuf == NULL) reqbuf = &my_reqbuf; /* Some drives, will, for certain audio cds, give an error if you ask them to play the entire cd using the values which are returned in the TOC. The play will succeed, however, if the ending address is adjusted downwards by a few frames. */ for (i=0; i<75; i++) { stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end, reqbuf); if (stat == 0 || !(reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x24)) return stat; --lba_end; if (lba_end <= lba_start) break; } return stat;}staticint cdrom_get_toc_entry (ide_drive_t *drive, int track, struct atapi_toc_entry **ent, struct atapi_request_sense *reqbuf){ int stat, ntracks; struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ stat = cdrom_read_toc (drive, reqbuf); if (stat) return stat; toc = drive->cdrom_info.toc; /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (track == CDROM_LEADOUT) *ent = &toc->ent[ntracks]; else if (track < toc->hdr.first_track || track > toc->hdr.last_track) return -EINVAL; else *ent = &toc->ent[track - toc->hdr.first_track]; return 0;}static intcdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks, char *buf, int buflen, struct atapi_request_sense *reqbuf){ struct packet_command pc; struct atapi_request_sense my_reqbuf; int stat; if (reqbuf == NULL) reqbuf = &my_reqbuf; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.buffer = buf; pc.buflen = buflen;#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->old_readcd) pc.c[0] = 0xd4; else#endif /* not STANDARD_ATAPI */ pc.c[0] = READ_CD; pc.c[1] = (format << 2); put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]); pc.c[8] = (nblocks & 0xff); pc.c[7] = ((nblocks>>8) & 0xff); pc.c[6] = ((nblocks>>16) & 0xff); if (format <= 1) pc.c[9] = 0xf8; else pc.c[9] = 0x10; stat = cdrom_queue_packet_command (drive, &pc);#if ! STANDARD_ATAPI /* If the drive doesn't recognize the READ CD opcode, retry the command with an older opcode for that command. */ if (stat && reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x20 && CDROM_CONFIG_FLAGS (drive)->old_readcd == 0) { printk ("%s: Drive does not recognize READ_CD;" "trying opcode 0xd4\n", drive->name); CDROM_CONFIG_FLAGS (drive)->old_readcd = 1; return cdrom_read_block (drive, format, lba, nblocks, buf, buflen, reqbuf); }#endif /* not STANDARD_ATAPI */ return stat;}/* If SLOT<0, unload the current slot. Otherwise, try to load SLOT. */static intcdrom_load_unload (ide_drive_t *drive, int slot, struct atapi_request_sense *reqbuf){ /* if the drive is a Sanyo 3 CD changer then TEST_UNIT_READY (used in the cdrom_check_status function) is used to switch CDs instead of LOAD_UNLOAD */ if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { if ((slot == 1) || (slot == 2)) { CDROM_STATE_FLAGS (drive)->sanyo_slot = slot; } else if (slot >= 0) { CDROM_STATE_FLAGS (drive)->sanyo_slot = 3; } else { return 0; } return cdrom_check_status (drive, NULL); } else { /* ATAPI Rev. 2.2+ standard for requesting switching of CDs in a multiplatter device */ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = LOAD_UNLOAD; pc.c[4] = 2 + (slot >= 0); pc.c[8] = slot; return cdrom_queue_packet_command (drive, &pc); }}int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { case CDROMEJECT: { int stat; if (drive->usage > 1) return -EBUSY; stat = cdrom_lockdoor (drive, 0, NULL); if (stat) return stat; return cdrom_eject (drive, 0, NULL); } case CDROMCLOSETRAY: { int stat; if (drive->usage > 1) return -EBUSY; stat = cdrom_eject (drive, 1, NULL); if (stat) return stat; return cdrom_lockdoor (drive, 1, NULL); } case CDROMEJECT_SW: { CDROM_STATE_FLAGS (drive)->eject_on_close = arg; return 0; } case CDROMPAUSE: return cdrom_pause (drive, 1, NULL); case CDROMRESUME: return cdrom_pause (drive, 0, NULL); case CDROMSTART: return cdrom_startstop (drive, 1, NULL); case CDROMSTOP: {#ifdef IHAVEADOLPHIN /* Certain Drives require this. Most don't and will produce errors upon CDROMSTOP pit says the Dolphin needs this. If you own a dolphin, just define IHAVEADOLPHIN somewhere */ int stat; stat = cdrom_startstop (drive, 0, NULL); if (stat) return stat; return cdrom_eject (drive, 1, NULL);#endif /* end of IHAVEADOLPHIN */ return cdrom_startstop (drive, 0, NULL); } case CDROMPLAYMSF: { struct cdrom_msf msf; int stat, lba_start, lba_end; stat = verify_area (VERIFY_READ, (void *)arg, sizeof (msf)); if (stat) return stat; memcpy_fromfs (&msf, (void *) arg, sizeof(msf)); lba_start = msf_to_lba (msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); lba_end = msf_to_lba (msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1) + 1; if (lba_end <= lba_start) return -EINVAL; return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); } /* Like just about every other Linux cdrom driver, we ignore the index part of the request here. */ case CDROMPLAYTRKIND: { int stat, lba_start, lba_end; struct cdrom_ti ti; struct atapi_toc_entry *first_toc, *last_toc; stat = verify_area (VERIFY_READ, (void *)arg, sizeof (ti)); if (stat) return stat; memcpy_fromfs (&ti, (void *) arg, sizeof(ti)); stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc, NULL); if (stat) return stat; stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc, NULL); if (stat) return stat; if (ti.cdti_trk1 != CDROM_LEADOUT) ++last_toc; lba_start = first_toc->addr.lba; lba_end = last_toc->addr.lba; if (lba_end <= lba_start) return -EINVAL; return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); } case CDROMREADTOCHDR: { int stat; struct cdrom_tochdr tochdr; struct atapi_toc *toc; stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (tochdr)); if (stat) return stat; /* Make sure our saved TOC is valid. */ stat = cdrom_read_toc (drive, NULL); if (stat) return stat; toc = drive->cdrom_info.toc; tochdr.cdth_trk0 = toc->hdr.first_track; tochdr.cdth_trk1 = toc->hdr.last_track; memcpy_tofs ((void *) arg, &tochdr, sizeof (tochdr)); return stat; } case CDROMREADTOCENTRY: { int stat; struct cdrom_tocentry tocentry; struct atapi_toc_entry *toce; stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (tocentry)); if (stat) return stat; memcpy_fromfs (&tocentry, (void *) arg, sizeof (tocentry)); stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce, NULL); if (stat) return stat; tocentry.cdte_ctrl = toce->control; tocentry.cdte_adr = toce->adr; if (tocentry.cdte_format == CDROM_MSF) { /* convert to MSF */ lba_to_msf (toce->addr.lba, &tocentry.cdte_addr.msf.minute, &tocentry.cdte_addr.msf.second, &tocentry.cdte_addr.msf.frame); } else tocentry.cdte_addr.lba = toce->addr.lba; memcpy_tofs ((void *) arg, &tocentry, sizeof (tocentry)); return stat; } case CDROMSUBCHNL: { struct atapi_cdrom_subchnl scbuf; int stat; struct cdrom_subchnl subchnl; stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (subchnl)); if (stat) return stat; memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl)); stat = cdrom_read_subchannel (drive, 1, /* current position */ (char *)&scbuf, sizeof (scbuf), NULL); if (stat) return stat;#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd) { msf_from_bcd (&scbuf.acdsc_absaddr.msf); msf_from_bcd (&scbuf.acdsc_reladdr.msf); } if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk);#endif /* not STANDARD_ATAPI */ if (subchnl.cdsc_format == CDROM_MSF) { subchnl.cdsc_absaddr.msf.minute = scbuf.acdsc_absaddr.msf.minute; subchnl.cdsc_absaddr.msf.second = scbuf.acdsc_absaddr.msf.second; subchnl.cdsc_absaddr.msf.frame = scbuf.acdsc_absaddr.msf.frame; subchnl.cdsc_rel
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -