📄 ide-cd.c
字号:
struct cdrom_info *info = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; int minor = MINOR (rq->rq_dev); /* If the request is relative to a partition, fix it up to refer to the absolute address. */ if ((minor & PARTN_MASK) != 0) { rq->sector = block; minor &= ~PARTN_MASK; rq->rq_dev = MKDEV (MAJOR(rq->rq_dev), minor); } /* We may be retrying this request after an error. Fix up any weirdness which might be present in the request packet. */ restore_request (rq); /* Satisfy whatever we can of this request from our cached sector. */ if (cdrom_read_from_buffer(drive)) return ide_stopped; /* Clear the local sector buffer. */ info->nsectors_buffered = 0; /* use dma, if possible. */ if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0)) info->dma = 1; else info->dma = 0; info->cmd = READ; /* Start sending the read request to the drive. */ return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);}/**************************************************************************** * Execute all other packet commands. *//* Forward declarations. */static int cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense);/* Interrupt routine for packet command completion. */static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive){ int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; ide_startstop_t startstop; /* Check for errors. */ if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; /* Read the interrupt reason and the transfer length. */ ireason = IN_BYTE (IDE_NSECTOR_REG); len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG); /* If DRQ is clear, the command has completed. Complain if we still have data left to transfer. */ if ((stat & DRQ_STAT) == 0) { /* Some of the trailing request sense fields are optional, and some drives don't send them. Sigh. */ if (pc->c[0] == GPCMD_REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { while (pc->buflen > 0) { *pc->buffer++ = 0; --pc->buflen; } } if (pc->buflen == 0) cdrom_end_request (1, drive); else { /* Comment this out, because this always happens right after a reset occurs, and it is annoying to always print expected stuff. */ /* printk ("%s: cdrom_pc_intr: data underrun %d\n", drive->name, pc->buflen); */ pc->stat = 1; cdrom_end_request (1, drive); } return ide_stopped; } /* Figure out how much data to transfer. */ thislen = pc->buflen; if (thislen > len) thislen = len; /* The drive wants to be written to. */ if ((ireason & 3) == 0) { /* Transfer the data. */ atapi_output_bytes (drive, pc->buffer, thislen); /* If we haven't moved enough data to satisfy the drive, add some padding. */ while (len > thislen) { int dum = 0; atapi_output_bytes (drive, &dum, sizeof (dum)); len -= sizeof (dum); } /* Keep count of how much data we've moved. */ pc->buffer += thislen; pc->buflen -= thislen; } /* Same drill for reading. */ else if ((ireason & 3) == 2) { /* Transfer the data. */ atapi_input_bytes (drive, pc->buffer, thislen); /* If we haven't moved enough data to satisfy the drive, add some padding. */ while (len > thislen) { int dum = 0; atapi_input_bytes (drive, &dum, sizeof (dum)); len -= sizeof (dum); } /* Keep count of how much data we've moved. */ pc->buffer += thislen; pc->buflen -= thislen; } else { printk ("%s: cdrom_pc_intr: The drive " "appears confused (ireason = 0x%2x)\n", drive->name, ireason); pc->stat = 1; } /* Now we wait for another interrupt. */ ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); return ide_started;}static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; if (!pc->timeout) pc->timeout = WAIT_CMD; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);}static ide_startstop_t 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; struct cdrom_info *info = drive->driver_data; info->dma = 0; info->cmd = 0; pc->stat = 0; len = pc->buflen; /* Start sending the command to the drive. */ return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);}/* Sleep for TIME jiffies. Not to be called from an interrupt handler. */staticvoid cdrom_sleep (int time){ int sleep = time; do { set_current_state(TASK_INTERRUPTIBLE); sleep = schedule_timeout(sleep); } while (sleep);}staticint cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc){ struct request_sense sense; struct request req; int retries = 10; if (pc->sense == NULL) pc->sense = &sense; /* Start of retry loop. */ do { ide_init_drive_cmd (&req); req.cmd = PACKET_COMMAND; req.buffer = (char *)pc; if (ide_do_drive_cmd (drive, &req, ide_wait)) { printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n", drive->name, req.buffer[0], req.buffer[1]); /* FIXME: we should probably abort/retry or something */ } if (pc->stat != 0) { /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ struct request_sense *reqbuf = pc->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); else if (reqbuf->sense_key == NOT_READY && reqbuf->asc == 4 && reqbuf->ascq != 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(2 * 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. */ return pc->stat ? -EIO : 0;}/* * Write handling */static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason){ /* Two notes about IDE interrupt reason here - 0 means that * the drive wants to receive data from us, 2 means that * the drive is expecting data from us. */ ireason &= 3; if (ireason == 2) { /* Whoops... The drive wants to send data. */ printk("%s: cdrom_write_intr: wrong transfer direction!\n", drive->name); /* Throw some data at the drive so it doesn't hang and quit this request. */ while (len > 0) { int dum = 0; atapi_output_bytes(drive, &dum, sizeof(dum)); len -= sizeof(dum); } } else { /* Drive wants a command packet, or invalid ireason... */ printk("%s: cdrom_write_intr: bad interrupt reason %d\n", drive->name, ireason); } cdrom_end_request(0, drive); return 1;}static ide_startstop_t cdrom_write_intr(ide_drive_t *drive){ int stat, ireason, len, sectors_to_transfer; struct cdrom_info *info = drive->driver_data; int i, dma_error = 0, dma = info->dma; ide_startstop_t startstop; struct request *rq = HWGROUP(drive)->rq; /* Check for errors. */ if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) { printk("ide-cd: write dma error\n"); HWIF(drive)->dmaproc(ide_dma_off, drive); } } if (cdrom_decode_status(&startstop, drive, 0, &stat)) { printk("ide-cd: write_intr decode_status bad\n"); return startstop; } if (dma) { if (dma_error) return ide_error(drive, "dma error", stat); rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; ide_end_request(1, HWGROUP(drive)); } return ide_stopped; } /* Read the interrupt reason and the transfer length. */ ireason = IN_BYTE(IDE_NSECTOR_REG); len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG); /* If DRQ is clear, the command has completed. */ if ((stat & DRQ_STAT) == 0) { /* If we're not done writing, complain. * Otherwise, complete the command normally. */ if (rq->current_nr_sectors > 0) { printk("%s: write_intr: data underrun (%ld blocks)\n", drive->name, rq->current_nr_sectors); cdrom_end_request(0, drive); } else cdrom_end_request(1, drive); return ide_stopped; } /* Check that the drive is expecting to do the same thing we are. */ if (ireason & 3) if (cdrom_write_check_ireason(drive, len, ireason)) return ide_stopped; /* The number of sectors we need to read from the drive. */ sectors_to_transfer = len / SECTOR_SIZE; /* Now loop while we still have data to read from the drive. DMA * transfers will already have been complete */ while (sectors_to_transfer > 0) { /* If we've filled the present buffer but there's another chained buffer after it, move on. */ if (rq->current_nr_sectors == 0 && rq->nr_sectors > 0) cdrom_end_request(1, drive); atapi_output_bytes(drive, rq->buffer, rq->current_nr_sectors); rq->nr_sectors -= rq->current_nr_sectors; rq->current_nr_sectors = 0; rq->sector += rq->current_nr_sectors; sectors_to_transfer -= rq->current_nr_sectors; } /* arm handler */ ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); return ide_started;}static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive){ struct packet_command pc; /* packet_command_t pc; */ struct request *rq = HWGROUP(drive)->rq; unsigned nframes, frame; nframes = rq->nr_sectors >> 2; frame = rq->sector >> 2; memset(&pc.c, 0, sizeof(pc.c)); /* * we might as well use WRITE_12, but none of the device I have * support the streaming feature anyway, so who cares. */ pc.c[0] = GPCMD_WRITE_10;#if 0 /* the immediate bit */ pc.c[1] = 1 << 3;#endif pc.c[7] = (nframes >> 8) & 0xff; pc.c[8] = nframes & 0xff; put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]); pc.timeout = 2 * WAIT_CMD; return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);}static ide_startstop_t cdrom_start_write(ide_drive_t *drive){ struct cdrom_info *info = drive->driver_data; info->nsectors_buffered = 0; /* use dma, if possible. we don't need to check more, since we * know that the transfer is always (at least!) 2KB aligned */ info->dma = drive->using_dma ? 1 : 0; info->cmd = WRITE; /* Start sending the read request to the drive. */ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);}/**************************************************************************** * cdrom driver request routine. */static ide_startstop_tide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block){ ide_startstop_t action; struct cdrom_info *info = drive->driver_data; switch (rq->cmd) { case WRITE: case READ: { if (CDROM_CONFIG_FLAGS(drive)->seeking) { unsigned long elpased = jiffies - info->start_seek; int stat = GET_STAT(); if ((stat & SEEK_STAT) != SEEK_STAT) { if (elpased < IDECD_SEEK_TIMEOUT) { ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -