hid-picolcd_core.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  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. if (data->status & PICOLCD_FAILED) {
  96. kfree(work);
  97. work = NULL;
  98. } else {
  99. data->pending = work;
  100. usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  101. spin_unlock_irqrestore(&data->lock, flags);
  102. wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
  103. spin_lock_irqsave(&data->lock, flags);
  104. data->pending = NULL;
  105. }
  106. spin_unlock_irqrestore(&data->lock, flags);
  107. mutex_unlock(&data->mutex);
  108. return work;
  109. }
  110. /*
  111. * input class device
  112. */
  113. static int picolcd_raw_keypad(struct picolcd_data *data,
  114. struct hid_report *report, u8 *raw_data, int size)
  115. {
  116. /*
  117. * Keypad event
  118. * First and second data bytes list currently pressed keys,
  119. * 0x00 means no key and at most 2 keys may be pressed at same time
  120. */
  121. int i, j;
  122. /* determine newly pressed keys */
  123. for (i = 0; i < size; i++) {
  124. unsigned int key_code;
  125. if (raw_data[i] == 0)
  126. continue;
  127. for (j = 0; j < sizeof(data->pressed_keys); j++)
  128. if (data->pressed_keys[j] == raw_data[i])
  129. goto key_already_down;
  130. for (j = 0; j < sizeof(data->pressed_keys); j++)
  131. if (data->pressed_keys[j] == 0) {
  132. data->pressed_keys[j] = raw_data[i];
  133. break;
  134. }
  135. input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
  136. if (raw_data[i] < PICOLCD_KEYS)
  137. key_code = data->keycode[raw_data[i]];
  138. else
  139. key_code = KEY_UNKNOWN;
  140. if (key_code != KEY_UNKNOWN) {
  141. dbg_hid(PICOLCD_NAME " got key press for %u:%d",
  142. raw_data[i], key_code);
  143. input_report_key(data->input_keys, key_code, 1);
  144. }
  145. input_sync(data->input_keys);
  146. key_already_down:
  147. continue;
  148. }
  149. /* determine newly released keys */
  150. for (j = 0; j < sizeof(data->pressed_keys); j++) {
  151. unsigned int key_code;
  152. if (data->pressed_keys[j] == 0)
  153. continue;
  154. for (i = 0; i < size; i++)
  155. if (data->pressed_keys[j] == raw_data[i])
  156. goto key_still_down;
  157. input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
  158. if (data->pressed_keys[j] < PICOLCD_KEYS)
  159. key_code = data->keycode[data->pressed_keys[j]];
  160. else
  161. key_code = KEY_UNKNOWN;
  162. if (key_code != KEY_UNKNOWN) {
  163. dbg_hid(PICOLCD_NAME " got key release for %u:%d",
  164. data->pressed_keys[j], key_code);
  165. input_report_key(data->input_keys, key_code, 0);
  166. }
  167. input_sync(data->input_keys);
  168. data->pressed_keys[j] = 0;
  169. key_still_down:
  170. continue;
  171. }
  172. return 1;
  173. }
  174. static int picolcd_check_version(struct hid_device *hdev)
  175. {
  176. struct picolcd_data *data = hid_get_drvdata(hdev);
  177. struct picolcd_pending *verinfo;
  178. int ret = 0;
  179. if (!data)
  180. return -ENODEV;
  181. verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
  182. if (!verinfo) {
  183. hid_err(hdev, "no version response from PicoLCD\n");
  184. return -ENODEV;
  185. }
  186. if (verinfo->raw_size == 2) {
  187. data->version[0] = verinfo->raw_data[1];
  188. data->version[1] = verinfo->raw_data[0];
  189. if (data->status & PICOLCD_BOOTLOADER) {
  190. hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
  191. verinfo->raw_data[1], verinfo->raw_data[0]);
  192. } else {
  193. hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
  194. verinfo->raw_data[1], verinfo->raw_data[0]);
  195. }
  196. } else {
  197. hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
  198. ret = -EINVAL;
  199. }
  200. kfree(verinfo);
  201. return ret;
  202. }
  203. /*
  204. * Reset our device and wait for answer to VERSION request
  205. */
  206. int picolcd_reset(struct hid_device *hdev)
  207. {
  208. struct picolcd_data *data = hid_get_drvdata(hdev);
  209. struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
  210. unsigned long flags;
  211. int error;
  212. if (!data || !report || report->maxfield != 1)
  213. return -ENODEV;
  214. spin_lock_irqsave(&data->lock, flags);
  215. if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
  216. data->status |= PICOLCD_BOOTLOADER;
  217. /* perform the reset */
  218. hid_set_field(report->field[0], 0, 1);
  219. if (data->status & PICOLCD_FAILED) {
  220. spin_unlock_irqrestore(&data->lock, flags);
  221. return -ENODEV;
  222. }
  223. usbhid_submit_report(hdev, report, USB_DIR_OUT);
  224. spin_unlock_irqrestore(&data->lock, flags);
  225. error = picolcd_check_version(hdev);
  226. if (error)
  227. return error;
  228. picolcd_resume_lcd(data);
  229. picolcd_resume_backlight(data);
  230. picolcd_fb_refresh(data);
  231. picolcd_leds_set(data);
  232. return 0;
  233. }
  234. /*
  235. * The "operation_mode" sysfs attribute
  236. */
  237. static ssize_t picolcd_operation_mode_show(struct device *dev,
  238. struct device_attribute *attr, char *buf)
  239. {
  240. struct picolcd_data *data = dev_get_drvdata(dev);
  241. if (data->status & PICOLCD_BOOTLOADER)
  242. return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
  243. else
  244. return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
  245. }
  246. static ssize_t picolcd_operation_mode_store(struct device *dev,
  247. struct device_attribute *attr, const char *buf, size_t count)
  248. {
  249. struct picolcd_data *data = dev_get_drvdata(dev);
  250. struct hid_report *report = NULL;
  251. size_t cnt = count;
  252. int timeout = data->opmode_delay;
  253. unsigned long flags;
  254. if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
  255. if (data->status & PICOLCD_BOOTLOADER)
  256. report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
  257. buf += 3;
  258. cnt -= 3;
  259. } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
  260. if (!(data->status & PICOLCD_BOOTLOADER))
  261. report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
  262. buf += 10;
  263. cnt -= 10;
  264. }
  265. if (!report)
  266. return -EINVAL;
  267. while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
  268. cnt--;
  269. if (cnt != 0)
  270. return -EINVAL;
  271. spin_lock_irqsave(&data->lock, flags);
  272. hid_set_field(report->field[0], 0, timeout & 0xff);
  273. hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
  274. usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  275. spin_unlock_irqrestore(&data->lock, flags);
  276. return count;
  277. }
  278. static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
  279. picolcd_operation_mode_store);
  280. /*
  281. * The "operation_mode_delay" sysfs attribute
  282. */
  283. static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
  284. struct device_attribute *attr, char *buf)
  285. {
  286. struct picolcd_data *data = dev_get_drvdata(dev);
  287. return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
  288. }
  289. static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
  290. struct device_attribute *attr, const char *buf, size_t count)
  291. {
  292. struct picolcd_data *data = dev_get_drvdata(dev);
  293. unsigned u;
  294. if (sscanf(buf, "%u", &u) != 1)
  295. return -EINVAL;
  296. if (u > 30000)
  297. return -EINVAL;
  298. else
  299. data->opmode_delay = u;
  300. return count;
  301. }
  302. static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
  303. picolcd_operation_mode_delay_store);
  304. /*
  305. * Handle raw report as sent by device
  306. */
  307. static int picolcd_raw_event(struct hid_device *hdev,
  308. struct hid_report *report, u8 *raw_data, int size)
  309. {
  310. struct picolcd_data *data = hid_get_drvdata(hdev);
  311. unsigned long flags;
  312. int ret = 0;
  313. if (!data)
  314. return 1;
  315. if (report->id == REPORT_KEY_STATE) {
  316. if (data->input_keys)
  317. ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
  318. } else if (report->id == REPORT_IR_DATA) {
  319. ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
  320. } else {
  321. spin_lock_irqsave(&data->lock, flags);
  322. /*
  323. * We let the caller of picolcd_send_and_wait() check if the
  324. * report we got is one of the expected ones or not.
  325. */
  326. if (data->pending) {
  327. memcpy(data->pending->raw_data, raw_data+1, size-1);
  328. data->pending->raw_size = size-1;
  329. data->pending->in_report = report;
  330. complete(&data->pending->ready);
  331. }
  332. spin_unlock_irqrestore(&data->lock, flags);
  333. }
  334. picolcd_debug_raw_event(data, hdev, report, raw_data, size);
  335. return 1;
  336. }
  337. #ifdef CONFIG_PM
  338. static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
  339. {
  340. if (PMSG_IS_AUTO(message))
  341. return 0;
  342. picolcd_suspend_backlight(hid_get_drvdata(hdev));
  343. dbg_hid(PICOLCD_NAME " device ready for suspend\n");
  344. return 0;
  345. }
  346. static int picolcd_resume(struct hid_device *hdev)
  347. {
  348. int ret;
  349. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  350. if (ret)
  351. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  352. return 0;
  353. }
  354. static int picolcd_reset_resume(struct hid_device *hdev)
  355. {
  356. int ret;
  357. ret = picolcd_reset(hdev);
  358. if (ret)
  359. dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
  360. ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
  361. if (ret)
  362. dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
  363. ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
  364. if (ret)
  365. dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
  366. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  367. if (ret)
  368. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  369. picolcd_leds_set(hid_get_drvdata(hdev));
  370. return 0;
  371. }
  372. #endif
  373. /* initialize keypad input device */
  374. static int picolcd_init_keys(struct picolcd_data *data,
  375. struct hid_report *report)
  376. {
  377. struct hid_device *hdev = data->hdev;
  378. struct input_dev *idev;
  379. int error, i;
  380. if (!report)
  381. return -ENODEV;
  382. if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
  383. report->field[0]->report_size != 8) {
  384. hid_err(hdev, "unsupported KEY_STATE report\n");
  385. return -EINVAL;
  386. }
  387. idev = input_allocate_device();
  388. if (idev == NULL) {
  389. hid_err(hdev, "failed to allocate input device\n");
  390. return -ENOMEM;
  391. }
  392. input_set_drvdata(idev, hdev);
  393. memcpy(data->keycode, def_keymap, sizeof(def_keymap));
  394. idev->name = hdev->name;
  395. idev->phys = hdev->phys;
  396. idev->uniq = hdev->uniq;
  397. idev->id.bustype = hdev->bus;
  398. idev->id.vendor = hdev->vendor;
  399. idev->id.product = hdev->product;
  400. idev->id.version = hdev->version;
  401. idev->dev.parent = &hdev->dev;
  402. idev->keycode = &data->keycode;
  403. idev->keycodemax = PICOLCD_KEYS;
  404. idev->keycodesize = sizeof(data->keycode[0]);
  405. input_set_capability(idev, EV_MSC, MSC_SCAN);
  406. set_bit(EV_REP, idev->evbit);
  407. for (i = 0; i < PICOLCD_KEYS; i++)
  408. input_set_capability(idev, EV_KEY, data->keycode[i]);
  409. error = input_register_device(idev);
  410. if (error) {
  411. hid_err(hdev, "error registering the input device\n");
  412. input_free_device(idev);
  413. return error;
  414. }
  415. data->input_keys = idev;
  416. return 0;
  417. }
  418. static void picolcd_exit_keys(struct picolcd_data *data)
  419. {
  420. struct input_dev *idev = data->input_keys;
  421. data->input_keys = NULL;
  422. if (idev)
  423. input_unregister_device(idev);
  424. }
  425. static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
  426. {
  427. int error;
  428. /* Setup keypad input device */
  429. error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
  430. if (error)
  431. goto err;
  432. /* Setup CIR input device */
  433. error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
  434. if (error)
  435. goto err;
  436. /* Set up the framebuffer device */
  437. error = picolcd_init_framebuffer(data);
  438. if (error)
  439. goto err;
  440. /* Setup lcd class device */
  441. error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
  442. if (error)
  443. goto err;
  444. /* Setup backlight class device */
  445. error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
  446. if (error)
  447. goto err;
  448. /* Setup the LED class devices */
  449. error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
  450. if (error)
  451. goto err;
  452. picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
  453. picolcd_out_report(REPORT_EE_WRITE, hdev),
  454. picolcd_out_report(REPORT_READ_MEMORY, hdev),
  455. picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
  456. picolcd_out_report(REPORT_RESET, hdev));
  457. return 0;
  458. err:
  459. picolcd_exit_leds(data);
  460. picolcd_exit_backlight(data);
  461. picolcd_exit_lcd(data);
  462. picolcd_exit_framebuffer(data);
  463. picolcd_exit_cir(data);
  464. picolcd_exit_keys(data);
  465. return error;
  466. }
  467. static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
  468. {
  469. picolcd_init_devfs(data, NULL, NULL,
  470. picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
  471. picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
  472. return 0;
  473. }
  474. static int picolcd_probe(struct hid_device *hdev,
  475. const struct hid_device_id *id)
  476. {
  477. struct picolcd_data *data;
  478. int error = -ENOMEM;
  479. dbg_hid(PICOLCD_NAME " hardware probe...\n");
  480. /*
  481. * Let's allocate the picolcd data structure, set some reasonable
  482. * defaults, and associate it with the device
  483. */
  484. data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
  485. if (data == NULL) {
  486. hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
  487. error = -ENOMEM;
  488. goto err_no_cleanup;
  489. }
  490. spin_lock_init(&data->lock);
  491. mutex_init(&data->mutex);
  492. data->hdev = hdev;
  493. data->opmode_delay = 5000;
  494. if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
  495. data->status |= PICOLCD_BOOTLOADER;
  496. hid_set_drvdata(hdev, data);
  497. /* Parse the device reports and start it up */
  498. error = hid_parse(hdev);
  499. if (error) {
  500. hid_err(hdev, "device report parse failed\n");
  501. goto err_cleanup_data;
  502. }
  503. error = hid_hw_start(hdev, 0);
  504. if (error) {
  505. hid_err(hdev, "hardware start failed\n");
  506. goto err_cleanup_data;
  507. }
  508. error = hid_hw_open(hdev);
  509. if (error) {
  510. hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
  511. goto err_cleanup_hid_hw;
  512. }
  513. error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
  514. if (error) {
  515. hid_err(hdev, "failed to create sysfs attributes\n");
  516. goto err_cleanup_hid_ll;
  517. }
  518. error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
  519. if (error) {
  520. hid_err(hdev, "failed to create sysfs attributes\n");
  521. goto err_cleanup_sysfs1;
  522. }
  523. if (data->status & PICOLCD_BOOTLOADER)
  524. error = picolcd_probe_bootloader(hdev, data);
  525. else
  526. error = picolcd_probe_lcd(hdev, data);
  527. if (error)
  528. goto err_cleanup_sysfs2;
  529. dbg_hid(PICOLCD_NAME " activated and initialized\n");
  530. return 0;
  531. err_cleanup_sysfs2:
  532. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  533. err_cleanup_sysfs1:
  534. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  535. err_cleanup_hid_ll:
  536. hid_hw_close(hdev);
  537. err_cleanup_hid_hw:
  538. hid_hw_stop(hdev);
  539. err_cleanup_data:
  540. kfree(data);
  541. err_no_cleanup:
  542. hid_set_drvdata(hdev, NULL);
  543. return error;
  544. }
  545. static void picolcd_remove(struct hid_device *hdev)
  546. {
  547. struct picolcd_data *data = hid_get_drvdata(hdev);
  548. unsigned long flags;
  549. dbg_hid(PICOLCD_NAME " hardware remove...\n");
  550. spin_lock_irqsave(&data->lock, flags);
  551. data->status |= PICOLCD_FAILED;
  552. spin_unlock_irqrestore(&data->lock, flags);
  553. picolcd_exit_devfs(data);
  554. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  555. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  556. hid_hw_close(hdev);
  557. hid_hw_stop(hdev);
  558. /* Shortcut potential pending reply that will never arrive */
  559. spin_lock_irqsave(&data->lock, flags);
  560. if (data->pending)
  561. complete(&data->pending->ready);
  562. spin_unlock_irqrestore(&data->lock, flags);
  563. /* Cleanup LED */
  564. picolcd_exit_leds(data);
  565. /* Clean up the framebuffer */
  566. picolcd_exit_backlight(data);
  567. picolcd_exit_lcd(data);
  568. picolcd_exit_framebuffer(data);
  569. /* Cleanup input */
  570. picolcd_exit_cir(data);
  571. picolcd_exit_keys(data);
  572. hid_set_drvdata(hdev, NULL);
  573. mutex_destroy(&data->mutex);
  574. /* Finally, clean up the picolcd data itself */
  575. kfree(data);
  576. }
  577. static const struct hid_device_id picolcd_devices[] = {
  578. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
  579. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
  580. { }
  581. };
  582. MODULE_DEVICE_TABLE(hid, picolcd_devices);
  583. static struct hid_driver picolcd_driver = {
  584. .name = "hid-picolcd",
  585. .id_table = picolcd_devices,
  586. .probe = picolcd_probe,
  587. .remove = picolcd_remove,
  588. .raw_event = picolcd_raw_event,
  589. #ifdef CONFIG_PM
  590. .suspend = picolcd_suspend,
  591. .resume = picolcd_resume,
  592. .reset_resume = picolcd_reset_resume,
  593. #endif
  594. };
  595. module_hid_driver(picolcd_driver);
  596. MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
  597. MODULE_LICENSE("GPL v2");