块设备驱动系统架构和简单设计

xiaoxiao2021-02-28  13

1.块设备概念 块设备是指只能以块(512Byte)为单位进行访问的设备, 块大小一般是512个字节的整数倍。常见的块 设备包括硬件,SD卡,光盘等。 2.快速体验 insmod simple-blk.ko ls /dev/simp_blkdev0 mkfs.ext3 /dev/simp_blk0 mkdir –p /mnt/blk mount /dev/simp_blk0 /mnt/blk cp /etc/init.d/* /mnt/blk ls /mnt/blk umount /mnt/blk ls /mnt/blk 3.块设备驱动系统架构  VFS是对各种具体文件系统的一种封装 ,为 用户程序访问文件提供 统一的接口 4.系统架构-Cache 当用户发起文件访问请求的时候,首先会到 Disk Cache中寻找文件是否被缓存了,如果 在cache中,则直接从cache中读取。 如果数据不在缓存中,就必须要到具体的文 件系统中读取数据了。 5.Mapping Layer(映射层、FS文件系统) 1. 首先确定文件系统的block size,然后计算 所请求的数据包含多少个block。 2. 调用具体文件系统的函数来访问文件的 inode 结构,确定所请求的数据在磁盘上的地址。 6.  Generic Block Layer Linux内核把把块设备看作是由若干个扇区组 成的数据空间。上层的读写请求在通用块层被构造成一个或多个bio结构。 7.  I/O Scheduler Layer I/O调度层负责采用某种算法(如:电梯调度 算法)将I/O操作进行排序。 8.  I/O Scheduler Layer 电梯调度算法的基本原则:如果电梯现在朝 上运动,如果当前楼层的上方和下方都有请 求,则先响应所有上方的请求,然后才向下 响应下方的请求;如果电梯向下运动,则刚 好相反。 9. 块设备驱动 在块系统架构的最底层,由块设备驱动根据 排序好的请求,对硬件进行数据访问。 10.块设备驱动实例分析 #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/timer.h> #include <linux/types.h> /* size_t */ #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/kdev_t.h> #include <linux/vmalloc.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> /* invalidate_bdev */ #include <linux/bio.h> MODULE_LICENSE("Dual BSD/GPL"); static int major = 0; static int sect_size = 512; static int nsectors = 1024; /* * The internal representation of our device. */ struct blk_dev{          int size; /* Device size in sectors */          u8 *data; /* The data array */          struct request_queue *queue; /* The device request queue */          struct gendisk *gd; /* The gendisk structure */ }; struct blk_dev *dev; /* * Handle an I/O request, in sectors. */ static void blk_transfer(struct blk_dev *dev, unsigned long sector,    unsigned long nsect, char *buffer, int write)                                                                                    //扇区访问函数 { unsigned long offset = sector*sect_size; unsigned long nbytes = nsect*sect_size; if ((offset + nbytes) > dev->size) {    printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);    return; } if (write)    memcpy(dev->data + offset, buffer, nbytes);                                                                                       //对内存读写 else    memcpy(buffer, dev->data + offset, nbytes); } /* * The simple form of the request function. */ static void blk_request(struct request_queue *q)                                                                                      //实现读写请求处理函数 { struct request *req; req = blk_fetch_request(q);                                                                                                           //从队列中取出一个请求 while (req != NULL) {    struct blk_dev *dev = req->rq_disk->private_data;    blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));        if(!__blk_end_request_cur(req, 0))                                                                                                 //判断请求队列是否为空    {     req = blk_fetch_request(q);                                                                                                       //嵌套处理    } } } /* * The device operations structure. */ static struct block_device_operations blk_ops = { .owner = THIS_MODULE, }; /* * Set up our internal device. */ static void setup_device() { /* * Get some memory. */ dev->size = nsectors*sect_size;                                                                                  //获取设备大小 dev->data = vmalloc(dev->size);                                                                                  //获取数据指针 if (dev->data == NULL) {    printk (KERN_NOTICE "vmalloc failure.\n");    return; }    dev->queue = blk_init_queue(blk_request, NULL);                                                               //请求队列初始化,blk_request是处理上层传下来的请求的    if (dev->queue == NULL)     goto out_vfree; blk_queue_logical_block_size(dev->queue, sect_size);                                                             //指明扇区大小 dev->queue->queuedata = dev; /* * And the gendisk structure. */ dev->gd = alloc_disk(1);                                                                                         //为块设备分配gendisk结构,并初始化 if (! dev->gd) {    printk (KERN_NOTICE "alloc_disk failure\n");    goto out_vfree; } dev->gd->major = major; dev->gd->first_minor = 0; dev->gd->fops = &blk_ops; dev->gd->queue = dev->queue; dev->gd->private_data = dev; sprintf (dev->gd->disk_name, "simp_blk%d", 0); set_capacity(dev->gd, nsectors*(sect_size/sect_size)); add_disk(dev->gd);                                                                                               //注册块设备 return; out_vfree: if (dev->data)    vfree(dev->data); } static int __init blk_init(void) { /* * Get registered. */ major = register_blkdev(major, "blk");                                                                  //注册块设备驱动,major若为0会自动分配 if (major <= 0) {    printk(KERN_WARNING "blk: unable to get major number\n");    return -EBUSY; } dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);                                                      //分配一个blk_dev空间 if (dev == NULL)    goto out_unregister;    setup_device();                                                                                      //调用函数       return 0; out_unregister: unregister_blkdev(major, "sbd"); return -ENOMEM; } static void blk_exit(void) {    if (dev->gd) {     del_gendisk(dev->gd);     put_disk(dev->gd);    }    if (dev->queue)     blk_cleanup_queue(dev->queue);    if (dev->data)     vfree(dev->data);    unregister_blkdev(major, "blk"); kfree(dev); } module_init(blk_init); module_exit(blk_exit); 11、 简单块设备驱动设计 #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/blkdev.h> #include <linux/bio.h> #include <linux/string.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/genhd.h> MODULE_LICENSE("GPL"); static int major = 0; static int sect_size = 512; static int nsectors = 1024; struct blk_dev {     int size;     u8 *data;     struct request_queue *queue;     struct gendisk *gd; }; struct blk_dev *dev; static void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect,char *buffer, int write) {     unsigned long offset = sector * sect_size;     unsigned long nbyte = nsect * sect_size;          if((offset + nbyte) > dev->size)     {         printk(KERN_NOTICE"Beyond-end write (%ld %ld)\n", offset, nbyte);     return;     }     if(write)     {         memcpy(dev->data + offset, buffer, nbyte);     }     else     {         memcpy(buffer, dev->data + offset, nbyte);     } } void blk_request(struct request_queue *q) {     struct request *req;     req = blk_fetch_request(q);     while(req != NULL)     {         struct blk_dev *dev = req->rq_disk->private_data;         //处理该请求     blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));          if(!__blk_end_request_cur(req, 0))      req = blk_fetch_request(q);     } } static struct block_device_operations blk_ops = {     .owner = THIS_MODULE, }; static void setup_device(void) {     dev->size = nsectors * sect_size;     dev->data = vmalloc(dev->size);     if(dev->data == NULL) {         printk(KERN_NOTICE "vmalloc failure.\n");     return;     }          dev->queue = blk_init_queue(blk_request, NULL);     if(dev->queue == NULL)     {         goto out_vfree;     }          blk_queue_logical_block_size(dev->queue, sect_size);     dev->queue->queuedata = dev;     dev->gd = alloc_disk(1);     if(!dev->gd)     {         printk(KERN_NOTICE "alloc_disk failure\n");     goto out_vfree;     }     dev->gd->major = major;     dev->gd->first_minor = 0;     dev->gd->fops = &blk_ops;     dev->gd->queue = dev->queue;     dev->gd->private_data = dev;     sprintf(dev->gd->disk_name, "simp_blk%d", 0);     set_capacity(dev->gd, nsectors);     add_disk(dev->gd);     return; out_vfree:     if(dev->data)         vfree(dev->data); } static int __init blk_init(void) {     major = register_blkdev(0, "blk");     if(major <= 0)     {         printk(KERN_WARNING "register blk dev fail!\n");     return -EBUSY;     }     dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);     if(dev == NULL)         goto out_unregister;     setup_device();     return 0; out_unregister:     unregister_blkdev(major, "sbd");     return -ENOMEM; } static void blk_exit(void) {     del_gendisk(dev->gd);     blk_cleanup_queue(dev->queue);     vfree(dev->data);     unregister_blkdev(major, "blk");     kfree(dev); } module_init(blk_init); module_exit(blk_exit); 错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。 第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久 <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 阅读(68) | 评论(0) | 转发(0) | 0

上一篇:LCD驱动程序架构和分析

下一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计

相关热门文章 SHTML是什么_SSI有什么用...查看linux中某个端口(port)...卡尔曼滤波的原理说明...shell中字符串操作关于java中的“错误:找不到或... 给主人留下些什么吧!~~ 评论热议
转载请注明原文地址: https://www.6miu.com/read-450133.html

最新回复(0)