* [PATCH 1/4] sixaxis: Add support for setting PS3 controller LEDs
2013-12-01 13:41 [PATCH 0/4] more sixaxis goodies Szymon Janc
@ 2013-12-01 13:41 ` Szymon Janc
2013-12-01 13:41 ` [PATCH 2/4] Rename device_is_connected to btd_device_is_connected Szymon Janc
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2013-12-01 13:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This will set controller LEDs according to joystick device number
when controller is connected over Bluetooth. If joystick number is too
big (> 7) or falied to be read, set it to 0 to switch off all LEDs.
This will allow to disable LEDs blinking after connection.
Waiting for events is not really needed when connected over Bluetooth
but this is in preparation for supporting LEDs setup over USB.
---
plugins/sixaxis.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 139 insertions(+), 2 deletions(-)
diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index 070b463..c3ca267 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -31,6 +31,7 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
+#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/hidraw.h>
#include <linux/input.h>
@@ -124,6 +125,62 @@ static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
return ret;
}
+static gboolean setup_leds(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ /*
+ * the total time the led is active (0xff means forever)
+ * | duty_length: cycle time in deciseconds (0 - "blink very fast")
+ * | | ??? (Maybe a phase shift or duty_length multiplier?)
+ * | | | % of duty_length led is off (0xff means 100%)
+ * | | | | % of duty_length led is on (0xff means 100%)
+ * | | | | |
+ * 0xff, 0x27, 0x10, 0x00, 0x32,
+ */
+ uint8_t leds_report[] = {
+ 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, /* rumble values TBD */
+ 0x00, 0x00, 0x00, 0x00, 0x00, /* LED_1=0x02, LED_2=0x04 ... */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_4 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_3 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_2 */
+ 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ int number = GPOINTER_TO_INT(user_data);
+ int ret;
+ int fd;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ return FALSE;
+
+ DBG("number %d", number);
+
+ /* TODO we could support up to 10 (1 + 2 + 3 + 4) */
+ if (number > 7)
+ return FALSE;
+
+ if (number > 4) {
+ leds_report[10] |= 0x10;
+ number -= 4;
+ }
+
+ leds_report[10] |= 0x01 << number;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ ret = write(fd, leds_report, sizeof(leds_report));
+ if (ret == sizeof(leds_report))
+ return FALSE;
+
+ if (ret < 0)
+ error("sixaxis: failed to set LEDS (%s)", strerror(errno));
+ else
+ error("sixaxis: failed to set LEDS (%d bytes written)", ret);
+
+ return FALSE;
+}
+
static void setup_device(int fd, int index, struct btd_adapter *adapter)
{
char device_addr[18], master_addr[18], adapter_addr[18];
@@ -167,6 +224,69 @@ static void setup_device(int fd, int index, struct btd_adapter *adapter)
btd_device_set_trusted(device, TRUE);
}
+static int get_js_number(struct udev_device *udevice)
+{
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_enumerate *enumerate;
+ struct udev_device *hid_parent;
+ const char *hidraw_node;
+ const char *hid_phys;
+ int number = 0;
+
+ hid_parent = udev_device_get_parent_with_subsystem_devtype(udevice,
+ "hid", NULL);
+
+ hid_phys = udev_device_get_property_value(hid_parent, "HID_PHYS");
+ hidraw_node = udev_device_get_devnode(udevice);
+ if (!hid_phys || !hidraw_node)
+ return 0;
+
+ enumerate = udev_enumerate_new(udev_device_get_udev(udevice));
+ udev_enumerate_add_match_sysname(enumerate, "js*");
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ struct udev_device *input_parent;
+ struct udev_device *js_dev;
+ const char *input_phys;
+ const char *devname;
+
+ devname = udev_list_entry_get_name(dev_list_entry);
+ js_dev = udev_device_new_from_syspath(
+ udev_device_get_udev(udevice),
+ devname);
+
+ input_parent = udev_device_get_parent_with_subsystem_devtype(
+ js_dev, "input", NULL);
+ if (!input_parent)
+ goto next;
+
+ /* check if this is the joystick relative to the hidraw device
+ * above */
+ input_phys = udev_device_get_sysattr_value(input_parent,
+ "phys");
+ if (!input_phys)
+ goto next;
+
+ if (!strcmp(input_phys, hid_phys)) {
+ number = atoi(udev_device_get_sysnum(js_dev));
+
+ /* joystick numbers start from 0, leds from 1 */
+ number++;
+
+ udev_device_unref(js_dev);
+ break;
+ }
+next:
+ udev_device_unref(js_dev);
+ }
+
+ udev_enumerate_unref(enumerate);
+
+ return number;
+}
+
static int get_supported_device(struct udev_device *udevice, uint16_t *bus)
{
struct udev_device *hid_parent;
@@ -195,6 +315,7 @@ static int get_supported_device(struct udev_device *udevice, uint16_t *bus)
static void device_added(struct udev_device *udevice)
{
struct btd_adapter *adapter;
+ GIOChannel *io;
uint16_t bus;
int index;
int fd;
@@ -215,10 +336,26 @@ static void device_added(struct udev_device *udevice)
if (fd < 0)
return;
- if (bus == BUS_USB)
+ io = g_io_channel_unix_new(fd);
+
+ switch (bus) {
+ case BUS_USB:
setup_device(fd, index, adapter);
+ break;
+ case BUS_BLUETOOTH:
+ /* wait for events before setting leds */
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ setup_leds,
+ GINT_TO_POINTER(get_js_number(udevice)));
+
+ break;
+ default:
+ DBG("uknown bus type (%u)", bus);
+ break;
+ }
- close(fd);
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_unref(io);
}
static gboolean monitor_watch(GIOChannel *source, GIOCondition condition,
--
1.8.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/4] Rename device_is_connected to btd_device_is_connected
2013-12-01 13:41 [PATCH 0/4] more sixaxis goodies Szymon Janc
2013-12-01 13:41 ` [PATCH 1/4] sixaxis: Add support for setting PS3 controller LEDs Szymon Janc
@ 2013-12-01 13:41 ` Szymon Janc
2013-12-01 13:41 ` [PATCH 3/4] sixaxis: Skip controller setup if already connected over Bluetooth Szymon Janc
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2013-12-01 13:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
Allow this symbol to be exported and usable from external plugins.
---
profiles/input/device.c | 4 ++--
src/adapter.c | 6 +++---
src/device.c | 6 +++---
src/device.h | 2 +-
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/profiles/input/device.c b/profiles/input/device.c
index 0c2089b..521aca8 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -667,7 +667,7 @@ static gboolean input_device_auto_reconnect(gpointer user_data)
/* Stop the recurrent reconnection attempts if the device is reconnected
* or is marked for removal. */
if (device_is_temporary(idev->device) ||
- device_is_connected(idev->device))
+ btd_device_is_connected(idev->device))
return FALSE;
/* Only attempt an auto-reconnect for at most 3 minutes (6 * 30s). */
@@ -713,7 +713,7 @@ static void input_device_enter_reconnect_mode(struct input_device *idev)
/* If the device is temporary we are not required to reconnect with the
* device. This is likely the case of a removing device. */
if (device_is_temporary(idev->device) ||
- device_is_connected(idev->device))
+ btd_device_is_connected(idev->device))
return;
if (idev->reconnect_timer > 0)
diff --git a/src/adapter.c b/src/adapter.c
index 55a41db..41f7bd6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2158,7 +2158,7 @@ static DBusMessage *remove_device(DBusConnection *conn,
btd_device_set_temporary(device, TRUE);
- if (!device_is_connected(device)) {
+ if (!btd_device_is_connected(device)) {
adapter_remove_device(adapter, device);
return dbus_message_new_method_return(msg);
}
@@ -4195,7 +4195,7 @@ connect_le:
* connect_list stop passive scanning so that a connection
* attempt to it can be made
*/
- if (device_is_le(dev) && !device_is_connected(dev) &&
+ if (device_is_le(dev) && !btd_device_is_connected(dev) &&
g_slist_find(adapter->connect_list, dev)) {
adapter->connect_le = dev;
stop_passive_scanning(adapter);
@@ -5865,7 +5865,7 @@ static void unpaired_callback(uint16_t index, uint16_t length,
btd_device_set_temporary(device, TRUE);
- if (device_is_connected(device))
+ if (btd_device_is_connected(device))
device_request_disconnect(device, NULL);
else
adapter_remove_device(adapter, device);
diff --git a/src/device.c b/src/device.c
index 847ffad..5380c1a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1355,7 +1355,7 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
if (device_is_le(dev)) {
int err;
- if (device_is_connected(dev))
+ if (btd_device_is_connected(dev))
return dbus_message_new_method_return(msg);
btd_device_set_temporary(dev, FALSE);
@@ -1645,7 +1645,7 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
* channel first and only then start pairing (there's code for
* this in the ATT connect callback)
*/
- if (device_is_le(device) && !device_is_connected(device))
+ if (device_is_le(device) && !btd_device_is_connected(device))
err = device_connect_le(device);
else
err = adapter_create_bonding(adapter, &device->bdaddr,
@@ -1791,7 +1791,7 @@ static const GDBusPropertyTable device_properties[] = {
{ }
};
-gboolean device_is_connected(struct btd_device *device)
+gboolean btd_device_is_connected(struct btd_device *device)
{
return device->connected;
}
diff --git a/src/device.h b/src/device.h
index c3fea4a..3a33cb2 100644
--- a/src/device.h
+++ b/src/device.h
@@ -74,7 +74,7 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
void device_set_bonded(struct btd_device *device, gboolean bonded);
void device_set_legacy(struct btd_device *device, bool legacy);
void device_set_rssi(struct btd_device *device, int8_t rssi);
-gboolean device_is_connected(struct btd_device *device);
+gboolean btd_device_is_connected(struct btd_device *device);
bool device_is_retrying(struct btd_device *device);
void device_bonding_complete(struct btd_device *device, uint8_t status);
gboolean device_is_bonding(struct btd_device *device, const char *sender);
--
1.8.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/4] sixaxis: Skip controller setup if already connected over Bluetooth
2013-12-01 13:41 [PATCH 0/4] more sixaxis goodies Szymon Janc
2013-12-01 13:41 ` [PATCH 1/4] sixaxis: Add support for setting PS3 controller LEDs Szymon Janc
2013-12-01 13:41 ` [PATCH 2/4] Rename device_is_connected to btd_device_is_connected Szymon Janc
@ 2013-12-01 13:41 ` Szymon Janc
2013-12-01 13:41 ` [PATCH 4/4] sixaxis: Add support for setting LEDs when connected over USB Szymon Janc
2013-12-03 7:48 ` [PATCH 0/4] more sixaxis goodies Johan Hedberg
4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2013-12-01 13:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
If controller is already connected over Bluetooth but was then
plugged-in via USB (eg. to charge battery) there is no need to do
any setup.
---
plugins/sixaxis.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index c3ca267..b8fe287 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -194,6 +194,12 @@ static void setup_device(int fd, int index, struct btd_adapter *adapter)
if (get_master_bdaddr(fd, &master_bdaddr) < 0)
return;
+ /* This can happen if controller was plugged while already connected
+ * eg. to charge up battery */
+ device = btd_adapter_find_device(adapter, &device_bdaddr);
+ if (device && btd_device_is_connected(device))
+ return;
+
adapter_bdaddr = btd_adapter_get_address(adapter);
if (bacmp(adapter_bdaddr, &master_bdaddr)) {
--
1.8.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/4] sixaxis: Add support for setting LEDs when connected over USB
2013-12-01 13:41 [PATCH 0/4] more sixaxis goodies Szymon Janc
` (2 preceding siblings ...)
2013-12-01 13:41 ` [PATCH 3/4] sixaxis: Skip controller setup if already connected over Bluetooth Szymon Janc
@ 2013-12-01 13:41 ` Szymon Janc
2013-12-03 7:48 ` [PATCH 0/4] more sixaxis goodies Johan Hedberg
4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2013-12-01 13:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This allows to setup LEDs when device is connected over USB, not
Bluetooth. This coverts two scenarios:
- user plugged PS3 controller and pressed PS3 button before unplugging,
in that case LEDs are set
- user plugged already BT connected PS3 controller to USB, this results
in new /dev/input/jsX device being create but controller is still
transmitting over BT and old jsX device exists. In that case don't
set LEDs as they are already set.
This is not directly related to Bluetooth itself but change is really
small and provides much better and consistent user experience.
---
plugins/sixaxis.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index b8fe287..45fa170 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -181,7 +181,7 @@ static gboolean setup_leds(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
-static void setup_device(int fd, int index, struct btd_adapter *adapter)
+static bool setup_device(int fd, int index, struct btd_adapter *adapter)
{
char device_addr[18], master_addr[18], adapter_addr[18];
bdaddr_t device_bdaddr, master_bdaddr;
@@ -189,22 +189,23 @@ static void setup_device(int fd, int index, struct btd_adapter *adapter)
struct btd_device *device;
if (get_device_bdaddr(fd, &device_bdaddr) < 0)
- return;
+ return false;
if (get_master_bdaddr(fd, &master_bdaddr) < 0)
- return;
+ return false;
/* This can happen if controller was plugged while already connected
- * eg. to charge up battery */
+ * eg. to charge up battery.
+ * Don't set LEDs in that case, hence return false */
device = btd_adapter_find_device(adapter, &device_bdaddr);
if (device && btd_device_is_connected(device))
- return;
+ return false;
adapter_bdaddr = btd_adapter_get_address(adapter);
if (bacmp(adapter_bdaddr, &master_bdaddr)) {
if (set_master_bdaddr(fd, adapter_bdaddr) < 0)
- return;
+ return false;
}
ba2str(&device_bdaddr, device_addr);
@@ -218,7 +219,7 @@ static void setup_device(int fd, int index, struct btd_adapter *adapter)
if (g_slist_find_custom(btd_device_get_uuids(device), HID_UUID,
(GCompareFunc)strcasecmp)) {
DBG("device %s already known, skipping", device_addr);
- return;
+ return true;
}
info("sixaxis: setting up new device");
@@ -228,6 +229,8 @@ static void setup_device(int fd, int index, struct btd_adapter *adapter)
devices[index].pid, devices[index].version);
btd_device_set_temporary(device, FALSE);
btd_device_set_trusted(device, TRUE);
+
+ return true;
}
static int get_js_number(struct udev_device *udevice)
@@ -346,8 +349,10 @@ static void device_added(struct udev_device *udevice)
switch (bus) {
case BUS_USB:
- setup_device(fd, index, adapter);
- break;
+ if (!setup_device(fd, index, adapter))
+ break;
+
+ /* fall through */
case BUS_BLUETOOTH:
/* wait for events before setting leds */
g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
--
1.8.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 0/4] more sixaxis goodies
2013-12-01 13:41 [PATCH 0/4] more sixaxis goodies Szymon Janc
` (3 preceding siblings ...)
2013-12-01 13:41 ` [PATCH 4/4] sixaxis: Add support for setting LEDs when connected over USB Szymon Janc
@ 2013-12-03 7:48 ` Johan Hedberg
4 siblings, 0 replies; 6+ messages in thread
From: Johan Hedberg @ 2013-12-03 7:48 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
Hi Szymon,
On Sun, Dec 01, 2013, Szymon Janc wrote:
> This adds support for setting PS3 controller LEDs both over Bluetooth
> and USB. More details in commits messages.
>
> One thing I noticed is that setting LEDs over Bluetooth fails on kernel
> 3.10+ (write always returns 0). Could this be related to HIDP related
> work that was merged in 3.10?
>
> Comments and testing are welcome.
>
> Szymon Janc (4):
> sixaxis: Add support for setting PS3 controller LEDs
> Rename device_is_connected to btd_device_is_connected
> sixaxis: Skip controller setup if already connected over Bluetooth
> sixaxis: Add support for setting LEDs when connected over USB
>
> plugins/sixaxis.c | 164 +++++++++++++++++++++++++++++++++++++++++++++---
> profiles/input/device.c | 4 +-
> src/adapter.c | 6 +-
> src/device.c | 6 +-
> src/device.h | 2 +-
> 5 files changed, 165 insertions(+), 17 deletions(-)
All four patches have been applied. Thanks.
Johan
^ permalink raw reply [flat|nested] 6+ messages in thread