📄 ide-cd.c
字号:
/* Now we wait for another interrupt. */ ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);}static void cdrom_do_pc_continuation (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; /* Send the command to the drive and return. */ cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c), &cdrom_pc_intr);}static void cdrom_do_packet_command (ide_drive_t *drive){ int len; struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; len = pc->buflen; if (len < 0) len = -len; pc->stat = 0; /* Start sending the command to the drive. */ cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);}#ifndef MACH/* Sleep for TIME jiffies. Not to be called from an interrupt handler. */staticvoid cdrom_sleep (int time){ current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + time; schedule ();}#endifstaticint cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc){ struct atapi_request_sense my_reqbuf; int retries = 10; struct request req; /* If our caller has not provided a place to stick any sense data, use our own area. */ if (pc->sense_data == NULL) pc->sense_data = &my_reqbuf; pc->sense_data->sense_key = 0; /* Start of retry loop. */ do { ide_init_drive_cmd (&req); req.cmd = PACKET_COMMAND; req.buffer = (char *)pc; (void) ide_do_drive_cmd (drive, &req, ide_wait); if (pc->stat != 0) { /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ struct atapi_request_sense *reqbuf = pc->sense_data; if (reqbuf->sense_key == UNIT_ATTENTION) ; else if (reqbuf->sense_key == NOT_READY && reqbuf->asc == 4) { /* The drive is in the process of loading a disk. Retry, but wait a little to give the drive time to complete the load. */ cdrom_sleep (HZ); } else /* Otherwise, don't retry. */ retries = 0; --retries; } /* End of retry loop. */ } while (pc->stat != 0 && retries >= 0); /* Return an error if the command failed. */ if (pc->stat != 0) return -EIO; else { /* The command succeeded. If it was anything other than a request sense, eject, or door lock command, and we think that the door is presently, lock it again. (The door was probably unlocked via an explicit CDROMEJECT ioctl.) */ if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && (pc->c[0] != REQUEST_SENSE && pc->c[0] != ALLOW_MEDIUM_REMOVAL && pc->c[0] != START_STOP)) { (void) cdrom_lockdoor (drive, 1, NULL); } return 0; }}/**************************************************************************** * cdrom driver request routine. */void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block){ struct request *rq = HWGROUP(drive)->rq; if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) cdrom_do_packet_command (drive); else if (rq -> cmd == RESET_DRIVE_COMMAND) { cdrom_end_request (1, drive); ide_do_reset (drive); return; } else if (rq -> cmd != READ) { printk ("ide-cd: bad cmd %d\n", rq -> cmd); cdrom_end_request (0, drive); } else cdrom_start_read (drive, block);}/**************************************************************************** * Ioctl handling. * * Routines which queue packet commands take as a final argument a pointer * to an atapi_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_BLOCK_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_BLOCK_OFFSET;}static intcdrom_check_status (ide_drive_t *drive, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = TEST_UNIT_READY; /* 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] = CDROM_STATE_FLAGS (drive)->sanyo_slot % 3; 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 atapi_request_sense *reqbuf){ struct atapi_request_sense my_reqbuf; int stat; struct packet_command pc; if (reqbuf == NULL) reqbuf = &my_reqbuf; /* 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_data = reqbuf; pc.c[0] = ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } if (stat == 0) CDROM_STATE_FLAGS (drive)->door_locked = lockflag; else { /* If we got an illegal field error, the drive probably cannot lock the door. */ if (reqbuf->sense_key == ILLEGAL_REQUEST && (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) { printk ("%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; 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 intcdrom_eject (ide_drive_t *drive, int ejectflag, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = START_STOP; pc.c[4] = 2 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc);}static intcdrom_pause (ide_drive_t *drive, int pauseflag, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = SCMD_PAUSE_RESUME; pc.c[8] = !pauseflag; return cdrom_queue_packet_command (drive, &pc);}static intcdrom_startstop (ide_drive_t *drive, int startflag, struct atapi_request_sense *reqbuf){ struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = START_STOP; pc.c[1] = 1; pc.c[4] = startflag; return cdrom_queue_packet_command (drive, &pc);}static intcdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, struct atapi_request_sense *reqbuf){ struct { unsigned lba; unsigned blocklen; } capbuf; int stat; struct packet_command pc; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; pc.c[0] = READ_CAPACITY; pc.buffer = (char *)&capbuf; pc.buflen = sizeof (capbuf); stat = cdrom_queue_packet_command (drive, &pc); if (stat == 0) *capacity = ntohl (capbuf.lba); return stat;}static intcdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, 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_TOC; 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 intcdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf){ int stat, ntracks, i; struct atapi_toc *toc = drive->cdrom_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); drive->cdrom_info.toc = toc; } if (toc == NULL) { printk ("%s: No cdrom TOC buffer!\n", drive->name); return -EIO; } /* Check to see if the existing data is still valid. If it is, just return. */ if (CDROM_STATE_FLAGS (drive)->toc_valid) (void) cdrom_check_status (drive, NULL); 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) + sizeof (struct atapi_toc_entry), reqbuf); 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, 0, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks+1) * sizeof (struct atapi_toc_entry), reqbuf); 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. */ stat = cdrom_read_tocentry (drive, 0, 1, 1, (char *)&ms_tmp, sizeof (ms_tmp), reqbuf); if (stat) return stat;#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. */ stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); if (stat) toc->capacity = 0x1fffff; HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = toc->capacity * SECTORS_PER_FRAME; drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -