hotkey.c 28 KB

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