diff options
author | Hans de Goede <hdegoede@redhat.com> | 2015-07-06 16:06:52 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2015-07-06 17:19:27 +0200 |
commit | d5b1640402cc77b873fbb865ec15da8b333a27ab (patch) | |
tree | b0496071b358cd91bf2450630b6c3c959cf24385 | |
parent | 131cde3a1d48a9fa6bd0d9e4430d32eab58438fd (diff) |
Add support for setting eco-mode
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | gm12u320_drv.c | 1 | ||||
-rw-r--r-- | gm12u320_main.c | 190 |
2 files changed, 144 insertions, 47 deletions
diff --git a/gm12u320_drv.c b/gm12u320_drv.c index c2b3df0..1469f56 100644 --- a/gm12u320_drv.c +++ b/gm12u320_drv.c @@ -124,4 +124,5 @@ static struct usb_driver gm12u320_driver = { }; module_usb_driver(gm12u320_driver); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_LICENSE("GPL"); diff --git a/gm12u320_main.c b/gm12u320_main.c index ba4154e..011444e 100644 --- a/gm12u320_main.c +++ b/gm12u320_main.c @@ -15,8 +15,14 @@ #include <linux/dma-buf.h> #include "gm12u320_drv.h" +static bool eco_mode; +module_param(eco_mode, bool, 0644); +MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); + +#define MISC_RCV_EPT 1 #define DATA_RCV_EPT 2 #define DATA_SND_EPT 3 +#define MISC_SND_EPT 4 #define DATA_BLOCK_HEADER_SIZE 84 #define DATA_BLOCK_CONTENT_SIZE 64512 @@ -30,49 +36,77 @@ DATA_BLOCK_FOOTER_SIZE #define CMD_SIZE 31 -#define READ_BLOCK_SIZE 13 - -#define CMD_TIMEOUT msecs_to_jiffies(200) -#define DATA_TIMEOUT msecs_to_jiffies(1000) -#define IDLE_TIMEOUT msecs_to_jiffies(2000) -#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000) - -static const char cmd_data[CMD_SIZE] = - {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x68, 0xfc, 0x00, 0x00, - 0x00, 0x00, 0x10, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -static const char cmd_draw[CMD_SIZE] = - {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0xfe, 0x00, 0x00, 0x00, 0xc0, 0xd1, 0x05, 0x00, 0x40, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -static const char data_block_header[DATA_BLOCK_HEADER_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x15, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0x00, 0x00, 0xdb }; - -static const char data_last_block_header[DATA_BLOCK_HEADER_SIZE] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0x00, 0x20, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0xd7 }; - -static const char data_block_footer[DATA_BLOCK_FOOTER_SIZE] = - { 0xfb, 0x14, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x4f }; - -static const char bl_get_set_brightness[CMD_SIZE] = - {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x80, 0x01, 0x10, 0xfd, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x35, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; +#define READ_STATUS_SIZE 13 +#define MISC_VALUE_SIZE 4 + +#define CMD_TIMEOUT msecs_to_jiffies(200) +#define DATA_TIMEOUT msecs_to_jiffies(1000) +#define IDLE_TIMEOUT msecs_to_jiffies(2000) +#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000) + +#define MISC_REQ_GET_SET_ECO_A 0xff +#define MISC_REQ_GET_SET_ECO_B 0x35 +/* Windows driver does once evert second, with with arg d = 1, others 0 */ +#define MISC_REQ_UNKNOWN1_A 0xff +#define MISC_REQ_UNKNOWN1_B 0x38 +/* Windows driver does this on init, with arg a, b = 0, c = 0xa0, d = 4 */ +#define MISC_REQ_UNKNOWN2_A 0xa5 +#define MISC_REQ_UNKNOWN2_B 0x00 + +static const char cmd_data[CMD_SIZE] = { + 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const char cmd_draw[CMD_SIZE] = { + 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfe, + 0x00, 0x00, 0x00, 0xc0, 0xd1, 0x05, 0x00, 0x40, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const char cmd_misc[CMD_SIZE] = { + 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x01, 0x10, 0xfd, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const char data_block_header[DATA_BLOCK_HEADER_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x15, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x01, 0x00, 0x00, 0xdb +}; + +static const char data_last_block_header[DATA_BLOCK_HEADER_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x20, 0x00, 0xc0, 0x0f, 0x00, 0x00, + 0x01, 0x00, 0x00, 0xd7 +}; + +static const char data_block_footer[DATA_BLOCK_FOOTER_SIZE] = { + 0xfb, 0x14, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x4f +}; static int gm12u320_usb_alloc(struct gm12u320_device *gm12u320) { @@ -115,6 +149,62 @@ static void gm12u320_usb_free(struct gm12u320_device *gm12u320) kfree(gm12u320->cmd_buf); } +static int gm12u320_misc_request(struct gm12u320_device *gm12u320, + u8 req_a, u8 req_b, + u8 arg_a, u8 arg_b, u8 arg_c, u8 arg_d) +{ + int ret, len; + u8 *buf, val; + + buf = kmalloc(CMD_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, &cmd_misc, CMD_SIZE); + buf[20] = req_a; + buf[21] = req_b; + buf[22] = arg_a; + buf[23] = arg_b; + buf[24] = arg_c; + buf[25] = arg_d; + + /* Send request */ + ret = usb_bulk_msg(gm12u320->udev, + usb_sndbulkpipe(gm12u320->udev, MISC_SND_EPT), + buf, CMD_SIZE, &len, CMD_TIMEOUT); + if (ret || len != CMD_SIZE) { + dev_err(&gm12u320->udev->dev, "Misc. req. error %d\n", ret); + ret = -EIO; + goto leave; + } + + /* Read value */ + ret = usb_bulk_msg(gm12u320->udev, + usb_rcvbulkpipe(gm12u320->udev, MISC_RCV_EPT), + buf, MISC_VALUE_SIZE, &len, DATA_TIMEOUT); + if (ret || len != MISC_VALUE_SIZE) { + dev_err(&gm12u320->udev->dev, "Misc. value error %d\n", ret); + ret = -EIO; + goto leave; + } + val = buf[0]; + + /* Read status */ + ret = usb_bulk_msg(gm12u320->udev, + usb_rcvbulkpipe(gm12u320->udev, MISC_RCV_EPT), + buf, READ_STATUS_SIZE, &len, CMD_TIMEOUT); + if (ret || len != READ_STATUS_SIZE) { + dev_err(&gm12u320->udev->dev, "Misc. status error %d\n", ret); + ret = -EIO; + goto leave; + } + + ret = val; +leave: + kfree(buf); + return ret; +} + void gm12u320_32bpp_to_24bpp_packed(u8 *dst, u8 *src, int len) { while (len--) { @@ -266,9 +356,9 @@ static void gm12u320_fb_update_work(struct work_struct *work) /* Read status */ ret = usb_bulk_msg(gm12u320->udev, usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT), - gm12u320->cmd_buf, READ_BLOCK_SIZE, &len, + gm12u320->cmd_buf, READ_STATUS_SIZE, &len, CMD_TIMEOUT); - if (ret || len != READ_BLOCK_SIZE) + if (ret || len != READ_STATUS_SIZE) goto err; } @@ -283,9 +373,9 @@ static void gm12u320_fb_update_work(struct work_struct *work) /* Read status */ ret = usb_bulk_msg(gm12u320->udev, usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT), - gm12u320->cmd_buf, READ_BLOCK_SIZE, &len, + gm12u320->cmd_buf, READ_STATUS_SIZE, &len, draw_status_timeout); - if (ret || len != READ_BLOCK_SIZE) + if (ret || len != READ_STATUS_SIZE) goto err; draw_status_timeout = CMD_TIMEOUT; @@ -317,6 +407,12 @@ int gm12u320_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&gm12u320->fb_update.lock); init_waitqueue_head(&gm12u320->fb_update.waitq); + ret = gm12u320_misc_request(gm12u320, MISC_REQ_GET_SET_ECO_A, + MISC_REQ_GET_SET_ECO_B, 0x01 /* set */, + eco_mode ? 0x01 : 0x00, 0x00, 0x01); + if (ret) + goto err; + ret = gm12u320_usb_alloc(gm12u320); if (ret) goto err; |