1、按键驱动程序的第一个版本:day07/04
   
   //内核模块的基本要求
   init.h module.h LICENSE
   
   struct cdev btn_cdev;
   
   btn_read(...)
   {
       //阻塞
         等待队列  睡眠
       //非阻塞
       
       将数据拷贝到用户空间
   }
   
   struct file_operations btn_fops=
   {
        .open
        .release //设备的独占式访问  竞态
        .read = btn_read    //等待队列
   }
   
   timer_func/ delay_work_func()
   {
       判断哪个按键触发的
       通过读取管脚电平状态判断是按下触发还是释放触发
       保存键值
       唤醒睡眠进程
   }
   btn_isr()
   {
       延时去抖 或者 底半部方式去抖
   }
   int __init btn_drv_init(void)
   {
        申请注册设备号
        初始化cdev //操作函数集合
        注册cdev
        自动产生设备文件
        注册中断
   }
   void __exit btn_drv_exit(void)
   {
   }
   module_init(btn_drv_init);
   module_exit(btn_drv_exit)
 
  以上程序存在的问题:
     1)键值的标准化问题
     
     2)按键缓冲区
        循环缓冲队列
        注意竞态问题的解决
     3)按键按住不放
        按下按键保存了键值之后 开启一个新的定时器
        该定时器隔一段时间就向按键缓冲区中存一个键值
        直到释放按键时停止该定时器   
        
2、按键驱动程序第二个版本:input子系统
  2.1 什么是input子系统
   随着linux内核支持的硬件不断增多
   发现有一类设备,只有输入没有输出:键盘 鼠标 触摸屏...
   这类设备在实现驱动程序时 都要解决
      设备号
      cdev
      自动创建设备文件
      键值缓冲区
      按住不放
      ... ...
   内核设计者将该类设备和硬件无关的代码在内核中实现完毕了
   该部分代码被称作input子系统
 2.2 input子系统的作用  
   驱动工程师在实现某款具体输入设备驱动程序时
   可以复用该部分代码,重点关注硬件相关的驱动代码编程
   缩短输入设备驱动编程的时间
 2.3 input子系统的使用方式(复用该部分代码的方法)
     
     input子系统的核心文件:drivers/input/input.c
     
     核心数据结构
         struct input_dev
         {
             name
             //标识该设备会触发哪些事件 不会哪些事件
             evbit
             /*标识EV_KEY会报告哪些按键编码 不会报告哪些
               按键编码*/
             keybit
             。。。
         }
     使用步骤:
         1)申请一个input_dev变量(kmalloc)
            struct input_dev *input_allocate_device(void)
         2)初始化input_dev变量
         
         3)注册input_dev变量
            int input_register_device(struct input_dev *dev)
         4)硬件操作
            注册中断
            去除抖动
            判断哪个按键触发的
            判断是按下触发还是释放触发
         
         5)报告事件 (保存键值 唤醒睡眠进程)   
            void input_event(struct input_dev *dev,
         unsigned int type, unsigned int code, int value)
         dev, 谁报告的
         type, 报告的事件类型
         code, 当事件类型不同时含义不同
               如果EV_KEY时,其含义为按键编码
         value,事件类型不同 含义不同
               如果EV_KEY时,代表按下触发还是释放触发
               0, 释放触发
               1, 按下触发
         6)注销input_dev变量
            void input_unregister_device(struct input_dev *dev)
         7)释放input_dev变量
            void input_free_device(struct input_dev *dev)
            
   注意:实验时安装模块后对应的设备文件怎么找?
         有两种方式,可以确定对应的设备文件
         1)ls /dev/input/event*
            insmod btn_drv.ko
            ls /dev/input/event*
         2)cat /proc/bus/input/devices
   验证:驱动程序的有效性
         hexdump /dev/input/event5      
序列号     秒        微秒   type code   value
0000000 d7c4 54a4 1e63 0001 0001 0067 0001 0000
0000010 d7c4 54a4 1e70 0001 0000 0000 0000 0000
0000020 d7c4 54a4 1bfc 0004 0001 0067 0000 0000
0000030 d7c4 54a4 1c00 0004 0000 0000 0000 0000                       
 
  课上的要求:能够按照以上7步实现按键驱动程序(能看懂)
 
  更高的要求:研究linux子系统的代码
      
    drivers/input/input.c
    input_init()
    {
        //主设备号为13的设备 对应的操作函数集合是input_fops
        register_chrdev(INPUT_MAJOR, "input", &input_fops);
    }

open("/dev/input/event5", ....)                
    -------------------------------------------
    sys_open()
    {
       struct file btn_file;//全局
       
       input_fops.open(inode, &btn_file)//input_open_file
       {
          //根据次设备号找到该设备对应handler
          //对于按键设备它找的handler是 evdev_handler
          handler = input_table[iminor(inode) >> 5];
          
          //将evdev_handler中记录的操作函数集合地址返回
          new_fops = fops_get(handler->fops)
          
          //将btn_file.f_op修改为 handler中记录的操作函数集合
          file->f_op = new_fops;
       }  
    }

#include "../../global.h"

#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <mach/platform.h> static struct input_dev *btn_input=NULL; typedef struct btn_desc
{
char *name;//名称
int irq;//中断号
unsigned short code;//按键编码值
int gpio;//管脚编号
}btn_desc_t;
btn_desc_t buttons[]=
{
{"up", IRQ_GPIO_A_START+, KEY_UP, PAD_GPIO_A+},
{"down", IRQ_GPIO_B_START+, KEY_DOWN, PAD_GPIO_B+},
{"left", IRQ_GPIO_B_START+, KEY_LEFT, PAD_GPIO_B+},
{"right", IRQ_GPIO_B_START+, KEY_RIGHT, PAD_GPIO_B+}, };
struct timer_list btn_timer; irqreturn_t btn_isr(int irq, void *dev)
{
/*传递按键的描述信息*/
btn_timer.data = (unsigned long)dev; mod_timer(&btn_timer, jiffies+HZ/); return IRQ_HANDLED;
}
void btn_timer_func(unsigned long data)
{
int stat = ;
/*获取哪个按键触发的*/
btn_desc_t *pdata = (btn_desc_t *)data;
/*判断是按下触发还是释放触发*/
stat = gpio_get_value(pdata->gpio); /*5 报告事件(保存键值 唤醒睡眠进程)*/
input_event(btn_input, EV_KEY, pdata->code, !stat);
input_event(btn_input, EV_SYN, , );//此事件是告诉操作系统我报告的事件已经全部报告完成,相当于结束标准。 }
int __init btn_drv_init(void)
{
int i = ;
int ret = ;
/*1 申请input_dev变量*/
btn_input = input_allocate_device();
/*2 初始化input_dev变量*/
btn_input->name = "mybuttons";
//段错误的
//strcpy(btn_input->name, "mybuttons");
/*2.1 配置该设备会报告的事件类型*/
__set_bit(EV_SYN, btn_input->evbit);
__set_bit(EV_KEY, btn_input->evbit);
__set_bit(EV_REP, btn_input->evbit);
/*2.2 配置EV_KEY时会报告的按键编码*/
for(; i<ARRAY_SIZE(buttons); i++)
{
__set_bit(buttons[i].code, btn_input->keybit);
}
/*3 注册input_dev变量*/
ret = input_register_device(btn_input);
/*4 硬件操作*/
for(i=; i<ARRAY_SIZE(buttons); i++)
{
ret = request_irq(buttons[i].irq, btn_isr,
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
buttons[i].name,
buttons+i);
}
init_timer(&btn_timer);
btn_timer.function = btn_timer_func; return ;
}
void __exit btn_drv_exit(void)
{
int i = ; del_timer(&btn_timer);
for(; i<ARRAY_SIZE(buttons); i++)
{
free_irq(buttons[i].irq, buttons+i);
} /*6注销input_dev变量*/
input_unregister_device(btn_input);
/*7释放input_dev变量空间*/
input_free_device(btn_input);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
#include <stdio.h>
#include <fcntl.h>
#include <linux/input.h> //struct input_event key_info;
struct key
{
long sec;
long usec;
unsigned short type;
unsigned short code;
int val;
}key_info; int main(void)
{
int fd = open("/dev/input/event5",
O_RDONLY); while()
{
read(fd, &key_info, sizeof(key_info));
if(key_info.type == EV_KEY)
{
printf("type=%d code=%d value=%d\n",
key_info.type, key_info.code,
key_info.val);
}
}
close(fd);
return ;
}

 

intput子系统的更多相关文章

  1. spi子系统之驱动SSD1306 OLED

    spi子系统之驱动SSD1306 OLED 接触Linux之前,曾以为读源码可以更快的学习软件,于是前几个博客都是一边读源码一边添加注释,甚至精读到每一行代码,实际上效果并不理想,看过之后就忘记了.主 ...

  2. linux输入子系统(input subsystem)之evdev.c事件处理过程

    1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...

  3. Android中基于CGroup的memory子系统HAL层分析-lmkd

    Android在内存管理上于Linux有些小的区别,其中一个就是引入了lowmemorykiller.从lowmemorykiller.c位于drivers/staging/android也可知道,属 ...

  4. Linux内核笔记--网络子系统初探

    内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...

  5. 嵌入式Linux驱动学习之路(十六)输入子系统

    以前写的一些输入设备的驱动都是采用字符设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以实现一种机制,可以对分散的.不同类别的输入设备进行统一的驱动,所以 ...

  6. IP多媒体子系统(IP Multimedia Subsystem,IMS)

      目录 1 什么是IP多媒体子系统[1] 2 IMS产生的背景[2] 3 IMS的特点分析[3] 4 IMS中的功能实体[3] 5 IMS中的接口和协议[3] 6 参考文献 [编辑] 什么是IP多媒 ...

  7. Linux 网络子系统

    今天记录一下Linux网络子系统相关的东西. 因为感觉对这一块还是有一个很大的空白,这件事情太可怕了. 摘抄多份博客进行总结一下Linux网络子系统的相关东西. 一. Linux网络子系统体系结构 L ...

  8. Linux UBI子系统设计初探

    问题领域 flash存储设备存在如下特点: 存在坏块 使用寿命较短 存储介质不稳定 读写速度慢 不支持随机访问(nand) 只能通过擦除将0改成1 最小读写单位为page or sub-page 便宜 ...

  9. linux kernel的中断子系统 softirq

    linux kernel的中断子系统之(八):softirq http://www.wowotech.net/irq_subsystem/soft-irq.html http://www.ibm.co ...

随机推荐

  1. java新学者(二)

    一.构造方法的特点 创建新的对象 A a =new A (); 二.抽象类和抽象方法的特点是什么? .抽象类使用abstract修饰: .抽象类不能实例化,即不能使用new关键字来实例化对象: .含有 ...

  2. 王艳 201771010127《面向对象程序设计(java)》第二周学习总结

     王艳 201771010127<面向对象程序设计(java)>第二周学习总结 第一部分:理论知识学习部分 3.1:基本概念. 1)标识符:标识符由字母.数字.美元符号以及下划线组成.且第 ...

  3. Spring Boot在Docker上的部署

    一.准备工作 1.1 安装Docker环境 Docker 给旧版本的WIN系统提供的是Docker Toolbox下载(https://docs.docker.com/toolbox/overview ...

  4. JAVA设计模式之原型模式(prototype)

    原型模式: 原型模式又叫克隆模式 Java自带克隆模式 实现克隆模式必须实现Cloneable 接口,如果不实现会发生java.lang.CloneNotSupportedException异常 当某 ...

  5. Vue 更换页面图标和title

    1.基础的做法就是直接换掉,logo换的时候需要使用icon格式的图标 title 直接在index.html 里面把原来的title注释掉 或者直接改了就行 2. 如果需要进行相应的改变啥的 ,需要 ...

  6. centos 7 firewalld防火墙配置

    1.查看firewall服务状态 systemctl status firewalld 2.查看firewall的状态 firewall-cmd --state 3.开启.重启.关闭.firewall ...

  7. Django + Celery 实现动态配置定时任务

    哈喽,今天给大家分享一篇Django+Celery实现动态配置定时任务,因为最近也是无意间看到一位大佬关于这块的文章,然后自己觉得不错,也想学习写一下,然后最终实现功能是在前端页面统一管理计划任务,大 ...

  8. SQL查找大小为n的连续区间

    数据准备 create table sequence ( seq int not null primary key ); insert into values(3); insert into valu ...

  9. 【Ubuntu】Ubuntu系统启动过程中,输入用户名与密码后登录一直卡在紫色界面问题(未解决,最后通过重装系统)

    0. 前言 由于本电脑为公用电脑,可能由于其他人点了图像界面中推荐的内核更新,导致原来安装的NVIDIA显卡驱动 430 与升级后的 5.0 内核不兼容,从而导致输入用户名后登录一直卡在紫色界面.在排 ...

  10. 二维DCT变换 | Python实现

    引言 最近专业课在学信息隐藏与数字水印,上到了变换域隐藏技术,提到了其中的DCT变换,遂布置了一个巨烦人的作业,让手动给两个\(8\times8\)的矩阵做二维DCT变换,在苦逼的算了一小时后,我决定 ...