hid-picolcd_core.c 18 KB

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