Linux内核在缺省配置下最多支持10个IDE接口,IDE接口用ide_hwif_t结构来描述,每个IDE接口具有一对主-从驱动器接口,它们用ide_drive_t结构来描述,每个驱动器接口可接不同种类的IDE设备,如IDE硬盘,光驱等,它们用ide_driver_t结构来描述.
每个驱动器接口包含一个命令请求队列,用request_queue_t结构来描述,具体的请求用request结构来描述.
多个IDE驱动器可以共享一个中断,共享同一中断的驱动器形成一个组,用ide_hwgroup_t结构来描述.ide_intr()是所有的ide驱动器所共用的硬件中断入口,对之对应的ide_hwgroup_t指针将作为dev_id传递给ide_intr.
每次在读写某个驱动器之前,需要用ide_set_handler()来设置ide_intr将要调用的中断函数指针.中断产生以后,该函数指针被自动清除.
do_rw_disk(drive,rq,block) 从逻辑扇区号block开始向IDE硬盘驱动器drive写入rq所描述的内容.
以下是硬盘PIO传输模式的有关代码.
; drivers/ide/ide-disk.c
static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
if (drive->select.b.lba) { 如果是逻辑块寻址模式
OUT_BYTE(block,IDE_SECTOR_REG);
OUT_BYTE(block>>=8,IDE_LCYL_REG);
OUT_BYTE(block>>=8,IDE_HCYL_REG);
OUT_BYTE(((block>>&0x0f)|drive->select.all,IDE_SELECT_REG);
} else {
unsigned int sect,head,cyl,track;
track = block / drive->sect;
sect = block % drive->sect + 1;
OUT_BYTE(sect,IDE_SECTOR_REG);
head = track % drive->head;
cyl = track / drive->head;
OUT_BYTE(cyl,IDE_LCYL_REG);
OUT_BYTE(cyl>>8,IDE_HCYL_REG);
OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
}
if (rq->cmd == READ) {{
ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); WAIT_CMD为10秒超时
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
return ide_started;
}
if (rq->cmd == WRITE) {
ide_startstop_t startstop;
OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
drive->mult_count ? "MULTWRITE" : "WRITE");
return startstop;
}
if (!drive->unmask)
__cli(); /* local CPU only */
if (drive->mult_count) { 如果允许多扇区传送
ide_hwgroup_t *hwgroup = HWGROUP(drive);
/*
* Ugh.. this part looks ugly because we MUST set up
* the interrupt handler before outputting the first block
* of data to be written. If we hit an error (corrupted buffer list)
* in ide_multwrite(), then we need to remove the handler/timer
* before returning. Fortunately, this NEVER happens (right?).
*
* Except when you get an error it seems...
*/
hwgroup->wrq = *rq; /* scratchpad */
ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
if (ide_multwrite(drive, drive->mult_count)) {
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
hwgroup->handler = NULL;
del_timer(&hwgroup->timer);
spin_unlock_irqrestore(&io_request_lock, flags);
return ide_stopped;
}
} else {
ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); 写入一扇区SECTOR_WORDS=512/4
}
return ide_started;
}
printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
ide_end_request(0, HWGROUP(drive));
return ide_stopped;
}
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
unsigned int timeout, ide_expiry_t *expiry)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
spin_lock_irqsave(&io_request_lock, flags);
if (hwgroup->handler != NULL) {
printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
drive->name, hwgroup->handler, handler);
}
hwgroup->handler = handler;
hwgroup->expiry = expiry;
hwgroup->timer.expires = jiffies + timeout;
add_timer(&hwgroup->timer);
spin_unlock_irqrestore(&io_request_lock, flags);
}
static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
if (drive->bswap) {
idedisk_bswap_data(buffer, wcount);
ide_output_data(drive, buffer, wcount);
idedisk_bswap_data(buffer, wcount);
} else
ide_output_data(drive, buffer, wcount);
}
void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
byte io_32bit = drive->io_32bit;
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
unsigned long flags;
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
do_vlb_sync(IDE_NSECTOR_REG);
outsl(IDE_DATA_REG, buffer, wcount);
__restore_flags(flags); /* local CPU only */
} else
#endif /* SUPPORT_VLB_SYNC */
outsl(IDE_DATA_REG, buffer, wcount);
} else {
#if SUPPORT_SLOW_DATA_PORTS
if (drive->slow) {
unsigned short *ptr = (unsigned short *) buffer;
while (wcount--) {
outw_p(*ptr++, IDE_DATA_REG);
outw_p(*ptr++, IDE_DATA_REG);
}
} else
#endif /* SUPPORT_SLOW_DATA_PORTS */
outsw(IDE_DATA_REG, buffer, wcount<<1);
}
}
int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
{
ide_hwgroup_t *hwgroup= HWGROUP(drive);
/*
* This may look a bit odd, but remember wrq is a copy of the
* request not the original. The pointers are real however so the
* bh's are not copies. Remember that or bad stuff will happen
*
* At the point we are called the drive has asked us for the
* data, and its our job to feed it, walking across bh boundaries
* if need be.
*/
struct request *rq = &hwgroup->wrq;
do {
unsigned long flags;
unsigned int nsect = rq->current_nr_sectors;
if (nsect > mcount)
nsect = mcount;
mcount -= nsect;
; 这时mcount为剩余的必需传送的扇区数
idedisk_output_data(drive, rq->buffer, nsect<<7);
spin_lock_irqsave(&io_request_lock, flags); /* Is this really necessary? */
#ifdef CONFIG_BLK_DEV_PDC4030
rq->sector += nsect;
#endif
if (((long)(rq->nr_sectors -= nsect)) <= 0)
spin_unlock_irqrestore(&io_request_lock, flags);
break;
}
if ((rq->current_nr_sectors -= nsect) == 0) {
if ((rq->bh = rq->bh->b_reqnext) != NULL) {{
rq->current_nr_sectors = rq->bh->b_size>>9;
rq->buffer = rq->bh->b_data;
} else {
spin_unlock_irqrestore(&io_request_lock, flags);
printk("%s: buffer list corrupted (%ld, %ld, %d)\n",
drive->name, rq->current_nr_sectors,
rq->nr_sectors, nsect);
ide_end_request(0, hwgroup);
return 1;
}
} else {
/* Fix the pointer.. we ate data */
rq->buffer += nsect << 9;
}
spin_unlock_irqrestore(&io_request_lock, flags);
} while (mcount);
return 0;
}
; IDE接口共用中断入口
void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
ide_hwif_t *hwif;
ide_drive_t *drive;
ide_handler_t *handler;
ide_startstop_t startstop;
spin_lock_irqsave(&io_request_lock, flags);
hwif = hwgroup->hwif;
if (!ide_ack_intr(hwif)) {
spin_unlock_irqrestore(&i
IDE硬盘驱动器读写过程
最新推荐文章于 2021-05-09 21:55:21 发布