?? ide-cd.c
字號:
{ struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *) rq->buffer; unsigned long wait = 0; /* * Some commands are *slow* and normally take a long time to * complete. Usually we can use the ATAPI "disconnect" to bypass * this, but not all commands/drives support that. Let * ide_timer_expiry keep polling us for these. */ switch (pc->c[0]) { case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: wait = WAIT_CMD; break; default: wait = 0; break; } return wait;}/* Set up the device registers for transferring a packet command on DEV, expecting to later transfer XFERLEN bytes. HANDLER is the routine which actually transfers the command to the drive. If this is a drq_interrupt device, this routine will arrange for HANDLER to be called when the interrupt from the drive arrives. Otherwise, HANDLER will be called immediately after the drive is prepared for the transfer. */static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, int xferlen, ide_handler_t *handler){ ide_startstop_t startstop; struct cdrom_info *info = drive->driver_data; /* Wait for the controller to be idle. */ if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) return startstop; if (info->dma) { if (info->cmd == READ) { info->dma = !HWIF(drive)->ide_dma_read(drive); } else if (info->cmd == WRITE) { info->dma = !HWIF(drive)->ide_dma_write(drive); } else { printk("ide-cd: DMA set, but not allowed\n"); } } /* Set up the controller registers. */ /* FIXME: for Virtual DMA we must check harder */ HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG); HWIF(drive)->OUTB(0, IDE_IREASON_REG); HWIF(drive)->OUTB(0, IDE_SECTOR_REG); HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG); HWIF(drive)->OUTB(xferlen >> 8 , IDE_BCOUNTH_REG); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* packet command */ ide_execute_command(drive, WIN_PACKETCMD, handler, WAIT_CMD, cdrom_timer_expiry); return ide_started; } else { /* packet command */ HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); return (*handler) (drive); }}/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. The device registers must have already been prepared by cdrom_start_packet_command. HANDLER is the interrupt handler to call when the command completes or there's data ready. *//* * changed 5 parameters to 3 for dvd-ram * struct packet_command *pc; now packet_command_t *pc; */static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, struct packet_command *pc, ide_handler_t *handler){ unsigned char *cmd_buf = pc->c; int cmd_len = sizeof(pc->c); unsigned int timeout = pc->timeout; struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ int stat_dum; /* Check for errors. */ if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum)) return startstop; } else { /* Otherwise, we must wait for DRQ to get set. */ if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) return startstop; } /* Arm the interrupt handler. */ ide_set_handler(drive, handler, timeout, cdrom_timer_expiry); /* Send the command to the device. */ HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len); /* Start the DMA if need be */ if (info->dma) (void) HWIF(drive)->ide_dma_begin(drive); return ide_started;}/**************************************************************************** * Block read functions. *//* * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector * buffer. Once the first sector is added, any subsequent sectors are * assumed to be continuous (until the buffer is cleared). For the first * sector added, SECTOR is its sector number. (SECTOR is then ignored until * the buffer is cleared.) */static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector, int sectors_to_transfer){ struct cdrom_info *info = drive->driver_data; /* Number of sectors to read into the buffer. */ int sectors_to_buffer = MIN (sectors_to_transfer, (SECTOR_BUFFER_SIZE >> SECTOR_BITS) - info->nsectors_buffered); char *dest; /* If we couldn't get a buffer, don't try to buffer anything... */ if (info->buffer == NULL) sectors_to_buffer = 0; /* If this is the first sector in the buffer, remember its number. */ if (info->nsectors_buffered == 0) info->sector_buffered = sector; /* Read the data into the buffer. */ dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE; while (sectors_to_buffer > 0) { HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE); --sectors_to_buffer; --sectors_to_transfer; ++info->nsectors_buffered; dest += SECTOR_SIZE; } /* Throw away any remaining data. */ while (sectors_to_transfer > 0) { char dum[SECTOR_SIZE]; HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum)); --sectors_to_transfer; }}/* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems. Returns 0 if everything's * ok; nonzero if the request has been terminated. */static inlineint cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason){ ireason &= 3; if (ireason == 2) return 0; if (ireason == 0) { /* Whoops... The drive is expecting to receive data from us! */ printk ("%s: cdrom_read_intr: " "Drive wants to transfer data the wrong way!\n", drive->name); /* Throw some data at the drive so it doesn't hang and quit this request. */ while (len > 0) { int dum = 0; HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum)); len -= sizeof (dum); } } else if (ireason == 1) { /* Some drives (ASUS) seem to tell us that status * info is available. just get it and ignore. */ (void) HWIF(drive)->INB(IDE_STATUS_REG); return 0; } else { /* Drive wants a command packet, or invalid ireason... */ printk ("%s: cdrom_read_intr: bad interrupt reason %d\n", drive->name, ireason); } cdrom_end_request(drive, 0); return -1;}/* * Interrupt routine. Called when a read request has completed. */static ide_startstop_t cdrom_read_intr (ide_drive_t *drive){ int stat; int ireason, len, sectors_to_transfer, nskip; struct cdrom_info *info = drive->driver_data; u8 lowcyl = 0, highcyl = 0; int i, dma = info->dma, dma_error = 0; ide_startstop_t startstop; struct request *rq = HWGROUP(drive)->rq; /* Check for errors. */ if (dma) { info->dma = 0;#ifdef CONFIG_ARCH_EP93XX dma_error = HWIF(drive)->ide_dma_end(drive);#else if ((dma_error = HWIF(drive)->ide_dma_end(drive))) HWIF(drive)->ide_dma_off(drive);#endif } if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; if (dma) { if (!dma_error) { for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; ide_cdrom_end_request(drive, 1); } return ide_stopped; } else#ifdef CONFIG_ARCH_EP93XX return ide_stopped;#else return DRIVER(drive)->error(drive, "dma error", stat);#endif } /* 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. */ if ((stat & DRQ_STAT) == 0) { /* If we're not done filling the current buffer, complain. Otherwise, complete the command normally. */ if (rq->current_nr_sectors > 0) { printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n", drive->name, rq->current_nr_sectors); cdrom_end_request(drive, 0); } else cdrom_end_request(drive, 1); return ide_stopped; } /* Check that the drive is expecting to do the same thing we are. */ if (cdrom_read_check_ireason (drive, len, ireason)) return ide_stopped; /* Assume that the drive will always provide data in multiples of at least SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */ if ((len % SECTOR_SIZE) != 0) { printk ("%s: cdrom_read_intr: Bad transfer size %d\n", drive->name, len); if (CDROM_CONFIG_FLAGS(drive)->limit_nframes) printk (" This drive is not supported by this version of the driver\n"); else { printk (" Trying to limit transfer sizes\n"); CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; } cdrom_end_request(drive, 0); return ide_stopped; } /* The number of sectors we need to read from the drive. */ sectors_to_transfer = len / SECTOR_SIZE; /* First, figure out if we need to bit-bucket any of the leading sectors. */ nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)), sectors_to_transfer); while (nskip > 0) { /* We need to throw away a sector. */ char dum[SECTOR_SIZE]; HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum)); --rq->current_nr_sectors; --nskip; --sectors_to_transfer; } /* Now loop while we still have data to read from the drive. */ while (sectors_to_transfer > 0) { int this_transfer; /* 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) cdrom_end_request(drive, 1); /* If the buffers are full, cache the rest of the data in our internal buffer. */ if (rq->current_nr_sectors == 0) { cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); sectors_to_transfer = 0; } else { /* Transfer data to the buffers. Figure out how many sectors we can transfer to the current buffer. */ this_transfer = MIN (sectors_to_transfer, rq->current_nr_sectors); /* Read this_transfer sectors into the current buffer. */ while (this_transfer > 0) { HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->nr_sectors; --rq->current_nr_sectors; ++rq->sector; --this_transfer; --sectors_to_transfer; } } } /* Done moving data! Wait for another interrupt. */ ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); return ide_started;}/* * Try to satisfy some of the current read request from our cached data. * Returns nonzero if the request has been completed, zero otherwise. */static int cdrom_read_from_buffer (ide_drive_t *drive){ struct cdrom_info *info = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; /* Can't do anything if there's no buffer. */ if (info->buffer == NULL) return 0; /* Loop while this request needs data and the next block is present in our cache. */ while (rq->nr_sectors > 0 && rq->sector >= info->sector_buffered && rq->sector < info->sector_buffered + info->nsectors_buffered) { if (rq->current_nr_sectors == 0) cdrom_end_request(drive, 1); memcpy (rq->buffer, info->buffer + (rq->sector - info->sector_buffered) * SECTOR_SIZE, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->current_nr_sectors; --rq->nr_sectors; ++rq->sector; } /* If we've satisfied the current request, terminate it successfully. */ if (rq->nr_sectors == 0) { cdrom_end_request(drive, 1); return -1; } /* Move on to the next buffer if needed. */ if (rq->current_nr_sectors == 0) cdrom_end_request(drive, 1); /* If this condition does not hold, then the kluge i use to represent the number of sectors to skip at the start of a transfer will fail. I think that this will never happen, but let's be paranoid and check. */ if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) && (rq->sector % SECTORS_PER_FRAME) != 0) { printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", drive->name, rq->sector); cdrom_end_request(drive, 0); return -1; } return 0;}/* * Routine to send a read packet command to the drive. * This is usually called directly from cdrom_start_read. * However, for drq_interrupt devices, it is called from an interrupt * when the drive is ready to accept the command. */static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -