public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [Bluez-devel] [PATCH] Dinovo Mediapad LCD support in Input service
@ 2007-09-27  2:43 Tim Hentenaar
  0 siblings, 0 replies; only message in thread
From: Tim Hentenaar @ 2007-09-27  2:43 UTC (permalink / raw)
  To: bluez-devel

[-- Attachment #1: Type: text/plain, Size: 333 bytes --]


Hello all,

Here is a patch against bluez-utils 3.19 to enable support for the
Dinovo Mediapad LCD. Originally, I implemented this in hidd, but since
hidd is "dead" I've revised my patch. 

This patch also addresses a bug in common/dbus.c where a pointer goes
unchecked and caused a segfault or two during my testing.

Regards,

Tim

[-- Attachment #2: input.patch --]
[-- Type: text/x-patch, Size: 36070 bytes --]

diff -ru bluez-utils-3.19/common/dbus.c bluez-utils-3.19/common/dbus.c
--- bluez-utils-3.19/common/dbus.c	2007-06-23 18:55:58.000000000 -0400
+++ bluez-utils-3.19/common/dbus.c	2007-09-26 01:13:05.688764887 -0400
@@ -524,8 +524,10 @@
 
 	dbus_watch_handle(watch, flags);
 
-	if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
-		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+	if (info) {
+		if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
+			g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+	}
 
 	return TRUE;
 }
diff -ru bluez-utils-3.19/input/Makefile.am bluez-utils-3.19/input/Makefile.am
--- bluez-utils-3.19/input/Makefile.am	2007-05-09 02:40:43.000000000 -0400
+++ bluez-utils-3.19/input/Makefile.am	2007-09-22 18:50:03.676128422 -0400
@@ -2,8 +2,10 @@
 if INPUTSERVICE
 if CONFIGFILES
 confdir = $(sysconfdir)/bluetooth
+conf_DATA = input.service 
 
-conf_DATA = input.service
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dbus_DATA = dinovo.conf
 endif
 
 servicedir = $(libdir)/bluetooth
@@ -12,7 +14,8 @@
 
 bluetoothd_service_input_SOURCES = main.c \
 	manager.h manager.c error.h error.c \
-	server.h server.c device.h device.c storage.h storage.c
+	server.h server.c device.h device.c storage.h storage.c \
+	logitech_mediapad.c
 
 LDADD = $(top_builddir)/common/libhelper.a \
 		@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
@@ -22,6 +25,6 @@
 
 INCLUDES = -I$(top_srcdir)/common
 
-EXTRA_DIST = input.service input-api.txt test-input
+EXTRA_DIST = input.service dinovo.conf input-api.txt test-input
 
 MAINTAINERCLEANFILES = Makefile.in
diff -ru bluez-utils-3.19/input/Makefile.in bluez-utils-3.19/input/Makefile.in
--- bluez-utils-3.19/input/Makefile.in	2007-09-16 04:10:09.000000000 -0400
+++ bluez-utils-3.19/input/Makefile.in	2007-09-22 18:54:43.556077871 -0400
@@ -45,16 +45,18 @@
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
-am__installdirs = "$(DESTDIR)$(servicedir)" "$(DESTDIR)$(confdir)"
+am__installdirs = "$(DESTDIR)$(servicedir)" "$(DESTDIR)$(confdir)" \
+	"$(DESTDIR)$(dbusdir)"
 servicePROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(service_PROGRAMS)
 am__bluetoothd_service_input_SOURCES_DIST = main.c manager.h manager.c \
 	error.h error.c server.h server.c device.h device.c storage.h \
-	storage.c
+	storage.c logitech_mediapad.c
 @INPUTSERVICE_TRUE@am_bluetoothd_service_input_OBJECTS =  \
 @INPUTSERVICE_TRUE@	main.$(OBJEXT) manager.$(OBJEXT) \
 @INPUTSERVICE_TRUE@	error.$(OBJEXT) server.$(OBJEXT) \
-@INPUTSERVICE_TRUE@	device.$(OBJEXT) storage.$(OBJEXT)
+@INPUTSERVICE_TRUE@	device.$(OBJEXT) storage.$(OBJEXT) \
+@INPUTSERVICE_TRUE@	logitech_mediapad.$(OBJEXT)
 bluetoothd_service_input_OBJECTS =  \
 	$(am_bluetoothd_service_input_OBJECTS)
 bluetoothd_service_input_LDADD = $(LDADD)
@@ -81,7 +83,8 @@
   esac;
 am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
 confDATA_INSTALL = $(INSTALL_DATA)
-DATA = $(conf_DATA)
+dbusDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(conf_DATA) $(dbus_DATA)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -214,18 +217,21 @@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 @CONFIGFILES_TRUE@@INPUTSERVICE_TRUE@confdir = $(sysconfdir)/bluetooth
-@CONFIGFILES_TRUE@@INPUTSERVICE_TRUE@conf_DATA = input.service
+@CONFIGFILES_TRUE@@INPUTSERVICE_TRUE@conf_DATA = input.service 
+@CONFIGFILES_TRUE@@INPUTSERVICE_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d
+@CONFIGFILES_TRUE@@INPUTSERVICE_TRUE@dbus_DATA = dinovo.conf
 @INPUTSERVICE_TRUE@servicedir = $(libdir)/bluetooth
 @INPUTSERVICE_TRUE@bluetoothd_service_input_SOURCES = main.c \
 @INPUTSERVICE_TRUE@	manager.h manager.c error.h error.c \
-@INPUTSERVICE_TRUE@	server.h server.c device.h device.c storage.h storage.c
+@INPUTSERVICE_TRUE@	server.h server.c device.h device.c storage.h storage.c \
+@INPUTSERVICE_TRUE@	logitech_mediapad.c
 
 @INPUTSERVICE_TRUE@LDADD = $(top_builddir)/common/libhelper.a \
 @INPUTSERVICE_TRUE@		@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 
 AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
 INCLUDES = -I$(top_srcdir)/common
-EXTRA_DIST = input.service input-api.txt test-input
+EXTRA_DIST = input.service dinovo.conf input-api.txt test-input
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 
@@ -300,6 +306,7 @@
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logitech_mediapad.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
@@ -348,6 +355,23 @@
 	  echo " rm -f '$(DESTDIR)$(confdir)/$$f'"; \
 	  rm -f "$(DESTDIR)$(confdir)/$$f"; \
 	done
+install-dbusDATA: $(dbus_DATA)
+	@$(NORMAL_INSTALL)
+	test -z "$(dbusdir)" || $(MKDIR_P) "$(DESTDIR)$(dbusdir)"
+	@list='$(dbus_DATA)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(dbusDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(dbusdir)/$$f'"; \
+	  $(dbusDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(dbusdir)/$$f"; \
+	done
+
+uninstall-dbusDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(dbus_DATA)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(dbusdir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(dbusdir)/$$f"; \
+	done
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -427,7 +451,7 @@
 check: check-am
 all-am: Makefile $(PROGRAMS) $(DATA)
 installdirs:
-	for dir in "$(DESTDIR)$(servicedir)" "$(DESTDIR)$(confdir)"; do \
+	for dir in "$(DESTDIR)$(servicedir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: install-am
@@ -476,7 +500,8 @@
 
 info-am:
 
-install-data-am: install-confDATA install-servicePROGRAMS
+install-data-am: install-confDATA install-dbusDATA \
+	install-servicePROGRAMS
 
 install-dvi: install-dvi-am
 
@@ -512,7 +537,8 @@
 
 ps-am:
 
-uninstall-am: uninstall-confDATA uninstall-servicePROGRAMS
+uninstall-am: uninstall-confDATA uninstall-dbusDATA \
+	uninstall-servicePROGRAMS
 
 .MAKE: install-am install-strip
 
@@ -521,15 +547,16 @@
 	distclean-compile distclean-generic distclean-libtool \
 	distclean-tags distdir dvi dvi-am html html-am info info-am \
 	install install-am install-confDATA install-data \
-	install-data-am install-dvi install-dvi-am install-exec \
-	install-exec-am install-html install-html-am install-info \
-	install-info-am install-man install-pdf install-pdf-am \
-	install-ps install-ps-am install-servicePROGRAMS install-strip \
-	installcheck installcheck-am installdirs maintainer-clean \
+	install-data-am install-dbusDATA install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am \
+	install-servicePROGRAMS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
 	maintainer-clean-generic mostlyclean mostlyclean-compile \
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags uninstall uninstall-am uninstall-confDATA \
-	uninstall-servicePROGRAMS
+	uninstall-dbusDATA uninstall-servicePROGRAMS
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff -ru bluez-utils-3.19/input/device.c bluez-utils-3.19/input/device.c
--- bluez-utils-3.19/input/device.c	2007-09-02 12:26:35.000000000 -0400
+++ bluez-utils-3.19/input/device.c	2007-09-22 22:19:31.160308530 -0400
@@ -52,6 +52,7 @@
 #include "error.h"
 #include "manager.h"
 #include "storage.h"
+#include "logitech_mediapad.h"
 
 #define INPUT_DEVICE_INTERFACE	"org.bluez.input.Device"
 
@@ -64,6 +65,7 @@
 	int		rfcomm; /* RFCOMM socket */
 	int		uinput;	/* uinput socket */
 	uint8_t		ch;	/* RFCOMM channel number */
+	gpointer	misc;	/* Misc. Device-dependant state data */
 };
 
 struct device {
@@ -174,11 +176,11 @@
 	ioctl(fd, UI_SET_EVBIT, EV_KEY);
 	ioctl(fd, UI_SET_EVBIT, EV_REL);
 	ioctl(fd, UI_SET_EVBIT, EV_REP);
+	ioctl(fd, UI_SET_EVBIT, EV_LED);
 
-	ioctl(fd, UI_SET_KEYBIT, KEY_UP);
-	ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP);
-	ioctl(fd, UI_SET_KEYBIT, KEY_DOWN);
-	ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN);
+	for (err=KEY_RESERVED;err <= KEY_UNKNOWN;err++) 
+		ioctl(fd,UI_SET_KEYBIT,err);
+	err = 0;
 
 	if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
 		err = errno;
@@ -621,9 +623,10 @@
 	}
 
 	err = ioctl(ctl, HIDPCONNADD, &req);
+
 cleanup:
 	close(ctl);
-
+	
 	if (req.rd_data)
 		free(req.rd_data);
 
@@ -665,12 +668,15 @@
 	}
 
 	idev->intr_sk = isk;
+
 	err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+
 	if (err < 0)
 		goto failed;
 
 	idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev);
 	idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev);
+
 	dbus_connection_emit_signal(idev->conn,
 			idev->path,
 			INPUT_DEVICE_INTERFACE,
@@ -1318,13 +1324,22 @@
 int input_device_connadd(bdaddr_t *src, bdaddr_t *dst)
 {
 	struct device *idev;
-	int err;
+	int err = 0;
 
 	idev = find_device(src, dst);
 	if (!idev)
 		return -ENOENT;
 
-	err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+	if (!strcmp(idev->name,"Logitech Bluetooth Mediapad") || !strcmp(idev->name,"Logitech Mediapad")) {
+		idev->fake         = g_new0(struct fake_input,1); err = 0;
+		idev->fake->uinput = uinput_create(idev->name);
+		idev->fake->misc   = logitech_mediapad_init(idev->intr_sk,idev->fake->uinput); 
+		idev->fake->io     = g_io_channel_unix_new(idev->intr_sk);
+		g_io_channel_set_close_on_unref(idev->fake->io, TRUE);
+		g_io_add_watch(idev->fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			      (GIOFunc) logitech_mediapad_io_cb, idev->fake->misc);
+	} else err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+
 	if (err < 0) {
 		close(idev->ctrl_sk);
 		close(idev->intr_sk);
diff -ru bluez-utils-3.19/input/dinovo.conf bluez-utils-3.19/input/dinovo.conf
--- bluez-utils-3.19/input/dinovo.conf	2007-09-22 18:53:10.450772102 -0400
+++ bluez-utils-3.19/input/dinovo.conf	2007-09-22 18:48:37.771232981 -0400
@@ -0,0 +1,18 @@
+<!-- This configuration file specifies the required security policies
+     for the Logitech Dinovo MediaPad driver. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+  <policy user="root">
+    <allow own="com.hentenaar.Dinovo.MediaPad"/>
+  </policy>
+
+  <policy at_console="true">
+    <allow send_path="/com/hentenaar"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad" />
+    <allow receive_sender="com.hentenaar.Dinovo.MediaPad"/>
+  </policy>
+</busconfig>
diff -ru bluez-utils-3.19/input/logitech_mediapad.c bluez-utils-3.19/input/logitech_mediapad.c
--- bluez-utils-3.19/input/logitech_mediapad.c	2007-09-22 18:53:15.871080988 -0400
+++ bluez-utils-3.19/input/logitech_mediapad.c	2007-09-26 22:10:37.120496939 -0400
@@ -0,0 +1,571 @@
+/************************ Logitech Mediapad Driver ********************************
+ *     (C) 2006-2007 Tim Hentenaar <tim@hentenaar.com>                            *
+ *     Licensed under the GNU General Public License.                             *
+ *     The latest version of this work is available at http://hentenaar.com       *
+ *                                                                                *
+ *     Updates:                                                                   *
+ *     		Thanks to Glen Rolle for suggesting the single-line write         *
+ *     		mode, and for showing me a better method for writing chars        *
+ *     		>= 0x80 from python.
+ *                                                                                *
+ *     Notes:                                                                     *
+ *		1) The i18n for the device isn't currently supported.             *
+ *			The way that the i18n works, is that when the device      *
+ *			connects, the Winblows app retrieves the respective       *
+ *			strings from the device and verifies/updates them.        *
+ *                                                                                *
+ *			Simple enough to do, but I'll worry about it later.       *
+ *		2) The '000' key actually sends 3 0's and is not a special key.   *
+ *		3) The "Copy calulator result to clipboard" requires an           *
+ *		   activation packet that I haven't isolated to date.             *
+ *              4) Git-R-Done!                                                    *
+ **********************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <glib.h>
+#include <syslog.h>
+
+#include "uinput.h"
+#include "logging.h"
+#include "dbus.h"
+
+/* LCD Line Flags */
+#define LCD_LINE_DISPLAY	0x10
+#define LCD_LINE_SCROLL		0x20
+#define LCD_LINE_INIT		0x01
+#define LCD_2_BUFFERS		0x02
+#define LCD_3_BUFFERS		0x03
+
+/* Icons */
+#define LCD_ICON_EMAIL		0x01
+#define LCD_ICON_IM		0x02
+#define LCD_ICON_MUTE		0x04
+#define LCD_ICON_ALERT		0x08
+#define LCD_ICON_ON		0x01
+#define LCD_ICON_BLINK		0x02
+
+/* Speaker / LED */
+#define LCD_LOW_BEEP		0x01
+#define LCD_LONG_BEEP		0x02
+#define LCD_SHORT_BEEP		0x03
+
+/* Modes */
+#define MODE_NUM		0x00
+#define MODE_NAV		0x01
+
+/* DBus Path */
+#define MP_DBUS_PATH		"com.hentenaar.Dinovo.MediaPad"
+#define MP_DBUS_SIGNAL_PATH	"/com/hentenaar/Dinovo/MediaPad"
+
+/* Mediapad State */
+struct mp_state {
+	int mode;
+	int discard_keyup;
+	int prev_key;
+	int icons;
+	int uinput;
+	int sock;
+	DBusConnection *db_conn;
+};
+
+/* Mediapad Command */
+struct mpcmd {	
+	char    command[22];
+	uint8_t len;
+};
+
+static struct mpcmd clscr[] = { /* Clear the screen */
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x10, 0x00, 0x01, 0x00 }, 8},										
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00 }, 8},										
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 21}, 
+	{{ 0xA2, 0x10, 0x00, 0x83, 0x11, 0x00, 0x00, 0x00 }, 8},										
+	{{ 0 }, 0}
+};
+
+static struct mpcmd write_icons[] = { /* Set Icons (0 = off) */
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 21}
+};
+
+static struct mpcmd write_ledspk[] = { /* LED / Speaker Control */
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x50, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x50, 0x00, 0x00, 0x00 }, 8},
+	{{ 0 }, 0}
+};
+
+static struct mpcmd write_clock[] = { /* Set the clock */ 
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x31, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x32, 0x02, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x33, 0x00, 0x00, 0x00 }, 8},
+	{{ 0 }, 0}
+};
+
+static struct mpcmd write_lcd[] = { /* Write text to the LCD */ 
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x12, 0x01, 0x01, 0x01 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x24, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x25, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x27, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x83, 0x11, 0x00, 0x00, 0x00 }, 8},
+	{{ 0 }, 0}
+};
+
+static struct mpcmd write_lcd_single[] = { /* Write a single line of text to the LCD */ 
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x12, 0x10, 0x10, 0x10 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00 }, 8},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21},
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x12, 0x10, 0x10, 0x10 }, 8},
+	{{ 0xA2, 0x10, 0x00, 0x83, 0x11, 0x00, 0x00, 0x00 }, 8},
+	{{ 0 }, 0}
+};
+
+#define N_LCDW_CMDS	14
+#define N_LCDS_CMDS	8
+
+#define inject_key(X,Y,Z) send_event(X,EV_KEY,Y,Z)
+
+static const char *introspect_ret = 
+"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+"        <node name=\"/com/hentenaar/Dinovo/MediaPad\">\n"
+"          <interface name=\"com.hentenaar.Dinovo.MediaPad\">\n"
+"            <method name=\"BlinkOrBeep\">\n"
+"              <!-- beep_type: 0 (none) | 1 (low beep) | 2 (beep-beep) | 3 (short beep)\n"
+"                   blink:     0 (no)   | 1 (yes) -->\n"
+"              <arg name=\"beep_type\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"blink\"     type=\"u\" direction=\"in\"/>\n"
+"           </method>\n"
+"            <method name=\"SetIndicator\">\n"
+"              <!-- indicator: 1 (email) | 2 (IM) | 4 (Mute) | 8 (Alert)\n"
+"                   show:      0 (hide)  | 1 (solid) | 2 (blink) -->\n"
+"              <arg name=\"indicator\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"show\"      type=\"u\" direction=\"in\"/>\n"
+"           </method>\n"
+"            <method name=\"SyncClock\" />\n"
+"            <method name=\"WriteText\">\n"
+"              <!-- Max Length: 144 -->\n"
+"              <arg name=\"text\" type=\"s\" direction=\"in\"/>\n"
+"           </method>\n"
+"            <method name=\"WriteLine\">\n"
+"              <!-- Max Length: 48 -->\n"
+"              <arg name=\"lineno\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"text\"   type=\"s\" direction=\"in\"/>\n"
+"           </method>\n"
+"            <method name=\"WriteTextBin\">\n"
+"              <!-- Max Length: 144 -->\n"
+"              <arg name=\"text\" type=\"ai\" direction=\"in\"/>\n"
+"           </method>\n"
+"            <method name=\"WriteLineBin\">\n"
+"              <!-- Max Length: 48 -->\n"
+"              <arg name=\"lineno\" type=\"u\"  direction=\"in\"/>\n"
+"              <arg name=\"text\"   type=\"ai\" direction=\"in\"/>\n"
+"           </method>\n"
+"         </interface>\n"
+"       </node>\n";
+
+static DBusHandlerResult logitech_mediapad_msg(DBusConnection *conn, DBusMessage *msg, void *data);
+static const DBusObjectPathVTable mp_vtable = {
+	.message_function = &logitech_mediapad_msg,
+	.unregister_function = NULL
+};
+
+
+static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) {
+	struct uinput_event event;
+	int err;
+
+	memset(&event, 0, sizeof(event));
+	event.type	= type;
+	event.code	= code;
+	event.value	= value;
+
+	err = write(fd, &event, sizeof(event));
+}
+
+static unsigned char translate_key(int mode, unsigned char key) {
+	switch(key) {
+		case 0x54: return KEY_KPSLASH;
+		case 0x55: return KEY_KPASTERISK;
+		case 0x56: return KEY_KPMINUS;
+		case 0x57: return KEY_KPPLUS;
+		case 0x58: return KEY_KPENTER;
+		case 0x59: return (mode != 0) ? KEY_OPEN      : KEY_1;
+		case 0x5a: return (mode != 0) ? KEY_LEFTMETA  : KEY_2;
+		case 0x5b: return (mode != 0) ? KEY_UNDO      : KEY_3;	/* Even though it should be KEY_CLOSE (non-existant) */
+		case 0x5c: return (mode != 0) ? KEY_LEFT      : KEY_4;
+		case 0x5d: return (mode != 0) ? KEY_DOWN      : KEY_5;
+		case 0x5e: return (mode != 0) ? KEY_RIGHT     : KEY_6;
+		case 0x5f: return (mode != 0) ? KEY_BACK      : KEY_7;
+		case 0x60: return (mode != 0) ? KEY_UP        : KEY_8;
+		case 0x61: return (mode != 0) ? KEY_FORWARD   : KEY_9;
+		case 0x62: return KEY_0;
+		case 0x63: return KEY_DOT;
+	}
+	return KEY_UNKNOWN;
+}
+
+static int clear_screen(int sock) {
+	int i = 0, x = 0;
+	while (clscr[i].len != 0) { x = write(sock,clscr[i].command,clscr[i].len); i++; }
+	if (x == -1) return 0;
+	return 1;
+}
+
+static int set_lcd_indicator(int sock, uint8_t indicator, int blink) {
+	struct mpcmd lcdwi; uint8_t on = (blink >= 1) ? ((blink == 2) ? LCD_ICON_BLINK : LCD_ICON_ON) : 0; int sel = 5;
+
+	if (sock < 4 || indicator == 0) return 0;
+	memcpy(&lcdwi,write_icons,sizeof(struct mpcmd));
+	while ((indicator & 1) == 0) { sel++; indicator >>= 1; }
+	while (indicator & 1) { lcdwi.command[sel++] = on; indicator >>= 1; }
+	if (write(sock,lcdwi.command,lcdwi.len) < 0) return 0;
+	return 1;
+}
+
+static int beep_or_blink(int sock, uint8_t beep, uint8_t blink) {
+	struct mpcmd bbeep[3]; int i = 0; int x = 0;
+
+	if (sock < 4) return 0;
+	memcpy(bbeep,write_ledspk,sizeof(struct mpcmd)*3);
+
+	if (beep)  bbeep[1].command[5] = (beep & 3);
+	if (blink) bbeep[1].command[6] = 1;
+	while (bbeep[i].len != 0) { x = write(sock,bbeep[i].command,bbeep[i].len); i++; }
+	if (x == -1) return 0;
+	return 1;
+}
+
+static int set_clock(int sock) {
+	struct mpcmd setclk[4]; struct tm tx; time_t tim = 0; int i = 0, x=0;
+
+	if (sock < 4) return 0;
+	memcpy(setclk,write_clock,sizeof(struct mpcmd)*4);
+	time(&tim); localtime_r(&tim,&tx);
+	setclk[0].command[5] = (char)(tx.tm_sec);
+	setclk[0].command[6] = (char)(tx.tm_min);
+	setclk[0].command[7] = (char)(tx.tm_hour);
+	setclk[1].command[6] = (char)(tx.tm_mday);
+	setclk[1].command[7] = (char)(tx.tm_mon);
+	setclk[2].command[5] = (char)(tx.tm_year - 100);
+	
+	while (setclk[i].len != 0) { x = write(sock,setclk[i].command,setclk[i].len); i++; }
+	if (x == -1) return 0;
+	return 1;
+}
+
+static int write_lcd_text(int sock, char *text) {
+	char lines[16*9]; struct mpcmd *lcdw = NULL; int q = 0; 
+	uint32_t i = 0,z = 0,line = 0; uint8_t f1 = LCD_LINE_DISPLAY, f2 = LCD_LINE_DISPLAY, f3 = LCD_LINE_DISPLAY;
+
+	if (!text || sock < 4) return 0;
+	memset(lines,0x20,16*9); z = (strlen(text) > 16*9) ? 16*9 : strlen(text);
+	for (i=0;i<z;i+=16) {
+		line = i / 16;
+		memcpy(lines+(16*line),text+i,((z-i) < 16) ?  (z-i) : 16);
+	}
+
+	lcdw = g_new0(struct mpcmd,N_LCDW_CMDS);
+	memcpy(lcdw,write_lcd,sizeof(struct mpcmd)*N_LCDW_CMDS);
+	
+	/* Copy the line text */
+	memcpy(lcdw[3].command+5,lines,16);        
+	memcpy(lcdw[4].command+5,lines+(16*3),16);
+	memcpy(lcdw[5].command+5,lines+(16*6),16);
+	memcpy(lcdw[6].command+5,lines+16,16);
+	memcpy(lcdw[7].command+5,lines+(16*4),16);
+	memcpy(lcdw[8].command+5,lines+(16*7),16);
+	memcpy(lcdw[9].command+5,lines+(16*2),16);
+	memcpy(lcdw[10].command+5,lines+(16*5),16);
+	memcpy(lcdw[11].command+5,lines+(16*8),16);
+
+	/* Autoscrolling */
+	if (z > 16*3) { 
+		f1 |= LCD_LINE_SCROLL | LCD_2_BUFFERS; f2 |= LCD_LINE_SCROLL | LCD_2_BUFFERS; f3 |= LCD_LINE_SCROLL | LCD_2_BUFFERS;
+		if (z > 16*6) { f1 &= 0xF0; f1 |= LCD_3_BUFFERS; f2 &= 0xF0; f2 |= LCD_3_BUFFERS;  f3 &= 0xF0; f3 |= LCD_3_BUFFERS; }
+	}
+
+	lcdw[12].command[5] = f1;
+	lcdw[12].command[6] = f2;
+	lcdw[12].command[7] = f3;		
+	i = 0; while (lcdw[i].len != 0) { q = write(sock,lcdw[i].command,lcdw[i].len); i++; } g_free(lcdw);
+	if (q == -1) return 0;
+	return 1;
+}	
+
+static int write_lcd_line(int sock, char *text, int lineno) {
+	char lines[16*3]; struct mpcmd *lcdw = NULL; int q = 0; uint32_t i = 0,z = 0,line = 0; uint8_t f = LCD_LINE_DISPLAY;
+
+	if (!text || sock < 4) return 0; lineno = (lineno > 3) ? 3 : (lineno <= 0) ? 1 : lineno;
+	memset(lines,0x20,16*3); z = (strlen(text) > 16*3) ? 16*3 : strlen(text);
+	for (i=0;i<z;i+=16) {
+		line = i / 16;
+		memcpy(lines+(16*line),text+i,((z-i) < 16) ?  (z-i) : 16);
+	}
+
+	lcdw = g_new0(struct mpcmd,N_LCDS_CMDS); 
+	memcpy(lcdw,write_lcd_single,sizeof(struct mpcmd)*N_LCDS_CMDS);
+	
+	/* Copy the line text */
+	memcpy(lcdw[3].command+5,lines,16);        
+	memcpy(lcdw[4].command+5,lines+16,16);
+	memcpy(lcdw[5].command+5,lines+(16*2),16);
+
+	/* Adjust the buffer numbers */
+	*(lcdw[3].command+4) = 0x20 + 3*(lineno-1);
+	*(lcdw[4].command+4) = 0x21 + 3*(lineno-1);
+	*(lcdw[5].command+4) = 0x22 + 3*(lineno-1);
+
+	/* Adjust flags */
+	if (z > 16) {
+		f |= LCD_LINE_SCROLL | LCD_2_BUFFERS;
+		if (z > 16*2) { f &= 0xF0; f |= LCD_3_BUFFERS; }
+	}
+
+	/* Write the text */
+	lcdw[1].command[4 + lineno] = LCD_LINE_INIT;
+	i = 0; while (lcdw[i].len != 0) { q = write(sock,lcdw[i].command,lcdw[i].len); i++; } g_free(lcdw);
+	if (q == -1) return 0;
+	else return 1;
+}		
+
+static DBusHandlerResult logitech_mediapad_msg(DBusConnection *conn, DBusMessage *msg, void *data) {
+	dbus_uint32_t u1,u2,u3; DBusMessageIter db_args,db_sub; DBusMessage *db_msg_reply; DBusError db_err;
+	struct mp_state *mp = (struct mp_state *)data; char *interface;
+
+	interface = (char *)dbus_message_get_interface(msg);
+
+	if (strlen(interface) == 35 && !strncmp(interface,"org.freedesktop.DBus.Introspectable",35)) {
+		if (!(db_msg_reply = dbus_message_new_method_return(msg)))
+			return DBUS_HANDLER_RESULT_NEED_MEMORY;
+		dbus_message_append_args(db_msg_reply, DBUS_TYPE_STRING, &introspect_ret, DBUS_TYPE_INVALID);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (!mp) {
+		info("mp is NULL!");
+		dbus_message_unref(msg);
+		dbus_connection_unref(conn);
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"BlinkOrBeep")) {
+		/* BlinkOrBeep(beep_type, blink) 
+		 * 	[beep_type := 0 (none) | 1 (low beep) | 2 (beep-beep) | 3 (short beep) ] 
+		 *	[blink     := 0 (no)   | 1 (yes) ]
+		 */
+	
+		dbus_error_init(&db_err);
+		dbus_message_get_args(msg,&db_err,DBUS_TYPE_UINT32,&u1,DBUS_TYPE_UINT32,&u2,DBUS_TYPE_INVALID);
+		if (dbus_error_is_set(&db_err)) {
+			error("logitech_mediapad: BlinkOrBeep: unable to get args! (%s)",db_err.message);
+		} else beep_or_blink(mp->sock,u1,u2);
+		dbus_error_free(&db_err);
+
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"WriteText")) {
+		/* WriteText(text) Max Length: 144 */ 
+		if (dbus_message_iter_init(msg,&db_args)) {
+			if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING) {
+				dbus_message_iter_get_basic(&db_args,&interface);
+				if (interface && strlen(interface) > 0) write_lcd_text(mp->sock,interface);
+			}
+		}
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"WriteLine")) {
+		/* WriteLine(lineno, text) Max Length: 48 */ 
+		if (dbus_message_iter_init(msg,&db_args)) {
+			if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32) dbus_message_iter_get_basic(&db_args,&u1);
+			if (dbus_message_iter_has_next(&db_args)) {
+				dbus_message_iter_next(&db_args);
+				if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING) {
+					dbus_message_iter_get_basic(&db_args,&interface);
+					if (interface && strlen(interface) > 0) write_lcd_line(mp->sock,interface,u1);
+				}
+			}
+		}
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"WriteTextBin")) {
+		/* WriteTextBin(chars) Max Length: 144 */ 
+		if (dbus_message_iter_init(msg,&db_args)) {
+			if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY) {
+				dbus_message_iter_recurse(&db_args,&db_sub);
+				if ((interface = g_new0(char,1+(16*9)))) {
+					for (u1=0;u1<=16*9;u1++) {
+						dbus_message_iter_get_basic(&db_sub,&u2);
+						interface[u1] = (char)u2;
+						if (dbus_message_iter_has_next(&db_sub)) dbus_message_iter_next(&db_sub);
+						else break;
+					} 
+					if (u1 > 0) write_lcd_text(mp->sock,interface); 
+					g_free(interface);
+				}
+			}
+		}
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"WriteLineBin")) {
+		/* WriteLineBin(lineno, chars) Max Length: 48 */ 
+		if (dbus_message_iter_init(msg,&db_args)) {
+			if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32) dbus_message_iter_get_basic(&db_args,&u1);
+			if (dbus_message_iter_has_next(&db_args)) {
+				dbus_message_iter_next(&db_args);
+				if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY) {
+					dbus_message_iter_recurse(&db_args,&db_sub);
+					if ((interface = g_new0(char,1+(16*3)))) {
+						for (u3=0;u3<=16*3;u3++) {
+							dbus_message_iter_get_basic(&db_sub,&u2);
+							interface[u3] = (char)u2;
+							if (dbus_message_iter_has_next(&db_sub)) dbus_message_iter_next(&db_sub);
+							else break;
+						} 
+						if (u3 > 0) write_lcd_line(mp->sock,interface,u1); g_free(interface);
+					}
+				}
+			}
+		}
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"SetIndicator")) {
+		/* SetIndicator(indicator, blink) 
+		 *	[ indicator := see LCD_ICON_* above ]
+		 *	[ blink     := 0 (off) | 1 (on) | >= 2 (blink) ] 
+		 */ 
+		
+		dbus_error_init(&db_err);
+		dbus_message_get_args(msg,&db_err,DBUS_TYPE_UINT32,&u1,DBUS_TYPE_UINT32,&u2,DBUS_TYPE_INVALID);
+		if (dbus_error_is_set(&db_err)) {
+			error("logitech_mediapad: SetIndicator: unable to get args! (%s)",db_err.message);
+		} else set_lcd_indicator(mp->sock,u1,u2);
+		dbus_error_free(&db_err);
+
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	if (dbus_message_is_method_call(msg,MP_DBUS_PATH,"SyncClock")) {
+		/* SyncClock() */
+		set_clock(mp->sock);
+		db_msg_reply = dbus_message_new_method_return(msg);
+		return send_message_and_unref(conn,db_msg_reply);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+gpointer logitech_mediapad_init(int isk, int uinput_fd) {
+	struct mp_state *mp = g_new0(struct mp_state,1); 
+	int on_dbus = 0,ln = 0; DBusConnection *db_conn = NULL; DBusError db_err; 
+
+	mp->uinput = uinput_fd;
+	mp->sock   = isk;
+	sleep(3); set_clock(isk);
+
+	/* Get-on-D-Bus :P */
+	dbus_error_init(&db_err);
+	db_conn = dbus_bus_get(DBUS_BUS_SYSTEM,&db_err);
+	if (db_conn) {
+		on_dbus = 1;
+		dbus_connection_set_exit_on_disconnect(db_conn,FALSE);
+		setup_dbus_with_main_loop(db_conn);
+		
+		/* Set our name */
+		ln = dbus_bus_request_name(db_conn,MP_DBUS_PATH,DBUS_NAME_FLAG_REPLACE_EXISTING,&db_err);
+		if (dbus_error_is_set(&db_err)) {
+			info("db_err was set! (%s: %s)\n",db_err.name,db_err.message ? db_err.message : "Out of Memory?");
+			on_dbus = 0; dbus_connection_unref(db_conn); db_conn = NULL;
+		} else if (ln != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) info("Unable to own...\n");
+	} else info("db_conn is NULL!\n");
+	dbus_error_free(&db_err);
+
+	if (on_dbus) {
+		mp->db_conn = db_conn;
+		if (!dbus_connection_register_object_path(db_conn,MP_DBUS_SIGNAL_PATH,&mp_vtable,mp)) 
+			error("Unable to register object path!");
+	}
+
+	return (gpointer)mp;
+}
+
+gboolean logitech_mediapad_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) {
+	int ln = 0, isk = 0; char buf[26]; struct mp_state *mp = (struct mp_state *)data;
+
+	isk = g_io_channel_unix_get_fd(chan);
+
+	if (cond == G_IO_IN) {
+		memset(buf,0,26);
+		if ((ln = read(isk, buf, sizeof(buf))) <= 0) { 
+			g_free(buf);
+			g_io_channel_unref(chan);
+			return FALSE;
+		} 
+
+		if (buf[1] == 0x03) { /* Special Keys */
+			/* e9 = vol up, ea = vol down, e2 = mute, b5 = ffwd, b6 = rew, b7 = stop, cd = play/pause */
+			if (buf[2] == (char)0x83 && buf[3] == 0x02) { 
+				clear_screen(isk); 
+				if (mp->icons & LCD_ICON_MUTE) { mp->icons = LCD_ICON_MUTE; set_lcd_indicator(isk, LCD_ICON_MUTE, 1); }
+			}
+			if (buf[2] == (char)0x00 && buf[3] == 0x00) { 
+				if (mp->prev_key != 0) { inject_key(mp->uinput,mp->prev_key,0); mp->prev_key = 0; } 
+				if (mp->discard_keyup) mp->discard_keyup = 0; 
+				else mp->mode = 0; 
+			}
+			if (buf[2] == (char)0x83 && buf[3] == 0x01) { mp->prev_key = KEY_PHONE; inject_key(mp->uinput,mp->prev_key,1); }
+			if (buf[2] == (char)0xb5 && buf[3] == 0x00) { mp->prev_key = KEY_NEXTSONG;     mp->discard_keyup = 1; inject_key(mp->uinput,mp->prev_key,1); }
+			if (buf[2] == (char)0xb6 && buf[3] == 0x00) { mp->prev_key = KEY_PREVIOUSSONG; mp->discard_keyup = 1; inject_key(mp->uinput,mp->prev_key,1); }
+			if (buf[2] == (char)0xb7 && buf[3] == 0x00) { mp->prev_key = KEY_STOP;         inject_key(mp->uinput,mp->prev_key,1); }
+			if (buf[2] == (char)0xcd && buf[3] == 0x00) { mp->prev_key = KEY_PLAYPAUSE;    inject_key(mp->uinput,mp->prev_key,1); }
+			if (buf[2] == (char)0xe2 && buf[3] == 0x00) { mp->prev_key = KEY_MUTE;         inject_key(mp->uinput,mp->prev_key,1); 
+								      mp->icons    = ((mp->icons & LCD_ICON_MUTE) != 0) ? 
+								     		      (mp->icons & ~LCD_ICON_MUTE) : (mp->icons | LCD_ICON_MUTE); 
+								     set_lcd_indicator(isk, LCD_ICON_MUTE, ((mp->icons & LCD_ICON_MUTE) != 0) ? 1 : 0); }
+			if (buf[2] == (char)0xe9 && buf[3] == 0x00) { mp->prev_key = KEY_VOLUMEUP;     inject_key(mp->uinput,mp->prev_key,1); 
+								      mp->icons    = (mp->icons & ~LCD_ICON_MUTE); set_lcd_indicator(isk, LCD_ICON_MUTE, 0); }
+			if (buf[2] == (char)0xea && buf[3] == 0x00) { mp->prev_key = KEY_VOLUMEDOWN;   inject_key(mp->uinput,mp->prev_key,1); 
+								      mp->icons    = (mp->icons & ~LCD_ICON_MUTE); set_lcd_indicator(isk, LCD_ICON_MUTE, 0); }
+		} else if (buf[1] == 0x01 && buf[2] == 0x00) {
+			if (buf[4] == 0x53 && buf[5] == 0x00) { mp->mode = 1; mp->prev_key = 0; } /* NAV key */
+			else if (buf[4] == 0x00 && buf[5] == 0x00 && mp->prev_key != 0) inject_key(mp->uinput,mp->prev_key,0);
+			else if (buf[4] != 0x00) { mp->prev_key = translate_key(mp->mode,buf[4] & 0x7f); inject_key(mp->uinput,mp->prev_key,1); }
+		} else if (buf[1] == 0x11 && buf[2] == 0x0a) { /* Calculator Result */
+			/*
+			 cwtmp = &buf[4]; while (*cwtmp && *cwtmp == 0x20) cwtmp++;
+			 syslog(LOG_WARNING,"Got Calc result");
+			 */
+		}
+	} else {
+		if (mp->db_conn) {
+			dbus_connection_unregister_object_path(mp->db_conn,MP_DBUS_PATH);
+			dbus_connection_unref(mp->db_conn); 
+		}
+		g_free(mp); 
+		return FALSE; 
+	}
+	return TRUE;
+}
+
diff -ru bluez-utils-3.19/input/logitech_mediapad.h bluez-utils-3.19/input/logitech_mediapad.h
--- bluez-utils-3.19/input/logitech_mediapad.h	2007-09-22 19:03:39.610625879 -0400
+++ bluez-utils-3.19/input/logitech_mediapad.h	2007-09-22 19:04:34.101731150 -0400
@@ -0,0 +1,7 @@
+#ifndef LOGITECH_MEDIAPAD_H
+#define LOGITECH_MEDIAPAD_H
+
+gpointer logitech_mediapad_init(int isk, int uinput_fd);
+gboolean logitech_mediapad_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data);
+
+#endif

[-- Attachment #3: Type: text/plain, Size: 228 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-09-27  2:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-27  2:43 [Bluez-devel] [PATCH] Dinovo Mediapad LCD support in Input service Tim Hentenaar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox