]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/USB_Host_Shield_2.0/XBOXUSB.cpp
ps2_usb: Fix for VUSB configuration
[tmk_keyboard.git] / tmk_core / protocol / usb_hid / USB_Host_Shield_2.0 / XBOXUSB.cpp
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
8 the GPL2 ("Copyleft").
9
10 Contact information
11 -------------------
12
13 Kristian Lauszus, TKJ Electronics
14 Web : http://www.tkjelectronics.com
15 e-mail : kristianl@tkjelectronics.com
16 */
17
18 #include "XBOXUSB.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
22
23 XBOXUSB::XBOXUSB(USB *p) :
24 pUsb(p), // pointer to USB class instance - mandatory
25 bAddress(0), // device address - mandatory
26 bPollEnable(false) { // don't start polling before dongle is connected
27 for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
28 epInfo[i].epAddr = 0;
29 epInfo[i].maxPktSize = (i) ? 0 : 8;
30 epInfo[i].epAttribs = 0;
31 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
32 }
33
34 if(pUsb) // register in USB subsystem
35 pUsb->RegisterDeviceClass(this); //set devConfig[] entry
36 }
37
38 uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
39 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
40 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
41 uint8_t rcode;
42 UsbDevice *p = NULL;
43 EpInfo *oldep_ptr = NULL;
44 uint16_t PID;
45 uint16_t VID;
46
47 // get memory address of USB device address pool
48 AddressPool &addrPool = pUsb->GetAddressPool();
49 #ifdef EXTRADEBUG
50 Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
51 #endif
52 // check if address has already been assigned to an instance
53 if(bAddress) {
54 #ifdef DEBUG_USB_HOST
55 Notify(PSTR("\r\nAddress in use"), 0x80);
56 #endif
57 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
58 }
59
60 // Get pointer to pseudo device with address 0 assigned
61 p = addrPool.GetUsbDevicePtr(0);
62
63 if(!p) {
64 #ifdef DEBUG_USB_HOST
65 Notify(PSTR("\r\nAddress not found"), 0x80);
66 #endif
67 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
68 }
69
70 if(!p->epinfo) {
71 #ifdef DEBUG_USB_HOST
72 Notify(PSTR("\r\nepinfo is null"), 0x80);
73 #endif
74 return USB_ERROR_EPINFO_IS_NULL;
75 }
76
77 // Save old pointer to EP_RECORD of address 0
78 oldep_ptr = p->epinfo;
79
80 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
81 p->epinfo = epInfo;
82
83 p->lowspeed = lowspeed;
84
85 // Get device descriptor
86 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
87 // Restore p->epinfo
88 p->epinfo = oldep_ptr;
89
90 if(rcode)
91 goto FailGetDevDescr;
92
93 VID = udd->idVendor;
94 PID = udd->idProduct;
95
96 if(VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID && VID != GAMESTOP_VID) // Check VID
97 goto FailUnknownDevice;
98 if(PID == XBOX_WIRELESS_PID) {
99 #ifdef DEBUG_USB_HOST
100 Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80);
101 #endif
102 goto FailUnknownDevice;
103 } else if(PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
104 #ifdef DEBUG_USB_HOST
105 Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
106 #endif
107 goto FailUnknownDevice;
108 } else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID && PID != AFTERGLOW_WIRED_PID && PID != JOYTECH_WIRED_PID) // Check PID
109 goto FailUnknownDevice;
110
111 // Allocate new address according to device class
112 bAddress = addrPool.AllocAddress(parent, false, port);
113
114 if(!bAddress)
115 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
116
117 // Extract Max Packet Size from device descriptor
118 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
119
120 // Assign new address to the device
121 rcode = pUsb->setAddr(0, 0, bAddress);
122 if(rcode) {
123 p->lowspeed = false;
124 addrPool.FreeAddress(bAddress);
125 bAddress = 0;
126 #ifdef DEBUG_USB_HOST
127 Notify(PSTR("\r\nsetAddr: "), 0x80);
128 D_PrintHex<uint8_t > (rcode, 0x80);
129 #endif
130 return rcode;
131 }
132 #ifdef EXTRADEBUG
133 Notify(PSTR("\r\nAddr: "), 0x80);
134 D_PrintHex<uint8_t > (bAddress, 0x80);
135 #endif
136 //delay(300); // Spec says you should wait at least 200ms
137
138 p->lowspeed = false;
139
140 //get pointer to assigned address record
141 p = addrPool.GetUsbDevicePtr(bAddress);
142 if(!p)
143 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
144
145 p->lowspeed = lowspeed;
146
147 // Assign epInfo to epinfo pointer - only EP0 is known
148 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
149 if(rcode)
150 goto FailSetDevTblEntry;
151
152 /* The application will work in reduced host mode, so we can save program and data
153 memory space. After verifying the VID we will use known values for the
154 configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */
155
156 /* Initialize data structures for endpoints of device */
157 epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint
158 epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
159 epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
160 epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
161 epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0;
162 epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0;
163 epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint
164 epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
165 epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
166 epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
167 epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0;
168 epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0;
169
170 rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
171 if(rcode)
172 goto FailSetDevTblEntry;
173
174 delay(200); // Give time for address change
175
176 rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
177 if(rcode)
178 goto FailSetConfDescr;
179
180 #ifdef DEBUG_USB_HOST
181 Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80);
182 #endif
183 onInit();
184 Xbox360Connected = true;
185 bPollEnable = true;
186 return 0; // Successful configuration
187
188 /* Diagnostic messages */
189 FailGetDevDescr:
190 #ifdef DEBUG_USB_HOST
191 NotifyFailGetDevDescr();
192 goto Fail;
193 #endif
194
195 FailSetDevTblEntry:
196 #ifdef DEBUG_USB_HOST
197 NotifyFailSetDevTblEntry();
198 goto Fail;
199 #endif
200
201 FailSetConfDescr:
202 #ifdef DEBUG_USB_HOST
203 NotifyFailSetConfDescr();
204 #endif
205 goto Fail;
206
207 FailUnknownDevice:
208 #ifdef DEBUG_USB_HOST
209 NotifyFailUnknownDevice(VID, PID);
210 #endif
211 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
212
213 Fail:
214 #ifdef DEBUG_USB_HOST
215 Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
216 NotifyFail(rcode);
217 #endif
218 Release();
219 return rcode;
220 }
221
222 /* Performs a cleanup after failed Init() attempt */
223 uint8_t XBOXUSB::Release() {
224 Xbox360Connected = false;
225 pUsb->GetAddressPool().FreeAddress(bAddress);
226 bAddress = 0;
227 bPollEnable = false;
228 return 0;
229 }
230
231 uint8_t XBOXUSB::Poll() {
232 if(!bPollEnable)
233 return 0;
234 uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
235 pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
236 readReport();
237 #ifdef PRINTREPORT
238 printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
239 #endif
240 return 0;
241 }
242
243 void XBOXUSB::readReport() {
244 if(readBuf == NULL)
245 return;
246 if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports
247 return;
248 }
249
250 ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24));
251
252 hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
253 hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
254 hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
255 hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
256
257 //Notify(PSTR("\r\nButtonState"), 0x80);
258 //PrintHex<uint32_t>(ButtonState, 0x80);
259
260 if(ButtonState != OldButtonState) {
261 ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
262 if(((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons
263 R2Clicked = true;
264 if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
265 L2Clicked = true;
266 OldButtonState = ButtonState;
267 }
268 }
269
270 void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
271 #ifdef PRINTREPORT
272 if(readBuf == NULL)
273 return;
274 for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
275 D_PrintHex<uint8_t > (readBuf[i], 0x80);
276 Notify(PSTR(" "), 0x80);
277 }
278 Notify(PSTR("\r\n"), 0x80);
279 #endif
280 }
281
282 uint8_t XBOXUSB::getButtonPress(ButtonEnum b) {
283 if(b == L2) // These are analog buttons
284 return (uint8_t)(ButtonState >> 8);
285 else if(b == R2)
286 return (uint8_t)ButtonState;
287 return (bool)(ButtonState & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16));
288 }
289
290 bool XBOXUSB::getButtonClick(ButtonEnum b) {
291 if(b == L2) {
292 if(L2Clicked) {
293 L2Clicked = false;
294 return true;
295 }
296 return false;
297 } else if(b == R2) {
298 if(R2Clicked) {
299 R2Clicked = false;
300 return true;
301 }
302 return false;
303 }
304 uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
305 bool click = (ButtonClickState & button);
306 ButtonClickState &= ~button; // clear "click" event
307 return click;
308 }
309
310 int16_t XBOXUSB::getAnalogHat(AnalogHatEnum a) {
311 return hatValue[a];
312 }
313
314 /* Xbox Controller commands */
315 void XBOXUSB::XboxCommand(uint8_t* data, uint16_t nbytes) {
316 //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
317 pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
318 }
319
320 void XBOXUSB::setLedRaw(uint8_t value) {
321 writeBuf[0] = 0x01;
322 writeBuf[1] = 0x03;
323 writeBuf[2] = value;
324
325 XboxCommand(writeBuf, 3);
326 }
327
328 void XBOXUSB::setLedOn(LEDEnum led) {
329 if(led == OFF)
330 setLedRaw(0);
331 else if(led != ALL) // All LEDs can't be on a the same time
332 setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4);
333 }
334
335 void XBOXUSB::setLedBlink(LEDEnum led) {
336 setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]));
337 }
338
339 void XBOXUSB::setLedMode(LEDModeEnum ledMode) { // This function is used to do some special LED stuff the controller supports
340 setLedRaw((uint8_t)ledMode);
341 }
342
343 void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
344 writeBuf[0] = 0x00;
345 writeBuf[1] = 0x08;
346 writeBuf[2] = 0x00;
347 writeBuf[3] = lValue; // big weight
348 writeBuf[4] = rValue; // small weight
349 writeBuf[5] = 0x00;
350 writeBuf[6] = 0x00;
351 writeBuf[7] = 0x00;
352
353 XboxCommand(writeBuf, 8);
354 }
355
356 void XBOXUSB::onInit() {
357 if(pFuncOnInit)
358 pFuncOnInit(); // Call the user function
359 else
360 setLedOn(LED1);
361 }
Imprint / Impressum