一、字符设备
字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。
在 Linux 中一切皆为文件,驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过对这个名“/dev/xxx”(xxx 是具体的驱动文件名字)的文件进行相应的操即可实现对硬件的操作。
二、驱动模块的加载和卸载
Linux驱动有两种运行方式,第一种就是将驱动编译进 Linux 内核中,这样当 Linux 内核启动的时候就会自动运行驱动程序。第二种就是将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用“insmod”命令加载驱动模块。
模块有加载和卸载两种操作,我们在编写驱动的时候需要注册这两种操作函数,模块的加载和卸载注册函数如下:
module_init(xxx_init);
module_exit(xxx_exit);
驱动编译完成以后扩展名为.ko,有两种命令可以加载驱动模块:insmod和modprobe;
insmod 命令不能解决模块的依赖关系,modprobe 会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中,因此modprobe 命令相比 insmod 要智能一些。
驱动模块的卸载使用命令“rmmod”即可,也可以使用“modprobe -r”命令卸载驱动,modprobe 命令可以卸载掉驱动模块所依赖的其他模块,前提是这些依赖模块已经没有被其他模块所使用,否则就不能使用modprobe来卸载驱动模块。
三、字符设备注册与注销
对于字符设备驱动而言,当驱动模块加载成功以后需要注册字符设备,同样,卸载驱动模块的时候也需要注销掉字符设备。
1)字符设备注册函数:
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
major:主设备号,Linux 下每个设备都有一个设备号,设备号分为主设备号和次
设备号两部分,关于设备号后面会详细讲解。
name:设备名字,指向一串字符串。
fops:结构体 file_operations 类型指针,指向设备的操作函数集合变量。
其中,file_operations 结构体就是设备的具体操作函数。
2)字符设备卸载函数:
static inline void unregister_chrdev(unsigned int major, const char *name)
major:要注销的设备对应的主设备号。
name:要注销的设备对应的设备名。
一般字符设备的注册在驱动模块的入口函数 xxx_init 中进行,字符设备的注销在驱动模块的出口函数 xxx_exit 中进行。
四、添加 LICENSE 和作者信息
在驱动中加入 LICENSE 信息和作者信息,其中 LICENSE 是必须添加的,否
则的话编译的时候会报错,作者信息可以添加也可以不添加。
MODULE_LICENSE() //添加模块 LICENSE 信息
MODULE_AUTHOR() //添加模块作者信息
五、设备号的分配
1.静态分配设备号
驱动开发者静态的指定一个设备号,驱动开发者静态的指定一个设备号。使用“cat /proc/devices”命令即可查看当前系统中所有已经使用了的设备号。
2.动态分配设备号
静态分配设备号需要我们检查当前系统中所有被使用了的设备号,然后挑选一个没有使用的。而且静态分配设备号很容易带来冲突问题,Linux 社区推荐使用动态分配设备号,在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号。
①.设备号的申请函数如下:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
dev:保存申请到的设备号。
baseminor:次设备号起始地址,alloc_chrdev_region 可以申请一段连续的多个设备号,这些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递增。一般 baseminor 为 0,也就是说次设备号从 0 开始。
count:要申请的设备号数量。
name:设备名字。
②.注销字符设备之后要释放掉设备号,设备号释放函数如下:
void unregister_chrdev_region(dev_t from, unsigned count)
此函数有两个参数:
from:要释放的设备号。
count:表示从 from 开始,要释放的设备号数量