LibXenon
Bare-metal Xbox 360 homebrew library
Loading...
Searching...
No Matches
usbctrl.c
Go to the documentation of this file.
1/* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * USB Human Interface Driver File: usb.c
5 *
6 * Xbox 360 Controller support
7 *
8 * Author: Felix Domke (based on usbhid.c)
9 *
10 * Multi wirless controller support hacked in by slasher - this is beta status at this point in time
11 *********************************************************************
12 *
13 * Copyright 2000,2001,2002,2003,2005
14 * Broadcom Corporation. All rights reserved.
15 *
16 * This software is furnished under license and may be used and
17 * copied only in accordance with the following terms and
18 * conditions. Subject to these conditions, you may download,
19 * copy, install, use, modify and distribute modified or unmodified
20 * copies of this software in source and/or binary form. No title
21 * or ownership is transferred hereby.
22 *
23 * 1) Any source code used, modified or distributed must reproduce
24 * and retain this copyright notice and list of conditions
25 * as they appear in the source file.
26 *
27 * 2) No right is granted to use any trade name, trademark, or
28 * logo of Broadcom Corporation. The "Broadcom Corporation"
29 * name may not be used to endorse or promote products derived
30 * from this software without the prior written permission of
31 * Broadcom Corporation.
32 *
33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGE.
46 ********************************************************************* */
47
48#include <input/input.h>
49#include "cfe.h"
50#include <xenon_smc/xenon_smc.h>
51
52
53#include "usbchap9.h"
54#include "usbd.h"
55
56/* For systems with non-coherent DMA, allocate all buffers to be
57 cache-aligned and multiples of a cache line in size, so that they
58 can be safely flushed or invalidated. */
59
60#define CACHE_ALIGN 32 /* XXX place holder, big enough to now. */
61#define BUFF_ALIGN 16
62#define ALIGN(n,align) (((n)+((align)-1)) & ~((align)-1))
63
64#define usb_dma_alloc(n) (KMALLOC(ALIGN((n),CACHE_ALIGN),BUFF_ALIGN))
65#define usb_dma_free(p) (KFREE(p))
66
67
68static int usbctrl_attach(usbdev_t *dev,usb_driver_t *drv);
69static int usbctrl_detach(usbdev_t *dev);
70
71#define UBR_KBD_MAX 20
72
73static int controller_mask = 0;
74
76
77typedef struct usbctrl_softc_s {
89
90static usbctrl_softc_t* controllers[4] = {NULL, NULL, NULL, NULL};
91
92static void setcontroller(usbctrl_softc_t* ctrl, int id) //FIXME: Not exactly sure if I like this way of finding a controller from a controller num, possibly rumble should be done through controller data and be updated periodically
93{
94 if(id >= 0 && id < 4)
95 controllers[id] = ctrl;
96}
97static usbctrl_softc_t* getcontroller(int id)
98{
99 if(id >= 0 && id < 4)
100 return controllers[id];
101 return 0;
102}
103
105 "Xbox 360 Controller",
106 usbctrl_attach,
107 usbctrl_detach
108};
109
110static int usbctrl_set_led_callback(usbreq_t *ur) {
111 usb_dma_free(ur->ur_buffer); //Don't leak the buffer
112 //printf("Got callback for set leds\n");
114 return 0;
115}
116
117int usbctrl_set_rol(uint controllerMask)
118{
119 if(!RFdev)
120 return -1;
121 return usb_simple_request(RFdev, 0x40, 0x02, controllerMask, 0x00);
122}
123
125 usbdev_t *dev = softc->dev;
126 usbreq_t *ur;
127
128 //xenon_smc_set_led(1, (unsigned char) (0x80 >> 3)); //We need to figure out how to set ROL and still have the sync button work
129
130 unsigned xdata_len = 0;
131 int command;
132 if(!clear)
133 {
134 command = 2 + (softc->index % 4);
135 }
136 else
137 {
138 command = 0;
139 }
140
141 uint8_t* buf = NULL;
142
143
144 if (softc->is_wireless)
145 {
146 uint8_t xdata[0xC] = { 0x00, 0x00, 0x08, 0x40 + (command % 0x0e), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
147 xdata_len = 0xC;
148
149 buf = usb_dma_alloc(0xC);
150 if (buf == NULL) {
151 printf("couldn't alloc buffer\n");
152 /* Could not allocate a buffer, fail. */
153 return -1;
154 }
155
156 memcpy(buf, &xdata, 0xC);
157
158 }
159 else
160 {
161 uint8_t xdata[3] = { 0x01, 0x03, command };
162 xdata_len = 3;
163
164 buf = usb_dma_alloc(3);
165 if (buf == NULL) {
166 printf("couldn't alloc buffer\n");
167 /* Could not allocate a buffer, fail. */
168 return -1;
169 }
170
171 memcpy(buf, &xdata, 3);
172 }
173
174 ur = usb_make_request(dev, softc->uhid_ipipe_tx, buf, xdata_len, UR_FLAG_OUT);
175 ur->ur_callback = usbctrl_set_led_callback;
177
178 return 0;
179}
180
182 usbdev_t *dev = softc->dev;
183 usbreq_t *ur;
184 unsigned xdata_len = 0;
185
186 uint8_t* buf = NULL;
187
188
189 if (softc->is_wireless)
190 {
191 uint8_t xdata[0xC] = { 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };//Request headset status command, works as a poll
192 xdata_len = 0xC;
193
194 buf = usb_dma_alloc(0xC);
195 if (buf == NULL) {
196 printf("couldn't alloc buffer\n");
197 /* Could not allocate a buffer, fail. */
198 return -1;
199 }
200 memcpy(buf, &xdata, 0xC);
201
202 }
203 else
204 {
205 return -1; //Polling not needed for wired controllers, and if there is a command it is not known at this time
206 }
207
208 ur = usb_make_request(dev, softc->uhid_ipipe_tx, buf, xdata_len, UR_FLAG_OUT);
209 ur->ur_callback = usbctrl_set_led_callback;
211
212 return 0;
213}
214
215int usbctrl_set_rumble(int port, uint8_t l, uint8_t r) {
216 usbctrl_softc_t * softc = getcontroller(port);
217 if(softc == NULL)
218 return -1;
219 usbdev_t *dev = softc->dev;
220 usbreq_t *ur;
221 unsigned xdata_len;
222 uint8_t* buf = NULL;
223
224 if(softc->is_wireless)
225 {
226 buf = usb_dma_alloc(0xC);
227
228 if (buf == NULL) {
229 printf("couldn't alloc buffer\n");
230 /* Could not allocate a buffer, fail. */
231 return -1;
232 }
233
234 uint8_t xdata[0xC] = { 0x00, 0x01, 0x0f, 0xc0, 0x00, l, r, 0x00, 0x00, 0x00, 0x00, 0x00 };
235 xdata_len = 0xC;
236 memcpy(buf, &xdata, 0xC);
237 }
238 else
239 {
240 buf = usb_dma_alloc(0x8);
241
242 if (buf == NULL) {
243 printf("couldn't alloc buffer\n");
244 /* Could not allocate a buffer, fail. */
245 return -1;
246 }
247
248 uint8_t xdata[0x8] = { 0x00, 0x08, 0x00, l, r, 0x00, 0x00, 0x00 };
249 xdata_len = 0x8;
250 memcpy(buf, &xdata, 0x8);
251 }
252
253
254
255 ur = usb_make_request(dev, softc->uhid_ipipe_tx, buf, xdata_len, UR_FLAG_OUT);
256 ur->ur_callback = usbctrl_set_led_callback;
258
259 return 0;
260}
261
262
263
264
265/* *********************************************************************
266 * usbctrl_ireq_callback(ur)
267 *
268 * This routine is called when our interrupt transfer completes
269 * and there is report data to be processed.
270 *
271 * Input parameters:
272 * ur - usb request
273 *
274 * Return value:
275 * 0
276 ********************************************************************* */
277
278
279// from wireless:
280//08 80 82 00 40 01 02 20 00 07 05 82 03 20 00 02 07 05 02 03
281//00 0f 00 f0 f0 cc 56 57 9e c0 53 7f c9 00 00 05 13 e7 20 1d
282//00 00 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
283//00 f8 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
284//00 00 00 13 e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
285//00 00 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
286//00 01 00 f0 00 13 00 00 00 00 4f fc 1e 06 88 07 f6 f7 00 00
287//00 00 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
288//00 01 00 f0 00 13 00 00 00 00 9d fd 1e 06 88 07 f6 f7 00 00
289//00 00 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
290//00 01 00 f0 00 13 00 00 00 00 9d fd ce 04 88 07 f6 f7 00 00
291
292static int usbctrl_ireq_callback(usbreq_t *ur)
293{
294 usbctrl_softc_t *uhid = (ur->ur_ref); //FIXME: are we allowed to use ur_ref for this purpose?
295
296/* int i;
297 for (i = 0; i < uhid->uhid_ipipemps; ++i)
298 printf("%02x ", ur->ur_buffer[i]);
299 printf("\n"); */
300
301 /*
302 * If the driver is unloaded, the request will be cancelled.
303 */
304
305 if (ur->ur_status == 0xFF) {
307 return 0;
308 }
309
310 /*
311 printf("Dump:\n");
312 int i;
313 for (i = 0; i < uhid->uhid_ipipemps; ++i)
314 printf("%02x ", ur->ur_buffer[i]);
315 printf("\n\n\n");
316 */
317
318
319 struct controller_data_s c;
320 unsigned char *b = ur->ur_buffer;
321
322 if (uhid->is_wireless)
323 {
324 //FIXME: A polled, disconnected controller may cause uneeded spam of the controller status message
325 if(uhid->index == -1)
326 {
327 //printf("Wireless controller %i has connected\n", uhid->wireless_index);
328 int i;
329 for (i = 0; controller_mask & (1<<i); ++i);
330 //printf("attached controller %d\n", i);
331 uhid->index = i;
332 setcontroller(uhid, uhid->index);
333 controller_mask |= 1<<i;
334
335 usbctrl_set_leds(uhid, 0);
336 usbctrl_set_rol(controller_mask);
337
338 }
339
340 if (b[0] == 0x8 && b[1] == 0x0)
341 {
342 //printf("Wireless controller %i has disconnected\n", uhid->wireless_index);
343 printf("detached controller %d\n", uhid->index);
344 setcontroller(NULL, uhid->index);
345 controller_mask &= ~(1<<uhid->index);
346
347 usbctrl_set_rol(controller_mask);
348
349 uhid->index = -1;
350 goto ignore;
351
352 }
353
354
355
356
357 if (b[5] == 0x13)
358 {
359#if 0
360 if (b[6] == 2) /* CHECKME: is this required for the Xbox racing wheel? */
361 b++;
362#endif
363 b += 4;
364
365 } else
366 goto ignore;
367 }
368
369 c.s1_x = (b[7] << 8) | b[6];
370 c.s1_y = (b[9] << 8) | b[8];
371 c.s2_x = (b[11] << 8) | b[10];
372 c.s2_y = (b[13] << 8) | b[12];
373 c.s1_z = !!(b[2] & 0x40);
374 c.s2_z = !!(b[2] & 0x80);
375 c.lt = b[4];
376 c.rt = b[5];
377 c.lb = !!(b[3] & 1);
378 c.rb = !!(b[3] & 2);
379
380 c.a = !!(b[3] & 0x10);
381 c.b = !!(b[3] & 0x20);
382 c.x = !!(b[3] & 0x40);
383 c.y = !!(b[3] & 0x80);
384
385 c.start = !!(b[2] & 0x10);
386 c.back = !!(b[2] & 0x20);
387
388 c.up = !!(b[2] & 1);
389 c.down = !!(b[2] & 2);
390 c.left = !!(b[2] & 4);
391 c.right = !!(b[2] & 8);
392
393 c.logo = !!(b[3] & 0x4);
394
395 set_controller_data(uhid->index, &c);
396
397ignore:
399
400 return 0;
401}
402
403
404/* *********************************************************************
405 * usbctrl_queue_intreq(dev,softc)
406 *
407 * Queue an interrupt request for this usb device. The
408 * driver will place this request on the queue that corresponds
409 * to the endpoint, and will call the callback routine when
410 * something happens.
411 *
412 * Input parameters:
413 * dev - usb device
414 * softc - the usb hid softc
415 *
416 * Return value:
417 * nothing
418 ********************************************************************* */
419
420static void usbctrl_queue_intreq(usbdev_t *dev,usbctrl_softc_t *softc)
421{
422 usbreq_t *ur;
423
424 ur = usb_make_request(dev,
425 softc->uhid_ipipe,
426 softc->uhid_imsg, softc->uhid_ipipemps,
427 UR_FLAG_IN);
428
429 ur->ur_callback = usbctrl_ireq_callback;
430
431 ur->ur_ref = softc; //FIXME: Part of the hackish multi-wireless support
432
434}
435
436
437/* *********************************************************************
438 * usbctrl_attach(dev,drv)
439 *
440 * This routine is called when the bus scan stuff finds a HID
441 * device. We finish up the initialization by configuring the
442 * device and allocating our softc here.
443 *
444 * Input parameters:
445 * dev - usb device, in the "addressed" state.
446 * drv - the driver table entry that matched
447 *
448 * Return value:
449 * 0
450 ********************************************************************* */
451
452static int usbctrl_attach(usbdev_t *dev,usb_driver_t *drv)
453{
454 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
455 //printf("Number of interfaces: %i\n", cfgdscr->bNumInterfaces);
456
457
458
459 dev->ud_drv = drv;
460
461 usbctrl_softc_t *softc;
462
463
464
465
466
467 //printf("Number of endpoints: %i\n", ifdscr->bNumEndpoints);
468
469 usb_endpoint_descr_t *epdscr;
470 usb_interface_descr_t *ifdscr;
471
472 int wireless = (GETUSBFIELD(&dev->ud_devdescr, idProduct) == 0x291) ||
473 (GETUSBFIELD(&dev->ud_devdescr, idProduct) == 0x2aa) ||
474 (GETUSBFIELD(&dev->ud_devdescr, idProduct) == 0x2a9);
475
476 if(wireless)
477 {
478
479 dev->ud_private = NULL;
480 RFdev = dev;
481
482 int i;
483 for(i = 0; i < 4; i++)
484 {
485 softc = KMALLOC(sizeof(usbctrl_softc_t),0);
486 softc->dev = dev;
487 softc->is_wireless = (wireless);
490
491 if (!epdscr || !ifdscr) {
492 printf("couldn't find descriptor for controller %i!\n", i);
493 return 0;
494 }
495
496
497 //printf("Initializing wireless controller %d\n", i);
498 softc->index = -1;
499 softc->wireless_index = i;
500 //controller_mask |= 1<<i; //Dont set this right now, let wired controllers use the slots
501
502 /*
503 * Allocate a DMA buffer
504 */
505
507 if (softc->uhid_imsg == NULL) {
508 printf("couldn't alloc buffer\n");
509 /* Could not allocate a buffer, fail. */
510 return -1;
511 }
512
513 /*
514 * Choose the standard configuration.
515 */
516
518
519 /*
520 * Open the interrupt pipe.
521 */
522
523 softc->uhid_ipipe = usb_open_pipe(dev,epdscr);
524
526 //if (USB_ENDPOINT_DIR_OUT(txdscr->bEndpointAddress))
527 // printf("Opened an outgoing endpoint\n");
528
529 softc->uhid_ipipe_tx = usb_open_pipe(dev, txdscr);
530
531
532
533 softc->uhid_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize);
534 softc->uhid_ipipemps_tx = GETUSBFIELD(epdscr,wMaxPacketSize);
535
536 usbctrl_set_leds(softc, 1); //Clear leds, FIXME: Implement controller shutdown somewhere
537 usbctrl_poll(softc);
538
539 /*
540 * Queue a transfer on the interrupt endpoint to catch
541 * our first characters.
542 */
543
544 usbctrl_queue_intreq(dev,softc);
545
546
547
548 }
549
550 //Make sure we set the lights for any previously detected wired controllers
551 usbctrl_set_rol(controller_mask);
552
553 }
554 else
555 {
556
557 softc = KMALLOC(sizeof(usbctrl_softc_t),0);
558 memset(softc,0,sizeof(usbctrl_softc_t));
559 softc->dev = dev;
560 dev->ud_private = softc;
561
562 softc->is_wireless = (wireless);
563
566
568
569
570 //if (USB_ENDPOINT_DIR_OUT(txdscr->bEndpointAddress))
571 // printf("Opened an outgoing endpoint\n");
572
573 softc->uhid_ipipe_tx = usb_open_pipe(dev, txdscr);
574
575 if (!epdscr || !ifdscr) {
576 printf("couldn't find descriptor!\n");
577 return 0;
578 }
579
580
581
582 int i;
583 for (i = 0; controller_mask & (1<<i); ++i);
584 printf("attached controller %d\n", i);
585 softc->index = i;
586 setcontroller(softc, i);
587 controller_mask |= 1<<i;
588
589 usbctrl_set_rol(controller_mask);
590
591 /*
592 * Allocate a DMA buffer
593 */
594
596 if (softc->uhid_imsg == NULL) {
597 printf("couldn't alloc buffer\n");
598 /* Could not allocate a buffer, fail. */
599 return -1;
600 }
601
602 /*
603 * Choose the standard configuration.
604 */
605
607
608 /*
609 * Open the interrupt pipe.
610 */
611
612 softc->uhid_ipipe = usb_open_pipe(dev,epdscr);
613 softc->uhid_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize);
614
615 /*
616 * Queue a transfer on the interrupt endpoint to catch
617 * our first characters.
618 */
619 usbctrl_set_leds(softc, 0);
620 usbctrl_queue_intreq(dev,softc);
621
622
623 }
624
625 return 0;
626
627
628}
629
630/* *********************************************************************
631 * usbctrl_detach(dev)
632 *
633 * This routine is called when the bus scanner notices that
634 * this device has been removed from the system. We should
635 * do any cleanup that is required. The pending requests
636 * will be cancelled automagically.
637 *
638 * Input parameters:
639 * dev - usb device
640 *
641 * Return value:
642 * 0
643 ********************************************************************* */
644
645static int usbctrl_detach(usbdev_t *dev)
646{
647 if(dev->ud_private)
648 {
649
650 usbctrl_softc_t *uhid = dev->ud_private;
651
652 printf("detached controller %d\n", uhid->index);
653 setcontroller(NULL, uhid->index);
654 controller_mask &= ~(1<<uhid->index);
655
656 usbctrl_set_rol(controller_mask);
657
658 return 0;
659
660 }
661 else
662 {
663 printf("Wirless module detatched, not yet handled\n");
664
665
666 return 0;
667
668 }
669
670}
671
#define NULL
Definition: def.h:47
u32 command
Definition: ehci_defs.h:2
void set_controller_data(int port, const struct controller_data_s *d)
Definition: input.c:16
#define KMALLOC(size, align)
Definition: lib_malloc.h:92
u32 uint32_t
Definition: libfdt_env.h:11
u8 uint8_t
Definition: libfdt_env.h:9
uint8_t bConfigurationValue
Definition: usbchap9.h:216
uint8_t * uhid_imsg
Definition: usbctrl.c:84
int uhid_ipipemps_tx
Definition: usbctrl.c:81
int wireless_index
Definition: usbctrl.c:83
int uhid_ipipe_tx
Definition: usbctrl.c:79
uint32_t uhid_shiftflags
Definition: usbctrl.c:86
int uhid_ipipe
Definition: usbctrl.c:78
usbdev_t * dev
Definition: usbctrl.c:87
int is_wireless
Definition: usbctrl.c:83
int uhid_ipipemps
Definition: usbctrl.c:80
int uhid_devtype
Definition: usbctrl.c:82
uint8_t uhid_lastmsg[UBR_KBD_MAX]
Definition: usbctrl.c:85
Definition: usbd.h:141
usb_config_descr_t * ud_cfgdescr
Definition: usbd.h:150
void * ud_private
Definition: usbd.h:148
usb_device_descr_t ud_devdescr
Definition: usbd.h:149
usb_driver_t * ud_drv
Definition: usbd.h:142
Definition: usbd.h:171
int(* ur_callback)(struct usbreq_s *req)
Definition: usbd.h:196
int ur_status
Definition: usbd.h:188
uint8_t * ur_buffer
Definition: usbd.h:185
void * ur_ref
Definition: usbd.h:194
#define GETUSBFIELD(s, f)
Definition: usbchap9.h:347
#define USB_ENDPOINT_DESCRIPTOR_TYPE
Definition: usbchap9.h:66
#define USB_INTERFACE_DESCRIPTOR_TYPE
Definition: usbchap9.h:65
int usbctrl_set_rol(uint controllerMask)
Definition: usbctrl.c:117
int usbctrl_poll(usbctrl_softc_t *softc)
Definition: usbctrl.c:181
struct usbctrl_softc_s usbctrl_softc_t
int usbctrl_set_leds(usbctrl_softc_t *softc, uint8_t clear)
Definition: usbctrl.c:124
#define usb_dma_free(p)
Definition: usbctrl.c:65
#define usb_dma_alloc(n)
Definition: usbctrl.c:64
#define UBR_KBD_MAX
Definition: usbctrl.c:71
int usbctrl_set_rumble(int port, uint8_t l, uint8_t r)
Definition: usbctrl.c:215
usb_driver_t usbctrl_driver
Definition: usbctrl.c:104
usbdev_t * RFdev
Definition: usbctrl.c:75
void * usb_find_cfg_descr(usbdev_t *dev, int dtype, int idx)
Definition: usbd.c:1237
int usb_simple_request(usbdev_t *dev, uint8_t reqtype, int bRequest, int wValue, int wIndex)
Definition: usbd.c:600
usbreq_t * usb_make_request(usbdev_t *dev, int epaddr, uint8_t *buf, int length, int flags)
Definition: usbd.c:353
void usb_free_request(usbreq_t *ur)
Definition: usbd.c:457
int usb_queue_request(usbreq_t *ur)
Definition: usbd.c:502
int usb_set_configuration(usbdev_t *dev, int config)
Definition: usbd.c:619
int usb_open_pipe(usbdev_t *dev, usb_endpoint_descr_t *epdesc)
Definition: usbd.c:165
#define UR_FLAG_OUT
Definition: usbd.h:165
#define UR_FLAG_IN
Definition: usbd.h:164
u8 c
Definition: xenos_edid.h:7