2011-02-10 10:42:04

by Antonio Ospite

[permalink] [raw]
Subject: [RESEND] ID_SERIAL for udev bluetooth joystick events

Hi,

I have a question about udev events generated by a bluetooth joystick:
when udev generates the joystick event for a bt joystick, the ID_SERIAL
property matches the one of the bt adapter not the one of the joystick.

For example (using "udevadm monitor --property"), when connecting the
Sony Sixaxis via usb I get:
ID_SERIAL=Sony_PLAYSTATION_R_3_Controller
in the input and joystick events, but when I connect it via bt, I get:
ID_SERIAL=Broadcom_Corp_ANYCOM_Blue_USB-200_250
which matches my bluetooth adapter.

Is this expected/known, or is it a bug?
I am using kernel 2.6.37, udev 164

For the records, I also get ID_BUS=usb when connecting via bt, but I can
live with that since I can differenciate usb and bt operation using
ID_USB_DRIVER=usbhid
versus
ID_USB_DRIVER=btusb

Some insight of what I am trying to achieve with udev:
1. Monitor new joystick devices.
2. If ID_SERIAL != Sony_PLAYSTATION_R_3_Controller, then STOP.
3. Get the associated hidraw device node navigating the event tree.
4. Set leds using the value from the ID_INPUT_JOYSTICK property.
5. If ID_USB_DRIVER=usbhid do the needed pairing.

And with the current behaviour for ID_SERIAL I cannot enforce 2.
I could listen for the (hid) event and use HID_NAME which seems to be a
little more consistent:
usb -> HID_NAME=Sony PLAYSTATION(R)3 Controller
bt -> HID_NAME=PLAYSTATION(R)3 Controller
and navigate the event hierarchy to get ID_INPUT_JOYSTICK, but that is
slightly more complicated, and I am curious about the ID_SERIAL
behavior anyways :)

Thanks,
Antonio

--
Antonio Ospite
http://ao2.it

PGP public key ID: 0x4553B001

A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?


Attachments:
(No filename) (1.74 kB)
(No filename) (198.00 B)
Download all attachments

2011-02-21 22:45:02

by Antonio Ospite

[permalink] [raw]
Subject: Re: [RESEND] ID_SERIAL for udev bluetooth joystick events

On Thu, 10 Feb 2011 11:42:04 +0100
Antonio Ospite <[email protected]> wrote:

> Hi,
>
> I have a question about udev events generated by a bluetooth joystick:
> when udev generates the joystick event for a bt joystick, the ID_SERIAL
> property matches the one of the bt adapter not the one of the joystick.
>

Ok, now I have a clearer picture of what udev does when I connect the
joystick and I can pose better questions.

> For example (using "udevadm monitor --property"), when connecting the
> Sony Sixaxis via usb I get:
> ID_SERIAL=Sony_PLAYSTATION_R_3_Controller
> in the input and joystick events, but when I connect it via bt, I get:
> ID_SERIAL=Broadcom_Corp_ANYCOM_Blue_USB-200_250
> which matches my bluetooth adapter.
>

This happens because /lib/udev/usb_id goes up to the usb device when
creating the event for bt input devices connected to a btusb dongle.

> Some insight of what I am trying to achieve with udev:
> 1. Monitor new joystick devices.
> 2. If ID_SERIAL != Sony_PLAYSTATION_R_3_Controller, then STOP.
> 3. Get the associated hidraw device node navigating the event tree.
> 4. Set leds using the value from the ID_INPUT_JOYSTICK property.

This is wrong, /lib/udev/input_id hardcodes a '1' as value there, I
thought it was the index of the joystick like in:
1 -> js0
2 -> js1
but it is not, ID_INPUT_JOYSTICK=1 means just "this is a joystick", so
I think I have to parse the DEVNAME (dev/jsX) to get the actual index,
right?

> 5. If ID_USB_DRIVER=usbhid do the needed pairing.
>
> And with the current behaviour for ID_SERIAL I cannot enforce 2.
> I could listen for the (hid) event and use HID_NAME which seems to be a
> little more consistent:
> usb -> HID_NAME=Sony PLAYSTATION(R)3 Controller
> bt -> HID_NAME=PLAYSTATION(R)3 Controller
> and navigate the event hierarchy to get ID_INPUT_JOYSTICK, but that is
> slightly more complicated, and I am curious about the ID_SERIAL
> behavior anyways :)
>

Maybe I'd still better monitor the 'input' event and move up and down
from here to collect the joystick index and the hidraw device node, but
I wonder if a patch along these lines (this is just for the sake of
discussion) could have sense to prevent exposing the dongle properties
also for the input devices:

diff --git a/extras/usb_id/usb_id.c b/extras/usb_id/usb_id.c
index fabd092..8e6e20f 100644
--- a/extras/usb_id/usb_id.c
+++ b/extras/usb_id/usb_id.c
@@ -56,6 +56,7 @@ static char serial_str[UTIL_NAME_SIZE];
static char packed_if_str[UTIL_NAME_SIZE];
static char revision_str[64];
static char type_str[64];
+static char bustype_str[64];
static char instance_str[64];
static const char *ifnum;
static const char *driver;
@@ -147,6 +148,29 @@ static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len
return type_num;
}

+static int set_usb_input_bustype(char *to, const char *from, size_t len)
+{
+ int bustype_num = 0;
+ char *eptr;
+ char *type = "unknown";
+
+ bustype_num = strtoul(from, &eptr, 0);
+ if (eptr != from) {
+ switch (bustype_num) {
+ case 3:
+ type = "usb";
+ break;
+ case 5:
+ type = "bluetooth";
+ break;
+ default:
+ break;
+ }
+ }
+ util_strscpy(to, len, type);
+ return bustype_num;
+}
+
static void set_scsi_type(char *to, const char *from, size_t len)
{
int type_num;
@@ -312,8 +336,8 @@ static int usb_id(struct udev_device *dev)
set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1);
}

- info(udev, "%s: if_class %d protocol %d\n",
- udev_device_get_syspath(dev_interface), if_class_num, protocol);
+ info(udev, "%s: if_class %d protocol %d type_str: %s\n",
+ udev_device_get_syspath(dev_interface), if_class_num, protocol, type_str);

/* usb device directory */
dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device");
@@ -326,6 +350,57 @@ static int usb_id(struct udev_device *dev)
/* all interfaces of the device in a single string */
dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));

+ /* input device XXX this check is not right, we might use a dev_input
+ * as below */
+ if ((protocol == 0) && !use_usb_info) {
+ struct udev_device *dev_input;
+ const char *input_vendor, *input_model, *input_rev, *input_bustype;
+
+ /* get input device */
+ dev_input = udev_device_get_parent_with_subsystem_devtype(dev, "input", NULL);
+ if (dev_input == NULL) {
+ info(udev, "unable to find parent 'input' device of '%s'\n",
+ udev_device_get_syspath(dev));
+ goto fallback;
+ }
+
+ input_vendor = udev_device_get_sysattr_value(dev_input, "id/vendor");
+ if (!input_vendor) {
+ info(udev, "%s: cannot get input vendor attribute\n",
+ udev_device_get_sysname(dev_input));
+ goto fallback;
+ }
+ udev_util_encode_string(input_vendor, vendor_str_enc, sizeof(vendor_str_enc));
+ udev_util_replace_whitespace(input_vendor, vendor_str, sizeof(vendor_str)-1);
+ udev_util_replace_chars(vendor_str, NULL);
+
+ vendor_id = input_vendor;
+ product_id = udev_device_get_sysattr_value(dev_input, "id/product");
+
+ input_model = udev_device_get_sysattr_value(dev_input, "name");
+ if (!input_model) {
+ info(udev, "%s: cannot get input model attribute\n",
+ udev_device_get_sysname(dev_input));
+ goto fallback;
+ }
+ udev_util_encode_string(input_model, model_str_enc, sizeof(model_str_enc));
+ udev_util_replace_whitespace(input_model, model_str, sizeof(model_str)-1);
+ udev_util_replace_chars(model_str, NULL);
+
+ input_rev = udev_device_get_sysattr_value(dev_input, "id/version");
+ if (!input_rev) {
+ info(udev, "%s: cannot get input revision attribute\n",
+ udev_device_get_sysname(dev_input));
+ goto fallback;
+ }
+ udev_util_replace_whitespace(input_rev, revision_str, sizeof(revision_str)-1);
+ udev_util_replace_chars(revision_str, NULL);
+
+ /* get Bus type, see BUS_* in linux/input.h */
+ input_bustype = udev_device_get_sysattr_value(dev_input, "id/bustype");
+ set_usb_input_bustype(bustype_str, input_bustype, sizeof(bustype_str) - 1 );
+ }
+
/* mass storage : SCSI or ATAPI */
if ((protocol == 6 || protocol == 2) && !use_usb_info) {
struct udev_device *dev_scsi;
@@ -390,8 +465,12 @@ static int usb_id(struct udev_device *dev)
}

fallback:
- vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
- product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");
+ if (vendor_id[0] == '\0') {
+ vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
+ }
+ if (product_id[0] == '\0') {
+ product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");
+ }

/* fallback to USB vendor & device */
if (vendor_str[0] == '\0') {
@@ -559,7 +638,7 @@ int main(int argc, char **argv)
printf("ID_TYPE=%s\n", type_str);
if (instance_str[0] != '\0')
printf("ID_INSTANCE=%s\n", instance_str);
- printf("ID_BUS=usb\n");
+ printf("ID_BUS=%s\n", (bustype_str[0] == '\0') ? "usb" : bustype_str);
if (packed_if_str[0] != '\0')
printf("ID_USB_INTERFACES=:%s\n", packed_if_str);
if (ifnum != NULL)


Thanks,
Antonio

--
Antonio Ospite
http://ao2.it

PGP public key ID: 0x4553B001

A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?


Attachments:
(No filename) (7.13 kB)
(No filename) (198.00 B)
Download all attachments