hid-picolcd_core.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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 sysfs_emit(buf, "[bootloader] lcd\n");
  232. else
  233. return sysfs_emit(buf, "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 sysfs_emit(buf, "%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. if (!data)
  295. return 1;
  296. if (size > 64) {
  297. hid_warn(hdev, "invalid size value (%d) for picolcd raw event (%d)\n",
  298. size, report->id);
  299. return 0;
  300. }
  301. if (report->id == REPORT_KEY_STATE) {
  302. if (data->input_keys)
  303. picolcd_raw_keypad(data, report, raw_data+1, size-1);
  304. } else if (report->id == REPORT_IR_DATA) {
  305. picolcd_raw_cir(data, report, raw_data+1, size-1);
  306. } else {
  307. spin_lock_irqsave(&data->lock, flags);
  308. /*
  309. * We let the caller of picolcd_send_and_wait() check if the
  310. * report we got is one of the expected ones or not.
  311. */
  312. if (data->pending) {
  313. memcpy(data->pending->raw_data, raw_data+1, size-1);
  314. data->pending->raw_size = size-1;
  315. data->pending->in_report = report;
  316. complete(&data->pending->ready);
  317. }
  318. spin_unlock_irqrestore(&data->lock, flags);
  319. }
  320. picolcd_debug_raw_event(data, hdev, report, raw_data, size);
  321. return 1;
  322. }
  323. #ifdef CONFIG_PM
  324. static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
  325. {
  326. if (PMSG_IS_AUTO(message))
  327. return 0;
  328. picolcd_suspend_backlight(hid_get_drvdata(hdev));
  329. dbg_hid(PICOLCD_NAME " device ready for suspend\n");
  330. return 0;
  331. }
  332. static int picolcd_resume(struct hid_device *hdev)
  333. {
  334. int ret;
  335. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  336. if (ret)
  337. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  338. return 0;
  339. }
  340. static int picolcd_reset_resume(struct hid_device *hdev)
  341. {
  342. int ret;
  343. ret = picolcd_reset(hdev);
  344. if (ret)
  345. dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
  346. ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
  347. if (ret)
  348. dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
  349. ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
  350. if (ret)
  351. dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
  352. ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
  353. if (ret)
  354. dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
  355. picolcd_leds_set(hid_get_drvdata(hdev));
  356. return 0;
  357. }
  358. #endif
  359. /* initialize keypad input device */
  360. static int picolcd_init_keys(struct picolcd_data *data,
  361. struct hid_report *report)
  362. {
  363. struct hid_device *hdev = data->hdev;
  364. struct input_dev *idev;
  365. int error, i;
  366. if (!report)
  367. return -ENODEV;
  368. if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
  369. report->field[0]->report_size != 8) {
  370. hid_err(hdev, "unsupported KEY_STATE report\n");
  371. return -EINVAL;
  372. }
  373. idev = input_allocate_device();
  374. if (idev == NULL) {
  375. hid_err(hdev, "failed to allocate input device\n");
  376. return -ENOMEM;
  377. }
  378. input_set_drvdata(idev, hdev);
  379. memcpy(data->keycode, def_keymap, sizeof(def_keymap));
  380. idev->name = hdev->name;
  381. idev->phys = hdev->phys;
  382. idev->uniq = hdev->uniq;
  383. idev->id.bustype = hdev->bus;
  384. idev->id.vendor = hdev->vendor;
  385. idev->id.product = hdev->product;
  386. idev->id.version = hdev->version;
  387. idev->dev.parent = &hdev->dev;
  388. idev->keycode = &data->keycode;
  389. idev->keycodemax = PICOLCD_KEYS;
  390. idev->keycodesize = sizeof(data->keycode[0]);
  391. input_set_capability(idev, EV_MSC, MSC_SCAN);
  392. set_bit(EV_REP, idev->evbit);
  393. for (i = 0; i < PICOLCD_KEYS; i++)
  394. input_set_capability(idev, EV_KEY, data->keycode[i]);
  395. error = input_register_device(idev);
  396. if (error) {
  397. hid_err(hdev, "error registering the input device\n");
  398. input_free_device(idev);
  399. return error;
  400. }
  401. data->input_keys = idev;
  402. return 0;
  403. }
  404. static void picolcd_exit_keys(struct picolcd_data *data)
  405. {
  406. struct input_dev *idev = data->input_keys;
  407. data->input_keys = NULL;
  408. if (idev)
  409. input_unregister_device(idev);
  410. }
  411. static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
  412. {
  413. int error;
  414. /* Setup keypad input device */
  415. error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
  416. if (error)
  417. goto err;
  418. /* Setup CIR input device */
  419. error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
  420. if (error)
  421. goto err;
  422. /* Setup lcd class device */
  423. error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
  424. if (error)
  425. goto err;
  426. /* Setup backlight class device */
  427. error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
  428. if (error)
  429. goto err;
  430. /* Set up the framebuffer device */
  431. error = picolcd_init_framebuffer(data);
  432. if (error)
  433. goto err;
  434. /* Setup the LED class devices */
  435. error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
  436. if (error)
  437. goto err;
  438. picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
  439. picolcd_out_report(REPORT_EE_WRITE, hdev),
  440. picolcd_out_report(REPORT_READ_MEMORY, hdev),
  441. picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
  442. picolcd_out_report(REPORT_RESET, hdev));
  443. return 0;
  444. err:
  445. picolcd_exit_leds(data);
  446. picolcd_exit_framebuffer(data);
  447. picolcd_exit_backlight(data);
  448. picolcd_exit_lcd(data);
  449. picolcd_exit_cir(data);
  450. picolcd_exit_keys(data);
  451. return error;
  452. }
  453. static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
  454. {
  455. picolcd_init_devfs(data, NULL, NULL,
  456. picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
  457. picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
  458. return 0;
  459. }
  460. static int picolcd_probe(struct hid_device *hdev,
  461. const struct hid_device_id *id)
  462. {
  463. struct picolcd_data *data;
  464. int error = -ENOMEM;
  465. dbg_hid(PICOLCD_NAME " hardware probe...\n");
  466. /*
  467. * Let's allocate the picolcd data structure, set some reasonable
  468. * defaults, and associate it with the device
  469. */
  470. data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
  471. if (data == NULL) {
  472. hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
  473. return -ENOMEM;
  474. }
  475. spin_lock_init(&data->lock);
  476. mutex_init(&data->mutex);
  477. data->hdev = hdev;
  478. data->opmode_delay = 5000;
  479. if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
  480. data->status |= PICOLCD_BOOTLOADER;
  481. hid_set_drvdata(hdev, data);
  482. /* Parse the device reports and start it up */
  483. error = hid_parse(hdev);
  484. if (error) {
  485. hid_err(hdev, "device report parse failed\n");
  486. goto err_cleanup_data;
  487. }
  488. error = hid_hw_start(hdev, 0);
  489. if (error) {
  490. hid_err(hdev, "hardware start failed\n");
  491. goto err_cleanup_data;
  492. }
  493. error = hid_hw_open(hdev);
  494. if (error) {
  495. hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
  496. goto err_cleanup_hid_hw;
  497. }
  498. error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
  499. if (error) {
  500. hid_err(hdev, "failed to create sysfs attributes\n");
  501. goto err_cleanup_hid_ll;
  502. }
  503. error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
  504. if (error) {
  505. hid_err(hdev, "failed to create sysfs attributes\n");
  506. goto err_cleanup_sysfs1;
  507. }
  508. if (data->status & PICOLCD_BOOTLOADER)
  509. error = picolcd_probe_bootloader(hdev, data);
  510. else
  511. error = picolcd_probe_lcd(hdev, data);
  512. if (error)
  513. goto err_cleanup_sysfs2;
  514. dbg_hid(PICOLCD_NAME " activated and initialized\n");
  515. return 0;
  516. err_cleanup_sysfs2:
  517. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  518. err_cleanup_sysfs1:
  519. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  520. err_cleanup_hid_ll:
  521. hid_hw_close(hdev);
  522. err_cleanup_hid_hw:
  523. hid_hw_stop(hdev);
  524. err_cleanup_data:
  525. kfree(data);
  526. return error;
  527. }
  528. static void picolcd_remove(struct hid_device *hdev)
  529. {
  530. struct picolcd_data *data = hid_get_drvdata(hdev);
  531. unsigned long flags;
  532. dbg_hid(PICOLCD_NAME " hardware remove...\n");
  533. spin_lock_irqsave(&data->lock, flags);
  534. data->status |= PICOLCD_FAILED;
  535. spin_unlock_irqrestore(&data->lock, flags);
  536. picolcd_exit_devfs(data);
  537. device_remove_file(&hdev->dev, &dev_attr_operation_mode);
  538. device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
  539. hid_hw_close(hdev);
  540. hid_hw_stop(hdev);
  541. /* Shortcut potential pending reply that will never arrive */
  542. spin_lock_irqsave(&data->lock, flags);
  543. if (data->pending)
  544. complete(&data->pending->ready);
  545. spin_unlock_irqrestore(&data->lock, flags);
  546. /* Cleanup LED */
  547. picolcd_exit_leds(data);
  548. /* Clean up the framebuffer */
  549. picolcd_exit_framebuffer(data);
  550. picolcd_exit_backlight(data);
  551. picolcd_exit_lcd(data);
  552. /* Cleanup input */
  553. picolcd_exit_cir(data);
  554. picolcd_exit_keys(data);
  555. mutex_destroy(&data->mutex);
  556. /* Finally, clean up the picolcd data itself */
  557. kfree(data);
  558. }
  559. static const struct hid_device_id picolcd_devices[] = {
  560. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
  561. { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
  562. { }
  563. };
  564. MODULE_DEVICE_TABLE(hid, picolcd_devices);
  565. static struct hid_driver picolcd_driver = {
  566. .name = "hid-picolcd",
  567. .id_table = picolcd_devices,
  568. .probe = picolcd_probe,
  569. .remove = picolcd_remove,
  570. .raw_event = picolcd_raw_event,
  571. #ifdef CONFIG_PM
  572. .suspend = picolcd_suspend,
  573. .resume = picolcd_resume,
  574. .reset_resume = picolcd_reset_resume,
  575. #endif
  576. };
  577. module_hid_driver(picolcd_driver);
  578. MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
  579. MODULE_LICENSE("GPL v2");