zoukankan      html  css  js  c++  java
  • LINUX按键驱动程序

    《《混杂设备驱动模型》》

    《混杂设设备的描述》

    <混在设备的概念>

    linux系统中,存在一类字符设备,他们拥有相同的主设备号(10),但是次设备号不同,称这类设备为混在设备(missdevice),所有的混杂设备形成一个链表,对设备进行访问,根据次设备号在链表中查找相应的混杂设备。

    注意:混杂设备是字符设备的一种。

    <混杂设备的设备描述符>

    struct miscdevice

    {

    int minor;   /*次设备号*/

    const char *name; /*设备名*/

    const struct file_operrations  *fops; /*文件操作*/

    struct list_head list;

    struct device *parent;

    struct  device *this _device ;

    };

    <设备注册>

    linux系统中欧使用函数 misc_register() 函数来注册一个混杂设备驱动。

    函数原型:

    int misc_register(struct miscdevice *misc)

    <设备注销>

    函数原型:

    int mic_deregister (struct miscdevice * misc)

    linux中断处理》

    <裸机中中断处理流程>

    中断会有一个统一的入口: ldr pc,_irq ——》保存环境处理——》执行:bl handle_init 指令——》 根据中断号,调用与之对应的中断处理程序。

    <linux中中断处理流程分析>

    linux系统中也有一个中断处理的同样的入口:irq_svc ——》接着做相应的环境保存——》获取产生中断的中断源(寄存器 INTPND)——》利用中断号找到irq_disc[*]这个结构——》在action 中就有用户事先填写编写好的处理函数

    总结:驱动程序需要做哪些事?

    1)实现中断处理过程

    2)将中断处理程序注册到linux系统中

    <linux 中中断处理程序>

    1)注册中断

    函数原型:
    int request_irq(unsigned int irq, void (*handler )(int ,void *,struct pt_regs*),unsigned long flags,const char*devname, void *dev_id)

    参数分析:

    unsigned int irq: 中断号

    注意:中断号和中断类型区别

    #define S3C2410_CPUIRQ_OFFSET  (16)

    #define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)

    void *handler (int ,void * , struct pt_regs * ): 中断处理程序

    unsigned long flags :与中断处理有关的各种的选项

    例:

    IRQF_DISABLEED (SA_INTERRUPT) :快速中断处理程序,如果没有该位,则表示慢速中断处理程序

    注意:快速中断和慢速中断的区别

    /慢速中断主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证,换句话说就是开启中断标志位 (屏蔽)(处理器 IF,在运行快速中断程序是关闭的,英因此在服务该中断时,不会别其他类型的中断打断;而调用慢速中断处理时,其他类型的中断可以得到服务。

    IRQF_SHARED(SA_SHIRQ):表明该中断号是设备共享的()多个设备可以共享多个中断。

    IRQF_TRIGGER_FALLING: 下降沿产生中断

    const char * devname:设备名

    void * dev_id :共享中断时使用

    返回值:

    返回0 表示成功

    失败:

    返回一个非0 的错误值

    注意:中断处理程序是在中断上下文中运行的,他的行为可能受某些限制:

    1)不能使用可能引起阻塞的函数

    2)不能使用可能引起调度的函数

    2)中断处理

    一般处理流程:

    检查设备是否产生中断——》清除中断标志(要不然下次中断没法响应)——》相应的硬件操作

    3)注销中断

    函数原型:

    void free_irq(unsigned int irq,void *dev_id)

    参数分析:

    irq;中断号

    dev_id:对于共享中断,一个中断号,对应多个中断程序,位了将加载的中断处理程序卸载,将其中对每个中断处理程序进行编号:dev_id

    《中断分层技术》

    <中断嵌套>

    (1)慢速中中断

    当处理慢速中断当过程中,中断开关(IF)是关闭当的,即可以被其他中断打断,执行本中断,直到处理完成,再返回执行执之前被打断当中断。

    注意:如果执行中断当过程中是被同类型当中断打断,此时linux系统是不会执行该中断当。

    (2)快速中断

    不可以被其他中断打断

    <中断分层技术>

    背景:

    中断处理流程大致可以分为和和硬件有关的工作,和硬件无关当工作,linux系统中,将和硬件有关的工作被放到中断处理程序中去做,其他的部分放到其他地方做。其目的是减少处理中断处理的时间。使用以下三中方式处理和硬件无关部分处理。

    (1)软中断

    (2)tasklet

    (3)工作队列

    由上图可以看见,加入说这是一个3核当CPU,每一CPU后面都跟有一个队列,将和硬件没有关系的处理程序插入到这些链表中,linux内核会为每一个链表创建一个线程,系统会在CPU相对空闲的时候把挂着的线程处理一遍,当处理完一个线程该链表就会从该队列中消失。

    <使用工作队列实现分层>

    (1)如何实现工作队列

    struct workqueue_struct

    {

    struct cpu_workqueue_struct *cpu_wq;

    struct list_head list;

    const char *name;  /*workqueue name */

    int signalthread;

    int freezeable  /*freeze threads during suspend*/

    int rt;

    }

    (2)如何描述一个工作

    struct work_struct

    {

    atomic_long_t data;

    struct list _head entry;

    work_fun_t func;

    }

    (3)实现步骤

    1)创建工作队列

    函数:

    create_workqueue(“name”)

    2)创建工作

    函数:

    INIT_WORK(work,fun)

    3)提交工作(将工作挂载到工作队列上)

    函数:
    queue_work(work_queue,work)

    注意:要创建工作队列,必须遵循GPL协议。

    MOUDLE_LICENSE(“GPL”)

    注意:但是在大多数情况下并不需要我们定义工作队列,linux系统会有一个默认当工作队列keventd_wq,所以只需要将工作挂载到该工作队列上即可。

    挂载函数:

    schedule_work(work)
    《按键去抖》

    <背景分析>

    在按动按键的时候,因硬件设计的缺陷,会导致信号出现尖刺,从而导致输入信号不准确。

    <处理按键抖动>

    (1)硬件去抖

    (2)软件去抖

    一般软件去抖采用延时的方式:
    1for()循环

    2)定时延时

    Linux系统中使用结构体数组:
    struct timer_list

    {

    struct list_head entry;

    unsigned long expires;

    viod (*function )(unsigned long);

    unsigned long data;

    struct tvec_base *base;

    }

    expires:用来设定时间

    function:这个函数指针指向定时结束后需要处理的工作。

    来描述一个定时器。

    注意:一般操作系统为处理的高效率,一般是不使用for()循环的。只能使用定时器。

    <定时器处理流程>

    (1)定义定时器变量

    (2)初始化定时器

    1init_timer()

    2)设置超时函数

    (3)add_timer()用来向内核注册定时器

    (4)mod_timer()启动定时器

    <多按键驱动的优化>

    相对于一个按键的驱动程序,需要多注册一个中断,注册中断就需要在对硬件操作部分多做一个引脚的功能配置。

    注意:首先要实现相应的硬件驱动程序,才能在应用程序中做相应的系统调用。

    <阻塞型驱动程序的设计>

    (1)阻塞必要

    当一个设备无法满足用户的读写请求的时候该怎么办?例如使用函数然而以后会有数据,或者一个进程企图向一个设备写入数据的时候,然而,此时设备没有做好接受数据的准备,当上述情况发生时,驱动程序应当(缺省的)阻塞进程,使进程进入等待(睡眠)状态,知道请求得到满足。

    (2)内核等待队列

    在实现阻塞驱动的过程中,也需要一个类似“候车室”的地方来安排阻塞队列的休息,当唤醒条件成熟时,则可以从候车室中将进程唤醒,这个“候车室”就是等待队列。

    1)定义等待队列

    wait_queue_head_t my_queue

    2)初始化等待队列

    init_waitqueue_head(&my_queue)

    3)或者定义并初始化等待队列

    DECLARE_WAIT_QUEUE_HEAD(my_queue)

    4)进入等待队列

    wait_event(queue,condition)

    condition(布尔表达式)为真时,立即返回,否者让进程进入TASK_UNINTERRUPTIBLE 模式的睡眠,并挂载到queue参数指定的等待队列上。

    wait_event_interrupttible(queue,condition)

    condition(布尔表达式)为真时,立即返回,否者让进程进入TASK_INTERRUPTIBLE的睡眠,并挂载在参数queue参数指定的队列上。

    5)从等待队列中唤醒

    wake_up(wait_queue_t *q)

    从等待队列q 中唤醒状态为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE 的所有进程

    wake_up_interruptible(wait_queue_t *q)

    从等待队列中q中,唤醒状态为TASK_INTERRUPTIBLE的进程。

    (3)阻塞驱动优化

     L

  • 相关阅读:
    C语言 简单的队列(数组队列)
    C语言 复杂的栈(链表栈)
    C语言 简单的栈
    C语言 链表的使用(链表的增删查改,链表逆转,链表排序)
    C语言 常用的时间函数
    C语言 百炼成钢17
    C语言 const常量讲解
    ndroid如何监听开机广播和关机广播
    Android判断GPS是否开启和强制帮用户打开GPS
    android java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题
  • 原文地址:https://www.cnblogs.com/big-devil/p/8589464.html
Copyright © 2011-2022 走看看