提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
学习记录
提示:这里可以添加本文要记录的大概内容:
本月关于字符设备驱动的学习记录
提示:以下是本篇文章正文内容,下面案例可供参考
一、字符设备驱动框架
1.驱动框架
只要是驱动程序,就必须满足驱动框架,不然是没办法编译为驱动程序
驱动代码必须有4部分:
//1、头文件
#include <linux/init.h>
#include <linux/module.h>
//2、驱动入口函数的声明,在内核加载驱动时,执行哪个函数;在内核卸载驱动时,执行哪个函数
//声明:加载时的入口声明
module_init(hello_init);
//声明:卸载时的入口声明
module_exit(hello_exit);
//3、加载函数、卸载函数的实现
//加载函数的实现:当内核加载驱动(内核执行这个驱动时,就会调用的函数)
static int __init hello_init(void)
{
return 0;
}
//卸载函数的实现:当内核卸载驱动(内核删除这个驱动时,就会调用的函数)
static void __exit hello_exit(void)
{
}
//4、协议选择GPL
MODULE_LICENSE("GPL");
实现驱动后:通过makefile来进行编译。
2.创建设备节点
手动创建:mknod 设备节点名 设备类型 主设备号 次设备号
mknod /dev/devname c major minor
自动创建(通过udev/mdev机制)
struct class * class_create(owner,name)
struct device *device_create( struct class *class,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)
3.向上提供接口
//实现file_operations结构体,实现文件io接口
file_operations fops
//应用和驱动传递数据
read、write
copy_to_user
copy_from_user
4.向下操作硬件 硬件的初始化 发送和接收
1)地址映射
void * ioremap(cookie,size);
2)申请中断
(外设产生中断,驱动要能检测到中断—申请中断(根据中断号))
(处理外设产生的中断)
在驱动中申请中断,实现中断处理
获取中断号:
//获取设备树节点,返回值就是从设备树中找到的节点
struct device_node *of_find_node_by_path(const char *path);
//从节点中获取到中断号,返回值就是中断号
unsigned int irq_of_parse_and_map(struct device_node *dev,int index);
申请中断:
typedef irqreturn_t (*irq_handler_t)(int, void *);
//类型替换,irq_handler_t代表函数指针
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
释放中断:
void free_irq(unsigned int irq,void * dev_id)
//与申请中的五个参数保持一致
3)实现硬件的寄存器初始化
中断底半部
1、 softirq:软中断,处理级别比较高,在内核机制中,需要修改内核源码功能
2、 tasklet:工作在中断上半部分,不能有耗时操作,不能有调度实际上就是内部调用了softirq
tasklet_schedule(struct tasklet_struct * t)
3、workqueue:工作队列,工作在进程上下文,可以有调度
INIT_WORK(struct work_struct *work,void (*work_func_t)(struct work_struct *work))