字符设备驱动框架
什么是字符设备?
就是它所产生的数据是字符流。读取速度快,读取数据少。比如LCD,keyboard,IIC
什么是块设备?
就是以块为单位存储的,就是存储设备。读取速度慢,读取数据大。比如,磁盘、u盘、flash、SD卡
什么是网络设备?
就是socket设备。比如,以太网、wifi
作为字符设备驱动要素:
1,必须有一个设备号,用在众多到设备驱动中进行区分
2,用户必须知道设备驱动对应到设备节点(设备文件)
linux把所有到设备都看成文件
crw-r----- 1 root root 13, 64 Mar 28 20:14 event0
crw-r----- 1 root root 13, 65 Mar 28 20:14 event1
crw-r----- 1 root root 13, 66 Mar 28 20:14 event2
3,对设备操作其实就是对文件操作,应用空间操作open,read,write的时候
实际在驱动代码有对应到open, read,write
设备节点
用于open的时候打开该设备
设备号
用于区分某一类设备中的某一个设备
申请设备号-register_chrdev接口
作为驱动必须有一个主设备号–向系统申请
申请
int register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
参数1:主设备号
设备号(32bit–dev_t)==主设备号(12bit) + 次设备号(20bit)
主设备号:表示一类设备–camera
次设备号: 表示一类设备中某一个:前置,后置
给定到方式有两种:
1,动态分配--参数1直接填0
2,静态指定--指定一个较大的整数,250
参数2: 描述一个设备信息,可以自定义
/proc/devices列举出所有到已经注册的设备
参数3: 文件操作对象--提供open, read,write
返回值: 正确返回0,错误返回负数
释放
void unregister_chrdev(unsigned int major, const char * name)
参数1:主设备号
参数2: 描述一个设备信息,可以自定义
ps:怎么查看函数的头文件?
在sourceinsight中把鼠标移到函数上会显示头文件信息
ps:怎么查看申请的设备信息?
cat /proc/devices
可以看到字符设备、块设备的设备号,在装载字符设备驱动后能查看是否装载成功
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
//静态的指定
static unsigned int dev_major = 250;
const struct file_operations my_fops{
};
static int __init char_dev_init(void)
{
//申请设备号,在proc/devices中可以查看注册的设备号
int ret;
ret = register_chrdev(dev_major, "char_dev_test", &my_fops);
if (ret == 0){
printk("register successfully!\n");
}else{
printk("register failed!\n");
return -EINVAL;
}
return 0;
}
static void __exit char_dev_exit()
{
//一般都是释放资源
unregister_chrdev(dev_major, "char_dev_test");
}
module_init(char_dev_init);
module_exit(char_dev_exit);
MODULE_LICENSE("GPL");
手动或自动创建设备节点
1,手动创建–缺点/dev/目录中文件都是在内存中,断电后/dev/文件就会消失
mknod /dev/设备名 类型 主设备号 次设备号
比如:
mknod /dev/chr0 c 250 0
[root@farsight drv_module]# ls /dev/chr0 -l
crw-r--r-- 1 0 0 250, 0 Jan 1 00:33 /dev/chr0
2,自动创建(通过udev/mdev机制)
struct class *class_create(owner, name)//创建一个类
参数1: THIS_MODULE
参数2: 字符串名字,自定义
返回一个class指针
//创建一个设备文件
struct device *device_create(struct class * class, struct device * parent, dev_t devt,
void * drvdata, const char * fmt,...)
参数1: class结构体,class_create调用之后到返回值
参数2:表示父亲,一般直接填NULL
参数3: 设备号类型 dev_t
dev_t devt
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
参数4:私有数据,一般直接填NULL
参数5和6:表示可变参数,字符串,表示设备节点名字,用于open的时候打开
销毁动作:
void device_destroy(devcls, MKDEV(dev_major, 0));
参数1: class结构体,class_create调用之后到返回值
参数2: 设备号类型 dev_t
void class_destroy(devcls);
参数1: class结构体,class_create调用之后到返回值
ps:怎么查看创建的设备节点?
ls /dev/
a,驱动中实现文件io操作接口:struct file_operations
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_