Commit fb53440b authored by Jakub Schmidtke's avatar Jakub Schmidtke Committed by Greg Kroah-Hartman

Staging: add asus_oled driver

Driver for the OLED tiny display on some Asus laptops.

From: Jakub Schmidtke <sjakub@gmail.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a8275fca
......@@ -73,5 +73,7 @@ source "drivers/staging/benet/Kconfig"
source "drivers/staging/comedi/Kconfig"
source "drivers/staging/asus_oled/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
......@@ -19,3 +19,4 @@ obj-$(CONFIG_OTUS) += otus/
obj-$(CONFIG_RT2860) += rt2860/
obj-$(CONFIG_BENET) += benet/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_ASUS_OLED) += asus_oled/
config ASUS_OLED
tristate "Asus OLED driver"
default N
---help---
Enable support for the OLED display present in some Asus laptops.
obj-$(CONFIG_ASUS_OLED) += asus_oled.o
Driver for Asus OLED display present in some Asus laptops.
The code of this driver is based on 'asusoled' program taken from
https://launchpad.net/asusoled/. I just wanted to have a simple
kernel driver for controlling this device, but I didn't know how
to do that. Now I know ;) Also, that program can not be used
with usbhid loaded, which means no USB mouse/keyboard while
controlling OLED display :(
It has been tested on Asus G1 and didn't cause any problems,
but I don't guarantee that it won't do anything wrong :)
It can (and probably does) have errors. It is usable
in my case, and I hope others will find it useful too!
*******
Building the module
To build the module you need kernel 2.6 include files and some C compiler.
Just run:
make
make install (as a root)
It will build (hopefully) the module and install it in
/lib/modules/'uname -r'/extra/asus_oled.ko.
To load it just use:
modprobe asus_oled
You can check if it has detected your OLED display by looking into dmesg output.
There should be something like this:
asus-oled 2-7:1.0: Attached Asus OLED device
If it doesn't find your display, you can try removing usbhid module.
If you add asus_oled into the list of modules loaded during system boot
before usbhid, it will work even when usbhid is present.
If it still doesn't detect your hardware, check lsusb output.
There should be similar line:
Bus 002 Device 005: ID 0b05:1726 ASUSTek Computer, Inc.
If you don't see any lines with '0b05:1726' it means that you have different
type of hardware that is not detected (it may or may not work, but the driver
knows only '0b05:1726' device).
*******
Configuration
There is only one option: start_off.
You can use it by: 'modprobe asus_oled start_off=1', or by adding this
line to /etc/modprobe.conf:
options asus_oled start_off=1
With this option provided, asus_oled driver will switch off the display
when it is detected and attached. It is nice feature to just switch off the 'ASUS'
logo. If you don't use the display, it is probably the good idea to switch it off,
to protect OLEDs from "wearing off".
*******
Usage
This module can be controlled with two special files:
/sys/class/asus_oled/oled_N/enabled
/sys/class/asus_oled/oled_N/picture
(N is the device number, the first, and probably the only, has number 1,
so it is /sys/class/asus_oled/oled_1/enabled
and /sys/class/asus_oled/oled_1/picture)
'enabled' files is for reading and writing, 'picture' is writeable only.
You can write 0 or 1 to 'enabled' file, which will switch
on and off the display. Reading from this file will tell you the last
status set, either 0 or 1. By default it is 1, so if the device was set to 'off',
and the computer was rebooted without power-off, this file will contain wrong
value - because the device is off, but hasn't been disabled this time and is
assumed to be on...
To 'picture' file you write pictures to be displayed by the OLED device.
The format of the file:
<M:WxH>
00001110010111000
00010101010101010
....
First line is a configuration parameter. Meaning of fields in <M:WxH>:
M - picture mode. It can be either 's' for static pictures,
'r' for rolling pictures, and 'f' for flashing pictures.
W - width of the picture. May be between 1 and 1792
H - height of the picture. May be between 1 and 32
For example <s:128x32> means static picture, 128 pixels long and 32 pixels high.
The physical size of the display is 128x32 pixels. Static and flashing pictures
can't be larger than that (actually they can, but only part of them will be displayed ;) )
If the picture is smaller than 128x32 it will be centered. Rolling pictures wider than
128 pixels will be centered too, unless their width = n*128. Vertically they will be
centered just like static pictures, if their height is smaller than 32.
Flashing pictures will be centered horizontally if their width < 128, but they were
centered vertically in a different way. If their height < 16, they will be centered
in the upper half of the display (rows 0-15). This is because only the first half
of flashing pictures is used for flashing. When the picture with heigh = 32 is
displayed in flashing mode, its upper 16 rows will be flashing in the upper half
of the display, and the lower half will be empty. After few seconds upper part will
stop flashing (but that part of the picture will remain there), and the lower
half of the display will start displayin the lower half of the picture
in rolling mode, unless it is empty, or the picture was small enough to fit in
upper part. It is not mine idea, this is just the way Asus' display work ;)
So if you need just flashing, use at most 128x16 picture. If you need flashing and
rolling, use whole size of the display.
Lines following the first, configuration, line are picture data. Each '1' means
that the pixel is lit, and '0' means that it is not. You can also use '#' as ON,
and ' ' (space) as OFF. Empty lines and all other characters are ignored.
It is possible to write everything in one line <M:WxH>01010101010101010...,
and W*H characters will be used. If there is not enough characters, nothing will be
displayed. However, the 'line mode' is easier to read (and write), and it also
lets to omit parts of data. Whenever End-Of-Line character is found, but
the line is not W characters long, it is assumed that all missing characters
are equal to the last character in the line.
Following line represents '0', '1' and a lots of '0's, dependng on the width of the picture
provided in configuration data:
010
So if you need empty line, it is sufficient to write line with only one '0' in it.
The same works with '1' (or ' ' and '#').
If there are too many data in the file, they will be ignored. If you are not sure
how many characters you are missing, you can add few lines with one zero in each of them.
There are some example pictures in .txt format, that can be used as follows:
cat foo.txt > /sys/class/asus_oled/oled_1/picture
If the display is switched off you also need to run:
echo 1 > /sys/class/asus_oled/oled_1/enabled
To switch it off, just use:
echo 0 > /sys/class/asus_oled/oled_1/enabled
*******
For any additional info please have a look at http://lapsus.berlios.de/asus_oled.html
Jakub Schmidtke (sjakub@gmail.com)
TODO:
- checkpatch.pl cleanups
- sparse fixes
- audit the userspace interface
- sysfs vs. char?
- Documentation/ABI/ needs to be added
- put the sample .txt files and README file somewhere.
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
Cc: Jakub Schmidtke <sjakub@gmail.com>
/*
* Asus OLED USB driver
*
* Copyright (C) 2007,2008 Jakub Schmidtke (sjakub@gmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*
*
* This module is based on usbled and asus-laptop modules.
*
*
* Asus OLED support is based on asusoled program taken from
* https://launchpad.net/asusoled/.
*
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/ctype.h>
#define ASUS_OLED_VERSION "0.04-dev"
#define ASUS_OLED_NAME "asus-oled"
#define ASUS_OLED_UNDERSCORE_NAME "asus_oled"
#define ASUS_OLED_ERROR "Asus OLED Display Error: "
#define ASUS_OLED_STATIC 's'
#define ASUS_OLED_ROLL 'r'
#define ASUS_OLED_FLASH 'f'
#define ASUS_OLED_MAX_WIDTH 1792
#define ASUS_OLED_DISP_HEIGHT 32
#define ASUS_OLED_PACKET_BUF_SIZE 256
MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
MODULE_LICENSE("GPL");
static struct class *oled_class = 0;
static int oled_num = 0;
static uint start_off = 0;
module_param(start_off, uint, 0644);
MODULE_PARM_DESC(start_off, "Set to 1 to switch off OLED display after it is attached");
typedef enum {
PACK_MODE_G1,
PACK_MODE_G50,
PACK_MODE_LAST
} oled_pack_mode_t;
struct oled_dev_desc_str {
uint16_t idVendor;
uint16_t idProduct;
uint16_t devWidth; // width of display
oled_pack_mode_t packMode; // formula to be used while packing the picture
const char *devDesc;
};
/* table of devices that work with this driver */
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0b05, 0x1726) }, // Asus G1/G2 (and variants)
{ USB_DEVICE(0x0b05, 0x175b) }, // Asus G50V (and possibly others - G70? G71?)
{ },
};
/* parameters of specific devices */
static struct oled_dev_desc_str oled_dev_desc_table [] = {
{ 0x0b05, 0x1726, 128, PACK_MODE_G1, "G1/G2" },
{ 0x0b05, 0x175b, 256, PACK_MODE_G50, "G50" },
{ },
};
MODULE_DEVICE_TABLE (usb, id_table);
#define SETUP_PACKET_HEADER(packet, val1, val2, val3, val4, val5, val6, val7) \
do { \
memset(packet, 0, sizeof(struct asus_oled_header)); \
packet->header.magic1 = 0x55; \
packet->header.magic2 = 0xaa; \
packet->header.flags = val1; \
packet->header.value3 = val2; \
packet->header.buffer1 = val3; \
packet->header.buffer2 = val4; \
packet->header.value6 = val5; \
packet->header.value7 = val6; \
packet->header.value8 = val7; \
} while(0);
struct asus_oled_header {
uint8_t magic1;
uint8_t magic2;
uint8_t flags;
uint8_t value3;
uint8_t buffer1;
uint8_t buffer2;
uint8_t value6;
uint8_t value7;
uint8_t value8;
uint8_t padding2[7];
} __attribute((packed));
struct asus_oled_packet {
struct asus_oled_header header;
uint8_t bitmap[ASUS_OLED_PACKET_BUF_SIZE];
} __attribute((packed));
struct asus_oled_dev {
struct usb_device * udev;
uint8_t pic_mode;
uint16_t dev_width;
oled_pack_mode_t pack_mode;
size_t height;
size_t width;
size_t x_shift;
size_t y_shift;
size_t buf_offs;
uint8_t last_val;
size_t buf_size;
char *buf;
uint8_t enabled;
struct device *dev;
};
static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
{
int a;
int retval;
int act_len;
struct asus_oled_packet * packet;
packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
if (!packet) {
dev_err(&odev->udev->dev, "out of memory\n");
return;
}
SETUP_PACKET_HEADER(packet, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
if (enabl) packet->bitmap[0] = 0xaf;
else packet->bitmap[0] = 0xae;
for (a=0; a<1; a++) {
retval = usb_bulk_msg(odev->udev,
usb_sndbulkpipe(odev->udev, 2),
packet,
sizeof(struct asus_oled_header) + 1,
&act_len,
-1);
if (retval)
dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
}
odev->enabled = enabl;
kfree(packet);
}
static ssize_t set_enabled(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct asus_oled_dev *odev = usb_get_intfdata(intf);
int temp = simple_strtoul(buf, NULL, 10);
enable_oled(odev, temp);
return count;
}
static ssize_t class_set_enabled(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
{
struct asus_oled_dev *odev = (struct asus_oled_dev *) dev_get_drvdata(device);
int temp = simple_strtoul(buf, NULL, 10);
enable_oled(odev, temp);
return count;
}
static ssize_t get_enabled(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct asus_oled_dev *odev = usb_get_intfdata(intf);
return sprintf(buf, "%d\n", odev->enabled);
}
static ssize_t class_get_enabled(struct device *device, struct device_attribute *attr, char *buf)
{
struct asus_oled_dev *odev = (struct asus_oled_dev *) dev_get_drvdata(device);
return sprintf(buf, "%d\n", odev->enabled);
}
static void send_packets(struct usb_device *udev, struct asus_oled_packet *packet,
char *buf, uint8_t p_type, size_t p_num)
{
size_t i;
int act_len;
for (i = 0; i < p_num; i++) {
int retval;
switch (p_type) {
case ASUS_OLED_ROLL:
SETUP_PACKET_HEADER(packet, 0x40, 0x80, p_num, i + 1, 0x00, 0x01, 0xff);
break;
case ASUS_OLED_STATIC:
SETUP_PACKET_HEADER(packet, 0x10 + i, 0x80, 0x01, 0x01, 0x00, 0x01, 0x00);
break;
case ASUS_OLED_FLASH:
SETUP_PACKET_HEADER(packet, 0x10 + i, 0x80, 0x01, 0x01, 0x00, 0x00, 0xff);
break;
}
memcpy(packet->bitmap, buf + (ASUS_OLED_PACKET_BUF_SIZE*i), ASUS_OLED_PACKET_BUF_SIZE);
retval = usb_bulk_msg(udev,
usb_sndctrlpipe(udev, 2),
packet,
sizeof(struct asus_oled_packet),
&act_len,
-1);
if (retval)
dev_dbg(&udev->dev, "retval = %d\n", retval);
}
}
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){
int retval;
int act_len;
SETUP_PACKET_HEADER(packet, b1, b2, b3, b4, b5, b6, 0x00);
memcpy(packet->bitmap, buf + offset, len);
retval = usb_bulk_msg(udev,
usb_sndctrlpipe(udev, 2),
packet,
sizeof(struct asus_oled_packet),
&act_len,
-1);
if (retval)
dev_dbg(&udev->dev, "retval = %d\n", retval);
}
static void send_packets_g50(struct usb_device *udev, struct asus_oled_packet *packet, char *buf)
{
send_packet(udev, packet, 0, 0x100, buf, 0x10, 0x00, 0x02, 0x01, 0x00, 0x01);
send_packet(udev, packet, 0x100, 0x080, buf, 0x10, 0x00, 0x02, 0x02, 0x80, 0x00);
send_packet(udev, packet, 0x180, 0x100, buf, 0x11, 0x00, 0x03, 0x01, 0x00, 0x01);
send_packet(udev, packet, 0x280, 0x100, buf, 0x11, 0x00, 0x03, 0x02, 0x00, 0x01);
send_packet(udev, packet, 0x380, 0x080, buf, 0x11, 0x00, 0x03, 0x03, 0x80, 0x00);
}
static void send_data(struct asus_oled_dev *odev)
{
size_t packet_num = odev->buf_size / ASUS_OLED_PACKET_BUF_SIZE;
struct asus_oled_packet * packet;
packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
if (!packet) {
dev_err(&odev->udev->dev, "out of memory\n");
return;
}
if (odev->pack_mode==PACK_MODE_G1){
// When sending roll-mode data the display updated only first packet.
// I have no idea why, but when static picture is send just before
// rolling picture - everything works fine.
if (odev->pic_mode == ASUS_OLED_ROLL)
send_packets(odev->udev, packet, odev->buf, ASUS_OLED_STATIC, 2);
// Only ROLL mode can use more than 2 packets.
if (odev->pic_mode != ASUS_OLED_ROLL && packet_num > 2)
packet_num = 2;
send_packets(odev->udev, packet, odev->buf, odev->pic_mode, packet_num);
}
else
if (odev->pack_mode==PACK_MODE_G50){
send_packets_g50(odev->udev, packet, odev->buf);
}
kfree(packet);
}
static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
{
while (count-- > 0) {
if (val) {
size_t x = odev->buf_offs % odev->width;
size_t y = odev->buf_offs / odev->width;
size_t i;
x += odev->x_shift;
y += odev->y_shift;
switch(odev->pack_mode)
{
case PACK_MODE_G1:
// i = (x/128)*640 + 127 - x + (y/8)*128;
// This one for 128 is the same, but might be better for different widths?
i = (x/odev->dev_width)*640 + odev->dev_width - 1 - x + (y/8)*odev->dev_width;
break;
case PACK_MODE_G50:
i = (odev->dev_width - 1 - x)/8 + y*odev->dev_width/8;
break;
default:
i = 0;
printk(ASUS_OLED_ERROR "Unknown OLED Pack Mode: %d!\n", odev->pack_mode);
break;
}
if (i >= odev->buf_size) {
printk(ASUS_OLED_ERROR "Buffer overflow! Report a bug in the driver: offs: %d >= %d i: %d (x: %d y: %d)\n",
(int) odev->buf_offs, (int) odev->buf_size, (int) i, (int) x, (int) y);
return -EIO;
}
switch (odev->pack_mode)
{
case PACK_MODE_G1:
odev->buf[i] &= ~(1<<(y%8));
break;
case PACK_MODE_G50:
odev->buf[i] &= ~(1<<(x%8));
break;
default:
// cannot get here; stops gcc complaining
;
}
}
odev->last_val = val;
odev->buf_offs++;
}
return 0;
}
static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, size_t count)
{
size_t offs = 0, max_offs;
if (count < 1) return 0;
if (tolower(buf[0]) == 'b'){
// binary mode, set the entire memory
size_t i;
odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8;
if (odev->buf) kfree(odev->buf);
odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
memset(odev->buf, 0xff, odev->buf_size);
for (i=1; i < count && i<=32*32; i++){
odev->buf[i-1] = buf[i];
odev->buf_offs = i-1;
}
odev->width=odev->dev_width / 8;
odev->height=ASUS_OLED_DISP_HEIGHT;
odev->x_shift=0;
odev->y_shift=0;
odev->last_val=0;
send_data(odev);
return count;
}
if (buf[0] == '<') {
size_t i;
size_t w = 0, h = 0;
size_t w_mem, h_mem;
if (count < 10 || buf[2] != ':') {
goto error_header;
}
switch(tolower(buf[1])) {
case ASUS_OLED_STATIC:
case ASUS_OLED_ROLL:
case ASUS_OLED_FLASH:
odev->pic_mode = buf[1];
break;
default:
printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n", buf[1]);
return -EIO;
break;
}
for (i = 3; i < count; ++i) {
if (buf[i] >= '0' && buf[i] <= '9') {
w = 10*w + (buf[i] - '0');
if (w > ASUS_OLED_MAX_WIDTH) goto error_width;
}
else if (tolower(buf[i]) == 'x') break;
else goto error_width;
}
for (++i; i < count; ++i) {
if (buf[i] >= '0' && buf[i] <= '9') {
h = 10*h + (buf[i] - '0');
if (h > ASUS_OLED_DISP_HEIGHT) goto error_height;
}
else if (tolower(buf[i]) == '>') break;
else goto error_height;
}
if (w < 1 || w > ASUS_OLED_MAX_WIDTH) goto error_width;
if (h < 1 || h > ASUS_OLED_DISP_HEIGHT) goto error_height;
if (i >= count || buf[i] != '>') goto error_header;
offs = i+1;
if (w % (odev->dev_width) != 0)
w_mem = (w/(odev->dev_width) + 1)*(odev->dev_width);
else
w_mem = w;
if (h < ASUS_OLED_DISP_HEIGHT)
h_mem = ASUS_OLED_DISP_HEIGHT;
else
h_mem = h;
odev->buf_size = w_mem * h_mem / 8;
if (odev->buf) kfree(odev->buf);
odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
if (odev->buf == NULL) {
odev->buf_size = 0;
printk(ASUS_OLED_ERROR "Out of memory!\n");
return -ENOMEM;
}
memset(odev->buf, 0xff, odev->buf_size);
odev->buf_offs = 0;
odev->width = w;
odev->height = h;
odev->x_shift = 0;
odev->y_shift = 0;
odev->last_val = 0;
if (odev->pic_mode == ASUS_OLED_FLASH) {
if (h < ASUS_OLED_DISP_HEIGHT/2)
odev->y_shift = (ASUS_OLED_DISP_HEIGHT/2 - h)/2;
}
else {
if (h < ASUS_OLED_DISP_HEIGHT)
odev->y_shift = (ASUS_OLED_DISP_HEIGHT - h)/2;
}
if (w < (odev->dev_width))
odev->x_shift = ((odev->dev_width) - w)/2;
}
max_offs = odev->width * odev->height;
while (offs < count && odev->buf_offs < max_offs) {
int ret;
if (buf[offs] == '1' || buf[offs] == '#') {
if ( (ret = append_values(odev, 1, 1)) < 0) return ret;
}
else if (buf[offs] == '0' || buf[offs] == ' ') {
if ( (ret = append_values(odev, 0, 1)) < 0) return ret;
}
else if (buf[offs] == '\n') {
// New line detected. Lets assume, that all characters till the end of the
// line were equal to the last character in this line.
if (odev->buf_offs % odev->width != 0)
if ( (ret = append_values(odev, odev->last_val,
odev->width - (odev->buf_offs % odev->width))) < 0) return ret;
}
offs++;
}
if (odev->buf_offs >= max_offs) send_data(odev);
return count;
error_width:
printk(ASUS_OLED_ERROR "Wrong picture width specified.\n");
return -EIO;
error_height:
printk(ASUS_OLED_ERROR "Wrong picture height specified.\n");
return -EIO;
error_header:
printk(ASUS_OLED_ERROR "Wrong picture header.\n");
return -EIO;
}
static ssize_t set_picture(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
return odev_set_picture(usb_get_intfdata(intf), buf, count);
}
static ssize_t class_set_picture(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
{
return odev_set_picture((struct asus_oled_dev *) dev_get_drvdata(device), buf, count);
}
#define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file
static DEVICE_ATTR(asus_oled_enabled, S_IWUGO | S_IRUGO, get_enabled, set_enabled);
static DEVICE_ATTR(asus_oled_picture, S_IWUGO , NULL, set_picture);
static DEVICE_ATTR(enabled, S_IWUGO | S_IRUGO, class_get_enabled, class_set_enabled);
static DEVICE_ATTR(picture, S_IWUGO, NULL, class_set_picture);
static int asus_oled_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct asus_oled_dev *odev = NULL;
int retval = -ENOMEM;
uint16_t dev_width = 0;
oled_pack_mode_t pack_mode = PACK_MODE_LAST;
const struct oled_dev_desc_str * dev_desc = oled_dev_desc_table;
const char *desc = 0;
if (id == 0) {
// Even possible? Just to make sure...
dev_err(&interface->dev, "No usb_device_id provided!\n");
return -ENODEV;
}
for (; dev_desc->idVendor; dev_desc++)
{
if (dev_desc->idVendor == id->idVendor
&& dev_desc->idProduct == id->idProduct)
{
dev_width = dev_desc->devWidth;
desc = dev_desc->devDesc;
pack_mode = dev_desc->packMode;
break;
}
}
if ( !desc || dev_width < 1 || pack_mode == PACK_MODE_LAST) {
dev_err(&interface->dev, "Missing or incomplete device description!\n");
return -ENODEV;
}
odev = kzalloc(sizeof(struct asus_oled_dev), GFP_KERNEL);
if (odev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
return -ENOMEM;
}
odev->udev = usb_get_dev(udev);
odev->pic_mode = ASUS_OLED_STATIC;
odev->dev_width = dev_width;
odev->pack_mode = pack_mode;
odev->height = 0;
odev->width = 0;
odev->x_shift = 0;
odev->y_shift = 0;
odev->buf_offs = 0;
odev->buf_size = 0;
odev->last_val = 0;
odev->buf = NULL;
odev->enabled = 1;
odev->dev = 0;
usb_set_intfdata (interface, odev);
if ((retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled)))) {
goto err_files;
}
if ((retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture)))) {
goto err_files;
}
odev->dev = device_create(oled_class, &interface->dev, MKDEV(0,0),
NULL,"oled_%d", ++oled_num);
if (IS_ERR(odev->dev)) {
retval = PTR_ERR(odev->dev);
goto err_files;
}
dev_set_drvdata(odev->dev, odev);
if ( (retval = device_create_file(odev->dev, &dev_attr_enabled))) {
goto err_class_enabled;
}
if ( (retval = device_create_file(odev->dev, &dev_attr_picture))) {
goto err_class_picture;
}
dev_info(&interface->dev, "Attached Asus OLED device: %s [width %u, pack_mode %d]\n", desc, odev->dev_width, odev->pack_mode);
if (start_off)
enable_oled(odev, 0);
return 0;
err_class_picture:
device_remove_file(odev->dev, &dev_attr_picture);
err_class_enabled:
device_remove_file(odev->dev, &dev_attr_enabled);
device_unregister(odev->dev);
err_files:
device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
usb_set_intfdata (interface, NULL);
usb_put_dev(odev->udev);
kfree(odev);
return retval;
}
static void asus_oled_disconnect(struct usb_interface *interface)
{
struct asus_oled_dev *odev;
odev = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
device_remove_file(odev->dev, &dev_attr_picture);
device_remove_file(odev->dev, &dev_attr_enabled);
device_unregister(odev->dev);
device_remove_file(&interface->dev, & ASUS_OLED_DEVICE_ATTR(picture));
device_remove_file(&interface->dev, & ASUS_OLED_DEVICE_ATTR(enabled));
usb_put_dev(odev->udev);
if (odev->buf) kfree(odev->buf);
kfree(odev);
dev_info(&interface->dev, "Disconnected Asus OLED device\n");
}
static struct usb_driver oled_driver = {
.name = ASUS_OLED_NAME,
.probe = asus_oled_probe,
.disconnect = asus_oled_disconnect,
.id_table = id_table,
};
static ssize_t version_show(struct class *dev, char *buf)
{
return sprintf(buf, ASUS_OLED_UNDERSCORE_NAME " %s\n", ASUS_OLED_VERSION);
}
static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
static int __init asus_oled_init(void)
{
int retval = 0;
oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
if (IS_ERR(oled_class)) {
err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class");
return PTR_ERR(oled_class);
}
if ((retval = class_create_file(oled_class, &class_attr_version))) {
err("Error creating class version file");
goto error;
}
retval = usb_register(&oled_driver);
if (retval) {
err("usb_register failed. Error number %d", retval);
goto error;
}
return retval;
error:
class_destroy(oled_class);
return retval;
}
static void __exit asus_oled_exit(void)
{
class_remove_file(oled_class, &class_attr_version);
class_destroy(oled_class);
usb_deregister(&oled_driver);
}
module_init (asus_oled_init);
module_exit (asus_oled_exit);
<s:74x32>
0
0
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
01111111111000000000000000000000000000000000000000000000000000000000000000
00011111100000000000000111000000000000000000000000000000000000000000000000
00001111000000000000000111000000000000000000000000000000000000000000000000
00001111000000000000000111000000000000000000000000000000000000000000000000
00001111000000000000000000000000000000000000000000000000000000000000000000
00001111000000000000000000000000000000000000000000000000000000000000000000
00001111000000000000011100001111111111100000111110011111100011111101111000
00001111000000000000111110000011111000111000111110000111100001111000110000
00001111000000000001101110000011111000111000001111000111100000111100100000
00001111000000000001001110000011110000111100001111000111100000111101100000
00001111000000000100001110000011110000111100001111000111100000011111000000
00001111000000000100011110000011110000111100001111000111100000001111000000
00001111000000000100011110000011110000111100001111000111100000001111000000
00001111000000000100011100100011110000111100001111000111100000001111100000
00001111000000001100111100100011110000111100001111000111100000001111110000
00001111000000001100111101100011110000111100001111000111100000011011110000
00001111000000011100111101000011110000111100001111000111100000010001111000
00011111000001111100111011000011110000111100001111001111100000110000111100
11111111111111111100011110001111111011111110000111110111111011111011111110
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
0
0
0
0
<f:128x16>
00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
<f:128x32>
00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
<s:32x32>
00000000000001111111000000000000
0000000000001 100000000000
000000000001 10000000000
000000000001 10000000000
000000000001 10000000000
000000000001 1 111 10000000000
000000000001 1 1 1000000000
000000000001 111 1000000000
000000000001 111111 1000000000
000000000001 111111 1000000000
000000000001 1 1 100000000
00000000001 11 100000000
00000000001 11111111 10000000
0000000001 11111111 1000000
000000001 111111111 1000000
000000001 1111111111 100000
00000001 11111111111 100000
00000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
000000011 11111111111 10000
000011 11 11111111111 100000
0001 1111 111111111111111 1000
001 1111111 11111111111111 1000
001 1111111 1111111 111111 100
001 11111111 111111 1111111 10
001 11111111 11111 100
001 1111111 111 11100
000111 111 11111 11 100000
000000111 111111111 1000000
<r:32x32>
00000000000001111111000000000000
0000000000001 100000000000
000000000001 10000000000
000000000001 10000000000
000000000001 10000000000
000000000001 1 111 10000000000
000000000001 1 1 1000000000
000000000001 111 1000000000
000000000001 111111 1000000000
000000000001 111111 1000000000
000000000001 1 1 100000000
00000000001 11 100000000
00000000001 11111111 10000000
0000000001 11111111 1000000
000000001 111111111 1000000
000000001 1111111111 100000
00000001 11111111111 100000
00000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
0000001 111111111111 10000
000000011 11111111111 10000
000011 11 11111111111 100000
0001 1111 111111111111111 1000
001 1111111 11111111111111 1000
001 1111111 1111111 111111 100
001 11111111 111111 1111111 10
001 11111111 11111 100
001 1111111 111 11100
000111 111 11111 11 100000
000000111 111111111 1000000
<r:256x32>
000000000000000000000000000000000000000000000000000000000000011111110000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1 111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1 1 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111100000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000001 1 1 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000001 11 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000001 11111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000011100001111111111100000111110011111100011111101111000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000001 11111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000111110000011111000111000111110000111100001111000110000000000000000000000000000000
000000000000000000000000000000000000000000000000000000001 111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001101110000011111000111000001111000111100000111100100000000000000000000000000000000
000000000000000000000000000000000000000000000000000000001 1111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001001110000011110000111100001111000111100000111101100000000000000000000000000000000
00000000000000000000000000000000000000000000000000000001 11111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100001110000011110000111100001111000111100000011111000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000001 111111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000011110000000001000111100000111100001111000011110001111000000011110000000
0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011110000011110000111100001111000111100000001111000000
0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011100100011110000111100001111000111100000001111100000000000000000000000000000000
0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111100100011110000111100001111000111100000001111110000000000000000000000000000000
0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111101100011110000111100001111000111100000011011110000000000000000000000000000000
000000000000000000000000000000000000000000000000000000011 11111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000011100111101000011110000111100001111000111100000010001111000000000000000000000000000000
000000000000000000000000000000000000000000000000000011 11 11111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000011111000001111100111011000011110000111100001111001111100000110000111100000000000000000000000000000
0000000000000000000000000000000000000000000000000001 1111 111111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111100011110001111111011111110000111110111111011111011111110000000000000000000000000000
000000000000000000000000000000000000000000000000001 1111111 11111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000001 1111111 1111111 111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000001 11111111 111111 1111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000001 11111111 11111 1000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000001 1111111 111 111000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000111 111 11111 11 10
000000000000000000000000000000000000000000000000000000111 111111111 10
<r:128x32>
10000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000001
01000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000000000010
00100000000000000000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000100
00010000000000000000000000000000000000000000000000000000000010000001000000000000000000000000000000000000000000000000000000001000
00001000000000000000000000000000000000000000000000000000000100000000100000000000000000000000000000000000000000000000000000010000
00000100000000000000000000000000000000000000000000000000001000000000010000000000000000000000000000000000000000000000000000100000
00000010000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000001000000
00000001000000000000000000000000000000000000000000000000100000000000000100000000000000000000000000000000000000000000000010000000
00000000100000000000000000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000100000000
00000000010000000000000000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000001000000000
00000000001000000000000000000000000000000000000000000100000000000000000000100000000000000000000000000000000000000000010000000000
00000000000100000000000000000000000000000000000000001000000000000000000000010000000000000000000000000000000000000000100000000000
00000000000010000000000000000000000000000000000000010000000000000000000000001000000000000000000000000000000000000001000000000000
00000000000001000000000000000000000000000000000000100000000000000000000000000100000000000000000000000000000000000010000000000000
00000000000000100000000000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000100000000000000
00000000000000010000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000001000000000000000
00000000000000001000000000000000000000000000000100000000000000000000000000000000100000000000000000000000000000010000000000000000
00000000000000000100000000000000000000000000001000000000000000000000000000000000010000000000000000000000000000100000000000000000
00000000000000000010000000000000000000000000010000000000000000000000000000000000001000000000000000000000000001000000000000000000
00000000000000000001000000000000000000000000100000000000000000000000000000000000000100000000000000000000000010000000000000000000
00000000000000000000100000000000000000000001000000000000000000000000000000000000000010000000000000000000000100000000000000000000
00000000000000000000010000000000000000000010000000000000000000000000000000000000000001000000000000000000001000000000000000000000
00000000000000000000001000000000000000000100000000000000000000000000000000000000000000100000000000000000010000000000000000000000
00000000000000000000000100000000000000001000000000000000000000000000000000000000000000010000000000000000100000000000000000000000
00000000000000000000000010000000000000010000000000000000000000000000000000000000000000001000000000000001000000000000000000000000
00000000000000000000000001000000000000100000000000000000000000000000000000000000000000000100000000000010000000000000000000000000
00000000000000000000000000100000000001000000000000000000000000000000000000000000000000000010000000000100000000000000000000000000
00000000000000000000000000010000000010000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000
00000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000100000010000000000000000000000000000
00000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000
00000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000001001000000000000000000000000000000
00000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment