2020年9月6日 星期日

Linux Kernel(20.3)- Creating an input device driver


這個範例用最簡單的input device driver來解釋必要的部分,首先用input_allocate_device()取得"struct input_dev",接著填入必要欄位,如evbit,這個範例是只會產生EV_KEY event type,且key/event code只有KEY_UP(103)與KEY_DOWN(108),之後呼叫input_register_device(btn_dev)向系統註冊一個input device。
我用QEMU跑,沒有實際的硬體可以驅動該input device,所以我在sys底下創建一個sysfs_report_key讓input device送event。
#include <linux/module.h>
#include <linux/init.h>

#include <linux/input.h>
#include <linux/device.h>
#include <linux/sysfs.h>

static struct input_dev *btn_dev;

static ssize_t sysfs_report_key_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
{
  int key, value;
  if (sscanf(buf, "%d %d", &key, &value) != 2) {
    printk("invalid format:%s", buf);
    return n;
  }
  printk("key:%d, value:%d", key, value);
  input_report_key(btn_dev, key, value);
  input_sync(btn_dev);
  return n;
}

static DEVICE_ATTR_WO(sysfs_report_key);
static int __init button_init(void)
{
  int ret;

  btn_dev = input_allocate_device();
  if (btn_dev == NULL) {
    printk(KERN_ERR "Not enough memory\n");
    return -ENOMEM;
  }

  btn_dev->name = "brook-input-dev";
  btn_dev->evbit[0] = BIT(EV_KEY);
  set_bit(KEY_UP, btn_dev->keybit);
  set_bit(KEY_DOWN, btn_dev->keybit);

  ret = input_register_device(btn_dev);
  if (ret) {
    dev_err(&(btn_dev->dev), "Failed to register device\n");
    goto err_free_dev;
  }

  /* used for send event from user-space. please ignore it */
  ret = device_create_file(&(btn_dev->dev), &dev_attr_sysfs_report_key);
  if (ret) {
    dev_err(&(btn_dev->dev), "cannot create sysfs attribute\n");
    goto err_unreg_dev;
  }

  return 0;

err_unreg_dev:
  input_unregister_device(btn_dev);
err_free_dev:
  input_free_device(btn_dev);
  return ret;
}

static void __exit button_exit(void)
{
  input_unregister_device(btn_dev);
  input_free_device(btn_dev);
}

module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");


執行結果
/ # insmod inputdev.ko
[60145.219561] inputdev: loading out-of-tree module taints kernel.
[60145.277803] input: brook-input-dev as /devices/virtual/input/input3
/ # ./input_test /dev/input/event1 &

送出KEY_UP(103)後,input_test會收到event。
/ # echo '103 1' > /sys/devices/virtual/input/input3/sysfs_report_key
type:1, code:103, val:1
type:0, code:0, val:0

重複的送出KEY_UP(103),input_test不會收到event。
/ # echo '103 1' > /sys/devices/virtual/input/input3/sysfs_report_key
[60174.829756] key:103, value:1
/ # echo '103 0' > /sys/devices/virtual/input/input3/sysfs_report_key
[60182.965543] key:103, value:1
type:1, code:103, val:0
/ # type:0, code:0, val:0

Key value只有0/1。
/ # echo '103 2' > /sys/devices/virtual/input/input3/sysfs_report_key
[60189.286751] key:103, value:0
type:1, code:103, val:1
/ # type:0, code:0, val:0

其他的key/event code是不會被送出。
/ # echo '105 2' > /sys/devices/virtual/input/input3/sysfs_report_key
[60194.705307] key:103, value:2
/ # echo '108 2' > /sys/devices/virtual/input/input3/sysfs_report_key
[60201.887535] key:105, value:2
type:1, code:108, val:1
type:0, code:0, val:0


基本上,所有的input_report_xxx()/input_sync底層都是呼叫input_event,input_report_key的value只有0/1。
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
  input_event(dev, EV_KEY, code, !!value);
}

static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
  input_event(dev, EV_REL, code, value);
}

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
  input_event(dev, EV_ABS, code, value);
}

static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
  input_event(dev, EV_FF_STATUS, code, value);
}

static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
{
  input_event(dev, EV_SW, code, !!value);
}

static inline void input_sync(struct input_dev *dev)
{
  input_event(dev, EV_SYN, SYN_REPORT, 0);
}


input_event() 在送出key/event code之前,會先判斷送的event type與當初device設定的是否一致。
void input_event(struct input_dev *dev,
         unsigned int type, unsigned int code, int value)
{
  unsigned long flags;

  if (is_event_supported(type, dev->evbit, EV_MAX)) {
    spin_lock_irqsave(&dev->event_lock, flags);
    input_handle_event(dev, type, code, value);
    spin_unlock_irqrestore(&dev->event_lock, flags);
  }
}

重複的KEY value是不會被設成INPUT_PASS_TO_HANDLERS,也就是INPUT_IGNORE_EVENT。
static void input_handle_event(struct input_dev *dev,
                   unsigned int type, unsigned int code, int value)
{
  int disposition = input_get_disposition(dev, type, code, &value);

  ...
}

static int input_get_disposition(struct input_dev *dev,
              unsigned int type, unsigned int code, int *pval)
{
  int disposition = INPUT_IGNORE_EVENT;
  int value = *pval;

  switch (type) {
  ...
  case EV_KEY:
    if (is_event_supported(code, dev->keybit, KEY_MAX)) {
      /* auto-repeat bypasses state updates */
      if (value == 2) {
        disposition = INPUT_PASS_TO_HANDLERS;
        break;
      }

      if (!!test_bit(code, dev->key) != !!value) {
        __change_bit(code, dev->key);
        disposition = INPUT_PASS_TO_HANDLERS;
      }

    }
    break;
  ...
  }
  
  *pval = value;
  return disposition;
}


    參考資料:
  • Documentation/input/input-programming.rst



沒有留言:

張貼留言

熱門文章