内核驱动
linux操作系统支持多种硬件平台和处理器平台,但是每个硬件平台的其它外设是不完全相同的,外设芯片的性能也是在不断提升的,要兼容这些外设硬件,就必须有一个灵活的设备驱动层。
驱动分类
是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。字符设备在 /dev/ 目录下会有一个设备文件,例如串口: /dev/ttySAC0 ,应用层使用打开文件写入读取文件等操作来控制外设。
是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。实际上linux中自带了nand flash驱动,所以我们块设备驱动不作为重点研究。
最简驱动模块
一个最简单的驱动模块要做以下几件事情
向内核注册模块初始化函数
实现文件操作file_operation结构体,包含几个函数指针 open(),read() 等
向内核注册模块的销毁函数
下面是一个具体的代码例子:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/device.h>static int first_drv_open(struct inode * inode,struct file * file)
{
printk("open!");
return 0;
}static int first_drv_write(struct file * file,const char __user *buf ,size_t count,loff_t * ppos)
{
printk("close!");
return 0;
}
static struct file_operations first_drv_fops={
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
} ;int major;static int my_drv_init(void)
{
major=register_chrdev(0,"first_drv",&first_drv_fops);
printk("module_init\\n");
return 0;
}static void my_drv_exit(void)
{
printk("module_exit\\n");
unregister_chrdev(major,"first_drv");
}
module_init(my_drv_init);
module_exit(my_drv_exit);
MODULE_LICENSE("GPL");
驱动模块编译后的格式为.ko,使用insmod命令将模块插入
insmod my_first_drv.ko
之后在 /proc/devices 中就可以找到这个模块了
cat /proc/devices
proc挂载在/proc目录下,提供操作系统的一些信息如进程信息和内存参数管理等。左侧是设备号,右侧是设备名
但是这个模块还没有一个设备文件,不过可以手动创建,设备文件的主设备号要和/proc/devices 分配的设备号一致
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>static struct class * firstdrv_class;static struct class_device *firstdrv_class_dev;static int first_drv_open(struct inode * inode,struct file * file)
{
printk("open!");
return 0;
}static int first_drv_write(struct file * file,const char __user *buf ,size_t count,loff_t * ppos)
{
printk("close!");
return 0;
}static struct file_operations first_drv_fops={
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
} ;int major;static int my_drv_init(void)
{
major=register_chrdev(0,"first_drv",&first_drv_fops);
firstdrv_class = class_create(THIS_MODULE,"firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"XYZ");
printk("module_init\\n");
return 0;
}static void my_drv_exit(void)
{
printk("module_exit\\n");
unregister_chrdev(major,"first_drv");
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
}
module_init(my_drv_init);
module_exit(my_drv_exit);
MODULE_LICENSE("GPL");
重新insmod模块,可以看到 /etc/XYZ 这个设备文件已经被驱动模块注册好了
文章来源:Joy & Owl