IOReturn XboxOriginalControllerClass::setReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options) { char data[2]; report->readBytes(0, data, 2); if (GetOwner(this)->rumbleType == 1) // Don't Rumble return kIOReturnSuccess; switch(data[0]) { case 0x00: // Set force feedback if((data[1]!=report->getLength()) || (data[1]!=0x04)) return kIOReturnUnsupported; { XBOX_OUT_RUMBLE rumble; Xbox360_Prepare(rumble,outRumble); report->readBytes(2,data,2); rumble.left=data[0]; // CHECKME != big, little rumble.right=data[1]; GetOwner(this)->QueueWrite(&rumble,sizeof(rumble)); // IOLog("Set rumble: big(%d) little(%d)\n", rumble.big, rumble.little); } return kIOReturnSuccess; case 0x01: // Set LEDs if((data[1]!=report->getLength())||(data[1]!=0x03)) return kIOReturnUnsupported; // No leds return kIOReturnSuccess; default: IOLog("Unknown escape %d\n", data[0]); return kIOReturnUnsupported; } }
// Handles a message from the userspace IOHIDDeviceInterface122::setReport function IOReturn Xbox360ControllerClass::setReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options) { char data[2]; report->readBytes(0, data, 2); switch(data[0]) { case 0x00: // Set force feedback if((data[1]!=report->getLength()) || (data[1]!=0x04)) return kIOReturnUnsupported; { XBOX360_OUT_RUMBLE rumble; Xbox360_Prepare(rumble,outRumble); report->readBytes(2,data,2); rumble.big=data[0]; rumble.little=data[1]; GetOwner(this)->QueueWrite(&rumble,sizeof(rumble)); // IOLog("Set rumble: big(%d) little(%d)\n", rumble.big, rumble.little); } return kIOReturnSuccess; case 0x01: // Set LEDs if((data[1]!=report->getLength())||(data[1]!=0x03)) return kIOReturnUnsupported; { XBOX360_OUT_LED led; report->readBytes(2,data,1); Xbox360_Prepare(led,outLed); led.pattern=data[0]; GetOwner(this)->QueueWrite(&led,sizeof(led)); // IOLog("Set LED: %d\n", led.pattern); } return kIOReturnSuccess; default: IOLog("Unknown escape %d\n", data[0]); return kIOReturnUnsupported; } }
// This converts XBox original controller report into XBox360 form // See https://github.com/Grumbel/xboxdrv/blob/master/src/controller/xbox_controller.cpp static void convertFromXBoxOriginal(UInt8 *data) { if (data[0] != 0x00 || data[1] != 0x14) { IOLog("Unknown report command %d, length %d\n", (int)data[0], (int)data[1]); return; } XBOX360_IN_REPORT report; Xbox360_Prepare (report, 0); XBOX_IN_REPORT *in = (XBOX_IN_REPORT*)data; XBox360_Short buttons = in->buttons; if (in->a) buttons |= 1 << 12; // a if (in->b) buttons |= 1 << 13; // b if (in->x) buttons |= 1 << 14; // x if (in->y) buttons |= 1 << 15; // y if (in->black) buttons |= 1 << 9; // black mapped to shoulder right if (in->white) buttons |= 1 << 8; // white mapped to shoulder left report.buttons = buttons; report.trigL = in->trigL; report.trigR = in->trigR; report.left.x = in->xL; report.left.y = in->yL; report.right.x = in->xR; report.right.y = in->yR; *((XBOX360_IN_REPORT *)data) = report; }
bool Xbox360Peripheral::start(IOService *provider) { const IOUSBConfigurationDescriptor *cd; IOUSBFindInterfaceRequest intf; IOUSBFindEndpointRequest pipe; XBOX360_OUT_LED led; IOWorkLoop *workloop = NULL; /* * Xbox One controller init packets. * The Rock Candy Xbox One controller requires more than just 0x05 * Minimum required packets unknown. */ UInt8 xoneInitFirst[] = { 0x02, 0x20, 0x01, 0x1C, 0x7E, 0xED, 0x8B, 0x11, 0x0F, 0xA8, 0x00, 0x00, 0x5E, 0x04, 0xD1, 0x02, 0x01, 0x00, 0x01, 0x00, 0x17, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 }; UInt8 xoneInitSecond[] = { 0x05, 0x20, 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x53 }; UInt8 xoneInitThird[] = { 0x05, 0x20, 0x01, 0x01, 0x00 }; UInt8 xoneInitFourth[] = { 0x0A, 0x20, 0x02, 0x03, 0x00, 0x01, 0x14 }; if (!super::start(provider)) return false; // Get device device=OSDynamicCast(IOUSBDevice,provider); if(device==NULL) { IOLog("start - invalid provider\n"); goto fail; } // Check for configurations if(device->GetNumConfigurations()<1) { device=NULL; IOLog("start - device has no configurations!\n"); goto fail; } // Set configuration cd=device->GetFullConfigurationDescriptor(0); if(cd==NULL) { device=NULL; IOLog("start - couldn't get configuration descriptor\n"); goto fail; } // Open if(!device->open(this)) { device=NULL; IOLog("start - unable to open device\n"); goto fail; } if(device->SetConfiguration(this,cd->bConfigurationValue,true)!=kIOReturnSuccess) { IOLog("start - unable to set configuration\n"); goto fail; } // Get release { UInt16 release = device->GetDeviceRelease(); switch (release) { default: IOLog("Unknown device release %.4x\n", release); // fall through case 0x0110: chatpadInit[0] = 0x01; chatpadInit[1] = 0x02; break; case 0x0114: chatpadInit[0] = 0x09; chatpadInit[1] = 0x00; break; } } // Find correct interface controllerType = Xbox360; intf.bInterfaceClass=kIOUSBFindInterfaceDontCare; intf.bInterfaceSubClass=93; intf.bInterfaceProtocol=1; intf.bAlternateSetting=kIOUSBFindInterfaceDontCare; interface=device->FindNextInterface(NULL,&intf); if(interface==NULL) { // Find correct interface, Xbox original intf.bInterfaceClass=kIOUSBFindInterfaceDontCare; intf.bInterfaceSubClass=66; intf.bInterfaceProtocol=0; intf.bAlternateSetting=kIOUSBFindInterfaceDontCare; interface=device->FindNextInterface(NULL,&intf); if(interface==NULL) { // Find correct interface, Xbox One intf.bInterfaceClass=255; intf.bInterfaceSubClass=71; intf.bInterfaceProtocol=208; intf.bAlternateSetting=kIOUSBFindInterfaceDontCare; interface=device->FindNextInterface(NULL, &intf); if(interface==NULL) { IOLog("start - unable to find the interface\n"); goto fail; } controllerType = XboxOne; goto interfacefound; } controllerType = XboxOriginal; goto interfacefound; } interfacefound: interface->open(this); // Find pipes pipe.direction=kUSBIn; pipe.interval=0; pipe.type=kUSBInterrupt; pipe.maxPacketSize=0; inPipe=interface->FindNextPipe(NULL,&pipe); if(inPipe==NULL) { IOLog("start - unable to find in pipe\n"); goto fail; } inPipe->retain(); pipe.direction=kUSBOut; outPipe=interface->FindNextPipe(NULL,&pipe); if(outPipe==NULL) { IOLog("start - unable to find out pipe\n"); goto fail; } outPipe->retain(); // Get a buffer inBuffer=IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,GetMaxPacketSize(inPipe)); if(inBuffer==NULL) { IOLog("start - failed to allocate input buffer\n"); goto fail; } // Find chatpad interface intf.bInterfaceClass = kIOUSBFindInterfaceDontCare; intf.bInterfaceSubClass = 93; intf.bInterfaceProtocol = 2; intf.bAlternateSetting = kIOUSBFindInterfaceDontCare; serialIn = device->FindNextInterface(NULL, &intf); if (serialIn == NULL) { IOLog("start - unable to find chatpad interface\n"); goto nochat; } serialIn->open(this); // Find chatpad pipe pipe.direction = kUSBIn; pipe.interval = 0; pipe.type = kUSBInterrupt; pipe.maxPacketSize = 0; serialInPipe = serialIn->FindNextPipe(NULL, &pipe); if (serialInPipe == NULL) { IOLog("start - unable to find chatpad in pipe\n"); goto fail; } serialInPipe->retain(); // Get a buffer for the chatpad serialInBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, GetMaxPacketSize(serialInPipe)); if (serialInBuffer == NULL) { IOLog("start - failed to allocate input buffer for chatpad\n"); goto fail; } // Create timer for chatpad serialTimer = IOTimerEventSource::timerEventSource(this, ChatPadTimerActionWrapper); if (serialTimer == NULL) { IOLog("start - failed to create timer for chatpad\n"); goto fail; } workloop = getWorkLoop(); if ((workloop == NULL) || (workloop->addEventSource(serialTimer) != kIOReturnSuccess)) { IOLog("start - failed to connect timer for chatpad\n"); goto fail; } // Configure ChatPad // Send 'configuration' SendInit(0xa30c, 0x4423); SendInit(0x2344, 0x7f03); SendInit(0x5839, 0x6832); // Set 'switch' if ((!SendSwitch(false)) || (!SendSwitch(true)) || (!SendSwitch(false))) { // Commenting goto fail fixes the driver for the Hori Real Arcade Pro EX //goto fail; } // Begin toggle serialHeard = false; serialActive = false; serialToggle = false; serialResetCount = 0; serialTimerState = tsToggle; serialTimer->setTimeoutMS(1000); // Begin reading if (!QueueSerialRead()) goto fail; nochat: if (!QueueRead()) goto fail; if (controllerType == XboxOne) { QueueWrite(&xoneInitFirst, sizeof(xoneInitFirst)); QueueWrite(&xoneInitSecond, sizeof(xoneInitSecond)); QueueWrite(&xoneInitThird, sizeof(xoneInitThird)); QueueWrite(&xoneInitFourth, sizeof(xoneInitFourth)); } else { // Disable LED Xbox360_Prepare(led,outLed); led.pattern=ledOff; QueueWrite(&led,sizeof(led)); } // Done PadConnect(); registerService(); return true; fail: ReleaseAll(); return false; }