classmate-laptop.c 26 KB

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