[gnome-settings-daemon/gnome-3-12] wacom: add Bluetooth OLED handling for Intuos4 WL
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon/gnome-3-12] wacom: add Bluetooth OLED handling for Intuos4 WL
- Date: Wed, 7 May 2014 15:47:08 +0000 (UTC)
commit a1f98e5a4bd86f663239a6d824deba70774d3a11
Author: Przemo Firszt <przemo firszt eu>
Date: Tue Mar 11 21:32:00 2014 +0000
wacom: add Bluetooth OLED handling for Intuos4 WL
That patch implements OLED handling over bluetooth for Intuos4 Wireless
tablets. Due to the nature of the device which accepts 4 bit colour images over
USB and only 1 bit colour images we have to handle those 2 situations
differently.
On top of that kernel side has been implemented in such way that
the images for USB connection have to be scrambled in userland before they are
send to the device.
The decision to move scrambling to the OLED helper and to
have 4-bit to 1-bit conversion in the same location is the cleanest solution
that I found to the problem of inconsistent image formatting. It changes
the previous approach to keep scrambling out of the helper which is executed
with elevated privileges.
https://bugzilla.gnome.org/show_bug.cgi?id=724955
plugins/wacom/Makefile.am | 3 +-
plugins/wacom/gsd-wacom-oled-constants.h | 40 +++++++
plugins/wacom/gsd-wacom-oled-helper.c | 174 ++++++++++++++++++++++++++----
plugins/wacom/gsd-wacom-oled.c | 27 +-----
plugins/wacom/gsd-wacom-oled.h | 10 +--
5 files changed, 199 insertions(+), 55 deletions(-)
---
diff --git a/plugins/wacom/Makefile.am b/plugins/wacom/Makefile.am
index 01ee14a..6274e43 100644
--- a/plugins/wacom/Makefile.am
+++ b/plugins/wacom/Makefile.am
@@ -14,6 +14,7 @@ libgsdwacom_la_SOURCES = \
gsd-wacom-osd-window.c \
gsd-wacom-oled.h \
gsd-wacom-oled.c \
+ gsd-wacom-oled-constants.h \
gsd-wacom-device.c \
gsd-wacom-device.h \
gsd-wacom-resources.c
@@ -59,7 +60,7 @@ polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy)
# so it always gets included in the tarball
gsd_wacom_led_helper_SOURCES = gsd-wacom-led-helper.c
-gsd_wacom_oled_helper_SOURCES = gsd-wacom-oled-helper.c
+gsd_wacom_oled_helper_SOURCES = gsd-wacom-oled-helper.c gsd-wacom-oled-constants.h
EXTRA_DIST = $(gsd_wacom_led_helper_SOURCES) wacom.gresource.xml tablet-layout.css \
$(gsd_wacom_oled_helper_SOURCES)
diff --git a/plugins/wacom/gsd-wacom-oled-constants.h b/plugins/wacom/gsd-wacom-oled-constants.h
new file mode 100644
index 0000000..b779cd2
--- /dev/null
+++ b/plugins/wacom/gsd-wacom-oled-constants.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Przemo Firszt <przemo firszt eu>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __GSD_WACOM_OLED_CONSTANTS_H
+#define __GSD_WACOM_OLED_CONSTANTS_H
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GSD_WACOM_OLED_TYPE_USB,
+ GSD_WACOM_OLED_TYPE_BLUETOOTH
+} GsdWacomOledType;
+
+/* OLED parameters */
+#define OLED_WIDTH 64 /*Width of OLED icon - hardware dependent*/
+#define OLED_HEIGHT 32 /*Height of OLED icon - hardware dependent*/
+#define LABEL_SIZE 30 /*Maximum length of text for OLED icon*/
+#define MAX_TOKEN (LABEL_SIZE >> 1) /*Maximum number of tokens equals half of maximum
number of characters*/
+#define MAX_IMAGE_SIZE 1024 /*Size of buffer for storing OLED image*/
+#define MAX_1ST_LINE_LEN 10 /*Maximum number of characters in 1st line of OLED
icon*/
+
+G_END_DECLS
+
+#endif /* __GSD_WACOM_OLED_CONSTANTS_H */
diff --git a/plugins/wacom/gsd-wacom-oled-helper.c b/plugins/wacom/gsd-wacom-oled-helper.c
index 99be48a..945286d 100644
--- a/plugins/wacom/gsd-wacom-oled-helper.c
+++ b/plugins/wacom/gsd-wacom-oled-helper.c
@@ -34,8 +34,73 @@
#include <fcntl.h>
#include <gudev/gudev.h>
+#include "gsd-wacom-oled-constants.h"
+
+#define USB_PIXELS_PER_BYTE 2
+#define BT_PIXELS_PER_BYTE 8
+#define USB_BUF_LEN OLED_HEIGHT * OLED_WIDTH / USB_PIXELS_PER_BYTE
+#define BT_BUF_LEN OLED_WIDTH * OLED_HEIGHT / BT_PIXELS_PER_BYTE
+
+static void
+oled_scramble_icon (guchar *image)
+{
+ guchar buf[USB_BUF_LEN];
+ int x, y, i;
+ guchar l1, l2, h1, h2;
+
+ for (i = 0; i < USB_BUF_LEN; i++)
+ buf[i] = image[i];
+
+ for (y = 0; y < (OLED_HEIGHT / 2); y++) {
+ for (x = 0; x < (OLED_WIDTH / 2); x++) {
+ l1 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y]));
+ l2 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y] >> 4));
+ h1 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y] << 4));
+ h2 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y]));
+
+ image[2 * x + OLED_WIDTH * y] = h1 | l1;
+ image[2 * x + 1 + OLED_WIDTH * y] = h2 | l2;
+ }
+ }
+}
+
+static int
+gsd_wacom_oled_prepare_buf (guchar *image, GsdWacomOledType type)
+{
+ guchar buf[BT_BUF_LEN];
+ guchar b0, b1, b2, b3, b4, b5, b6, b7;
+ int i;
+ int len = 0;
+
+ if (type == GSD_WACOM_OLED_TYPE_USB) {
+ /* Image has to be scrambled for devices connected over USB ... */
+ oled_scramble_icon (image);
+ len = USB_BUF_LEN;
+ } else if (type == GSD_WACOM_OLED_TYPE_BLUETOOTH) {
+ /* ... but for bluetooth it has to be converted to 1 bit colour instead of scrambling */
+ for (i = 0; i < BT_BUF_LEN; i++) {
+ b0 = 0b10000000 & (image[(4 * i) + 0] >> 0);
+ b1 = 0b01000000 & (image[(4 * i) + 0] << 3);
+ b2 = 0b00100000 & (image[(4 * i) + 1] >> 2);
+ b3 = 0b00010000 & (image[(4 * i) + 1] << 1);
+ b4 = 0b00001000 & (image[(4 * i) + 2] >> 4);
+ b5 = 0b00000100 & (image[(4 * i) + 2] >> 1);
+ b6 = 0b00000010 & (image[(4 * i) + 3] >> 6);
+ b7 = 0b00000001 & (image[(4 * i) + 3] >> 3);
+ buf[i] = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7;
+ }
+ for (i = 0; i < BT_BUF_LEN; i++)
+ image[i] = buf[i];
+ len = BT_BUF_LEN;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ return len;
+}
+
static gboolean
-gsd_wacom_oled_helper_write (const gchar *filename, gchar *buffer, GError **error)
+gsd_wacom_oled_helper_write (const gchar *filename, gchar *buffer, GsdWacomOledType type, GError **error)
{
guchar *image;
gint retval;
@@ -46,19 +111,33 @@ gsd_wacom_oled_helper_write (const gchar *filename, gchar *buffer, GError **erro
fd = open (filename, O_WRONLY);
if (fd < 0) {
ret = FALSE;
- g_set_error (error, 1, 0, "failed to open filename: %s", filename);
+ g_set_error (error, 1, 0, "Failed to open filename: %s", filename);
goto out;
}
image = g_base64_decode (buffer, &length);
- if (!image)
+ if (length != USB_BUF_LEN) {
+ ret = FALSE;
+ g_set_error (error, 1, 0, "Base64 buffer has length of %" G_GSIZE_FORMAT " (expected %i)",
length, USB_BUF_LEN);
goto out;
+ }
+ if (!image) {
+ ret = FALSE;
+ g_set_error (error, 1, 0, "Decoding base64 buffer failed");
+ goto out;
+ }
+
+ length = gsd_wacom_oled_prepare_buf (image, type);
+ if (!length) {
+ ret = FALSE;
+ g_set_error (error, 1, 0, "Invalid image buffer length");
+ goto out;
+ }
- /* write to device file */
retval = write (fd, image, length);
if (retval != length) {
ret = FALSE;
- g_set_error (error, 1, 0, "writing to %s failed", filename);
+ g_set_error (error, 1, 0, "Writing to %s failed", filename);
}
g_free (image);
@@ -82,6 +161,48 @@ get_oled_sysfs_path (GUdevDevice *device,
return filename;
}
+static char *
+get_bt_oled_sysfs_path (GUdevDevice *device, int button_num)
+{
+ char *status;
+ char *filename;
+
+ status = g_strdup_printf ("/oled%i_img", button_num);
+ filename = g_build_filename (g_udev_device_get_sysfs_path (device), status, NULL);
+ g_free (status);
+ return filename;
+}
+
+static char *
+get_bt_oled_filename (GUdevClient *client, GUdevDevice *device, int button_num)
+{
+ GUdevDevice *hid_dev;
+ const char *dev_uniq;
+ GList *hid_list;
+ GList *element;
+ const char *dev_hid_uniq;
+ char *filename = NULL;
+
+ dev_uniq = g_udev_device_get_property (device, "UNIQ");
+
+ hid_list = g_udev_client_query_by_subsystem (client, "hid");
+ element = g_list_first(hid_list);
+ while (element) {
+ hid_dev = (GUdevDevice*)element->data;
+ dev_hid_uniq = g_udev_device_get_property (hid_dev, "HID_UNIQ");
+ if (g_strrstr (dev_uniq, dev_hid_uniq)){
+ filename = get_bt_oled_sysfs_path (hid_dev, button_num);
+ g_object_unref (hid_dev);
+ break;
+ }
+ g_object_unref (hid_dev);
+ element = g_list_next(element);
+ }
+ g_list_free(hid_list);
+ return filename;
+}
+
+
int main (int argc, char **argv)
{
GOptionContext *context;
@@ -92,6 +213,7 @@ int main (int argc, char **argv)
GError *error = NULL;
const char * const subsystems[] = { "input", NULL };
int ret = 1;
+ GsdWacomOledType type;
char *path = NULL;
char *buffer = "";
@@ -134,33 +256,45 @@ int main (int argc, char **argv)
client = g_udev_client_new (subsystems);
device = g_udev_client_query_by_device_file (client, path);
if (device == NULL) {
- g_debug ("Could not find device '%s' in udev database", path);
+ g_critical ("Could not find device '%s' in udev database", path);
goto out;
}
if (g_udev_device_get_property_as_boolean (device, "ID_INPUT_TABLET") == FALSE &&
g_udev_device_get_property_as_boolean (device, "ID_INPUT_TOUCHPAD") == FALSE) {
- g_debug ("Device '%s' is not a Wacom tablet", path);
+ g_critical ("Device '%s' is not a Wacom tablet", path);
goto out;
}
- if (g_strcmp0 (g_udev_device_get_property (device, "ID_BUS"), "usb") != 0) {
- /* FIXME handle Bluetooth OLEDs too */
- g_debug ("Non-USB OLEDs setting is not (yet) supported");
- goto out;
- }
+ if (g_strcmp0 (g_udev_device_get_property (device, "ID_BUS"), "usb") == 0) {
+ parent = g_udev_device_get_parent_with_subsystem (device, "usb", "usb_interface");
+ if (parent == NULL) {
+ g_critical ("Could not find parent USB device for '%s'", path);
+ goto out;
+ }
+ g_object_unref (device);
+ device = parent;
+
+ filename = get_oled_sysfs_path (device, button_num);
+ type = GSD_WACOM_OLED_TYPE_USB;
+ } else if (g_strrstr( g_udev_device_get_property (device, "DEVPATH"), "bluetooth")) {
+ parent = g_udev_device_get_parent (device);
+ if (parent == NULL) {
+ g_critical ("Could not find parent device for '%s'", path);
+ goto out;
+ }
+ g_object_unref (device);
+ device = parent;
- parent = g_udev_device_get_parent_with_subsystem (device, "usb", "usb_interface");
- if (parent == NULL) {
- g_debug ("Could not find parent USB device for '%s'", path);
+ filename = get_bt_oled_filename (client, device, button_num);
+ type = GSD_WACOM_OLED_TYPE_BLUETOOTH;
+ } else {
+ g_critical ("Not an expected device: %s", path);
goto out;
}
- g_object_unref (device);
- device = parent;
- filename = get_oled_sysfs_path (device, button_num);
- if (gsd_wacom_oled_helper_write (filename, buffer, &error) == FALSE) {
- g_debug ("Could not set OLED icon for '%s': %s", path, error->message);
+ if (gsd_wacom_oled_helper_write (filename, buffer, type, &error) == FALSE) {
+ g_critical ("Could not set OLED icon for '%s': %s", path, error->message);
g_error_free (error);
g_free (filename);
goto out;
diff --git a/plugins/wacom/gsd-wacom-oled.c b/plugins/wacom/gsd-wacom-oled.c
index 5163568..004edcf 100644
--- a/plugins/wacom/gsd-wacom-oled.c
+++ b/plugins/wacom/gsd-wacom-oled.c
@@ -35,29 +35,6 @@
#define ROTATION_KEY "rotation"
static void
-oled_scramble_icon (guchar* image)
-{
- unsigned char buf[MAX_IMAGE_SIZE];
- int x, y, i;
- unsigned char l1, l2, h1, h2;
-
- for (i = 0; i < MAX_IMAGE_SIZE; i++)
- buf[i] = image[i];
-
- for (y = 0; y < (OLED_HEIGHT / 2); y++) {
- for (x = 0; x < (OLED_WIDTH / 2); x++) {
- l1 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y]));
- l2 = (0x0F & (buf[OLED_HEIGHT - 1 - x + OLED_WIDTH * y] >> 4));
- h1 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y] << 4));
- h2 = (0xF0 & (buf[OLED_WIDTH - 1 - x + OLED_WIDTH * y]));
-
- image[2 * x + OLED_WIDTH * y] = h1 | l1;
- image[2 * x + 1 + OLED_WIDTH * y] = h2 | l2;
- }
- }
-}
-
-static void
oled_surface_to_image (guchar *image,
cairo_surface_t *surface)
{
@@ -220,7 +197,6 @@ gsd_wacom_oled_gdkpixbuf_to_base64 (GdkPixbuf *pixbuf)
}
}
- oled_scramble_icon (image);
base_string = g_base64_encode (image, MAX_IMAGE_SIZE);
base64 = g_strconcat (MAGIC_BASE64, base_string, NULL);
g_free (base_string);
@@ -233,13 +209,12 @@ static char *
oled_encode_image (char *label,
GsdWacomRotation rotation)
{
- guchar *image;
+ unsigned char *image;
image = g_malloc (MAX_IMAGE_SIZE);
/* convert label to image */
oled_render_text (label, image, rotation);
- oled_scramble_icon (image);
return (g_base64_encode (image, MAX_IMAGE_SIZE));
}
diff --git a/plugins/wacom/gsd-wacom-oled.h b/plugins/wacom/gsd-wacom-oled.h
index 933355a..f71176a 100644
--- a/plugins/wacom/gsd-wacom-oled.h
+++ b/plugins/wacom/gsd-wacom-oled.h
@@ -17,19 +17,13 @@
*
*/
+#include "gsd-wacom-oled-constants.h"
+
#ifndef __GSD_WACOM_OLED_H
#define __GSD_WACOM_OLED_H
G_BEGIN_DECLS
-/* OLED parameters */
-#define OLED_WIDTH 64 /*Width of OLED icon - hardware dependent*/
-#define OLED_HEIGHT 32 /*Height of OLED icon - hardware dependent*/
-#define LABEL_SIZE 30 /*Maximum length of text for OLED icon*/
-#define MAX_TOKEN (LABEL_SIZE >> 1) /*Maximum number of tokens equals half of maximum
number of characters*/
-#define MAX_IMAGE_SIZE 1024 /*Size of buffer for storing OLED image*/
-#define MAX_1ST_LINE_LEN 10 /*Maximum number of characters in 1st line of OLED
icon*/
-
void set_oled (GsdWacomDevice *device, char *button_id, char *label);
char *gsd_wacom_oled_gdkpixbuf_to_base64 (GdkPixbuf *pixbuf);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]