IMX257 输入子系统

发布时间:2024-08-14  

一、输入子系统

1.输入子系统结构体定义

struct input_dev{

 

const char *name; 设备名

const char *phys; 设备在系统中路径

const char *uniq;

struct input_id id; 用于匹配input hander参数

unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

 

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

//设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等

 

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)];

 

unsigned int hint_events_per_packet;

 

unsigned int keycodemax;

 

unsigned int keycodesize;

 

void *keycode;

 

int (*setkeycode)(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode);

 

int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke);

 

struct ff_device *ff;

 

unsigned int repeat_key;

 

struct timer_list timer;

 

int rep[REP_CNT];

 

struct input_mt_slot *mt;

 

int mtsize;

 

int slot;

 

int trkid;

 

struct input_absinfo *absinfo;

 

unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //按键对应的键值

 

unsigned long led[BITS_TO_LONGS(LED_CNT)]; //LED对应的指示灯状态

 

unsigned long snd[BITS_TO_LONGS(SND_CNT)];

 

unsigned long sw[BITS_TO_LONGS(SW_CNT)];

 

int (*open)(struct input_dev *dev);

 

void (*close)(struct input_dev *dev);

 

int (*flush)(struct input_dev *dev, struct file *file);

 

int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

//事件处理函数,主要是接收用户下发的命令,如点亮led;

 

struct input_handle __rcu *grab;

 

spinlock_t event_lock;

 

struct mutex mutex;

 

unsigned int users;

 

bool going_away;

 

bool sync;

 

struct device dev;

 

struct list_headh_list; //设备所支持的input handle;

 

struct list_headnode;

 

};

 

输入设备信息:

输入设备信息,匹配input hander时主要用下面参数

struct input_id {

__u16 bustype; 总线类型

__u16 vendor; 产家编号

__u16 product; 产品编号

__u16 version; 版本信息

};

 

2.输入设备事件处理结构

用于 输入设备事件处理 的数据结构:

struct input_handler {

void *private;

 

void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

 

bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

 

bool (*match)(struct input_handler *handler, struct input_dev *dev);

 

int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

//当输入设备和input handler相匹配时调用该函数;

 

void (*disconnect)(struct input_handle *handle);

 

void (*start)(struct input_handle *handle);

 

const struct file_operations *fops; //所支持的file operation操作;

 

int minor;

 

const char *name;

 

const struct input_device_id *id_table; //所有能够支持的输入设备;

 

struct list_headh_list;

 

struct list_headnode;

};

 

3. 链接input_dev 和input_handler 的结构体

连接input-dev 和input handler的数据结构:

struct input_handle {

void *private;

int open;

const char *name;

struct input_dev *dev; input dev

struct input_handler *handler; input handler

struct list_headd_node;

struct list_headh_node;

};

 

 

4. 注册和注销函数

int input_register_device(struct input_dev *dev)

int input_unregister_device(struct input_dev *dev)

 

5. 驱动事件支持

设备驱动通过set_bit()告诉input子系统它支持哪些事件,哪些按键。例如:

set_bit(EV_KEY,button_dev.evbit)

struct input_dev中的两个成员:

evbit--事件类型

keybit--按键类型

 

事件类型:

EV_RST--reset

EV_REL--相对坐标

EV_MSC--其它

EV_SND--声音

EV_FF--力反馈

EV_KEY--按键

EV_ABS--绝对坐标

EV_LED--led

EV_REP--repeat

 

当事件类型为EV_KEY时,还需指明按键类型:

BTN_LEFT--鼠标左键

BTN_RIGHT--鼠标右键

BTN_MIDDLE--鼠标中键

BTN_0--数字0键

BTN_1--数字1键

 

6. 事件报告

Void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value);

//报告指定type,code的输入事件

Void input_report_key(struct input_dev *dev,unsigned int code,int value); //报告键值

Void input_report_rel(struct input_dev *dev,unsigned int code,int value); //报告相对坐标

Void input_report_abs(struct input_dev *dev,unsigned int code,int value); //报告绝对坐标

Void input_sync(struct input_dev *dev);

//报告同步事件 在触摸屏驱动设计中,一次坐标及按下状态的整个报告过程如下:

Input_report_abs(input_dev,ABS_X,x); //X坐标

Input_report_abs(input_dev,ABS_Y,y); //Y坐标

Input_report_abs(input_dev,ABS_PRESSURE,pres); //压力

 

input_sync(struct input_dev *dev); //同步

 

structinput_event {

struct timeval time;

__u16 type;

__u16 code;

__s32 value;

};

① code

事件的代码。如果事件类型是EV_KEY,该代码则为设备的键盘代码。例如:键盘上的按键代码值为0--127,鼠标按键代码为0x110---0x116,其中0x110(BTN_LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标左键,其它代码含义参考include/linux/input.h文件。

 

②value

事件的值。若事件的类型是EV_KEY,当按键按下时值为1,松开值为0

 

报告完毕之后,input_sync()通知系统接受,告诉input core:此次报告已结束。

 

二、程序分析

1.定义输入子系统结构体

 

2.设置GPIO引脚模式及初始化GPIO中断

 

3.输入子系统相关设置

如图所示:

80行 分配一个input_dev结构体

82行 设置输入子系统支持按键操作

83行 设置支持按键的类型为BTN_0

84行 设置名字和初始化名字

86行 注册输入子系统

 

4.初始化定时器,用于防抖动

 

5.发生按键操作时,进入中断中断,开启定时器

 

如图所示,全局保存发生发生中断的引脚,然后开启定时器,在定时器中断函数中处理。

 

6.定时器中断函数

如图所示,在定时器中断函数中,获取发生按键的键值,然后使用input_report_key函数向系统报告事件,接着就是使用input_sync函数通知接收者,报告完毕。

 

7. 在exit函数中注销

如图所示,在exit函数中,将我们前面申请的GPIO端口和GPIO中断都释放,然后删除定时器,

接着就是注销我们的输入子系统,释放输入子系统结构体。

 

8.测试: 在应用程序中打开设备

如图所示,在/dev/input/下面有event1。

9.读取输入子系统

如图所示,

我们使用read函数来读取输入子系统的数据,注意此处我们得到的是一个input_event的结构体。

接着如果我们的信息是按键按下,则打印按键一些信息,如果是通知信息,则打印syn event。

10.编译测试

附驱动程序:


  1 /******************************

  2     linux key_inputSystem

  3  *****************************/

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include //error: 'TASK_INTERRUPTIBLE' undeclared 

 17 #include

 18 #include

 19 #include

 20 #include

 21 

 22 #include 'mx257_gpio.h'

 23 #include 'mx25_pins.h'

 24 #include 'iomux.h'

 25 

 26 #define Driver_NAME 'key_input'

 27 #define GPIO2_10    MX25_PIN_A24

 28 //定义各个按键按下的键值

 29 struct pin_desc{

 30     unsigned int pin;

 31     unsigned int key_val;

 32 };

 33 //当按键按下时,键值分别为 以下值

 34 struct pin_desc pins_desc[1] = {

 35     {GPIO2_10,    0x05},

 36 };

 37 

 38 static struct input_dev *key_input_dev;//输入子系统设备结构体

 39 static struct timer_list key_timer;    //定时器结构体

 40 static struct pin_desc *pin_desc_irq; //保存发生中断的引脚信息

 41 

 42 //定时器到时函数

 43 static int key_timer_function(unsigned long data){    

 44     struct pin_desc *pin_desc_tmp = pin_desc_irq;    //发生中断的引脚信息

 45     unsigned int pinval_tmp;        //按键键值缓冲

 46     if(!pin_desc_tmp)

 47         return 0;

 48     pinval_tmp = gpio_get_value(IOMUX_TO_GPIO(pin_desc_tmp->pin));//获取键值

 49     if(!pinval_tmp){

 50         input_report_key(key_input_dev, BTN_0,0);

 51         input_sync(key_input_dev);                //报告完毕,通知接收者

 52     }else{

 53         input_report_key(key_input_dev, BTN_0, 1);

 54         input_sync(key_input_dev);                //报告完毕,通知接收者

 55     }

 56     return 0;

 57 }

 58 /* 中断程序key_irq */

 59 static irqreturn_t key_irq_function(int irq, void *dev_id)

 60 {

 61     pin_desc_irq = (struct pin_desc *)dev_id; //获取中断引脚的信息

 62     mod_timer(&key_timer,jiffies+HZ/50);    //开启定时器,时间20ms

 63 

 64     return IRQ_RETVAL(IRQ_HANDLED);

 65 }

 66 //初始化函数

 67 static int __init  key_input_init(void)

 68 {

 69     printk('<0>nHello,this is %s module!nn',Driver_NAME);

 70       

 71     mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);//设备引脚为GPIO模式

 72      gpio_request(IOMUX_TO_GPIO(GPIO2_10), 'GPIO2_10');//申请IO端口使用

 73     gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));//设备引脚为输入

 74     //设备引脚为上拉输入

 75     mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_100K_PU);

 76     if(request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq_function, IRQF_TRIGGER_FALLING, 'key_GPIO2_10', &pins_desc[0]))

 77         return -1;

 78     

 79     //input输入子系统设置

 80     key_input_dev = input_allocate_device();//分配一个input_dev结构体

 81     //设置能产生哪些事件

 82     key_input_dev->evbit[0] = BIT_MASK(EV_KEY);   //设置按键信息

 83     key_input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);

 84     key_input_dev->name = 'key_input_name';

 85     key_input_dev->dev.init_name = 'key_input_init_name';

 86     input_register_device(key_input_dev);

 87 

 88     init_timer(&key_timer);    //初始化定时器

 89     key_timer.function = &key_timer_function;    //设置定时器处理函数

 90     add_timer(&key_timer);    //将该定时器加入内核

 91     

 92     printk('<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !n');

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>