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("Failed to register input device\n");
goto err1;
}
這部分代碼input_allocate_device()和input_register_device()的使用比較好理解,需要注意的是input_dev初始化這部分內容
在這個input_dev一般需要初始化的主要有如下成員:
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]);
}
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)];