文章目录
全系列传送门
Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)
Linux嵌入式驱动开发06——第一个相对完整的驱动实践编写
Linux嵌入式驱动开发07——GPIO驱动过程记录(飞凌开发板)
Linux嵌入式驱动开发11——平台总线模型修改为设备树实例
Linux嵌入式驱动开发12——pinctl和gpio子系统实践操作
Linux嵌入式驱动开发13——ioctl接口(gpio控制使用)
Linux嵌入式驱动开发14——中断的原理以及按键中断的实现(tasklet中断下文)
Linux三大设备驱动
字符设备
IO的传输过程是以字符为单位的,没有缓冲,比如I2C,SPI都是字符设备
块设备
IO的传输过程以块为单位,跟存储相关的,都属于块设备,比如TF卡
网络设备
与前两个不一样,是以socket套接字来访问的
杂项设备驱动
杂项设备是字符设备的一种,可以自动生成设备节点
系统中也有很多的杂项设备,输入下面的命令可以查看
cat /proc/misc
可以看到misc的所有的子设备驱动
杂项设备和字符设备区别
杂项设备要比字符设备代码简单
杂项设备的主设备号相同,均为10,次设备号不同,主设备号相同就可以节省内核的资源
主设备号和次设备号
设备号包含主设备号和次设备号,主设备号在Linux系统里是唯一的,但是次设备号不一定唯一。
设备号是计算机识别设备的一种方式,主设备号相同的也就被视为同一类设备。
主设备号可以比作电话号码的区号,比如北京的区号是010
次设备号可以比作电话号码
主设备号可以通过命令
cat /proc/devices
杂项设备的描述
通过命令打开Linux源码目录下的
include/linux/
可以看到很多的头文件
我们找到我们所要查看的杂项设备mis的头文件miscdevice.h,然后打开
就可以找到对于mis砸向驱动的描述了
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
- int minor;次设备号
- const char *name;设备节点的名字
- const struct file_operations *fops;文件操作集
文件操作集的使用
include/linux/fs.h
通过搜索查找file_operations 可以找到这个结构体
次设备号分配
次设备号要保证唯一,这里的MISC_DYNAMIC_MINOR可以自动分配
下面的这个是对杂项设备的注册和注销
extern int misc_register(struct miscdevice *misc);
extern int misc_deregister(struct miscdevice *misc);
编写一个杂项设备驱动
注册杂项设备的流程
- 第一步 填充miscdevice结构体成员
- 第二步 填充file_operations结构体
- 第三步 注册杂项设备并生成设备节点
第一步 填充miscdevice结构体成员
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "hello_misc",
.fops = misc_fops
};
第二步 填充file_operations结构体
struct file_operations misc_fops = {
.owner = THIS_MODULE
};
第三步 注册杂项设备并生成设备节点
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret < 0){
printk("misc_register failed!!!\n");
return -1;
}
printk("misc_register succeed!!!\n"); // 在内核中无法使用c语言库,所以不用printf
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc exit!!!\n");
}
完整代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
struct file_operations misc_fops = {
.owner = THIS_MODULE
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "hello_misc",
.fops = misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret < 0){
printk("misc_register failed!!!\n");
return -1;
}
printk("misc_register succeed!!!\n"); // 在内核中无法使用c语言库,所以不用printf
return 0;
}
static void misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc exit!!!\n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL"); //声明模块拥有开源许可
编译成模块
Make file
# 开发板Linux内核的实际路径
# KDIR变量
KDIR:=/work/linux-4.1.15
# 获取当前目录
PWD:=$(shell pwd)
# obj-m表示将 chrdevbase.c这个文件 编译为 chrdevbase.ko模块。
obj-m += misc.o
# 编译成模块
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
执行make,但是出现错误
所以来定位到程序中检查,原来是结构体的错误引用,这里应该加上地址符
排查完错误,保存,make,编译成功
注册验证
发送到开发板ko文件,然后
insmod misc.ko
再到我们的/dev文件夹查看
ls /dev/
这样,最简单的杂项设备我们就完成了
然后再验证一下注销功能
rmmod misc.ko