1.编写驱动的环境配置
内核实现、文件系统实现、驱动实现---ubuntu中实现
gcc-4.6.4----->arm-none-linux-gnueabi-gcc
a、通过tftp提供uImage和.dtb----提供内核
b、通过nfs提供文件系统rootfs
2.编写驱动的步骤
驱动代码必须有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");
3.字符驱动设备怎么写
请简述 字符设备驱动模型 的工作过程.
申请设备号
创建设备节点(设备文件)
硬件初始化
实现文件io
4.中断驱动
中断驱动---检测外部中断
获取外设的数据内容,通过中断信号进行获取
在驱动中设置外设为中断模式:当外设产生设定的特定信号(就是中断)
在驱动中实现中断处理操作(函数)
中断驱动应该做什么
a、获取到中断号
获取设备树节点,返回值就是从设备树中找到的节点
struct device_node *of_find_node_by_path(const char *path);
从节点中获取到中断号,返回值就是中断号
unsigned int irq_of_parse_and_map(struct device_node *dev,int index);
b、申请中断
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)
c、释放中断:
void free_irq(unsigned int irq,void * dev_id)
中断下半部分/内核中的延迟工作机制有哪些?
softirq软中断,处理级别比较高,在内核机制中,需要修改内核源码功能
tasklet:就是内部调用了softirq
workqueue:工作队列
1.请简述linux内核中断处理分成上半部分和下半部分的原因,为何要分?一般如何使用下半部分,在哪里使用?
a、因为中断处理的时间不宜过长,而有些中断中存在耗时任务,所以就将中断处理分为上半部分和下半部分,上半部分进行短时间的操作处理,将耗时任务交给下半部分进行延后处理
b、一般通过tasklet以及workqueue进行使用,在上半部分中,使用下半部分
5、文件io模型
阻塞io模型------休眠等待
驱动中实现阻塞:
要创建等待队列头:
wait_queue_head_t head;
init_waitqueue_head(&head);
1、在需要等待的位置(没有数据),就阻塞等待
wait_event_interruptible(wq,condition)-----根据参数是否进行阻塞等待,完成阻塞等待
2、合适位置进行阻塞唤醒
wake_up_interruptible(&head);
非阻塞:在进行读写操作时,如果没有数据,就立即返回,如果有数据读取数据然后立即返回
应用程序:设置为非阻塞打开
int fd = open("/dev/key3",O_RDONLY | O_NONBLOCK);
驱动添加:
if((file->f_flags & O_NONBLOCK != 0) && (condition == 0))
return -1;
问:驱动程序和一般程序的异同?