概述
输入子系统:为上层应用提供统一的抽象层;实现为驱动层提供统一的接口函数;
输入子系统有三层:上层为核心层input.c,其中包含registe_chrdev,里面的file operation结构体只有open函数,早open函数中会有一个中转的过程,利用input_table数组根据打开设备结点的次设备号找到一个handler,调用其中的open函数,并且将file operation指向handler中的file operation,之后读写都是调用这个新的file operation中的read和write;下层有input_handler(纯软件层)和input_dev(硬件层),通过向上调用input_register_handler和input_register_device向上注册;注册input_dev或者input_handler时,会比较input_handler和input_device能不能支持(根据input_hadler的id_table来判断这个input_handler能否支持该input_dev),如果能支持,则调用input_handler的connect函数来建立连接;
建立连接过程:
1.分配一个input_handle结构体;
2. 设置input_handle结构体中dev和handler指向
input_handle.dec = dev //指向input_dev;
input_handle.handler = handler //指向input_handler
3.注册:将input_handler的h_list和input_dev的h_list指向input_handle;
input_hansler->h_list = &input_handle;
input_dev->h_list = &input_handle;
input_handler结构体成员:
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
const struct file_operations *fops;
int minor;
const char *name;
const struct input_device_id *id_table;
const struct input_device_id *blacklist;
struct list_head h_list;
struct list_head node;
};
id_table:所支持的设备id表
fops:该handler的fileo peration
connect:用于找到对应的input_device之后的连接
disconnect:断开连接
.event:事件处理函数,让device调用
h_list:用于保存input_handle结构体指针
input_dev结构体成员:
struct input_dev {
void *private;
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[NBITS(EV_MAX)]; //设备支持的事件类型
unsigned long keybit[NBITS(KEY_MAX)]; //设备支持的按键类型
unsigned long relbit[NBITS(REL_MAX)]; //相对位移事件
unsigned long absbit[NBITS(ABS_MAX)]; //绝对位移事件
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int state;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
unsigned long sw[NBITS(SW_MAX)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
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);
struct input_handle *grab;
struct mutex mutex; /* serializes open and close operations */
unsigned int users;
struct class_device cdev;
union { /* temporarily so while we switching to struct device */
struct device *parent;
} dev;
struct list_head h_list;
struct list_head node;
}
input_handler和input_dev分别使用两个链表进行维护,这两个链表都是全局链表;
input_handle结构体
该结构体没有链表对其进行维护,当input_dev和input_handler分别向上层进行注册并连接时,input_handle中的dev指针就会指向对应的input_dev;handler指针会指向对应的input_handler结构体;而input_handler和input_dev中的h_list都会指向这个input_handle结构体,让三个结构之间建立联系;
读取数据:
应用层程序读取read会导致某一个handler中的evdev_fops中的读函数(evdev_read)被调用;
唤醒使用evdev_event :
evdev_event被谁调用:设备中断服务函数程序里,确定事件是什么,然后调用相应的input_handler的event处理函数;
输入子系统驱动程序框架:
1.分配一个input_dev结构体;
2.设置;
3.注册;
4.硬件相关代码(如中断服务程序上报事件);
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/device.h> //class_create
#include <mach/regs-gpio.h> //S3C2410_GPF1
//#include <asm/arch/regs-gpio.h>
#include <mach/hardware.h>
//#include <asm/hardware.h>
#include <linux/interrupt.h> //wait_event_interruptible
#include <linux/poll.h> //poll
#include <linux/fcntl.h>
#include <linux/input.h>
static struct pin_desc{
int irq;
unsigned char *name;
unsigned int pin;
unsigned int key_val;
};
static struct pin_desc pins_desc[4] = {
{IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
{IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
{IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
{IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
};
static struct pin_desc *irq_pd;
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;
/* 用户中断处理函数 */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
irq_pd = (struct pin_desc *)dev_id;
/* 修改定时器定时时间,定时10ms,即10秒后启动定时器
* HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
* 这里HZ/100即定时10ms
*/
mod_timer(&buttons_timer, jiffies + (HZ /100));
return IRQ_HANDLED;
}
/* 定时器处理函数 */
static void buttons_timer_function(unsigned long data)
{
struct pin_desc *pindesc = irq_pd;
unsigned int pinval;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if(pinval)
{
/* 松开 最后一个参数: 0-松开, 1-按下 */
input_event(buttons_dev,EV_KEY,pindesc->key_val,0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev,EV_KEY,pindesc->key_val,1);
input_sync(buttons_dev);
}
}
/* 驱动入口函数 */
static int buttons_input_init(void)
{
int i;
/* 1.分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
/* 2.设置 */
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,buttons_dev->evbit);
set_bit(EV_REP,buttons_dev->evbit);
/* 2.2 设置能产生这类操作的哪些事件 */
set_bit(KEY_L,buttons_dev->keybit);
set_bit(KEY_S,buttons_dev->keybit);
set_bit(KEY_ENTER,buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
/* 3.注册 */
input_register_device(buttons_dev);
/* 4.硬件相关的设置 */
/* 4.1 定时器相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
/* 4.2 申请中断 */
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
/* 驱动出口函数 */
static void buttons_input_exit(void)
{
int i;
for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
}
del_timer(&buttons_timer);
input_unregister_device(buttons_dev);
input_free_device(buttons_dev);
}
module_init(buttons_input_init); //用于修饰入口函数
module_exit(buttons_input_exit); //用于修饰出口函数
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL"); //遵循GPL协议
最后
以上就是秀丽豌豆为你收集整理的Linux驱动——Linux输入子系统的全部内容,希望文章能够帮你解决Linux驱动——Linux输入子系统所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复