hid-picolcd_fb.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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/vmalloc.h>
  21. #include "usbhid/usbhid.h"
  22. #include <linux/usb.h>
  23. #include <linux/fb.h>
  24. #include <linux/module.h>
  25. #include "hid-picolcd.h"
  26. /* Framebuffer
  27. *
  28. * The PicoLCD use a Topway LCD module of 256x64 pixel
  29. * This display area is tiled over 4 controllers with 8 tiles
  30. * each. Each tile has 8x64 pixel, each data byte representing
  31. * a 1-bit wide vertical line of the tile.
  32. *
  33. * The display can be updated at a tile granularity.
  34. *
  35. * Chip 1 Chip 2 Chip 3 Chip 4
  36. * +----------------+----------------+----------------+----------------+
  37. * | Tile 1 | Tile 1 | Tile 1 | Tile 1 |
  38. * +----------------+----------------+----------------+----------------+
  39. * | Tile 2 | Tile 2 | Tile 2 | Tile 2 |
  40. * +----------------+----------------+----------------+----------------+
  41. * ...
  42. * +----------------+----------------+----------------+----------------+
  43. * | Tile 8 | Tile 8 | Tile 8 | Tile 8 |
  44. * +----------------+----------------+----------------+----------------+
  45. */
  46. #define PICOLCDFB_NAME "picolcdfb"
  47. #define PICOLCDFB_WIDTH (256)
  48. #define PICOLCDFB_HEIGHT (64)
  49. #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
  50. #define PICOLCDFB_UPDATE_RATE_LIMIT 10
  51. #define PICOLCDFB_UPDATE_RATE_DEFAULT 2
  52. /* Framebuffer visual structures */
  53. static const struct fb_fix_screeninfo picolcdfb_fix = {
  54. .id = PICOLCDFB_NAME,
  55. .type = FB_TYPE_PACKED_PIXELS,
  56. .visual = FB_VISUAL_MONO01,
  57. .xpanstep = 0,
  58. .ypanstep = 0,
  59. .ywrapstep = 0,
  60. .line_length = PICOLCDFB_WIDTH / 8,
  61. .accel = FB_ACCEL_NONE,
  62. };
  63. static const struct fb_var_screeninfo picolcdfb_var = {
  64. .xres = PICOLCDFB_WIDTH,
  65. .yres = PICOLCDFB_HEIGHT,
  66. .xres_virtual = PICOLCDFB_WIDTH,
  67. .yres_virtual = PICOLCDFB_HEIGHT,
  68. .width = 103,
  69. .height = 26,
  70. .bits_per_pixel = 1,
  71. .grayscale = 1,
  72. .red = {
  73. .offset = 0,
  74. .length = 1,
  75. .msb_right = 0,
  76. },
  77. .green = {
  78. .offset = 0,
  79. .length = 1,
  80. .msb_right = 0,
  81. },
  82. .blue = {
  83. .offset = 0,
  84. .length = 1,
  85. .msb_right = 0,
  86. },
  87. .transp = {
  88. .offset = 0,
  89. .length = 0,
  90. .msb_right = 0,
  91. },
  92. };
  93. /* Send a given tile to PicoLCD */
  94. static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
  95. int chip, int tile)
  96. {
  97. struct hid_report *report1, *report2;
  98. unsigned long flags;
  99. u8 *tdata;
  100. int i;
  101. report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, data->hdev);
  102. if (!report1 || report1->maxfield != 1)
  103. return -ENODEV;
  104. report2 = picolcd_out_report(REPORT_LCD_DATA, data->hdev);
  105. if (!report2 || report2->maxfield != 1)
  106. return -ENODEV;
  107. spin_lock_irqsave(&data->lock, flags);
  108. if ((data->status & PICOLCD_FAILED)) {
  109. spin_unlock_irqrestore(&data->lock, flags);
  110. return -ENODEV;
  111. }
  112. hid_set_field(report1->field[0], 0, chip << 2);
  113. hid_set_field(report1->field[0], 1, 0x02);
  114. hid_set_field(report1->field[0], 2, 0x00);
  115. hid_set_field(report1->field[0], 3, 0x00);
  116. hid_set_field(report1->field[0], 4, 0xb8 | tile);
  117. hid_set_field(report1->field[0], 5, 0x00);
  118. hid_set_field(report1->field[0], 6, 0x00);
  119. hid_set_field(report1->field[0], 7, 0x40);
  120. hid_set_field(report1->field[0], 8, 0x00);
  121. hid_set_field(report1->field[0], 9, 0x00);
  122. hid_set_field(report1->field[0], 10, 32);
  123. hid_set_field(report2->field[0], 0, (chip << 2) | 0x01);
  124. hid_set_field(report2->field[0], 1, 0x00);
  125. hid_set_field(report2->field[0], 2, 0x00);
  126. hid_set_field(report2->field[0], 3, 32);
  127. tdata = vbitmap + (tile * 4 + chip) * 64;
  128. for (i = 0; i < 64; i++)
  129. if (i < 32)
  130. hid_set_field(report1->field[0], 11 + i, tdata[i]);
  131. else
  132. hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
  133. usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
  134. usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
  135. spin_unlock_irqrestore(&data->lock, flags);
  136. return 0;
  137. }
  138. /* Translate a single tile*/
  139. static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
  140. int chip, int tile)
  141. {
  142. int i, b, changed = 0;
  143. u8 tdata[64];
  144. u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
  145. if (bpp == 1) {
  146. for (b = 7; b >= 0; b--) {
  147. const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
  148. for (i = 0; i < 64; i++) {
  149. tdata[i] <<= 1;
  150. tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
  151. }
  152. }
  153. } else if (bpp == 8) {
  154. for (b = 7; b >= 0; b--) {
  155. const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
  156. for (i = 0; i < 64; i++) {
  157. tdata[i] <<= 1;
  158. tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
  159. }
  160. }
  161. } else {
  162. /* Oops, we should never get here! */
  163. WARN_ON(1);
  164. return 0;
  165. }
  166. for (i = 0; i < 64; i++)
  167. if (tdata[i] != vdata[i]) {
  168. changed = 1;
  169. vdata[i] = tdata[i];
  170. }
  171. return changed;
  172. }
  173. void picolcd_fb_refresh(struct picolcd_data *data)
  174. {
  175. if (data->fb_info)
  176. schedule_delayed_work(&data->fb_info->deferred_work, 0);
  177. }
  178. /* Reconfigure LCD display */
  179. int picolcd_fb_reset(struct picolcd_data *data, int clear)
  180. {
  181. struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
  182. struct picolcd_fb_data *fbdata = data->fb_info->par;
  183. int i, j;
  184. unsigned long flags;
  185. static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
  186. if (!report || report->maxfield != 1)
  187. return -ENODEV;
  188. spin_lock_irqsave(&data->lock, flags);
  189. for (i = 0; i < 4; i++) {
  190. for (j = 0; j < report->field[0]->maxusage; j++)
  191. if (j == 0)
  192. hid_set_field(report->field[0], j, i << 2);
  193. else if (j < sizeof(mapcmd))
  194. hid_set_field(report->field[0], j, mapcmd[j]);
  195. else
  196. hid_set_field(report->field[0], j, 0);
  197. usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  198. }
  199. spin_unlock_irqrestore(&data->lock, flags);
  200. if (clear) {
  201. memset(fbdata->vbitmap, 0, PICOLCDFB_SIZE);
  202. memset(fbdata->bitmap, 0, PICOLCDFB_SIZE*fbdata->bpp);
  203. }
  204. fbdata->force = 1;
  205. /* schedule first output of framebuffer */
  206. if (fbdata->ready)
  207. schedule_delayed_work(&data->fb_info->deferred_work, 0);
  208. else
  209. fbdata->ready = 1;
  210. return 0;
  211. }
  212. /* Update fb_vbitmap from the screen_base and send changed tiles to device */
  213. static void picolcd_fb_update(struct fb_info *info)
  214. {
  215. int chip, tile, n;
  216. unsigned long flags;
  217. struct picolcd_fb_data *fbdata = info->par;
  218. struct picolcd_data *data;
  219. mutex_lock(&info->lock);
  220. spin_lock_irqsave(&fbdata->lock, flags);
  221. if (!fbdata->ready && fbdata->picolcd)
  222. picolcd_fb_reset(fbdata->picolcd, 0);
  223. spin_unlock_irqrestore(&fbdata->lock, flags);
  224. /*
  225. * Translate the framebuffer into the format needed by the PicoLCD.
  226. * See display layout above.
  227. * Do this one tile after the other and push those tiles that changed.
  228. *
  229. * Wait for our IO to complete as otherwise we might flood the queue!
  230. */
  231. n = 0;
  232. for (chip = 0; chip < 4; chip++)
  233. for (tile = 0; tile < 8; tile++) {
  234. if (!fbdata->force && !picolcd_fb_update_tile(
  235. fbdata->vbitmap, fbdata->bitmap,
  236. fbdata->bpp, chip, tile))
  237. continue;
  238. n += 2;
  239. if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
  240. spin_lock_irqsave(&fbdata->lock, flags);
  241. data = fbdata->picolcd;
  242. spin_unlock_irqrestore(&fbdata->lock, flags);
  243. mutex_unlock(&info->lock);
  244. if (!data)
  245. return;
  246. usbhid_wait_io(data->hdev);
  247. mutex_lock(&info->lock);
  248. n = 0;
  249. }
  250. spin_lock_irqsave(&fbdata->lock, flags);
  251. data = fbdata->picolcd;
  252. spin_unlock_irqrestore(&fbdata->lock, flags);
  253. if (!data || picolcd_fb_send_tile(data,
  254. fbdata->vbitmap, chip, tile))
  255. goto out;
  256. }
  257. fbdata->force = false;
  258. if (n) {
  259. spin_lock_irqsave(&fbdata->lock, flags);
  260. data = fbdata->picolcd;
  261. spin_unlock_irqrestore(&fbdata->lock, flags);
  262. mutex_unlock(&info->lock);
  263. if (data)
  264. usbhid_wait_io(data->hdev);
  265. return;
  266. }
  267. out:
  268. mutex_unlock(&info->lock);
  269. }
  270. /* Stub to call the system default and update the image on the picoLCD */
  271. static void picolcd_fb_fillrect(struct fb_info *info,
  272. const struct fb_fillrect *rect)
  273. {
  274. if (!info->par)
  275. return;
  276. sys_fillrect(info, rect);
  277. schedule_delayed_work(&info->deferred_work, 0);
  278. }
  279. /* Stub to call the system default and update the image on the picoLCD */
  280. static void picolcd_fb_copyarea(struct fb_info *info,
  281. const struct fb_copyarea *area)
  282. {
  283. if (!info->par)
  284. return;
  285. sys_copyarea(info, area);
  286. schedule_delayed_work(&info->deferred_work, 0);
  287. }
  288. /* Stub to call the system default and update the image on the picoLCD */
  289. static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
  290. {
  291. if (!info->par)
  292. return;
  293. sys_imageblit(info, image);
  294. schedule_delayed_work(&info->deferred_work, 0);
  295. }
  296. /*
  297. * this is the slow path from userspace. they can seek and write to
  298. * the fb. it's inefficient to do anything less than a full screen draw
  299. */
  300. static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
  301. size_t count, loff_t *ppos)
  302. {
  303. ssize_t ret;
  304. if (!info->par)
  305. return -ENODEV;
  306. ret = fb_sys_write(info, buf, count, ppos);
  307. if (ret >= 0)
  308. schedule_delayed_work(&info->deferred_work, 0);
  309. return ret;
  310. }
  311. static int picolcd_fb_blank(int blank, struct fb_info *info)
  312. {
  313. /* We let fb notification do this for us via lcd/backlight device */
  314. return 0;
  315. }
  316. static void picolcd_fb_destroy(struct fb_info *info)
  317. {
  318. struct picolcd_fb_data *fbdata = info->par;
  319. /* make sure no work is deferred */
  320. fb_deferred_io_cleanup(info);
  321. /* No thridparty should ever unregister our framebuffer! */
  322. WARN_ON(fbdata->picolcd != NULL);
  323. vfree((u8 *)info->fix.smem_start);
  324. framebuffer_release(info);
  325. }
  326. static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  327. {
  328. __u32 bpp = var->bits_per_pixel;
  329. __u32 activate = var->activate;
  330. /* only allow 1/8 bit depth (8-bit is grayscale) */
  331. *var = picolcdfb_var;
  332. var->activate = activate;
  333. if (bpp >= 8) {
  334. var->bits_per_pixel = 8;
  335. var->red.length = 8;
  336. var->green.length = 8;
  337. var->blue.length = 8;
  338. } else {
  339. var->bits_per_pixel = 1;
  340. var->red.length = 1;
  341. var->green.length = 1;
  342. var->blue.length = 1;
  343. }
  344. return 0;
  345. }
  346. static int picolcd_set_par(struct fb_info *info)
  347. {
  348. struct picolcd_fb_data *fbdata = info->par;
  349. u8 *tmp_fb, *o_fb;
  350. if (info->var.bits_per_pixel == fbdata->bpp)
  351. return 0;
  352. /* switch between 1/8 bit depths */
  353. if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
  354. return -EINVAL;
  355. o_fb = fbdata->bitmap;
  356. tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
  357. if (!tmp_fb)
  358. return -ENOMEM;
  359. /* translate FB content to new bits-per-pixel */
  360. if (info->var.bits_per_pixel == 1) {
  361. int i, b;
  362. for (i = 0; i < PICOLCDFB_SIZE; i++) {
  363. u8 p = 0;
  364. for (b = 0; b < 8; b++) {
  365. p <<= 1;
  366. p |= o_fb[i*8+b] ? 0x01 : 0x00;
  367. }
  368. tmp_fb[i] = p;
  369. }
  370. memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
  371. info->fix.visual = FB_VISUAL_MONO01;
  372. info->fix.line_length = PICOLCDFB_WIDTH / 8;
  373. } else {
  374. int i;
  375. memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
  376. for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
  377. o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
  378. info->fix.visual = FB_VISUAL_DIRECTCOLOR;
  379. info->fix.line_length = PICOLCDFB_WIDTH;
  380. }
  381. kfree(tmp_fb);
  382. fbdata->bpp = info->var.bits_per_pixel;
  383. return 0;
  384. }
  385. /* Note this can't be const because of struct fb_info definition */
  386. static struct fb_ops picolcdfb_ops = {
  387. .owner = THIS_MODULE,
  388. .fb_destroy = picolcd_fb_destroy,
  389. .fb_read = fb_sys_read,
  390. .fb_write = picolcd_fb_write,
  391. .fb_blank = picolcd_fb_blank,
  392. .fb_fillrect = picolcd_fb_fillrect,
  393. .fb_copyarea = picolcd_fb_copyarea,
  394. .fb_imageblit = picolcd_fb_imageblit,
  395. .fb_check_var = picolcd_fb_check_var,
  396. .fb_set_par = picolcd_set_par,
  397. };
  398. /* Callback from deferred IO workqueue */
  399. static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
  400. {
  401. picolcd_fb_update(info);
  402. }
  403. static const struct fb_deferred_io picolcd_fb_defio = {
  404. .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
  405. .deferred_io = picolcd_fb_deferred_io,
  406. };
  407. /*
  408. * The "fb_update_rate" sysfs attribute
  409. */
  410. static ssize_t picolcd_fb_update_rate_show(struct device *dev,
  411. struct device_attribute *attr, char *buf)
  412. {
  413. struct picolcd_data *data = dev_get_drvdata(dev);
  414. struct picolcd_fb_data *fbdata = data->fb_info->par;
  415. unsigned i, fb_update_rate = fbdata->update_rate;
  416. size_t ret = 0;
  417. for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
  418. if (ret >= PAGE_SIZE)
  419. break;
  420. else if (i == fb_update_rate)
  421. ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
  422. else
  423. ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
  424. if (ret > 0)
  425. buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
  426. return ret;
  427. }
  428. static ssize_t picolcd_fb_update_rate_store(struct device *dev,
  429. struct device_attribute *attr, const char *buf, size_t count)
  430. {
  431. struct picolcd_data *data = dev_get_drvdata(dev);
  432. struct picolcd_fb_data *fbdata = data->fb_info->par;
  433. int i;
  434. unsigned u;
  435. if (count < 1 || count > 10)
  436. return -EINVAL;
  437. i = sscanf(buf, "%u", &u);
  438. if (i != 1)
  439. return -EINVAL;
  440. if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
  441. return -ERANGE;
  442. else if (u == 0)
  443. u = PICOLCDFB_UPDATE_RATE_DEFAULT;
  444. fbdata->update_rate = u;
  445. data->fb_info->fbdefio->delay = HZ / fbdata->update_rate;
  446. return count;
  447. }
  448. static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
  449. picolcd_fb_update_rate_store);
  450. /* initialize Framebuffer device */
  451. int picolcd_init_framebuffer(struct picolcd_data *data)
  452. {
  453. struct device *dev = &data->hdev->dev;
  454. struct fb_info *info = NULL;
  455. struct picolcd_fb_data *fbdata = NULL;
  456. int i, error = -ENOMEM;
  457. u32 *palette;
  458. /* The extra memory is:
  459. * - 256*u32 for pseudo_palette
  460. * - struct fb_deferred_io
  461. */
  462. info = framebuffer_alloc(256 * sizeof(u32) +
  463. sizeof(struct fb_deferred_io) +
  464. sizeof(struct picolcd_fb_data) +
  465. PICOLCDFB_SIZE, dev);
  466. if (info == NULL) {
  467. dev_err(dev, "failed to allocate a framebuffer\n");
  468. goto err_nomem;
  469. }
  470. info->fbdefio = info->par;
  471. *info->fbdefio = picolcd_fb_defio;
  472. info->par += sizeof(struct fb_deferred_io);
  473. palette = info->par;
  474. info->par += 256 * sizeof(u32);
  475. for (i = 0; i < 256; i++)
  476. palette[i] = i > 0 && i < 16 ? 0xff : 0;
  477. info->pseudo_palette = palette;
  478. info->fbops = &picolcdfb_ops;
  479. info->var = picolcdfb_var;
  480. info->fix = picolcdfb_fix;
  481. info->fix.smem_len = PICOLCDFB_SIZE*8;
  482. info->flags = FBINFO_FLAG_DEFAULT;
  483. fbdata = info->par;
  484. spin_lock_init(&fbdata->lock);
  485. fbdata->picolcd = data;
  486. fbdata->update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
  487. fbdata->bpp = picolcdfb_var.bits_per_pixel;
  488. fbdata->force = 1;
  489. fbdata->vbitmap = info->par + sizeof(struct picolcd_fb_data);
  490. fbdata->bitmap = vmalloc(PICOLCDFB_SIZE*8);
  491. if (fbdata->bitmap == NULL) {
  492. dev_err(dev, "can't get a free page for framebuffer\n");
  493. goto err_nomem;
  494. }
  495. info->screen_base = (char __force __iomem *)fbdata->bitmap;
  496. info->fix.smem_start = (unsigned long)fbdata->bitmap;
  497. memset(fbdata->vbitmap, 0xff, PICOLCDFB_SIZE);
  498. data->fb_info = info;
  499. error = picolcd_fb_reset(data, 1);
  500. if (error) {
  501. dev_err(dev, "failed to configure display\n");
  502. goto err_cleanup;
  503. }
  504. error = device_create_file(dev, &dev_attr_fb_update_rate);
  505. if (error) {
  506. dev_err(dev, "failed to create sysfs attributes\n");
  507. goto err_cleanup;
  508. }
  509. fb_deferred_io_init(info);
  510. error = register_framebuffer(info);
  511. if (error) {
  512. dev_err(dev, "failed to register framebuffer\n");
  513. goto err_sysfs;
  514. }
  515. return 0;
  516. err_sysfs:
  517. device_remove_file(dev, &dev_attr_fb_update_rate);
  518. fb_deferred_io_cleanup(info);
  519. err_cleanup:
  520. data->fb_info = NULL;
  521. err_nomem:
  522. if (fbdata)
  523. vfree(fbdata->bitmap);
  524. framebuffer_release(info);
  525. return error;
  526. }
  527. void picolcd_exit_framebuffer(struct picolcd_data *data)
  528. {
  529. struct fb_info *info = data->fb_info;
  530. struct picolcd_fb_data *fbdata = info->par;
  531. unsigned long flags;
  532. device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
  533. /* disconnect framebuffer from HID dev */
  534. spin_lock_irqsave(&fbdata->lock, flags);
  535. fbdata->picolcd = NULL;
  536. spin_unlock_irqrestore(&fbdata->lock, flags);
  537. /* make sure there is no running update - thus that fbdata->picolcd
  538. * once obtained under lock is guaranteed not to get free() under
  539. * the feet of the deferred work */
  540. flush_delayed_work(&info->deferred_work);
  541. data->fb_info = NULL;
  542. unregister_framebuffer(info);
  543. }