input子系統

drivers/input/input.c:
input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);node

static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};數組

問:怎麼讀按鍵?app

input_open_file
struct input_handler *handler = input_table[iminor(inode) >> 5];
new_fops = fops_get(handler->fops) // =>&evdev_fops
file->f_op = new_fops;
err = new_fops->open(inode, file);框架

app: read > ... > file->f_op->read函數

input_table數組由誰構造?測試

input_register_handlercode

註冊input_handler:
input_register_handler
// 放入數組
input_table[handler->minor >> 5] = handler;事件

// 放入鏈表
list_add_tail(&handler->node, &input_handler_list);

// 對於每一個input_dev,調用input_attach_handler
list_for_each_entry(dev, &input_dev_list, node)
	input_attach_handler(dev, handler); // 根據input_handler的id_table判斷可否支持這個input_dev

註冊輸入設備:
input_register_device
// 放入鏈表
list_add_tail(&dev->node, &input_dev_list);get

// 對於每個input_handler,都調用input_attach_handler
list_for_each_entry(handler, &input_handler_list, node)
	input_attach_handler(dev, handler); // 根據input_handler的id_table判斷可否支持這個input_dev

input_attach_handler
id = input_match_device(handler->id_table, dev);input

error = handler->connect(handler, dev, id);

註冊input_dev或input_handler時,會兩兩比較左邊的input_dev和右邊的input_handler,
根據input_handler的id_table判斷這個input_handler可否支持這個input_dev,
若是能支持,則調用input_handler的connect函數創建"鏈接"

怎麼創建鏈接?

  1. 分配一個input_handle結構體
  2. input_handle.dev = input_dev; // 指向左邊的input_dev
    input_handle.handler = input_handler; // 指向右邊的input_handler
  3. 註冊:
    input_handler->h_list = &input_handle;
    inpu_dev->h_list = &input_handle;

evdev_connect
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); // 分配一個input_handle

// 設置
evdev->handle.dev = dev;  // 指向左邊的input_dev
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;  // 指向右邊的input_handler
evdev->handle.private = evdev;

// 註冊
error = input_register_handle(&evdev->handle);

怎麼讀按鍵?
app: read

.......
evdev_read
// 無數據而且是非阻塞方式打開,則馬上返回
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;

// 不然休眠
		retval = wait_event_interruptible(evdev->wait,
			client->head != client->tail || !evdev->exist);

誰來喚醒?
evdev_event
wake_up_interruptible(&evdev->wait);

evdev_event被誰調用?
猜:應該是硬件相關的代碼,input_dev那層調用的
在設備的中斷服務程序裏,肯定事件是什麼,而後調用相應的input_handler的event處理函數
gpio_keys_isr
// 上報事件
input_event(input, type, button->code, !!state);
input_sync(input);

input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
struct input_handle *handle;

list_for_each_entry(handle, &dev->h_list, d_node)
	if (handle->open)
		handle->handler->event(handle, type, code, value);

怎麼寫符合輸入子系統框架的驅動程序?

  1. 分配一個input_dev結構體
  2. 設置
  3. 註冊
  4. 硬件相關的代碼,好比在中斷服務程序裏上報事件

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)]; // 表示能產生哪些相對位移事件, x,y,滾輪
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能產生哪些絕對位移事件, x,y
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)];

測試:
1.
hexdump /dev/event1 (open(/dev/event1), read(), )
秒 微秒 類 code value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

  1. 若是沒有啓動QT:
    cat /dev/tty1
    按:s2,s3,s4
    就能夠獲得ls

或者:
exec 0</dev/tty1
而後能夠使用按鍵來輸入

  1. 若是已經啓動了QT: 能夠點開記事本 而後按:s2,s3,s4
相關文章
相關標籤/搜索