IOKit: не получают отчеты о прерываниях HID от контроллера DualShock 4, подключенного через Bluetooth

Введение

Я работаю над получением полной поддержки PlayStation 4 Controller с использованием интерфейса HID в IOKit. Контроллер подключен через Bluetooth. Я могу открыть соединение с контроллером и начать получать отчеты, однако, как только я отправлю ему отчет, он внезапно остановится.

Чтобы получить полный контроль над контроллером PS4 (вибрация, трекпад, светодиоды), я ссылался на страница eleccelerator.com DualShock 4, содержащая информацию об отчетах, которые могут/отправляются между PS4 и DS4.

Код

Сначала я создаю IOHIDManager, который отвечает за обнаружение контроллеров.

self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
// Make sure we detect ANY type of 'game controller'
NSArray *criteria = [NSArray arrayWithObjects:
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick),
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad),
        CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController),
    nil];

IOHIDManagerSetDeviceMatchingMultiple(self.hidManager, (__bridge CFArrayRef)criteria);

IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(self.hidManager, kIOHIDOptionsTypeNone);

// Register callbacks
IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, ControllerConnected, (__bridge void *)self);
IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, ControllerDisconnected, (__bridge void *)self);

Затем, получив вызов ControllerConnected, я создаю экземпляр класса джойстика, который инициализирует класс IOHIDDeviceRef.

- (void)registerDevice:(IOHIDDeviceRef)device {
    self.device = device;

    // Initialize the buffer
    self.receivedPacketMaxSize = 552; // When using Bluetooth
    self.receivedReport = (uint8_t *)calloc(self.receivedPacketMaxSize, sizeof(uint8_t));

    // Register the device report callback
    IOHIDDeviceScheduleWithRunLoop(self.device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    IOHIDDeviceRegisterInputReportCallback(self.device, self.receivedReport, self.receivedPacketMaxSize, ControllerReport, (__bridge void *)self);

    self.isValid = YES;
}

Теперь я ДЕЙСТВИТЕЛЬНО получаю звонки на ControllerReport, однако отчеты, которые я получаю, имеют тип 0x01, которые ограничены в том, что они содержат (у них нет данных трекпада или акселерометра), но я хочу получать пакеты типа 0x11, которые содержат все данные с контроллера.

Чтобы переключить, какой пакет отправляет контроллер, на веб-сайте указано This report is sent once the GET REPORT FEATURE 0x02 is received. Поэтому я отправляю этот запрос:

CFIndex len = self.receivedPacketMaxSize;
IOReturn featureMode2RequestError = IOHIDDeviceGetReport(self.device, kIOHIDReportTypeFeature, 0x02, self.receivedReport, &len);
if (featureMode2RequestError != kIOReturnSuccess) {
    NSLog(@"Could switch the controller to mode 2 :(");
}

В этот момент ControllerReport перестает вызываться с новыми отчетами от контроллера.

Я знаю, что могу отправить данные на контроллер, потому что я могу отправить пакет, который меняет цвет светодиода или устанавливает скорость вибрации.

Вопрос

Как я могу получить более длинные отчеты 0x11 от контроллера PS4?

Что я пробовал

Я пытался использовать IOHIDDeviceGetReportWithCallback и IOHIDDeviceGetReport, но всегда возвращал kIOReturnUnsupported.

Я также нашел ссылку на эту проблему в исходниках драйвера linux для контроллера в виде ... it starts sending input reports in report 17. Since report 17 is undefined ..., однако я не знаю, как указать IOKit обрабатывать отчет 17 (0x11).


person David Skrundz    schedule 12.06.2015    source источник
comment
Я не могу сказать вам, почему вы видите эту конкретную проблему и как ее исправить, но если бы я ее отлаживал, я бы проверил Семейство IOKit HID и IOKit userlib HID и проследите путь отчетов устройства. Как только вы нашли место, где их игнорируют, это не должно быть слишком сложно обойти.   -  person pmdj    schedule 18.06.2015
comment
У меня сейчас еще есть решение. Поскольку кажется, что это вызвано ошибкой в ​​​​фреймворке, я попробую еще раз осенью, когда будет выпущена macOS. Однако я сомневаюсь, что у меня будут ресурсы, чтобы найти и исправить проблему, если она все еще существует.   -  person David Skrundz    schedule 27.06.2016


Ответы (1)


Проблема в том, что IOHIDDeviceGetReport kIOHIDReportTypeOutput отправляет выходные отчеты через конечную точку прерывания; DS4 ожидает его через конечную точку управления. Насколько я знаю, в OS X нет способа сделать вывод GetReport через конечную точку ctrl (если не считать написания kext для его переопределения).

person geowar    schedule 23.10.2015