summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2015-07-06 16:06:52 +0200
committerHans de Goede <hdegoede@redhat.com>2015-07-06 17:19:27 +0200
commitd5b1640402cc77b873fbb865ec15da8b333a27ab (patch)
treeb0496071b358cd91bf2450630b6c3c959cf24385
parent131cde3a1d48a9fa6bd0d9e4430d32eab58438fd (diff)
Add support for setting eco-mode
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--gm12u320_drv.c1
-rw-r--r--gm12u320_main.c190
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;