1 /***************************************************************************
2 * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
4 * Based on Logitech G13 driver (v0.4) *
5 * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
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. *
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. *
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 ***************************************************************************/
20 #include <linux/hid.h>
21 #include <linux/vmalloc.h>
22 #include "usbhid/usbhid.h"
23 #include <linux/usb.h>
26 #include <linux/module.h>
28 #include "hid-picolcd.h"
32 * The PicoLCD use a Topway LCD module of 256x64 pixel
33 * This display area is tiled over 4 controllers with 8 tiles
34 * each. Each tile has 8x64 pixel, each data byte representing
35 * a 1-bit wide vertical line of the tile.
37 * The display can be updated at a tile granularity.
39 * Chip 1 Chip 2 Chip 3 Chip 4
40 * +----------------+----------------+----------------+----------------+
41 * | Tile 1 | Tile 1 | Tile 1 | Tile 1 |
42 * +----------------+----------------+----------------+----------------+
43 * | Tile 2 | Tile 2 | Tile 2 | Tile 2 |
44 * +----------------+----------------+----------------+----------------+
46 * +----------------+----------------+----------------+----------------+
47 * | Tile 8 | Tile 8 | Tile 8 | Tile 8 |
48 * +----------------+----------------+----------------+----------------+
50 #define PICOLCDFB_NAME "picolcdfb"
51 #define PICOLCDFB_WIDTH (256)
52 #define PICOLCDFB_HEIGHT (64)
53 #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
55 #define PICOLCDFB_UPDATE_RATE_LIMIT 10
56 #define PICOLCDFB_UPDATE_RATE_DEFAULT 2
58 /* Framebuffer visual structures */
59 static const struct fb_fix_screeninfo picolcdfb_fix
= {
61 .type
= FB_TYPE_PACKED_PIXELS
,
62 .visual
= FB_VISUAL_MONO01
,
66 .line_length
= PICOLCDFB_WIDTH
/ 8,
67 .accel
= FB_ACCEL_NONE
,
70 static const struct fb_var_screeninfo picolcdfb_var
= {
71 .xres
= PICOLCDFB_WIDTH
,
72 .yres
= PICOLCDFB_HEIGHT
,
73 .xres_virtual
= PICOLCDFB_WIDTH
,
74 .yres_virtual
= PICOLCDFB_HEIGHT
,
101 /* Send a given tile to PicoLCD */
102 static int picolcd_fb_send_tile(struct picolcd_data
*data
, u8
*vbitmap
,
105 struct hid_report
*report1
, *report2
;
110 report1
= picolcd_out_report(REPORT_LCD_CMD_DATA
, data
->hdev
);
111 if (!report1
|| report1
->maxfield
!= 1)
113 report2
= picolcd_out_report(REPORT_LCD_DATA
, data
->hdev
);
114 if (!report2
|| report2
->maxfield
!= 1)
117 spin_lock_irqsave(&data
->lock
, flags
);
118 if ((data
->status
& PICOLCD_FAILED
)) {
119 spin_unlock_irqrestore(&data
->lock
, flags
);
122 hid_set_field(report1
->field
[0], 0, chip
<< 2);
123 hid_set_field(report1
->field
[0], 1, 0x02);
124 hid_set_field(report1
->field
[0], 2, 0x00);
125 hid_set_field(report1
->field
[0], 3, 0x00);
126 hid_set_field(report1
->field
[0], 4, 0xb8 | tile
);
127 hid_set_field(report1
->field
[0], 5, 0x00);
128 hid_set_field(report1
->field
[0], 6, 0x00);
129 hid_set_field(report1
->field
[0], 7, 0x40);
130 hid_set_field(report1
->field
[0], 8, 0x00);
131 hid_set_field(report1
->field
[0], 9, 0x00);
132 hid_set_field(report1
->field
[0], 10, 32);
134 hid_set_field(report2
->field
[0], 0, (chip
<< 2) | 0x01);
135 hid_set_field(report2
->field
[0], 1, 0x00);
136 hid_set_field(report2
->field
[0], 2, 0x00);
137 hid_set_field(report2
->field
[0], 3, 32);
139 tdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
140 for (i
= 0; i
< 64; i
++)
142 hid_set_field(report1
->field
[0], 11 + i
, tdata
[i
]);
144 hid_set_field(report2
->field
[0], 4 + i
- 32, tdata
[i
]);
146 usbhid_submit_report(data
->hdev
, report1
, USB_DIR_OUT
);
147 usbhid_submit_report(data
->hdev
, report2
, USB_DIR_OUT
);
148 spin_unlock_irqrestore(&data
->lock
, flags
);
152 /* Translate a single tile*/
153 static int picolcd_fb_update_tile(u8
*vbitmap
, const u8
*bitmap
, int bpp
,
156 int i
, b
, changed
= 0;
158 u8
*vdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
161 for (b
= 7; b
>= 0; b
--) {
162 const u8
*bdata
= bitmap
+ tile
* 256 + chip
* 8 + b
* 32;
163 for (i
= 0; i
< 64; i
++) {
165 tdata
[i
] |= (bdata
[i
/8] >> (i
% 8)) & 0x01;
168 } else if (bpp
== 8) {
169 for (b
= 7; b
>= 0; b
--) {
170 const u8
*bdata
= bitmap
+ (tile
* 256 + chip
* 8 + b
* 32) * 8;
171 for (i
= 0; i
< 64; i
++) {
173 tdata
[i
] |= (bdata
[i
] & 0x80) ? 0x01 : 0x00;
177 /* Oops, we should never get here! */
182 for (i
= 0; i
< 64; i
++)
183 if (tdata
[i
] != vdata
[i
]) {
190 void picolcd_fb_refresh(struct picolcd_data
*data
)
193 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
196 /* Reconfigure LCD display */
197 int picolcd_fb_reset(struct picolcd_data
*data
, int clear
)
199 struct hid_report
*report
= picolcd_out_report(REPORT_LCD_CMD
, data
->hdev
);
200 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
203 static const u8 mapcmd
[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
205 if (!report
|| report
->maxfield
!= 1)
208 spin_lock_irqsave(&data
->lock
, flags
);
209 for (i
= 0; i
< 4; i
++) {
210 for (j
= 0; j
< report
->field
[0]->maxusage
; j
++)
212 hid_set_field(report
->field
[0], j
, i
<< 2);
213 else if (j
< sizeof(mapcmd
))
214 hid_set_field(report
->field
[0], j
, mapcmd
[j
]);
216 hid_set_field(report
->field
[0], j
, 0);
217 usbhid_submit_report(data
->hdev
, report
, USB_DIR_OUT
);
219 spin_unlock_irqrestore(&data
->lock
, flags
);
222 memset(fbdata
->vbitmap
, 0, PICOLCDFB_SIZE
);
223 memset(fbdata
->bitmap
, 0, PICOLCDFB_SIZE
*fbdata
->bpp
);
227 /* schedule first output of framebuffer */
229 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
236 /* Update fb_vbitmap from the screen_base and send changed tiles to device */
237 static void picolcd_fb_update(struct fb_info
*info
)
241 struct picolcd_fb_data
*fbdata
= info
->par
;
242 struct picolcd_data
*data
;
244 mutex_lock(&info
->lock
);
246 spin_lock_irqsave(&fbdata
->lock
, flags
);
247 if (!fbdata
->ready
&& fbdata
->picolcd
)
248 picolcd_fb_reset(fbdata
->picolcd
, 0);
249 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
252 * Translate the framebuffer into the format needed by the PicoLCD.
253 * See display layout above.
254 * Do this one tile after the other and push those tiles that changed.
256 * Wait for our IO to complete as otherwise we might flood the queue!
259 for (chip
= 0; chip
< 4; chip
++)
260 for (tile
= 0; tile
< 8; tile
++) {
261 if (!fbdata
->force
&& !picolcd_fb_update_tile(
262 fbdata
->vbitmap
, fbdata
->bitmap
,
263 fbdata
->bpp
, chip
, tile
))
266 if (n
>= HID_OUTPUT_FIFO_SIZE
/ 2) {
267 spin_lock_irqsave(&fbdata
->lock
, flags
);
268 data
= fbdata
->picolcd
;
269 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
270 mutex_unlock(&info
->lock
);
273 usbhid_wait_io(data
->hdev
);
274 mutex_lock(&info
->lock
);
277 spin_lock_irqsave(&fbdata
->lock
, flags
);
278 data
= fbdata
->picolcd
;
279 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
280 if (!data
|| picolcd_fb_send_tile(data
,
281 fbdata
->vbitmap
, chip
, tile
))
284 fbdata
->force
= false;
286 spin_lock_irqsave(&fbdata
->lock
, flags
);
287 data
= fbdata
->picolcd
;
288 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
289 mutex_unlock(&info
->lock
);
291 usbhid_wait_io(data
->hdev
);
295 mutex_unlock(&info
->lock
);
298 /* Stub to call the system default and update the image on the picoLCD */
299 static void picolcd_fb_fillrect(struct fb_info
*info
,
300 const struct fb_fillrect
*rect
)
304 sys_fillrect(info
, rect
);
306 schedule_delayed_work(&info
->deferred_work
, 0);
309 /* Stub to call the system default and update the image on the picoLCD */
310 static void picolcd_fb_copyarea(struct fb_info
*info
,
311 const struct fb_copyarea
*area
)
315 sys_copyarea(info
, area
);
317 schedule_delayed_work(&info
->deferred_work
, 0);
320 /* Stub to call the system default and update the image on the picoLCD */
321 static void picolcd_fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
325 sys_imageblit(info
, image
);
327 schedule_delayed_work(&info
->deferred_work
, 0);
331 * this is the slow path from userspace. they can seek and write to
332 * the fb. it's inefficient to do anything less than a full screen draw
334 static ssize_t
picolcd_fb_write(struct fb_info
*info
, const char __user
*buf
,
335 size_t count
, loff_t
*ppos
)
340 ret
= fb_sys_write(info
, buf
, count
, ppos
);
342 schedule_delayed_work(&info
->deferred_work
, 0);
346 static int picolcd_fb_blank(int blank
, struct fb_info
*info
)
348 /* We let fb notification do this for us via lcd/backlight device */
352 static void picolcd_fb_destroy(struct fb_info
*info
)
354 struct picolcd_fb_data
*fbdata
= info
->par
;
356 /* make sure no work is deferred */
357 fb_deferred_io_cleanup(info
);
359 /* No thridparty should ever unregister our framebuffer! */
360 WARN_ON(fbdata
->picolcd
!= NULL
);
362 vfree((u8
*)info
->fix
.smem_start
);
363 framebuffer_release(info
);
366 static int picolcd_fb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
368 __u32 bpp
= var
->bits_per_pixel
;
369 __u32 activate
= var
->activate
;
371 /* only allow 1/8 bit depth (8-bit is grayscale) */
372 *var
= picolcdfb_var
;
373 var
->activate
= activate
;
375 var
->bits_per_pixel
= 8;
377 var
->green
.length
= 8;
378 var
->blue
.length
= 8;
380 var
->bits_per_pixel
= 1;
382 var
->green
.length
= 1;
383 var
->blue
.length
= 1;
388 static int picolcd_set_par(struct fb_info
*info
)
390 struct picolcd_fb_data
*fbdata
= info
->par
;
392 if (info
->var
.bits_per_pixel
== fbdata
->bpp
)
394 /* switch between 1/8 bit depths */
395 if (info
->var
.bits_per_pixel
!= 1 && info
->var
.bits_per_pixel
!= 8)
398 o_fb
= fbdata
->bitmap
;
399 tmp_fb
= kmalloc(PICOLCDFB_SIZE
*info
->var
.bits_per_pixel
, GFP_KERNEL
);
403 /* translate FB content to new bits-per-pixel */
404 if (info
->var
.bits_per_pixel
== 1) {
406 for (i
= 0; i
< PICOLCDFB_SIZE
; i
++) {
408 for (b
= 0; b
< 8; b
++) {
410 p
|= o_fb
[i
*8+b
] ? 0x01 : 0x00;
414 memcpy(o_fb
, tmp_fb
, PICOLCDFB_SIZE
);
415 info
->fix
.visual
= FB_VISUAL_MONO01
;
416 info
->fix
.line_length
= PICOLCDFB_WIDTH
/ 8;
419 memcpy(tmp_fb
, o_fb
, PICOLCDFB_SIZE
);
420 for (i
= 0; i
< PICOLCDFB_SIZE
* 8; i
++)
421 o_fb
[i
] = tmp_fb
[i
/8] & (0x01 << (7 - i
% 8)) ? 0xff : 0x00;
422 info
->fix
.visual
= FB_VISUAL_DIRECTCOLOR
;
423 info
->fix
.line_length
= PICOLCDFB_WIDTH
;
427 fbdata
->bpp
= info
->var
.bits_per_pixel
;
431 /* Note this can't be const because of struct fb_info definition */
432 static struct fb_ops picolcdfb_ops
= {
433 .owner
= THIS_MODULE
,
434 .fb_destroy
= picolcd_fb_destroy
,
435 .fb_read
= fb_sys_read
,
436 .fb_write
= picolcd_fb_write
,
437 .fb_blank
= picolcd_fb_blank
,
438 .fb_fillrect
= picolcd_fb_fillrect
,
439 .fb_copyarea
= picolcd_fb_copyarea
,
440 .fb_imageblit
= picolcd_fb_imageblit
,
441 .fb_check_var
= picolcd_fb_check_var
,
442 .fb_set_par
= picolcd_set_par
,
446 /* Callback from deferred IO workqueue */
447 static void picolcd_fb_deferred_io(struct fb_info
*info
, struct list_head
*pagelist
)
449 picolcd_fb_update(info
);
452 static const struct fb_deferred_io picolcd_fb_defio
= {
453 .delay
= HZ
/ PICOLCDFB_UPDATE_RATE_DEFAULT
,
454 .deferred_io
= picolcd_fb_deferred_io
,
459 * The "fb_update_rate" sysfs attribute
461 static ssize_t
picolcd_fb_update_rate_show(struct device
*dev
,
462 struct device_attribute
*attr
, char *buf
)
464 struct picolcd_data
*data
= dev_get_drvdata(dev
);
465 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
466 unsigned i
, fb_update_rate
= fbdata
->update_rate
;
469 for (i
= 1; i
<= PICOLCDFB_UPDATE_RATE_LIMIT
; i
++)
470 if (ret
>= PAGE_SIZE
)
472 else if (i
== fb_update_rate
)
473 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "[%u] ", i
);
475 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "%u ", i
);
477 buf
[min(ret
, (size_t)PAGE_SIZE
)-1] = '\n';
481 static ssize_t
picolcd_fb_update_rate_store(struct device
*dev
,
482 struct device_attribute
*attr
, const char *buf
, size_t count
)
484 struct picolcd_data
*data
= dev_get_drvdata(dev
);
485 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
489 if (count
< 1 || count
> 10)
492 i
= sscanf(buf
, "%u", &u
);
496 if (u
> PICOLCDFB_UPDATE_RATE_LIMIT
)
499 u
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
501 fbdata
->update_rate
= u
;
502 data
->fb_info
->fbdefio
->delay
= HZ
/ fbdata
->update_rate
;
506 static DEVICE_ATTR(fb_update_rate
, 0666, picolcd_fb_update_rate_show
,
507 picolcd_fb_update_rate_store
);
509 /* initialize Framebuffer device */
510 int picolcd_init_framebuffer(struct picolcd_data
*data
)
512 struct device
*dev
= &data
->hdev
->dev
;
513 struct fb_info
*info
= NULL
;
514 struct picolcd_fb_data
*fbdata
= NULL
;
515 int i
, error
= -ENOMEM
;
518 /* The extra memory is:
519 * - 256*u32 for pseudo_palette
520 * - struct fb_deferred_io
522 info
= framebuffer_alloc(256 * sizeof(u32
) +
523 sizeof(struct fb_deferred_io
) +
524 sizeof(struct picolcd_fb_data
) +
525 PICOLCDFB_SIZE
, dev
);
527 dev_err(dev
, "failed to allocate a framebuffer\n");
531 info
->fbdefio
= info
->par
;
532 *info
->fbdefio
= picolcd_fb_defio
;
533 info
->par
+= sizeof(struct fb_deferred_io
);
535 info
->par
+= 256 * sizeof(u32
);
536 for (i
= 0; i
< 256; i
++)
537 palette
[i
] = i
> 0 && i
< 16 ? 0xff : 0;
538 info
->pseudo_palette
= palette
;
539 info
->fbops
= &picolcdfb_ops
;
540 info
->var
= picolcdfb_var
;
541 info
->fix
= picolcdfb_fix
;
542 info
->fix
.smem_len
= PICOLCDFB_SIZE
*8;
543 info
->flags
= FBINFO_FLAG_DEFAULT
;
546 spin_lock_init(&fbdata
->lock
);
547 fbdata
->picolcd
= data
;
548 fbdata
->update_rate
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
549 fbdata
->bpp
= picolcdfb_var
.bits_per_pixel
;
551 fbdata
->vbitmap
= info
->par
+ sizeof(struct picolcd_fb_data
);
552 fbdata
->bitmap
= vmalloc(PICOLCDFB_SIZE
*8);
553 if (fbdata
->bitmap
== NULL
) {
554 dev_err(dev
, "can't get a free page for framebuffer\n");
557 info
->screen_base
= (char __force __iomem
*)fbdata
->bitmap
;
558 info
->fix
.smem_start
= (unsigned long)fbdata
->bitmap
;
559 memset(fbdata
->vbitmap
, 0xff, PICOLCDFB_SIZE
);
560 data
->fb_info
= info
;
562 error
= picolcd_fb_reset(data
, 1);
564 dev_err(dev
, "failed to configure display\n");
568 error
= device_create_file(dev
, &dev_attr_fb_update_rate
);
570 dev_err(dev
, "failed to create sysfs attributes\n");
574 fb_deferred_io_init(info
);
575 error
= register_framebuffer(info
);
577 dev_err(dev
, "failed to register framebuffer\n");
583 device_remove_file(dev
, &dev_attr_fb_update_rate
);
584 fb_deferred_io_cleanup(info
);
586 data
->fb_info
= NULL
;
590 vfree(fbdata
->bitmap
);
591 framebuffer_release(info
);
595 void picolcd_exit_framebuffer(struct picolcd_data
*data
)
597 struct fb_info
*info
= data
->fb_info
;
598 struct picolcd_fb_data
*fbdata
= info
->par
;
601 device_remove_file(&data
->hdev
->dev
, &dev_attr_fb_update_rate
);
603 /* disconnect framebuffer from HID dev */
604 spin_lock_irqsave(&fbdata
->lock
, flags
);
605 fbdata
->picolcd
= NULL
;
606 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
608 /* make sure there is no running update - thus that fbdata->picolcd
609 * once obtained under lock is guaranteed not to get free() under
610 * the feet of the deferred work */
611 flush_delayed_work(&info
->deferred_work
);
613 data
->fb_info
= NULL
;
614 unregister_framebuffer(info
);