hotkey.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. /*
  2. * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $)
  3. *
  4. * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  5. *
  6. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21. *
  22. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23. */
  24. #include <linux/kernel.h>
  25. #include <linux/module.h>
  26. #include <linux/init.h>
  27. #include <linux/types.h>
  28. #include <linux/proc_fs.h>
  29. #include <linux/sched.h>
  30. #include <linux/kmod.h>
  31. #include <linux/seq_file.h>
  32. #include <acpi/acpi_drivers.h>
  33. #include <acpi/acpi_bus.h>
  34. #include <asm/uaccess.h>
  35. #define HOTKEY_ACPI_VERSION "0.1"
  36. #define HOTKEY_PROC "hotkey"
  37. #define HOTKEY_EV_CONFIG "event_config"
  38. #define HOTKEY_PL_CONFIG "poll_config"
  39. #define HOTKEY_ACTION "action"
  40. #define HOTKEY_INFO "info"
  41. #define ACPI_HOTK_NAME "Generic Hotkey Driver"
  42. #define ACPI_HOTK_CLASS "Hotkey"
  43. #define ACPI_HOTK_DEVICE_NAME "Hotkey"
  44. #define ACPI_HOTK_HID "Unknown?"
  45. #define ACPI_HOTKEY_COMPONENT 0x20000000
  46. #define ACPI_HOTKEY_EVENT 0x1
  47. #define ACPI_HOTKEY_POLLING 0x2
  48. #define ACPI_UNDEFINED_EVENT 0xf
  49. #define RESULT_STR_LEN 80
  50. #define ACTION_METHOD 0
  51. #define POLL_METHOD 1
  52. #define IS_EVENT(e) ((e) <= 10000 && (e) >0)
  53. #define IS_POLL(e) ((e) > 10000)
  54. #define IS_OTHERS(e) ((e)<=0 || (e)>=20000)
  55. #define _COMPONENT ACPI_HOTKEY_COMPONENT
  56. ACPI_MODULE_NAME("acpi_hotkey")
  57. MODULE_AUTHOR("luming.yu@intel.com");
  58. MODULE_DESCRIPTION(ACPI_HOTK_NAME);
  59. MODULE_LICENSE("GPL");
  60. /* standardized internal hotkey number/event */
  61. enum {
  62. /* Video Extension event */
  63. HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80,
  64. HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE,
  65. HK_EVENT_CYCLE_DISPLAY_OUTPUT,
  66. HK_EVENT_NEXT_DISPLAY_OUTPUT,
  67. HK_EVENT_PREVIOUS_DISPLAY_OUTPUT,
  68. HK_EVENT_CYCLE_BRIGHTNESS,
  69. HK_EVENT_INCREASE_BRIGHTNESS,
  70. HK_EVENT_DECREASE_BRIGHTNESS,
  71. HK_EVENT_ZERO_BRIGHTNESS,
  72. HK_EVENT_DISPLAY_DEVICE_OFF,
  73. /* Snd Card event */
  74. HK_EVENT_VOLUME_MUTE,
  75. HK_EVENT_VOLUME_INCLREASE,
  76. HK_EVENT_VOLUME_DECREASE,
  77. /* running state control */
  78. HK_EVENT_ENTERRING_S3,
  79. HK_EVENT_ENTERRING_S4,
  80. HK_EVENT_ENTERRING_S5,
  81. };
  82. /* procdir we use */
  83. static struct proc_dir_entry *hotkey_proc_dir;
  84. static struct proc_dir_entry *hotkey_config;
  85. static struct proc_dir_entry *hotkey_poll_config;
  86. static struct proc_dir_entry *hotkey_action;
  87. static struct proc_dir_entry *hotkey_info;
  88. /* linkage for all type of hotkey */
  89. struct acpi_hotkey_link {
  90. struct list_head entries;
  91. int hotkey_type; /* event or polling based hotkey */
  92. int hotkey_standard_num; /* standardized hotkey(event) number */
  93. };
  94. /* event based hotkey */
  95. struct acpi_event_hotkey {
  96. struct acpi_hotkey_link hotkey_link;
  97. int flag;
  98. acpi_handle bus_handle; /* bus to install notify handler */
  99. int external_hotkey_num; /* external hotkey/event number */
  100. acpi_handle action_handle; /* acpi handle attached aml action method */
  101. char *action_method; /* action method */
  102. };
  103. /*
  104. * There are two ways to poll status
  105. * 1. directy call read_xxx method, without any arguments passed in
  106. * 2. call write_xxx method, with arguments passed in, you need
  107. * the result is saved in acpi_polling_hotkey.poll_result.
  108. * anthoer read command through polling interface.
  109. *
  110. */
  111. /* polling based hotkey */
  112. struct acpi_polling_hotkey {
  113. struct acpi_hotkey_link hotkey_link;
  114. int flag;
  115. acpi_handle poll_handle; /* acpi handle attached polling method */
  116. char *poll_method; /* poll method */
  117. acpi_handle action_handle; /* acpi handle attached action method */
  118. char *action_method; /* action method */
  119. union acpi_object *poll_result; /* polling_result */
  120. struct proc_dir_entry *proc;
  121. };
  122. /* hotkey object union */
  123. union acpi_hotkey {
  124. struct list_head entries;
  125. struct acpi_hotkey_link link;
  126. struct acpi_event_hotkey event_hotkey;
  127. struct acpi_polling_hotkey poll_hotkey;
  128. };
  129. /* hotkey object list */
  130. struct acpi_hotkey_list {
  131. struct list_head *entries;
  132. int count;
  133. };
  134. static int auto_hotkey_add(struct acpi_device *device);
  135. static int auto_hotkey_remove(struct acpi_device *device, int type);
  136. static struct acpi_driver hotkey_driver = {
  137. .name = ACPI_HOTK_NAME,
  138. .class = ACPI_HOTK_CLASS,
  139. .ids = ACPI_HOTK_HID,
  140. .ops = {
  141. .add = auto_hotkey_add,
  142. .remove = auto_hotkey_remove,
  143. },
  144. };
  145. static void free_hotkey_device(union acpi_hotkey *key);
  146. static void free_hotkey_buffer(union acpi_hotkey *key);
  147. static void free_poll_hotkey_buffer(union acpi_hotkey *key);
  148. static int hotkey_open_config(struct inode *inode, struct file *file);
  149. static int hotkey_poll_open_config(struct inode *inode, struct file *file);
  150. static ssize_t hotkey_write_config(struct file *file,
  151. const char __user * buffer,
  152. size_t count, loff_t * data);
  153. static int hotkey_info_open_fs(struct inode *inode, struct file *file);
  154. static int hotkey_action_open_fs(struct inode *inode, struct file *file);
  155. static ssize_t hotkey_execute_aml_method(struct file *file,
  156. const char __user * buffer,
  157. size_t count, loff_t * data);
  158. static int hotkey_config_seq_show(struct seq_file *seq, void *offset);
  159. static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset);
  160. static int hotkey_polling_open_fs(struct inode *inode, struct file *file);
  161. static union acpi_hotkey *get_hotkey_by_event(struct
  162. acpi_hotkey_list
  163. *hotkey_list, int event);
  164. /* event based config */
  165. static struct file_operations hotkey_config_fops = {
  166. .open = hotkey_open_config,
  167. .read = seq_read,
  168. .write = hotkey_write_config,
  169. .llseek = seq_lseek,
  170. .release = single_release,
  171. };
  172. /* polling based config */
  173. static struct file_operations hotkey_poll_config_fops = {
  174. .open = hotkey_poll_open_config,
  175. .read = seq_read,
  176. .write = hotkey_write_config,
  177. .llseek = seq_lseek,
  178. .release = single_release,
  179. };
  180. /* hotkey driver info */
  181. static struct file_operations hotkey_info_fops = {
  182. .open = hotkey_info_open_fs,
  183. .read = seq_read,
  184. .llseek = seq_lseek,
  185. .release = single_release,
  186. };
  187. /* action */
  188. static struct file_operations hotkey_action_fops = {
  189. .open = hotkey_action_open_fs,
  190. .read = seq_read,
  191. .write = hotkey_execute_aml_method,
  192. .llseek = seq_lseek,
  193. .release = single_release,
  194. };
  195. /* polling results */
  196. static struct file_operations hotkey_polling_fops = {
  197. .open = hotkey_polling_open_fs,
  198. .read = seq_read,
  199. .llseek = seq_lseek,
  200. .release = single_release,
  201. };
  202. struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */
  203. struct list_head hotkey_entries; /* head of the list of hotkey_list */
  204. static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
  205. {
  206. seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION);
  207. return 0;
  208. }
  209. static int hotkey_info_open_fs(struct inode *inode, struct file *file)
  210. {
  211. return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
  212. }
  213. static char *format_result(union acpi_object *object)
  214. {
  215. char *buf = NULL;
  216. buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL);
  217. if (buf)
  218. memset(buf, 0, RESULT_STR_LEN);
  219. else
  220. goto do_fail;
  221. /* Now, just support integer type */
  222. if (object->type == ACPI_TYPE_INTEGER)
  223. sprintf(buf, "%d\n", (u32) object->integer.value);
  224. do_fail:
  225. return (buf);
  226. }
  227. static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
  228. {
  229. struct acpi_polling_hotkey *poll_hotkey =
  230. (struct acpi_polling_hotkey *)seq->private;
  231. char *buf;
  232. if (poll_hotkey->poll_result) {
  233. buf = format_result(poll_hotkey->poll_result);
  234. if (buf)
  235. seq_printf(seq, "%s", buf);
  236. kfree(buf);
  237. }
  238. return 0;
  239. }
  240. static int hotkey_polling_open_fs(struct inode *inode, struct file *file)
  241. {
  242. return single_open(file, hotkey_polling_seq_show, PDE(inode)->data);
  243. }
  244. static int hotkey_action_open_fs(struct inode *inode, struct file *file)
  245. {
  246. return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
  247. }
  248. /* Mapping external hotkey number to standardized hotkey event num */
  249. static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
  250. {
  251. struct list_head *entries;
  252. int val = -1;
  253. list_for_each(entries, list->entries) {
  254. union acpi_hotkey *key =
  255. container_of(entries, union acpi_hotkey, entries);
  256. if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
  257. && key->event_hotkey.external_hotkey_num == event) {
  258. val = key->link.hotkey_standard_num;
  259. break;
  260. }
  261. }
  262. return val;
  263. }
  264. static void
  265. acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
  266. {
  267. struct acpi_device *device = NULL;
  268. u32 internal_event;
  269. if (acpi_bus_get_device(handle, &device))
  270. return;
  271. internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
  272. acpi_bus_generate_event(device, internal_event, 0);
  273. return;
  274. }
  275. /* Need to invent automatically hotkey add method */
  276. static int auto_hotkey_add(struct acpi_device *device)
  277. {
  278. /* Implement me */
  279. return 0;
  280. }
  281. /* Need to invent automatically hotkey remove method */
  282. static int auto_hotkey_remove(struct acpi_device *device, int type)
  283. {
  284. /* Implement me */
  285. return 0;
  286. }
  287. /* Create a proc file for each polling method */
  288. static int create_polling_proc(union acpi_hotkey *device)
  289. {
  290. struct proc_dir_entry *proc;
  291. char proc_name[80];
  292. mode_t mode;
  293. mode = S_IFREG | S_IRUGO | S_IWUGO;
  294. sprintf(proc_name, "%d", device->link.hotkey_standard_num);
  295. /*
  296. strcat(proc_name, device->poll_hotkey.poll_method);
  297. */
  298. proc = create_proc_entry(proc_name, mode, hotkey_proc_dir);
  299. if (!proc) {
  300. return -ENODEV;
  301. } else {
  302. proc->proc_fops = &hotkey_polling_fops;
  303. proc->owner = THIS_MODULE;
  304. proc->data = device;
  305. proc->uid = 0;
  306. proc->gid = 0;
  307. device->poll_hotkey.proc = proc;
  308. }
  309. return 0;
  310. }
  311. static int hotkey_add(union acpi_hotkey *device)
  312. {
  313. int status = 0;
  314. struct acpi_device *dev = NULL;
  315. if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
  316. acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
  317. status = acpi_install_notify_handler(dev->handle,
  318. ACPI_DEVICE_NOTIFY,
  319. acpi_hotkey_notify_handler,
  320. dev);
  321. } else /* Add polling hotkey */
  322. create_polling_proc(device);
  323. global_hotkey_list.count++;
  324. list_add_tail(&device->link.entries, global_hotkey_list.entries);
  325. return status;
  326. }
  327. static int hotkey_remove(union acpi_hotkey *device)
  328. {
  329. struct list_head *entries, *next;
  330. list_for_each_safe(entries, next, global_hotkey_list.entries) {
  331. union acpi_hotkey *key =
  332. container_of(entries, union acpi_hotkey, entries);
  333. if (key->link.hotkey_standard_num ==
  334. device->link.hotkey_standard_num) {
  335. list_del(&key->link.entries);
  336. free_hotkey_device(key);
  337. global_hotkey_list.count--;
  338. break;
  339. }
  340. }
  341. kfree(device);
  342. return 0;
  343. }
  344. static int hotkey_update(union acpi_hotkey *key)
  345. {
  346. struct list_head *entries;
  347. list_for_each(entries, global_hotkey_list.entries) {
  348. union acpi_hotkey *tmp =
  349. container_of(entries, union acpi_hotkey, entries);
  350. if (tmp->link.hotkey_standard_num ==
  351. key->link.hotkey_standard_num) {
  352. if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
  353. free_hotkey_buffer(tmp);
  354. tmp->event_hotkey.bus_handle =
  355. key->event_hotkey.bus_handle;
  356. tmp->event_hotkey.external_hotkey_num =
  357. key->event_hotkey.external_hotkey_num;
  358. tmp->event_hotkey.action_handle =
  359. key->event_hotkey.action_handle;
  360. tmp->event_hotkey.action_method =
  361. key->event_hotkey.action_method;
  362. kfree(key);
  363. } else {
  364. /*
  365. char proc_name[80];
  366. sprintf(proc_name, "%d", tmp->link.hotkey_standard_num);
  367. strcat(proc_name, tmp->poll_hotkey.poll_method);
  368. remove_proc_entry(proc_name,hotkey_proc_dir);
  369. */
  370. free_poll_hotkey_buffer(tmp);
  371. tmp->poll_hotkey.poll_handle =
  372. key->poll_hotkey.poll_handle;
  373. tmp->poll_hotkey.poll_method =
  374. key->poll_hotkey.poll_method;
  375. tmp->poll_hotkey.action_handle =
  376. key->poll_hotkey.action_handle;
  377. tmp->poll_hotkey.action_method =
  378. key->poll_hotkey.action_method;
  379. tmp->poll_hotkey.poll_result =
  380. key->poll_hotkey.poll_result;
  381. /*
  382. create_polling_proc(tmp);
  383. */
  384. kfree(key);
  385. }
  386. return 0;
  387. break;
  388. }
  389. }
  390. return -ENODEV;
  391. }
  392. static void free_hotkey_device(union acpi_hotkey *key)
  393. {
  394. struct acpi_device *dev;
  395. if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
  396. acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
  397. if (dev->handle)
  398. acpi_remove_notify_handler(dev->handle,
  399. ACPI_DEVICE_NOTIFY,
  400. acpi_hotkey_notify_handler);
  401. free_hotkey_buffer(key);
  402. } else {
  403. char proc_name[80];
  404. sprintf(proc_name, "%d", key->link.hotkey_standard_num);
  405. /*
  406. strcat(proc_name, key->poll_hotkey.poll_method);
  407. */
  408. remove_proc_entry(proc_name, hotkey_proc_dir);
  409. free_poll_hotkey_buffer(key);
  410. }
  411. kfree(key);
  412. return;
  413. }
  414. static void free_hotkey_buffer(union acpi_hotkey *key)
  415. {
  416. kfree(key->event_hotkey.action_method);
  417. }
  418. static void free_poll_hotkey_buffer(union acpi_hotkey *key)
  419. {
  420. kfree(key->poll_hotkey.action_method);
  421. kfree(key->poll_hotkey.poll_method);
  422. kfree(key->poll_hotkey.poll_result);
  423. }
  424. static int
  425. init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str,
  426. char *method, int std_num, int external_num)
  427. {
  428. acpi_handle tmp_handle;
  429. acpi_status status = AE_OK;
  430. if (std_num < 0 || IS_POLL(std_num) || !key)
  431. goto do_fail;
  432. if (!bus_str || !action_str || !method)
  433. goto do_fail;
  434. key->link.hotkey_type = ACPI_HOTKEY_EVENT;
  435. key->link.hotkey_standard_num = std_num;
  436. key->event_hotkey.flag = 0;
  437. key->event_hotkey.action_method = method;
  438. status =
  439. acpi_get_handle(NULL, bus_str, &(key->event_hotkey.bus_handle));
  440. if (ACPI_FAILURE(status))
  441. goto do_fail;
  442. key->event_hotkey.external_hotkey_num = external_num;
  443. status =
  444. acpi_get_handle(NULL, action_str,
  445. &(key->event_hotkey.action_handle));
  446. if (ACPI_FAILURE(status))
  447. goto do_fail;
  448. status = acpi_get_handle(key->event_hotkey.action_handle,
  449. method, &tmp_handle);
  450. if (ACPI_FAILURE(status))
  451. goto do_fail;
  452. return AE_OK;
  453. do_fail:
  454. return -ENODEV;
  455. }
  456. static int
  457. init_poll_hotkey_device(union acpi_hotkey *key,
  458. char *poll_str,
  459. char *poll_method,
  460. char *action_str, char *action_method, int std_num)
  461. {
  462. acpi_status status = AE_OK;
  463. acpi_handle tmp_handle;
  464. if (std_num < 0 || IS_EVENT(std_num) || !key)
  465. goto do_fail;
  466. if (!poll_str || !poll_method || !action_str || !action_method)
  467. goto do_fail;
  468. key->link.hotkey_type = ACPI_HOTKEY_POLLING;
  469. key->link.hotkey_standard_num = std_num;
  470. key->poll_hotkey.flag = 0;
  471. key->poll_hotkey.poll_method = poll_method;
  472. key->poll_hotkey.action_method = action_method;
  473. status =
  474. acpi_get_handle(NULL, poll_str, &(key->poll_hotkey.poll_handle));
  475. if (ACPI_FAILURE(status))
  476. goto do_fail;
  477. status = acpi_get_handle(key->poll_hotkey.poll_handle,
  478. poll_method, &tmp_handle);
  479. if (ACPI_FAILURE(status))
  480. goto do_fail;
  481. status =
  482. acpi_get_handle(NULL, action_str,
  483. &(key->poll_hotkey.action_handle));
  484. if (ACPI_FAILURE(status))
  485. goto do_fail;
  486. status = acpi_get_handle(key->poll_hotkey.action_handle,
  487. action_method, &tmp_handle);
  488. if (ACPI_FAILURE(status))
  489. goto do_fail;
  490. key->poll_hotkey.poll_result =
  491. (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
  492. if (!key->poll_hotkey.poll_result)
  493. goto do_fail;
  494. return AE_OK;
  495. do_fail:
  496. return -ENODEV;
  497. }
  498. static int hotkey_open_config(struct inode *inode, struct file *file)
  499. {
  500. return (single_open
  501. (file, hotkey_config_seq_show, PDE(inode)->data));
  502. }
  503. static int hotkey_poll_open_config(struct inode *inode, struct file *file)
  504. {
  505. return (single_open
  506. (file, hotkey_poll_config_seq_show, PDE(inode)->data));
  507. }
  508. static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
  509. {
  510. struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
  511. struct list_head *entries;
  512. char bus_name[ACPI_PATHNAME_MAX] = { 0 };
  513. char action_name[ACPI_PATHNAME_MAX] = { 0 };
  514. struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
  515. struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
  516. list_for_each(entries, hotkey_list->entries) {
  517. union acpi_hotkey *key =
  518. container_of(entries, union acpi_hotkey, entries);
  519. if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
  520. acpi_get_name(key->event_hotkey.bus_handle,
  521. ACPI_NAME_TYPE_MAX, &bus);
  522. acpi_get_name(key->event_hotkey.action_handle,
  523. ACPI_NAME_TYPE_MAX, &act);
  524. seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name,
  525. action_name,
  526. key->event_hotkey.action_method,
  527. key->link.hotkey_standard_num,
  528. key->event_hotkey.external_hotkey_num);
  529. }
  530. }
  531. seq_puts(seq, "\n");
  532. return 0;
  533. }
  534. static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
  535. {
  536. struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
  537. struct list_head *entries;
  538. char bus_name[ACPI_PATHNAME_MAX] = { 0 };
  539. char action_name[ACPI_PATHNAME_MAX] = { 0 };
  540. struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
  541. struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
  542. list_for_each(entries, hotkey_list->entries) {
  543. union acpi_hotkey *key =
  544. container_of(entries, union acpi_hotkey, entries);
  545. if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) {
  546. acpi_get_name(key->poll_hotkey.poll_handle,
  547. ACPI_NAME_TYPE_MAX, &bus);
  548. acpi_get_name(key->poll_hotkey.action_handle,
  549. ACPI_NAME_TYPE_MAX, &act);
  550. seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name,
  551. key->poll_hotkey.poll_method,
  552. action_name,
  553. key->poll_hotkey.action_method,
  554. key->link.hotkey_standard_num);
  555. }
  556. }
  557. seq_puts(seq, "\n");
  558. return 0;
  559. }
  560. static int
  561. get_parms(char *config_record,
  562. int *cmd,
  563. char **bus_handle,
  564. char **bus_method,
  565. char **action_handle,
  566. char **method, int *internal_event_num, int *external_event_num)
  567. {
  568. char *tmp, *tmp1, count;
  569. sscanf(config_record, "%d", cmd);
  570. if (*cmd == 1) {
  571. if (sscanf(config_record, "%d:%d", cmd, internal_event_num) !=
  572. 2)
  573. goto do_fail;
  574. else
  575. return (6);
  576. }
  577. tmp = strchr(config_record, ':');
  578. if (!tmp)
  579. goto do_fail;
  580. tmp++;
  581. tmp1 = strchr(tmp, ':');
  582. if (!tmp1)
  583. goto do_fail;
  584. count = tmp1 - tmp;
  585. *bus_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
  586. if (!*bus_handle)
  587. goto do_fail;
  588. strncpy(*bus_handle, tmp, count);
  589. *(*bus_handle + count) = 0;
  590. tmp = tmp1;
  591. tmp++;
  592. tmp1 = strchr(tmp, ':');
  593. if (!tmp1)
  594. goto do_fail;
  595. count = tmp1 - tmp;
  596. *bus_method = (char *)kmalloc(count + 1, GFP_KERNEL);
  597. if (!*bus_method)
  598. goto do_fail;
  599. strncpy(*bus_method, tmp, count);
  600. *(*bus_method + count) = 0;
  601. tmp = tmp1;
  602. tmp++;
  603. tmp1 = strchr(tmp, ':');
  604. if (!tmp1)
  605. goto do_fail;
  606. count = tmp1 - tmp;
  607. *action_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
  608. if (!*action_handle)
  609. goto do_fail;
  610. strncpy(*action_handle, tmp, count);
  611. *(*action_handle + count) = 0;
  612. tmp = tmp1;
  613. tmp++;
  614. tmp1 = strchr(tmp, ':');
  615. if (!tmp1)
  616. goto do_fail;
  617. count = tmp1 - tmp;
  618. *method = (char *)kmalloc(count + 1, GFP_KERNEL);
  619. if (!*method)
  620. goto do_fail;
  621. strncpy(*method, tmp, count);
  622. *(*method + count) = 0;
  623. if (sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num) <=
  624. 0)
  625. goto do_fail;
  626. return 6;
  627. do_fail:
  628. return -1;
  629. }
  630. /* count is length for one input record */
  631. static ssize_t hotkey_write_config(struct file *file,
  632. const char __user * buffer,
  633. size_t count, loff_t * data)
  634. {
  635. char *config_record = NULL;
  636. char *bus_handle = NULL;
  637. char *bus_method = NULL;
  638. char *action_handle = NULL;
  639. char *method = NULL;
  640. int cmd, internal_event_num, external_event_num;
  641. int ret = 0;
  642. union acpi_hotkey *key = NULL;
  643. config_record = (char *)kmalloc(count + 1, GFP_KERNEL);
  644. if (!config_record)
  645. return -ENOMEM;
  646. if (copy_from_user(config_record, buffer, count)) {
  647. kfree(config_record);
  648. printk(KERN_ERR PREFIX "Invalid data\n");
  649. return -EINVAL;
  650. }
  651. config_record[count] = 0;
  652. ret = get_parms(config_record,
  653. &cmd,
  654. &bus_handle,
  655. &bus_method,
  656. &action_handle,
  657. &method, &internal_event_num, &external_event_num);
  658. kfree(config_record);
  659. if (IS_OTHERS(internal_event_num))
  660. goto do_fail;
  661. if (ret != 6) {
  662. do_fail:
  663. kfree(bus_handle);
  664. kfree(bus_method);
  665. kfree(action_handle);
  666. kfree(method);
  667. printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret);
  668. return -EINVAL;
  669. }
  670. key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
  671. if (!key)
  672. goto do_fail;
  673. memset(key, 0, sizeof(union acpi_hotkey));
  674. if (cmd == 1) {
  675. union acpi_hotkey *tmp = NULL;
  676. tmp = get_hotkey_by_event(&global_hotkey_list,
  677. internal_event_num);
  678. if (!tmp)
  679. printk(KERN_ERR PREFIX "Invalid key\n");
  680. else
  681. memcpy(key, tmp, sizeof(union acpi_hotkey));
  682. goto cont_cmd;
  683. }
  684. if (IS_EVENT(internal_event_num)) {
  685. kfree(bus_method);
  686. ret = init_hotkey_device(key, bus_handle, action_handle, method,
  687. internal_event_num,
  688. external_event_num);
  689. } else
  690. ret = init_poll_hotkey_device(key, bus_handle, bus_method,
  691. action_handle, method,
  692. internal_event_num);
  693. if (ret) {
  694. kfree(bus_handle);
  695. kfree(action_handle);
  696. if (IS_EVENT(internal_event_num))
  697. free_hotkey_buffer(key);
  698. else
  699. free_poll_hotkey_buffer(key);
  700. kfree(key);
  701. printk(KERN_ERR PREFIX "Invalid hotkey\n");
  702. return -EINVAL;
  703. }
  704. cont_cmd:
  705. kfree(bus_handle);
  706. kfree(action_handle);
  707. switch (cmd) {
  708. case 0:
  709. if (get_hotkey_by_event
  710. (&global_hotkey_list, key->link.hotkey_standard_num))
  711. goto fail_out;
  712. else
  713. hotkey_add(key);
  714. break;
  715. case 1:
  716. hotkey_remove(key);
  717. break;
  718. case 2:
  719. if (hotkey_update(key))
  720. goto fail_out;
  721. break;
  722. default:
  723. goto fail_out;
  724. break;
  725. }
  726. return count;
  727. fail_out:
  728. if (IS_EVENT(internal_event_num))
  729. free_hotkey_buffer(key);
  730. else
  731. free_poll_hotkey_buffer(key);
  732. kfree(key);
  733. printk(KERN_ERR PREFIX "invalid key\n");
  734. return -EINVAL;
  735. }
  736. /*
  737. * This function evaluates an ACPI method, given an int as parameter, the
  738. * method is searched within the scope of the handle, can be NULL. The output
  739. * of the method is written is output, which can also be NULL
  740. *
  741. * returns 1 if write is successful, 0 else.
  742. */
  743. static int write_acpi_int(acpi_handle handle, const char *method, int val,
  744. struct acpi_buffer *output)
  745. {
  746. struct acpi_object_list params; /* list of input parameters (an int here) */
  747. union acpi_object in_obj; /* the only param we use */
  748. acpi_status status;
  749. params.count = 1;
  750. params.pointer = &in_obj;
  751. in_obj.type = ACPI_TYPE_INTEGER;
  752. in_obj.integer.value = val;
  753. status = acpi_evaluate_object(handle, (char *)method, &params, output);
  754. return (status == AE_OK);
  755. }
  756. static int read_acpi_int(acpi_handle handle, const char *method,
  757. union acpi_object *val)
  758. {
  759. struct acpi_buffer output;
  760. union acpi_object out_obj;
  761. acpi_status status;
  762. output.length = sizeof(out_obj);
  763. output.pointer = &out_obj;
  764. status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
  765. if (val) {
  766. val->integer.value = out_obj.integer.value;
  767. val->type = out_obj.type;
  768. } else
  769. printk(KERN_ERR PREFIX "null val pointer\n");
  770. return ((status == AE_OK)
  771. && (out_obj.type == ACPI_TYPE_INTEGER));
  772. }
  773. static union acpi_hotkey *get_hotkey_by_event(struct
  774. acpi_hotkey_list
  775. *hotkey_list, int event)
  776. {
  777. struct list_head *entries;
  778. list_for_each(entries, hotkey_list->entries) {
  779. union acpi_hotkey *key =
  780. container_of(entries, union acpi_hotkey, entries);
  781. if (key->link.hotkey_standard_num == event) {
  782. return (key);
  783. }
  784. }
  785. return (NULL);
  786. }
  787. /*
  788. * user call AML method interface:
  789. * Call convention:
  790. * echo "event_num: arg type : value"
  791. * example: echo "1:1:30" > /proc/acpi/action
  792. * Just support 1 integer arg passing to AML method
  793. */
  794. static ssize_t hotkey_execute_aml_method(struct file *file,
  795. const char __user * buffer,
  796. size_t count, loff_t * data)
  797. {
  798. struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
  799. char *arg;
  800. int event, method_type, type, value;
  801. union acpi_hotkey *key;
  802. arg = (char *)kmalloc(count + 1, GFP_KERNEL);
  803. if (!arg)
  804. return -ENOMEM;
  805. arg[count] = 0;
  806. if (copy_from_user(arg, buffer, count)) {
  807. kfree(arg);
  808. printk(KERN_ERR PREFIX "Invalid argument 2\n");
  809. return -EINVAL;
  810. }
  811. if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) !=
  812. 4) {
  813. kfree(arg);
  814. printk(KERN_ERR PREFIX "Invalid argument 3\n");
  815. return -EINVAL;
  816. }
  817. kfree(arg);
  818. if (type == ACPI_TYPE_INTEGER) {
  819. key = get_hotkey_by_event(hotkey_list, event);
  820. if (!key)
  821. goto do_fail;
  822. if (IS_EVENT(event))
  823. write_acpi_int(key->event_hotkey.action_handle,
  824. key->event_hotkey.action_method, value,
  825. NULL);
  826. else if (IS_POLL(event)) {
  827. if (method_type == POLL_METHOD)
  828. read_acpi_int(key->poll_hotkey.poll_handle,
  829. key->poll_hotkey.poll_method,
  830. key->poll_hotkey.poll_result);
  831. else if (method_type == ACTION_METHOD)
  832. write_acpi_int(key->poll_hotkey.action_handle,
  833. key->poll_hotkey.action_method,
  834. value, NULL);
  835. else
  836. goto do_fail;
  837. }
  838. } else {
  839. printk(KERN_WARNING "Not supported\n");
  840. return -EINVAL;
  841. }
  842. return count;
  843. do_fail:
  844. return -EINVAL;
  845. }
  846. static int __init hotkey_init(void)
  847. {
  848. int result;
  849. mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
  850. if (acpi_disabled)
  851. return -ENODEV;
  852. if (acpi_specific_hotkey_enabled) {
  853. printk("Using specific hotkey driver\n");
  854. return -ENODEV;
  855. }
  856. hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
  857. if (!hotkey_proc_dir) {
  858. return (-ENODEV);
  859. }
  860. hotkey_proc_dir->owner = THIS_MODULE;
  861. hotkey_config =
  862. create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
  863. if (!hotkey_config) {
  864. goto do_fail1;
  865. } else {
  866. hotkey_config->proc_fops = &hotkey_config_fops;
  867. hotkey_config->data = &global_hotkey_list;
  868. hotkey_config->owner = THIS_MODULE;
  869. hotkey_config->uid = 0;
  870. hotkey_config->gid = 0;
  871. }
  872. hotkey_poll_config =
  873. create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
  874. if (!hotkey_poll_config) {
  875. goto do_fail2;
  876. } else {
  877. hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
  878. hotkey_poll_config->data = &global_hotkey_list;
  879. hotkey_poll_config->owner = THIS_MODULE;
  880. hotkey_poll_config->uid = 0;
  881. hotkey_poll_config->gid = 0;
  882. }
  883. hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
  884. if (!hotkey_action) {
  885. goto do_fail3;
  886. } else {
  887. hotkey_action->proc_fops = &hotkey_action_fops;
  888. hotkey_action->owner = THIS_MODULE;
  889. hotkey_action->uid = 0;
  890. hotkey_action->gid = 0;
  891. }
  892. hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
  893. if (!hotkey_info) {
  894. goto do_fail4;
  895. } else {
  896. hotkey_info->proc_fops = &hotkey_info_fops;
  897. hotkey_info->owner = THIS_MODULE;
  898. hotkey_info->uid = 0;
  899. hotkey_info->gid = 0;
  900. }
  901. result = acpi_bus_register_driver(&hotkey_driver);
  902. if (result < 0)
  903. goto do_fail5;
  904. global_hotkey_list.count = 0;
  905. global_hotkey_list.entries = &hotkey_entries;
  906. INIT_LIST_HEAD(&hotkey_entries);
  907. return (0);
  908. do_fail5:
  909. remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
  910. do_fail4:
  911. remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
  912. do_fail3:
  913. remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
  914. do_fail2:
  915. remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
  916. do_fail1:
  917. remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
  918. return (-ENODEV);
  919. }
  920. static void __exit hotkey_exit(void)
  921. {
  922. struct list_head *entries, *next;
  923. list_for_each_safe(entries, next, global_hotkey_list.entries) {
  924. union acpi_hotkey *key =
  925. container_of(entries, union acpi_hotkey, entries);
  926. acpi_os_wait_events_complete(NULL);
  927. list_del(&key->link.entries);
  928. global_hotkey_list.count--;
  929. free_hotkey_device(key);
  930. }
  931. acpi_bus_unregister_driver(&hotkey_driver);
  932. remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
  933. remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
  934. remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
  935. remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
  936. remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
  937. return;
  938. }
  939. module_init(hotkey_init);
  940. module_exit(hotkey_exit);