• 1
  • 2
  • 3
  • 4(current)
  • 5
  • 6
  • 56
[LINUX] Sony PlayStation 3 Blu-ray Disc Remote (PS3 BD) + LIRC + XBMC = SUCCESS
#46
Everything works fine until I'm trying to find the remote controll with
cat /proc/bus/input/devices. It dosen't show ps3 remote. I have no idea what has gone wrong. I'm using Ubunty Jaunty.
Anyone has any idea?

//Klimpen
Reply
#47
ruff Wrote:Well, my initial intention to modify fakehid was to fix unpairing and manual remote turn-off with ps key. And at the same time I remapped the keys to avoid additional daemons and configurations %)

I have no problems with unpairing, only after I pair with my PS3 I need to reconnect it with BlueZ. When does it happen for you?
I tried additional daemons (evrouter and gizmod), they allow you to map a key to a different code. Which works great, except that events which use the new keycode will never arrive because fakehid drops all events for codes it doesn't know about Eek So modifying fakehid, like you did, is the only way I can think of to make all buttons work.
Reply
#48
Exposure Wrote:I have no problems with unpairing, only after I pair with my PS3 I need to reconnect it with BlueZ. When does it happen for you?
The thing is that input device is not removed after unpairing. Especially if it is unpaired by turning off the remote with holding ps button or when remote gone to standby/lowpower mode.
Moreover, in first case remote generates keypress, and input driver starting to generate key repeats, waiting for key release event. But release never occurs as remote is turned off...
Only when I initiate unpairing from host (blueman f.i.), or remove batteries - input device will be removed, but in several minutes.
Reply
#49
Can we detect the low power mode ? Does it send anything to other devices when it does that ?
Reply
#50
Here is new "powersaving" patch. It includes all previous modifications.
This patch now is watching for time passed since last keypress event, and disconnecting BT channel on idle. Though, it keeps input device always on, which allows application to receive keypress immediately on pairing event. Before that, application missed keypress pairing event due to new HID creation and delays in evdev for new device recognition. Now, if device is sleeping, you'll notice only one second delay for first pairing keypress.
The point is, that remote is consuming 0.18mA wile paired and 0.03-4 mA while unpaired (sleeping). At least such numbers are shown by my multimeter. %) And it doesn't matter if sleep mode is done explicitly (holding ps) or implicitly by closing connection from host.
Idle timeout is used from input.conf, though in ps3 code it is measured in seconds. If timeout is less then 5(sec) it is set to 300 (5 min). I'm using 15 sec. Sufficient to actively navigate through menus but quickly goes sleeping.
Code:
diff -ur bluez-4.47/input/device.c bluez-4.47-my/input/device.c
--- bluez-4.47/input/device.c    2009-05-09 11:31:01.000000000 +0200
+++ bluez-4.47-my/input/device.c    2009-08-23 23:31:14.000000000 +0200
@@ -83,18 +83,6 @@
    struct input_device    *idev;
};

-struct input_device {
-    DBusConnection        *conn;
-    char            *path;
-    bdaddr_t        src;
-    bdaddr_t        dst;
-    uint32_t        handle;
-    guint            dc_id;
-    char            *name;
-    struct btd_device    *device;
-    GSList            *connections;
-};
-
GSList *devices = NULL;

static struct input_device *find_device_by_path(GSList *list, const char *path)
@@ -636,6 +624,8 @@

    fake_hid = get_fake_hid(req->vendor, req->product);
    if (fake_hid) {
+        fake_hid->idev = idev;
+        fake_hid->timeout = iconn->timeout/60;
        fake = g_new0(struct fake_input, 1);
        fake->connect = fake_hid_connect;
        fake->disconnect = fake_hid_disconnect;
diff -ur bluez-4.47/input/device.h bluez-4.47-my/input/device.h
--- bluez-4.47/input/device.h    2009-04-23 03:40:04.000000000 +0200
+++ bluez-4.47-my/input/device.h    2009-08-23 19:26:24.000000000 +0200
@@ -27,7 +27,18 @@
#define L2CAP_PSM_HIDP_CTRL    0x11
#define L2CAP_PSM_HIDP_INTR    0x13

-struct input_device;
+struct input_device {
+    DBusConnection        *conn;
+    char            *path;
+    bdaddr_t        src;
+    bdaddr_t        dst;
+    uint32_t        handle;
+    guint            dc_id;
+    char            *name;
+    struct btd_device    *device;
+    GSList            *connections;
+};
+
struct input_conn;

struct fake_input {
Patch continues in next post.
Reply
#51
Code:
diff -ur bluez-4.47/input/fakehid.c bluez-4.47-my/input/fakehid.c
--- bluez-4.47/input/fakehid.c    2009-04-23 03:40:04.000000000 +0200
+++ bluez-4.47-my/input/fakehid.c    2009-08-23 23:31:01.000000000 +0200
@@ -31,11 +31,13 @@
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <sys/stat.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hidp.h>
#include <bluetooth/sdp.h>
+#include <bluetooth/hci.h>

#include <glib.h>
#include <dbus/dbus.h>
@@ -94,11 +96,11 @@

static unsigned int ps3remote_keymap[] = {
    [0x16] = KEY_EJECTCD,
-    [0x64] = KEY_AUDIO,
-    [0x65] = KEY_ANGLE,
-    [0x63] = KEY_SUBTITLE,
-    [0x0f] = KEY_CLEAR,
-    [0x28] = KEY_TIME,
+    [0x64] = KEY_A,            /* audio */
+    [0x65] = KEY_Z,            /* angle */
+    [0x63] = KEY_T,            /* subtitle */
+    [0x0f] = KEY_DELETE,        /* clear */
+    [0x28] = KEY_END,        /* timer */
    [0x00] = KEY_1,
    [0x01] = KEY_2,
    [0x02] = KEY_3,
@@ -109,41 +111,41 @@
    [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 */
+    [0x81] = KEY_F7,        /* red */
+    [0x82] = KEY_F8,        /* green */
+    [0x83] = KEY_F9,        /* yellow */
+    [0x80] = KEY_F10,        /* blue */
+    [0x70] = KEY_D,            /* display */
    [0x1a] = KEY_MENU,        /* top menu */
-    [0x40] = KEY_CONTEXT_MENU,    /* pop up/menu */
+    [0x40] = KEY_F11,        /* pop up/menu */
    [0x0e] = KEY_ESC,        /* return */
-    [0x5c] = KEY_OPTION,        /* options/triangle */
+    [0x5c] = KEY_F12,        /* options/triangle */
    [0x5d] = KEY_BACK,        /* back/circle */
-    [0x5f] = KEY_SCREEN,        /* view/square */
-    [0x5e] = BTN_0,            /* cross */
+    [0x5f] = KEY_V,            /* view/square */
+    [0x5e] = KEY_X,            /* 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 */
+    [0x5a] = KEY_F1,        /* L1 */
+    [0x58] = KEY_F2,        /* L2 */
+    [0x51] = KEY_F3,        /* L3 */
+    [0x5b] = KEY_F4,        /* R1 */
+    [0x59] = KEY_F5,        /* R2 */
+    [0x52] = KEY_F6,        /* R3 */
    [0x43] = KEY_HOMEPAGE,        /* PS button */
-    [0x50] = KEY_SELECT,
-    [0x53] = BTN_START,
-    [0x33] = KEY_REWIND,        /* scan back */
+    [0x50] = KEY_INSERT,        /* select */
+    [0x53] = KEY_HOME,        /* start */
+    [0x33] = KEY_R,            /* scan back */
    [0x32] = KEY_PLAY,
-    [0x34] = KEY_FORWARD,        /* scan forward */
-    [0x30] = KEY_PREVIOUS,
-    [0x38] = KEY_STOP,
-    [0x31] = KEY_NEXT,
-    [0x60] = KEY_FRAMEBACK,        /* slow/step back */
-    [0x39] = KEY_PAUSE,
-    [0x61] = KEY_FRAMEFORWARD,    /* slow/step forward */
+    [0x34] = KEY_F,            /* scan forward */
+    [0x30] = KEY_PAGEDOWN,        /* next */
+    [0x38] = KEY_STOP,        /* stop */
+    [0x31] = KEY_PAGEUP,        /* previous */
+    [0x60] = KEY_COMMA,        /* slow/step back */
+    [0x39] = KEY_PLAYPAUSE,        /* pause */
+    [0x61] = KEY_DOT,        /* slow/step forward */
    [0xff] = KEY_MAX,
};

@@ -167,7 +169,7 @@
    for (i = 0; i < 24; i++) {
        if ((lastmask & (1 << i)) == (mask & (1 << i)))
            continue;
-        if (ps3remote_bits[i] == 0)
+    if (ps3remote_bits[i] == 0)
            goto error;
        retval = ps3remote_keymap[ps3remote_bits[i]];
        if (mask & (1 << i))
@@ -208,18 +210,67 @@
                        lastmask & 0xff, lastkey);
    return -1;
}
+static gboolean ps3remote_sendkey(int uinput, unsigned int key,
+                  unsigned int value)
+{
+    struct uinput_event event;
+    memset(&event, 0, sizeof(event));
+    gettimeofday(&event.time, NULL);
+    event.type = EV_KEY;
+    event.code = key;
+    event.value = value;
+    if (write(uinput, &event, sizeof(event)) != sizeof(event)) {
+        error("Error writing to uinput device");
+        return FALSE;
+    }

+    memset(&event, 0, sizeof(event));
+    gettimeofday(&event.time, NULL);
+    event.type = EV_SYN;
+    event.code = SYN_REPORT;
+    if (write(uinput, &event, sizeof(event)) != sizeof(event)) {
+        error("Error writing to uinput device");
+        return FALSE;
+    }
+    return TRUE;
+}
+static gboolean ps3remote_out(GIOChannel *chan, GIOCondition cond,
+                                gpointer data)
+{
+    struct fake_input *fake = data;
+    const struct input_device *idev = ((struct fake_hid *)fake->priv)->idev;
+    gulong ms;
+    uint16_t to = (((struct fake_hid *)fake->priv)->timeout < 5) ?
+                300 : ((struct fake_hid *)fake->priv)->timeout;
+
+    if(g_timer_elapsed(((struct fake_hid *)fake->priv)->timer,&ms) > to ) {
+        DBG("idle timeout, disconnecting BT channel");
+        device_request_disconnect(idev->device, NULL);
+        return FALSE;
+    } else
+        usleep(1000);
+    return TRUE;
+}
static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
                gpointer data)
{
+    static unsigned int lastkey = 0;
+    static unsigned int lastval = 0;
    struct fake_input *fake = data;
-    struct uinput_event event;
    unsigned int key, value = 0;
    gsize size;
    char buff[50];

-    if (cond & G_IO_NVAL)
-        return FALSE;
+    g_timer_start(((struct fake_hid *)fake->priv)->timer);
+    if (cond & G_IO_NVAL) {
+        if(lastkey == KEY_HOMEPAGE && lastval == 1) {
+            DBG("Remote turned off");
+            goto failed;
+        } else {
+            DBG("Remote unpaired [%u:%u]", lastkey, lastval);
+            goto failed;
+        }
+    }

    if (cond & (G_IO_HUP | G_IO_ERR)) {
        error("Hangup or error on rfcomm server socket");
@@ -233,50 +284,51 @@
        error("IO Channel read error");
        goto failed;
    }
-
    key = ps3remote_decode(buff, size, &value);
    if (key == KEY_RESERVED) {
        error("Got invalid key from decode");
        goto failed;
    } else if (key == KEY_MAX)
        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");
+    /* Delaying key till release, assuming possible turn-off */
+    if(key == KEY_HOMEPAGE) {
+        if(value == 0 && lastkey == KEY_HOMEPAGE && lastval == 1) {
+            ps3remote_sendkey(fake->uinput, key, 1);
+            ps3remote_sendkey(fake->uinput, key, 0);
+        } else
+            DBG("Delayed: %u:%u (%u:%u)", key, value, lastkey, lastval);
+    } else if(!ps3remote_sendkey(fake->uinput, key, value))
        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;
-    }
-
+    lastkey = key;
+    lastval = value;
+    DBG("Passed key %u:%u", key, value);
    return TRUE;

-failed:
+failed: /*
    ioctl(fake->uinput, UI_DEV_DESTROY);
    close(fake->uinput);
-    fake->uinput = -1;
+    fake->uinput = -1;*/
+    g_timer_stop(((struct fake_hid *)fake->priv)->timer);
    g_io_channel_unref(fake->io);
-
+    DBG("Event failed");
    return FALSE;
}
-
static int ps3remote_setup_uinput(struct fake_input *fake,
                  struct fake_hid *fake_hid)
{
    struct uinput_dev dev;
+    struct stat sbuf;
    int i;

+    if(fake->uinput > 0) {
+        if(!(i=fstat(fake->uinput, &sbuf))) {
+            DBG("input %d is opened", fake->uinput);
+            return 0;
+        } else {
+            DBG("fstat(%d): error[%d]: %s", fake->uinput, i, strerror(errno));
+        }
+    }
+
    fake->uinput = open("/dev/input/uinput", O_RDWR);
    if (fake->uinput < 0) {
        fake->uinput = open("/dev/uinput", O_RDWR);
@@ -348,6 +400,8 @@
        .disconnect    = fake_hid_common_disconnect,
        .event        = ps3remote_event,
        .setup_uinput    = ps3remote_setup_uinput,
+        .fake        = NULL,
+        .timeout    = 15,
    },

    { },
@@ -373,6 +427,13 @@
int fake_hid_connadd(struct fake_input *fake, GIOChannel *intr_io,
                        struct fake_hid *fake_hid)
{
+    if(fake_hid->fake == NULL) {
+        fake_hid->fake = fake;
+        fake_hid->timer = g_timer_new();
+    } else {
+        g_free(fake);
+        fake = fake_hid->fake;
+    }
    if (fake_hid->setup_uinput(fake, fake_hid)) {
        error("Error setting up uinput");
        return ENOMEM;
@@ -382,6 +443,6 @@
    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);
-
+    g_io_add_watch(fake->io, G_IO_OUT, (GIOFunc) ps3remote_out, fake);
    return 0;
}
Only in bluez-4.47-my/input/: fakehid.c.bak
Only in bluez-4.47-my/input/: fakehid.c.new
diff -ur bluez-4.47/input/fakehid.h bluez-4.47-my/input/fakehid.h
--- bluez-4.47/input/fakehid.h    2009-02-25 21:14:11.000000000 +0100
+++ bluez-4.47-my/input/fakehid.h    2009-08-23 22:57:46.000000000 +0200
@@ -31,6 +31,10 @@
    int (*disconnect) (struct fake_input *fake_input);
    gboolean (*event) (GIOChannel *chan, GIOCondition cond, gpointer data);
    int (*setup_uinput) (struct fake_input *fake, struct fake_hid *fake_hid);
+    struct fake_input *fake;
+    const struct input_device *idev;
+    GTimer *timer;
+    uint16_t timeout;
};

struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product);
Reply
#52
ruff: Have you submitted this patch to upstream? If so, what do they think about it? Also since 4.48 is out, are there any changes that need to be made for the new version?
Reply
#53
I submitted first patch, it is still being discussed. I'd appreciate if someone else will try it and report back of any issue.
Patch applied without any issue to 48 rel.
Code:
ruff@ruff:~/bluez-4.48$ patch -p1 </home/share/fakehid.patch
patching file input/device.c
patching file input/device.h
patching file input/fakehid.c
patching file input/fakehid.h
<snip configure && make && make install>
Making install in input
  CC     main.lo
  CC     manager.lo
  CC     server.lo
  CC     device.lo
  CC     fakehid.lo
  CCLD   input.la
<snip>
root@ruff:~# /opt/bluez/sbin/bluetoothd -nd
bluetoothd[14361]: Bluetooth daemon 4.48
bluetoothd[14361]: Enabling debug information
...
bluetoothd[14361]: Agent registered for hci0 at :1.688:/org/blueman/agent/adapter/hci0
bluetoothd[14361]: Changing service classes to 0x5a0104
...
bluetoothd[14361]: ps3remote_out: idle timeout, disconnecting BT channel
bluetoothd[14361]: Input: disconnect /org/bluez/14361/hci0/dev_00_21_4F_B1_F2_79
bluetoothd[14361]: ps3remote_event: Remote unpaired [45:0]
Reply
#54
I just ordered a remote and dongle so I should be able to try it out soon. It appears they released 4.49 today so I guess I will try it with that version.
Reply
#55
ruff Wrote:I submitted first patch, it is still being discussed. I'd appreciate if someone else will try it and report back of any issue.
Patch applied without any issue to 48 rel.

I can confirm the patches work on current git version of BlueZ. Nice work!
Reply
#56
I've successfully been able to pair the remote and can see output from irw, but how do I go about configuring lircmap.xml and keymap.xml to do the good stuff? I have no previous experience with lirc, so I'm at a bit of a loss in doing this part.

I've only modified hardware.conf, lircd.conf, lircmap.xml and keymap.xml... is that all that's required?
Reply
#57
rshuck Wrote:is that all that's required?
Yes, if you see key events in irw - remote is working and lircmap is sufficient. If some extra functions required - you can add them to keymap.
Reply
#58
ruff Wrote:Yes, if you see key events in irw - remote is working and lircmap is sufficient. If some extra functions required - you can add them to keymap.

Ok, I guess I'll have to take another look tonight to see why XBMC isn't responding. The remote does nothing at all at this point in XBMC, but acts just like it used to on the desktop (like a keyboard's arrow keys).
Reply
#59
Check logs (~/.xbmc/temp/xbmc.log), might be your files are rejected due to some typos
Reply
#60
Put this in userdata/advancedsettings.xml to get some useful info about keypresses in your log.

Code:
<displayremotecodes>true</displayremotecodes>
Reply
  • 1
  • 2
  • 3
  • 4(current)
  • 5
  • 6
  • 56

Logout Mark Read Team Forum Stats Members Help
[LINUX] Sony PlayStation 3 Blu-ray Disc Remote (PS3 BD) + LIRC + XBMC = SUCCESS6