hid-picolcd_core.c 19 KB

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