|
71 | 71 | struct hid_device_ {
|
72 | 72 | int device_handle;
|
73 | 73 | int blocking;
|
| 74 | + int needs_ble_hack; |
74 | 75 | wchar_t *last_error_str;
|
75 | 76 | struct hid_device_info* device_info;
|
76 | 77 | };
|
@@ -564,6 +565,69 @@ static int parse_uevent_info(const char *uevent, unsigned *bus_type,
|
564 | 565 | return (found_id && found_name && found_serial);
|
565 | 566 | }
|
566 | 567 |
|
| 568 | +static int is_BLE(hid_device *dev) |
| 569 | +{ |
| 570 | + struct udev *udev; |
| 571 | + struct udev_device *udev_dev, *hid_dev; |
| 572 | + struct stat s; |
| 573 | + int ret; |
| 574 | + |
| 575 | + /* Create the udev object */ |
| 576 | + udev = udev_new(); |
| 577 | + if (!udev) { |
| 578 | + printf("Can't create udev\n"); |
| 579 | + return -1; |
| 580 | + } |
| 581 | + |
| 582 | + /* Get the dev_t (major/minor numbers) from the file handle. */ |
| 583 | + if (fstat(dev->device_handle, &s) < 0) { |
| 584 | + udev_unref(udev); |
| 585 | + return -1; |
| 586 | + } |
| 587 | + |
| 588 | + /* Open a udev device from the dev_t. 'c' means character device. */ |
| 589 | + ret = 0; |
| 590 | + udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); |
| 591 | + if (udev_dev) { |
| 592 | + hid_dev = udev_device_get_parent_with_subsystem_devtype( |
| 593 | + udev_dev, |
| 594 | + "hid", |
| 595 | + NULL); |
| 596 | + if (hid_dev) { |
| 597 | + unsigned short dev_vid = 0; |
| 598 | + unsigned short dev_pid = 0; |
| 599 | + unsigned bus_type = 0; |
| 600 | + char *serial_number_utf8 = NULL; |
| 601 | + char *product_name_utf8 = NULL; |
| 602 | + |
| 603 | + parse_uevent_info( |
| 604 | + udev_device_get_sysattr_value(hid_dev, "uevent"), |
| 605 | + &bus_type, |
| 606 | + &dev_vid, |
| 607 | + &dev_pid, |
| 608 | + &serial_number_utf8, |
| 609 | + &product_name_utf8); |
| 610 | + free(serial_number_utf8); |
| 611 | + free(product_name_utf8); |
| 612 | + |
| 613 | + if (bus_type == BUS_BLUETOOTH) { |
| 614 | + /* Right now the Steam Controller is the only BLE device that we send feature reports to */ |
| 615 | + if (dev_vid == 0x28de /* Valve */) { |
| 616 | + ret = 1; |
| 617 | + } |
| 618 | + } |
| 619 | + |
| 620 | + /* hid_dev doesn't need to be (and can't be) unref'd. |
| 621 | + I'm not sure why, but it'll throw double-free() errors. */ |
| 622 | + } |
| 623 | + udev_device_unref(udev_dev); |
| 624 | + } |
| 625 | + |
| 626 | + udev_unref(udev); |
| 627 | + |
| 628 | + return ret; |
| 629 | +} |
| 630 | + |
567 | 631 |
|
568 | 632 | static struct hid_device_info * create_device_info_for_device(struct udev_device *raw_dev)
|
569 | 633 | {
|
@@ -1030,6 +1094,8 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
|
1030 | 1094 | return NULL;
|
1031 | 1095 | }
|
1032 | 1096 |
|
| 1097 | + dev->needs_ble_hack = (is_BLE(dev) == 1); |
| 1098 | + |
1033 | 1099 | return dev;
|
1034 | 1100 | }
|
1035 | 1101 | else {
|
@@ -1143,12 +1209,26 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char
|
1143 | 1209 | int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
|
1144 | 1210 | {
|
1145 | 1211 | int res;
|
| 1212 | + unsigned char report = data[0]; |
1146 | 1213 |
|
1147 | 1214 | register_device_error(dev, NULL);
|
1148 | 1215 |
|
1149 | 1216 | res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
|
1150 | 1217 | if (res < 0)
|
1151 | 1218 | register_device_error_format(dev, "ioctl (GFEATURE): %s", strerror(errno));
|
| 1219 | + else if (dev->needs_ble_hack) { |
| 1220 | + /* Versions of BlueZ before 5.56 don't include the report in the data, |
| 1221 | + * and versions of BlueZ >= 5.56 include 2 copies of the report. |
| 1222 | + * We'll fix it so that there is a single copy of the report in both cases |
| 1223 | + */ |
| 1224 | + if (data[0] == report && data[1] == report) { |
| 1225 | + memmove(&data[0], &data[1], res); |
| 1226 | + } else if (data[0] != report) { |
| 1227 | + memmove(&data[1], &data[0], res); |
| 1228 | + data[0] = report; |
| 1229 | + ++res; |
| 1230 | + } |
| 1231 | + } |
1152 | 1232 |
|
1153 | 1233 | return res;
|
1154 | 1234 | }
|
|
0 commit comments