--- bluez-utils-3.13.orig/input/Makefile.am	2007-05-09 02:40:43.000000000 -0400
+++ bluez-utils-3.13/input/Makefile.am	2007-11-13 12:10:53.000000000 -0500
@@ -12,7 +12,9 @@ service_PROGRAMS = bluetoothd-service-in
 
 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 bluetooth_ids.h \
+	fake_hid.c fake_hid.h
 
 LDADD = $(top_builddir)/common/libhelper.a \
 		@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ bluez-utils-3.13/input/bluetooth_ids.h	2007-11-13 12:11:40.000000000 -0500
@@ -0,0 +1,9 @@
+#ifndef BLUETOOTH_IDS_H
+#define BLUETOOTH_IDS_H
+
+#define BLUETOOTH_VENDOR_ID_SONY 0x054c
+#define BLUETOOTH_DEVICE_ID_PS3CONTROLLER 0x0268
+#define BLUETOOTH_DEVICE_ID_PS3REMOTE 0x0306
+
+#endif	/* BLUETOOTH_IDS_H */
+
--- bluez-utils-3.13.orig/input/device.c	2007-11-13 12:02:40.000000000 -0500
+++ bluez-utils-3.13/input/device.c	2007-11-13 12:11:03.000000000 -0500
@@ -52,6 +52,8 @@
 #include "error.h"
 #include "manager.h"
 #include "storage.h"
+#include "bluetooth_ids.h"
+#include "fake_hid.h"
 
 #define INPUT_DEVICE_INTERFACE	"org.bluez.input.Device"
 
@@ -59,30 +61,6 @@
 
 #define UPDOWN_ENABLED		1
 
-struct fake_input {
-	GIOChannel	*io;
-	int		rfcomm; /* RFCOMM socket */
-	int		uinput;	/* uinput socket */
-	uint8_t		ch;	/* RFCOMM channel number */
-};
-
-struct device {
-	bdaddr_t		src;
-	bdaddr_t		dst;
-	char			*name;
-	uint8_t			major;
-	uint8_t			minor;
-	uint16_t		product;
-	uint16_t		vendor;
-	struct fake_input	*fake;
-	DBusMessage		*pending_connect;
-	DBusConnection		*conn;
-	char			*path;
-	int			ctrl_sk;
-	int			intr_sk;
-	guint			watch;
-};
-
 GSList *devices = NULL;
 
 static struct device *device_new(bdaddr_t *src, bdaddr_t *dst)
@@ -575,7 +553,8 @@ static int hidp_connadd(bdaddr_t *src, b
 
 	info("New input device %s (%s)", addr, req.name);
 
-	if (req.vendor == 0x054c && req.product == 0x0268) {
+	if (req.vendor == BLUETOOTH_VENDOR_ID_SONY &&
+	    req.product == BLUETOOTH_DEVICE_ID_PS3CONTROLLER) {
 		unsigned char buf[] = { 0x53, 0xf4,  0x42, 0x03, 0x00, 0x00 };
 		err = write(ctrl_sk, buf, sizeof(buf));
 	}
@@ -717,6 +696,26 @@ failed:
 	return FALSE;
 }
 
+static int fake_disconnect(struct device *idev)
+{
+	struct fake_input *fake = idev->fake;
+
+	if (!fake->io)
+		return -ENOTCONN;
+
+	g_io_channel_close(fake->io);
+	g_io_channel_unref(fake->io);
+	fake->io = NULL;
+
+	if (fake->uinput >= 0) {
+		ioctl(fake->uinput, UI_DEV_DESTROY);
+		close(fake->uinput);
+		fake->uinput = -1;
+	}
+
+	return 0;
+}
+
 static int disconnect(struct device *idev, uint32_t flags)
 {
 	struct fake_input *fake = idev->fake;
@@ -725,22 +724,8 @@ static int disconnect(struct device *ide
 	int ctl, err;
 
 	/* Fake input disconnect */
-	if (fake) {
-		if (!fake->io)
-			return -ENOTCONN;
-
-		g_io_channel_close(fake->io);
-		g_io_channel_unref(fake->io);
-		fake->io = NULL;
-
-		if (fake->uinput >= 0) {
-			ioctl(fake->uinput, UI_DEV_DESTROY);
-			close(fake->uinput);
-			fake->uinput = -1;
-		}
-
-		return 0;
-	}
+	if (fake)
+		return fake->disconnect(idev);
 
 	/* Standard HID disconnect */
 	if (idev->ctrl_sk >= 0) {
@@ -793,12 +778,8 @@ static int is_connected(struct device *i
 	int ctl;
 
 	/* Fake input */
-	if (fake) {
-		if (fake->io)
-			return 1;
-		else
-			return 0;
-	}
+	if (fake)
+		return fake->is_connected(idev);
 
 	/* Standard HID */
 	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
@@ -827,6 +808,7 @@ static DBusHandlerResult device_connect(
 					DBusMessage *msg, void *data)
 {
 	struct device *idev = data;
+	struct fake_input *fake = idev->fake;
 
 	if (idev->pending_connect)
 		return err_connection_failed(conn, msg, "Connection in progress");
@@ -837,10 +819,10 @@ static DBusHandlerResult device_connect(
 	idev->pending_connect = dbus_message_ref(msg);
 
 	/* Fake input device */
-	if (idev->fake) {
-		if (rfcomm_connect(idev) < 0) {
+	if (fake) {
+		if (fake->connect(idev) < 0) {
 			const char *str = strerror(errno);
-			error("RFCOMM connect failed: %s(%d)", str, errno);
+			error("Connect failed: %s(%d)", str, errno);
 			dbus_message_unref(idev->pending_connect);
 			idev->pending_connect = NULL;
 			return err_connection_failed(conn, msg, str);
@@ -1070,6 +1052,15 @@ int input_device_register(DBusConnection
 	return err;
 }
 
+static int fake_is_connected(struct device *idev)
+{
+	struct fake_input *fake = idev->fake;
+
+	if (fake->io)
+		return 1;
+	return 0;
+}
+
 int fake_input_register(DBusConnection *conn, bdaddr_t *src,
 			bdaddr_t *dst, uint8_t ch, const char **ppath)
 {
@@ -1086,6 +1077,9 @@ int fake_input_register(DBusConnection *
 
 	idev->fake = g_new0(struct fake_input, 1);
 	idev->fake->ch = ch;
+	idev->fake->connect = rfcomm_connect;
+	idev->fake->disconnect = fake_disconnect;
+	idev->fake->is_connected = fake_is_connected;
 
 	err = register_path(conn, path, idev);
 
@@ -1264,13 +1258,18 @@ int input_device_close_channels(bdaddr_t
 int input_device_connadd(bdaddr_t *src, bdaddr_t *dst)
 {
 	struct device *idev;
+	struct fake_hid *fake_hid;
 	int err;
 
 	idev = find_device(src, dst);
 	if (!idev)
 		return -ENOENT;
 
-	err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+	fake_hid = is_fake_hid(idev);
+	if (fake_hid)
+		err = fake_hid_connadd(idev, fake_hid);
+	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);
--- bluez-utils-3.13.orig/input/device.h	2007-06-23 18:55:58.000000000 -0400
+++ bluez-utils-3.13/input/device.h	2007-11-13 12:11:13.000000000 -0500
@@ -24,6 +24,33 @@
 #define L2CAP_PSM_HIDP_CTRL	0x11
 #define L2CAP_PSM_HIDP_INTR	0x13
 
+struct device {
+	bdaddr_t		src;
+	bdaddr_t		dst;
+	char			*name;
+	uint8_t			major;
+	uint8_t			minor;
+	uint16_t		product;
+	uint16_t		vendor;
+	struct fake_input	*fake;
+	DBusMessage		*pending_connect;
+	DBusConnection		*conn;
+	char			*path;
+	int			ctrl_sk;
+	int			intr_sk;
+	guint			watch;
+};
+
+struct fake_input {
+	GIOChannel	*io;
+	int		rfcomm; /* RFCOMM socket */
+	int		uinput;	/* uinput socket */
+	uint8_t		ch;	/* RFCOMM channel number */
+	gboolean 	(*connect)(struct device *idev);
+	int		(*disconnect)(struct device *idev);
+	int		(*is_connected)(struct device *idev);
+};
+
 int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
 			struct hidp_connadd_req *hidp, const char **ppath);
 int fake_input_register(DBusConnection *conn, bdaddr_t *src,
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ bluez-utils-3.13/input/fake_hid.c	2007-11-13 12:11:40.000000000 -0500
@@ -0,0 +1,299 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <linux/input.h>
+#include <linux/uinput.h>
+#include <dbus/dbus.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/l2cap.h>
+#include "logging.h"
+#include "bluetooth_ids.h"
+#include "device.h"
+#include "fake_hid.h"
+
+#define FAKE_HID_ENTRY(v, p, c, d, i, e, s) { \
+	.vendor = BLUETOOTH_VENDOR_ID_##v, \
+	.product = BLUETOOTH_DEVICE_ID_##p, \
+	.connect = c, \
+	.disconnect = d, \
+	.is_connected = i, \
+	.event = e, \
+	.setup_uinput = s, \
+	}
+
+/* ps3 remote support */
+#ifndef KEY_SLOWREWIND
+#define KEY_SLOWREWIND		0x1b0   /* Slow motion rewind */
+#define KEY_SLOWFORWARD		0x1b1   /* Slow motion forward */
+#endif
+static unsigned int ps3remote_keymap[] = {
+	[0x16] = KEY_EJECTCD,
+	[0x64] = KEY_AUDIO,
+	[0x65] = KEY_ANGLE,
+	[0x63] = KEY_SUBTITLE,
+	[0x0f] = KEY_CLEAR,
+	[0x28] = KEY_TIME,
+	[0x00] = KEY_1,
+	[0x01] = KEY_2,
+	[0x02] = KEY_3,
+	[0x03] = KEY_4,
+	[0x04] = KEY_5,
+	[0x05] = KEY_6,
+	[0x06] = KEY_7,
+	[0x07] = KEY_8,
+	[0x08] = KEY_9,
+	[0x09] = KEY_0,
+	[0x81] = KEY_RED,
+	[0x82] = KEY_GREEN,
+	[0x80] = KEY_BLUE,
+	[0x83] = KEY_YELLOW,
+	[0x70] = KEY_INFO,		/* display */
+	[0x1a] = BTN_TOP,		/* top menu */
+	[0x40] = KEY_MENU,		/* pop up/menu */
+	[0x0e] = KEY_ESC,		/* return */
+	[0x5c] = KEY_OPTION,		/* options/triangle */
+	[0x5d] = KEY_BACK,		/* back/circle */
+	[0x5f] = KEY_SCREEN,		/* view/square */
+	[0x5e] = KEY_ENTER,		/* cross */
+	[0x54] = KEY_UP,
+	[0x56] = KEY_DOWN,
+	[0x57] = KEY_LEFT,
+	[0x55] = KEY_RIGHT,
+	[0x0b] = KEY_ENTER,
+	[0x5a] = BTN_TL,		/* L1 */
+	[0x58] = BTN_TL2,		/* L2 */
+	[0x51] = BTN_THUMBL,		/* L3 */
+	[0x5b] = BTN_TR,		/* R1 */
+	[0x59] = BTN_TR2,		/* R2 */
+	[0x52] = BTN_THUMBR,		/* R3 */
+	[0x43] = KEY_HOMEPAGE,		/* PS button */
+	[0x50] = BTN_SELECT,
+	[0x53] = BTN_START,
+	[0x33] = KEY_REWIND,		/* scan back */
+	[0x32] = KEY_PLAY,
+	[0x34] = KEY_FORWARD,		/* scan forward */
+	[0x30] = KEY_PREVIOUS,
+	[0x38] = KEY_STOP,
+	[0x31] = KEY_NEXT,
+	[0x60] = KEY_SLOWREWIND,	/* slow/step back */
+	[0x39] = KEY_PAUSE,
+	[0x61] = KEY_SLOWFORWARD,	/* slow/step forward */
+	[0xff] = KEY_MAX,
+};
+
+static int ps3remote_decode(char *buff, int size, unsigned int *value)
+{
+	static unsigned int lastkey = KEY_RESERVED;
+	int retval, ps3;
+
+	if (size < 12) {
+		error("Got a shorter packet! (size %i)\n", size);
+		return KEY_RESERVED;
+	}
+
+	*value = buff[11];
+
+	if (*value == 0)
+		return lastkey;
+
+	ps3 = buff[5];
+	lastkey = retval = ps3remote_keymap[ps3];
+
+	if (retval == KEY_RESERVED)
+		error("ps3remote: unrecognized key [%#x] value [%#x]",
+		      buff[5], buff[11]);
+
+	return retval;
+}
+
+static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	struct fake_input *fake = data;
+	struct input_event event;
+	unsigned int size, key, value;
+	char buff[50];
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		error("Hangup or error on rfcomm server socket");
+		goto failed;
+	}
+
+	memset(buff, 0, sizeof(buff));
+
+	if (g_io_channel_read(chan, buff, sizeof(buff), &size) !=
+	    G_IO_ERROR_NONE) {
+		error("IO Channel read error");
+		goto failed;
+	}
+
+	key = ps3remote_decode(buff, size, &value);
+	if (key == KEY_RESERVED) {
+		error("Got invalid key from decode");
+		return TRUE;
+	}
+
+	memset(&event, 0, sizeof(event));
+	gettimeofday(&event.time, NULL);
+	event.type = EV_KEY;
+	event.code = key;
+	event.value = value;
+	if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
+		error("Error writing to uinput device");
+		goto failed;
+	}
+
+	memset(&event, 0, sizeof(event));
+	gettimeofday(&event.time, NULL);
+	event.type = EV_SYN;
+	event.code = SYN_REPORT;
+	if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
+		error("Error writing to uinput device");
+		goto failed;
+	}
+
+	return TRUE;
+failed:
+	ioctl(fake->uinput, UI_DEV_DESTROY);
+	close(fake->uinput);
+        fake->uinput = -1;
+	g_io_channel_unref(fake->io);
+
+	return FALSE;
+}
+
+static int ps3remote_setup_uinput(struct device *idev,
+				  struct fake_hid *fake_hid)
+{
+	struct fake_input *fake = idev->fake;
+	struct uinput_user_dev dev;
+	int i;
+
+	fake->uinput = open("/dev/input/uinput", O_RDWR);
+	if (fake->uinput < 0) {
+		fake->uinput = open("/dev/uinput", O_RDWR);
+		if (fake->uinput < 0)
+			fake->uinput = open("/dev/misc/uinput", O_RDWR);
+	}
+	if (fake->uinput < 0) {
+		error("Error opening uinput device file. Is uinput loaded?");
+		return 1;
+	}
+
+	memset(&dev, 0, sizeof(dev));
+	snprintf(&dev.name, sizeof(dev.name), "%s", "PS3 Remote Controller");
+	dev.id.bustype = BUS_BLUETOOTH;
+	dev.id.vendor = idev->vendor;
+	dev.id.product = idev->product;
+
+	if (write(fake->uinput, &dev, sizeof(dev)) != sizeof(dev)) {
+		error("Error creating uinput device");
+		goto err;
+	}
+
+	/* enabling key events */
+	if (ioctl(fake->uinput, UI_SET_EVBIT, EV_KEY) < 0) {
+		error("Error enabling uinput device key events");
+		goto err;
+	}
+
+	/* enabling keys */
+	for (i = 0; i < 256; i++)
+		if (ps3remote_keymap[i] != KEY_RESERVED)
+			if (ioctl(fake->uinput, UI_SET_KEYBIT,
+				  ps3remote_keymap[i]) < 0) {
+				error("Error enabling uinput key %i", ps3remote_keymap[i]);
+				goto err;
+			}
+
+	/* creating the device */
+	if (ioctl(fake->uinput, UI_DEV_CREATE) < 0) {
+		error("Error creating uinput device");
+		goto err;
+	}
+
+	return 0;
+err:
+	close(fake->uinput);
+	return 1;
+}
+
+static gboolean fake_hid_common_connect(struct device *idev)
+{
+	return TRUE;
+}
+
+static int fake_hid_common_disconnect(struct device *idev)
+{
+	return 0;
+}
+
+static int fake_hid_common_is_connected(struct device *idev)
+{
+	return 1;
+}
+
+static struct fake_hid fake_hid_table[] = {
+	FAKE_HID_ENTRY(SONY, PS3REMOTE, fake_hid_common_connect,
+		       fake_hid_common_disconnect,
+		       fake_hid_common_is_connected,
+		       ps3remote_event,
+		       ps3remote_setup_uinput),
+	{ },
+};
+
+static inline int fake_hid_match_device(struct device *idev,
+					struct fake_hid *fhid)
+{
+	return idev->vendor == fhid->vendor &&
+	       idev->product == fhid->product;
+}
+
+struct fake_hid *is_fake_hid(struct device *idev)
+{
+	int i;
+
+	for (i = 0; fake_hid_table[i].vendor != 0; i++)
+		if (fake_hid_match_device(idev, &fake_hid_table[i]))
+			return &fake_hid_table[i];
+
+	return NULL;
+}
+
+int fake_hid_connadd(struct device *idev, struct fake_hid *fake_hid)
+{
+	struct fake_input *fake;
+
+	fake = malloc(sizeof(struct fake_input));
+	if (fake == NULL)
+		return ENOMEM;
+	memset(fake, 0, sizeof(struct fake_input));
+
+	fake->connect = fake_hid->connect;
+	fake->disconnect = fake_hid->disconnect;
+	fake->is_connected = fake_hid->is_connected;
+	idev->fake = fake;
+
+	if (fake_hid->setup_uinput(idev, fake_hid)) {
+		error("Error setting up uinput");
+		free(fake);
+		idev->fake = NULL;
+		return 1;
+	}
+
+	fake->io = g_io_channel_unix_new(idev->intr_sk);
+	g_io_channel_set_close_on_unref(fake->io, TRUE);
+	g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						(GIOFunc) fake_hid->event, fake);
+
+	return 0;
+}
+
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ bluez-utils-3.13/input/fake_hid.h	2007-11-13 12:10:53.000000000 -0500
@@ -0,0 +1,20 @@
+#ifndef FAKE_HID_H
+#define FAKE_HID_H
+#include <glib.h>
+struct device;
+struct fake_hid;
+
+struct fake_hid {
+	uint16_t vendor;
+	uint16_t product;
+	gboolean (*connect)(struct device *idev);
+	int (*disconnect)(struct device *idev);
+	int (*is_connected)(struct device *idev);
+	gboolean (*event)(GIOChannel *chan, GIOCondition cond, gpointer data);
+	int (*setup_uinput)(struct device *idev, struct fake_hid *fake_hid);
+};
+
+struct fake_hid *is_fake_hid(struct device *idev);
+int fake_hid_connadd(struct device *idev, struct fake_hid *fake_hid);
+#endif	/* FAKE_HID_H */
+
