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>
24 #include <linux/module.h>
26 #include "hid-picolcd.h"
30 * The PicoLCD use a Topway LCD module of 256x64 pixel
31 * This display area is tiled over 4 controllers with 8 tiles
32 * each. Each tile has 8x64 pixel, each data byte representing
33 * a 1-bit wide vertical line of the tile.
35 * The display can be updated at a tile granularity.
37 * Chip 1 Chip 2 Chip 3 Chip 4
38 * +----------------+----------------+----------------+----------------+
39 * | Tile 1 | Tile 1 | Tile 1 | Tile 1 |
40 * +----------------+----------------+----------------+----------------+
41 * | Tile 2 | Tile 2 | Tile 2 | Tile 2 |
42 * +----------------+----------------+----------------+----------------+
44 * +----------------+----------------+----------------+----------------+
45 * | Tile 8 | Tile 8 | Tile 8 | Tile 8 |
46 * +----------------+----------------+----------------+----------------+
48 #define PICOLCDFB_NAME "picolcdfb"
49 #define PICOLCDFB_WIDTH (256)
50 #define PICOLCDFB_HEIGHT (64)
51 #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
53 #define PICOLCDFB_UPDATE_RATE_LIMIT 10
54 #define PICOLCDFB_UPDATE_RATE_DEFAULT 2
56 /* Framebuffer visual structures */
57 static const struct fb_fix_screeninfo picolcdfb_fix
= {
59 .type
= FB_TYPE_PACKED_PIXELS
,
60 .visual
= FB_VISUAL_MONO01
,
64 .line_length
= PICOLCDFB_WIDTH
/ 8,
65 .accel
= FB_ACCEL_NONE
,
68 static const struct fb_var_screeninfo picolcdfb_var
= {
69 .xres
= PICOLCDFB_WIDTH
,
70 .yres
= PICOLCDFB_HEIGHT
,
71 .xres_virtual
= PICOLCDFB_WIDTH
,
72 .yres_virtual
= PICOLCDFB_HEIGHT
,
99 /* Send a given tile to PicoLCD */
100 static int picolcd_fb_send_tile(struct picolcd_data
*data
, u8
*vbitmap
,
103 struct hid_report
*report1
, *report2
;
108 report1
= picolcd_out_report(REPORT_LCD_CMD_DATA
, data
->hdev
);
109 if (!report1
|| report1
->maxfield
!= 1)
111 report2
= picolcd_out_report(REPORT_LCD_DATA
, data
->hdev
);
112 if (!report2
|| report2
->maxfield
!= 1)
115 spin_lock_irqsave(&data
->lock
, flags
);
116 if ((data
->status
& PICOLCD_FAILED
)) {
117 spin_unlock_irqrestore(&data
->lock
, flags
);
120 hid_set_field(report1
->field
[0], 0, chip
<< 2);
121 hid_set_field(report1
->field
[0], 1, 0x02);
122 hid_set_field(report1
->field
[0], 2, 0x00);
123 hid_set_field(report1
->field
[0], 3, 0x00);
124 hid_set_field(report1
->field
[0], 4, 0xb8 | tile
);
125 hid_set_field(report1
->field
[0], 5, 0x00);
126 hid_set_field(report1
->field
[0], 6, 0x00);
127 hid_set_field(report1
->field
[0], 7, 0x40);
128 hid_set_field(report1
->field
[0], 8, 0x00);
129 hid_set_field(report1
->field
[0], 9, 0x00);
130 hid_set_field(report1
->field
[0], 10, 32);
132 hid_set_field(report2
->field
[0], 0, (chip
<< 2) | 0x01);
133 hid_set_field(report2
->field
[0], 1, 0x00);
134 hid_set_field(report2
->field
[0], 2, 0x00);
135 hid_set_field(report2
->field
[0], 3, 32);
137 tdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
138 for (i
= 0; i
< 64; i
++)
140 hid_set_field(report1
->field
[0], 11 + i
, tdata
[i
]);
142 hid_set_field(report2
->field
[0], 4 + i
- 32, tdata
[i
]);
144 hid_hw_request(data
->hdev
, report1
, HID_REQ_SET_REPORT
);
145 hid_hw_request(data
->hdev
, report2
, HID_REQ_SET_REPORT
);
146 spin_unlock_irqrestore(&data
->lock
, flags
);
150 /* Translate a single tile*/
151 static int picolcd_fb_update_tile(u8
*vbitmap
, const u8
*bitmap
, int bpp
,
154 int i
, b
, changed
= 0;
156 u8
*vdata
= vbitmap
+ (tile
* 4 + chip
) * 64;
159 for (b
= 7; b
>= 0; b
--) {
160 const u8
*bdata
= bitmap
+ tile
* 256 + chip
* 8 + b
* 32;
161 for (i
= 0; i
< 64; i
++) {
163 tdata
[i
] |= (bdata
[i
/8] >> (i
% 8)) & 0x01;
166 } else if (bpp
== 8) {
167 for (b
= 7; b
>= 0; b
--) {
168 const u8
*bdata
= bitmap
+ (tile
* 256 + chip
* 8 + b
* 32) * 8;
169 for (i
= 0; i
< 64; i
++) {
171 tdata
[i
] |= (bdata
[i
] & 0x80) ? 0x01 : 0x00;
175 /* Oops, we should never get here! */
180 for (i
= 0; i
< 64; i
++)
181 if (tdata
[i
] != vdata
[i
]) {
188 void picolcd_fb_refresh(struct picolcd_data
*data
)
191 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
194 /* Reconfigure LCD display */
195 int picolcd_fb_reset(struct picolcd_data
*data
, int clear
)
197 struct hid_report
*report
= picolcd_out_report(REPORT_LCD_CMD
, data
->hdev
);
198 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
201 static const u8 mapcmd
[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
203 if (!report
|| report
->maxfield
!= 1)
206 spin_lock_irqsave(&data
->lock
, flags
);
207 for (i
= 0; i
< 4; i
++) {
208 for (j
= 0; j
< report
->field
[0]->maxusage
; j
++)
210 hid_set_field(report
->field
[0], j
, i
<< 2);
211 else if (j
< sizeof(mapcmd
))
212 hid_set_field(report
->field
[0], j
, mapcmd
[j
]);
214 hid_set_field(report
->field
[0], j
, 0);
215 hid_hw_request(data
->hdev
, report
, HID_REQ_SET_REPORT
);
217 spin_unlock_irqrestore(&data
->lock
, flags
);
220 memset(fbdata
->vbitmap
, 0, PICOLCDFB_SIZE
);
221 memset(fbdata
->bitmap
, 0, PICOLCDFB_SIZE
*fbdata
->bpp
);
225 /* schedule first output of framebuffer */
227 schedule_delayed_work(&data
->fb_info
->deferred_work
, 0);
234 /* Update fb_vbitmap from the screen_base and send changed tiles to device */
235 static void picolcd_fb_update(struct fb_info
*info
)
239 struct picolcd_fb_data
*fbdata
= info
->par
;
240 struct picolcd_data
*data
;
242 mutex_lock(&info
->lock
);
244 spin_lock_irqsave(&fbdata
->lock
, flags
);
245 if (!fbdata
->ready
&& fbdata
->picolcd
)
246 picolcd_fb_reset(fbdata
->picolcd
, 0);
247 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
250 * Translate the framebuffer into the format needed by the PicoLCD.
251 * See display layout above.
252 * Do this one tile after the other and push those tiles that changed.
254 * Wait for our IO to complete as otherwise we might flood the queue!
257 for (chip
= 0; chip
< 4; chip
++)
258 for (tile
= 0; tile
< 8; tile
++) {
259 if (!fbdata
->force
&& !picolcd_fb_update_tile(
260 fbdata
->vbitmap
, fbdata
->bitmap
,
261 fbdata
->bpp
, chip
, tile
))
264 if (n
>= HID_OUTPUT_FIFO_SIZE
/ 2) {
265 spin_lock_irqsave(&fbdata
->lock
, flags
);
266 data
= fbdata
->picolcd
;
267 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
268 mutex_unlock(&info
->lock
);
271 hid_hw_wait(data
->hdev
);
272 mutex_lock(&info
->lock
);
275 spin_lock_irqsave(&fbdata
->lock
, flags
);
276 data
= fbdata
->picolcd
;
277 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
278 if (!data
|| picolcd_fb_send_tile(data
,
279 fbdata
->vbitmap
, chip
, tile
))
282 fbdata
->force
= false;
284 spin_lock_irqsave(&fbdata
->lock
, flags
);
285 data
= fbdata
->picolcd
;
286 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
287 mutex_unlock(&info
->lock
);
289 hid_hw_wait(data
->hdev
);
293 mutex_unlock(&info
->lock
);
296 /* Stub to call the system default and update the image on the picoLCD */
297 static void picolcd_fb_fillrect(struct fb_info
*info
,
298 const struct fb_fillrect
*rect
)
302 sys_fillrect(info
, rect
);
304 schedule_delayed_work(&info
->deferred_work
, 0);
307 /* Stub to call the system default and update the image on the picoLCD */
308 static void picolcd_fb_copyarea(struct fb_info
*info
,
309 const struct fb_copyarea
*area
)
313 sys_copyarea(info
, area
);
315 schedule_delayed_work(&info
->deferred_work
, 0);
318 /* Stub to call the system default and update the image on the picoLCD */
319 static void picolcd_fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
323 sys_imageblit(info
, image
);
325 schedule_delayed_work(&info
->deferred_work
, 0);
329 * this is the slow path from userspace. they can seek and write to
330 * the fb. it's inefficient to do anything less than a full screen draw
332 static ssize_t
picolcd_fb_write(struct fb_info
*info
, const char __user
*buf
,
333 size_t count
, loff_t
*ppos
)
338 ret
= fb_sys_write(info
, buf
, count
, ppos
);
340 schedule_delayed_work(&info
->deferred_work
, 0);
344 static int picolcd_fb_blank(int blank
, struct fb_info
*info
)
346 /* We let fb notification do this for us via lcd/backlight device */
350 static void picolcd_fb_destroy(struct fb_info
*info
)
352 struct picolcd_fb_data
*fbdata
= info
->par
;
354 /* make sure no work is deferred */
355 fb_deferred_io_cleanup(info
);
357 /* No thridparty should ever unregister our framebuffer! */
358 WARN_ON(fbdata
->picolcd
!= NULL
);
360 vfree((u8
*)info
->fix
.smem_start
);
361 framebuffer_release(info
);
364 static int picolcd_fb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
366 __u32 bpp
= var
->bits_per_pixel
;
367 __u32 activate
= var
->activate
;
369 /* only allow 1/8 bit depth (8-bit is grayscale) */
370 *var
= picolcdfb_var
;
371 var
->activate
= activate
;
373 var
->bits_per_pixel
= 8;
375 var
->green
.length
= 8;
376 var
->blue
.length
= 8;
378 var
->bits_per_pixel
= 1;
380 var
->green
.length
= 1;
381 var
->blue
.length
= 1;
386 static int picolcd_set_par(struct fb_info
*info
)
388 struct picolcd_fb_data
*fbdata
= info
->par
;
390 if (info
->var
.bits_per_pixel
== fbdata
->bpp
)
392 /* switch between 1/8 bit depths */
393 if (info
->var
.bits_per_pixel
!= 1 && info
->var
.bits_per_pixel
!= 8)
396 o_fb
= fbdata
->bitmap
;
397 tmp_fb
= kmalloc_array(PICOLCDFB_SIZE
, info
->var
.bits_per_pixel
,
402 /* translate FB content to new bits-per-pixel */
403 if (info
->var
.bits_per_pixel
== 1) {
405 for (i
= 0; i
< PICOLCDFB_SIZE
; i
++) {
407 for (b
= 0; b
< 8; b
++) {
409 p
|= o_fb
[i
*8+b
] ? 0x01 : 0x00;
413 memcpy(o_fb
, tmp_fb
, PICOLCDFB_SIZE
);
414 info
->fix
.visual
= FB_VISUAL_MONO01
;
415 info
->fix
.line_length
= PICOLCDFB_WIDTH
/ 8;
418 memcpy(tmp_fb
, o_fb
, PICOLCDFB_SIZE
);
419 for (i
= 0; i
< PICOLCDFB_SIZE
* 8; i
++)
420 o_fb
[i
] = tmp_fb
[i
/8] & (0x01 << (7 - i
% 8)) ? 0xff : 0x00;
421 info
->fix
.visual
= FB_VISUAL_DIRECTCOLOR
;
422 info
->fix
.line_length
= PICOLCDFB_WIDTH
;
426 fbdata
->bpp
= info
->var
.bits_per_pixel
;
430 /* Note this can't be const because of struct fb_info definition */
431 static struct fb_ops picolcdfb_ops
= {
432 .owner
= THIS_MODULE
,
433 .fb_destroy
= picolcd_fb_destroy
,
434 .fb_read
= fb_sys_read
,
435 .fb_write
= picolcd_fb_write
,
436 .fb_blank
= picolcd_fb_blank
,
437 .fb_fillrect
= picolcd_fb_fillrect
,
438 .fb_copyarea
= picolcd_fb_copyarea
,
439 .fb_imageblit
= picolcd_fb_imageblit
,
440 .fb_check_var
= picolcd_fb_check_var
,
441 .fb_set_par
= picolcd_set_par
,
445 /* Callback from deferred IO workqueue */
446 static void picolcd_fb_deferred_io(struct fb_info
*info
, struct list_head
*pagelist
)
448 picolcd_fb_update(info
);
451 static const struct fb_deferred_io picolcd_fb_defio
= {
452 .delay
= HZ
/ PICOLCDFB_UPDATE_RATE_DEFAULT
,
453 .deferred_io
= picolcd_fb_deferred_io
,
458 * The "fb_update_rate" sysfs attribute
460 static ssize_t
picolcd_fb_update_rate_show(struct device
*dev
,
461 struct device_attribute
*attr
, char *buf
)
463 struct picolcd_data
*data
= dev_get_drvdata(dev
);
464 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
465 unsigned i
, fb_update_rate
= fbdata
->update_rate
;
468 for (i
= 1; i
<= PICOLCDFB_UPDATE_RATE_LIMIT
; i
++)
469 if (ret
>= PAGE_SIZE
)
471 else if (i
== fb_update_rate
)
472 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "[%u] ", i
);
474 ret
+= snprintf(buf
+ret
, PAGE_SIZE
-ret
, "%u ", i
);
476 buf
[min(ret
, (size_t)PAGE_SIZE
)-1] = '\n';
480 static ssize_t
picolcd_fb_update_rate_store(struct device
*dev
,
481 struct device_attribute
*attr
, const char *buf
, size_t count
)
483 struct picolcd_data
*data
= dev_get_drvdata(dev
);
484 struct picolcd_fb_data
*fbdata
= data
->fb_info
->par
;
488 if (count
< 1 || count
> 10)
491 i
= sscanf(buf
, "%u", &u
);
495 if (u
> PICOLCDFB_UPDATE_RATE_LIMIT
)
498 u
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
500 fbdata
->update_rate
= u
;
501 data
->fb_info
->fbdefio
->delay
= HZ
/ fbdata
->update_rate
;
505 static DEVICE_ATTR(fb_update_rate
, 0664, picolcd_fb_update_rate_show
,
506 picolcd_fb_update_rate_store
);
508 /* initialize Framebuffer device */
509 int picolcd_init_framebuffer(struct picolcd_data
*data
)
511 struct device
*dev
= &data
->hdev
->dev
;
512 struct fb_info
*info
= NULL
;
513 struct picolcd_fb_data
*fbdata
= NULL
;
514 int i
, error
= -ENOMEM
;
517 /* The extra memory is:
518 * - 256*u32 for pseudo_palette
519 * - struct fb_deferred_io
521 info
= framebuffer_alloc(256 * sizeof(u32
) +
522 sizeof(struct fb_deferred_io
) +
523 sizeof(struct picolcd_fb_data
) +
524 PICOLCDFB_SIZE
, dev
);
526 dev_err(dev
, "failed to allocate a framebuffer\n");
530 info
->fbdefio
= info
->par
;
531 *info
->fbdefio
= picolcd_fb_defio
;
532 info
->par
+= sizeof(struct fb_deferred_io
);
534 info
->par
+= 256 * sizeof(u32
);
535 for (i
= 0; i
< 256; i
++)
536 palette
[i
] = i
> 0 && i
< 16 ? 0xff : 0;
537 info
->pseudo_palette
= palette
;
538 info
->fbops
= &picolcdfb_ops
;
539 info
->var
= picolcdfb_var
;
540 info
->fix
= picolcdfb_fix
;
541 info
->fix
.smem_len
= PICOLCDFB_SIZE
*8;
542 info
->flags
= FBINFO_FLAG_DEFAULT
;
545 spin_lock_init(&fbdata
->lock
);
546 fbdata
->picolcd
= data
;
547 fbdata
->update_rate
= PICOLCDFB_UPDATE_RATE_DEFAULT
;
548 fbdata
->bpp
= picolcdfb_var
.bits_per_pixel
;
550 fbdata
->vbitmap
= info
->par
+ sizeof(struct picolcd_fb_data
);
551 fbdata
->bitmap
= vmalloc(PICOLCDFB_SIZE
*8);
552 if (fbdata
->bitmap
== NULL
) {
553 dev_err(dev
, "can't get a free page for framebuffer\n");
556 info
->screen_base
= (char __force __iomem
*)fbdata
->bitmap
;
557 info
->fix
.smem_start
= (unsigned long)fbdata
->bitmap
;
558 memset(fbdata
->vbitmap
, 0xff, PICOLCDFB_SIZE
);
559 data
->fb_info
= info
;
561 error
= picolcd_fb_reset(data
, 1);
563 dev_err(dev
, "failed to configure display\n");
567 error
= device_create_file(dev
, &dev_attr_fb_update_rate
);
569 dev_err(dev
, "failed to create sysfs attributes\n");
573 fb_deferred_io_init(info
);
574 error
= register_framebuffer(info
);
576 dev_err(dev
, "failed to register framebuffer\n");
582 device_remove_file(dev
, &dev_attr_fb_update_rate
);
583 fb_deferred_io_cleanup(info
);
585 data
->fb_info
= NULL
;
589 vfree(fbdata
->bitmap
);
590 framebuffer_release(info
);
594 void picolcd_exit_framebuffer(struct picolcd_data
*data
)
596 struct fb_info
*info
= data
->fb_info
;
597 struct picolcd_fb_data
*fbdata
;
603 device_remove_file(&data
->hdev
->dev
, &dev_attr_fb_update_rate
);
606 /* disconnect framebuffer from HID dev */
607 spin_lock_irqsave(&fbdata
->lock
, flags
);
608 fbdata
->picolcd
= NULL
;
609 spin_unlock_irqrestore(&fbdata
->lock
, flags
);
611 /* make sure there is no running update - thus that fbdata->picolcd
612 * once obtained under lock is guaranteed not to get free() under
613 * the feet of the deferred work */
614 flush_delayed_work(&info
->deferred_work
);
616 data
->fb_info
= NULL
;
617 unregister_framebuffer(info
);