?? ide-cd.c
字號:
{ struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; int nsect, sector, nframes, frame, nskip; /* Number of sectors to transfer. */ nsect = rq->nr_sectors; /* Starting sector. */ sector = rq->sector; /* If the requested sector doesn't start on a cdrom block boundary, we must adjust the start of the transfer so that it does, and remember to skip the first few sectors. If the CURRENT_NR_SECTORS field is larger than the size of the buffer, it will mean that we're to skip a number of sectors equal to the amount by which CURRENT_NR_SECTORS is larger than the buffer size. */ nskip = (sector % SECTORS_PER_FRAME); if (nskip > 0) { /* Sanity check... */ if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) && (rq->sector % CD_FRAMESIZE != 0)) { printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); cdrom_end_request(drive, 0); return ide_stopped; } sector -= nskip; nsect += nskip; rq->current_nr_sectors += nskip; } /* Convert from sectors to cdrom blocks, rounding up the transfer length if needed. */ nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME; frame = sector / SECTORS_PER_FRAME; /* Largest number of frames was can transfer at once is 64k-1. For some drives we need to limit this even more. */ nframes = MIN (nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ? (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ memset (&pc.c, 0, sizeof (pc.c)); pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); pc.timeout = WAIT_CMD; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);}#define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive){ struct cdrom_info *info = drive->driver_data; int stat; static int retry = 10; ide_startstop_t startstop; if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; CDROM_CONFIG_FLAGS(drive)->seeking = 1; if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) { if (--retry == 0) { /* * this condition is far too common, to bother * users about it */#if 0 printk("%s: disabled DSC seek overlap\n", drive->name);#endif drive->dsc_overlap = 0; } } return ide_stopped;}static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive){ struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; int sector, frame, nskip; sector = rq->sector; nskip = (sector % SECTORS_PER_FRAME); if (nskip > 0) sector -= nskip; frame = sector / SECTORS_PER_FRAME; memset (&pc.c, 0, sizeof (pc.c)); pc.c[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); pc.timeout = WAIT_CMD; return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);}static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block){ struct cdrom_info *info = drive->driver_data; info->dma = 0; info->cmd = 0; info->start_seek = jiffies; return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);}static inline int cdrom_merge_requests(struct request *rq, struct request *nxt){ int ret = 1; /* * partitions not really working, but better check anyway... */ if (rq->cmd == nxt->cmd && rq->rq_dev == nxt->rq_dev) { rq->nr_sectors += nxt->nr_sectors; rq->hard_nr_sectors += nxt->nr_sectors; rq->bhtail->b_reqnext = nxt->bh; rq->bhtail = nxt->bhtail; list_del(&nxt->queue); blkdev_release_request(nxt); ret = 0; } return ret;}/* * the current request will always be the first one on the list */static void cdrom_attempt_remerge(ide_drive_t *drive, struct request *rq){ struct list_head *entry; struct request *nxt; unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); while (1) { entry = rq->queue.next; if (entry == &drive->queue.queue_head) break; nxt = blkdev_entry_to_request(entry); if (rq->sector + rq->nr_sectors != nxt->sector) break; else if (rq->nr_sectors + nxt->nr_sectors > SECTORS_MAX) break; if (cdrom_merge_requests(rq, nxt)) break; } spin_unlock_irqrestore(&io_request_lock, flags);}/* Fix up a possibly partially-processed request so that we can start it over entirely, or even put it back on the request queue. */static void restore_request (struct request *rq){ if (rq->buffer != rq->bh->b_data) { int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; rq->buffer = rq->bh->b_data; rq->nr_sectors += n; rq->sector -= n; } rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; rq->hard_nr_sectors = rq->nr_sectors; rq->hard_sector = rq->sector;}/* * Start a read request from the CD-ROM. */static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block){ 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) { 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; cdrom_attempt_remerge(drive, rq); /* 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; u8 lowcyl = 0, highcyl = 0; /* Check for errors. */ if (cdrom_decode_status(&startstop, drive, 0, &stat)) return startstop; /* Read the interrupt reason and the transfer length. */ ireason = HWIF(drive)->INB(IDE_IREASON_REG); lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); len = lowcyl + (256 * highcyl); /* 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(drive, 1); 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(drive, 1); } 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. */ HWIF(drive)->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; HWIF(drive)->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. */ HWIF(drive)->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; HWIF(drive)->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; ide_do_drive_cmd(drive, &req, ide_wait); /* FIXME: we should probably abort/retry or something * in case of failure */ 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; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -