diff -rupN bluez-utils-3.36/hidd/dinovo.conf bluez-utils-3.36-test/hidd/dinovo.conf
--- bluez-utils-3.36/hidd/dinovo.conf	1970-01-01 01:00:00.000000000 +0100
+++ bluez-utils-3.36-test/hidd/dinovo.conf	2009-02-09 13:39:16.000000000 +0100
@@ -0,0 +1,39 @@
+<!-- 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"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Introspectable" />
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Properties" />
+    <allow send_path="/com/hentenaar"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad" />
+    <allow receive_sender="com.hentenaar.Dinovo.MediaPad"/>
+  </policy>
+
+  <policy group="users">
+    <allow send_path="/com/hentenaar"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad" />
+    <allow receive_sender="com.hentenaar.Dinovo.MediaPad"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Introspectable" />
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Properties" />
+  </policy>
+
+  <policy at_console="true">
+    <allow send_path="/com/hentenaar"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad" />
+    <allow receive_sender="com.hentenaar.Dinovo.MediaPad"/>
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Introspectable" />
+    <allow send_destination="com.hentenaar.Dinovo.MediaPad"
+           send_interface="org.freedesktop.DBus.Properties" />
+  </policy>
+</busconfig>
diff -rupN bluez-utils-3.36/hidd/fakehid.c bluez-utils-3.36-test/hidd/fakehid.c
--- bluez-utils-3.36/hidd/fakehid.c	2008-05-20 18:14:31.000000000 +0200
+++ bluez-utils-3.36-test/hidd/fakehid.c	2009-02-09 13:49:00.000000000 +0100
@@ -32,6 +32,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <time.h>
 #include <sys/poll.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -43,6 +44,10 @@
 #include "hidd.h"
 #include "uinput.h"
 
+// define two additional keys for the Logitech Mediapad not present in uinput.h
+#define KEY_FASTFORWARD 208
+#define KEY_MEDIA 226
+
 #include <math.h>
 
 #ifdef NEED_PPOLL
@@ -667,3 +672,977 @@ int celluon_keyboard(const bdaddr_t *src
 
 	return 0;
 }
+
+/************************ 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.                                                     *
+ *                                                                                *
+ *     Updates by Glen Rolle:                                                     *
+ *       1) Split up functions in atomic functions to allow a more detailed       *
+ *          control over the mediapad. The original functions are still available *
+ *          as convenience functions                                              *
+ *       2) Replaced the Numlock emulation by the Logitech NavMode                *
+ *       3) Moved the Mediapad connection code from search to connect (in main.c) *
+ *          so that the this fakehid-driver is registered even when the Mediapad  *
+ *          is connected by pressing a key                                        *
+ *       4) New functions added:                                                  *
+ *          SendRawData: Send arbitrary bytes to the Mediapad (Only for           *
+ *                       experienced users or developers!)                        *
+ *          ScrollLine: Sets a line to scrolling mode                             *
+ *       5) DBus interface extended to publish the atomic functions               *
+ *                                                                                *
+ *     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!                                                           *
+ **********************************************************************************/
+
+struct mpcmd {
+	char    command[22];
+	uint8_t len;
+};
+
+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}
+};
+
+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}
+};
+
+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}
+};
+
+struct mpcmd write_num[] = { /* Set Numlock (0 = off) */
+	{{ 0xA2, 0x01, 0x00 }, 3}
+};
+
+struct mpcmd write_raw[] = { /* raw data */
+	{{ 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 21}
+};
+
+struct mpcmd write_line[] = { /* write a single line */
+	{{ 0xA2, 0x11, 0x00, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 21}
+};
+
+struct mpcmd write_screen_mode[] = { /* 0 = 3 lines, 1 =  clock */
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00 }, 8},
+};
+
+struct mpcmd write_scroll_mode[] = { 
+	{{ 0xA2, 0x10, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 }, 8},
+};
+
+struct mpcmd write_screen_prepare[] = { 
+	{{ 0xA2, 0x10, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00 }, 8},
+};
+
+struct mpcmd write_screen_finish[] = { 
+	{{ 0xA2, 0x10, 0x00, 0x83, 0x11, 0x00, 0x00, 0x00 }, 8},
+};
+
+#define LCD_LINE_LENGTH 16
+#define LCD_RAW_MSG_LENGTH 20
+
+/* Screen modes */
+#define LCD_SCREEN_LINES  0x00
+#define LCD_SCREEN_CLOCK  0x01
+
+/* Scroll modes */
+#define LCD_DO_NOTHING    0x00
+#define LCD_HIDE          0x01  // hide the line
+#define LCD_DISPLAY_1     0x10  // display char  1-16
+#define LCD_DISPLAY_2     0x11  // display char 17-32
+#define LCD_DISPLAY_3     0x12  // display char 33-48
+#define LCD_SCROLL        0x20  // scroll per char
+#define LCD_SCROLL_2      0x32  // scroll 2 * 16 chars
+#define LCD_SCROLL_3      0x33  // scroll 3 * 16 chars
+
+/* Icons */
+#define LCD_ICON_EMAIL  0x01
+#define LCD_ICON_IM     0x02
+#define LCD_ICON_MUTE   0x04
+#define LCD_ICON_ALERT  0x08
+#define LCD_ICON_ALL    0x0f
+#define LCD_ICON_OFF    0x00
+#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
+
+/* max number of int args in DBus interface */
+#define ARGS_MAX  5
+
+#define inject_key(X,Y,Z) send_event(X,EV_KEY,Y,Z)
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <syslog.h>
+
+#define dinovo_dbus_do_signal(X) \
+	db_msg = dbus_message_new_signal("/com/hentenaar/Dinovo/MediaPad/"X, "com.hentenaar.Dinovo.MediaPad", X); \
+	dbus_connection_send(db_conn,db_msg,NULL); dbus_connection_flush(db_conn); dbus_message_unref(db_msg); 
+
+#define dinovo_dbus_do_reply(X) \
+	db_msg_reply = dbus_message_new_method_return(X); dbus_connection_send(db_conn,db_msg_reply,NULL); dbus_connection_flush(db_conn); dbus_message_unref(db_msg_reply);
+
+static 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=\"Clear\" />\n"
+"            <method name=\"WriteText\">\n"
+"              <!-- Max Length: 144 -->\n"
+"              <arg name=\"text\" type=\"s\" direction=\"in\"/>\n"
+"              <arg name=\"reset\"  type=\"u\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"WriteTextBin\">\n"
+"              <!-- Max Length: 144 -->\n"
+"              <arg name=\"text\" type=\"ai\" direction=\"in\"/>\n"
+"              <arg name=\"reset\"  type=\"u\" 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"
+"              <arg name=\"scroll\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"reset\"  type=\"u\" 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"
+"              <arg name=\"scroll\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"reset\"  type=\"u\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"WriteBuffer\">\n"
+"              <!-- Max Length: 16 -->\n"
+"              <arg name=\"buffer\" type=\"u\"  direction=\"in\"/>\n"
+"              <arg name=\"text\"   type=\"s\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"WriteBufferBin\">\n"
+"              <!-- Max Length: 16 -->\n"
+"              <arg name=\"buffer\" type=\"u\"  direction=\"in\"/>\n"
+"              <arg name=\"text\"   type=\"ai\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"SetScreenMode\">\n"
+"              <arg name=\"mode\" type=\"u\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"SetScrollMode\">\n"
+"              <arg name=\"mode1\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"mode2\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"mode3\" type=\"u\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"SetLineScrollMode\">\n"
+"              <arg name=\"lineno\" type=\"u\" direction=\"in\"/>\n"
+"              <arg name=\"mode\" type=\"u\" direction=\"in\"/>\n"
+"            </method>\n"
+"            <method name=\"PrepareScreen\" />\n"
+"            <method name=\"FinishScreen\" />\n"
+"            <method name=\"SendRawData\">\n"
+"              <!-- Max Length: 20 -->\n"
+"              <arg name=\"data\" type=\"ai\" direction=\"in\"/>\n"
+"            </method>\n"
+"         </interface>\n"
+"       </node>\n";
+
+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 KEY_1;
+		case 0x5a: return (mode != 0) ? KEY_DOWN  : KEY_2;
+		case 0x5b: return KEY_3;
+		case 0x5c: return (mode != 0) ? KEY_LEFT  : KEY_4;
+		case 0x5d: return KEY_5;
+		case 0x5e: return (mode != 0) ? KEY_RIGHT : KEY_6;
+		case 0x5f: return KEY_7;
+		case 0x60: return (mode != 0) ? KEY_UP    : KEY_8;
+		case 0x61: return KEY_9;
+		case 0x62: return KEY_0;
+		case 0x63: return KEY_DOT;
+	}
+	return KEY_UNKNOWN;
+}
+
+/***********************************************************************************
+ * Atomic functions
+ **********************************************************************************/
+
+/*
+ * Set screen mode (last bit is relevant)
+ * 0 = 3 lines
+ * 1 = clock
+ */
+static void set_screen_mode(int sock, int mode) {
+	struct mpcmd lcdwi; 
+	
+	if (sock < 4) return;
+	memcpy(&lcdwi,write_screen_mode,sizeof(struct mpcmd));
+	lcdwi.command[6] = (char) mode;
+	write(sock,lcdwi.command,lcdwi.len);
+}
+
+/*
+ * Set scroll mode
+ */
+static void set_scroll_mode(int sock, int line1, int line2, int line3) {
+	struct mpcmd lcdwi; 
+	
+	if (sock < 4) return;
+	memcpy(&lcdwi,write_scroll_mode,sizeof(struct mpcmd));
+	lcdwi.command[5] = (char) line1;
+	lcdwi.command[6] = (char) line2;
+	lcdwi.command[7] = (char) line3;
+	write(sock,lcdwi.command,lcdwi.len);
+}
+
+static void set_line_scroll_mode(int sock, int line, int mode) {
+	struct mpcmd lcdwi; 
+	
+	if (sock < 4) return;
+	memcpy(&lcdwi,write_scroll_mode,sizeof(struct mpcmd));
+	lcdwi.command[5 + line - 1] = (char) mode;
+	write(sock,lcdwi.command,lcdwi.len);
+}
+
+/*
+ * Set screen prepare
+ */
+static void set_screen_prepare(int sock) {
+	if (sock < 4) return;
+	write(sock,write_screen_prepare[0].command,write_screen_prepare[0].len);
+}
+/*
+ * Set screen finish
+ */
+static void set_screen_finish(int sock) {
+	if (sock < 4) return;
+	write(sock,write_screen_finish[0].command,write_screen_finish[0].len);
+}
+
+/*
+ * Send raw data to the MediaPad
+ * The data does not require the 0xa2 at the beginning
+ */
+static void send_raw_data(int sock, char *data) {
+	struct mpcmd lcdwi;
+	int z = 0;
+	if (!data || sock < 4) 
+		return;
+	memcpy(&lcdwi,write_raw,sizeof(struct mpcmd));
+	z = strlen(data) > LCD_RAW_MSG_LENGTH ? LCD_RAW_MSG_LENGTH : strlen(data);
+	memcpy(lcdwi.command + 1,data,z);
+
+	write(sock,lcdwi.command,z);
+}
+
+/*
+ * Set the state of an icon
+ */
+static void 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;
+	memcpy(&lcdwi,write_icons,sizeof(struct mpcmd));
+	while ((indicator & 1) == 0)
+	{
+		sel++;
+		indicator >>= 1;
+	}
+	while (indicator & 1)
+	{
+		lcdwi.command[sel++] = on;
+		indicator >>= 1;
+	}
+	write(sock,lcdwi.command,lcdwi.len);
+}
+
+/*
+ * Clear the screen
+ * Turns off all icons and sets the display to the clock
+ */
+static void clear_screen(int sock) {
+	set_screen_mode (sock, LCD_SCREEN_CLOCK);
+	set_screen_prepare (sock);
+	set_lcd_indicator(sock, LCD_ICON_ALL, LCD_ICON_OFF);
+	set_screen_finish(sock);
+}
+
+/*
+ * Set the numlock state
+ */
+static void set_numlock(int sock, char mode) {
+	struct mpcmd lcdnum; 
+	
+	if (sock < 4) return;
+	memcpy(&lcdnum,write_num,sizeof(struct mpcmd));
+	lcdnum.command[2] = mode;
+	write(sock,lcdnum.command,lcdnum.len);
+}
+
+/*
+ * Make the speaker beep or the blue led blink
+ */
+static void beep_or_blink(int sock, uint8_t beep, uint8_t blink) {
+	struct mpcmd bbeep[3]; int i = 0;
+
+	if (sock < 4) return;
+	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) { write(sock,bbeep[i].command,bbeep[i].len); i++; }
+}
+
+/*
+ * Set the current time
+ */
+static void set_clock(int sock) {
+	struct mpcmd setclk[4]; struct tm tx; time_t tim = 0; int i = 0;
+
+	if (sock < 4) return;
+	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) { write(sock,setclk[i].command,setclk[i].len); i++; }
+}
+
+/*
+ * Write a single text buffer (16 chars) to the mediapad
+ */
+static void write_single_line(int sock, char *text, int buffer) {
+	char lines[LCD_LINE_LENGTH]; struct mpcmd lcdw; uint32_t z = 0;
+
+	if (!text || sock < 4) return;
+	buffer = (buffer > 9) ? 9 : (buffer < 1) ? 1 : buffer;
+	memset(lines,0x00,LCD_LINE_LENGTH);
+	z = (strlen(text) > LCD_LINE_LENGTH) ? LCD_LINE_LENGTH : strlen(text);
+	memcpy(lines,text,z);
+
+	memcpy(&lcdw,write_line,sizeof(struct mpcmd));
+	
+	memcpy(lcdw.command+5,lines,LCD_LINE_LENGTH);
+
+	/* Adjust the buffer numbers */
+	*(lcdw.command+4) = 0x20 + buffer - 1;
+
+	write(sock,lcdw.command,lcdw.len);
+}
+
+/***********************************************************************************
+ * Convenience functions
+ **********************************************************************************/
+
+/* write_lcd_text
+ * Write a text up to 144 chars to the mediapad flipping through pages of 48 chars
+ */
+static void write_lcd_text(int sock, char *text, int reset) {
+	char line[LCD_LINE_LENGTH];
+	uint32_t i = 0,z = 0, j = 0, o = 0;
+
+	if (!text || sock < 4)
+		return;
+
+	set_screen_prepare (sock);
+	if (reset > 0)
+	{
+		set_scroll_mode (sock, LCD_HIDE, LCD_HIDE, LCD_HIDE);
+		set_screen_mode (sock, LCD_SCREEN_LINES);
+	}
+	
+	z = (strlen(text) > LCD_LINE_LENGTH*9) ? LCD_LINE_LENGTH*9 : strlen(text);
+	j = 0;
+	while (j < 3)
+	{
+		i = 0;
+		while (i < 3)
+		{
+			o = (j * 3 + i) * LCD_LINE_LENGTH;
+			if (o < z)
+			{
+				memset(line,0x20,LCD_LINE_LENGTH);
+				memcpy(line, text + o, (z-o < LCD_LINE_LENGTH) ?  z-o : LCD_LINE_LENGTH);
+				write_single_line (sock, line, (i * 3 + j) + 1);
+			}
+			i++;
+		}
+		j++;
+	}
+
+	/* Adjust flags */
+	if (z <= LCD_LINE_LENGTH * 3)
+		i = LCD_DISPLAY_1;
+	else if (z <= LCD_LINE_LENGTH * 6)
+		i = LCD_SCROLL_2;
+	else
+		i = LCD_SCROLL_3;
+
+	set_scroll_mode (sock, i, i, i);
+	set_screen_finish (sock);
+}
+
+/* write_lcd_line
+ * Write a line up to 48 chars to the mediapad flipping through three buffers of 16 chars or the scrolling mode
+ */
+static void write_lcd_line(int sock, char *text, int lineno, int scroll, int reset) {
+	char lines[LCD_LINE_LENGTH];
+	uint32_t i = 0,z = 0;
+
+	if (!text || sock < 4)
+		return;
+	
+	lineno = (lineno > 3) ? 3 : (lineno <= 0) ? 1 : lineno;
+
+	set_screen_prepare (sock);
+	if (reset > 0)
+	{
+		set_line_scroll_mode (sock, lineno, LCD_HIDE);
+		set_screen_mode (sock, LCD_SCREEN_LINES);
+	}
+	
+	z = (strlen(text) > LCD_LINE_LENGTH*3) ? LCD_LINE_LENGTH*3 : strlen(text);
+	for (i = 0; i < z; i += LCD_LINE_LENGTH) {
+		memset(lines,scroll == 1 ? 0x00 : 0x20,LCD_LINE_LENGTH);
+		memcpy(lines, text + i, ((z-i) < LCD_LINE_LENGTH) ?  (z-i) : LCD_LINE_LENGTH);
+		write_single_line (sock, lines, (lineno - 1) * 3 + i / LCD_LINE_LENGTH + 1);
+	}
+
+	/* Adjust flags */
+	if (scroll == 0)
+	{
+		if (z <= LCD_LINE_LENGTH)
+			i = LCD_DISPLAY_1;
+		else if (z <= 2 * LCD_LINE_LENGTH)
+			i = LCD_SCROLL_2;
+		else
+			i = LCD_SCROLL_3;
+	}
+	else
+		i = LCD_SCROLL;
+		
+	set_line_scroll_mode (sock, lineno, i);
+	set_screen_finish (sock);
+}
+
+int logitech_mediapad(int sock) {
+	DBusMessage *db_msg, *db_msg_reply;
+	DBusConnection *db_conn = NULL;
+	DBusError db_err;
+	DBusMessageIter db_args, db_sub;
+	dbus_uint32_t db_u[ARGS_MAX], db_u1 = 0, db_u2 = 0;
+	char buf[25], *cwtmp;
+	struct pollfd p;
+	int fd = 0, mode = 0, discard_keyup = 0, prev_key = 0, icons = 0, on_dbus = 0, last_dbus_poll = 0, ln = 0, idx = 0, allocated = 0;
+	
+	memset(&p,0,sizeof(struct pollfd)); p.fd = sock; p.events = POLLIN | POLLHUP | POLLERR; 
+
+	setsid();
+	sleep(3); /* Give time for "Connected :-)" to go away */
+	openlog("dinovod",LOG_NDELAY | LOG_CONS | LOG_PID,LOG_DAEMON);
+
+	/* Register with uinput */
+	if ((fd = uinput_create("Logitech Mediapad - Bluetooth Remote Commander", 1, 0)) < 4) {
+		close(sock);
+		closelog();
+		return -1;
+	}
+
+	set_clock(sock); 
+	while (!__io_canceled) {
+		if (!on_dbus) {
+			if ((time(NULL) - last_dbus_poll) > 60) {
+				/* Get-on-D-Bus :P */
+				dbus_error_init(&db_err);
+				if (!(db_conn = dbus_bus_get(DBUS_BUS_SYSTEM,&db_err))) {
+					syslog(LOG_ERR,"Unable to connect to DBUS! Will retry in 60 sec. (%s)",db_err.message ? db_err.message : "Out of Memory?");
+				} else {
+					on_dbus = 1;
+
+					/* Set our name */
+					ln = dbus_bus_request_name(db_conn,"com.hentenaar.Dinovo.MediaPad",DBUS_NAME_FLAG_REPLACE_EXISTING,&db_err);
+					if (dbus_error_is_set(&db_err) || ln != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+						on_dbus = 0; dbus_connection_unref(db_conn); db_conn = NULL;
+						if (ln == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) 
+							syslog(LOG_ERR,"Unable to own com.hentenaar.Dinovo.MediaPad! (%s)",db_err.message ? db_err.message : "No Error Message");
+						__io_canceled = 1; break; 
+					} else {
+						/* Send the "Connected" signal */
+						dinovo_dbus_do_signal("Connected");
+					}
+				}
+
+				last_dbus_poll = time(NULL);
+			}
+		} else {
+			/* Poll for DBUS messages */
+			dbus_connection_read_write(db_conn, 0);
+			if ((db_msg = dbus_connection_pop_message(db_conn))) {
+				if (dbus_message_is_signal(db_msg,DBUS_INTERFACE_LOCAL,"Disconnected")) {
+					dbus_connection_unref(db_conn);
+					on_dbus = 0; db_conn = NULL;
+				} else if (strlen(dbus_message_get_interface(db_msg)) == 35 && !strncmp(dbus_message_get_interface(db_msg),"org.freedesktop.DBus.Introspectable",35)) {
+					db_msg_reply = dbus_message_new_method_return(db_msg); 
+					dbus_message_iter_init_append(db_msg_reply,&db_args);
+					dbus_message_iter_append_basic(&db_args,DBUS_TYPE_STRING,&introspect_ret);
+					dbus_connection_send(db_conn,db_msg_reply,NULL); dbus_connection_flush(db_conn); dbus_message_unref(db_msg_reply);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","BlinkOrBeep")) {
+					/* BlinkOrBeep(beep_type, blink) 
+					 * 	[beep_type := 0 (none) | 1 (low beep) | 2 (beep-beep) | 3 (short beep) ] 
+					 *	[blink     := 0 (no)   | 1 (yes) ]
+					 */
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 2)
+							beep_or_blink(sock,db_u[0],db_u[1]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteText")) {
+					/* WriteText(text, reset) Max Length: 144
+					 *   [reset > 0: reet the display for text display]
+					 */
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING)
+								dbus_message_iter_get_basic(&db_args,&cwtmp);
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 1 && cwtmp && strlen(cwtmp) > 0)
+							write_lcd_text(sock,cwtmp,db_u[0]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteTextBin")) {
+					/* WriteTextBin (chars, reset) Max Length: 144
+					 *   [reset > 0: reet the display for text display]
+					 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY)
+							{
+								dbus_message_iter_recurse(&db_args,&db_sub);
+								allocated = 0;
+								if ((cwtmp = malloc(1+(LCD_LINE_LENGTH*9))))
+								{
+									allocated = 1;
+									memset(cwtmp,0,1+(LCD_LINE_LENGTH*9));
+									for (db_u1=0;db_u1<=LCD_LINE_LENGTH*9;db_u1++)
+									{
+										dbus_message_iter_get_basic(&db_sub,&db_u2);
+										cwtmp[db_u1] = (char)db_u2;
+										if (dbus_message_iter_has_next(&db_sub))
+											dbus_message_iter_next(&db_sub);
+										else
+											break;
+									} 
+								}
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 1 && db_u1 > 0)
+							write_lcd_text(sock,cwtmp,db_u[0]);
+						if (allocated > 0)
+							free(cwtmp);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteLine")) {
+					/* WriteLine(lineno, text, scroll, reset) Max Length: 48 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING)
+								dbus_message_iter_get_basic(&db_args,&cwtmp);
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 3 && cwtmp && strlen(cwtmp) > 0)
+							write_lcd_line(sock,cwtmp,db_u[0],db_u[1],db_u[2]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteLineBin")) {
+					/* WriteLineBin(lineno, chars) Max Length: 48 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY)
+							{
+								dbus_message_iter_recurse(&db_args,&db_sub);
+								allocated = 0;
+								if ((cwtmp = malloc(1+(LCD_LINE_LENGTH*3))))
+								{
+									allocated = 1;
+									memset(cwtmp,0,1+(LCD_LINE_LENGTH*3));
+									for (db_u1=0;db_u1<=LCD_LINE_LENGTH*3;db_u1++)
+									{
+										dbus_message_iter_get_basic(&db_sub,&db_u2);
+										cwtmp[db_u1] = (char)db_u2;
+										if (dbus_message_iter_has_next(&db_sub))
+											dbus_message_iter_next(&db_sub);
+										else
+											break;
+									} 
+								}
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 3 && db_u1 > 0)
+							write_lcd_line(sock,cwtmp,db_u[0],db_u[1],db_u[2]);
+						if (allocated > 0)
+							free(cwtmp);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteBuffer")) {
+					/* WriteBuffer(buffer, text) Max Length: 16 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING)
+								dbus_message_iter_get_basic(&db_args,&cwtmp);
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 1 && cwtmp && strlen(cwtmp) > 0)
+							write_single_line(sock,cwtmp,db_u[0]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteBufferBin")) {
+					/* WriteBufferBin(buffer, chars) Max Length: 16 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							else if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY)
+							{
+								dbus_message_iter_recurse(&db_args,&db_sub);
+								allocated = 0;
+								if ((cwtmp = malloc(1+(LCD_LINE_LENGTH))))
+								{
+									allocated = 1;
+									memset(cwtmp,0,1+(LCD_LINE_LENGTH));
+									for (db_u1=0;db_u1<=LCD_LINE_LENGTH;db_u1++)
+									{
+										dbus_message_iter_get_basic(&db_sub,&db_u2);
+										cwtmp[db_u1] = (char)db_u2;
+										if (dbus_message_iter_has_next(&db_sub))
+											dbus_message_iter_next(&db_sub);
+										else
+											break;
+									} 
+								}
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 1 && db_u1 > 0)
+							write_single_line(sock,cwtmp,db_u[0]);
+						if (allocated > 0)
+							free(cwtmp);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SetScreenMode")) {
+					/* SetScreenMode(mode) 
+					*	[ 0 = 3 lines | 1 = clock ] 
+					*/ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 1)
+							set_screen_mode(sock,db_u[0]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SetScrollMode")) {
+					/* SetScrollMode(mode, mode, mode) 
+					*	mode per line 
+					*/ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 3)
+							set_scroll_mode(sock,db_u[0],db_u[1],db_u[2]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SetLineScrollMode")) {
+					/* SetLineScrollMode(line, mode) 
+					*	mode for a single line
+					*/ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 2)
+							set_line_scroll_mode(sock,db_u[0],db_u[1]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SendRawData")) {
+					/* SendRawData(data)  */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY)
+							{
+								dbus_message_iter_recurse(&db_args,&db_sub);
+								allocated = 0;
+								if ((cwtmp = malloc(1+(LCD_RAW_MSG_LENGTH))))
+								{
+									allocated = 1;
+									memset(cwtmp,0,1+(LCD_RAW_MSG_LENGTH));
+									for (db_u1=0;db_u1<=LCD_RAW_MSG_LENGTH;db_u1++)
+									{
+										dbus_message_iter_get_basic(&db_sub,&db_u2);
+										cwtmp[db_u1] = (char)db_u2;
+										if (dbus_message_iter_has_next(&db_sub))
+											dbus_message_iter_next(&db_sub);
+										else
+											break;
+									} 
+								}
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (db_u1 > 0)
+							send_raw_data (sock,cwtmp);
+						if (allocated > 0)
+							free(cwtmp);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SetIndicator")) {
+					/* SetIndicator(indicator, blink) 
+					 *	[ indicator := see LCD_ICON_* above ]
+					 *	[ blink     := 0 (off) | 1 (on) | >= 2 (blink) ] 
+					 */ 
+					if (dbus_message_iter_init(db_msg,&db_args))
+					{
+						idx = 0;
+						while (dbus_message_iter_get_arg_type(&db_args) != DBUS_TYPE_INVALID)
+						{
+							if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32 && idx < ARGS_MAX)
+							{
+								dbus_message_iter_get_basic(&db_args,&db_u[idx]);
+								idx++;
+							}
+							dbus_message_iter_next(&db_args);
+						}
+						if (idx == 2)
+							set_lcd_indicator(sock,db_u[0],db_u[1]);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","SyncClock")) {
+					/* SyncClock() */
+					set_clock(sock);
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","PrepareScreen")) {
+					/* PrepareScreen() */
+					set_screen_prepare(sock);
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","FinishScreen")) {
+					/* FinishScreen() */
+					set_screen_finish(sock);
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","Clear")) {
+					/* Clear() */
+					clear_screen(sock);
+					dinovo_dbus_do_reply(db_msg);
+				} 
+				dbus_message_unref(db_msg); 
+			}
+		}
+		
+		p.revents = 0; p.fd = sock;
+		if (poll(&p,1,1) < 0) { __io_canceled = 1; break; }
+		if (p.revents & POLLIN) {
+			if ((ln = read(p.fd, buf, sizeof(buf))) <= 0) { __io_canceled = 1; break; }
+//			syslog(LOG_WARNING, "Got mode %d - key_up %d - prev %d - key %x | %x %x %x %x : %x %x %x %x : %x %x %x", mode, discard_keyup, prev_key, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
+			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(p.fd);
+					if (icons & LCD_ICON_MUTE)
+					{
+						icons = LCD_ICON_MUTE;
+						set_lcd_indicator(p.fd, LCD_ICON_MUTE, 1);
+					}
+				}
+				if (buf[2] == (char)0x00 && buf[3] == 0x00)
+				{/*
+					if (prev_key != 0) {
+						inject_key(fd,prev_key,0);
+						prev_key = 0;
+					} 
+					if (discard_keyup)
+						discard_keyup = 0;
+					else {
+						//mode = 0;
+					}
+				*/}
+				if (buf[2] == (char)0x83 && buf[3] == 0x01) { prev_key = KEY_MEDIA;        /*226*/ inject_key(fd,prev_key,1); } /* Media key */
+				if (buf[2] == (char)0xb5 && buf[3] == 0x00) { prev_key = KEY_NEXTSONG;     /*163*/ inject_key(fd,prev_key,1); discard_keyup = 1; }
+				if (buf[2] == (char)0xb6 && buf[3] == 0x00) { prev_key = KEY_PREVIOUSSONG; /*165*/ inject_key(fd,prev_key,1); discard_keyup = 1; }
+				if (buf[2] == (char)0xb7 && buf[3] == 0x00) { prev_key = KEY_STOP;         /*128*/ inject_key(fd,prev_key,1); }
+				if (buf[2] == (char)0xcd && buf[3] == 0x00) { prev_key = KEY_PLAYPAUSE;    /*164*/ inject_key(fd,prev_key,1); }
+				if (buf[2] == (char)0xe2 && buf[3] == 0x00) { prev_key = KEY_MUTE;         /*113*/ inject_key(fd,prev_key,1); 
+									     icons ^= LCD_ICON_MUTE; set_lcd_indicator(p.fd, LCD_ICON_MUTE, ((icons & LCD_ICON_MUTE) != 0) ? 1 : 0); }
+				if (buf[2] == (char)0xe9 && buf[3] == 0x00) { prev_key = KEY_VOLUMEUP;     /*115*/ inject_key(fd,prev_key,1); 
+									     icons = (icons & ~LCD_ICON_MUTE); set_lcd_indicator(p.fd, LCD_ICON_MUTE, 0); }
+				if (buf[2] == (char)0xea && buf[3] == 0x00) { prev_key = KEY_VOLUMEDOWN;   /*114*/ inject_key(fd,prev_key,1); 
+									     icons = (icons & ~LCD_ICON_MUTE); set_lcd_indicator(p.fd, LCD_ICON_MUTE, 0); }
+				if (buf[2] == (char)0x24 && buf[3] == 0x02) { prev_key = KEY_REWIND;       /*168*/  inject_key(fd,prev_key,1); }
+				if (buf[2] == (char)0x25 && buf[3] == 0x02) { prev_key = KEY_FASTFORWARD;  /*208*/ inject_key(fd,prev_key,1); }
+			} else if (buf[1] == 0x01 && buf[2] == 0x00) {
+				if (buf[4] == 0x53 && buf[5] == 0x00) {
+					mode ^= 1;
+					prev_key = KEY_NUMLOCK;
+					inject_key(fd,prev_key,1);
+					set_numlock(sock, mode ^ 1);
+				} /* NAV key */
+				else if (buf[4] == 0x00 && buf[5] == 0x00 && prev_key != 0) { inject_key(fd,prev_key,0); }
+				else if (buf[4] != 0x00) { prev_key = translate_key(mode,buf[4] & 0x7f); inject_key(fd,prev_key,1); }
+			} else if (buf[1] == 0x01 && buf[2] == 0x08) {
+				prev_key = KEY_LEFTMETA;	inject_key(fd,prev_key,1);
+			} else if (buf[1] == 0x01 && buf[2] == 0x04) {
+				if (buf[4] == (char)0x3d) {
+					prev_key = KEY_CLOSE;
+					inject_key(fd,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");
+			}
+		} 
+		usleep(20);
+	}
+
+	if (db_conn) { dinovo_dbus_do_signal("Disconnected"); dbus_connection_unref(db_conn); }
+	ioctl(fd, UI_DEV_DESTROY);
+	close(fd);
+	close(sock); 
+	closelog();
+	return 0;
+}
diff -rupN bluez-utils-3.36/hidd/hidd.h bluez-utils-3.36-test/hidd/hidd.h
--- bluez-utils-3.36/hidd/hidd.h	2008-02-02 00:16:32.000000000 +0100
+++ bluez-utils-3.36-test/hidd/hidd.h	2009-02-09 13:39:16.000000000 +0100
@@ -32,3 +32,4 @@ int epox_presenter(const bdaddr_t *src, 
 int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
 int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
 int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
+int logitech_mediapad(int sock);
diff -rupN bluez-utils-3.36/hidd/main.c bluez-utils-3.36-test/hidd/main.c
--- bluez-utils-3.36/hidd/main.c	2008-06-18 18:24:55.000000000 +0200
+++ bluez-utils-3.36-test/hidd/main.c	2009-02-09 13:39:16.000000000 +0100
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <malloc.h>
 #include <string.h>
 #include <syslog.h>
 #include <signal.h>
@@ -311,6 +312,11 @@ static int create_device(int ctl, int cs
 	}
 
 create:
+        // Connect to the Logitech diNovo Mediapad which uses D-Bus protocoll
+        if (!strcmp(req.name, "Logitech Bluetooth Mediapad")) {
+                logitech_mediapad(isk);
+                return 0;
+        }
 	if (subclass != 0x00)
 		req.subclass = subclass;
 
@@ -518,7 +524,6 @@ connect:
 		close(ctl);
 		exit(1);
 	}
-
 	err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout);
 	if (err < 0) {
 		fprintf(stderr, "HID create error %d (%s)\n",
diff -rupN bluez-utils-3.36/hidd/Makefile bluez-utils-3.36-test/hidd/Makefile
--- bluez-utils-3.36/hidd/Makefile	2009-02-09 13:14:46.000000000 +0100
+++ bluez-utils-3.36-test/hidd/Makefile	2009-02-09 13:41:15.000000000 +0100
@@ -43,7 +43,8 @@ am__configure_deps = $(am__aclocal_m4_de
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
+	"$(DESTDIR)$(dbusdir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
 am__hidd_SOURCES_DIST = main.c hidd.h sdp.c fakehid.c
@@ -68,6 +69,14 @@ DIST_SOURCES = $(am__hidd_SOURCES_DIST)
 man1dir = $(mandir)/man1
 NROFF = nroff
 MANS = $(man_MANS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+dbusDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(dbus_DATA)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -85,6 +94,8 @@ BLUEZ_LIBS = -lbluetooth  
 CC = gcc
 CCDEPMODE = depmode=gcc3
 CFLAGS = -Wall -O2 -D_FORTIFY_SOURCE=2 -fPIE
+CONFIGFILES_FALSE = #
+CONFIGFILES_TRUE = 
 CPP = gcc -E
 CPPFLAGS = 
 CYGPATH_W = echo
@@ -197,14 +208,16 @@ sharedstatedir = ${prefix}/com
 srcdir = .
 sysconfdir = ${prefix}/etc
 target_alias = 
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dbus_DATA = dinovo.conf
 top_builddir = ..
 top_srcdir = ..
 hidd_SOURCES = main.c hidd.h sdp.c fakehid.c
-hidd_LDADD = -lbluetooth   -lm $(top_builddir)/common/libhelper.a
-AM_CFLAGS =  
+hidd_LDADD = -lbluetooth   -ldbus-1   -lm $(top_builddir)/common/libhelper.a
+AM_CFLAGS =   -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include  
 INCLUDES = -I$(top_srcdir)/common
 man_MANS = hidd.1
-EXTRA_DIST = hidd.1 fakehid.txt
+EXTRA_DIST = hidd.1 fakehid.txt dinovo.conf
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 
@@ -352,7 +365,24 @@ uninstall-man1:
 	  echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
 	  rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
 	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)'; \
 	unique=`for i in $$list; do \
@@ -428,9 +458,9 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile $(PROGRAMS) $(MANS)
+all-am: Makefile $(PROGRAMS) $(MANS) $(DATA)
 installdirs:
-	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbusdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: install-am
@@ -478,7 +508,7 @@ info: info-am
 
 info-am:
 
-install-data-am: install-man
+install-data-am: install-dbusDATA install-man
 
 install-dvi: install-dvi-am
 
@@ -514,7 +544,7 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-binPROGRAMS uninstall-man
+uninstall-am: uninstall-binPROGRAMS uninstall-dbusDATA uninstall-man
 
 uninstall-man: uninstall-man1
 
@@ -525,7 +555,7 @@ uninstall-man: uninstall-man1
 	distclean-generic distclean-libtool distclean-tags distdir dvi \
 	dvi-am html html-am info info-am install install-am \
 	install-binPROGRAMS install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
+	install-dbusDATA install-dvi-am install-exec install-exec-am install-html \
 	install-html-am install-info install-info-am install-man \
 	install-man1 install-pdf install-pdf-am install-ps \
 	install-ps-am install-strip installcheck installcheck-am \
@@ -533,7 +563,7 @@ uninstall-man: uninstall-man1
 	mostlyclean mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
 	uninstall-am uninstall-binPROGRAMS uninstall-man \
-	uninstall-man1
+	uninstall-dbusDATA uninstall-man1
 
 # 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 -rupN bluez-utils-3.36/hidd/Makefile.am bluez-utils-3.36-test/hidd/Makefile.am
--- bluez-utils-3.36/hidd/Makefile.am	2007-05-15 10:06:17.000000000 +0200
+++ bluez-utils-3.36-test/hidd/Makefile.am	2009-02-09 13:39:16.000000000 +0100
@@ -1,13 +1,17 @@
+if CONFIGFILES
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dbus_DATA = dinovo.conf
+endif
 
 if HIDD
 bin_PROGRAMS = hidd
 
 hidd_SOURCES = main.c hidd.h sdp.c fakehid.c
 
-hidd_LDADD = @BLUEZ_LIBS@ -lm $(top_builddir)/common/libhelper.a
+hidd_LDADD = @BLUEZ_LIBS@ @DBUS_LIBS@ -lm $(top_builddir)/common/libhelper.a
 endif
 
-AM_CFLAGS = @BLUEZ_CFLAGS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@
 
 INCLUDES = -I$(top_srcdir)/common
 
@@ -17,6 +21,6 @@ man_MANS = hidd.1
 endif
 endif
 
-EXTRA_DIST = hidd.1 fakehid.txt
+EXTRA_DIST = hidd.1 fakehid.txt dinovo.conf
 
 MAINTAINERCLEANFILES = Makefile.in
diff -rupN bluez-utils-3.36/hidd/Makefile.in bluez-utils-3.36-test/hidd/Makefile.in
--- bluez-utils-3.36/hidd/Makefile.in	2008-07-11 11:02:40.000000000 +0200
+++ bluez-utils-3.36-test/hidd/Makefile.in	2009-02-09 13:39:16.000000000 +0100
@@ -43,7 +43,8 @@ am__configure_deps = $(am__aclocal_m4_de
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
+	"$(DESTDIR)$(dbusdir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
 am__hidd_SOURCES_DIST = main.c hidd.h sdp.c fakehid.c
@@ -68,6 +69,14 @@ DIST_SOURCES = $(am__hidd_SOURCES_DIST)
 man1dir = $(mandir)/man1
 NROFF = nroff
 MANS = $(man_MANS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+dbusDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(dbus_DATA)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -85,6 +94,8 @@ BLUEZ_LIBS = @BLUEZ_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CONFIGFILES_FALSE = @CONFIGFILES_FALSE@
+CONFIGFILES_TRUE = @CONFIGFILES_TRUE@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CYGPATH_W = @CYGPATH_W@
@@ -197,14 +208,16 @@ sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+@CONFIGFILES_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d
+@CONFIGFILES_TRUE@dbus_DATA = dinovo.conf
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 @HIDD_TRUE@hidd_SOURCES = main.c hidd.h sdp.c fakehid.c
-@HIDD_TRUE@hidd_LDADD = @BLUEZ_LIBS@ -lm $(top_builddir)/common/libhelper.a
-AM_CFLAGS = @BLUEZ_CFLAGS@
+@HIDD_TRUE@hidd_LDADD = @BLUEZ_LIBS@ @DBUS_LIBS@ -lm $(top_builddir)/common/libhelper.a
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@
 INCLUDES = -I$(top_srcdir)/common
 @HIDD_TRUE@@MANPAGES_TRUE@man_MANS = hidd.1
-EXTRA_DIST = hidd.1 fakehid.txt
+EXTRA_DIST = hidd.1 fakehid.txt dinovo.conf
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 
@@ -352,7 +365,24 @@ uninstall-man1:
 	  echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
 	  rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
 	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)'; \
 	unique=`for i in $$list; do \
@@ -428,9 +458,9 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile $(PROGRAMS) $(MANS)
+all-am: Makefile $(PROGRAMS) $(MANS) $(DATA)
 installdirs:
-	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbusdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: install-am
@@ -478,7 +508,7 @@ info: info-am
 
 info-am:
 
-install-data-am: install-man
+install-data-am: install-dbusDATA install-man
 
 install-dvi: install-dvi-am
 
@@ -514,7 +544,7 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-binPROGRAMS uninstall-man
+uninstall-am: uninstall-binPROGRAMS uninstall-dbusDATA uninstall-man
 
 uninstall-man: uninstall-man1
 
@@ -525,7 +555,7 @@ uninstall-man: uninstall-man1
 	distclean-generic distclean-libtool distclean-tags distdir dvi \
 	dvi-am html html-am info info-am install install-am \
 	install-binPROGRAMS install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
+	install-dbusDATA install-dvi-am install-exec install-exec-am install-html \
 	install-html-am install-info install-info-am install-man \
 	install-man1 install-pdf install-pdf-am install-ps \
 	install-ps-am install-strip installcheck installcheck-am \
@@ -533,7 +563,7 @@ uninstall-man: uninstall-man1
 	mostlyclean mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
 	uninstall-am uninstall-binPROGRAMS uninstall-man \
-	uninstall-man1
+	uninstall-dbusDATA uninstall-man1
 
 # 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.

