Linux-Flash驱动(2)-块设备驱动实例分析
来源:互联网 发布:福建省应急管理网络 编辑:程序博客网 时间:2024/05/23 19:20
在上一节课中,我们在内存中划分出512kB作为一个块设备,并对它实现读写的操作。现在我们来具体分析这段代码。
#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);elsememcpy(buffer, dev->data + offset, nbytes);}/** 读写请求处理函数*/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);}}}/** Transfer a single BIO.*/static int blk_xfer_bio(struct blk_dev *dev, struct bio *bio){int i;struct bio_vec *bvec;sector_t sector = bio->bi_sector;/* Do each segment independently. */bio_for_each_segment(bvec, bio, i) {char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);blk_transfer(dev, sector, bio_cur_bytes(bio)>>9 /* in sectors */, buffer, bio_data_dir(bio) == WRITE);sector += bio_cur_bytes(bio)>>9; /* in sectors */__bio_kunmap_atomic(bio, KM_USER0);}return 0; /* Always "succeed" */}/** Transfer a full request.*/static int blk_xfer_request(struct blk_dev *dev, struct request *req){struct bio *bio;int nsect = 0; __rq_for_each_bio(bio, req) {blk_xfer_bio(dev, bio);nsect += bio->bi_size/sect_size;}return nsect;}/** The device operations structure.*/static struct block_device_operations blk_ops = {.owner = THIS_MODULE,};/** Set up our internal device.*/static void setup_device(){//计算设备大小dev->size = nsectors*sect_size;dev->data = vmalloc(dev->size);if (dev->data == NULL) {printk (KERN_NOTICE "vmalloc failure.\n");return;}//把块设备放入请求队列中,blk_request用于指明处理这个请求的函数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;//分配gendisk结构dev->gd = alloc_disk(1);if (! dev->gd) {printk (KERN_NOTICE "alloc_disk failure\n");goto out_vfree;}/*初始化alloc_disk*/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){/** 注册块设备,申请主设备号*/major = register_blkdev(major, "blk");if (major <= 0) {printk(KERN_WARNING "blk: unable to get major number\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){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);nregister_blkdev(major, "blk");kfree(dev);}module_init(blk_init);module_exit(blk_exit);
1、注册一个快设备register_blkdev,如果没有分配到主设备号则打印错误信息
2、然后是申请一个结构,这个结构是用来保存这个块设备信息的,不是每个块设备都有
3、再安装这个设备setup_device,这个函数是自定义的
3.1完成块设备大小的计算
3.2把快设备放入请求队列中(IO调度层把请求排序后放入请求队列中,里面的参数blk_request是一个函数,用于指明使用哪个函数对这个请求进行处理)
3.3指明设备的扇区大小
3.4然后用alloc_disk函数分配一个gendisk结构(一个驱动可能对于几个块设备,用gendisk来区分)
3.5紧接着需要对这个结构进行初始化,如下:
/*初始化alloc_disk*/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));//扇区数
3.6注册这个块设备
第二个重要的函数是实现读写请求处理,读写请求通过blk_request函数来实现:
1、使用blk_fetch_request从队列中取出要处理的一个请求
2、使用blk_transfer实现对对应扇区的硬件操作,比如读和写,应该这里的块设备是内存模拟的,所以使用的是memcpy函数
3、使用__blk_end_request_cur判断请求队列是否还有请求要处理,如果有则继续处理,没有退出。阅读全文
0 0
- Linux-Flash驱动(2)-块设备驱动实例分析
- Linux块设备驱动实例
- Linux块设备驱动之NAND FLASH
- Linux块设备驱动之NOR FLASH
- linux块设备驱动程序分析之 nor flash驱动分析 以及使用内存模拟 nor flash
- 块设备驱动实例
- Linux-Flash驱动(3)-简单块设备驱动设计
- LINUX块设备驱动2
- LINUX块设备驱动<2>
- Linux 块设备驱动 (2)
- 转:Linux 块设备驱动 实例
- linux块设备驱动之实例
- 块设备驱动分析
- 块设备驱动分析
- 块设备驱动之NOR FLASH驱动
- Linux块设备驱动
- Linux块设备驱动
- Linux块设备驱动
- Vuejs2.0 小应用
- 动态规划算法在不同阶楼梯中的走法
- Hibernate怎么修改ehcache.xml文件的存放位置
- Windows Sockets网络编程(1)TCP select & thread
- SSM框架中Mybatis向映射文件(XML)的<insert>元素传入多个数组参数的问题
- Linux-Flash驱动(2)-块设备驱动实例分析
- NSS管脚信号
- bzoj 3671 [Noi2014]随机数生成器
- nginx释放请求与tcp连接
- nginx基于用户认证
- java中super的作用及子类对象的创建过程
- 美团-字符串计数-Java
- 二分查找
- 运行web项目常见错误