返回列表 发帖

[站长原创] Linux设备驱动类型 - 块型设备驱动

[站长原创] Linux设备驱动类型 - 块型设备驱动

嵌入式开发联盟www.mcuos.com

Osboy站长原创

QQ:82475491

Mcuos.com@gmail.com


我们在字符型驱动程序的帖子中,提出了osboy的驱动编写观点1,回顾一下,下面我们用这个理论再次阐述块设备驱动的编写。

http://mcuos.com/thread-8514-1-1.html


Osboy观点1:一种类型的驱动程序都有一个固定的数据结构来代表,然后我们要做的事情就是初始化这个数据结构,然后通过一个API注册给内核,而对该设备进行读写等操作的函数在初始化这个结构体的过程中声明过了,我们需要针对相应设备的特性实现这些读写函数,这就是编写设备驱动我们需要做的事情,很简单吧?


(1)代表块型设备驱动的数据结构:gendisk


  1. struct gendisk {
  2.         /* major, first_minor and minors are input parameters only,
  3.          * don't use directly.  Use disk_devt() and disk_max_parts().
  4.          */
  5.         int major;                        /* major number of driver */
  6.         int first_minor;
  7.         int minors;                     /* maximum number of minors, =1 for
  8.                                          * disks that can't be partitioned. */

  9.         char disk_name[DISK_NAME_LEN];        /* name of major driver */
  10.         char *(*devnode)(struct gendisk *gd, mode_t *mode);

  11.         unsigned int events;                /* supported events */
  12.         unsigned int async_events;        /* async events, subset of all */

  13.         /* Array of pointers to partitions indexed by partno.
  14.          * Protected with matching bdev lock but stat and other
  15.          * non-critical accesses use RCU.  Always access through
  16.          * helpers.
  17.          */
  18.         struct disk_part_tbl __rcu *part_tbl;
  19.         struct hd_struct part0;

  20.         const struct block_device_operations *fops;
  21.         struct request_queue *queue;
  22.         void *private_data;

  23.         int flags;
  24.         struct device *driverfs_dev;  // FIXME: remove
  25.         struct kobject *slave_dir;

  26.         struct timer_rand_state *random;
  27.         atomic_t sync_io;                /* RAID */
  28.         struct disk_events *ev;
  29. #ifdef  CONFIG_BLK_DEV_INTEGRITY
  30.         struct blk_integrity *integrity;
  31. #endif
  32.         int node_id;
  33. };
复制代码


我们可以通过alloc_disk动态或者静态定义这个gendisk结构体。


(2)初始化这个数据结构


初始化代码类似于:


  1.                 disk->major = HD_MAJOR;
  2.                 disk->first_minor = drive << 6;
  3.                 disk->fops = &hd_fops;
  4.                 sprintf(disk->disk_name, "hd%c", 'a'+drive);
  5.                 disk->private_data = p;
  6.                 set_capacity(disk, p->head * p->sect * p->cyl);
  7.                 disk->queue = hd_queue;
  8.                 p->unit = drive;
复制代码


块设备驱动的初始化不如字符型那么简单,我们归纳为下面几个主要方面:


1)初始化注册设备号。

例子:disk->first_minor = drive << 6;

2)初始化block_device_operations结构体。

例子:disk->fops = &hd_fops;

3)初始化块设备容量,用set_capacity接口函数。

例子:set_capacity(disk, p->head * p->sect * p->cyl);

4)分配一个请求队列,而且使用:blk_init_queue来初始化这个队列。

例子:disk->queue = hd_queue;

           hd_queue = blk_init_queue(do_hd_request, &hd_lock);

do_hd_request就是请求队列具体的函数。


(3)把这个gendisk注册给内核

通过add_disk函数API把gendisk注册给内核。


(4)实现请求队列中的读写函数


  1. switch (rq_data_dir(req)) {
  2.                 case READ:
  3.                         hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
  4.                                 &read_intr);
  5.                         if (reset)
  6.                                 goto repeat;
  7.                         break;
  8.                 case WRITE:
复制代码


一般的套路都是实现do_hd_request请求队列函数,这个函数中主要实习的是根据rq_data_dir(req)来识别上层调用的是读,还是写操作,然后才去调用真正的读写函数,不过这个读写函数还是我们根据您的设备的特性实现的。


Osboy观点3:万变不离其宗,看似linux设备驱动程序架构庞大,难以理解,其实概括抽象一下无非就是字符型,块型驱动而已,而且他们的编写就是那么简单的几步骤。任何基于字符型,和块型的设备驱动,都是上面osboy说的那几步,绝对不会有例外。

分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友

师傅,我现在有一个很大的问题,我看不懂上面的代码!

TOP

师傅,我现在有一个很大的问题,我看不懂上面的代码!
linzhaodejia 发表于 2012-11-8 09:41



   我这个帖子哪是要你看代码,是要大家明白思想。

TOP

回复 2# linzhaodejia


   我觉得能看懂代码,写出代码,差不多可以出师了

TOP

返回列表
网页右侧QQ悬浮滚动在线客服
网页右侧QQ悬浮滚动在线客服