button.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * button.c - ACPI Button Driver
  4. *
  5. * Copyright (C) 2001, 2002 Andy Grover <[email protected]>
  6. * Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>
  7. */
  8. #define pr_fmt(fmt) "ACPI: button: " fmt
  9. #include <linux/compiler.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/types.h>
  14. #include <linux/proc_fs.h>
  15. #include <linux/seq_file.h>
  16. #include <linux/input.h>
  17. #include <linux/slab.h>
  18. #include <linux/acpi.h>
  19. #include <linux/dmi.h>
  20. #include <acpi/button.h>
  21. #define ACPI_BUTTON_CLASS "button"
  22. #define ACPI_BUTTON_FILE_STATE "state"
  23. #define ACPI_BUTTON_TYPE_UNKNOWN 0x00
  24. #define ACPI_BUTTON_NOTIFY_STATUS 0x80
  25. #define ACPI_BUTTON_SUBCLASS_POWER "power"
  26. #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button"
  27. #define ACPI_BUTTON_TYPE_POWER 0x01
  28. #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
  29. #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button"
  30. #define ACPI_BUTTON_TYPE_SLEEP 0x03
  31. #define ACPI_BUTTON_SUBCLASS_LID "lid"
  32. #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
  33. #define ACPI_BUTTON_TYPE_LID 0x05
  34. enum {
  35. ACPI_BUTTON_LID_INIT_IGNORE,
  36. ACPI_BUTTON_LID_INIT_OPEN,
  37. ACPI_BUTTON_LID_INIT_METHOD,
  38. ACPI_BUTTON_LID_INIT_DISABLED,
  39. };
  40. static const char * const lid_init_state_str[] = {
  41. [ACPI_BUTTON_LID_INIT_IGNORE] = "ignore",
  42. [ACPI_BUTTON_LID_INIT_OPEN] = "open",
  43. [ACPI_BUTTON_LID_INIT_METHOD] = "method",
  44. [ACPI_BUTTON_LID_INIT_DISABLED] = "disabled",
  45. };
  46. MODULE_AUTHOR("Paul Diefenbaugh");
  47. MODULE_DESCRIPTION("ACPI Button Driver");
  48. MODULE_LICENSE("GPL");
  49. static const struct acpi_device_id button_device_ids[] = {
  50. {ACPI_BUTTON_HID_LID, 0},
  51. {ACPI_BUTTON_HID_SLEEP, 0},
  52. {ACPI_BUTTON_HID_SLEEPF, 0},
  53. {ACPI_BUTTON_HID_POWER, 0},
  54. {ACPI_BUTTON_HID_POWERF, 0},
  55. {"", 0},
  56. };
  57. MODULE_DEVICE_TABLE(acpi, button_device_ids);
  58. /* Please keep this list sorted alphabetically by vendor and model */
  59. static const struct dmi_system_id dmi_lid_quirks[] = {
  60. {
  61. /* GP-electronic T701, _LID method points to a floating GPIO */
  62. .matches = {
  63. DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
  64. DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
  65. DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
  66. },
  67. .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
  68. },
  69. {
  70. /*
  71. * Lenovo Yoga 9 14ITL5, initial notification of the LID device
  72. * never happens.
  73. */
  74. .matches = {
  75. DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
  76. DMI_MATCH(DMI_PRODUCT_NAME, "82BG"),
  77. },
  78. .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
  79. },
  80. {
  81. /*
  82. * Medion Akoya E2215T, notification of the LID device only
  83. * happens on close, not on open and _LID always returns closed.
  84. */
  85. .matches = {
  86. DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
  87. DMI_MATCH(DMI_PRODUCT_NAME, "E2215T"),
  88. },
  89. .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
  90. },
  91. {
  92. /*
  93. * Medion Akoya E2228T, notification of the LID device only
  94. * happens on close, not on open and _LID always returns closed.
  95. */
  96. .matches = {
  97. DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
  98. DMI_MATCH(DMI_PRODUCT_NAME, "E2228T"),
  99. },
  100. .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
  101. },
  102. {
  103. /*
  104. * Razer Blade Stealth 13 late 2019, notification of the LID device
  105. * only happens on close, not on open and _LID always returns closed.
  106. */
  107. .matches = {
  108. DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
  109. DMI_MATCH(DMI_PRODUCT_NAME, "Razer Blade Stealth 13 Late 2019"),
  110. },
  111. .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
  112. },
  113. {}
  114. };
  115. static int acpi_button_add(struct acpi_device *device);
  116. static int acpi_button_remove(struct acpi_device *device);
  117. static void acpi_button_notify(struct acpi_device *device, u32 event);
  118. #ifdef CONFIG_PM_SLEEP
  119. static int acpi_button_suspend(struct device *dev);
  120. static int acpi_button_resume(struct device *dev);
  121. #else
  122. #define acpi_button_suspend NULL
  123. #define acpi_button_resume NULL
  124. #endif
  125. static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume);
  126. static struct acpi_driver acpi_button_driver = {
  127. .name = "button",
  128. .class = ACPI_BUTTON_CLASS,
  129. .ids = button_device_ids,
  130. .ops = {
  131. .add = acpi_button_add,
  132. .remove = acpi_button_remove,
  133. .notify = acpi_button_notify,
  134. },
  135. .drv.pm = &acpi_button_pm,
  136. };
  137. struct acpi_button {
  138. unsigned int type;
  139. struct input_dev *input;
  140. char phys[32]; /* for input device */
  141. unsigned long pushed;
  142. int last_state;
  143. ktime_t last_time;
  144. bool suspended;
  145. bool lid_state_initialized;
  146. };
  147. static struct acpi_device *lid_device;
  148. static long lid_init_state = -1;
  149. static unsigned long lid_report_interval __read_mostly = 500;
  150. module_param(lid_report_interval, ulong, 0644);
  151. MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
  152. /* FS Interface (/proc) */
  153. static struct proc_dir_entry *acpi_button_dir;
  154. static struct proc_dir_entry *acpi_lid_dir;
  155. static int acpi_lid_evaluate_state(struct acpi_device *device)
  156. {
  157. unsigned long long lid_state;
  158. acpi_status status;
  159. status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state);
  160. if (ACPI_FAILURE(status))
  161. return -ENODEV;
  162. return lid_state ? 1 : 0;
  163. }
  164. static int acpi_lid_notify_state(struct acpi_device *device, int state)
  165. {
  166. struct acpi_button *button = acpi_driver_data(device);
  167. ktime_t next_report;
  168. bool do_update;
  169. /*
  170. * In lid_init_state=ignore mode, if user opens/closes lid
  171. * frequently with "open" missing, and "last_time" is also updated
  172. * frequently, "close" cannot be delivered to the userspace.
  173. * So "last_time" is only updated after a timeout or an actual
  174. * switch.
  175. */
  176. if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE ||
  177. button->last_state != !!state)
  178. do_update = true;
  179. else
  180. do_update = false;
  181. next_report = ktime_add(button->last_time,
  182. ms_to_ktime(lid_report_interval));
  183. if (button->last_state == !!state &&
  184. ktime_after(ktime_get(), next_report)) {
  185. /* Complain the buggy firmware */
  186. pr_warn_once("The lid device is not compliant to SW_LID.\n");
  187. /*
  188. * Send the unreliable complement switch event:
  189. *
  190. * On most platforms, the lid device is reliable. However
  191. * there are exceptions:
  192. * 1. Platforms returning initial lid state as "close" by
  193. * default after booting/resuming:
  194. * https://bugzilla.kernel.org/show_bug.cgi?id=89211
  195. * https://bugzilla.kernel.org/show_bug.cgi?id=106151
  196. * 2. Platforms never reporting "open" events:
  197. * https://bugzilla.kernel.org/show_bug.cgi?id=106941
  198. * On these buggy platforms, the usage model of the ACPI
  199. * lid device actually is:
  200. * 1. The initial returning value of _LID may not be
  201. * reliable.
  202. * 2. The open event may not be reliable.
  203. * 3. The close event is reliable.
  204. *
  205. * But SW_LID is typed as input switch event, the input
  206. * layer checks if the event is redundant. Hence if the
  207. * state is not switched, the userspace cannot see this
  208. * platform triggered reliable event. By inserting a
  209. * complement switch event, it then is guaranteed that the
  210. * platform triggered reliable one can always be seen by
  211. * the userspace.
  212. */
  213. if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE) {
  214. do_update = true;
  215. /*
  216. * Do generate complement switch event for "close"
  217. * as "close" is reliable and wrong "open" won't
  218. * trigger unexpected behaviors.
  219. * Do not generate complement switch event for
  220. * "open" as "open" is not reliable and wrong
  221. * "close" will trigger unexpected behaviors.
  222. */
  223. if (!state) {
  224. input_report_switch(button->input,
  225. SW_LID, state);
  226. input_sync(button->input);
  227. }
  228. }
  229. }
  230. /* Send the platform triggered reliable event */
  231. if (do_update) {
  232. acpi_handle_debug(device->handle, "ACPI LID %s\n",
  233. state ? "open" : "closed");
  234. input_report_switch(button->input, SW_LID, !state);
  235. input_sync(button->input);
  236. button->last_state = !!state;
  237. button->last_time = ktime_get();
  238. }
  239. return 0;
  240. }
  241. static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq,
  242. void *offset)
  243. {
  244. struct acpi_device *device = seq->private;
  245. int state;
  246. state = acpi_lid_evaluate_state(device);
  247. seq_printf(seq, "state: %s\n",
  248. state < 0 ? "unsupported" : (state ? "open" : "closed"));
  249. return 0;
  250. }
  251. static int acpi_button_add_fs(struct acpi_device *device)
  252. {
  253. struct acpi_button *button = acpi_driver_data(device);
  254. struct proc_dir_entry *entry = NULL;
  255. int ret = 0;
  256. /* procfs I/F for ACPI lid device only */
  257. if (button->type != ACPI_BUTTON_TYPE_LID)
  258. return 0;
  259. if (acpi_button_dir || acpi_lid_dir) {
  260. pr_info("More than one Lid device found!\n");
  261. return -EEXIST;
  262. }
  263. /* create /proc/acpi/button */
  264. acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
  265. if (!acpi_button_dir)
  266. return -ENODEV;
  267. /* create /proc/acpi/button/lid */
  268. acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
  269. if (!acpi_lid_dir) {
  270. ret = -ENODEV;
  271. goto remove_button_dir;
  272. }
  273. /* create /proc/acpi/button/lid/LID/ */
  274. acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir);
  275. if (!acpi_device_dir(device)) {
  276. ret = -ENODEV;
  277. goto remove_lid_dir;
  278. }
  279. /* create /proc/acpi/button/lid/LID/state */
  280. entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO,
  281. acpi_device_dir(device), acpi_button_state_seq_show,
  282. device);
  283. if (!entry) {
  284. ret = -ENODEV;
  285. goto remove_dev_dir;
  286. }
  287. done:
  288. return ret;
  289. remove_dev_dir:
  290. remove_proc_entry(acpi_device_bid(device),
  291. acpi_lid_dir);
  292. acpi_device_dir(device) = NULL;
  293. remove_lid_dir:
  294. remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
  295. acpi_lid_dir = NULL;
  296. remove_button_dir:
  297. remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
  298. acpi_button_dir = NULL;
  299. goto done;
  300. }
  301. static int acpi_button_remove_fs(struct acpi_device *device)
  302. {
  303. struct acpi_button *button = acpi_driver_data(device);
  304. if (button->type != ACPI_BUTTON_TYPE_LID)
  305. return 0;
  306. remove_proc_entry(ACPI_BUTTON_FILE_STATE,
  307. acpi_device_dir(device));
  308. remove_proc_entry(acpi_device_bid(device),
  309. acpi_lid_dir);
  310. acpi_device_dir(device) = NULL;
  311. remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
  312. acpi_lid_dir = NULL;
  313. remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
  314. acpi_button_dir = NULL;
  315. return 0;
  316. }
  317. /* Driver Interface */
  318. int acpi_lid_open(void)
  319. {
  320. if (!lid_device)
  321. return -ENODEV;
  322. return acpi_lid_evaluate_state(lid_device);
  323. }
  324. EXPORT_SYMBOL(acpi_lid_open);
  325. static int acpi_lid_update_state(struct acpi_device *device,
  326. bool signal_wakeup)
  327. {
  328. int state;
  329. state = acpi_lid_evaluate_state(device);
  330. if (state < 0)
  331. return state;
  332. if (state && signal_wakeup)
  333. acpi_pm_wakeup_event(&device->dev);
  334. return acpi_lid_notify_state(device, state);
  335. }
  336. static void acpi_lid_initialize_state(struct acpi_device *device)
  337. {
  338. struct acpi_button *button = acpi_driver_data(device);
  339. switch (lid_init_state) {
  340. case ACPI_BUTTON_LID_INIT_OPEN:
  341. (void)acpi_lid_notify_state(device, 1);
  342. break;
  343. case ACPI_BUTTON_LID_INIT_METHOD:
  344. (void)acpi_lid_update_state(device, false);
  345. break;
  346. case ACPI_BUTTON_LID_INIT_IGNORE:
  347. default:
  348. break;
  349. }
  350. button->lid_state_initialized = true;
  351. }
  352. static void acpi_button_notify(struct acpi_device *device, u32 event)
  353. {
  354. struct acpi_button *button = acpi_driver_data(device);
  355. struct input_dev *input;
  356. switch (event) {
  357. case ACPI_FIXED_HARDWARE_EVENT:
  358. event = ACPI_BUTTON_NOTIFY_STATUS;
  359. fallthrough;
  360. case ACPI_BUTTON_NOTIFY_STATUS:
  361. input = button->input;
  362. if (button->type == ACPI_BUTTON_TYPE_LID) {
  363. if (button->lid_state_initialized)
  364. acpi_lid_update_state(device, true);
  365. } else {
  366. int keycode;
  367. acpi_pm_wakeup_event(&device->dev);
  368. if (button->suspended)
  369. break;
  370. keycode = test_bit(KEY_SLEEP, input->keybit) ?
  371. KEY_SLEEP : KEY_POWER;
  372. input_report_key(input, keycode, 1);
  373. input_sync(input);
  374. input_report_key(input, keycode, 0);
  375. input_sync(input);
  376. acpi_bus_generate_netlink_event(
  377. device->pnp.device_class,
  378. dev_name(&device->dev),
  379. event, ++button->pushed);
  380. }
  381. break;
  382. default:
  383. acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
  384. event);
  385. break;
  386. }
  387. }
  388. #ifdef CONFIG_PM_SLEEP
  389. static int acpi_button_suspend(struct device *dev)
  390. {
  391. struct acpi_device *device = to_acpi_device(dev);
  392. struct acpi_button *button = acpi_driver_data(device);
  393. button->suspended = true;
  394. return 0;
  395. }
  396. static int acpi_button_resume(struct device *dev)
  397. {
  398. struct acpi_device *device = to_acpi_device(dev);
  399. struct acpi_button *button = acpi_driver_data(device);
  400. button->suspended = false;
  401. if (button->type == ACPI_BUTTON_TYPE_LID) {
  402. button->last_state = !!acpi_lid_evaluate_state(device);
  403. button->last_time = ktime_get();
  404. acpi_lid_initialize_state(device);
  405. }
  406. return 0;
  407. }
  408. #endif
  409. static int acpi_lid_input_open(struct input_dev *input)
  410. {
  411. struct acpi_device *device = input_get_drvdata(input);
  412. struct acpi_button *button = acpi_driver_data(device);
  413. button->last_state = !!acpi_lid_evaluate_state(device);
  414. button->last_time = ktime_get();
  415. acpi_lid_initialize_state(device);
  416. return 0;
  417. }
  418. static int acpi_button_add(struct acpi_device *device)
  419. {
  420. struct acpi_button *button;
  421. struct input_dev *input;
  422. const char *hid = acpi_device_hid(device);
  423. char *name, *class;
  424. int error;
  425. if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
  426. lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
  427. return -ENODEV;
  428. button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
  429. if (!button)
  430. return -ENOMEM;
  431. device->driver_data = button;
  432. button->input = input = input_allocate_device();
  433. if (!input) {
  434. error = -ENOMEM;
  435. goto err_free_button;
  436. }
  437. name = acpi_device_name(device);
  438. class = acpi_device_class(device);
  439. if (!strcmp(hid, ACPI_BUTTON_HID_POWER) ||
  440. !strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
  441. button->type = ACPI_BUTTON_TYPE_POWER;
  442. strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
  443. sprintf(class, "%s/%s",
  444. ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
  445. } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
  446. !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
  447. button->type = ACPI_BUTTON_TYPE_SLEEP;
  448. strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
  449. sprintf(class, "%s/%s",
  450. ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
  451. } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
  452. button->type = ACPI_BUTTON_TYPE_LID;
  453. strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
  454. sprintf(class, "%s/%s",
  455. ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
  456. input->open = acpi_lid_input_open;
  457. } else {
  458. pr_info("Unsupported hid [%s]\n", hid);
  459. error = -ENODEV;
  460. goto err_free_input;
  461. }
  462. error = acpi_button_add_fs(device);
  463. if (error)
  464. goto err_free_input;
  465. snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
  466. input->name = name;
  467. input->phys = button->phys;
  468. input->id.bustype = BUS_HOST;
  469. input->id.product = button->type;
  470. input->dev.parent = &device->dev;
  471. switch (button->type) {
  472. case ACPI_BUTTON_TYPE_POWER:
  473. input_set_capability(input, EV_KEY, KEY_POWER);
  474. break;
  475. case ACPI_BUTTON_TYPE_SLEEP:
  476. input_set_capability(input, EV_KEY, KEY_SLEEP);
  477. break;
  478. case ACPI_BUTTON_TYPE_LID:
  479. input_set_capability(input, EV_SW, SW_LID);
  480. break;
  481. }
  482. input_set_drvdata(input, device);
  483. error = input_register_device(input);
  484. if (error)
  485. goto err_remove_fs;
  486. if (button->type == ACPI_BUTTON_TYPE_LID) {
  487. /*
  488. * This assumes there's only one lid device, or if there are
  489. * more we only care about the last one...
  490. */
  491. lid_device = device;
  492. }
  493. device_init_wakeup(&device->dev, true);
  494. pr_info("%s [%s]\n", name, acpi_device_bid(device));
  495. return 0;
  496. err_remove_fs:
  497. acpi_button_remove_fs(device);
  498. err_free_input:
  499. input_free_device(input);
  500. err_free_button:
  501. kfree(button);
  502. return error;
  503. }
  504. static int acpi_button_remove(struct acpi_device *device)
  505. {
  506. struct acpi_button *button = acpi_driver_data(device);
  507. acpi_button_remove_fs(device);
  508. input_unregister_device(button->input);
  509. kfree(button);
  510. return 0;
  511. }
  512. static int param_set_lid_init_state(const char *val,
  513. const struct kernel_param *kp)
  514. {
  515. int i;
  516. i = sysfs_match_string(lid_init_state_str, val);
  517. if (i < 0)
  518. return i;
  519. lid_init_state = i;
  520. pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]);
  521. return 0;
  522. }
  523. static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
  524. {
  525. int i, c = 0;
  526. for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
  527. if (i == lid_init_state)
  528. c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
  529. else
  530. c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
  531. buf[c - 1] = '\n'; /* Replace the final space with a newline */
  532. return c;
  533. }
  534. module_param_call(lid_init_state,
  535. param_set_lid_init_state, param_get_lid_init_state,
  536. NULL, 0644);
  537. MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
  538. static int acpi_button_register_driver(struct acpi_driver *driver)
  539. {
  540. const struct dmi_system_id *dmi_id;
  541. if (lid_init_state == -1) {
  542. dmi_id = dmi_first_match(dmi_lid_quirks);
  543. if (dmi_id)
  544. lid_init_state = (long)dmi_id->driver_data;
  545. else
  546. lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
  547. }
  548. /*
  549. * Modules such as nouveau.ko and i915.ko have a link time dependency
  550. * on acpi_lid_open(), and would therefore not be loadable on ACPI
  551. * capable kernels booted in non-ACPI mode if the return value of
  552. * acpi_bus_register_driver() is returned from here with ACPI disabled
  553. * when this driver is built as a module.
  554. */
  555. if (acpi_disabled)
  556. return 0;
  557. return acpi_bus_register_driver(driver);
  558. }
  559. static void acpi_button_unregister_driver(struct acpi_driver *driver)
  560. {
  561. if (!acpi_disabled)
  562. acpi_bus_unregister_driver(driver);
  563. }
  564. module_driver(acpi_button_driver, acpi_button_register_driver,
  565. acpi_button_unregister_driver);