hid-picolcd_core.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /***************************************************************************
  2. * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
  3. * *
  4. * Based on Logitech G13 driver (v0.4) *
  5. * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
  6. * *
  7. * This program is free software: you can redistribute it and/or modify *
  8. * it under the terms of the GNU General Public License as published by *
  9. * the Free Software Foundation, version 2 of the License. *
  10. * *
  11. * This driver is distributed in the hope that it will be useful, but *
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  14. * General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with this software. If not see <http://www.gnu.org/licenses/>. *
  18. ***************************************************************************/
  19. #include <linux/hid.h>
  20. #include <linux/hid-debug.h>
  21. #include <linux/input.h>
  22. #include "hid-ids.h"
  23. #include "usbhid/usbhid.h"
  24. #include <linux/usb.h>
  25. #include <linux/fb.h>
  26. #include <linux/vmalloc.h>
  27. #include <linux/completion.h>
  28. #include <linux/uaccess.h>
  29. #include <linux/module.h>
  30. #include "hid-picolcd.h"
  31. /* Input device
  32. *
  33. * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
  34. * and header for 4x4 key matrix. The built-in keys are part of the matrix.
  35. */
  36. static const unsigned short def_keymap[PICOLCD_KEYS] = {
  37. KEY_RESERVED, /* none */
  38. KEY_BACK, /* col 4 + row 1 */
  39. KEY_HOMEPAGE, /* col 3 + row 1 */
  40. KEY_RESERVED, /* col 2 + row 1 */
  41. KEY_RESERVED, /* col 1 + row 1 */
  42. KEY_SCROLLUP, /* col 4 + row 2 */
  43. KEY_OK, /* col 3 + row 2 */
  44. KEY_SCROLLDOWN, /* col 2 + row 2 */
  45. KEY_RESERVED, /* col 1 + row 2 */
  46. KEY_RESERVED, /* col 4 + row 3 */
  47. KEY_RESERVED, /* col 3 + row 3 */
  48. KEY_RESERVED, /* col 2 + row 3 */
  49. KEY_RESERVED, /* col 1 + row 3 */
  50. KEY_RESERVED, /* col 4 + row 4 */
  51. KEY_RESERVED, /* col 3 + row 4 */
  52. KEY_RESERVED, /* col 2 + row 4 */
  53. KEY_RESERVED, /* col 1 + row 4 */
  54. };
  55. /* Find a given report */
  56. struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
  57. {
  58. struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
  59. struct hid_report *report = NULL;
  60. list_for_each_entry(report, feature_report_list, list) {
  61. if (report->id == id)
  62. return report;
  63. }
  64. hid_warn(hdev, "No report with id 0x%x found\n", id);
  65. return NULL;
  66. }
  67. /* Submit a report and wait for a reply from device - if device fades away
  68. * or does not respond in time, return NULL */
  69. struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
  70. int report_id, const u8 *raw_data, int size)
  71. {
  72. struct picolcd_data *data = hid_get_drvdata(hdev);
  73. struct picolcd_pending *work;
  74. struct hid_report *report = picolcd_out_report(report_id, hdev);
  75. unsigned long flags;
  76. int i, j, k;
  77. if (!report || !data)
  78. return NULL;
  79. if (data->status & PICOLCD_FAILED)
  80. return NULL;
  81. work = kzalloc(sizeof(*work), GFP_KERNEL);
  82. if (!work)
  83. return NULL;
  84. init_completion(&work->ready);
  85. work->out_report = report;
  86. work->in_report = NULL;
  87. work->raw_size = 0;
  88. mutex_lock(&data->mutex);
  89. spin_lock_irqsave(&data->lock, flags);
  90. for (i = k = 0; i < report->maxfield; i++)
  91. for (j = 0; j < report->field[i]->report_count; j++) {
  92. hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
  93. k++;
  94. }
  95. data->pending = work;
  96. usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  97. spin_unlock_irqrestore(&data->lock, flags);
  98. wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
  99. spin_lock_irqsave(&data->lock, flags);
  100. data->pending = NULL;
  101. spin_unlock_irqrestore(&data->lock, flags);
  102. mutex_unlock(&data->mutex);
  103. return work;
  104. }
  105. /*
  106. * input class device
  107. */
  108. static int picolcd_raw_keypad(struct picolcd_data *data,
  109. struct hid_report *report, u8 *raw_data, int size)
  110. {
  111. /*
  112. * Keypad event
  113. * First and second data bytes list currently pressed keys,
  114. * 0x00 means no key and at most 2 keys may be pressed at same time
  115. */
  116. int i, j;
  117. /* determine newly pressed keys */
  118. for (i = 0; i < size; i++) {
  119. unsigned int key_code;
  120. if (raw_data[i] == 0)
  121. continue;
  122. for (j = 0; j < sizeof(data->pressed_keys); j++)
  123. if (data->pressed_keys[j] == raw_data[i])
  124. goto key_already_down;
  125. for (j = 0; j < sizeof(data->pressed_keys); j++)
  126. if (data->pressed_keys[j] == 0) {
  127. data->pressed_keys[j] = raw_data[i];
  128. break;
  129. }
  130. input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
  131. if (raw_data[i] < PICOLCD_KEYS)
  132. key_code = data->keycode[raw_data[i]];
  133. else
  134. key_code = KEY_UNKNOWN;
  135. if (key_code != KEY_UNKNOWN) {
  136. dbg_hid(PICOLCD_NAME " got key press for %u:%d",
  137. raw_data[i], key_code);
  138. input_report_key(data->input_keys, key_code, 1);
  139. }
  140. input_sync(data->input_keys);
  141. key_already_down:
  142. continue;
  143. }
  144. /* determine newly released keys */
  145. for (j = 0; j < sizeof(data->pressed_keys); j++) {
  146. unsigned int key_code;
  147. if (data->pressed_keys[j] == 0)
  148. continue;
  149. for (i = 0; i < size; i++)
  150. if (data->pressed_keys[j] == raw_data[i])
  151. goto key_still_down;
  152. input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
  153. if (data->pressed_keys[j] < PICOLCD_KEYS)
  154. key_code = data->keycode[data->pressed_keys[j]];
  155. else
  156. key_code = KEY_UNKNOWN;
  157. if (key_code != KEY_UNKNOWN) {
  158. dbg_hid(PICOLCD_NAME " got key release for %u:%d",
  159. data->pressed_keys[j], key_code);
  160. input_report_key(data->input_keys, key_code, 0);
  161. }
  162. input_sync(data->input_keys);
  163. data->pressed_keys[j] = 0;
  164. key_still_down:
  165. continue;
  166. }
  167. return 1;
  168. }
  169. static int picolcd_check_version(struct hid_device *hdev)
  170. {
  171. struct picolcd_data *data = hid_get_drvdata(hdev);
  172. struct picolcd_pending *verinfo;
  173. int ret = 0;
  174. if (!data)
  175. return -ENODEV;
  176. verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
  177. if (!verinfo) {
  178. hid_err(hdev, "no version response from PicoLCD\n");
  179. return -ENODEV;
  180. }
  181. if (verinfo->raw_size == 2) {
  182. data->version[0] = verinfo->raw_data[1];
  183. data->version[1] = verinfo->raw_data[0];
  184. if (data->status & PICOLCD_BOOTLOADER) {
  185. hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
  186. verinfo->raw_data[1], verinfo->raw_data[0]);
  187. } else {
  188. hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
  189. verinfo->raw_data[1], verinfo->raw_data[0]);
  190. }
  191. } else {
  192. hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
  193. ret = -EINVAL;
  194. }
  195. kfree(verinfo);
  196. return ret;
  197. }
  198. /*
  199. * Reset our device and wait for answer to VERSION request
  200. */
  201. int picolcd_reset(struct hid_device *hdev)
  202. {
  203. struct picolcd_data *data = hid_get_drvdata(hdev);
  204. struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
  205. unsigned long flags;
  206. int error;
  207. if (!data || !report || report->maxfield != 1)
  208. return -ENODEV;
  209. spin_lock_irqsave(&data->lock, flags);
  210. if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
  211. data->status |= PICOLCD_BOOTLOADER;
  212. /* perform the reset */
  213. hid_set_field(report->field[0], 0, 1);
  214. usbhid_submit_report(hdev, report, USB_DIR_OUT);
  215. spin_unlock_irqrestore(&data->lock, flags);
  216. error = picolcd_check_version(hdev);
  217. if (error)
  218. return error;
  219. picolcd_resume_lcd(data);
  220. picolcd_resume_backlight(data);
  221. picolcd_fb_refresh(data);
  222. picolcd_leds_set(data);
  223. return 0;
  224. }
  225. /*
  226. * The "operation_mode" sysfs attribute
  227. */
  228. static ssize_t picolcd_operation_mode_show(struct device *dev,
  229. struct device_attribute *attr, char *buf)
  230. {
  231. struct picolcd_data *data = dev_get_drvdata(dev);
  232. if (data->status & PICOLCD_BOOTLOADER)
  233. return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
  234. else
  235. return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
  236. }
  237. static ssize_t picolcd_operation_mode_store(struct device *dev,
  238. struct device_attribute *attr, const char *buf, size_t count)
  239. {
  240. struct picolcd_data *data = dev_get_drvdata(dev);
  241. struct hid_report *report = NULL;
  242. size_t cnt = count;
  243. int timeout = data->opmode_delay;
  244. unsigned long flags;
  245. if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
  246. if (data->status & PICOLCD_BOOTLOADER)
  247. report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
  248. buf += 3;
  249. cnt -= 3;
  250. } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
  251. if (!(data->status & PICOLCD_BOOTLOADER))
  252. report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
  253. buf += 10;
  254. cnt -= 10;
  255. }
  256. if (!report)
  257. return -EINVAL;
  258. while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
  259. cnt--;
  260. if (cnt != 0)
  261. return -EINVAL;
  262. spin_lock_irqsave(&data->lock, flags);
  263. hid_set_field(report->field[0], 0, timeout & 0xff);
  264. hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
  265. usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  266. spin_unlock_irqrestore(&data->lock, flags);
  267. return count;
  268. }
  269. static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
  270. picolcd_operation_mode_store);
  271. /*
  272. * The "operation_mode_delay" sysfs attribute
  273. */
  274. static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
  275. struct device_attribute *attr, char *buf)
  276. {
  277. struct picolcd_data *data = dev_get_drvdata(dev);
  278. return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
  279. }
  280. static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
  281. struct device_attribute *attr, const char *buf, size_t count)
  282. {
  283. struct picolcd_data *data = dev_get_drvdata(dev);
  284. unsigned u;
  285. if (sscanf(buf, "%u", &u) != 1)
  286. return -EINVAL;
  287. if (u > 30000)
  288. return -EINVAL;
  289. else
  290. data->opmode_delay = u;
  291. return count;
  292. }
  293. static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
  294. picolcd_operation_mode_delay_store);
  295. /*
  296. * Handle raw report as sent by device
  297. */
  298. static int picolcd_raw_event(struct hid_device *hdev,
  299. struct hid_report *report, u8 *raw_data, int size)
  300. {
  301. struct picolcd_data *data = hid_get_drvdata(hdev);
  302. unsigned long flags;
  303. int ret = 0;
  304. if (!data)
  305. return 1;
  306. if (report->id == REPORT_KEY_STATE) {
  307. if (data->input_keys)
  308. ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
  309. } else if (report->id == REPORT_IR_DATA) {
  310. if (data->input_cir)
  311. ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
  312. } else {
  313. spin_lock_irqsave(&data->lock, flags);
  314. /*
  315. * We let the caller of picolcd_send_and_wait() check if the
  316. * report we got is one of the expected ones or not.
  317. */
  318. if (data->pending) {
  319. memcpy(data->pending->raw_data, raw_data+1, size-1);
  320. data->pending->raw_size = size-1;
  321. data->pending->in_report = report;
  322. complete(&data->pending->ready);
  323. }
  324. spin_unlock_irqrestore(&data->lock, flags);
  325. }
  326. picolcd_debug_raw_event(data, hdev, report, raw_data, size);
  327. return 1;
  328. }
  329. #ifdef CONFIG_PM
  330. static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
  331. {
  332. if (PMSG_IS_AUTO(message))
  333. return 0;
  334. picolcd_suspend_backlight(hid_get_drvdata(hdev));
  335. dbg_hid(PICOLCD_NAME " device ready for suspend\n");
  336. return 0;
  337. }
  338. static int picolcd_resume(struct hid_device *hdev)
  339. {
  340. int ret;
  341. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  342. if (ret)
  343. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  344. return 0;
  345. }
  346. static int picolcd_reset_resume(struct hid_device *hdev)
  347. {
  348. int ret;
  349. ret = picolcd_reset(hdev);
  350. if (ret)
  351. dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
  352. ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
  353. if (ret)
  354. dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
  355. ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
  356. if (ret)
  357. dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
  358. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  359. if (ret)
  360. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  361. picolcd_leds_set(hid_get_drvdata(hdev));
  362. return 0;
  363. }
  364. #endif
  365. /* initialize keypad input device */
  366. static int picolcd_init_keys(struct picolcd_data *data,
  367. struct hid_report *report)
  368. {
  369. struct hid_device *hdev = data->hdev;
  370. struct input_dev *idev;
  371. int error, i;
  372. if (!report)
  373. return -ENODEV;
  374. if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
  375. report->field[0]->report_size != 8) {
  376. hid_err(hdev, "unsupported KEY_STATE report\n");
  377. return -EINVAL;
  378. }
  379. idev = input_allocate_device();
  380. if (idev == NULL) {
  381. hid_err(hdev, "failed to allocate input device\n");
  382. return -ENOMEM;
  383. }
  384. input_set_drvdata(idev, hdev);
  385. memcpy(data->keycode, def_keymap, sizeof(def_keymap));
  386. idev->name = hdev->name;
  387. idev->phys = hdev->phys;
  388. idev->uniq = hdev->uniq;
  389. idev->id.bustype = hdev->bus;
  390. idev->id.vendor = hdev->vendor;
  391. idev->id.product = hdev->product;
  392. idev->id.version = hdev->version;
  393. idev->dev.parent = hdev->dev.parent;
  394. idev->keycode = &data->keycode;
  395. idev->keycodemax = PICOLCD_KEYS;
  396. idev->keycodesize = sizeof(data->keycode[0]);
  397. input_set_capability(idev, EV_MSC, MSC_SCAN);
  398. set_bit(EV_REP, idev->evbit);
  399. for (i = 0; i < PICOLCD_KEYS; i++)
  400. input_set_capability(idev, EV_KEY, data->keycode[i]);
  401. error = input_register_device(idev);
  402. if (error) {
  403. hid_err(hdev, "error registering the input device\n");
  404. input_free_device(idev);
  405. return error;
  406. }
  407. data->input_keys = idev;
  408. return 0;
  409. }
  410. static void picolcd_exit_keys(struct picolcd_data *data)
  411. {
  412. struct input_dev *idev = data->input_keys;
  413. data->input_keys = NULL;
  414. if (idev)
  415. input_unregister_device(idev);
  416. }
  417. static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
  418. {
  419. int error;
  420. error = picolcd_check_version(hdev);
  421. if (error)
  422. return error;
  423. if (data->version[0] != 0 && data->version[1] != 3)
  424. hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
  425. dev_name(&hdev->dev));
  426. /* Setup keypad input device */
  427. error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
  428. if (error)
  429. goto err;
  430. /* Setup CIR input device */
  431. error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
  432. if (error)
  433. goto err;
  434. /* Set up the framebuffer device */
  435. error = picolcd_init_framebuffer(data);
  436. if (error)
  437. goto err;
  438. /* Setup lcd class device */
  439. error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
  440. if (error)
  441. goto err;
  442. /* Setup backlight class device */
  443. error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
  444. if (error)
  445. goto err;
  446. /* Setup the LED class devices */
  447. error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
  448. if (error)
  449. goto err;
  450. picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
  451. picolcd_out_report(REPORT_EE_WRITE, hdev),
  452. picolcd_out_report(REPORT_READ_MEMORY, hdev),
  453. picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
  454. picolcd_out_report(REPORT_RESET, hdev));
  455. return 0;
  456. err:
  457. picolcd_exit_leds(data);
  458. picolcd_exit_backlight(data);
  459. picolcd_exit_lcd(data);
  460. picolcd_exit_framebuffer(data);
  461. picolcd_exit_cir(data);
  462. picolcd_exit_keys(data);
  463. return error;
  464. }
  465. static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
  466. {
  467. int error;
  468. error = picolcd_check_version(hdev);
  469. if (error)
  470. return error;
  471. if (data->version[0] != 1 && data->version[1] != 0)
  472. hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
  473. dev_name(&hdev->dev));
  474. picolcd_init_devfs(data, NULL, NULL,
  475. picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
  476. picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
  477. return 0;
  478. }
  479. static int picolcd_probe(struct hid_device *hdev,
  480. const struct hid_device_id *id)
  481. {
  482. struct picolcd_data *data;
  483. int error = -ENOMEM;
  484. dbg_hid(PICOLCD_NAME " hardware probe...\n");
  485. /*
  486. * Let's allocate the picolcd data structure, set some reasonable
  487. * defaults, and associate it with the device
  488. */
  489. data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
  490. if (data == NULL) {
  491. hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
  492. error = -ENOMEM;
  493. goto err_no_cleanup;
  494. }
  495. spin_lock_init(&data->lock);
  496. mutex_init(&data->mutex);
  497. data->hdev = hdev;
  498. data->opmode_delay = 5000;
  499. if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
  500. data->status |= PICOLCD_BOOTLOADER;
  501. hid_set_drvdata(hdev, data);
  502. /* Parse the device reports and start it up */
  503. error = hid_parse(hdev);
  504. if (error) {
  505. hid_err(hdev, "device report parse failed\n");
  506. goto err_cleanup_data;
  507. }
  508. /* We don't use hidinput but hid_hw_start() fails if nothing is
  509. * claimed. So spoof claimed input. */
  510. hdev->claimed = HID_CLAIMED_INPUT;
  511. error = hid_hw_start(hdev, 0);
  512. hdev->claimed = 0;
  513. if (error) {
  514. hid_err(hdev, "hardware start failed\n");
  515. goto err_cleanup_data;
  516. }
  517. error = hid_hw_open(hdev);
  518. if (error) {
  519. hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
  520. goto err_cleanup_hid_hw;
  521. }
  522. error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
  523. if (error) {
  524. hid_err(hdev, "failed to create sysfs attributes\n");
  525. goto err_cleanup_hid_ll;
  526. }
  527. error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
  528. if (error) {
  529. hid_err(hdev, "failed to create sysfs attributes\n");
  530. goto err_cleanup_sysfs1;
  531. }
  532. if (data->status & PICOLCD_BOOTLOADER)
  533. error = picolcd_probe_bootloader(hdev, data);
  534. else
  535. error = picolcd_probe_lcd(hdev, data);
  536. if (error)
  537. goto err_cleanup_sysfs2;
  538. dbg_hid(PICOLCD_NAME " activated and initialized\n");
  539. return 0;
  540. err_cleanup_sysfs2:
  541. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  542. err_cleanup_sysfs1:
  543. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  544. err_cleanup_hid_ll:
  545. hid_hw_close(hdev);
  546. err_cleanup_hid_hw:
  547. hid_hw_stop(hdev);
  548. err_cleanup_data:
  549. kfree(data);
  550. err_no_cleanup:
  551. hid_set_drvdata(hdev, NULL);
  552. return error;
  553. }
  554. static void picolcd_remove(struct hid_device *hdev)
  555. {
  556. struct picolcd_data *data = hid_get_drvdata(hdev);
  557. unsigned long flags;
  558. dbg_hid(PICOLCD_NAME " hardware remove...\n");
  559. spin_lock_irqsave(&data->lock, flags);
  560. data->status |= PICOLCD_FAILED;
  561. spin_unlock_irqrestore(&data->lock, flags);
  562. picolcd_exit_devfs(data);
  563. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  564. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  565. hid_hw_close(hdev);
  566. hid_hw_stop(hdev);
  567. hid_set_drvdata(hdev, NULL);
  568. /* Shortcut potential pending reply that will never arrive */
  569. spin_lock_irqsave(&data->lock, flags);
  570. if (data->pending)
  571. complete(&data->pending->ready);
  572. spin_unlock_irqrestore(&data->lock, flags);
  573. /* Cleanup LED */
  574. picolcd_exit_leds(data);
  575. /* Clean up the framebuffer */
  576. picolcd_exit_backlight(data);
  577. picolcd_exit_lcd(data);
  578. picolcd_exit_framebuffer(data);
  579. /* Cleanup input */
  580. picolcd_exit_cir(data);
  581. picolcd_exit_keys(data);
  582. mutex_destroy(&data->mutex);
  583. /* Finally, clean up the picolcd data itself */
  584. kfree(data);
  585. }
  586. static const struct hid_device_id picolcd_devices[] = {
  587. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
  588. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
  589. { }
  590. };
  591. MODULE_DEVICE_TABLE(hid, picolcd_devices);
  592. static struct hid_driver picolcd_driver = {
  593. .name = "hid-picolcd",
  594. .id_table = picolcd_devices,
  595. .probe = picolcd_probe,
  596. .remove = picolcd_remove,
  597. .raw_event = picolcd_raw_event,
  598. #ifdef CONFIG_PM
  599. .suspend = picolcd_suspend,
  600. .resume = picolcd_resume,
  601. .reset_resume = picolcd_reset_resume,
  602. #endif
  603. };
  604. static int __init picolcd_init(void)
  605. {
  606. return hid_register_driver(&picolcd_driver);
  607. }
  608. static void __exit picolcd_exit(void)
  609. {
  610. hid_unregister_driver(&picolcd_driver);
  611. }
  612. module_init(picolcd_init);
  613. module_exit(picolcd_exit);
  614. MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
  615. MODULE_LICENSE("GPL v2");