2.1. 驱动框架搭建
键盘驱动是典型的字符设备驱动,由于zlg7290使用的是I2C总线,所以这里首先搭建一个基于input子系统的驱动框架
static int zlg7290_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
return 0;
}
static int zlg7290_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id zlg7290_id[] = {
{ZLG7290_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, zlg7290_id);
static struct i2c_driver zlg7290_driver= {
.probe = zlg7290_probe,
.remove = zlg7290_remove,
.id_table = zlg7290_id,
.driver = {
.name = ZLG7290_NAME,
.owner = THIS_MODULE,
},
};
static int __init zlg7290_init(void)
{
return i2c_add_driver(&zlg7290_driver);
}
static void __exit zlg7290_exit(void)
{
i2c_del_driver(&zlg7290_driver);
}
MODULE_AUTHOR("farsight");
MODULE_DESCRIPTION("zlg7290 driver");
MODULE_LICENSE("GPL");
module_init(zlg7290_init);
module_exit(zlg7290_exit);
2.2. Input驱动框架搭建
键盘一般在内核中被注册为input设备,所以本例也需要将我们的键盘注册为一个input设备,input设备注册相关函数及结构体如下:
struct input_dev;
struct input_dev *input_allocate_device();
int input_register_device(struct input_dev *);
input_dev是linux内核中用来描述一个input设备的结构体,这个结构体用来描述一个input设备。
input_allocate_device内核中用来为input_dev分配空间的函数,这个函数不能被kmalloc等分配内存空间的函数替代,因为这个函数处理分配空间外还做了一些基本的初始化。
input_register_device内核中用来注册input_dev到linux内核中的函数,在调用这个函数前必须完成input_dev的初始化。
如下:
C++ Code
zlg7290->key = input_allocate_device();
if (zlg7290->key == NULL) {
kfree(zlg7290);
return -ENOMEM;
}
key_dev = zlg7290->key;
key_dev->name = "zlg7290";
key_dev->id.bustype = BUS_HOST;
key_dev->id.vendor = 0x0001;
key_dev->id.product = 0x0001;
key_dev->id.version = 0x0001;
key_dev->evbit[0] = BIT_MASK(EV_KEY);
for(i = 1; i <= 64; i++) {
key_dev->keybit[BIT_WORD(key_value<i>)] |= BIT_MASK(key_value<i>);
}
ret = input_register_device(key_dev);
if (ret < 0) {
printk(&quot;Failed to register input device\n&quot;);
goto err1;
}
这部分代码input_allocate_device()和input_register_device()的使用比较好理解,需要注意的是input_dev初始化这部分内容
在这个input_dev一般需要初始化的主要有如下成员:
key_dev->name = &quot;zlg7290&quot;;
key_dev->id.bustype = BUS_HOST;
key_dev->id.vendor = 0x0001;
key_dev->id.product = 0x0001;
key_dev->id.version = 0x0001;
这些成员主要是一些描述类信息。
key_dev->evbit[0] = BIT_MASK(EV_KEY);
for(i = 1; i <= 64; i++) {
key_dev->keybit[BIT_WORD(key_value<i>)] |= BIT_MASK(key_value<i>);
}
key_dev->evbit[0] = BIT_MASK(EV_KEY);
evbit是设备所支持的事件类型,在这里我们使用EV_KEY作为我们的事件类型,有些设备支持多种事件类型。Linux内核时间类型很多,不同设备在注册时使用不同事件类型:
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
key_dev->keybit[BIT_WORD(key_value<i>)] |= BIT_MASK(key_value<i>);
keybit中每一位对应一个按键,初始化所有位都为0,当某一位被置1时,对应按键才能生效。按键需要初始化keybit,如果是其他的input设备则需要初始化其他成员,如下:
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)];
|