• Linux内核中ideapad-laptop.c文件全解析6


    接前一篇文章《Linux内核中ideapad-laptop.c文件全解析5》,地址为:

    Linux内核中ideapad-laptop.c文件全解析5_蓝天居士的博客-CSDN博客

    上一篇详细分析了ideapad_debugfs_init,本篇详细分析ideapad_input_init。

    • ideapad_input_init

    ideapad_input_init在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,代码如下:

    1. static int ideapad_input_init(struct ideapad_private *priv)
    2. {
    3. struct input_dev *inputdev;
    4. int err;
    5. inputdev = input_allocate_device();
    6. if (!inputdev)
    7. return -ENOMEM;
    8. inputdev->name = "Ideapad extra buttons";
    9. inputdev->phys = "ideapad/input0";
    10. inputdev->id.bustype = BUS_HOST;
    11. inputdev->dev.parent = &priv->platform_device->dev;
    12. err = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
    13. if (err) {
    14. dev_err(&priv->platform_device->dev,
    15. "Could not set up input device keymap: %d\n", err);
    16. goto err_free_dev;
    17. }
    18. err = input_register_device(inputdev);
    19. if (err) {
    20. dev_err(&priv->platform_device->dev,
    21. "Could not register input device: %d\n", err);
    22. goto err_free_dev;
    23. }
    24. priv->inputdev = inputdev;
    25. return 0;
    26. err_free_dev:
    27. input_free_device(inputdev);
    28. return err;
    29. }
    30. static void ideapad_input_exit(struct ideapad_private *priv)
    31. {
    32. input_unregister_device(priv->inputdev);
    33. priv->inputdev = NULL;
    34. }

    input_allocate_device函数在drivers/input/input.c中,代码如下:

    1. /**
    2. * input_allocate_device - allocate memory for new input device
    3. *
    4. * Returns prepared struct input_dev or %NULL.
    5. *
    6. * NOTE: Use input_free_device() to free devices that have not been
    7. * registered; input_unregister_device() should be used for already
    8. * registered devices.
    9. */
    10. struct input_dev *input_allocate_device(void)
    11. {
    12. static atomic_t input_no = ATOMIC_INIT(-1);
    13. struct input_dev *dev;
    14. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    15. if (dev) {
    16. dev->dev.type = &input_dev_type;
    17. dev->dev.class = &input_class;
    18. device_initialize(&dev->dev);
    19. mutex_init(&dev->mutex);
    20. spin_lock_init(&dev->event_lock);
    21. timer_setup(&dev->timer, NULL, 0);
    22. INIT_LIST_HEAD(&dev->h_list);
    23. INIT_LIST_HEAD(&dev->node);
    24. dev_set_name(&dev->dev, "input%lu",
    25. (unsigned long)atomic_inc_return(&input_no));
    26. __module_get(THIS_MODULE);
    27. }
    28. return dev;
    29. }
    30. EXPORT_SYMBOL(input_allocate_device);

    由input_allocate_device函数,就进入了Linux输入子系统(Linux Input Subsystem)。

    以下内容引自input 子系统架构总结_lbmygf的博客-CSDN博客

    #############################################################################

    Linux 的输入子系统不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。

    输入子系统又叫input子系统。其构建非常灵活,只需要调用一些简单的函数,就可以将一个输入设备的功能呈现给应用程序。

    #############################################################################
    input_allocate_device函数位于核心层,其作用是动态分配一个input_dev结构体实例并初始化。该结构体是一个输入设备结构体,包含了输入设备的一些相关信息,如:设备支持的按键码、设备的名称、设备支持的事件等。函数返回一个指向函数中动态分配的input_dev结构实例的指针。

    sparse_keymap_setup函数在drivers/input/sparse-keymap.c中,代码如下:

    1. /**
    2. * sparse_keymap_setup - set up sparse keymap for an input device
    3. * @dev: Input device
    4. * @keymap: Keymap in form of array of &key_entry structures ending
    5. * with %KE_END type entry
    6. * @setup: Function that can be used to adjust keymap entries
    7. * depending on device's needs, may be %NULL
    8. *
    9. * The function calculates size and allocates copy of the original
    10. * keymap after which sets up input device event bits appropriately.
    11. * The allocated copy of the keymap is automatically freed when it
    12. * is no longer needed.
    13. */
    14. int sparse_keymap_setup(struct input_dev *dev,
    15. const struct key_entry *keymap,
    16. int (*setup)(struct input_dev *, struct key_entry *))
    17. {
    18. size_t map_size = 1; /* to account for the last KE_END entry */
    19. const struct key_entry *e;
    20. struct key_entry *map, *entry;
    21. int i;
    22. int error;
    23. for (e = keymap; e->type != KE_END; e++)
    24. map_size++;
    25. map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
    26. GFP_KERNEL);
    27. if (!map)
    28. return -ENOMEM;
    29. for (i = 0; i < map_size; i++) {
    30. entry = &map[i];
    31. if (setup) {
    32. error = setup(dev, entry);
    33. if (error)
    34. return error;
    35. }
    36. switch (entry->type) {
    37. case KE_KEY:
    38. __set_bit(EV_KEY, dev->evbit);
    39. __set_bit(entry->keycode, dev->keybit);
    40. break;
    41. case KE_SW:
    42. case KE_VSW:
    43. __set_bit(EV_SW, dev->evbit);
    44. __set_bit(entry->sw.code, dev->swbit);
    45. break;
    46. }
    47. }
    48. if (test_bit(EV_KEY, dev->evbit)) {
    49. __set_bit(KEY_UNKNOWN, dev->keybit);
    50. __set_bit(EV_MSC, dev->evbit);
    51. __set_bit(MSC_SCAN, dev->mscbit);
    52. }
    53. dev->keycode = map;
    54. dev->keycodemax = map_size;
    55. dev->getkeycode = sparse_keymap_getkeycode;
    56. dev->setkeycode = sparse_keymap_setkeycode;
    57. return 0;
    58. }
    59. EXPORT_SYMBOL(sparse_keymap_setup);

    如函数说明,sparse_keymap_setup函数建立了输入设备的稀疏键映射。

    ideapad_input_init函数中调用sparse_keymap_setup时,第2个参数const struct key_entry *keymap传入的实参是ideapad_keymap。ideapad_keymap数组在同文件(drivers/platform/x86/ideapad-laptop.c)中初始化,如下代码:

    1. static const struct key_entry ideapad_keymap[] = {
    2. { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
    3. { KE_KEY, 7, { KEY_CAMERA } },
    4. { KE_KEY, 8, { KEY_MICMUTE } },
    5. { KE_KEY, 11, { KEY_F16 } },
    6. { KE_KEY, 13, { KEY_WLAN } },
    7. { KE_KEY, 16, { KEY_PROG1 } },
    8. { KE_KEY, 17, { KEY_PROG2 } },
    9. { KE_KEY, 64, { KEY_PROG3 } },
    10. { KE_KEY, 65, { KEY_PROG4 } },
    11. { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
    12. { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
    13. { KE_KEY, 128, { KEY_ESC } },
    14. { KE_END },
    15. };

    input_register_device函数是input设备注册的接口,在drivers/input/input.c中,代码如下:

    1. /**
    2. * input_register_device - register device with input core
    3. * @dev: device to be registered
    4. *
    5. * This function registers device with input core. The device must be
    6. * allocated with input_allocate_device() and all it's capabilities
    7. * set up before registering.
    8. * If function fails the device must be freed with input_free_device().
    9. * Once device has been successfully registered it can be unregistered
    10. * with input_unregister_device(); input_free_device() should not be
    11. * called in this case.
    12. *
    13. * Note that this function is also used to register managed input devices
    14. * (ones allocated with devm_input_allocate_device()). Such managed input
    15. * devices need not be explicitly unregistered or freed, their tear down
    16. * is controlled by the devres infrastructure. It is also worth noting
    17. * that tear down of managed input devices is internally a 2-step process:
    18. * registered managed input device is first unregistered, but stays in
    19. * memory and can still handle input_event() calls (although events will
    20. * not be delivered anywhere). The freeing of managed input device will
    21. * happen later, when devres stack is unwound to the point where device
    22. * allocation was made.
    23. */
    24. int input_register_device(struct input_dev *dev)
    25. {
    26. struct input_devres *devres = NULL;
    27. struct input_handler *handler;
    28. unsigned int packet_size;
    29. const char *path;
    30. int error;
    31. if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
    32. dev_err(&dev->dev,
    33. "Absolute device without dev->absinfo, refusing to register\n");
    34. return -EINVAL;
    35. }
    36. if (dev->devres_managed) {
    37. devres = devres_alloc(devm_input_device_unregister,
    38. sizeof(*devres), GFP_KERNEL);
    39. if (!devres)
    40. return -ENOMEM;
    41. devres->input = dev;
    42. }
    43. /* Every input device generates EV_SYN/SYN_REPORT events. */
    44. __set_bit(EV_SYN, dev->evbit);
    45. /* KEY_RESERVED is not supposed to be transmitted to userspace. */
    46. __clear_bit(KEY_RESERVED, dev->keybit);
    47. /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
    48. input_cleanse_bitmasks(dev);
    49. packet_size = input_estimate_events_per_packet(dev);
    50. if (dev->hint_events_per_packet < packet_size)
    51. dev->hint_events_per_packet = packet_size;
    52. dev->max_vals = dev->hint_events_per_packet + 2;
    53. dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
    54. if (!dev->vals) {
    55. error = -ENOMEM;
    56. goto err_devres_free;
    57. }
    58. /*
    59. * If delay and period are pre-set by the driver, then autorepeating
    60. * is handled by the driver itself and we don't do it in input.c.
    61. */
    62. if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
    63. input_enable_softrepeat(dev, 250, 33);
    64. if (!dev->getkeycode)
    65. dev->getkeycode = input_default_getkeycode;
    66. if (!dev->setkeycode)
    67. dev->setkeycode = input_default_setkeycode;
    68. if (dev->poller)
    69. input_dev_poller_finalize(dev->poller);
    70. error = device_add(&dev->dev);
    71. if (error)
    72. goto err_free_vals;
    73. path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    74. pr_info("%s as %s\n",
    75. dev->name ? dev->name : "Unspecified device",
    76. path ? path : "N/A");
    77. kfree(path);
    78. error = mutex_lock_interruptible(&input_mutex);
    79. if (error)
    80. goto err_device_del;
    81. list_add_tail(&dev->node, &input_dev_list);
    82. list_for_each_entry(handler, &input_handler_list, node)
    83. input_attach_handler(dev, handler);
    84. input_wakeup_procfs_readers();
    85. mutex_unlock(&input_mutex);
    86. if (dev->devres_managed) {
    87. dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
    88. __func__, dev_name(&dev->dev));
    89. devres_add(dev->dev.parent, devres);
    90. }
    91. return 0;
    92. err_device_del:
    93. device_del(&dev->dev);
    94. err_free_vals:
    95. kfree(dev->vals);
    96. dev->vals = NULL;
    97. err_devres_free:
    98. devres_free(devres);
    99. return error;
    100. }
    101. EXPORT_SYMBOL(input_register_device);

    输入子系统部分的代码要完全分析清楚,需要一个系列才可以。由于这并不是我们的重点,所以只是点到为止,把涉及到的接口及代码列在这里,并不深入展开了。

    至此,ideapad_input_init函数也就算是分析完了。

  • 相关阅读:
    闭包、回调函数
    mysql修改字段的更新时间
    mysql死锁介绍以及解决
    Django框架简介
    一种高选择性和灵敏的荧光生物标记物,可用于标记碱性磷酸酶 (ALP),5-FAM-Alkyne,510758-19-7,荧光生物标记物
    NoSQL常用数据结构 LSM Tree 简介
    基于TCAD与紧凑模型结合方法探究陷阱对AlGaN/GaN HEMTs功率附加效率及线性度的影响
    SDK接口是什么?
    代码随想录第44天 | ● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和 动态规划
    (建议收藏)TCP协议灵魂之问,巩固你的网路底层基础
  • 原文地址:https://blog.csdn.net/phmatthaus/article/details/128102767