| | |
| | | int device_handle; |
| | | int blocking; |
| | | int uses_numbered_reports; |
| | | int is_bluetooth; |
| | | int needs_ble_hack; |
| | | }; |
| | | |
| | | |
| | |
| | | dev->device_handle = -1; |
| | | dev->blocking = 1; |
| | | dev->uses_numbered_reports = 0; |
| | | dev->is_bluetooth = 0; |
| | | dev->needs_ble_hack = 0; |
| | | |
| | | return dev; |
| | | } |
| | |
| | | return (found_id && found_name && found_serial); |
| | | } |
| | | |
| | | static int is_bluetooth(hid_device *dev) |
| | | static int is_BLE(hid_device *dev) |
| | | { |
| | | struct udev *udev; |
| | | struct udev_device *udev_dev, *hid_dev; |
| | | struct stat s; |
| | | int ret = -1; |
| | | int ret; |
| | | |
| | | /* Create the udev object */ |
| | | udev = udev_new(); |
| | |
| | | } |
| | | |
| | | /* Get the dev_t (major/minor numbers) from the file handle. */ |
| | | ret = fstat(dev->device_handle, &s); |
| | | if (-1 == ret) { |
| | | if (fstat(dev->device_handle, &s) < 0) { |
| | | udev_unref(udev); |
| | | return ret; |
| | | return -1; |
| | | } |
| | | |
| | | /* Open a udev device from the dev_t. 'c' means character device. */ |
| | | ret = 0; |
| | | udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); |
| | | if (udev_dev) { |
| | | hid_dev = udev_device_get_parent_with_subsystem_devtype( |
| | |
| | | "hid", |
| | | NULL); |
| | | if (hid_dev) { |
| | | unsigned short dev_vid; |
| | | unsigned short dev_pid; |
| | | int bus_type; |
| | | unsigned short dev_vid = 0; |
| | | unsigned short dev_pid = 0; |
| | | int bus_type = 0; |
| | | char *serial_number_utf8 = NULL; |
| | | char *product_name_utf8 = NULL; |
| | | |
| | | ret = parse_uevent_info( |
| | | parse_uevent_info( |
| | | udev_device_get_sysattr_value(hid_dev, "uevent"), |
| | | &bus_type, |
| | | &dev_vid, |
| | |
| | | free(serial_number_utf8); |
| | | free(product_name_utf8); |
| | | |
| | | ret = (bus_type == BUS_BLUETOOTH); |
| | | if (bus_type == BUS_BLUETOOTH) { |
| | | /* Right now the Steam Controller is the only BLE device that we send feature reports to */ |
| | | if (dev_vid == 0x28de /* Valve */) { |
| | | ret = 1; |
| | | } |
| | | } |
| | | |
| | | /* hid_dev doesn't need to be (and can't be) unref'd. |
| | | I'm not sure why, but it'll throw double-free() errors. */ |
| | |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) |
| | | { |
| | |
| | | dev->device_handle = open(path, O_RDWR); |
| | | |
| | | /* If we have a good handle, return it. */ |
| | | if (dev->device_handle > 0) { |
| | | if (dev->device_handle >= 0) { |
| | | |
| | | /* Get the report descriptor */ |
| | | int res, desc_size = 0; |
| | |
| | | rpt_desc.size); |
| | | } |
| | | |
| | | dev->is_bluetooth = (is_bluetooth(dev) == 1); |
| | | dev->needs_ble_hack = (is_BLE(dev) == 1); |
| | | |
| | | return dev; |
| | | } |
| | |
| | | { |
| | | int res; |
| | | |
| | | /* It looks like HIDIOCGFEATURE() on Bluetooth devices doesn't return the report number */ |
| | | if (dev->is_bluetooth) { |
| | | /* It looks like HIDIOCGFEATURE() on Bluetooth LE devices doesn't return the report number */ |
| | | if (dev->needs_ble_hack) { |
| | | data[1] = data[0]; |
| | | ++data; |
| | | --length; |
| | |
| | | res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); |
| | | if (res < 0) |
| | | perror("ioctl (GFEATURE)"); |
| | | else if (dev->is_bluetooth) |
| | | else if (dev->needs_ble_hack) |
| | | ++res; |
| | | |
| | | return res; |