classmate-laptop.c 26 KB

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