Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBHostXpad by
USBHostXpad.cpp@0:bd0f6bf72a8b, 2013-12-10 (annotated)
- Committer:
- okini3939
- Date:
- Tue Dec 10 06:50:37 2013 +0000
- Revision:
- 0:bd0f6bf72a8b
- Child:
- 1:5bb153989f33
1st build;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:bd0f6bf72a8b | 1 | /* |
okini3939 | 0:bd0f6bf72a8b | 2 | * Xbox 360 Wireless Controller for Windows library |
okini3939 | 0:bd0f6bf72a8b | 3 | * for mbed USBHost library |
okini3939 | 0:bd0f6bf72a8b | 4 | * Copyright (c) 2013 Hiroshi Suga |
okini3939 | 0:bd0f6bf72a8b | 5 | * |
okini3939 | 0:bd0f6bf72a8b | 6 | * VID=0x045e PID=0x0719 |
okini3939 | 0:bd0f6bf72a8b | 7 | * |
okini3939 | 0:bd0f6bf72a8b | 8 | * Note: 2012-12-10 |
okini3939 | 0:bd0f6bf72a8b | 9 | * The library has some problems. |
okini3939 | 0:bd0f6bf72a8b | 10 | * - X-logo lamp remains flickering. |
okini3939 | 0:bd0f6bf72a8b | 11 | * - probe() function is irresponsible. |
okini3939 | 0:bd0f6bf72a8b | 12 | */ |
okini3939 | 0:bd0f6bf72a8b | 13 | |
okini3939 | 0:bd0f6bf72a8b | 14 | #include "USBHostXpad.h" |
okini3939 | 0:bd0f6bf72a8b | 15 | |
okini3939 | 0:bd0f6bf72a8b | 16 | #if 1 or USBHOST_XPAD |
okini3939 | 0:bd0f6bf72a8b | 17 | |
okini3939 | 0:bd0f6bf72a8b | 18 | #include "dbg.h" |
okini3939 | 0:bd0f6bf72a8b | 19 | |
okini3939 | 0:bd0f6bf72a8b | 20 | #define DEVICE_TO_HOST 0x80 |
okini3939 | 0:bd0f6bf72a8b | 21 | #define HOST_TO_DEVICE 0x00 |
okini3939 | 0:bd0f6bf72a8b | 22 | |
okini3939 | 0:bd0f6bf72a8b | 23 | USBHostXpad::USBHostXpad() |
okini3939 | 0:bd0f6bf72a8b | 24 | { |
okini3939 | 0:bd0f6bf72a8b | 25 | host = USBHost::getHostInst(); |
okini3939 | 0:bd0f6bf72a8b | 26 | init(); |
okini3939 | 0:bd0f6bf72a8b | 27 | } |
okini3939 | 0:bd0f6bf72a8b | 28 | |
okini3939 | 0:bd0f6bf72a8b | 29 | void USBHostXpad::init() { |
okini3939 | 0:bd0f6bf72a8b | 30 | dev_connected = false; |
okini3939 | 0:bd0f6bf72a8b | 31 | dev = NULL; |
okini3939 | 0:bd0f6bf72a8b | 32 | int_in = NULL; |
okini3939 | 0:bd0f6bf72a8b | 33 | int_out = NULL; |
okini3939 | 0:bd0f6bf72a8b | 34 | xpad_intf = -1; |
okini3939 | 0:bd0f6bf72a8b | 35 | xpad_device_found = false; |
okini3939 | 0:bd0f6bf72a8b | 36 | nb_ep = 0; |
okini3939 | 0:bd0f6bf72a8b | 37 | } |
okini3939 | 0:bd0f6bf72a8b | 38 | |
okini3939 | 0:bd0f6bf72a8b | 39 | bool USBHostXpad::connected() |
okini3939 | 0:bd0f6bf72a8b | 40 | { |
okini3939 | 0:bd0f6bf72a8b | 41 | return dev_connected; |
okini3939 | 0:bd0f6bf72a8b | 42 | } |
okini3939 | 0:bd0f6bf72a8b | 43 | |
okini3939 | 0:bd0f6bf72a8b | 44 | bool USBHostXpad::connect() |
okini3939 | 0:bd0f6bf72a8b | 45 | { |
okini3939 | 0:bd0f6bf72a8b | 46 | |
okini3939 | 0:bd0f6bf72a8b | 47 | if (dev_connected) { |
okini3939 | 0:bd0f6bf72a8b | 48 | return true; |
okini3939 | 0:bd0f6bf72a8b | 49 | } |
okini3939 | 0:bd0f6bf72a8b | 50 | |
okini3939 | 0:bd0f6bf72a8b | 51 | for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { |
okini3939 | 0:bd0f6bf72a8b | 52 | if ((dev = host->getDevice(i)) != NULL) { |
okini3939 | 0:bd0f6bf72a8b | 53 | |
okini3939 | 0:bd0f6bf72a8b | 54 | USB_DBG("Trying to connect MSD device\r\n"); |
okini3939 | 0:bd0f6bf72a8b | 55 | |
okini3939 | 0:bd0f6bf72a8b | 56 | if(host->enumerate(dev, this)) |
okini3939 | 0:bd0f6bf72a8b | 57 | break; |
okini3939 | 0:bd0f6bf72a8b | 58 | |
okini3939 | 0:bd0f6bf72a8b | 59 | if (xpad_device_found) { |
okini3939 | 0:bd0f6bf72a8b | 60 | xpad_device_found = false; |
okini3939 | 0:bd0f6bf72a8b | 61 | int_in = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, IN); |
okini3939 | 0:bd0f6bf72a8b | 62 | int_out = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, OUT); |
okini3939 | 0:bd0f6bf72a8b | 63 | |
okini3939 | 0:bd0f6bf72a8b | 64 | if (!int_in || !int_out) |
okini3939 | 0:bd0f6bf72a8b | 65 | continue; |
okini3939 | 0:bd0f6bf72a8b | 66 | |
okini3939 | 0:bd0f6bf72a8b | 67 | USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 68 | USB_INFO("endpoint in:%08x out:%08x", int_in, int_out); |
okini3939 | 0:bd0f6bf72a8b | 69 | dev->setName("XPAD", xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 70 | host->registerDriver(dev, xpad_intf, this, &USBHostXpad::init); |
okini3939 | 0:bd0f6bf72a8b | 71 | |
okini3939 | 0:bd0f6bf72a8b | 72 | int_in->attach(this, &USBHostXpad::rxHandler); |
okini3939 | 0:bd0f6bf72a8b | 73 | probe(0x00, 0x00, 0x08, 0x40); |
okini3939 | 0:bd0f6bf72a8b | 74 | probe(0x01, 0x03, 0x09, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 75 | probe(0x01, 0x03, 0x08, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 76 | probe(0x01, 0x03, 0x09, 0x00); |
okini3939 | 0:bd0f6bf72a8b | 77 | probe(0x01, 0x03, 0x09, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 78 | probe(0x01, 0x03, 0x08, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 79 | probe(0x01, 0x03, 0x09, 0x00); |
okini3939 | 0:bd0f6bf72a8b | 80 | probe(0x01, 0x03, 0x09, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 81 | probe(0x01, 0x03, 0x08, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 82 | probe(0x01, 0x03, 0x09, 0x00); |
okini3939 | 0:bd0f6bf72a8b | 83 | probe(0x01, 0x03, 0x09, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 84 | probe(0x01, 0x03, 0x08, 0x01); |
okini3939 | 0:bd0f6bf72a8b | 85 | probe(0x01, 0x03, 0x09, 0x00); |
okini3939 | 0:bd0f6bf72a8b | 86 | host->interruptRead(dev, int_in, report, int_in->getSize(), false); |
okini3939 | 0:bd0f6bf72a8b | 87 | dev_connected = true; |
okini3939 | 0:bd0f6bf72a8b | 88 | // USB_INFO("RETURN TRUE"); |
okini3939 | 0:bd0f6bf72a8b | 89 | return true; |
okini3939 | 0:bd0f6bf72a8b | 90 | } |
okini3939 | 0:bd0f6bf72a8b | 91 | |
okini3939 | 0:bd0f6bf72a8b | 92 | } //if() |
okini3939 | 0:bd0f6bf72a8b | 93 | } //for() |
okini3939 | 0:bd0f6bf72a8b | 94 | // USB_INFO("RETURN FALSE"); |
okini3939 | 0:bd0f6bf72a8b | 95 | init(); |
okini3939 | 0:bd0f6bf72a8b | 96 | return false; |
okini3939 | 0:bd0f6bf72a8b | 97 | } |
okini3939 | 0:bd0f6bf72a8b | 98 | |
okini3939 | 0:bd0f6bf72a8b | 99 | void USBHostXpad::rxHandler() { |
okini3939 | 0:bd0f6bf72a8b | 100 | int len_listen = int_in->getSize(); |
okini3939 | 0:bd0f6bf72a8b | 101 | int len = int_in->getLengthTransferred(); |
okini3939 | 0:bd0f6bf72a8b | 102 | |
okini3939 | 0:bd0f6bf72a8b | 103 | USB_INFO("rxHandler len:%d data:%02x %02x", len, report[0], report[1]); |
okini3939 | 0:bd0f6bf72a8b | 104 | for (int i = 0; i < len_listen; i ++) { |
okini3939 | 0:bd0f6bf72a8b | 105 | std::printf(" %02x", report[i]); |
okini3939 | 0:bd0f6bf72a8b | 106 | } |
okini3939 | 0:bd0f6bf72a8b | 107 | std::printf("\r\n"); |
okini3939 | 0:bd0f6bf72a8b | 108 | |
okini3939 | 0:bd0f6bf72a8b | 109 | if (report[0] == 0x08 && report[1] == 0x80) { |
okini3939 | 0:bd0f6bf72a8b | 110 | probe(0x00, 0x00, 0x00, 0x40); |
okini3939 | 0:bd0f6bf72a8b | 111 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 112 | } else |
okini3939 | 0:bd0f6bf72a8b | 113 | if (report[0] == 0x00 && report[1] == 0x0f) { |
okini3939 | 0:bd0f6bf72a8b | 114 | probe(0x00, 0x00, 0x08, 0x46); |
okini3939 | 0:bd0f6bf72a8b | 115 | probe(0x00, 0x00, 0x00, 0x40); |
okini3939 | 0:bd0f6bf72a8b | 116 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 117 | } else |
okini3939 | 0:bd0f6bf72a8b | 118 | if (report[0] == 0x00 && report[1] == 0x00 && report[2] == 0x00 && report[3] == 0x0f) { |
okini3939 | 0:bd0f6bf72a8b | 119 | // |
okini3939 | 0:bd0f6bf72a8b | 120 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 121 | } else |
okini3939 | 0:bd0f6bf72a8b | 122 | if (report[0] != 0x00 || !(report[1] & 1)) { // Check if it's the correct report - the controller also sends different status reports |
okini3939 | 0:bd0f6bf72a8b | 123 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 124 | } |
okini3939 | 0:bd0f6bf72a8b | 125 | |
okini3939 | 0:bd0f6bf72a8b | 126 | buttons = ((uint32_t)report[7] << 8) | report[6]; |
okini3939 | 0:bd0f6bf72a8b | 127 | trigger_l = report[8]; |
okini3939 | 0:bd0f6bf72a8b | 128 | trigger_r = report[9]; |
okini3939 | 0:bd0f6bf72a8b | 129 | |
okini3939 | 0:bd0f6bf72a8b | 130 | stick_lx = ((int16_t)report[11] << 8) | report[10]; |
okini3939 | 0:bd0f6bf72a8b | 131 | stick_ly = ((int16_t)report[13] << 8) | report[12]; |
okini3939 | 0:bd0f6bf72a8b | 132 | stick_rx = ((int16_t)report[15] << 8) | report[14]; |
okini3939 | 0:bd0f6bf72a8b | 133 | stick_ry = ((int16_t)report[17] << 8) | report[16]; |
okini3939 | 0:bd0f6bf72a8b | 134 | |
okini3939 | 0:bd0f6bf72a8b | 135 | if (onUpdate) { |
okini3939 | 0:bd0f6bf72a8b | 136 | (*onUpdate)(buttons, stick_lx, stick_ly, stick_rx, stick_ry, trigger_l, trigger_r); |
okini3939 | 0:bd0f6bf72a8b | 137 | } |
okini3939 | 0:bd0f6bf72a8b | 138 | exit: |
okini3939 | 0:bd0f6bf72a8b | 139 | if (dev) |
okini3939 | 0:bd0f6bf72a8b | 140 | host->interruptRead(dev, int_in, report, len_listen, false); |
okini3939 | 0:bd0f6bf72a8b | 141 | } |
okini3939 | 0:bd0f6bf72a8b | 142 | |
okini3939 | 0:bd0f6bf72a8b | 143 | /*virtual*/ void USBHostXpad::setVidPid(uint16_t vid, uint16_t pid) |
okini3939 | 0:bd0f6bf72a8b | 144 | { |
okini3939 | 0:bd0f6bf72a8b | 145 | // we don't check VID/PID for MSD driver |
okini3939 | 0:bd0f6bf72a8b | 146 | } |
okini3939 | 0:bd0f6bf72a8b | 147 | |
okini3939 | 0:bd0f6bf72a8b | 148 | /*virtual*/ bool USBHostXpad::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed |
okini3939 | 0:bd0f6bf72a8b | 149 | { |
okini3939 | 0:bd0f6bf72a8b | 150 | USB_INFO("parseInterface class:%02x subclass:%02x protocol:%02x [nb: %d - intf: %d]", intf_class, intf_subclass, intf_protocol, intf_nb, xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 151 | if ((xpad_intf == -1) && |
okini3939 | 0:bd0f6bf72a8b | 152 | (intf_class == 0xff) && |
okini3939 | 0:bd0f6bf72a8b | 153 | (intf_subclass == 0x5d) && |
okini3939 | 0:bd0f6bf72a8b | 154 | (intf_protocol == 0x81)) { |
okini3939 | 0:bd0f6bf72a8b | 155 | xpad_intf = intf_nb; |
okini3939 | 0:bd0f6bf72a8b | 156 | return true; |
okini3939 | 0:bd0f6bf72a8b | 157 | } |
okini3939 | 0:bd0f6bf72a8b | 158 | return false; |
okini3939 | 0:bd0f6bf72a8b | 159 | } |
okini3939 | 0:bd0f6bf72a8b | 160 | |
okini3939 | 0:bd0f6bf72a8b | 161 | /*virtual*/ bool USBHostXpad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used |
okini3939 | 0:bd0f6bf72a8b | 162 | { |
okini3939 | 0:bd0f6bf72a8b | 163 | USB_INFO("useEndpoint nb:%d type:%d dir:%d", intf_nb, type, dir); |
okini3939 | 0:bd0f6bf72a8b | 164 | if (intf_nb == xpad_intf) { |
okini3939 | 0:bd0f6bf72a8b | 165 | if (type == INTERRUPT_ENDPOINT) { |
okini3939 | 0:bd0f6bf72a8b | 166 | nb_ep ++; |
okini3939 | 0:bd0f6bf72a8b | 167 | if (nb_ep == 2) |
okini3939 | 0:bd0f6bf72a8b | 168 | xpad_device_found = true; |
okini3939 | 0:bd0f6bf72a8b | 169 | return true; |
okini3939 | 0:bd0f6bf72a8b | 170 | } |
okini3939 | 0:bd0f6bf72a8b | 171 | } |
okini3939 | 0:bd0f6bf72a8b | 172 | return false; |
okini3939 | 0:bd0f6bf72a8b | 173 | } |
okini3939 | 0:bd0f6bf72a8b | 174 | |
okini3939 | 0:bd0f6bf72a8b | 175 | void USBHostXpad::poll () |
okini3939 | 0:bd0f6bf72a8b | 176 | { |
okini3939 | 0:bd0f6bf72a8b | 177 | probe(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 0:bd0f6bf72a8b | 178 | probe(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 0:bd0f6bf72a8b | 179 | probe(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 0:bd0f6bf72a8b | 180 | probe(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 0:bd0f6bf72a8b | 181 | } |
okini3939 | 0:bd0f6bf72a8b | 182 | |
okini3939 | 0:bd0f6bf72a8b | 183 | bool USBHostXpad::probe(int val1, int val2, int val3, int val4) |
okini3939 | 0:bd0f6bf72a8b | 184 | { |
okini3939 | 0:bd0f6bf72a8b | 185 | unsigned char bdata[32]; |
okini3939 | 0:bd0f6bf72a8b | 186 | memset(bdata, 0, sizeof(bdata)); |
okini3939 | 0:bd0f6bf72a8b | 187 | bdata[0] = val1; |
okini3939 | 0:bd0f6bf72a8b | 188 | bdata[1] = val2; |
okini3939 | 0:bd0f6bf72a8b | 189 | bdata[2] = val3; |
okini3939 | 0:bd0f6bf72a8b | 190 | bdata[3] = val4; |
okini3939 | 0:bd0f6bf72a8b | 191 | if (dev) |
okini3939 | 0:bd0f6bf72a8b | 192 | host->interruptWrite(dev, int_out, bdata, 12, false); |
okini3939 | 0:bd0f6bf72a8b | 193 | return true; |
okini3939 | 0:bd0f6bf72a8b | 194 | } |
okini3939 | 0:bd0f6bf72a8b | 195 | |
okini3939 | 0:bd0f6bf72a8b | 196 | bool USBHostXpad::effect(uint8_t strong, uint8_t weak) |
okini3939 | 0:bd0f6bf72a8b | 197 | { |
okini3939 | 0:bd0f6bf72a8b | 198 | unsigned char odata[32]; |
okini3939 | 0:bd0f6bf72a8b | 199 | |
okini3939 | 0:bd0f6bf72a8b | 200 | odata[0] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 201 | odata[1] = 0x01; |
okini3939 | 0:bd0f6bf72a8b | 202 | odata[2] = 0x0F; |
okini3939 | 0:bd0f6bf72a8b | 203 | odata[3] = 0xC0; |
okini3939 | 0:bd0f6bf72a8b | 204 | odata[4] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 205 | odata[5] = strong; |
okini3939 | 0:bd0f6bf72a8b | 206 | odata[6] = weak; |
okini3939 | 0:bd0f6bf72a8b | 207 | odata[7] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 208 | odata[8] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 209 | odata[9] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 210 | odata[10] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 211 | odata[11] = 0x00; |
okini3939 | 0:bd0f6bf72a8b | 212 | host->interruptWrite(dev, int_in, odata, 12, false); |
okini3939 | 0:bd0f6bf72a8b | 213 | return true; |
okini3939 | 0:bd0f6bf72a8b | 214 | } |
okini3939 | 0:bd0f6bf72a8b | 215 | |
okini3939 | 0:bd0f6bf72a8b | 216 | #endif |
okini3939 | 0:bd0f6bf72a8b | 217 |