接前一篇文章《Linux内核中ideapad-laptop.c文件全解析1》,地址为:
Linux内核中ideapad-laptop.c文件全解析1_蓝天居士的博客-CSDN博客
上一回讲到了ideapad_acpi_driver。本文对于其成员进行详细解析。再列一下其源码:
- static const struct acpi_device_id ideapad_device_ids[] = {
- {"VPC2004", 0},
- {"", 0},
- };
- MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
-
- static struct platform_driver ideapad_acpi_driver = {
- .probe = ideapad_acpi_add,
- .remove = ideapad_acpi_remove,
- .driver = {
- .name = "ideapad_acpi",
- .pm = &ideapad_pm,
- .acpi_match_table = ACPI_PTR(ideapad_device_ids),
- },
- };
-
- module_platform_driver(ideapad_acpi_driver);
ideapad_device_ids数组也可以说是表的定义和初始化就在上边,它是用来匹配平台驱动和平台设备的。
probe探测函数对应的ideapad_acpi_add函数在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,源码如下:
- static int ideapad_acpi_add(struct platform_device *pdev)
- {
- struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
- struct ideapad_private *priv;
- acpi_status status;
- unsigned long cfg;
- int err, i;
-
- if (!adev || eval_int(adev->handle, "_CFG", &cfg))
- return -ENODEV;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- dev_set_drvdata(&pdev->dev, priv);
-
- priv->cfg = cfg;
- priv->adev = adev;
- priv->platform_device = pdev;
-
- ideapad_check_features(priv);
-
- err = ideapad_sysfs_init(priv);
- if (err)
- return err;
-
- ideapad_debugfs_init(priv);
-
- err = ideapad_input_init(priv);
- if (err)
- goto input_failed;
-
- err = ideapad_kbd_bl_init(priv);
- if (err) {
- if (err != -ENODEV)
- dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err);
- else
- dev_info(&pdev->dev, "Keyboard backlight control not available\n");
- }
-
- /*
- * On some models without a hw-switch (the yoga 2 13 at least)
- * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
- */
- if (!priv->features.hw_rfkill_switch)
- write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
-
- /* The same for Touchpad */
- if (!priv->features.touchpad_ctrl_via_ec)
- write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
-
- for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
- if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
- ideapad_register_rfkill(priv, i);
-
- ideapad_sync_rfk_state(priv);
- ideapad_sync_touchpad_state(priv);
-
- err = ideapad_dytc_profile_init(priv);
- if (err) {
- if (err != -ENODEV)
- dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err);
- else
- dev_info(&pdev->dev, "DYTC interface is not available\n");
- }
-
- if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
- err = ideapad_backlight_init(priv);
- if (err && err != -ENODEV)
- goto backlight_failed;
- }
-
- status = acpi_install_notify_handler(adev->handle,
- ACPI_DEVICE_NOTIFY,
- ideapad_acpi_notify, priv);
- if (ACPI_FAILURE(status)) {
- err = -EIO;
- goto notification_failed;
- }
-
- #if IS_ENABLED(CONFIG_ACPI_WMI)
- for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
- status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
- ideapad_wmi_notify, priv);
- if (ACPI_SUCCESS(status)) {
- priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
- break;
- }
- }
-
- if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
- err = -EIO;
- goto notification_failed_wmi;
- }
- #endif
-
- return 0;
-
- #if IS_ENABLED(CONFIG_ACPI_WMI)
- notification_failed_wmi:
- acpi_remove_notify_handler(priv->adev->handle,
- ACPI_DEVICE_NOTIFY,
- ideapad_acpi_notify);
- #endif
-
- notification_failed:
- ideapad_backlight_exit(priv);
-
- backlight_failed:
- ideapad_dytc_profile_exit(priv);
-
- for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
- ideapad_unregister_rfkill(priv, i);
-
- ideapad_kbd_bl_exit(priv);
- ideapad_input_exit(priv);
-
- input_failed:
- ideapad_debugfs_exit(priv);
- ideapad_sysfs_exit(priv);
-
- return err;
- }
remove移除函数对应的ideapad_acpi_remove函数也在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,源码如下:
- static int ideapad_acpi_remove(struct platform_device *pdev)
- {
- struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
- int i;
-
- #if IS_ENABLED(CONFIG_ACPI_WMI)
- if (priv->fnesc_guid)
- wmi_remove_notify_handler(priv->fnesc_guid);
- #endif
-
- acpi_remove_notify_handler(priv->adev->handle,
- ACPI_DEVICE_NOTIFY,
- ideapad_acpi_notify);
-
- ideapad_backlight_exit(priv);
- ideapad_dytc_profile_exit(priv);
-
- for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
- ideapad_unregister_rfkill(priv, i);
-
- ideapad_kbd_bl_exit(priv);
- ideapad_input_exit(priv);
- ideapad_debugfs_exit(priv);
- ideapad_sysfs_exit(priv);
-
- return 0;
- }
实际上通过ideapad_acpi_remove函数更容易看出ideapad_acpi_add函数完成的工作,包括了:
欲知各个函数的具体实现细节,且听下回分解。