classmate-laptop.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  1. /*
  2. * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include <linux/init.h>
  19. #include <linux/module.h>
  20. #include <linux/slab.h>
  21. #include <linux/workqueue.h>
  22. #include <linux/acpi.h>
  23. #include <linux/backlight.h>
  24. #include <linux/input.h>
  25. #include <linux/rfkill.h>
  26. MODULE_LICENSE("GPL");
  27. struct cmpc_accel {
  28. int sensitivity;
  29. int g_select;
  30. int inputdev_state;
  31. };
  32. #define CMPC_ACCEL_DEV_STATE_CLOSED 0
  33. #define CMPC_ACCEL_DEV_STATE_OPEN 1
  34. #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
  35. #define CMPC_ACCEL_G_SELECT_DEFAULT 0
  36. #define CMPC_ACCEL_HID "ACCE0000"
  37. #define CMPC_ACCEL_HID_V4 "ACCE0001"
  38. #define CMPC_TABLET_HID "TBLT0000"
  39. #define CMPC_IPML_HID "IPML200"
  40. #define CMPC_KEYS_HID "FNBT0000"
  41. /*
  42. * Generic input device code.
  43. */
  44. typedef void (*input_device_init)(struct input_dev *dev);
  45. static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
  46. input_device_init idev_init)
  47. {
  48. struct input_dev *inputdev;
  49. int error;
  50. inputdev = input_allocate_device();
  51. if (!inputdev)
  52. return -ENOMEM;
  53. inputdev->name = name;
  54. inputdev->dev.parent = &acpi->dev;
  55. idev_init(inputdev);
  56. error = input_register_device(inputdev);
  57. if (error) {
  58. input_free_device(inputdev);
  59. return error;
  60. }
  61. dev_set_drvdata(&acpi->dev, inputdev);
  62. return 0;
  63. }
  64. static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
  65. {
  66. struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
  67. input_unregister_device(inputdev);
  68. return 0;
  69. }
  70. /*
  71. * Accelerometer code for Classmate V4
  72. */
  73. static acpi_status cmpc_start_accel_v4(acpi_handle handle)
  74. {
  75. union acpi_object param[4];
  76. struct acpi_object_list input;
  77. acpi_status status;
  78. param[0].type = ACPI_TYPE_INTEGER;
  79. param[0].integer.value = 0x3;
  80. param[1].type = ACPI_TYPE_INTEGER;
  81. param[1].integer.value = 0;
  82. param[2].type = ACPI_TYPE_INTEGER;
  83. param[2].integer.value = 0;
  84. param[3].type = ACPI_TYPE_INTEGER;
  85. param[3].integer.value = 0;
  86. input.count = 4;
  87. input.pointer = param;
  88. status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
  89. return status;
  90. }
  91. static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
  92. {
  93. union acpi_object param[4];
  94. struct acpi_object_list input;
  95. acpi_status status;
  96. param[0].type = ACPI_TYPE_INTEGER;
  97. param[0].integer.value = 0x4;
  98. param[1].type = ACPI_TYPE_INTEGER;
  99. param[1].integer.value = 0;
  100. param[2].type = ACPI_TYPE_INTEGER;
  101. param[2].integer.value = 0;
  102. param[3].type = ACPI_TYPE_INTEGER;
  103. param[3].integer.value = 0;
  104. input.count = 4;
  105. input.pointer = param;
  106. status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
  107. return status;
  108. }
  109. static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
  110. {
  111. union acpi_object param[4];
  112. struct acpi_object_list input;
  113. param[0].type = ACPI_TYPE_INTEGER;
  114. param[0].integer.value = 0x02;
  115. param[1].type = ACPI_TYPE_INTEGER;
  116. param[1].integer.value = val;
  117. param[2].type = ACPI_TYPE_INTEGER;
  118. param[2].integer.value = 0;
  119. param[3].type = ACPI_TYPE_INTEGER;
  120. param[3].integer.value = 0;
  121. input.count = 4;
  122. input.pointer = param;
  123. return acpi_evaluate_object(handle, "ACMD", &input, NULL);
  124. }
  125. static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
  126. {
  127. union acpi_object param[4];
  128. struct acpi_object_list input;
  129. param[0].type = ACPI_TYPE_INTEGER;
  130. param[0].integer.value = 0x05;
  131. param[1].type = ACPI_TYPE_INTEGER;
  132. param[1].integer.value = val;
  133. param[2].type = ACPI_TYPE_INTEGER;
  134. param[2].integer.value = 0;
  135. param[3].type = ACPI_TYPE_INTEGER;
  136. param[3].integer.value = 0;
  137. input.count = 4;
  138. input.pointer = param;
  139. return acpi_evaluate_object(handle, "ACMD", &input, NULL);
  140. }
  141. static acpi_status cmpc_get_accel_v4(acpi_handle handle,
  142. int16_t *x,
  143. int16_t *y,
  144. int16_t *z)
  145. {
  146. union acpi_object param[4];
  147. struct acpi_object_list input;
  148. struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
  149. int16_t *locs;
  150. acpi_status status;
  151. param[0].type = ACPI_TYPE_INTEGER;
  152. param[0].integer.value = 0x01;
  153. param[1].type = ACPI_TYPE_INTEGER;
  154. param[1].integer.value = 0;
  155. param[2].type = ACPI_TYPE_INTEGER;
  156. param[2].integer.value = 0;
  157. param[3].type = ACPI_TYPE_INTEGER;
  158. param[3].integer.value = 0;
  159. input.count = 4;
  160. input.pointer = param;
  161. status = acpi_evaluate_object(handle, "ACMD", &input, &output);
  162. if (ACPI_SUCCESS(status)) {
  163. union acpi_object *obj;
  164. obj = output.pointer;
  165. locs = (int16_t *) obj->buffer.pointer;
  166. *x = locs[0];
  167. *y = locs[1];
  168. *z = locs[2];
  169. kfree(output.pointer);
  170. }
  171. return status;
  172. }
  173. static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
  174. {
  175. if (event == 0x81) {
  176. int16_t x, y, z;
  177. acpi_status status;
  178. status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
  179. if (ACPI_SUCCESS(status)) {
  180. struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
  181. input_report_abs(inputdev, ABS_X, x);
  182. input_report_abs(inputdev, ABS_Y, y);
  183. input_report_abs(inputdev, ABS_Z, z);
  184. input_sync(inputdev);
  185. }
  186. }
  187. }
  188. static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
  189. struct device_attribute *attr,
  190. char *buf)
  191. {
  192. struct acpi_device *acpi;
  193. struct input_dev *inputdev;
  194. struct cmpc_accel *accel;
  195. acpi = to_acpi_device(dev);
  196. inputdev = dev_get_drvdata(&acpi->dev);
  197. accel = dev_get_drvdata(&inputdev->dev);
  198. return sprintf(buf, "%d\n", accel->sensitivity);
  199. }
  200. static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
  201. struct device_attribute *attr,
  202. const char *buf, size_t count)
  203. {
  204. struct acpi_device *acpi;
  205. struct input_dev *inputdev;
  206. struct cmpc_accel *accel;
  207. unsigned long sensitivity;
  208. int r;
  209. acpi = to_acpi_device(dev);
  210. inputdev = dev_get_drvdata(&acpi->dev);
  211. accel = dev_get_drvdata(&inputdev->dev);
  212. r = kstrtoul(buf, 0, &sensitivity);
  213. if (r)
  214. return r;
  215. /* sensitivity must be between 1 and 127 */
  216. if (sensitivity < 1 || sensitivity > 127)
  217. return -EINVAL;
  218. accel->sensitivity = sensitivity;
  219. cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
  220. return strnlen(buf, count);
  221. }
  222. static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
  223. .attr = { .name = "sensitivity", .mode = 0660 },
  224. .show = cmpc_accel_sensitivity_show_v4,
  225. .store = cmpc_accel_sensitivity_store_v4
  226. };
  227. static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
  228. struct device_attribute *attr,
  229. char *buf)
  230. {
  231. struct acpi_device *acpi;
  232. struct input_dev *inputdev;
  233. struct cmpc_accel *accel;
  234. acpi = to_acpi_device(dev);
  235. inputdev = dev_get_drvdata(&acpi->dev);
  236. accel = dev_get_drvdata(&inputdev->dev);
  237. return sprintf(buf, "%d\n", accel->g_select);
  238. }
  239. static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
  240. struct device_attribute *attr,
  241. const char *buf, size_t count)
  242. {
  243. struct acpi_device *acpi;
  244. struct input_dev *inputdev;
  245. struct cmpc_accel *accel;
  246. unsigned long g_select;
  247. int r;
  248. acpi = to_acpi_device(dev);
  249. inputdev = dev_get_drvdata(&acpi->dev);
  250. accel = dev_get_drvdata(&inputdev->dev);
  251. r = kstrtoul(buf, 0, &g_select);
  252. if (r)
  253. return r;
  254. /* 0 means 1.5g, 1 means 6g, everything else is wrong */
  255. if (g_select != 0 && g_select != 1)
  256. return -EINVAL;
  257. accel->g_select = g_select;
  258. cmpc_accel_set_g_select_v4(acpi->handle, g_select);
  259. return strnlen(buf, count);
  260. }
  261. static struct device_attribute cmpc_accel_g_select_attr_v4 = {
  262. .attr = { .name = "g_select", .mode = 0660 },
  263. .show = cmpc_accel_g_select_show_v4,
  264. .store = cmpc_accel_g_select_store_v4
  265. };
  266. static int cmpc_accel_open_v4(struct input_dev *input)
  267. {
  268. struct acpi_device *acpi;
  269. struct cmpc_accel *accel;
  270. acpi = to_acpi_device(input->dev.parent);
  271. accel = dev_get_drvdata(&input->dev);
  272. cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
  273. cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
  274. if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
  275. accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
  276. return 0;
  277. }
  278. return -EIO;
  279. }
  280. static void cmpc_accel_close_v4(struct input_dev *input)
  281. {
  282. struct acpi_device *acpi;
  283. struct cmpc_accel *accel;
  284. acpi = to_acpi_device(input->dev.parent);
  285. accel = dev_get_drvdata(&input->dev);
  286. cmpc_stop_accel_v4(acpi->handle);
  287. accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
  288. }
  289. static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
  290. {
  291. set_bit(EV_ABS, inputdev->evbit);
  292. input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
  293. input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
  294. input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
  295. inputdev->open = cmpc_accel_open_v4;
  296. inputdev->close = cmpc_accel_close_v4;
  297. }
  298. #ifdef CONFIG_PM_SLEEP
  299. static int cmpc_accel_suspend_v4(struct device *dev)
  300. {
  301. struct input_dev *inputdev;
  302. struct cmpc_accel *accel;
  303. inputdev = dev_get_drvdata(dev);
  304. accel = dev_get_drvdata(&inputdev->dev);
  305. if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
  306. return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
  307. return 0;
  308. }
  309. static int cmpc_accel_resume_v4(struct device *dev)
  310. {
  311. struct input_dev *inputdev;
  312. struct cmpc_accel *accel;
  313. inputdev = dev_get_drvdata(dev);
  314. accel = dev_get_drvdata(&inputdev->dev);
  315. if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
  316. cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
  317. accel->sensitivity);
  318. cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
  319. accel->g_select);
  320. if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
  321. return -EIO;
  322. }
  323. return 0;
  324. }
  325. #endif
  326. static int cmpc_accel_add_v4(struct acpi_device *acpi)
  327. {
  328. int error;
  329. struct input_dev *inputdev;
  330. struct cmpc_accel *accel;
  331. accel = kmalloc(sizeof(*accel), GFP_KERNEL);
  332. if (!accel)
  333. return -ENOMEM;
  334. accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
  335. accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
  336. cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
  337. error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
  338. if (error)
  339. goto failed_sensitivity;
  340. accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
  341. cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
  342. error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
  343. if (error)
  344. goto failed_g_select;
  345. error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
  346. cmpc_accel_idev_init_v4);
  347. if (error)
  348. goto failed_input;
  349. inputdev = dev_get_drvdata(&acpi->dev);
  350. dev_set_drvdata(&inputdev->dev, accel);
  351. return 0;
  352. failed_input:
  353. device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
  354. failed_g_select:
  355. device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
  356. failed_sensitivity:
  357. kfree(accel);
  358. return error;
  359. }
  360. static int cmpc_accel_remove_v4(struct acpi_device *acpi)
  361. {
  362. struct input_dev *inputdev;
  363. struct cmpc_accel *accel;
  364. inputdev = dev_get_drvdata(&acpi->dev);
  365. accel = dev_get_drvdata(&inputdev->dev);
  366. device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
  367. device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
  368. return cmpc_remove_acpi_notify_device(acpi);
  369. }
  370. static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
  371. cmpc_accel_resume_v4);
  372. static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
  373. {CMPC_ACCEL_HID_V4, 0},
  374. {"", 0}
  375. };
  376. static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
  377. .owner = THIS_MODULE,
  378. .name = "cmpc_accel_v4",
  379. .class = "cmpc_accel_v4",
  380. .ids = cmpc_accel_device_ids_v4,
  381. .ops = {
  382. .add = cmpc_accel_add_v4,
  383. .remove = cmpc_accel_remove_v4,
  384. .notify = cmpc_accel_handler_v4,
  385. },
  386. .drv.pm = &cmpc_accel_pm,
  387. };
  388. /*
  389. * Accelerometer code for Classmate versions prior to V4
  390. */
  391. static acpi_status cmpc_start_accel(acpi_handle handle)
  392. {
  393. union acpi_object param[2];
  394. struct acpi_object_list input;
  395. acpi_status status;
  396. param[0].type = ACPI_TYPE_INTEGER;
  397. param[0].integer.value = 0x3;
  398. param[1].type = ACPI_TYPE_INTEGER;
  399. input.count = 2;
  400. input.pointer = param;
  401. status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
  402. return status;
  403. }
  404. static acpi_status cmpc_stop_accel(acpi_handle handle)
  405. {
  406. union acpi_object param[2];
  407. struct acpi_object_list input;
  408. acpi_status status;
  409. param[0].type = ACPI_TYPE_INTEGER;
  410. param[0].integer.value = 0x4;
  411. param[1].type = ACPI_TYPE_INTEGER;
  412. input.count = 2;
  413. input.pointer = param;
  414. status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
  415. return status;
  416. }
  417. static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
  418. {
  419. union acpi_object param[2];
  420. struct acpi_object_list input;
  421. param[0].type = ACPI_TYPE_INTEGER;
  422. param[0].integer.value = 0x02;
  423. param[1].type = ACPI_TYPE_INTEGER;
  424. param[1].integer.value = val;
  425. input.count = 2;
  426. input.pointer = param;
  427. return acpi_evaluate_object(handle, "ACMD", &input, NULL);
  428. }
  429. static acpi_status cmpc_get_accel(acpi_handle handle,
  430. unsigned char *x,
  431. unsigned char *y,
  432. unsigned char *z)
  433. {
  434. union acpi_object param[2];
  435. struct acpi_object_list input;
  436. struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
  437. unsigned char *locs;
  438. acpi_status status;
  439. param[0].type = ACPI_TYPE_INTEGER;
  440. param[0].integer.value = 0x01;
  441. param[1].type = ACPI_TYPE_INTEGER;
  442. input.count = 2;
  443. input.pointer = param;
  444. status = acpi_evaluate_object(handle, "ACMD", &input, &output);
  445. if (ACPI_SUCCESS(status)) {
  446. union acpi_object *obj;
  447. obj = output.pointer;
  448. locs = obj->buffer.pointer;
  449. *x = locs[0];
  450. *y = locs[1];
  451. *z = locs[2];
  452. kfree(output.pointer);
  453. }
  454. return status;
  455. }
  456. static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
  457. {
  458. if (event == 0x81) {
  459. unsigned char x, y, z;
  460. acpi_status status;
  461. status = cmpc_get_accel(dev->handle, &x, &y, &z);
  462. if (ACPI_SUCCESS(status)) {
  463. struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
  464. input_report_abs(inputdev, ABS_X, x);
  465. input_report_abs(inputdev, ABS_Y, y);
  466. input_report_abs(inputdev, ABS_Z, z);
  467. input_sync(inputdev);
  468. }
  469. }
  470. }
  471. static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
  472. struct device_attribute *attr,
  473. char *buf)
  474. {
  475. struct acpi_device *acpi;
  476. struct input_dev *inputdev;
  477. struct cmpc_accel *accel;
  478. acpi = to_acpi_device(dev);
  479. inputdev = dev_get_drvdata(&acpi->dev);
  480. accel = dev_get_drvdata(&inputdev->dev);
  481. return sprintf(buf, "%d\n", accel->sensitivity);
  482. }
  483. static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
  484. struct device_attribute *attr,
  485. const char *buf, size_t count)
  486. {
  487. struct acpi_device *acpi;
  488. struct input_dev *inputdev;
  489. struct cmpc_accel *accel;
  490. unsigned long sensitivity;
  491. int r;
  492. acpi = to_acpi_device(dev);
  493. inputdev = dev_get_drvdata(&acpi->dev);
  494. accel = dev_get_drvdata(&inputdev->dev);
  495. r = kstrtoul(buf, 0, &sensitivity);
  496. if (r)
  497. return r;
  498. accel->sensitivity = sensitivity;
  499. cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
  500. return strnlen(buf, count);
  501. }
  502. static struct device_attribute cmpc_accel_sensitivity_attr = {
  503. .attr = { .name = "sensitivity", .mode = 0660 },
  504. .show = cmpc_accel_sensitivity_show,
  505. .store = cmpc_accel_sensitivity_store
  506. };
  507. static int cmpc_accel_open(struct input_dev *input)
  508. {
  509. struct acpi_device *acpi;
  510. acpi = to_acpi_device(input->dev.parent);
  511. if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
  512. return 0;
  513. return -EIO;
  514. }
  515. static void cmpc_accel_close(struct input_dev *input)
  516. {
  517. struct acpi_device *acpi;
  518. acpi = to_acpi_device(input->dev.parent);
  519. cmpc_stop_accel(acpi->handle);
  520. }
  521. static void cmpc_accel_idev_init(struct input_dev *inputdev)
  522. {
  523. set_bit(EV_ABS, inputdev->evbit);
  524. input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
  525. input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
  526. input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
  527. inputdev->open = cmpc_accel_open;
  528. inputdev->close = cmpc_accel_close;
  529. }
  530. static int cmpc_accel_add(struct acpi_device *acpi)
  531. {
  532. int error;
  533. struct input_dev *inputdev;
  534. struct cmpc_accel *accel;
  535. accel = kmalloc(sizeof(*accel), GFP_KERNEL);
  536. if (!accel)
  537. return -ENOMEM;
  538. accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
  539. cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
  540. error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
  541. if (error)
  542. goto failed_file;
  543. error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
  544. cmpc_accel_idev_init);
  545. if (error)
  546. goto failed_input;
  547. inputdev = dev_get_drvdata(&acpi->dev);
  548. dev_set_drvdata(&inputdev->dev, accel);
  549. return 0;
  550. failed_input:
  551. device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
  552. failed_file:
  553. kfree(accel);
  554. return error;
  555. }
  556. static int cmpc_accel_remove(struct acpi_device *acpi)
  557. {
  558. struct input_dev *inputdev;
  559. struct cmpc_accel *accel;
  560. inputdev = dev_get_drvdata(&acpi->dev);
  561. accel = dev_get_drvdata(&inputdev->dev);
  562. device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
  563. return cmpc_remove_acpi_notify_device(acpi);
  564. }
  565. static const struct acpi_device_id cmpc_accel_device_ids[] = {
  566. {CMPC_ACCEL_HID, 0},
  567. {"", 0}
  568. };
  569. static struct acpi_driver cmpc_accel_acpi_driver = {
  570. .owner = THIS_MODULE,
  571. .name = "cmpc_accel",
  572. .class = "cmpc_accel",
  573. .ids = cmpc_accel_device_ids,
  574. .ops = {
  575. .add = cmpc_accel_add,
  576. .remove = cmpc_accel_remove,
  577. .notify = cmpc_accel_handler,
  578. }
  579. };
  580. /*
  581. * Tablet mode code.
  582. */
  583. static acpi_status cmpc_get_tablet(acpi_handle handle,
  584. unsigned long long *value)
  585. {
  586. union acpi_object param;
  587. struct acpi_object_list input;
  588. unsigned long long output;
  589. acpi_status status;
  590. param.type = ACPI_TYPE_INTEGER;
  591. param.integer.value = 0x01;
  592. input.count = 1;
  593. input.pointer = &param;
  594. status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
  595. if (ACPI_SUCCESS(status))
  596. *value = output;
  597. return status;
  598. }
  599. static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
  600. {
  601. unsigned long long val = 0;
  602. struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
  603. if (event == 0x81) {
  604. if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
  605. input_report_switch(inputdev, SW_TABLET_MODE, !val);
  606. input_sync(inputdev);
  607. }
  608. }
  609. }
  610. static void cmpc_tablet_idev_init(struct input_dev *inputdev)
  611. {
  612. unsigned long long val = 0;
  613. struct acpi_device *acpi;
  614. set_bit(EV_SW, inputdev->evbit);
  615. set_bit(SW_TABLET_MODE, inputdev->swbit);
  616. acpi = to_acpi_device(inputdev->dev.parent);
  617. if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
  618. input_report_switch(inputdev, SW_TABLET_MODE, !val);
  619. input_sync(inputdev);
  620. }
  621. }
  622. static int cmpc_tablet_add(struct acpi_device *acpi)
  623. {
  624. return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
  625. cmpc_tablet_idev_init);
  626. }
  627. static int cmpc_tablet_remove(struct acpi_device *acpi)
  628. {
  629. return cmpc_remove_acpi_notify_device(acpi);
  630. }
  631. #ifdef CONFIG_PM_SLEEP
  632. static int cmpc_tablet_resume(struct device *dev)
  633. {
  634. struct input_dev *inputdev = dev_get_drvdata(dev);
  635. unsigned long long val = 0;
  636. if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
  637. input_report_switch(inputdev, SW_TABLET_MODE, !val);
  638. input_sync(inputdev);
  639. }
  640. return 0;
  641. }
  642. #endif
  643. static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
  644. static const struct acpi_device_id cmpc_tablet_device_ids[] = {
  645. {CMPC_TABLET_HID, 0},
  646. {"", 0}
  647. };
  648. static struct acpi_driver cmpc_tablet_acpi_driver = {
  649. .owner = THIS_MODULE,
  650. .name = "cmpc_tablet",
  651. .class = "cmpc_tablet",
  652. .ids = cmpc_tablet_device_ids,
  653. .ops = {
  654. .add = cmpc_tablet_add,
  655. .remove = cmpc_tablet_remove,
  656. .notify = cmpc_tablet_handler,
  657. },
  658. .drv.pm = &cmpc_tablet_pm,
  659. };
  660. /*
  661. * Backlight code.
  662. */
  663. static acpi_status cmpc_get_brightness(acpi_handle handle,
  664. unsigned long long *value)
  665. {
  666. union acpi_object param;
  667. struct acpi_object_list input;
  668. unsigned long long output;
  669. acpi_status status;
  670. param.type = ACPI_TYPE_INTEGER;
  671. param.integer.value = 0xC0;
  672. input.count = 1;
  673. input.pointer = &param;
  674. status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
  675. if (ACPI_SUCCESS(status))
  676. *value = output;
  677. return status;
  678. }
  679. static acpi_status cmpc_set_brightness(acpi_handle handle,
  680. unsigned long long value)
  681. {
  682. union acpi_object param[2];
  683. struct acpi_object_list input;
  684. acpi_status status;
  685. unsigned long long output;
  686. param[0].type = ACPI_TYPE_INTEGER;
  687. param[0].integer.value = 0xC0;
  688. param[1].type = ACPI_TYPE_INTEGER;
  689. param[1].integer.value = value;
  690. input.count = 2;
  691. input.pointer = param;
  692. status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
  693. return status;
  694. }
  695. static int cmpc_bl_get_brightness(struct backlight_device *bd)
  696. {
  697. acpi_status status;
  698. acpi_handle handle;
  699. unsigned long long brightness;
  700. handle = bl_get_data(bd);
  701. status = cmpc_get_brightness(handle, &brightness);
  702. if (ACPI_SUCCESS(status))
  703. return brightness;
  704. else
  705. return -1;
  706. }
  707. static int cmpc_bl_update_status(struct backlight_device *bd)
  708. {
  709. acpi_status status;
  710. acpi_handle handle;
  711. handle = bl_get_data(bd);
  712. status = cmpc_set_brightness(handle, bd->props.brightness);
  713. if (ACPI_SUCCESS(status))
  714. return 0;
  715. else
  716. return -1;
  717. }
  718. static const struct backlight_ops cmpc_bl_ops = {
  719. .get_brightness = cmpc_bl_get_brightness,
  720. .update_status = cmpc_bl_update_status
  721. };
  722. /*
  723. * RFKILL code.
  724. */
  725. static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
  726. unsigned long long *value)
  727. {
  728. union acpi_object param;
  729. struct acpi_object_list input;
  730. unsigned long long output;
  731. acpi_status status;
  732. param.type = ACPI_TYPE_INTEGER;
  733. param.integer.value = 0xC1;
  734. input.count = 1;
  735. input.pointer = &param;
  736. status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
  737. if (ACPI_SUCCESS(status))
  738. *value = output;
  739. return status;
  740. }
  741. static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
  742. unsigned long long value)
  743. {
  744. union acpi_object param[2];
  745. struct acpi_object_list input;
  746. acpi_status status;
  747. unsigned long long output;
  748. param[0].type = ACPI_TYPE_INTEGER;
  749. param[0].integer.value = 0xC1;
  750. param[1].type = ACPI_TYPE_INTEGER;
  751. param[1].integer.value = value;
  752. input.count = 2;
  753. input.pointer = param;
  754. status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
  755. return status;
  756. }
  757. static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
  758. {
  759. acpi_status status;
  760. acpi_handle handle;
  761. unsigned long long state;
  762. bool blocked;
  763. handle = data;
  764. status = cmpc_get_rfkill_wlan(handle, &state);
  765. if (ACPI_SUCCESS(status)) {
  766. blocked = state & 1 ? false : true;
  767. rfkill_set_sw_state(rfkill, blocked);
  768. }
  769. }
  770. static int cmpc_rfkill_block(void *data, bool blocked)
  771. {
  772. acpi_status status;
  773. acpi_handle handle;
  774. unsigned long long state;
  775. bool is_blocked;
  776. handle = data;
  777. status = cmpc_get_rfkill_wlan(handle, &state);
  778. if (ACPI_FAILURE(status))
  779. return -ENODEV;
  780. /* Check if we really need to call cmpc_set_rfkill_wlan */
  781. is_blocked = state & 1 ? false : true;
  782. if (is_blocked != blocked) {
  783. state = blocked ? 0 : 1;
  784. status = cmpc_set_rfkill_wlan(handle, state);
  785. if (ACPI_FAILURE(status))
  786. return -ENODEV;
  787. }
  788. return 0;
  789. }
  790. static const struct rfkill_ops cmpc_rfkill_ops = {
  791. .query = cmpc_rfkill_query,
  792. .set_block = cmpc_rfkill_block,
  793. };
  794. /*
  795. * Common backlight and rfkill code.
  796. */
  797. struct ipml200_dev {
  798. struct backlight_device *bd;
  799. struct rfkill *rf;
  800. };
  801. static int cmpc_ipml_add(struct acpi_device *acpi)
  802. {
  803. int retval;
  804. struct ipml200_dev *ipml;
  805. struct backlight_properties props;
  806. ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
  807. if (ipml == NULL)
  808. return -ENOMEM;
  809. memset(&props, 0, sizeof(struct backlight_properties));
  810. props.type = BACKLIGHT_PLATFORM;
  811. props.max_brightness = 7;
  812. ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
  813. acpi->handle, &cmpc_bl_ops,
  814. &props);
  815. if (IS_ERR(ipml->bd)) {
  816. retval = PTR_ERR(ipml->bd);
  817. goto out_bd;
  818. }
  819. ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
  820. &cmpc_rfkill_ops, acpi->handle);
  821. /*
  822. * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
  823. * This is OK, however, since all other uses of the device will not
  824. * derefence it.
  825. */
  826. if (ipml->rf) {
  827. retval = rfkill_register(ipml->rf);
  828. if (retval) {
  829. rfkill_destroy(ipml->rf);
  830. ipml->rf = NULL;
  831. }
  832. }
  833. dev_set_drvdata(&acpi->dev, ipml);
  834. return 0;
  835. out_bd:
  836. kfree(ipml);
  837. return retval;
  838. }
  839. static int cmpc_ipml_remove(struct acpi_device *acpi)
  840. {
  841. struct ipml200_dev *ipml;
  842. ipml = dev_get_drvdata(&acpi->dev);
  843. backlight_device_unregister(ipml->bd);
  844. if (ipml->rf) {
  845. rfkill_unregister(ipml->rf);
  846. rfkill_destroy(ipml->rf);
  847. }
  848. kfree(ipml);
  849. return 0;
  850. }
  851. static const struct acpi_device_id cmpc_ipml_device_ids[] = {
  852. {CMPC_IPML_HID, 0},
  853. {"", 0}
  854. };
  855. static struct acpi_driver cmpc_ipml_acpi_driver = {
  856. .owner = THIS_MODULE,
  857. .name = "cmpc",
  858. .class = "cmpc",
  859. .ids = cmpc_ipml_device_ids,
  860. .ops = {
  861. .add = cmpc_ipml_add,
  862. .remove = cmpc_ipml_remove
  863. }
  864. };
  865. /*
  866. * Extra keys code.
  867. */
  868. static int cmpc_keys_codes[] = {
  869. KEY_UNKNOWN,
  870. KEY_WLAN,
  871. KEY_SWITCHVIDEOMODE,
  872. KEY_BRIGHTNESSDOWN,
  873. KEY_BRIGHTNESSUP,
  874. KEY_VENDOR,
  875. KEY_UNKNOWN,
  876. KEY_CAMERA,
  877. KEY_BACK,
  878. KEY_FORWARD,
  879. KEY_MAX
  880. };
  881. static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
  882. {
  883. struct input_dev *inputdev;
  884. int code = KEY_MAX;
  885. if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
  886. code = cmpc_keys_codes[event & 0x0F];
  887. inputdev = dev_get_drvdata(&dev->dev);
  888. input_report_key(inputdev, code, !(event & 0x10));
  889. input_sync(inputdev);
  890. }
  891. static void cmpc_keys_idev_init(struct input_dev *inputdev)
  892. {
  893. int i;
  894. set_bit(EV_KEY, inputdev->evbit);
  895. for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
  896. set_bit(cmpc_keys_codes[i], inputdev->keybit);
  897. }
  898. static int cmpc_keys_add(struct acpi_device *acpi)
  899. {
  900. return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
  901. cmpc_keys_idev_init);
  902. }
  903. static int cmpc_keys_remove(struct acpi_device *acpi)
  904. {
  905. return cmpc_remove_acpi_notify_device(acpi);
  906. }
  907. static const struct acpi_device_id cmpc_keys_device_ids[] = {
  908. {CMPC_KEYS_HID, 0},
  909. {"", 0}
  910. };
  911. static struct acpi_driver cmpc_keys_acpi_driver = {
  912. .owner = THIS_MODULE,
  913. .name = "cmpc_keys",
  914. .class = "cmpc_keys",
  915. .ids = cmpc_keys_device_ids,
  916. .ops = {
  917. .add = cmpc_keys_add,
  918. .remove = cmpc_keys_remove,
  919. .notify = cmpc_keys_handler,
  920. }
  921. };
  922. /*
  923. * General init/exit code.
  924. */
  925. static int cmpc_init(void)
  926. {
  927. int r;
  928. r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
  929. if (r)
  930. goto failed_keys;
  931. r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
  932. if (r)
  933. goto failed_bl;
  934. r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
  935. if (r)
  936. goto failed_tablet;
  937. r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
  938. if (r)
  939. goto failed_accel;
  940. r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
  941. if (r)
  942. goto failed_accel_v4;
  943. return r;
  944. failed_accel_v4:
  945. acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
  946. failed_accel:
  947. acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
  948. failed_tablet:
  949. acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
  950. failed_bl:
  951. acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
  952. failed_keys:
  953. return r;
  954. }
  955. static void cmpc_exit(void)
  956. {
  957. acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
  958. acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
  959. acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
  960. acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
  961. acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
  962. }
  963. module_init(cmpc_init);
  964. module_exit(cmpc_exit);
  965. static const struct acpi_device_id cmpc_device_ids[] = {
  966. {CMPC_ACCEL_HID, 0},
  967. {CMPC_ACCEL_HID_V4, 0},
  968. {CMPC_TABLET_HID, 0},
  969. {CMPC_IPML_HID, 0},
  970. {CMPC_KEYS_HID, 0},
  971. {"", 0}
  972. };
  973. MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);