話說Android中Event輸入裝置驅動原理分析還不如說Linux輸入子系統呢,反正這個是沒變的,在android的底層開發中對于Linux的基本驅動程式設計還是沒變的,當然Android底層機制也增加幾個屬于android自己的機制。典型的IPC
Android中的input裝置驅動主要包括:遊戲杆(joystick)、滑鼠(mouse)和事件裝置(Event)。
1、Input輸入子系統的構架,在網上找到兩幅灰常漂亮的圖。
下面這幅更漂亮,更直覺的能看出input型輸入子系統究竟是什麼咚咚,更能夠展現出,使用者空間,核心空間,驅動程式是怎麼關聯起來的。。。
Input驅動同樣也是字元裝置,主裝置号是13,次裝置号是64~95之間自動生成的,這個Input驅動程式那是相當相當的複雜。在android核心中主要需要關注一下幾個檔案
a)include/linux/input.h(驅動頭檔案)
b)driver/input/input.c (驅動核心實作,包含大量的操作接口)
c)driver/input/event.c (event機制)
d)driver/input/joydev.c (joystick驅動)
e)driver/input/mousedev.c(滑鼠驅動)
其實上面這些東西都不要我們自己去實作核心已經幫我們實作好了,不過我們在寫硬體驅動的時候需要和Inputcore互動,是以需要用到上面這些函數中的接口,也就是說上面這些函數是透明的。
2、Event事件驅動原理及其實作
在核心中,用input_dev來描述一個Input裝置,該結構的定義如下,其中核心中使用input_register_device(struct input_dev *dev)來注冊一個input裝置
這個結構體好長,是以就列了幾個。。。。它的定義在input.h當中
struct input_dev {
。。。。。。。。。。。
struct input_id id;
bool sync;
struct device dev;
struct list_head h_list; //
struct list_head node; //input_handle連結清單的list節點
};
用input_handler表示input裝置的接口,使用input_register_handler(structinput_handler *handler)注冊
struct input_handler {
void *private;
。。。。。。。。。。
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;
struct list_head h_list;
struct list_head node;
};
Event事件驅動實作過程
1)Input裝置注冊
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
__set_bit(EV_SYN, dev->evbit);//see to inpu.h
__clear_bit(KEY_RESERVED, dev->keybit);
input_cleanse_bitmasks(dev);
init_timer(&dev->timer);
//處理重複按鍵.如果沒指派則為其賦預設的值
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
if (!dev->getkeycode)//擷取鍵的掃描碼
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)//設定鍵值
dev->setkeycode = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
//将input_dev中封裝的device注冊到sysfs
error = device_add(&dev->dev);
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
//将input_device挂到input_dev_list連結清單中
list_add_tail(&dev->node, &input_dev_list);
//對挂載在input_dev_list中的每一個handler調用input_attach_handler(dev, handler);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
上述函數首先将input_device挂接到input_dev_list連結清單上,然後對挂載在input_dev_list中的每一個handler調用input_attach_handler(dev, handler)來進行比對,舉個例子,裝置模型中的device和driver的比對,所有的input device都挂載在input_dev_list上而所有的handler都挂載在input_handler_list上,那麼它們是怎麼聯系起來的?比對過程如下
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;
id = input_match_device(handler, dev);
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
上面函數調用input_match_device來對handler, dev通過input_device_id *id來進行比對如果比對成功則調用handler->connect來關聯struct input_dev *dev, 和struct input_handler *handler結構。下面看看input_match_device(handler, dev)的過程
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
if (i != BITS_TO_LONGS(max)) \
continue;
static const struct input_device_id *input_match_device(struct input_handler *handler,struct input_dev *dev)
{
const struct input_device_id *id;
int i;
for (id = handler->id_table; id->flags || id->driver_info; id++) {//flags配置比對的類型
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)//比對總線類型
if (id->bustype != dev->id.bustype)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)//比對廠商
if (id->vendor != dev->id.vendor)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)//比對制造商
if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)//比對版本号
if (id->version != dev->id.version)
continue;
//如果上面的id->flags比對成功或者是id->flags沒有定義則執行下面的函數
MATCH_BIT(evbit, EV_MAX);
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit, FF_MAX);
MATCH_BIT(swbit, SW_MAX);
if (!handler->match || handler->match(handler, dev))
return id;
}
return NULL;
}
其中handler的注冊和上述類似,感興趣的朋友可以讀linux核心源碼