📄 ide-cd.c
字号:
} printk ("%s: DSC timeout\n", drive->name); } CDROM_CONFIG_FLAGS(drive)->seeking = 0; } if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) action = cdrom_start_seek (drive, block); else { if (rq->cmd == READ) action = cdrom_start_read(drive, block); else action = cdrom_start_write(drive); } info->last_block = block; return action; } case PACKET_COMMAND: case REQUEST_SENSE_COMMAND: { return cdrom_do_packet_command(drive); } case RESET_DRIVE_COMMAND: { cdrom_end_request(1, drive); return ide_do_reset(drive); } default: { printk("ide-cd: bad cmd %d\n", rq->cmd); cdrom_end_request(0, drive); return ide_stopped; } }}/**************************************************************************** * Ioctl handling. * * Routines which queue packet commands take as a final argument a pointer * to a request_sense struct. If execution of the command results * in an error with a CHECK CONDITION status, this structure will be filled * with the results of the subsequent request sense command. The pointer * can also be NULL, in which case no sense information is returned. */#if ! STANDARD_ATAPIstatic inlineint bin2bcd (int x){ return (x%10) | ((x/10) << 4);}static inlineint bcd2bin (int x){ return (x >> 4) * 10 + (x & 0x0f);}staticvoid msf_from_bcd (struct atapi_msf *msf){ msf->minute = bcd2bin (msf->minute); msf->second = bcd2bin (msf->second); msf->frame = bcd2bin (msf->frame);}#endif /* not STANDARD_ATAPI */static inlinevoid lba_to_msf (int lba, byte *m, byte *s, byte *f){ lba += CD_MSF_OFFSET; lba &= 0xffffff; /* negative lbas use only 24 bits */ *m = lba / (CD_SECS * CD_FRAMES); lba %= (CD_SECS * CD_FRAMES); *s = lba / CD_FRAMES; *f = lba % CD_FRAMES;}static inlineint msf_to_lba (byte m, byte s, byte f){ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;}static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense){ struct packet_command pc; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.c[0] = GPCMD_TEST_UNIT_READY;#if ! STANDARD_ATAPI /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs instead of supporting the LOAD_UNLOAD opcode */ pc.c[7] = cdi->sanyo_slot % 3;#endif /* not STANDARD_ATAPI */ return cdrom_queue_packet_command(drive, &pc);}/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */static intcdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense){ struct request_sense my_sense; struct packet_command pc; int stat; if (sense == NULL) sense = &my_sense; /* If the drive cannot lock the door, just pretend. */ if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) { stat = 0; } else { memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = lockflag ? 1 : 0; stat = cdrom_queue_packet_command (drive, &pc); } /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && sense->sense_key == ILLEGAL_REQUEST && (sense->asc == 0x24 || sense->asc == 0x20)) { printk ("%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; stat = 0; } /* no medium, that's alright. */ if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) stat = 0; if (stat == 0) CDROM_STATE_FLAGS (drive)->door_locked = lockflag; return stat;}/* Eject the disk if EJECTFLAG is 0. If EJECTFLAG is 1, try to reload the disk. */static int cdrom_eject(ide_drive_t *drive, int ejectflag, struct request_sense *sense){ struct packet_command pc; if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; /* reload fails on some drives, if the tray is locked */ if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) return 0; memset(&pc, 0, sizeof (pc)); pc.sense = sense; pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc);}static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity, struct request_sense *sense){ struct { __u32 lba; __u32 blocklen; } capbuf; int stat; struct packet_command pc; memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; pc.buflen = sizeof(capbuf); stat = cdrom_queue_packet_command(drive, &pc); if (stat == 0) *capacity = 1 + be32_to_cpu(capbuf.lba); return stat;}static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, int format, char *buf, int buflen, struct request_sense *sense){ struct packet_command pc; memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; pc.c[0] = GPCMD_READ_TOC_PMA_ATIP; pc.c[6] = trackno; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); pc.c[9] = (format << 6); if (msf_flag) pc.c[1] = 2; return cdrom_queue_packet_command (drive, &pc);}/* Try to read the entire TOC for the disk into our internal buffer. */static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense){ int minor, stat, ntracks, i; kdev_t dev; struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; struct { struct atapi_toc_header hdr; struct atapi_toc_entry ent; } ms_tmp; if (toc == NULL) { /* Try to allocate space. */ toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), GFP_KERNEL); info->toc = toc; if (toc == NULL) { printk ("%s: No cdrom TOC buffer!\n", drive->name); return -ENOMEM; } } /* Check to see if the existing data is still valid. If it is, just return. */ (void) cdrom_check_status(drive, sense); if (CDROM_STATE_FLAGS(drive)->toc_valid) return 0; /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, sizeof(struct atapi_toc_header), sense); if (stat) return stat;#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { toc->hdr.first_track = bcd2bin (toc->hdr.first_track); toc->hdr.last_track = bcd2bin (toc->hdr.last_track); }#endif /* not STANDARD_ATAPI */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (ntracks <= 0) return -EIO; if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof(struct atapi_toc_header) + (ntracks + 1) * sizeof(struct atapi_toc_entry), sense); if (stat && toc->hdr.first_track > 1) { /* Cds with CDI tracks only don't have any TOC entries, despite of this the returned values are first_track == last_track = number of CDI tracks + 1, so that this case is indistinguishable from the same layout plus an additional audio track. If we get an error for the regular case, we assume a CDI without additional audio tracks. In this case the readable TOC is empty (CDI tracks are not included) and only holds the Leadout entry. Heiko Ei遞eldt */ ntracks = 0; stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0, (char *)&toc->hdr, sizeof(struct atapi_toc_header) + (ntracks + 1) * sizeof(struct atapi_toc_entry), sense); if (stat) { return stat; }#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { toc->hdr.first_track = bin2bcd(CDROM_LEADOUT); toc->hdr.last_track = bin2bcd(CDROM_LEADOUT); } else#endif /* not STANDARD_ATAPI */ { toc->hdr.first_track = CDROM_LEADOUT; toc->hdr.last_track = CDROM_LEADOUT; } } if (stat) return stat; toc->hdr.toc_length = ntohs (toc->hdr.toc_length);#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { toc->hdr.first_track = bcd2bin (toc->hdr.first_track); toc->hdr.last_track = bcd2bin (toc->hdr.last_track); }#endif /* not STANDARD_ATAPI */ for (i=0; i<=ntracks; i++) {#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) { if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) toc->ent[i].track = bcd2bin (toc->ent[i].track); msf_from_bcd (&toc->ent[i].addr.msf); }#endif /* not STANDARD_ATAPI */ toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute, toc->ent[i].addr.msf.second, toc->ent[i].addr.msf.frame); } /* Read the multisession information. */ if (toc->hdr.first_track != CDROM_LEADOUT) { /* Read the multisession information. */ stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, sizeof(ms_tmp), sense); if (stat) return stat; } else { ms_tmp.ent.addr.msf.minute = 0; ms_tmp.ent.addr.msf.second = 2; ms_tmp.ent.addr.msf.frame = 0; ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT; }#if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) msf_from_bcd (&ms_tmp.ent.addr.msf);#endif /* not STANDARD_ATAPI */ toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.minute, ms_tmp.ent.addr.msf.second, ms_tmp.ent.addr.msf.frame); toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ minor = (drive->select.b.unit) << PARTN_BITS; dev = MKDEV(HWIF(drive)->major, minor); stat = cdrom_get_last_written(dev, (long *)&toc->capacity); if (stat) stat = cdrom_read_capacity(drive, &toc->capacity, sense); if (stat) toc->capacity = 0x1fffff; HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; return 0;}static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, int buflen, struct request_sense *sense){ struct packet_command pc; memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; pc.c[0] = GPCMD_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);}/* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */static int cdrom_select_spee
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -