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).
1 ответ
Проблема в том, что IOHIDDeviceGetReport kIOHIDReportTypeOutput отправляет выходные отчеты через конечную точку прерывания; DS4 ожидает этого через контрольную точку управления. AFAIK, на OS X нет никакого способа сделать вывод GetReport через конечную точку ctrl (если не считать написания kext для его переопределения).