Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  button.c - ACPI Button Driver
0004  *
0005  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
0006  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
0007  */
0008 
0009 #define pr_fmt(fmt) "ACPI: button: " fmt
0010 
0011 #include <linux/compiler.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/types.h>
0016 #include <linux/proc_fs.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/input.h>
0019 #include <linux/slab.h>
0020 #include <linux/acpi.h>
0021 #include <linux/dmi.h>
0022 #include <acpi/button.h>
0023 
0024 #define ACPI_BUTTON_CLASS       "button"
0025 #define ACPI_BUTTON_FILE_STATE      "state"
0026 #define ACPI_BUTTON_TYPE_UNKNOWN    0x00
0027 #define ACPI_BUTTON_NOTIFY_STATUS   0x80
0028 
0029 #define ACPI_BUTTON_SUBCLASS_POWER  "power"
0030 #define ACPI_BUTTON_DEVICE_NAME_POWER   "Power Button"
0031 #define ACPI_BUTTON_TYPE_POWER      0x01
0032 
0033 #define ACPI_BUTTON_SUBCLASS_SLEEP  "sleep"
0034 #define ACPI_BUTTON_DEVICE_NAME_SLEEP   "Sleep Button"
0035 #define ACPI_BUTTON_TYPE_SLEEP      0x03
0036 
0037 #define ACPI_BUTTON_SUBCLASS_LID    "lid"
0038 #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
0039 #define ACPI_BUTTON_TYPE_LID        0x05
0040 
0041 enum {
0042     ACPI_BUTTON_LID_INIT_IGNORE,
0043     ACPI_BUTTON_LID_INIT_OPEN,
0044     ACPI_BUTTON_LID_INIT_METHOD,
0045     ACPI_BUTTON_LID_INIT_DISABLED,
0046 };
0047 
0048 static const char * const lid_init_state_str[] = {
0049     [ACPI_BUTTON_LID_INIT_IGNORE]       = "ignore",
0050     [ACPI_BUTTON_LID_INIT_OPEN]     = "open",
0051     [ACPI_BUTTON_LID_INIT_METHOD]       = "method",
0052     [ACPI_BUTTON_LID_INIT_DISABLED]     = "disabled",
0053 };
0054 
0055 MODULE_AUTHOR("Paul Diefenbaugh");
0056 MODULE_DESCRIPTION("ACPI Button Driver");
0057 MODULE_LICENSE("GPL");
0058 
0059 static const struct acpi_device_id button_device_ids[] = {
0060     {ACPI_BUTTON_HID_LID,    0},
0061     {ACPI_BUTTON_HID_SLEEP,  0},
0062     {ACPI_BUTTON_HID_SLEEPF, 0},
0063     {ACPI_BUTTON_HID_POWER,  0},
0064     {ACPI_BUTTON_HID_POWERF, 0},
0065     {"", 0},
0066 };
0067 MODULE_DEVICE_TABLE(acpi, button_device_ids);
0068 
0069 /* Please keep this list sorted alphabetically by vendor and model */
0070 static const struct dmi_system_id dmi_lid_quirks[] = {
0071     {
0072         /* GP-electronic T701, _LID method points to a floating GPIO */
0073         .matches = {
0074             DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
0075             DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
0076             DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
0077         },
0078         .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
0079     },
0080     {
0081         /*
0082          * Lenovo Yoga 9 14ITL5, initial notification of the LID device
0083          * never happens.
0084          */
0085         .matches = {
0086             DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0087             DMI_MATCH(DMI_PRODUCT_NAME, "82BG"),
0088         },
0089         .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
0090     },
0091     {
0092         /*
0093          * Medion Akoya E2215T, notification of the LID device only
0094          * happens on close, not on open and _LID always returns closed.
0095          */
0096         .matches = {
0097             DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
0098             DMI_MATCH(DMI_PRODUCT_NAME, "E2215T"),
0099         },
0100         .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
0101     },
0102     {
0103         /*
0104          * Medion Akoya E2228T, notification of the LID device only
0105          * happens on close, not on open and _LID always returns closed.
0106          */
0107         .matches = {
0108             DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
0109             DMI_MATCH(DMI_PRODUCT_NAME, "E2228T"),
0110         },
0111         .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
0112     },
0113     {
0114         /*
0115          * Razer Blade Stealth 13 late 2019, notification of the LID device
0116          * only happens on close, not on open and _LID always returns closed.
0117          */
0118         .matches = {
0119             DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
0120             DMI_MATCH(DMI_PRODUCT_NAME, "Razer Blade Stealth 13 Late 2019"),
0121         },
0122         .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
0123     },
0124     {}
0125 };
0126 
0127 static int acpi_button_add(struct acpi_device *device);
0128 static int acpi_button_remove(struct acpi_device *device);
0129 static void acpi_button_notify(struct acpi_device *device, u32 event);
0130 
0131 #ifdef CONFIG_PM_SLEEP
0132 static int acpi_button_suspend(struct device *dev);
0133 static int acpi_button_resume(struct device *dev);
0134 #else
0135 #define acpi_button_suspend NULL
0136 #define acpi_button_resume NULL
0137 #endif
0138 static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume);
0139 
0140 static struct acpi_driver acpi_button_driver = {
0141     .name = "button",
0142     .class = ACPI_BUTTON_CLASS,
0143     .ids = button_device_ids,
0144     .ops = {
0145         .add = acpi_button_add,
0146         .remove = acpi_button_remove,
0147         .notify = acpi_button_notify,
0148     },
0149     .drv.pm = &acpi_button_pm,
0150 };
0151 
0152 struct acpi_button {
0153     unsigned int type;
0154     struct input_dev *input;
0155     char phys[32];          /* for input device */
0156     unsigned long pushed;
0157     int last_state;
0158     ktime_t last_time;
0159     bool suspended;
0160     bool lid_state_initialized;
0161 };
0162 
0163 static struct acpi_device *lid_device;
0164 static long lid_init_state = -1;
0165 
0166 static unsigned long lid_report_interval __read_mostly = 500;
0167 module_param(lid_report_interval, ulong, 0644);
0168 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
0169 
0170 /* FS Interface (/proc) */
0171 static struct proc_dir_entry *acpi_button_dir;
0172 static struct proc_dir_entry *acpi_lid_dir;
0173 
0174 static int acpi_lid_evaluate_state(struct acpi_device *device)
0175 {
0176     unsigned long long lid_state;
0177     acpi_status status;
0178 
0179     status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state);
0180     if (ACPI_FAILURE(status))
0181         return -ENODEV;
0182 
0183     return lid_state ? 1 : 0;
0184 }
0185 
0186 static int acpi_lid_notify_state(struct acpi_device *device, int state)
0187 {
0188     struct acpi_button *button = acpi_driver_data(device);
0189     ktime_t next_report;
0190     bool do_update;
0191 
0192     /*
0193      * In lid_init_state=ignore mode, if user opens/closes lid
0194      * frequently with "open" missing, and "last_time" is also updated
0195      * frequently, "close" cannot be delivered to the userspace.
0196      * So "last_time" is only updated after a timeout or an actual
0197      * switch.
0198      */
0199     if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE ||
0200         button->last_state != !!state)
0201         do_update = true;
0202     else
0203         do_update = false;
0204 
0205     next_report = ktime_add(button->last_time,
0206                 ms_to_ktime(lid_report_interval));
0207     if (button->last_state == !!state &&
0208         ktime_after(ktime_get(), next_report)) {
0209         /* Complain the buggy firmware */
0210         pr_warn_once("The lid device is not compliant to SW_LID.\n");
0211 
0212         /*
0213          * Send the unreliable complement switch event:
0214          *
0215          * On most platforms, the lid device is reliable. However
0216          * there are exceptions:
0217          * 1. Platforms returning initial lid state as "close" by
0218          *    default after booting/resuming:
0219          *     https://bugzilla.kernel.org/show_bug.cgi?id=89211
0220          *     https://bugzilla.kernel.org/show_bug.cgi?id=106151
0221          * 2. Platforms never reporting "open" events:
0222          *     https://bugzilla.kernel.org/show_bug.cgi?id=106941
0223          * On these buggy platforms, the usage model of the ACPI
0224          * lid device actually is:
0225          * 1. The initial returning value of _LID may not be
0226          *    reliable.
0227          * 2. The open event may not be reliable.
0228          * 3. The close event is reliable.
0229          *
0230          * But SW_LID is typed as input switch event, the input
0231          * layer checks if the event is redundant. Hence if the
0232          * state is not switched, the userspace cannot see this
0233          * platform triggered reliable event. By inserting a
0234          * complement switch event, it then is guaranteed that the
0235          * platform triggered reliable one can always be seen by
0236          * the userspace.
0237          */
0238         if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE) {
0239             do_update = true;
0240             /*
0241              * Do generate complement switch event for "close"
0242              * as "close" is reliable and wrong "open" won't
0243              * trigger unexpected behaviors.
0244              * Do not generate complement switch event for
0245              * "open" as "open" is not reliable and wrong
0246              * "close" will trigger unexpected behaviors.
0247              */
0248             if (!state) {
0249                 input_report_switch(button->input,
0250                             SW_LID, state);
0251                 input_sync(button->input);
0252             }
0253         }
0254     }
0255     /* Send the platform triggered reliable event */
0256     if (do_update) {
0257         acpi_handle_debug(device->handle, "ACPI LID %s\n",
0258                   state ? "open" : "closed");
0259         input_report_switch(button->input, SW_LID, !state);
0260         input_sync(button->input);
0261         button->last_state = !!state;
0262         button->last_time = ktime_get();
0263     }
0264 
0265     return 0;
0266 }
0267 
0268 static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq,
0269                              void *offset)
0270 {
0271     struct acpi_device *device = seq->private;
0272     int state;
0273 
0274     state = acpi_lid_evaluate_state(device);
0275     seq_printf(seq, "state:      %s\n",
0276            state < 0 ? "unsupported" : (state ? "open" : "closed"));
0277     return 0;
0278 }
0279 
0280 static int acpi_button_add_fs(struct acpi_device *device)
0281 {
0282     struct acpi_button *button = acpi_driver_data(device);
0283     struct proc_dir_entry *entry = NULL;
0284     int ret = 0;
0285 
0286     /* procfs I/F for ACPI lid device only */
0287     if (button->type != ACPI_BUTTON_TYPE_LID)
0288         return 0;
0289 
0290     if (acpi_button_dir || acpi_lid_dir) {
0291         pr_info("More than one Lid device found!\n");
0292         return -EEXIST;
0293     }
0294 
0295     /* create /proc/acpi/button */
0296     acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
0297     if (!acpi_button_dir)
0298         return -ENODEV;
0299 
0300     /* create /proc/acpi/button/lid */
0301     acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
0302     if (!acpi_lid_dir) {
0303         ret = -ENODEV;
0304         goto remove_button_dir;
0305     }
0306 
0307     /* create /proc/acpi/button/lid/LID/ */
0308     acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir);
0309     if (!acpi_device_dir(device)) {
0310         ret = -ENODEV;
0311         goto remove_lid_dir;
0312     }
0313 
0314     /* create /proc/acpi/button/lid/LID/state */
0315     entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO,
0316             acpi_device_dir(device), acpi_button_state_seq_show,
0317             device);
0318     if (!entry) {
0319         ret = -ENODEV;
0320         goto remove_dev_dir;
0321     }
0322 
0323 done:
0324     return ret;
0325 
0326 remove_dev_dir:
0327     remove_proc_entry(acpi_device_bid(device),
0328               acpi_lid_dir);
0329     acpi_device_dir(device) = NULL;
0330 remove_lid_dir:
0331     remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
0332     acpi_lid_dir = NULL;
0333 remove_button_dir:
0334     remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
0335     acpi_button_dir = NULL;
0336     goto done;
0337 }
0338 
0339 static int acpi_button_remove_fs(struct acpi_device *device)
0340 {
0341     struct acpi_button *button = acpi_driver_data(device);
0342 
0343     if (button->type != ACPI_BUTTON_TYPE_LID)
0344         return 0;
0345 
0346     remove_proc_entry(ACPI_BUTTON_FILE_STATE,
0347               acpi_device_dir(device));
0348     remove_proc_entry(acpi_device_bid(device),
0349               acpi_lid_dir);
0350     acpi_device_dir(device) = NULL;
0351     remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
0352     acpi_lid_dir = NULL;
0353     remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
0354     acpi_button_dir = NULL;
0355 
0356     return 0;
0357 }
0358 
0359 /* Driver Interface */
0360 int acpi_lid_open(void)
0361 {
0362     if (!lid_device)
0363         return -ENODEV;
0364 
0365     return acpi_lid_evaluate_state(lid_device);
0366 }
0367 EXPORT_SYMBOL(acpi_lid_open);
0368 
0369 static int acpi_lid_update_state(struct acpi_device *device,
0370                  bool signal_wakeup)
0371 {
0372     int state;
0373 
0374     state = acpi_lid_evaluate_state(device);
0375     if (state < 0)
0376         return state;
0377 
0378     if (state && signal_wakeup)
0379         acpi_pm_wakeup_event(&device->dev);
0380 
0381     return acpi_lid_notify_state(device, state);
0382 }
0383 
0384 static void acpi_lid_initialize_state(struct acpi_device *device)
0385 {
0386     struct acpi_button *button = acpi_driver_data(device);
0387 
0388     switch (lid_init_state) {
0389     case ACPI_BUTTON_LID_INIT_OPEN:
0390         (void)acpi_lid_notify_state(device, 1);
0391         break;
0392     case ACPI_BUTTON_LID_INIT_METHOD:
0393         (void)acpi_lid_update_state(device, false);
0394         break;
0395     case ACPI_BUTTON_LID_INIT_IGNORE:
0396     default:
0397         break;
0398     }
0399 
0400     button->lid_state_initialized = true;
0401 }
0402 
0403 static void acpi_button_notify(struct acpi_device *device, u32 event)
0404 {
0405     struct acpi_button *button = acpi_driver_data(device);
0406     struct input_dev *input;
0407 
0408     switch (event) {
0409     case ACPI_FIXED_HARDWARE_EVENT:
0410         event = ACPI_BUTTON_NOTIFY_STATUS;
0411         fallthrough;
0412     case ACPI_BUTTON_NOTIFY_STATUS:
0413         input = button->input;
0414         if (button->type == ACPI_BUTTON_TYPE_LID) {
0415             if (button->lid_state_initialized)
0416                 acpi_lid_update_state(device, true);
0417         } else {
0418             int keycode;
0419 
0420             acpi_pm_wakeup_event(&device->dev);
0421             if (button->suspended)
0422                 break;
0423 
0424             keycode = test_bit(KEY_SLEEP, input->keybit) ?
0425                         KEY_SLEEP : KEY_POWER;
0426             input_report_key(input, keycode, 1);
0427             input_sync(input);
0428             input_report_key(input, keycode, 0);
0429             input_sync(input);
0430 
0431             acpi_bus_generate_netlink_event(
0432                     device->pnp.device_class,
0433                     dev_name(&device->dev),
0434                     event, ++button->pushed);
0435         }
0436         break;
0437     default:
0438         acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
0439                   event);
0440         break;
0441     }
0442 }
0443 
0444 #ifdef CONFIG_PM_SLEEP
0445 static int acpi_button_suspend(struct device *dev)
0446 {
0447     struct acpi_device *device = to_acpi_device(dev);
0448     struct acpi_button *button = acpi_driver_data(device);
0449 
0450     button->suspended = true;
0451     return 0;
0452 }
0453 
0454 static int acpi_button_resume(struct device *dev)
0455 {
0456     struct acpi_device *device = to_acpi_device(dev);
0457     struct acpi_button *button = acpi_driver_data(device);
0458 
0459     button->suspended = false;
0460     if (button->type == ACPI_BUTTON_TYPE_LID) {
0461         button->last_state = !!acpi_lid_evaluate_state(device);
0462         button->last_time = ktime_get();
0463         acpi_lid_initialize_state(device);
0464     }
0465     return 0;
0466 }
0467 #endif
0468 
0469 static int acpi_lid_input_open(struct input_dev *input)
0470 {
0471     struct acpi_device *device = input_get_drvdata(input);
0472     struct acpi_button *button = acpi_driver_data(device);
0473 
0474     button->last_state = !!acpi_lid_evaluate_state(device);
0475     button->last_time = ktime_get();
0476     acpi_lid_initialize_state(device);
0477 
0478     return 0;
0479 }
0480 
0481 static int acpi_button_add(struct acpi_device *device)
0482 {
0483     struct acpi_button *button;
0484     struct input_dev *input;
0485     const char *hid = acpi_device_hid(device);
0486     char *name, *class;
0487     int error;
0488 
0489     if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
0490          lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
0491         return -ENODEV;
0492 
0493     button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
0494     if (!button)
0495         return -ENOMEM;
0496 
0497     device->driver_data = button;
0498 
0499     button->input = input = input_allocate_device();
0500     if (!input) {
0501         error = -ENOMEM;
0502         goto err_free_button;
0503     }
0504 
0505     name = acpi_device_name(device);
0506     class = acpi_device_class(device);
0507 
0508     if (!strcmp(hid, ACPI_BUTTON_HID_POWER) ||
0509         !strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
0510         button->type = ACPI_BUTTON_TYPE_POWER;
0511         strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
0512         sprintf(class, "%s/%s",
0513             ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
0514     } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
0515            !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
0516         button->type = ACPI_BUTTON_TYPE_SLEEP;
0517         strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
0518         sprintf(class, "%s/%s",
0519             ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
0520     } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
0521         button->type = ACPI_BUTTON_TYPE_LID;
0522         strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
0523         sprintf(class, "%s/%s",
0524             ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
0525         input->open = acpi_lid_input_open;
0526     } else {
0527         pr_info("Unsupported hid [%s]\n", hid);
0528         error = -ENODEV;
0529         goto err_free_input;
0530     }
0531 
0532     error = acpi_button_add_fs(device);
0533     if (error)
0534         goto err_free_input;
0535 
0536     snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
0537 
0538     input->name = name;
0539     input->phys = button->phys;
0540     input->id.bustype = BUS_HOST;
0541     input->id.product = button->type;
0542     input->dev.parent = &device->dev;
0543 
0544     switch (button->type) {
0545     case ACPI_BUTTON_TYPE_POWER:
0546         input_set_capability(input, EV_KEY, KEY_POWER);
0547         break;
0548 
0549     case ACPI_BUTTON_TYPE_SLEEP:
0550         input_set_capability(input, EV_KEY, KEY_SLEEP);
0551         break;
0552 
0553     case ACPI_BUTTON_TYPE_LID:
0554         input_set_capability(input, EV_SW, SW_LID);
0555         break;
0556     }
0557 
0558     input_set_drvdata(input, device);
0559     error = input_register_device(input);
0560     if (error)
0561         goto err_remove_fs;
0562     if (button->type == ACPI_BUTTON_TYPE_LID) {
0563         /*
0564          * This assumes there's only one lid device, or if there are
0565          * more we only care about the last one...
0566          */
0567         lid_device = device;
0568     }
0569 
0570     device_init_wakeup(&device->dev, true);
0571     pr_info("%s [%s]\n", name, acpi_device_bid(device));
0572     return 0;
0573 
0574  err_remove_fs:
0575     acpi_button_remove_fs(device);
0576  err_free_input:
0577     input_free_device(input);
0578  err_free_button:
0579     kfree(button);
0580     return error;
0581 }
0582 
0583 static int acpi_button_remove(struct acpi_device *device)
0584 {
0585     struct acpi_button *button = acpi_driver_data(device);
0586 
0587     acpi_button_remove_fs(device);
0588     input_unregister_device(button->input);
0589     kfree(button);
0590     return 0;
0591 }
0592 
0593 static int param_set_lid_init_state(const char *val,
0594                     const struct kernel_param *kp)
0595 {
0596     int i;
0597 
0598     i = sysfs_match_string(lid_init_state_str, val);
0599     if (i < 0)
0600         return i;
0601 
0602     lid_init_state = i;
0603     pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]);
0604     return 0;
0605 }
0606 
0607 static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
0608 {
0609     int i, c = 0;
0610 
0611     for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
0612         if (i == lid_init_state)
0613             c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
0614         else
0615             c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
0616 
0617     buf[c - 1] = '\n'; /* Replace the final space with a newline */
0618 
0619     return c;
0620 }
0621 
0622 module_param_call(lid_init_state,
0623           param_set_lid_init_state, param_get_lid_init_state,
0624           NULL, 0644);
0625 MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
0626 
0627 static int acpi_button_register_driver(struct acpi_driver *driver)
0628 {
0629     const struct dmi_system_id *dmi_id;
0630 
0631     if (lid_init_state == -1) {
0632         dmi_id = dmi_first_match(dmi_lid_quirks);
0633         if (dmi_id)
0634             lid_init_state = (long)dmi_id->driver_data;
0635         else
0636             lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
0637     }
0638 
0639     /*
0640      * Modules such as nouveau.ko and i915.ko have a link time dependency
0641      * on acpi_lid_open(), and would therefore not be loadable on ACPI
0642      * capable kernels booted in non-ACPI mode if the return value of
0643      * acpi_bus_register_driver() is returned from here with ACPI disabled
0644      * when this driver is built as a module.
0645      */
0646     if (acpi_disabled)
0647         return 0;
0648 
0649     return acpi_bus_register_driver(driver);
0650 }
0651 
0652 static void acpi_button_unregister_driver(struct acpi_driver *driver)
0653 {
0654     if (!acpi_disabled)
0655         acpi_bus_unregister_driver(driver);
0656 }
0657 
0658 module_driver(acpi_button_driver, acpi_button_register_driver,
0659            acpi_button_unregister_driver);