02 关于设备号,设备节点等一些简单概念
2016-06-02 11:46
441 查看
1,设备
Linux文件系统/dev/下通常存放了一系列设备名称。对设备的访问,即访问这些文件。
ls -l /dev/ 能看到这些设备的一些基本信息。如下图所示
了解过Linux下文件类型的小伙伴应该对哪些是字符设备、块设备不会感到陌生了。(bcd-lsp分别是块、字符、目录、普通、链接、套接字、管道)
root后面 那两个逗号隔开的数字是设备的主设备号和次设备号。那我们跳到下一个概念吧。
2,设备号
设备号分为主设备号和次设备号;
主设备号标识设备对应的驱动程序,次设备号由内核使用,区分同一个类型的多个设备,如两个串口。个人认为了解这些就够了。我们需要重点关注的是驱动程序里面如何表达这些概念,也就是下一步。
dev_t devno //定义设备号,数据类型为dev_t,实际是一个32位的数。
devno = MKDEV(int major, int minor); //major minor 即我们看到的程序员给出的203,0等这些数字。习惯上限于255个主设备号,255个次设备号 devno = major << 20 | minor;
int major = MAJOR(dev_t devno);
int minor = MINOR(dev_t devno); //与上面的相反,如果你想通过dev_t devno获得主设备号和次设备号的话,可以这么做。
3,分配和释放设备号
直接上代码
#include <linux/fs.h>
int register_chrdev_region(dev_t first, unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
参数说明:
dev_t first :MKDEV();获取得到的设备号,
unsigned int count :连续设备编号的个数
char *name :文件系统中看到的设备驱动的名称,cat /proc/devices 或 ls /dev/下能看到的
初始化时需要register,退出时需要unregister。
alloc顾名思义,动态分配。经常认为通用PC随机分配,嵌入式产品需提前规划好,故尽量用静态。
register成功返回0,失败返回负的错误码,时刻谨记,可能失败,所以要添加if判断。
驱动程序设计师们经常这样写:
4,设备节点
当你驱动程序按上面的步骤写好后,编译并且insmod。你会发现文件系统中:
cat /proc/devices/下会出现你添加的设备名称,和主设备号。但是/dev/下并没有存在你所注册的dev。这是因为你还没有创建设备节点。这时你需要执行如下命令:
mknod /dev/name c $major minor
你可以确定count 个设备节点,根据你代码中register时指定的count个数。
动态分配主设备号有一个缺点:无法预先创建设备节点。不过,你可以通过/proc/devices/中获得。如果要写成脚本自动分配,可以参考书Page 51,有一个很棒的shell脚本,帮我们完成了。
最后附上几行简单的完整的注册设备号程序:
1 #include <linux/module.h>
2 #include <linux/init.h>
3 #include <linux/kernel.h>
4 #include <linux/fs.h> //note: register_chrdev need it
5
6 MODULE_LICENSE("Dual BSD/GPL");
7
8 static int __init scull_init(void)
9 {
10 dev_t devno = MKDEV(250, 66);
11 int ret;
12
13 printk(KERN_ALERT "scull dev init\n");
14 ret = register_chrdev_region(devno, 3, "scull");
15 if (0 == ret ) {
16 printk(KERN_ALERT " register success\n");
17 } else {
18 printk(KERN_ALERT "register fail ret:%d\n", ret);
19 goto register_fail;
20 }
21
22 return 0;
23 register_fail:
24 unregister_chrdev_region(devno, 1);
25 }
26 static void __exit scull_exit(void)
27 {
28 dev_t devno = MKDEV(250, 66);
29
30 printk(KERN_ALERT "scull exit\n");
31 unregister_chrdev_region(devno, 1);
32 }
33
34 module_init(scull_init);
35 module_exit(scull_exit);
Linux文件系统/dev/下通常存放了一系列设备名称。对设备的访问,即访问这些文件。
ls -l /dev/ 能看到这些设备的一些基本信息。如下图所示
了解过Linux下文件类型的小伙伴应该对哪些是字符设备、块设备不会感到陌生了。(bcd-lsp分别是块、字符、目录、普通、链接、套接字、管道)
root后面 那两个逗号隔开的数字是设备的主设备号和次设备号。那我们跳到下一个概念吧。
2,设备号
设备号分为主设备号和次设备号;
主设备号标识设备对应的驱动程序,次设备号由内核使用,区分同一个类型的多个设备,如两个串口。个人认为了解这些就够了。我们需要重点关注的是驱动程序里面如何表达这些概念,也就是下一步。
dev_t devno //定义设备号,数据类型为dev_t,实际是一个32位的数。
devno = MKDEV(int major, int minor); //major minor 即我们看到的程序员给出的203,0等这些数字。习惯上限于255个主设备号,255个次设备号 devno = major << 20 | minor;
int major = MAJOR(dev_t devno);
int minor = MINOR(dev_t devno); //与上面的相反,如果你想通过dev_t devno获得主设备号和次设备号的话,可以这么做。
3,分配和释放设备号
直接上代码
#include <linux/fs.h>
int register_chrdev_region(dev_t first, unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
参数说明:
dev_t first :MKDEV();获取得到的设备号,
unsigned int count :连续设备编号的个数
char *name :文件系统中看到的设备驱动的名称,cat /proc/devices 或 ls /dev/下能看到的
初始化时需要register,退出时需要unregister。
alloc顾名思义,动态分配。经常认为通用PC随机分配,嵌入式产品需提前规划好,故尽量用静态。
register成功返回0,失败返回负的错误码,时刻谨记,可能失败,所以要添加if判断。
驱动程序设计师们经常这样写:
4,设备节点
当你驱动程序按上面的步骤写好后,编译并且insmod。你会发现文件系统中:
cat /proc/devices/下会出现你添加的设备名称,和主设备号。但是/dev/下并没有存在你所注册的dev。这是因为你还没有创建设备节点。这时你需要执行如下命令:
mknod /dev/name c $major minor
你可以确定count 个设备节点,根据你代码中register时指定的count个数。
动态分配主设备号有一个缺点:无法预先创建设备节点。不过,你可以通过/proc/devices/中获得。如果要写成脚本自动分配,可以参考书Page 51,有一个很棒的shell脚本,帮我们完成了。
最后附上几行简单的完整的注册设备号程序:
1 #include <linux/module.h>
2 #include <linux/init.h>
3 #include <linux/kernel.h>
4 #include <linux/fs.h> //note: register_chrdev need it
5
6 MODULE_LICENSE("Dual BSD/GPL");
7
8 static int __init scull_init(void)
9 {
10 dev_t devno = MKDEV(250, 66);
11 int ret;
12
13 printk(KERN_ALERT "scull dev init\n");
14 ret = register_chrdev_region(devno, 3, "scull");
15 if (0 == ret ) {
16 printk(KERN_ALERT " register success\n");
17 } else {
18 printk(KERN_ALERT "register fail ret:%d\n", ret);
19 goto register_fail;
20 }
21
22 return 0;
23 register_fail:
24 unregister_chrdev_region(devno, 1);
25 }
26 static void __exit scull_exit(void)
27 {
28 dev_t devno = MKDEV(250, 66);
29
30 printk(KERN_ALERT "scull exit\n");
31 unregister_chrdev_region(devno, 1);
32 }
33
34 module_init(scull_init);
35 module_exit(scull_exit);
相关文章推荐
- jpush 第一篇 (初步认识)
- 关于EntityFramework连接Oracle的详细教程
- [java] abstract class 和interface 的区别
- 苹果手机照片误删如何找回
- android -view基础
- 修正nagios主机配置文件
- android6.0 framework修改使用两个声卡
- 怎样在Eclipse中使用debug模式调试程序
- android studio最操蛋的错误(1)
- Android学习路线指南
- 网络服务器并发编程的几种方案对比
- linux内核系统调用和标准C库函数的关系分析
- redis实现session共享
- spring modelAttributes的使用
- redis 高并发导致无法连接处理
- 反反外挂驱动的驱动
- Python eval() 和 exec()函数
- eclipse中 linked resource的使用
- Golang MySQL存储过程的使用
- Linux下MySQL配置文件my.ini位置