📄 ide-cd.c
字号:
info->dma = 0; dma_error = HWIF(drive)->ide_dma_end(drive); } if (cdrom_decode_status(drive, 0, &stat)) return ide_stopped; /* * using dma, transfer is complete now */ if (dma) { if (dma_error) { printk(KERN_ERR "ide-cd: dma error\n"); ide_dma_off(drive); return ide_error(drive, "dma error", stat); } end_that_request_chunk(rq, 1, rq->data_len); rq->data_len = 0; goto end_request; } /* * ok we fall to pio :/ */ ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); len = lowcyl + (256 * highcyl); thislen = rq->data_len; if (thislen > len) thislen = len; /* * If DRQ is clear, the command has completed. */ if ((stat & DRQ_STAT) == 0) goto end_request; /* * check which way to transfer data */ if (rq_data_dir(rq) == WRITE) { /* * write to drive */ if (cdrom_write_check_ireason(drive, len, ireason)) return ide_stopped; xferfunc = HWIF(drive)->atapi_output_bytes; } else { /* * read from drive */ if (cdrom_read_check_ireason(drive, len, ireason)) return ide_stopped; xferfunc = HWIF(drive)->atapi_input_bytes; } /* * transfer data */ while (thislen > 0) { int blen = blen = rq->data_len; char *ptr = rq->data; /* * bio backed? */ if (rq->bio) { ptr = bio_data(rq->bio); blen = bio_iovec(rq->bio)->bv_len; } if (!ptr) { printk(KERN_ERR "%s: confused, missing data\n", drive->name); break; } if (blen > thislen) blen = thislen; xferfunc(drive, ptr, blen); thislen -= blen; len -= blen; rq->data_len -= blen; if (rq->bio) end_that_request_chunk(rq, 1, blen); else rq->data += blen; } /* * pad, if necessary */ if (len > 0) { while (len > 0) { int pad = 0; xferfunc(drive, &pad, sizeof(pad)); len -= sizeof(pad); } } BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL); return ide_started;end_request: spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); end_that_request_last(rq, 1); HWGROUP(drive)->rq = NULL; spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped;}static ide_startstop_t cdrom_write_intr(ide_drive_t *drive){ int stat, ireason, len, sectors_to_transfer, uptodate; struct cdrom_info *info = drive->driver_data; int dma_error = 0, dma = info->dma; u8 lowcyl = 0, highcyl = 0; struct request *rq = HWGROUP(drive)->rq; /* Check for errors. */ if (dma) { info->dma = 0; dma_error = HWIF(drive)->ide_dma_end(drive); if (dma_error) { printk(KERN_ERR "%s: DMA write error\n", drive->name); ide_dma_off(drive); } } if (cdrom_decode_status(drive, 0, &stat)) return ide_stopped; /* * using dma, transfer is complete now */ if (dma) { if (dma_error) return ide_error(drive, "dma error", stat); ide_end_request(drive, 1, rq->nr_sectors); return ide_stopped; } /* Read the interrupt reason and the transfer length. */ ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; 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 writing, complain. * Otherwise, complete the command normally. */ uptodate = 1; if (rq->current_nr_sectors > 0) { printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n", drive->name, __FUNCTION__, rq->current_nr_sectors); uptodate = 0; } cdrom_end_request(drive, uptodate); return ide_stopped; } /* Check that the drive is expecting to do the same thing we are. */ if (cdrom_write_check_ireason(drive, len, ireason)) return ide_stopped; sectors_to_transfer = len / SECTOR_SIZE; /* * now loop and write out the data */ while (sectors_to_transfer > 0) { int this_transfer; if (!rq->current_nr_sectors) { printk(KERN_ERR "%s: %s: confused, missing data\n", drive->name, __FUNCTION__); break; } /* * Figure out how many sectors we can transfer */ this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors); while (this_transfer > 0) { HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->nr_sectors; --rq->current_nr_sectors; ++rq->sector; --this_transfer; --sectors_to_transfer; } /* * current buffer complete, move on */ if (rq->current_nr_sectors == 0 && rq->nr_sectors) cdrom_end_request(drive, 1); } /* re-arm handler */ ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL); return ide_started;}static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq;#if 0 /* the immediate bit */ rq->cmd[1] = 1 << 3;#endif rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);}static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq){ struct cdrom_info *info = drive->driver_data; struct gendisk *g = info->disk; unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS; /* * writes *must* be hardware frame aligned */ if ((rq->nr_sectors & (sectors_per_frame - 1)) || (rq->sector & (sectors_per_frame - 1))) { cdrom_end_request(drive, 0); return ide_stopped; } /* * disk has become write protected */ if (g->policy) { cdrom_end_request(drive, 0); return ide_stopped; } 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!) frame aligned */ info->dma = drive->using_dma ? 1 : 0; info->devinfo.media_written = 1; /* Start sending the write request to the drive. */ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);}static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; if (!rq->timeout) rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);}static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq){ struct cdrom_info *info = drive->driver_data; rq->cmd_flags |= REQ_QUIET; info->dma = 0; /* * sg request */ if (rq->bio) { int mask = drive->queue->dma_alignment; unsigned long addr = (unsigned long) page_address(bio_page(rq->bio)); info->dma = drive->using_dma; /* * check if dma is safe * * NOTE! The "len" and "addr" checks should possibly have * separate masks. */ if ((rq->data_len & 15) || (addr & mask)) info->dma = 0; } /* Start sending the command to the drive. */ return cdrom_start_packet_command(drive, rq->data_len, cdrom_do_newpc_cont);}/**************************************************************************** * cdrom driver request routine. */static ide_startstop_tide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block){ ide_startstop_t action; struct cdrom_info *info = drive->driver_data; if (blk_fs_request(rq)) { if (CDROM_CONFIG_FLAGS(drive)->seeking) { unsigned long elapsed = jiffies - info->start_seek; int stat = HWIF(drive)->INB(IDE_STATUS_REG); if ((stat & SEEK_STAT) != SEEK_STAT) { if (elapsed < IDECD_SEEK_TIMEOUT) { ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped; } printk (KERN_ERR "%s: DSC timeout\n", drive->name); } CDROM_CONFIG_FLAGS(drive)->seeking = 0; } if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) { action = cdrom_start_seek(drive, block); } else { if (rq_data_dir(rq) == READ) action = cdrom_start_read(drive, block); else action = cdrom_start_write(drive, rq); } info->last_block = block; return action; } else if (rq->cmd_type == REQ_TYPE_SENSE || rq->cmd_type == REQ_TYPE_ATA_PC) { return cdrom_do_packet_command(drive); } else if (blk_pc_request(rq)) { return cdrom_do_block_pc(drive, rq); } else if (blk_special_request(rq)) { /* * right now this can only be a reset... */ cdrom_end_request(drive, 1); return ide_stopped; } blk_dump_rq_flags(rq, "ide-cd bad flags"); cdrom_end_request(drive, 0); 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_OFFSE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -