• 驱动08.块设备驱动程序


    1 块设备的概述

      linux支持的两种重要的设备类型分别是字符设备和块设备,块设备可以随机地以固定大小的块传送数据。与字符设备相比,块设备有以下几个特殊之处:

      (1)块设备可以从数据的任何位置进行访问

      (2)块数据总是以固定长度进行传输,即便请求的这是一个字节

      (3)对块设备的访问有大量的缓存。当进行读时,如果已经缓存了,就直接使用缓存中的数据,而不再读设备,对于写也通过缓存来进行延迟处理。

      在块系统中,数据块指的是固定大小的数据,该固定大小由内核规定,通常是4096个字节。与数据块对应的是扇区,它是由设备硬件所决定的一个块,其大小取决于硬件,常见的硬件的扇区大多都是512个字节。数据块的大小都是扇区大小的整数倍。

    2 对比之前的字符设备驱动程序的区别;

    app:open  read   write

    块: drv_open drv_read drv_write

           硬件

    如果按照操作字符设备的那套方法来操作块设备,效率低,且容易损坏仪器。

    块设备的框架:

    app:      open,read,write "1.txt"
    ---------------------------------------------  文件的读写
    文件系统: vfat, ext2, ext3, yaffs2, jffs2      (把文件的读写转换为扇区的读写)
    -----------------ll_rw_block-----------------  扇区的读写
                           1. 把"读写"放入队列
                           2. 调用队列的处理函数(优化/调顺序/合并)
                块设备驱动程序     
    ---------------------------------------------
    硬件:        硬盘,flash

    3 分析ll_rw_block函数

        ll_rw_block
            for (i = 0; i < nr; i++) {
                struct buffer_head *bh = bhs[i];
                submit_bh(rw, bh);
                    struct bio *bio; // 使用bh来构造bio (block input/output)
                    submit_bio(rw, bio);
                        // 通用的构造请求: 使用bio来构造请求(request)
                        generic_make_request(bio);
                            __generic_make_request(bio);
                                request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列  
                                
                                // 调用队列的"构造请求函数"
                                ret = q->make_request_fn(q, bio);
                                        // 默认的函数是__make_request
                                        __make_request
                                            // 先尝试合并
                                            elv_merge(q, &req, bio);
                                            
                                            // 如果合并不成,使用bio构造请求
                                            init_request_from_bio(req, bio);
                                            
                                            // 把请求放入队列
                                            add_request(q, req);
                                            
                                            // 执行队列
                                            __generic_unplug_device(q);
                                                    // 调用队列的"处理函数"
                                                    q->request_fn(q);

    4 怎么写块设备驱动程序呢?
      1. 分配gendisk: alloc_disk
      2. 设置
      2.1 分配/设置队列: request_queue_t  // 它提供读写能力
        blk_init_queue
      2.2 设置gendisk其他信息             // 它提供属性: 比如容量
      3. 注册: add_disk
    参考:driverslockxd.c和driverslockz2ram.c
    --------------------------------------------------------------编辑于2017-01-13 01:03:00

      1 /*参考:driverslockz2ram.c*/
      2 
      3 
      4 #include <linux/module.h>
      5 #include <linux/errno.h>
      6 #include <linux/interrupt.h>
      7 #include <linux/mm.h>
      8 #include <linux/fs.h>
      9 #include <linux/kernel.h>
     10 #include <linux/timer.h>
     11 #include <linux/genhd.h>
     12 #include <linux/hdreg.h>
     13 #include <linux/ioport.h>
     14 #include <linux/init.h>
     15 #include <linux/wait.h>
     16 #include <linux/blkdev.h>
     17 #include <linux/blkpg.h>
     18 #include <linux/delay.h>
     19 #include <linux/io.h>
     20 
     21 #include <asm/system.h>
     22 #include <asm/uaccess.h>
     23 #include <asm/dma.h>
     24 
     25 
     26 #define RAMBLOCK_SIZE (1024*1024)
     27 #define DEVICE_NAME "ramblock"
     28 
     29 static DEFINE_SPINLOCK(ramblock_lock);
     30 
     31 static struct gendisk *ramblock_gendisk;
     32 static int major;
     33 static struct request_queue *ramblock_queue;
     34 static unsigned char *ramblock_buf;
     35 
     36 static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
     37 {
     38     geo->heads = 2;
     39     geo->cylinders = 32;
     40     geo->sectors = RAMBLOCK_SIZE/2/32/512;
     41     return 0;
     42 }
     43 
     44 
     45 static struct block_device_operations ramblock_fops = {
     46     .owner    = THIS_MODULE,
     47     .getgeo    = ramblock_getgeo,
     48 };
     49 
     50 static void do_ramblock_request(request_queue_t *q)
     51 {    
     52     struct request *req;
     53     if((req = elv_next_request(q)) != NULL)
     54     {
     55         unsigned long offset = req->sector <<9;
     56         unsigned long len = req->current_nr_sectors << 9;
     57 
     58         if (rq_data_dir(req) == READ)
     59         {
     60             memcpy(req->buffer, ramblock_buf+offset, len);
     61         }
     62         else
     63         {
     64             memcpy(ramblock_buf+offset, req->buffer, len);
     65         }
     66         end_request(req, 1);
     67             
     68     }
     69 
     70 
     71 }
     72 
     73 static int ramblock_init(void)
     74 {    
     75     ramblock_gendisk = alloc_disk(16);
     76 
     77     ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);
     78        ramblock_gendisk->queue = ramblock_queue;
     79 
     80 
     81     major = register_blkdev(0, DEVICE_NAME);
     82         ramblock_gendisk->major = major;
     83         ramblock_gendisk->first_minor = 0;
     84         ramblock_gendisk->fops = &ramblock_fops;
     85         sprintf(ramblock_gendisk->disk_name, "ramblock");
     86     set_capacity(ramblock_gendisk, RAMBLOCK_SIZE / 512);
     87 
     88     ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
     89         add_disk(ramblock_gendisk);
     90 
     91 
     92     return 0;
     93 }
     94 
     95 static void ramblock_exit(void)
     96 {
     97     unregister_blkdev(major, DEVICE_NAME);
     98     del_gendisk(ramblock_gendisk);
     99     put_disk(ramblock_gendisk);
    100     blk_cleanup_queue(ramblock_queue);
    101     
    102     kfree(ramblock_buf);
    103     
    104     
    105 }
    106 
    107 module_init(ramblock_init);
    108 module_exit(ramblock_exit);
    109 MODULE_LICENSE("GPL");
    ramblock.c

    --------------------------------------------------------------编辑于2017-01-13 14:34:44

  • 相关阅读:
    (48)zabbix报警媒介:自定义脚本Custom alertscripts
    Centos7下cratedb数据导入导出copy to copy from
    CentOS7下cratedb备份及恢复(快照)
    Centos7下mysql5.7.22主从配置
    Centos7安装配置MySQL5.7
    Centos7安装配置iptable
    Centos7 LNMP 一键安装
    Centos7防范SYN
    Centos7安装RabbitMQ解决Erlang依赖报错
    centos7安装配置zabbix4.0
  • 原文地址:https://www.cnblogs.com/Lwd-linux/p/6280459.html
Copyright © 2020-2023  润新知