输入子系统是对多种不同类别的输入设备(如键盘、鼠标、跟踪球、操作杆、触摸屏、加速计和手写板)进行统一处理(inputcore)的驱动程序。
输入子系统带来的好处:
①统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论是PS/2、USB,还是蓝牙,都做同样的处理;
②提供了给用户应用程序的简单的事件接口;
③抽取出了输入驱动程序的通用部分,也简化了驱动程序
在Linux内核中用input_dev结构体来描述input设备。驱动的核心工作是向系统报告按键,触摸屏,鼠标等输入事件(event,用input_event描述),驱动中不再需要关心文件操作接口,驱动报告的事件经过inputcore和eventhardler,最终到达用户空间
驱动实现:
①分配input结构,并用set_bit()告诉input子系统需要报告那些事件,
②注册输入设备
③在有按键按下/抬起、或触摸屏被触摸/抬起/滑动等发生时(用中断或查询抓捕事件发生),用report_xxx()报告发生的事件及对应的键值/坐标状态
主要事件包括:
EV_KEY(案件事件),
EV_REL(相对值,比如光标移动,是相对最后一次位置的偏移),
EV_ABS(绝对值,比如触摸屏坐标)
- 常见典型事件
- EV_RST 0x00 Reset
-
EV_KEY 0x01 按键
-
EV_REL 0x02 相对坐标
-
EV_ABS 0x03 绝对坐标
-
EV_MSC 0x04 其它
-
EV_LED 0x11 LED
-
EV_SND 0x12 声音
-
EV_REP 0x14 Repeat
-
EV_FF 0x15 力反馈
报告EV_KEY,EV_REL,EV_ABS的函数分别是
- 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)
input_sync()用于事件同步,告诉事件接收者驱动已经发出了一个完整的报告。比如触摸屏案件事件
- void input_report_abs(input_dev,ABS_X,x);
-
void input_report_abs(input_dev,ABS_Y,y);
-
void input_report_abs(input_dev,ABS_PRESSURE,pres);//压力
-
input_sync(input_dev);
注册,注销函数
- void input_register_device(struct input_dev *dev)
-
void input_unregister_device(struct input_dev *dev)
下面摘录自手头案例的部分代码(按键板输入,IIC接口)
- #define JG616L_I2C_ADDR (0xc>>1)
-
static struct jg616l_chip *g_jg616l_chip;
-
struct key_val {
-
unsigned int usVal;
-
unsigned int ucKey;
-
};
-
-
static struct key_val gstKey[] = {
-
{0x02, KEY_1},
-
{0x03, KEY_2},
-
{0x04, KEY_3},
-
{0x05, KEY_4},
-
{0x06, KEY_5},
-
{0x07, KEY_6},
-
{0x08, KEY_7},
-
{0x09, KEY_8},
-
{0x0a, KEY_9},
-
{0x01, KEY_ESC},
-
{0x0b, KEY_0},
-
{0x1c, KEY_ENTER},
-
{0x1e, KEY_A}, //F1
-
{0x30, KEY_B}, //F2
-
{0x2e, KEY_C}, //F3
-
};
-
-
static void scan_max7349_key(unsigned long data)
-
{
-
unsigned char ucVal, ucVal1, ucLoop, ucData[4];
-
struct i2c_client *client;
-
-
struct jg616l_chip *stMaxChip;
-
unsigned short usVal = 0, usGpio = 0;
-
stMaxChip = g_jg616l_chip;
-
-
int i = 0;
-
i2c_read_reg(gstI2cHandle, &usVal);//从I2C器件读到按键值,要是IO案件的话,要做消抖处理
-
if (0 == usVal)
-
return;
-
if (0x1ff >= usVal) {
-
for (i = 0; i < ARRAY_SIZE(gstKey); i++) {
-
if (usVal == gstKey[i].usVal) {
-
input_report_key(stMaxChip->key_input,gstKey[i].ucKey, 1);
-
input_sync(stMaxChip->key_input);//提交一个完整的input事件
-
return;
-
}
-
}
-
}
-
}
-
-
static irqreturn_t jg616l_irq(int irq, void *handle)
-
{
-
unsigned char ucData;
-
struct i2c_client *client;
-
unsigned long ulFlag;
-
struct jg616l_chip *stMaxChip = handle;
-
-
schedule_work(&stMaxChip->work);//中断函数里,启动scan_max7349_key函数
-
-
return IRQ_HANDLED;
-
}
-
-
static int jg616l_probe(struct i2c_client *client)
-
{
-
struct input_dev *key_input;
-
int err = 0;
-
struct jg616l_chip *stMaxChip;
-
u32 key_val;
-
-
stMaxChip = kzalloc(sizeof(struct jg616l_chip), GFP_KERNEL);
-
if (NULL == stMaxChip) {
-
printk("Can't malloc memony!\r\n");
-
return -ENOMEM;
-
}
-
-
INIT_WORK(&stMaxChip->work, scan_max7349_key, NULL);
-
key_input = kzalloc(sizeof(struct input_dev), GFP_KERNEL);//分配input结构体
-
-
if (!key_input) {
-
printk("key input devices err!\r\n");
-
return -ENOMEM;
-
}
-
stMaxChip->key_input = key_input;
- set_bit(EV_KEY,key_input->evbit);//向input注册事件类型
-
-
for (ucLoop = 0; ucLoop < ARRAY_SIZE(gstKey); ucLoop++) {
-
__set_bit(gstKey[ucLoop].ucKey, key_input->keybit);//注册按键值
-
}
- //申请中断
-
if (request_irq(stMaxChip->jg616l_irq, jg616l_irq, 0, key_input->name,stMaxChip)) {
-
printk("request irq failed!\r\n");
-
err = -EBUSY;
-
free_irq(stMaxChip->jg616l_irq, stMaxChip);
-
goto err_free_irq;
-
}
-
-
input_register_device(key_input);//注册input设备
-
-
return err;
-
err_free_irq:
-
-
kfree(stMaxChip->key_input);
-
kfree(stMaxChip);
-
return err;
-
}
-
-
static int jg616l_remove(struct i2c_client *client)
-
{
-
struct jg616l_chip *stMaxChip;
-
-
input_unregister_device(stMaxChip->key_input);//注销input设备,释放相关资源
-
free_irq(stMaxChip->jg616l_irq, stMaxChip);
-
kfree(stMaxChip->key_input);
-
-
return 0;
-
}
阅读(1538) | 评论(0) | 转发(0) |