diff -ru bluez-utils-3.19/hidd/dinovo.conf bluez-utils-3.19/hidd/dinovo.conf
--- bluez-utils-3.19/hidd/dinovo.conf	2007-09-13 22:42:05.130896968 -0400
+++ bluez-utils-3.19/hidd/dinovo.conf	2007-09-13 22:37:57.051392968 -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/hidd/fakehid.c bluez-utils-3.19/hidd/fakehid.c
--- bluez-utils-3.19/hidd/fakehid.c	2007-02-17 22:34:50.000000000 -0500
+++ bluez-utils-3.19/hidd/fakehid.c	2007-09-13 23:06:00.620609468 -0400
@@ -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>
@@ -667,3 +668,493 @@
 
 	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.
+ *                                                                                *
+ *     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 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}
+};
+
+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_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}
+};
+
+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
+
+/* 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
+
+#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=\"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 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 void clear_screen(int sock) {
+	int i = 0;
+	while (clscr[i].len != 0) { write(sock,clscr[i].command,clscr[i].len); i++; }
+}
+
+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);
+}
+
+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++; }
+}
+
+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++; }
+}
+
+static void write_lcd_text(int sock, char *text) {
+	char lines[16*9]; struct mpcmd *lcdw = NULL; 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;
+	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 = malloc(sizeof(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) { write(sock,lcdw[i].command,lcdw[i].len); i++; } free(lcdw);
+}	
+
+static void write_lcd_line(int sock, char *text, int lineno) {
+	char lines[16*3]; struct mpcmd *lcdw = NULL; uint32_t i = 0,z = 0,line = 0; uint8_t f = LCD_LINE_DISPLAY;
+
+	if (!text || sock < 4) return; 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 = malloc(sizeof(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) { write(sock,lcdw[i].command,lcdw[i].len); i++; } free(lcdw);
+}		
+
+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_u1, db_u2, db_u3;
+	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;
+	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)) {
+						db_u1 = db_u2 = 0;
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32)  dbus_message_iter_get_basic(&db_args,&db_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_UINT32) dbus_message_iter_get_basic(&db_args,&db_u2);
+						}
+						beep_or_blink(sock,db_u1,db_u2);
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteText")) {
+					/* WriteText(text) Max Length: 144 */ 
+					if (dbus_message_iter_init(db_msg,&db_args)) {
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_STRING) {
+							dbus_message_iter_get_basic(&db_args,&cwtmp);
+							if (cwtmp && strlen(cwtmp) > 0) write_lcd_text(sock,cwtmp);
+						}
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteLine")) {
+					/* WriteLine(lineno, text) Max Length: 48 */ 
+					if (dbus_message_iter_init(db_msg,&db_args)) {
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32) dbus_message_iter_get_basic(&db_args,&db_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,&cwtmp);
+								if (cwtmp && strlen(cwtmp) > 0) write_lcd_line(sock,cwtmp,db_u1);
+							}
+						}
+					}
+					dinovo_dbus_do_reply(db_msg);
+				} else if (dbus_message_is_method_call(db_msg,"com.hentenaar.Dinovo.MediaPad","WriteTextBin")) {
+					/* WriteTextBin(chars) Max Length: 144 */ 
+					if (dbus_message_iter_init(db_msg,&db_args)) {
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_ARRAY) {
+							dbus_message_iter_recurse(&db_args,&db_sub);
+							if ((cwtmp = malloc(1+(16*9)))) {
+								memset(cwtmp,0,1+(16*9));
+								for (db_u1=0;db_u1<=16*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;
+								} 
+								if (db_u1 > 0) write_lcd_text(sock,cwtmp); 
+								free(cwtmp);
+							}
+						}
+					}
+					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)) {
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32) dbus_message_iter_get_basic(&db_args,&db_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 ((cwtmp = malloc(1+(16*3)))) {
+									memset(cwtmp,0,1+(16*3));
+									for (db_u3=0;db_u3<=16*3;db_u3++) {
+										dbus_message_iter_get_basic(&db_sub,&db_u2);
+										cwtmp[db_u3] = (char)db_u2;
+										if (dbus_message_iter_has_next(&db_sub)) dbus_message_iter_next(&db_sub);
+										else break;
+									} 
+									if (db_u3 > 0) write_lcd_line(sock,cwtmp,db_u1); 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)) {
+						if (dbus_message_iter_get_arg_type(&db_args) == DBUS_TYPE_UINT32) dbus_message_iter_get_basic(&db_args,&db_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_UINT32) dbus_message_iter_get_basic(&db_args,&db_u2);
+						}
+						set_lcd_indicator(sock,db_u1,db_u2);
+					}
+					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);
+				} 
+				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; }
+			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_PHONE;        inject_key(fd,prev_key,1); } /* Media key */
+				if (buf[2] == (char)0xb5 && buf[3] == 0x00) { prev_key = KEY_NEXTSONG;     inject_key(fd,prev_key,1); discard_keyup = 1; }
+				if (buf[2] == (char)0xb6 && buf[3] == 0x00) { prev_key = KEY_PREVIOUSSONG; inject_key(fd,prev_key,1); discard_keyup = 1; }
+				if (buf[2] == (char)0xb7 && buf[3] == 0x00) { prev_key = KEY_STOP;         inject_key(fd,prev_key,1); }
+				if (buf[2] == (char)0xcd && buf[3] == 0x00) { prev_key = KEY_PLAYPAUSE;    inject_key(fd,prev_key,1); }
+				if (buf[2] == (char)0xe2 && buf[3] == 0x00) { prev_key = KEY_MUTE;         inject_key(fd,prev_key,1); 
+									     icons = ((icons & LCD_ICON_MUTE) != 0) ? (icons & ~LCD_ICON_MUTE) : (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;     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;   inject_key(fd,prev_key,1); 
+									     icons = (icons & ~LCD_ICON_MUTE); set_lcd_indicator(p.fd, LCD_ICON_MUTE, 0); }
+			} else if (buf[1] == 0x01 && buf[2] == 0x00) {
+				if (buf[4] == 0x53 && buf[5] == 0x00) { mode = 1; prev_key = 0; } /* 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] == 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 -ru bluez-utils-3.19/hidd/hidd.h bluez-utils-3.19/hidd/hidd.h
--- bluez-utils-3.19/hidd/hidd.h	2007-01-28 15:16:47.000000000 -0500
+++ bluez-utils-3.19/hidd/hidd.h	2007-09-13 22:31:54.652744468 -0400
@@ -32,3 +32,4 @@
 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 -ru bluez-utils-3.19/hidd/main.c bluez-utils-3.19/hidd/main.c
--- bluez-utils-3.19/hidd/main.c	2007-05-09 02:40:42.000000000 -0400
+++ bluez-utils-3.19/hidd/main.c	2007-09-13 22:51:23.577797718 -0400
@@ -337,7 +337,13 @@
 	if (req.vendor == 0x054c && req.product == 0x0268)
 		enable_sixaxis(csk);
 
-	err = ioctl(ctl, HIDPCONNADD, &req);
+	if (!strcmp(req.name,"Logitech Bluetooth Mediapad")) {
+		if (!fork()) {
+			logitech_mediapad(isk);
+			close(ctl);
+			exit(0);
+		}
+	} else err = ioctl(ctl, HIDPCONNADD, &req);
 
 error:
 	if (req.rd_data)
@@ -521,8 +527,7 @@
 
 	err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout);
 	if (err < 0) {
-		fprintf(stderr, "HID create error %d (%s)\n",
-						errno, strerror(errno));
+		fprintf(stderr, "HID create error %d (%s)\n",errno, strerror(errno));
 		close(isk);
 		sleep(1);
 		close(csk);
@@ -797,6 +802,7 @@
 			close(csk);
 			exit(1);
 		}
+		do_search(ctl,&bdaddr,subclass,fakehid,bootonly,encrypt,timeout);
 		break;
 
 	case SEARCH:
diff -ru bluez-utils-3.19/hidd/Makefile.am bluez-utils-3.19/hidd/Makefile.am
--- bluez-utils-3.19/hidd/Makefile.am	2007-05-15 04:06:17.000000000 -0400
+++ bluez-utils-3.19/hidd/Makefile.am	2007-09-13 22:35:40.386851968 -0400
@@ -1,13 +1,18 @@
 
 if HIDD
+if CONFIGFILES
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dbus_DATA = dinovo.conf
+endif
+
 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 +22,6 @@
 endif
 endif
 
-EXTRA_DIST = hidd.1 fakehid.txt
+EXTRA_DIST = hidd.1 fakehid.txt dinovo.conf
 
 MAINTAINERCLEANFILES = Makefile.in
diff -ru bluez-utils-3.19/hidd/Makefile.in bluez-utils-3.19/hidd/Makefile.in
--- bluez-utils-3.19/hidd/Makefile.in	2007-09-02 12:41:25.000000000 -0400
+++ bluez-utils-3.19/hidd/Makefile.in	2007-09-13 22:39:10.479981968 -0400
@@ -14,6 +14,7 @@
 
 @SET_MAKE@
 
+
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -43,7 +44,8 @@
 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 +70,14 @@
 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)
@@ -199,12 +209,14 @@
 target_alias = @target_alias@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
+@CONFIGFILES_TRUE@@HIDD_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d
+@CONFIGFILES_TRUE@@HIDD_TRUE@dbus_DATA = dinovo.conf
 @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,6 +364,23 @@
 	  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)'; \
@@ -429,9 +458,9 @@
 	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
@@ -479,7 +508,7 @@
 
 info-am:
 
-install-data-am: install-man
+install-data-am: install-dbusDATA install-man
 
 install-dvi: install-dvi-am
 
@@ -515,7 +544,7 @@
 
 ps-am:
 
-uninstall-am: uninstall-binPROGRAMS uninstall-man
+uninstall-am: uninstall-binPROGRAMS uninstall-dbusDATA uninstall-man
 
 uninstall-man: uninstall-man1
 
@@ -525,16 +554,16 @@
 	clean-generic clean-libtool ctags distclean distclean-compile \
 	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-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 \
-	installdirs maintainer-clean maintainer-clean-generic \
-	mostlyclean mostlyclean-compile mostlyclean-generic \
-	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
-	uninstall-am uninstall-binPROGRAMS uninstall-man \
-	uninstall-man1
+	install-binPROGRAMS install-data 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-man1 install-pdf \
+	install-pdf-am install-ps install-ps-am 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-binPROGRAMS \
+	uninstall-dbusDATA uninstall-man 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.

