puppy居
puppy居士
posts - 41,comments - 27,trackbacks - 0

Linux块设备层分析(3)

R.wen


以上均是IDE总线上设备的通用接口,直到do_request开始才执行特定设备的驱动,如CDHD, floppyIDE设备。我们来看一下ide-disk

1、 首先是设备的初始化操作。

IDE设备接口

static ide_driver_t idedisk_driver = {

       .gen_driver = {

              .owner           = THIS_MODULE,

              .name             = "ide-disk",

              .bus        = &ide_bus_type,

       },

       .probe                   = ide_disk_probe,

       .remove                 = ide_disk_remove,

       .shutdown             = ide_device_shutdown,

       .version          = IDEDISK_VERSION,

       .media                   = ide_disk,

       .supports_dsc_overlap   = 0,

       .do_request            = ide_do_rw_disk,

       .end_request          = ide_end_request,

       .error                    = __ide_error,

       .abort                    = __ide_abort,

       .proc                     = idedisk_proc,

};

static struct block_device_operations idedisk_ops = {

       .owner           = THIS_MODULE,

       .open             = idedisk_open,

       .release    = idedisk_release,

       .ioctl              = idedisk_ioctl,

       .getgeo           = idedisk_getgeo,

       .media_changed     = idedisk_media_changed,

       .revalidate_disk= idedisk_revalidate_disk

};

//设备注册

static int __init idedisk_init(void)

{

       return driver_register(&idedisk_driver.gen_driver);

}

//这个probe函数是在设备注册时由驱动模型去执行

static int ide_disk_probe(ide_drive_t *drive)

{

       struct ide_disk_obj *idkp;

       struct gendisk *g;

       idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);

      

//分配一个gendisk结构

g = alloc_disk_node(1 << PARTN_BITS,

                     hwif_to_node(drive->hwif));

       ide_init_disk(g, drive);

       //用上面的结构注册设备

       ide_register_subdriver(drive, &idedisk_driver);

       kref_init(&idkp->kref);

       //一些初始化操作

       idkp->drive = drive;

       idkp->driver = &idedisk_driver;

       idkp->disk = g;

       g->private_data = &idkp->driver;

       drive->driver_data = idkp;

       idedisk_setup(drive);

       g->minors = 1 << PARTN_BITS;

       g->driverfs_dev = &drive->gendev;

       g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;

       set_capacity(g, idedisk_capacity(drive));

       g->fops = &idedisk_ops;

       add_disk(g); //插入设备,至此,该设备可用

       return 0;

}

2、 处理IDE总线发来的请求

由上可以看到,IDE总线驱动调用设备的do_request()去处理这个请求,我们在上面的注册中可以看到。在ide-disk里,它是ide_do_rw_disk()

/*

* 268435455 == 137439 MB or 28bit limit

* 320173056 == 163929 MB or 48bit addressing

* 1073741822 == 549756 MB or 48bit addressing fake drive

*/

static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)

{

       ide_hwif_t *hwif = HWIF(drive);

……

       if (hwif->rw_disk)

       hwif->rw_disk(drive, rq);

       return __ide_do_rw_disk(drive, rq, block);

}

//以下就是特定硬盘设备的驱动了,因为我们只关心块设备驱动编程的框架,所以就不深入进去了。

/*

* __ide_do_rw_disk() issues READ and WRITE commands to a disk,

* using LBA if supported, or CHS otherwise, to address sectors.

*/

static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block)

{

       ide_hwif_t *hwif    = HWIF(drive);

       unsigned int dma    = drive->using_dma;

       u8 lba48         = (drive->addressing == 1) ? 1 : 0;

       task_ioreg_t command   = WIN_NOP;

       ata_nsector_t         nsectors;

       nsectors.all            = (u16) rq->nr_sectors;

       if (hwif->no_lba48_dma && lba48 && dma) {

              if (block + rq->nr_sectors > 1ULL << 28)

                     dma = 0;

              else

                     lba48 = 0;

       }

       if (drive->select.b.lba) {

              if (lba48) {

                     ……

              } else {

              ……

              }

       } else {

              ……

       }

       if (dma) {

              ……

              /* fallback to PIO */

              ide_init_sg_cmd(drive, rq);

       }

       if (rq_data_dir(rq) == READ) {

              if (drive->mult_count) {

                     hwif->data_phase = TASKFILE_MULTI_IN;

                     command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;

              } else {

                     hwif->data_phase = TASKFILE_IN;

                     command = lba48 ? WIN_READ_EXT : WIN_READ;

              }

              ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);

              return ide_started;

       } else {

       ……

              return pre_task_out_intr(drive, rq);

       }

}

3、 块设备驱动小结

我们由上看到, 块设备驱动编程的主要工作包括分配并初始化一个gendisk结构,分配并初始化一个请求队列,请求处理函数的编写(request_fn),还有中断的处理等等。但具体到不同的设备,实现又有一些出入,我们在上面看到的IDE设备,它大部分工作都是在IDE总线级上实现了,它做了许多繁琐但必要的工作,并向下层特定设备提供统一的接口,这样就大大简化了块设备驱动的编写过程。

       有兴趣可以参考一下内核ramdisk的实现。

posted on 2008-08-22 15:19 puppy 阅读(479) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。