hotkey.c 27 KB

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