드라이버 데이04
답변:
驱动属于内核内核, 内核模块的基本构成
#포함
#포함
MODULE_LICENSE("GPL");
int __init xxx_init(void){ }
void __exit xxx_exit(void){}
module_init //linux/init.h
module_exit
实现一个字符设备驱动,实则就是实例化一个cdev
在实例化过程最主工作的集中在struct file_operations
具体到某个硬件,只需要实现fil_operations的一个子集
file_operations中实现的函数是如何被用户空间调用的?
通过系统调用实现的
你如何理解系统调用?
设备文件,就是应用程序调用驱动程序的媒介
/dev/beep c major minor
open read write ioctl close
xxx_open xxx_read xxx_write xxx_unlocked_ioctl xxx_release
相应的驱动函数中操作硬件就可以了
gpio库函数:
1)申请
gpio_request
2)使用
gpio_direction_output
3) 释放
gpio_free
内核空间和用户空间的数据交换
copy_to_user/copy_from_user
put_user/get_user
设备文件的自动创建
class_create
device_create
以上两个函数调用内核视为热插拔事件
热插拔事件会导致mdev的调用
设备文件是mdev根据以上两个函数信息创建的
linux中的中断
Linux의 中断处理过程和ARM裸板中的中断处理过程是一致的
不同点在于裸板开始时所有的软件都是自行编程完成的
에서 linux中很多中断相关的代码内核已经实现完毕了,
某个中断产生后应该做什么样的具體工作没有完成
需要我们自己编程实现
1、linux内核中中断的注册与注销
int request_irq(unsigned int irq, irq_handler_t 핸들러, unsigned long 플래그,
const 문자 *이름, 무효 *dev)
作用:注册中断服务程序
irq: 中断号,内核中将S5P6818所有的中断源做了统一的编号
获取linux内核中断号的方式
1) int gpio_to_irq(부호 없는 gpio)
将管脚编号gpio转换为对应的中断编号
2) s5p6818_irq.h
IRQ_GPIO_A_START + 인덱스
handler: 要注册的irq号中断源对应的中断服务程序
btn_isr 也被称作回调函数/钩子函数
flags: 设置哪种情况下触发irq号中断
IRQF_TRIGGER_RISING,上升沿触发中断
IRQF_TRIGGER_FALLING
IRQF_TRIGGER_HIGH,高电平触发中断
IRQF_TRIGGER_LOW
IRQF_SHARED: 共享中断
name: 名称
dev: 调用handler 函数时传递的参数
返回值:注册成功返回0
失败返回非0
typedef irqreturn_t (*irq_handler_t)(int, void *);
第一个参数:中断号
第二个参数:
void free_irq(unsigned int irq, void *dev)
作用:注销中断服务程序
注意:当调用request_irq(....,dev)
当调用free_iqr(.......,dev)
最后一参数要保持一致
不然注销失败
电路原理图:
K1 ----> GPIOA_28
K2 ----> GPIOB_30
K3 ----> GPIOB_31
K4 ----> GPIOB_9
只关注按下动作,下降沿触发中断
编程
实验步骤:
insmod btn_drv.ko
insmod: can't insert 'btn_drv.ko': Resource temporarily unavailable
原因:
内核中自带了按键的驱动程序
在其中通过request_irq的方式注册了K1对应的中断服务程序
导致再次调用request_irq时注册失败
解决方法:
make menuconfig
Device Drivers --->
Input device support --->
[*] Keyboards --->
< > SLsiAP push Keypad support
make uImage
让开发板使用新内核
cp arch/arm/boot/uImage /tftpboot/
tftp 48000000 uImage
mmc write 48000000 800 3000
insmod btn_drv.ko
按下K1观察实验效果
cat /proc/interrupts
中断号 中断产生的次数
134: 0 GPIO K1
中断服务程序的特点:
1)中断处理程序不属于任何一个进程
它运行于中断上下文
2) 要求对应的处理过程,执行速度越快越好
3)中断用的栈为独立的栈空间
栈空间为一个内存页 ,一般为4KB
4)在中断上下文中不能做用户空间和内核空间的数据交互
5)在中断上下文中不允许执行引起阻塞或者睡眠的函数
수면//睡眠函数
recv//阻塞函数
copy_to_user/copy_from_user/kmalloc
关于内核编程中,OOPS信息:
1)自己编程造成的错误
문자 *p = NULL;
*p = '아';
2) 再调用内核函数,由于参数使用不当造成的内核崩溃
中断服务程序越快结束越好,但是某些硬件的对应的中断
处理起来非常耗时,不能很快结束.
针对以上矛盾,linux内核中将中断处理过程分为两部分:
1)顶半部 상반신
에서 其中完成最紧急的工作,
通常取寄存器的值,清除中断标志
登记底半部(告诉内核,活没干完,
由内核找一个合适的时间继续完成剩余工作)
完成后中断直接返回
2)底半部 하반부
在其中完成不太紧急,非常耗时的工作
2、底半部登记方式
2.1 软中断方式
编程实现,需要修改内核源码,不能直接使用在
内核模块中,使用起来不方便
2.2 태스크릿
作用:可以用来完成底半部的登记
怎么使用?
核心数据结构
구조체 tasklet_struct
{
... ...
/底半部工作对应的处理函数/
무효(펑크)(부호 없는 롱);
/内核调用 func时传递的参数*/
부호 없는 긴 데이터;
}
具體用步骤:
1) 定义一个tasklet变量
구조체 tasklet_struct btn_tasklet;
2) 初始化tasklet变量
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
//定义 初始化
DECLARE_TASKLET(이름, 기능, 데이터)
3)登记底半부
void tasklet_schedule(struct tasklet_struct *t)
2.3 工作者队列
linux关于中断内核中实现了哪些代码,框架结构是?
百度 搜索 “linux 中断子系统”
Reference
이 문제에 관하여(드라이버 데이04), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/moonxu0722/driver-day04-15dh텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)