드라이버 데이04

5046 단어
上一层的驱动开发工程师:bsp驱动开发工程师
답변:
驱动属于内核内核, 内核模块的基本构成
#포함
#포함

     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 中断子系统” 

좋은 웹페이지 즐겨찾기