4 * Copyright (C) 2007,2008 Jakub Schmidtke (sjakub@gmail.com)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * This module is based on usbled and asus-laptop modules.
26 * Asus OLED support is based on asusoled program taken from
27 * https://launchpad.net/asusoled/.
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/init.h>
35 #include <linux/slab.h>
36 #include <linux/module.h>
37 #include <linux/usb.h>
38 #include <linux/platform_device.h>
39 #include <linux/ctype.h>
41 #define ASUS_OLED_VERSION "0.04-dev"
42 #define ASUS_OLED_NAME "asus-oled"
43 #define ASUS_OLED_UNDERSCORE_NAME "asus_oled"
45 #define ASUS_OLED_ERROR "Asus OLED Display Error: "
47 #define ASUS_OLED_STATIC 's'
48 #define ASUS_OLED_ROLL 'r'
49 #define ASUS_OLED_FLASH 'f'
51 #define ASUS_OLED_MAX_WIDTH 1792
52 #define ASUS_OLED_DISP_HEIGHT 32
53 #define ASUS_OLED_PACKET_BUF_SIZE 256
55 MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
56 MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION
);
57 MODULE_LICENSE("GPL");
59 static struct class *oled_class
= 0;
60 static int oled_num
= 0;
62 static uint start_off
= 0;
64 module_param(start_off
, uint
, 0644);
66 MODULE_PARM_DESC(start_off
, "Set to 1 to switch off OLED display after it is attached");
74 struct oled_dev_desc_str
{
77 uint16_t devWidth
; // width of display
78 oled_pack_mode_t packMode
; // formula to be used while packing the picture
82 /* table of devices that work with this driver */
83 static struct usb_device_id id_table
[] = {
84 { USB_DEVICE(0x0b05, 0x1726) }, // Asus G1/G2 (and variants)
85 { USB_DEVICE(0x0b05, 0x175b) }, // Asus G50V (and possibly others - G70? G71?)
89 /* parameters of specific devices */
90 static struct oled_dev_desc_str oled_dev_desc_table
[] = {
91 { 0x0b05, 0x1726, 128, PACK_MODE_G1
, "G1/G2" },
92 { 0x0b05, 0x175b, 256, PACK_MODE_G50
, "G50" },
96 MODULE_DEVICE_TABLE (usb
, id_table
);
98 #define SETUP_PACKET_HEADER(packet, val1, val2, val3, val4, val5, val6, val7) \
100 memset(packet, 0, sizeof(struct asus_oled_header)); \
101 packet->header.magic1 = 0x55; \
102 packet->header.magic2 = 0xaa; \
103 packet->header.flags = val1; \
104 packet->header.value3 = val2; \
105 packet->header.buffer1 = val3; \
106 packet->header.buffer2 = val4; \
107 packet->header.value6 = val5; \
108 packet->header.value7 = val6; \
109 packet->header.value8 = val7; \
112 struct asus_oled_header
{
123 } __attribute((packed
));
125 struct asus_oled_packet
{
126 struct asus_oled_header header
;
127 uint8_t bitmap
[ASUS_OLED_PACKET_BUF_SIZE
];
128 } __attribute((packed
));
130 struct asus_oled_dev
{
131 struct usb_device
* udev
;
134 oled_pack_mode_t pack_mode
;
147 static void enable_oled(struct asus_oled_dev
*odev
, uint8_t enabl
)
152 struct asus_oled_packet
* packet
;
154 packet
= kzalloc(sizeof(struct asus_oled_packet
), GFP_KERNEL
);
157 dev_err(&odev
->udev
->dev
, "out of memory\n");
161 SETUP_PACKET_HEADER(packet
, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
163 if (enabl
) packet
->bitmap
[0] = 0xaf;
164 else packet
->bitmap
[0] = 0xae;
166 for (a
=0; a
<1; a
++) {
167 retval
= usb_bulk_msg(odev
->udev
,
168 usb_sndbulkpipe(odev
->udev
, 2),
170 sizeof(struct asus_oled_header
) + 1,
175 dev_dbg(&odev
->udev
->dev
, "retval = %d\n", retval
);
178 odev
->enabled
= enabl
;
183 static ssize_t
set_enabled(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
185 struct usb_interface
*intf
= to_usb_interface(dev
);
186 struct asus_oled_dev
*odev
= usb_get_intfdata(intf
);
187 int temp
= simple_strtoul(buf
, NULL
, 10);
189 enable_oled(odev
, temp
);
194 static ssize_t
class_set_enabled(struct device
*device
, struct device_attribute
*attr
, const char *buf
, size_t count
)
196 struct asus_oled_dev
*odev
= (struct asus_oled_dev
*) dev_get_drvdata(device
);
198 int temp
= simple_strtoul(buf
, NULL
, 10);
200 enable_oled(odev
, temp
);
205 static ssize_t
get_enabled(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
207 struct usb_interface
*intf
= to_usb_interface(dev
);
208 struct asus_oled_dev
*odev
= usb_get_intfdata(intf
);
210 return sprintf(buf
, "%d\n", odev
->enabled
);
213 static ssize_t
class_get_enabled(struct device
*device
, struct device_attribute
*attr
, char *buf
)
215 struct asus_oled_dev
*odev
= (struct asus_oled_dev
*) dev_get_drvdata(device
);
217 return sprintf(buf
, "%d\n", odev
->enabled
);
220 static void send_packets(struct usb_device
*udev
, struct asus_oled_packet
*packet
,
221 char *buf
, uint8_t p_type
, size_t p_num
)
226 for (i
= 0; i
< p_num
; i
++) {
231 SETUP_PACKET_HEADER(packet
, 0x40, 0x80, p_num
, i
+ 1, 0x00, 0x01, 0xff);
233 case ASUS_OLED_STATIC
:
234 SETUP_PACKET_HEADER(packet
, 0x10 + i
, 0x80, 0x01, 0x01, 0x00, 0x01, 0x00);
236 case ASUS_OLED_FLASH
:
237 SETUP_PACKET_HEADER(packet
, 0x10 + i
, 0x80, 0x01, 0x01, 0x00, 0x00, 0xff);
241 memcpy(packet
->bitmap
, buf
+ (ASUS_OLED_PACKET_BUF_SIZE
*i
), ASUS_OLED_PACKET_BUF_SIZE
);
243 retval
= usb_bulk_msg(udev
,
244 usb_sndctrlpipe(udev
, 2),
246 sizeof(struct asus_oled_packet
),
251 dev_dbg(&udev
->dev
, "retval = %d\n", retval
);
255 static void send_packet(struct usb_device
*udev
, struct asus_oled_packet
*packet
, size_t offset
, size_t len
, char *buf
, uint8_t b1
, uint8_t b2
, uint8_t b3
, uint8_t b4
, uint8_t b5
, uint8_t b6
){
259 SETUP_PACKET_HEADER(packet
, b1
, b2
, b3
, b4
, b5
, b6
, 0x00);
260 memcpy(packet
->bitmap
, buf
+ offset
, len
);
262 retval
= usb_bulk_msg(udev
,
263 usb_sndctrlpipe(udev
, 2),
265 sizeof(struct asus_oled_packet
),
270 dev_dbg(&udev
->dev
, "retval = %d\n", retval
);
274 static void send_packets_g50(struct usb_device
*udev
, struct asus_oled_packet
*packet
, char *buf
)
276 send_packet(udev
, packet
, 0, 0x100, buf
, 0x10, 0x00, 0x02, 0x01, 0x00, 0x01);
277 send_packet(udev
, packet
, 0x100, 0x080, buf
, 0x10, 0x00, 0x02, 0x02, 0x80, 0x00);
279 send_packet(udev
, packet
, 0x180, 0x100, buf
, 0x11, 0x00, 0x03, 0x01, 0x00, 0x01);
280 send_packet(udev
, packet
, 0x280, 0x100, buf
, 0x11, 0x00, 0x03, 0x02, 0x00, 0x01);
281 send_packet(udev
, packet
, 0x380, 0x080, buf
, 0x11, 0x00, 0x03, 0x03, 0x80, 0x00);
285 static void send_data(struct asus_oled_dev
*odev
)
287 size_t packet_num
= odev
->buf_size
/ ASUS_OLED_PACKET_BUF_SIZE
;
288 struct asus_oled_packet
* packet
;
290 packet
= kzalloc(sizeof(struct asus_oled_packet
), GFP_KERNEL
);
293 dev_err(&odev
->udev
->dev
, "out of memory\n");
297 if (odev
->pack_mode
==PACK_MODE_G1
){
298 // When sending roll-mode data the display updated only first packet.
299 // I have no idea why, but when static picture is send just before
300 // rolling picture - everything works fine.
301 if (odev
->pic_mode
== ASUS_OLED_ROLL
)
302 send_packets(odev
->udev
, packet
, odev
->buf
, ASUS_OLED_STATIC
, 2);
304 // Only ROLL mode can use more than 2 packets.
305 if (odev
->pic_mode
!= ASUS_OLED_ROLL
&& packet_num
> 2)
308 send_packets(odev
->udev
, packet
, odev
->buf
, odev
->pic_mode
, packet_num
);
311 if (odev
->pack_mode
==PACK_MODE_G50
){
312 send_packets_g50(odev
->udev
, packet
, odev
->buf
);
318 static int append_values(struct asus_oled_dev
*odev
, uint8_t val
, size_t count
)
320 while (count
-- > 0) {
322 size_t x
= odev
->buf_offs
% odev
->width
;
323 size_t y
= odev
->buf_offs
/ odev
->width
;
329 switch(odev
->pack_mode
)
332 // i = (x/128)*640 + 127 - x + (y/8)*128;
333 // This one for 128 is the same, but might be better for different widths?
334 i
= (x
/odev
->dev_width
)*640 + odev
->dev_width
- 1 - x
+ (y
/8)*odev
->dev_width
;
338 i
= (odev
->dev_width
- 1 - x
)/8 + y
*odev
->dev_width
/8;
343 printk(ASUS_OLED_ERROR
"Unknown OLED Pack Mode: %d!\n", odev
->pack_mode
);
347 if (i
>= odev
->buf_size
) {
348 printk(ASUS_OLED_ERROR
"Buffer overflow! Report a bug in the driver: offs: %d >= %d i: %d (x: %d y: %d)\n",
349 (int) odev
->buf_offs
, (int) odev
->buf_size
, (int) i
, (int) x
, (int) y
);
353 switch (odev
->pack_mode
)
356 odev
->buf
[i
] &= ~(1<<(y
%8));
360 odev
->buf
[i
] &= ~(1<<(x
%8));
364 // cannot get here; stops gcc complaining
369 odev
->last_val
= val
;
376 static ssize_t
odev_set_picture(struct asus_oled_dev
*odev
, const char *buf
, size_t count
)
378 size_t offs
= 0, max_offs
;
380 if (count
< 1) return 0;
382 if (tolower(buf
[0]) == 'b'){
383 // binary mode, set the entire memory
387 odev
->buf_size
= (odev
->dev_width
* ASUS_OLED_DISP_HEIGHT
) / 8;
389 if (odev
->buf
) kfree(odev
->buf
);
390 odev
->buf
= kmalloc(odev
->buf_size
, GFP_KERNEL
);
392 memset(odev
->buf
, 0xff, odev
->buf_size
);
394 for (i
=1; i
< count
&& i
<=32*32; i
++){
395 odev
->buf
[i
-1] = buf
[i
];
396 odev
->buf_offs
= i
-1;
399 odev
->width
=odev
->dev_width
/ 8;
400 odev
->height
=ASUS_OLED_DISP_HEIGHT
;
415 if (count
< 10 || buf
[2] != ':') {
419 switch(tolower(buf
[1])) {
420 case ASUS_OLED_STATIC
:
422 case ASUS_OLED_FLASH
:
423 odev
->pic_mode
= buf
[1];
426 printk(ASUS_OLED_ERROR
"Wrong picture mode: '%c'.\n", buf
[1]);
431 for (i
= 3; i
< count
; ++i
) {
432 if (buf
[i
] >= '0' && buf
[i
] <= '9') {
433 w
= 10*w
+ (buf
[i
] - '0');
435 if (w
> ASUS_OLED_MAX_WIDTH
) goto error_width
;
437 else if (tolower(buf
[i
]) == 'x') break;
438 else goto error_width
;
441 for (++i
; i
< count
; ++i
) {
442 if (buf
[i
] >= '0' && buf
[i
] <= '9') {
443 h
= 10*h
+ (buf
[i
] - '0');
445 if (h
> ASUS_OLED_DISP_HEIGHT
) goto error_height
;
447 else if (tolower(buf
[i
]) == '>') break;
448 else goto error_height
;
451 if (w
< 1 || w
> ASUS_OLED_MAX_WIDTH
) goto error_width
;
453 if (h
< 1 || h
> ASUS_OLED_DISP_HEIGHT
) goto error_height
;
455 if (i
>= count
|| buf
[i
] != '>') goto error_header
;
459 if (w
% (odev
->dev_width
) != 0)
460 w_mem
= (w
/(odev
->dev_width
) + 1)*(odev
->dev_width
);
464 if (h
< ASUS_OLED_DISP_HEIGHT
)
465 h_mem
= ASUS_OLED_DISP_HEIGHT
;
469 odev
->buf_size
= w_mem
* h_mem
/ 8;
471 if (odev
->buf
) kfree(odev
->buf
);
472 odev
->buf
= kmalloc(odev
->buf_size
, GFP_KERNEL
);
474 if (odev
->buf
== NULL
) {
476 printk(ASUS_OLED_ERROR
"Out of memory!\n");
480 memset(odev
->buf
, 0xff, odev
->buf_size
);
489 if (odev
->pic_mode
== ASUS_OLED_FLASH
) {
490 if (h
< ASUS_OLED_DISP_HEIGHT
/2)
491 odev
->y_shift
= (ASUS_OLED_DISP_HEIGHT
/2 - h
)/2;
494 if (h
< ASUS_OLED_DISP_HEIGHT
)
495 odev
->y_shift
= (ASUS_OLED_DISP_HEIGHT
- h
)/2;
498 if (w
< (odev
->dev_width
))
499 odev
->x_shift
= ((odev
->dev_width
) - w
)/2;
502 max_offs
= odev
->width
* odev
->height
;
504 while (offs
< count
&& odev
->buf_offs
< max_offs
) {
507 if (buf
[offs
] == '1' || buf
[offs
] == '#') {
508 if ( (ret
= append_values(odev
, 1, 1)) < 0) return ret
;
510 else if (buf
[offs
] == '0' || buf
[offs
] == ' ') {
511 if ( (ret
= append_values(odev
, 0, 1)) < 0) return ret
;
513 else if (buf
[offs
] == '\n') {
514 // New line detected. Lets assume, that all characters till the end of the
515 // line were equal to the last character in this line.
516 if (odev
->buf_offs
% odev
->width
!= 0)
517 if ( (ret
= append_values(odev
, odev
->last_val
,
518 odev
->width
- (odev
->buf_offs
% odev
->width
))) < 0) return ret
;
524 if (odev
->buf_offs
>= max_offs
) send_data(odev
);
529 printk(ASUS_OLED_ERROR
"Wrong picture width specified.\n");
533 printk(ASUS_OLED_ERROR
"Wrong picture height specified.\n");
537 printk(ASUS_OLED_ERROR
"Wrong picture header.\n");
541 static ssize_t
set_picture(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
543 struct usb_interface
*intf
= to_usb_interface(dev
);
545 return odev_set_picture(usb_get_intfdata(intf
), buf
, count
);
548 static ssize_t
class_set_picture(struct device
*device
, struct device_attribute
*attr
, const char *buf
, size_t count
)
550 return odev_set_picture((struct asus_oled_dev
*) dev_get_drvdata(device
), buf
, count
);
553 #define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file
555 static DEVICE_ATTR(asus_oled_enabled
, S_IWUGO
| S_IRUGO
, get_enabled
, set_enabled
);
556 static DEVICE_ATTR(asus_oled_picture
, S_IWUGO
, NULL
, set_picture
);
558 static DEVICE_ATTR(enabled
, S_IWUGO
| S_IRUGO
, class_get_enabled
, class_set_enabled
);
559 static DEVICE_ATTR(picture
, S_IWUGO
, NULL
, class_set_picture
);
561 static int asus_oled_probe(struct usb_interface
*interface
, const struct usb_device_id
*id
)
563 struct usb_device
*udev
= interface_to_usbdev(interface
);
564 struct asus_oled_dev
*odev
= NULL
;
565 int retval
= -ENOMEM
;
566 uint16_t dev_width
= 0;
567 oled_pack_mode_t pack_mode
= PACK_MODE_LAST
;
568 const struct oled_dev_desc_str
* dev_desc
= oled_dev_desc_table
;
569 const char *desc
= 0;
572 // Even possible? Just to make sure...
573 dev_err(&interface
->dev
, "No usb_device_id provided!\n");
577 for (; dev_desc
->idVendor
; dev_desc
++)
579 if (dev_desc
->idVendor
== id
->idVendor
580 && dev_desc
->idProduct
== id
->idProduct
)
582 dev_width
= dev_desc
->devWidth
;
583 desc
= dev_desc
->devDesc
;
584 pack_mode
= dev_desc
->packMode
;
589 if ( !desc
|| dev_width
< 1 || pack_mode
== PACK_MODE_LAST
) {
590 dev_err(&interface
->dev
, "Missing or incomplete device description!\n");
594 odev
= kzalloc(sizeof(struct asus_oled_dev
), GFP_KERNEL
);
597 dev_err(&interface
->dev
, "Out of memory\n");
601 odev
->udev
= usb_get_dev(udev
);
602 odev
->pic_mode
= ASUS_OLED_STATIC
;
603 odev
->dev_width
= dev_width
;
604 odev
->pack_mode
= pack_mode
;
616 usb_set_intfdata (interface
, odev
);
618 if ((retval
= device_create_file(&interface
->dev
, &ASUS_OLED_DEVICE_ATTR(enabled
)))) {
622 if ((retval
= device_create_file(&interface
->dev
, &ASUS_OLED_DEVICE_ATTR(picture
)))) {
626 odev
->dev
= device_create(oled_class
, &interface
->dev
, MKDEV(0,0),
627 NULL
,"oled_%d", ++oled_num
);
629 if (IS_ERR(odev
->dev
)) {
630 retval
= PTR_ERR(odev
->dev
);
634 dev_set_drvdata(odev
->dev
, odev
);
636 if ( (retval
= device_create_file(odev
->dev
, &dev_attr_enabled
))) {
637 goto err_class_enabled
;
640 if ( (retval
= device_create_file(odev
->dev
, &dev_attr_picture
))) {
641 goto err_class_picture
;
644 dev_info(&interface
->dev
, "Attached Asus OLED device: %s [width %u, pack_mode %d]\n", desc
, odev
->dev_width
, odev
->pack_mode
);
647 enable_oled(odev
, 0);
652 device_remove_file(odev
->dev
, &dev_attr_picture
);
655 device_remove_file(odev
->dev
, &dev_attr_enabled
);
656 device_unregister(odev
->dev
);
659 device_remove_file(&interface
->dev
, &ASUS_OLED_DEVICE_ATTR(enabled
));
660 device_remove_file(&interface
->dev
, &ASUS_OLED_DEVICE_ATTR(picture
));
662 usb_set_intfdata (interface
, NULL
);
663 usb_put_dev(odev
->udev
);
669 static void asus_oled_disconnect(struct usb_interface
*interface
)
671 struct asus_oled_dev
*odev
;
673 odev
= usb_get_intfdata (interface
);
674 usb_set_intfdata (interface
, NULL
);
676 device_remove_file(odev
->dev
, &dev_attr_picture
);
677 device_remove_file(odev
->dev
, &dev_attr_enabled
);
678 device_unregister(odev
->dev
);
680 device_remove_file(&interface
->dev
, & ASUS_OLED_DEVICE_ATTR(picture
));
681 device_remove_file(&interface
->dev
, & ASUS_OLED_DEVICE_ATTR(enabled
));
683 usb_put_dev(odev
->udev
);
685 if (odev
->buf
) kfree(odev
->buf
);
689 dev_info(&interface
->dev
, "Disconnected Asus OLED device\n");
692 static struct usb_driver oled_driver
= {
693 .name
= ASUS_OLED_NAME
,
694 .probe
= asus_oled_probe
,
695 .disconnect
= asus_oled_disconnect
,
696 .id_table
= id_table
,
699 static ssize_t
version_show(struct class *dev
, char *buf
)
701 return sprintf(buf
, ASUS_OLED_UNDERSCORE_NAME
" %s\n", ASUS_OLED_VERSION
);
704 static CLASS_ATTR(version
, S_IRUGO
, version_show
, NULL
);
706 static int __init
asus_oled_init(void)
709 oled_class
= class_create(THIS_MODULE
, ASUS_OLED_UNDERSCORE_NAME
);
711 if (IS_ERR(oled_class
)) {
712 err("Error creating " ASUS_OLED_UNDERSCORE_NAME
" class");
713 return PTR_ERR(oled_class
);
716 if ((retval
= class_create_file(oled_class
, &class_attr_version
))) {
717 err("Error creating class version file");
721 retval
= usb_register(&oled_driver
);
724 err("usb_register failed. Error number %d", retval
);
731 class_destroy(oled_class
);
735 static void __exit
asus_oled_exit(void)
737 class_remove_file(oled_class
, &class_attr_version
);
738 class_destroy(oled_class
);
740 usb_deregister(&oled_driver
);
743 module_init (asus_oled_init
);
744 module_exit (asus_oled_exit
);