博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
韦东山视频_第25课_字符设备驱动程序另一种写法
阅读量:5884 次
发布时间:2019-06-19

本文共 4537 字,大约阅读时间需要 15 分钟。

  旧字符设备驱动程序的框架:

1、确定主设备号major;

2、构造file_operations

3、注册register_chrdev;

4、创建类和设备结点

这个框架有很大的弊端,弊端出现在注册函数register_chrdev上,其实现中有这么一句:

cd = __register_chrdev_region(major, 0, 256, name);

其向内核连续注册了256个此设备号,也就把major这个主设备号下的所有此设备号都占用了,而其实我们大部分情况下用不到这么多次设备号,造成了巨大的浪费。

于是有了这样两个函数:

①  register_chrdev_region(dev_t from, unsigned count, const char  *name)

②  alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char  *name)

register_chrdev_region函数的第一个参数dev_t from是一个unsigned型的数,高12位表示主设备号,低20位表示

次设备号。因此这个参数中包含了起始的次设备号。第二个参数unsigned count表示需要注册的连续的次设备号的个
数。最后一个参数表示设备或驱动的名字。在解释alloc_chrdev_region函数的参数之前先解释一下,这2个函数的区别和用法。register_chrdev_region这个函数在调用之前需要确定from这个参数的值,就是说设备号是已知的。而alloc_chrdev_region这个函数调用的时候不需要知道设备的设备号是多少,内核会动态分配一个给他。在
分配好了之后会把设备号写到设备号变量的地址,所以我们看到在调用alloc_chrdev_region这个函数的时候它的第一个参数是设备号变量的地址。alloc_chrdev_region它的第二个参数是起始次设备号,第三个参数是要注册的次设备号个数,最后一个是设备或驱动的名字。
这两个函数最终调用的都是__register_chrdev_region,同时需要跟cdev_init(struct cdev  *cdev, const struct
file_operations *fops)和 cdev_add(struct cdev *p, dev_t dev, unsigned count)来配合使用。这2个函数的功能在以前的字符设备驱动程序中是在register_chrdev这一个函数中完成的,在这里需要我们自己来调用。这样一来,register_chrdev这个函数就被完美的替代了。我们就可以通过控制注册的起始次设备号以及多少个次设备号,实现了用多少注册多少的目的。

字符设备驱动新框架:

1、确定主设备号

主设备号已知,

devid = MKDEV(major, 0);
register_chrdev_region(devid, HELLO_CNT, "hello");
主设备号未知,
alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
major = MAJOR(devid);

2、构造file_operations

static struct file_operations hello_fops =

{

  .owner = THIS_MODULE,
  .open = hello_open,
};

3、注册

cdev_init(&hello_cdev, &hello_fops);

cdev_add(&hello_cdev, devid, HELLO_CNT);

4、创建类和设备

hello_class = class_create(THIS_MODULE, CLASS_NAME);

device_create(hello_class, NULL, MKDEV(hello_major, 0), NULL, DEV_NAME);

 

一个实例程序如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 14 #define HELLO_MAJOR 0 //预设的主设备号 15 #define START_MINOR 0 //起始次设备号 16 #define DEV_CNT 2 //要注册的设备数 17 #define DRV_CNT 2 //要注册的驱动数 18 #define DRIVER_NAME "hello" //驱动名 19 #define CLASS_NAME "hello_drv" //类名 20 #define DEV_NAME "hello%d" //设备名 21 22 static int hello_major = HELLO_MAJOR; 23 24 struct class *hello_class = NULL; 25 26 //字符设备结构体 27 struct hello_dev 28 { 29 struct cdev cdev; //cdev结构体 30 void *private_data; //私有数据 31 }; 32 33 struct hello_dev *hello_devp; //设备结构体指针 34 35 static int hello_open(struct inode *inode, struct file *file) 36 { 37 printk("hello_open\n"); 38 return 0; 39 } 40 41 //文件操作结构体 42 static const struct file_operations hello_fops = 43 { 44 .owner = THIS_MODULE, 45 .open = hello_open, 46 //.read = hello_read, 47 //.write = hello_write, 48 //.ioctl = hello_ioctl, 49 }; 50 51 //设备驱动模块加载函数 52 int hello_init(void) 53 { 54 int i, res; 55 dev_t devno; 56 57 //申请次设备号范围、主设备号 58 if (hello_major) 59 { 60 devno = MKDEV(hello_major, START_MINOR); 61 res = register_chrdev_region(devno, DEV_CNT * DRV_CNT, DRIVER_NAME); 62 } 63 else 64 { 65 res = alloc_chrdev_region(&devno, START_MINOR, DEV_CNT * DRV_CNT, DRIVER_NAME); 66 hello_major = MAJOR(devno); 67 } 68 69 if (res < 0) 70 { 71 return res; 72 } 73 74 //动态申请设备结构体内存 75 hello_devp = kmalloc(DRV_CNT * sizeof(struct hello_dev), GFP_KERNEL); 76 if (hello_devp == NULL) 77 { 78 res = - ENOMEM; 79 goto fail_malloc; 80 } 81 memset(hello_devp, 0, DRV_CNT * sizeof(struct hello_dev)); 82 83 for (i = 0; i < DRV_CNT; i++) 84 { 85 cdev_init(&hello_devp[i].cdev, &hello_fops); 86 hello_devp[i].cdev.owner = THIS_MODULE; 87 cdev_add(&hello_devp[i].cdev, MKDEV(hello_major, i * DEV_CNT), DEV_CNT); 88 } 89 90 //自动创建设备节点 91 hello_class = class_create(THIS_MODULE, CLASS_NAME); 92 93 for (i = 0; i < DEV_CNT * DRV_CNT; i++) 94 { 95 device_create(hello_class, NULL, MKDEV(hello_major, i), NULL, DEV_NAME, i); 96 } 97 98 return 0; 99 100 fail_malloc:101 unregister_chrdev_region(devno, DEV_CNT);102 return res;103 }104 105 //模块卸载函数106 void hello_exit(void)107 {108 int i;109 110 cdev_del(&hello_devp->cdev);111 kfree(hello_devp);112 unregister_chrdev_region(MKDEV(hello_major, 0), DEV_CNT * DRV_CNT);113 for (i = 0; i < DEV_CNT * DRV_CNT; i++)114 {115 device_destroy(hello_class, MKDEV(hello_major, i));116 }117 class_destroy(hello_class);118 }119 120 module_init(hello_init);121 module_exit(hello_exit);122 MODULE_LICENSE("GPL");123 MODULE_AUTHOR("Lcm");

程序中,一个主设备号和一个次设备号共同对应一个设备节点,例子中有两个c_dev结构体,且对应同一个主设备号,每个c_dev结构体对应两个次设备号,即创建两个字符设备。

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/cmembd/p/3489825.html

你可能感兴趣的文章
js /jquery停止事件冒泡和阻止浏览器默认事件
查看>>
[翻译]Protocol Buffer 基础: C++
查看>>
runloop与线程的关系
查看>>
[Bzoj2246]迷宫探险(概率+DP)
查看>>
详解消息队列的设计与使用
查看>>
使用Sqoop从mysql向hdfs或者hive导入数据时出现的一些错误
查看>>
控制子窗口的高度
查看>>
处理 Oracle SQL in 超过1000 的解决方案
查看>>
Alpha线性混合实现半透明效果
查看>>
chkconfig 系统服务管理
查看>>
ORACLE---Unit04: SQL(高级查询)
查看>>
贪食蛇
查看>>
201521123009 《Java程序设计》第11周学习总结
查看>>
Python3之多线程学习
查看>>
MVC和MTV结构分析
查看>>
(转)微信网页扫码登录的实现
查看>>
mariadb启动报错:[ERROR] Can't start server : Bind on unix socket: Permission denied
查看>>
nginx的信号量
查看>>
云im php,网易云IM
查看>>
河南农业大学c语言平时作业答案,河南农业大学2004-2005学年第二学期《C语言程序设计》期末考试试卷(2份,有答案)...
查看>>