
本文共 2597 字,大约阅读时间需要 8 分钟。
底层驱动:从概念到实践
底层驱动是让设备工作的基本程序,它为用户提供了操作设备的接口。以树莓派为例,想要使用其40Pin中的GPIO口,就需要依赖底层驱动来实现对GPIO寄存器的操作。没有驱动,设备无法正常工作。
为什么要写驱动?
当系统没有提供相应设备的操作库或者没有驱动时,就需要自己编写驱动。例如,树莓派提供的wiringPi库让开发者方便地操作GPIO,但如果换到其他Linux板子(如2440、RK3399、nanoPi等),没有像wiringPi这样的库时,就必须手动编写驱动,否则无法操作底层设备。
如何编写驱动?
在编写驱动之前,需要了解Linux是如何调用驱动的,以及用户如何使用驱动。在Linux系统中,所有设备都以文件形式存在,驱动也不例外。
驱动文件的存放位置
驱动文件通常存放在/dev
目录下。编写好的驱动文件在安装时应放置在/dev
目录中。当使用驱动时,也应该使用/dev
目录下的驱动文件。
驱动的使用及区分方式
一个写好的驱动安装后,可以使用C库中的open
、write
和read
函数来操作驱动,因为驱动本身也是文件。这三个文件操作函数同样可以用于驱动:
open("/dev/xxx", O_RDWR)
生成文件描述符fd
;write(fd, "xxx", size_t);
向驱动发送指令;read(fd, char *, size_t);
读取驱动返回的数据。操作方式有了,但如何在/dev
目录下找到相应的驱动,系统又如何在众多驱动中找到我们写的驱动?有两种方式:
/dev
目录下的某个驱动文件;- 主设备号:用来区分不同的设备,如GPIO、IIC、UART等;
- 次设备号:用来区分相同设备中的多个设备,如GPIO.0、GPIO.1等。
设备号的查看可用命令:cd /dev && ls -l
。
驱动链表 file_operations
驱动链表的结构体file_operations
包含大量函数,其中包括open
、write
、read
等函数。在编写驱动时,需要根据需求为结构体的某个函数编写对应的函数,例如open
、write
、read
:
int pin4_open(struct inode *inode, struct file *file) { // 实现的操作 return 0;}ssize_t pin4_write(struct file *file, const char __user *buf, size_t count, loff_t *loffs) { // 实现的操作 return 0;}ssize_t pin4_read(struct file *file, char __user *buf, size_t count, loff_t *loff) { // 实现的操作 return 0;}struct file_operations pin_pos = { .owner = THIS_MODULE, .open = pin4_open, .write = pin4_write, .read = pin4_read,};
完成这些后,只是将驱动链表中的结构体搭建好了,还需要将其插入到链表中。
驱动注册及自动创建驱动文件
建立好驱动的结构体后,需要将其插入到驱动链表中。注册驱动的函数为register_chrdev
:
int register_chrdev(int major, char *module_name, struct file_operations *file_operation);
参数说明:
major
:驱动的主设备号;module_name
:驱动在链表中的名字;file_operation
:驱动的操作结构体指针。自动创建驱动文件需要几个函数的配合,包括MKDEV
宏和device_create
函数:
#define dev_t MKDEV(int major, int minor)struct class *class_create(struct module *owner, const char *name);struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
设备创建函数的使用示例:
int __init pin4_dev_init(void) { int ret; devno = MKDEV(major, minor); ret = register_chrdev(major, module_name, &pin_pos); pin4_class = class_create(THIS_MODULE, "myfirstdemo"); pin4_dev = device_create(pin4_class, NULL, devno, NULL, module_name); return 0;}module_init(pin4_dev_init);
卸载驱动函数的示例:
void __exit pin4_exit(void) { device_destroy(pin4_class, devno); class_destroy(pin4_class); unregister_chrdev(major, module_name);}module_exit(pin4_exit);
最后,别忘了添加许可:
MODULE_LICENSE("GPL v2");
总结
编写驱动的基本框架包括:
file_operations
结构体;- 生成设备号
MKDEV
; - 注册驱动
register_chrdev
; - 创建设备类
class_create
; - 创建设备
device_create
;
MODULE_LICENSE
。通过以上步骤,可以实现对底层设备的有效控制和管理。
发表评论
最新留言
关于作者
