Linux内核孩子Input子系统

来源:互联网 发布:香港中文大学人工智能 编辑:程序博客网 时间:2024/06/06 04:44

 

 0.在学习Linux驱动的过程中,遇到一个宏叫做container_of。
 该宏定义在include/linux/kernel.h中,首先来贴出它的代码:

 #define container_of(ptr, type, member) ({\
 const typeof( ((type *)0)->member ) *__mptr = (ptr);\
 /**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:        the pointer to the member.
 * @type:       the type of the container struct this is embedded in.
 * @member:     the name of the member within the struct.
 * */

 它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。
 比如,有一个结构体变量,其定义如下:
 struct demo_struct {
  type1 member1;
  type2 member2;
  type3 member3;
  type4 member4;
 };     
  struct demo_struct demo;
  同时,在另一个地方,获得了变量demo中的某一个域成员变量的指针,比如:
  type3  *memp = get_member_pointer_from_somewhere();
  此时,如果需要获取指向整个结构体变量的指针,而不仅仅只是其某一个域成员变量的指针,我们就可以
  这么做:struct demo_struct *demop = container_of(memp, struct demo_struct,member3);

 1.更改程序启动界面logo:
   执行/ARM/shared_arm_development/tools/usr/sbin目录下的可执行文件,调出图片图形化界面
   添加图片转换生成目标文件,将目标文件存放在/ARM/linux-3.5-millet/drivers/video/logo目录下
   在/ARM/linux-3.5-millet/目录下编译内核生存zImage文件,将新的zImage文件烧写到开发板上

 2.Input子系统架构:
   Linux系统提供了input子系统,按键、触摸屏、键盘、鼠标等输入都可以利用input接口函数来实现设备驱动,下
   面是Input子系统架构:
 
   2.1)Input系统的组成

    输入子系统由驱动层(Drivers),输入子系统核心层( Input Core)和事件处理层(EventHandler)三部份组
    成。一个输入事件,如鼠标移动,键盘按键按下等都是通过 Driver-> InputCore -> Eventhandler -> userspace
    的顺序到达用户空间传给应用程序。下面介绍各部分的功能:

    1).驱动层功能:负责和底层的硬件设备打交道,将底层硬件设备对用户输入的响应转换为标准的输入事件以后再
    向上发送给输入子系统核心层(InputCore).
    2).Input系统核心层:Input Core即InputLayer,由driver/input/input.c及相关头文件实现,它对下提供了设备
    驱动层的接口,对上提供了事件处理层(EventHandler)的编程接口.
       3).事件处理层将硬件设备上报的事件分发到用户空间和内核.
  
   2.2).Input设备驱动编写
     在Linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核
     心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再
     需要关心文件操作接口,因为input子系统已经完成了文件操作接口。驱动报告的事件经过InputCore和
     Eventhandler最终到达用户空间.
    
      2.3).利用linux 内核所提供的input子系统编写字符设备驱动的步骤:

包含头文件:
#include <linux/input.h>

涉及核心结构体:
struct input_dev {
 .........
 unsigned long evbit[BITS_TO_LONGS(EV_CNT)];   //用于描述设备所产生数据的事件分类

 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //根据事件分类设置具体编码
 unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
 unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
 unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
};

第一步:实例化输入设备对应的结构体指针
   static struct input_dev *inputdev;

第二步:为输入设备结构体指针指向的对象分配空间。
   inputdev = input_allocate_device();

第三步:设置事件分类对应的成员数组和根据事件分类设置编码数组。

可以使用如下两种方法设置:
 
 宏:
 BIT_WORD(), BIT_MASK();

 利用函数来设置:
 
 set_bit(nr, long *array);
 
 button_dev->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY);
 button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
 
 //set_bit(EV_KEY, evbit);
 //set_bit(BTN_0, keybit);

//第四步:向内核注册输入设备
      error = input_register_device();

//反向注册:input_unregister_device();

 如果注册失败,需要使用input_free_device(); 释放利用
 input_allocate_device(); 分配的空间。

//第五步:在拿到数据的地方向用户态上报。

 input_report_abs();
 input_report_rel();
 input_report_key();
 input_sync();
 input_mt_sync();

 他们都调用input_event();

0 0
原创粉丝点击