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


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

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

    上一回讲到了ideapad_acpi_driver。本文对于其成员进行详细解析。再列一下其源码:

    1. static const struct acpi_device_id ideapad_device_ids[] = {
    2. {"VPC2004", 0},
    3. {"", 0},
    4. };
    5. MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
    6. static struct platform_driver ideapad_acpi_driver = {
    7. .probe = ideapad_acpi_add,
    8. .remove = ideapad_acpi_remove,
    9. .driver = {
    10. .name = "ideapad_acpi",
    11. .pm = &ideapad_pm,
    12. .acpi_match_table = ACPI_PTR(ideapad_device_ids),
    13. },
    14. };
    15. module_platform_driver(ideapad_acpi_driver);

    ideapad_device_ids数组也可以说是表的定义和初始化就在上边,它是用来匹配平台驱动和平台设备的。

    probe探测函数对应的ideapad_acpi_add函数在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,源码如下:

    1. static int ideapad_acpi_add(struct platform_device *pdev)
    2. {
    3. struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
    4. struct ideapad_private *priv;
    5. acpi_status status;
    6. unsigned long cfg;
    7. int err, i;
    8. if (!adev || eval_int(adev->handle, "_CFG", &cfg))
    9. return -ENODEV;
    10. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    11. if (!priv)
    12. return -ENOMEM;
    13. dev_set_drvdata(&pdev->dev, priv);
    14. priv->cfg = cfg;
    15. priv->adev = adev;
    16. priv->platform_device = pdev;
    17. ideapad_check_features(priv);
    18. err = ideapad_sysfs_init(priv);
    19. if (err)
    20. return err;
    21. ideapad_debugfs_init(priv);
    22. err = ideapad_input_init(priv);
    23. if (err)
    24. goto input_failed;
    25. err = ideapad_kbd_bl_init(priv);
    26. if (err) {
    27. if (err != -ENODEV)
    28. dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err);
    29. else
    30. dev_info(&pdev->dev, "Keyboard backlight control not available\n");
    31. }
    32. /*
    33. * On some models without a hw-switch (the yoga 2 13 at least)
    34. * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
    35. */
    36. if (!priv->features.hw_rfkill_switch)
    37. write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
    38. /* The same for Touchpad */
    39. if (!priv->features.touchpad_ctrl_via_ec)
    40. write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
    41. for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
    42. if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
    43. ideapad_register_rfkill(priv, i);
    44. ideapad_sync_rfk_state(priv);
    45. ideapad_sync_touchpad_state(priv);
    46. err = ideapad_dytc_profile_init(priv);
    47. if (err) {
    48. if (err != -ENODEV)
    49. dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err);
    50. else
    51. dev_info(&pdev->dev, "DYTC interface is not available\n");
    52. }
    53. if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
    54. err = ideapad_backlight_init(priv);
    55. if (err && err != -ENODEV)
    56. goto backlight_failed;
    57. }
    58. status = acpi_install_notify_handler(adev->handle,
    59. ACPI_DEVICE_NOTIFY,
    60. ideapad_acpi_notify, priv);
    61. if (ACPI_FAILURE(status)) {
    62. err = -EIO;
    63. goto notification_failed;
    64. }
    65. #if IS_ENABLED(CONFIG_ACPI_WMI)
    66. for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
    67. status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
    68. ideapad_wmi_notify, priv);
    69. if (ACPI_SUCCESS(status)) {
    70. priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
    71. break;
    72. }
    73. }
    74. if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
    75. err = -EIO;
    76. goto notification_failed_wmi;
    77. }
    78. #endif
    79. return 0;
    80. #if IS_ENABLED(CONFIG_ACPI_WMI)
    81. notification_failed_wmi:
    82. acpi_remove_notify_handler(priv->adev->handle,
    83. ACPI_DEVICE_NOTIFY,
    84. ideapad_acpi_notify);
    85. #endif
    86. notification_failed:
    87. ideapad_backlight_exit(priv);
    88. backlight_failed:
    89. ideapad_dytc_profile_exit(priv);
    90. for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
    91. ideapad_unregister_rfkill(priv, i);
    92. ideapad_kbd_bl_exit(priv);
    93. ideapad_input_exit(priv);
    94. input_failed:
    95. ideapad_debugfs_exit(priv);
    96. ideapad_sysfs_exit(priv);
    97. return err;
    98. }

    remove移除函数对应的ideapad_acpi_remove函数也在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,源码如下:

    1. static int ideapad_acpi_remove(struct platform_device *pdev)
    2. {
    3. struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
    4. int i;
    5. #if IS_ENABLED(CONFIG_ACPI_WMI)
    6. if (priv->fnesc_guid)
    7. wmi_remove_notify_handler(priv->fnesc_guid);
    8. #endif
    9. acpi_remove_notify_handler(priv->adev->handle,
    10. ACPI_DEVICE_NOTIFY,
    11. ideapad_acpi_notify);
    12. ideapad_backlight_exit(priv);
    13. ideapad_dytc_profile_exit(priv);
    14. for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
    15. ideapad_unregister_rfkill(priv, i);
    16. ideapad_kbd_bl_exit(priv);
    17. ideapad_input_exit(priv);
    18. ideapad_debugfs_exit(priv);
    19. ideapad_sysfs_exit(priv);
    20. return 0;
    21. }

    实际上通过ideapad_acpi_remove函数更容易看出ideapad_acpi_add函数完成的工作,包括了:

    • sysfs初始化:ideapad_sysfs_init
    • debugfs初始化:ideapad_debugfs_init
    • 输入初始化:idea_input_init_init
    • 键盘(按键)背光初始化:ideapad_kbd_bl_init
    • 配置初始化:idea_dytc_profile_init
    • 背光初始化:ideapad_backlight_init
    • acpi通知处理:acpi_install_notify_handler
    • wmi通知处理:wmi_install_notify_handler
    • ……

    欲知各个函数的具体实现细节,且听下回分解。

  • 相关阅读:
    认知世界和提示自己不可或缺的50本书
    SpringBoot 发送邮件
    为什么UI自动化难做?—— 关于Selenium UI自动化的思考
    数据服务器之raid1使用
    算法导论实战(六)(算法导论习题三十四、三十五章)
    1359:围成面积
    (附源码)ssm驾校考试车预约管理系统 毕业设计 271506
    思维模型 飞轮效应
    大模型自动优化 Prompt 的可行性分析
    【外卖项目实战开发四】
  • 原文地址:https://blog.csdn.net/phmatthaus/article/details/128075030