USB Host Library for Sprint Dongles

Fork of USBHostWANDongleSprint_bleedingedge by Donatien Garnier

Legacy Warning

This is an mbed 2 libary. To learn more about mbed OS 5, visit the docs.

Committer:
donatien
Date:
Wed Sep 12 08:15:02 2012 +0000
Revision:
0:bfed5767d0a5
Child:
2:34c976009b70
Initial Commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:bfed5767d0a5 1 /* Copyright (c) 2010-2012 mbed.org, MIT License
donatien 0:bfed5767d0a5 2 *
donatien 0:bfed5767d0a5 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
donatien 0:bfed5767d0a5 4 * and associated documentation files (the "Software"), to deal in the Software without
donatien 0:bfed5767d0a5 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
donatien 0:bfed5767d0a5 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
donatien 0:bfed5767d0a5 7 * Software is furnished to do so, subject to the following conditions:
donatien 0:bfed5767d0a5 8 *
donatien 0:bfed5767d0a5 9 * The above copyright notice and this permission notice shall be included in all copies or
donatien 0:bfed5767d0a5 10 * substantial portions of the Software.
donatien 0:bfed5767d0a5 11 *
donatien 0:bfed5767d0a5 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
donatien 0:bfed5767d0a5 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
donatien 0:bfed5767d0a5 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
donatien 0:bfed5767d0a5 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
donatien 0:bfed5767d0a5 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
donatien 0:bfed5767d0a5 17 */
donatien 0:bfed5767d0a5 18
donatien 0:bfed5767d0a5 19 #define __DEBUG__ 0 //WARN: ENABLING DEBUGGING HERE WILL PRINTF IN IRQS!! UNEXPECTED BEHAVIOUR MAY RESULT...
donatien 0:bfed5767d0a5 20 #ifndef __MODULE__
donatien 0:bfed5767d0a5 21 #define __MODULE__ "USBHost.cpp"
donatien 0:bfed5767d0a5 22 #endif
donatien 0:bfed5767d0a5 23
donatien 0:bfed5767d0a5 24 #include "core/dbg.h"
donatien 0:bfed5767d0a5 25 #include <cstdint>
donatien 0:bfed5767d0a5 26
donatien 0:bfed5767d0a5 27 #include "USBHost.h"
donatien 0:bfed5767d0a5 28 #include "rtos.h"
donatien 0:bfed5767d0a5 29
donatien 0:bfed5767d0a5 30
donatien 0:bfed5767d0a5 31 #define NB_MAX_INTF 2
donatien 0:bfed5767d0a5 32
donatien 0:bfed5767d0a5 33 USBHost * USBHost::instHost = NULL;
donatien 0:bfed5767d0a5 34
donatien 0:bfed5767d0a5 35 USBHost::USBHost()
donatien 0:bfed5767d0a5 36 #if 0 //try not to use this
donatien 0:bfed5767d0a5 37 : m_usbQueue(), m_usbThread(3, this, &USBHost::usbProcess)
donatien 0:bfed5767d0a5 38 #endif
donatien 0:bfed5767d0a5 39 {
donatien 0:bfed5767d0a5 40 headControlEndpoint = NULL;
donatien 0:bfed5767d0a5 41 headBulkEndpoint = NULL;
donatien 0:bfed5767d0a5 42 headInterruptEndpoint = NULL;
donatien 0:bfed5767d0a5 43 tailControlEndpoint = NULL;
donatien 0:bfed5767d0a5 44 tailBulkEndpoint = NULL;
donatien 0:bfed5767d0a5 45 tailInterruptEndpoint = NULL;
donatien 0:bfed5767d0a5 46
donatien 0:bfed5767d0a5 47 nb_devices = 0;
donatien 0:bfed5767d0a5 48 lenReportDescr = 0;
donatien 0:bfed5767d0a5 49
donatien 0:bfed5767d0a5 50 controlEndpointAllocated = false;
donatien 0:bfed5767d0a5 51
donatien 0:bfed5767d0a5 52 for (int i = 0; i < MAX_DEVICE_NB; i++) {
donatien 0:bfed5767d0a5 53 deviceInUse[i] = false;
donatien 0:bfed5767d0a5 54 devices[i].setAddress(i + 1);
donatien 0:bfed5767d0a5 55 deviceReset[i] = false;
donatien 0:bfed5767d0a5 56 }
donatien 0:bfed5767d0a5 57 }
donatien 0:bfed5767d0a5 58
donatien 0:bfed5767d0a5 59
donatien 0:bfed5767d0a5 60 void USBHost::transferCompleted(volatile uint32_t addr) {
donatien 0:bfed5767d0a5 61 #if 0 //try not to use this
donatien 0:bfed5767d0a5 62 Interrupt::enter();
donatien 0:bfed5767d0a5 63 m_usbQueue.post(addr);
donatien 0:bfed5767d0a5 64 Interrupt::leave();
donatien 0:bfed5767d0a5 65 #else
donatien 0:bfed5767d0a5 66
donatien 0:bfed5767d0a5 67 if(addr == NULL) //Nothing to process?
donatien 0:bfed5767d0a5 68 {
donatien 0:bfed5767d0a5 69 return;
donatien 0:bfed5767d0a5 70 }
donatien 0:bfed5767d0a5 71
donatien 0:bfed5767d0a5 72 volatile HCTD* tdList = NULL;
donatien 0:bfed5767d0a5 73
donatien 0:bfed5767d0a5 74 //First we must reverse the list order and dequeue each TD
donatien 0:bfed5767d0a5 75 do
donatien 0:bfed5767d0a5 76 {
donatien 0:bfed5767d0a5 77 volatile HCTD* td = (volatile HCTD*)addr;
donatien 0:bfed5767d0a5 78
donatien 0:bfed5767d0a5 79 if(td->control & 0xF0000000 != 0)
donatien 0:bfed5767d0a5 80 {
donatien 0:bfed5767d0a5 81 WARN("Condition code %02x", td->control >> 28);
donatien 0:bfed5767d0a5 82 }
donatien 0:bfed5767d0a5 83
donatien 0:bfed5767d0a5 84 addr = td->nextTD; //Dequeue from physical list
donatien 0:bfed5767d0a5 85 td->nextTD = (uint32_t)tdList; //Enqueue into reversed list
donatien 0:bfed5767d0a5 86 tdList = td;
donatien 0:bfed5767d0a5 87 } while(addr);
donatien 0:bfed5767d0a5 88
donatien 0:bfed5767d0a5 89 //Now we can process the list
donatien 0:bfed5767d0a5 90 USBEndpoint * volatile iter = NULL;
donatien 0:bfed5767d0a5 91
donatien 0:bfed5767d0a5 92 while(tdList != NULL)
donatien 0:bfed5767d0a5 93 {
donatien 0:bfed5767d0a5 94 bool found = false;
donatien 0:bfed5767d0a5 95 volatile HCTD* td = tdList;
donatien 0:bfed5767d0a5 96 tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below
donatien 0:bfed5767d0a5 97 for (int i = 0; i < 3; i++) {
donatien 0:bfed5767d0a5 98 if (found) {
donatien 0:bfed5767d0a5 99 break;
donatien 0:bfed5767d0a5 100 }
donatien 0:bfed5767d0a5 101 iter = (i == 0) ? headControlEndpoint : ( (i == 1) ? headBulkEndpoint : headInterruptEndpoint);
donatien 0:bfed5767d0a5 102 while (iter != NULL) {
donatien 0:bfed5767d0a5 103 if (iter->getProcessedTD() == td) {
donatien 0:bfed5767d0a5 104 DBG("td=%p FOUND ed: %08X", td, (void *)iter->getHCED());
donatien 0:bfed5767d0a5 105 if (((HCTD *)td)->control >> 28) {
donatien 0:bfed5767d0a5 106 DBG("TD Error: %d", td->control >> 28);
donatien 0:bfed5767d0a5 107 iter->setState(USB_TYPE_TDFAIL);
donatien 0:bfed5767d0a5 108 } else if ((uint32_t)iter->getHCED() & 0x1) {
donatien 0:bfed5767d0a5 109 DBG("HALTED");
donatien 0:bfed5767d0a5 110 iter->setState(USB_TYPE_HALTED);
donatien 0:bfed5767d0a5 111 } else if (!td->currBufPtr) {
donatien 0:bfed5767d0a5 112 DBG("!%p", iter);
donatien 0:bfed5767d0a5 113 iter->setState(USB_TYPE_IDLE);
donatien 0:bfed5767d0a5 114 found=true;
donatien 0:bfed5767d0a5 115 } else {
donatien 0:bfed5767d0a5 116 DBG("!%p", iter);
donatien 0:bfed5767d0a5 117 iter->setState(USB_TYPE_IDLE);
donatien 0:bfed5767d0a5 118 iter->setLengthTransferred(td->currBufPtr - iter->getBufStart());
donatien 0:bfed5767d0a5 119 found=true;
donatien 0:bfed5767d0a5 120 }
donatien 0:bfed5767d0a5 121 break;
donatien 0:bfed5767d0a5 122 }
donatien 0:bfed5767d0a5 123 iter = iter->nextEndpoint();
donatien 0:bfed5767d0a5 124 }
donatien 0:bfed5767d0a5 125 }
donatien 0:bfed5767d0a5 126
donatien 0:bfed5767d0a5 127
donatien 0:bfed5767d0a5 128 if (found) {
donatien 0:bfed5767d0a5 129 iter->unqueueTransfer(td);
donatien 0:bfed5767d0a5 130
donatien 0:bfed5767d0a5 131 if (iter->getType() != CONTROL_ENDPOINT) {
donatien 0:bfed5767d0a5 132 iter->call();
donatien 0:bfed5767d0a5 133 }
donatien 0:bfed5767d0a5 134 }
donatien 0:bfed5767d0a5 135 else
donatien 0:bfed5767d0a5 136 {
donatien 0:bfed5767d0a5 137 WARN("TD not found!!!");
donatien 0:bfed5767d0a5 138 freeTD((uint8_t *)td); //Device must have been disconnected meanwhile
donatien 0:bfed5767d0a5 139 }
donatien 0:bfed5767d0a5 140
donatien 0:bfed5767d0a5 141 }
donatien 0:bfed5767d0a5 142 #endif
donatien 0:bfed5767d0a5 143 }
donatien 0:bfed5767d0a5 144
donatien 0:bfed5767d0a5 145 USBHost * USBHost::getHostInst() {
donatien 0:bfed5767d0a5 146 if (instHost == NULL) {
donatien 0:bfed5767d0a5 147 instHost = new USBHost();
donatien 0:bfed5767d0a5 148 instHost->init();
donatien 0:bfed5767d0a5 149 }
donatien 0:bfed5767d0a5 150 return instHost;
donatien 0:bfed5767d0a5 151 }
donatien 0:bfed5767d0a5 152
donatien 0:bfed5767d0a5 153
donatien 0:bfed5767d0a5 154 /*
donatien 0:bfed5767d0a5 155 * Call in ISR when a device has been connected
donatien 0:bfed5767d0a5 156 */
donatien 0:bfed5767d0a5 157 void USBHost::deviceConnected(int hub, int port, bool lowSpeed) {
donatien 0:bfed5767d0a5 158
donatien 0:bfed5767d0a5 159 for (int i = 0; i < MAX_DEVICE_NB; i++) {
donatien 0:bfed5767d0a5 160 if (!deviceInUse[i]) {
donatien 0:bfed5767d0a5 161 deviceInUse[i] = true;
donatien 0:bfed5767d0a5 162 WARN("will call init on device %p: speed: %d", (void *)&devices[i], lowSpeed);
donatien 0:bfed5767d0a5 163 devices[i].init(hub, port, lowSpeed);
donatien 0:bfed5767d0a5 164 deviceReset[i] = false;
donatien 0:bfed5767d0a5 165 break;
donatien 0:bfed5767d0a5 166 }
donatien 0:bfed5767d0a5 167 }
donatien 0:bfed5767d0a5 168
donatien 0:bfed5767d0a5 169 if (!controlEndpointAllocated) {
donatien 0:bfed5767d0a5 170 control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00);
donatien 0:bfed5767d0a5 171 addEndpoint(NULL, 0, (USBEndpoint*)control);
donatien 0:bfed5767d0a5 172 controlEndpointAllocated = true;
donatien 0:bfed5767d0a5 173 }
donatien 0:bfed5767d0a5 174 }
donatien 0:bfed5767d0a5 175
donatien 0:bfed5767d0a5 176 /*
donatien 0:bfed5767d0a5 177 * Call in ISR when a device has been disconnected
donatien 0:bfed5767d0a5 178 */
donatien 0:bfed5767d0a5 179 void USBHost::deviceDisconnected(int hub, int port, volatile uint32_t addr) {
donatien 0:bfed5767d0a5 180
donatien 0:bfed5767d0a5 181 bool controlListState = disableControlList();
donatien 0:bfed5767d0a5 182 bool bulkListState = disableBulkList();
donatien 0:bfed5767d0a5 183 bool interruptListState = disableInterruptList();
donatien 0:bfed5767d0a5 184
donatien 0:bfed5767d0a5 185 transferCompleted(addr); //Finish processing any pending completed TD
donatien 0:bfed5767d0a5 186
donatien 0:bfed5767d0a5 187 for (int i = 0; i < MAX_DEVICE_NB; i++) {
donatien 0:bfed5767d0a5 188 if ((devices[i].getHub() == hub) && (devices[i].getPort() == port)) {
donatien 0:bfed5767d0a5 189 WARN("device disconnected: %p", (void *)&devices[i]);
donatien 0:bfed5767d0a5 190 deviceInUse[i] = false;
donatien 0:bfed5767d0a5 191 deviceReset[i] = false;
donatien 0:bfed5767d0a5 192 freeDevice((USBDeviceConnected*)&devices[i]);
donatien 0:bfed5767d0a5 193 break;
donatien 0:bfed5767d0a5 194 }
donatien 0:bfed5767d0a5 195 }
donatien 0:bfed5767d0a5 196 nb_devices--;
donatien 0:bfed5767d0a5 197
donatien 0:bfed5767d0a5 198 if (controlListState) enableControlList();
donatien 0:bfed5767d0a5 199 if (bulkListState) enableBulkList();
donatien 0:bfed5767d0a5 200 if (interruptListState) enableInterruptList();
donatien 0:bfed5767d0a5 201 }
donatien 0:bfed5767d0a5 202
donatien 0:bfed5767d0a5 203 void USBHost::freeDevice(USBDeviceConnected * dev) {
donatien 0:bfed5767d0a5 204 USBEndpoint * ep = NULL;
donatien 0:bfed5767d0a5 205 // HCTD * td = NULL;
donatien 0:bfed5767d0a5 206 HCED * ed = NULL;
donatien 0:bfed5767d0a5 207
donatien 0:bfed5767d0a5 208 for (int j = 0; j < dev->getNbInterface(); j++) {
donatien 0:bfed5767d0a5 209 DBG("FREE INTF %d, %p, nb_endpot: %d", j, (void *)dev->getInterface(j), dev->getInterface(j)->nb_endpoint);
donatien 0:bfed5767d0a5 210 for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) {
donatien 0:bfed5767d0a5 211 if ((ep = dev->getEndpoint(j, i)) != NULL) {
donatien 0:bfed5767d0a5 212 DBG("Freeing USBEndpoint");
donatien 0:bfed5767d0a5 213 ed = (HCED *)ep->getHCED();
donatien 0:bfed5767d0a5 214 ed->control |= (1 << 13); //sKip bit
donatien 0:bfed5767d0a5 215 DBG("Dequeueing USBEndpoint");
donatien 0:bfed5767d0a5 216 unqueueEndpoint(ep);
donatien 0:bfed5767d0a5 217
donatien 0:bfed5767d0a5 218 DBG("Freeing first transfer descriptor");
donatien 0:bfed5767d0a5 219 freeTD((volatile uint8_t*)ep->getTDList()[0]);
donatien 0:bfed5767d0a5 220 DBG("Freeing second transfer descriptor");
donatien 0:bfed5767d0a5 221 freeTD((volatile uint8_t*)ep->getTDList()[1]);
donatien 0:bfed5767d0a5 222
donatien 0:bfed5767d0a5 223 DBG("Freeing USBEndpoint descriptor");
donatien 0:bfed5767d0a5 224 freeED((uint8_t *)ep->getHCED());
donatien 0:bfed5767d0a5 225 }
donatien 0:bfed5767d0a5 226 //printBulk();
donatien 0:bfed5767d0a5 227 //printInt();
donatien 0:bfed5767d0a5 228 }
donatien 0:bfed5767d0a5 229 }
donatien 0:bfed5767d0a5 230 DBG("Disconnecting device");
donatien 0:bfed5767d0a5 231 dev->disconnect();
donatien 0:bfed5767d0a5 232 DBG("Device disconnected");
donatien 0:bfed5767d0a5 233 }
donatien 0:bfed5767d0a5 234
donatien 0:bfed5767d0a5 235
donatien 0:bfed5767d0a5 236 void USBHost::unqueueEndpoint(USBEndpoint * ep) {
donatien 0:bfed5767d0a5 237 USBEndpoint * prec = NULL;
donatien 0:bfed5767d0a5 238 USBEndpoint * current = NULL;
donatien 0:bfed5767d0a5 239 bool found = false;
donatien 0:bfed5767d0a5 240
donatien 0:bfed5767d0a5 241 DBG("want to unqueue ep: %p", (void *)ep->getHCED());
donatien 0:bfed5767d0a5 242
donatien 0:bfed5767d0a5 243 for (int i = 0; i < 2; i++) {
donatien 0:bfed5767d0a5 244 if (found) {
donatien 0:bfed5767d0a5 245 DBG("USBEndpoint unqueued: %p", (void *)ep->getHCED());
donatien 0:bfed5767d0a5 246 break;
donatien 0:bfed5767d0a5 247 }
donatien 0:bfed5767d0a5 248 current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint;
donatien 0:bfed5767d0a5 249 prec = current;
donatien 0:bfed5767d0a5 250 while (current != NULL) {
donatien 0:bfed5767d0a5 251 if (current == ep) {
donatien 0:bfed5767d0a5 252 if (current->nextEndpoint() != NULL) {
donatien 0:bfed5767d0a5 253 prec->queueEndpoint(current->nextEndpoint());
donatien 0:bfed5767d0a5 254 if (current == headBulkEndpoint) {
donatien 0:bfed5767d0a5 255 updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED());
donatien 0:bfed5767d0a5 256 headBulkEndpoint = current->nextEndpoint();
donatien 0:bfed5767d0a5 257 }
donatien 0:bfed5767d0a5 258 if (current == headInterruptEndpoint) {
donatien 0:bfed5767d0a5 259 updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED());
donatien 0:bfed5767d0a5 260 headInterruptEndpoint = current->nextEndpoint();
donatien 0:bfed5767d0a5 261 }
donatien 0:bfed5767d0a5 262 } else {
donatien 0:bfed5767d0a5 263 prec->queueEndpoint(NULL);
donatien 0:bfed5767d0a5 264 if (current == headBulkEndpoint) {
donatien 0:bfed5767d0a5 265 updateBulkHeadED(0);
donatien 0:bfed5767d0a5 266 headBulkEndpoint = current->nextEndpoint();
donatien 0:bfed5767d0a5 267 }
donatien 0:bfed5767d0a5 268 if (current == headInterruptEndpoint) {
donatien 0:bfed5767d0a5 269 updateInterruptHeadED(0);
donatien 0:bfed5767d0a5 270 headInterruptEndpoint = current->nextEndpoint();
donatien 0:bfed5767d0a5 271 }
donatien 0:bfed5767d0a5 272 }
donatien 0:bfed5767d0a5 273 found = true;
donatien 0:bfed5767d0a5 274 current->setState(USB_TYPE_FREE);
donatien 0:bfed5767d0a5 275 break;
donatien 0:bfed5767d0a5 276 }
donatien 0:bfed5767d0a5 277 prec = current;
donatien 0:bfed5767d0a5 278 current = current->nextEndpoint();
donatien 0:bfed5767d0a5 279 }
donatien 0:bfed5767d0a5 280 }
donatien 0:bfed5767d0a5 281 //printBulk();
donatien 0:bfed5767d0a5 282 //printInt();
donatien 0:bfed5767d0a5 283 }
donatien 0:bfed5767d0a5 284
donatien 0:bfed5767d0a5 285
donatien 0:bfed5767d0a5 286 USBDeviceConnected * USBHost::getDevice(uint8_t index) {
donatien 0:bfed5767d0a5 287 if ((index >= MAX_DEVICE_NB) || (!deviceInUse[index])) {
donatien 0:bfed5767d0a5 288 return NULL;
donatien 0:bfed5767d0a5 289 }
donatien 0:bfed5767d0a5 290 return (USBDeviceConnected*)&devices[index];
donatien 0:bfed5767d0a5 291 }
donatien 0:bfed5767d0a5 292
donatien 0:bfed5767d0a5 293
donatien 0:bfed5767d0a5 294
donatien 0:bfed5767d0a5 295 // create an USBEndpoint descriptor. the USBEndpoint is not linked
donatien 0:bfed5767d0a5 296 USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) {
donatien 0:bfed5767d0a5 297 int i = 0;
donatien 0:bfed5767d0a5 298 HCED * ed = (HCED *)getED();
donatien 0:bfed5767d0a5 299 HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
donatien 0:bfed5767d0a5 300
donatien 0:bfed5767d0a5 301 memset((void *)td_list[0], 0x00, sizeof(HCTD));
donatien 0:bfed5767d0a5 302 memset((void *)td_list[1], 0x00, sizeof(HCTD));
donatien 0:bfed5767d0a5 303
donatien 0:bfed5767d0a5 304 // search a free USBEndpoint
donatien 0:bfed5767d0a5 305 for (i = 0; i < MAX_ENDPOINT; i++) {
donatien 0:bfed5767d0a5 306 if (endpoints[i].getState() == USB_TYPE_FREE) {
donatien 0:bfed5767d0a5 307 DBG("Trying to create ep");
donatien 0:bfed5767d0a5 308 endpoints[i].init(ed, type, dir, size, addr, td_list);
donatien 0:bfed5767d0a5 309 //endpoints[i].queueTransfer(nullTd);
donatien 0:bfed5767d0a5 310 DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d", &endpoints[i], type, dir, size, addr);
donatien 0:bfed5767d0a5 311 return &endpoints[i];
donatien 0:bfed5767d0a5 312 }
donatien 0:bfed5767d0a5 313 }
donatien 0:bfed5767d0a5 314 DBG("could not allocate more endpoints!!!!");
donatien 0:bfed5767d0a5 315 return NULL;
donatien 0:bfed5767d0a5 316 }
donatien 0:bfed5767d0a5 317
donatien 0:bfed5767d0a5 318
donatien 0:bfed5767d0a5 319 USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev) {
donatien 0:bfed5767d0a5 320 int index = findDevice(dev);
donatien 0:bfed5767d0a5 321 if ((index != -1) && (!deviceReset[index])) {
donatien 0:bfed5767d0a5 322 resetPort(dev->getHub(), dev->getPort());
donatien 0:bfed5767d0a5 323 deviceReset[index] = true;
donatien 0:bfed5767d0a5 324 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 325 }
donatien 0:bfed5767d0a5 326 return USB_TYPE_NOTFOUND;
donatien 0:bfed5767d0a5 327 }
donatien 0:bfed5767d0a5 328
donatien 0:bfed5767d0a5 329 // link the USBEndpoint to the linked list and attach an USBEndpoint to a device
donatien 0:bfed5767d0a5 330 bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) {
donatien 0:bfed5767d0a5 331
donatien 0:bfed5767d0a5 332 if (ep == NULL) {
donatien 0:bfed5767d0a5 333 return false;
donatien 0:bfed5767d0a5 334 }
donatien 0:bfed5767d0a5 335
donatien 0:bfed5767d0a5 336 DBG("New ep %p", ep);
donatien 0:bfed5767d0a5 337
donatien 0:bfed5767d0a5 338 HCED * prevEd;
donatien 0:bfed5767d0a5 339
donatien 0:bfed5767d0a5 340 // set device address in the USBEndpoint descriptor
donatien 0:bfed5767d0a5 341 if (dev == NULL) {
donatien 0:bfed5767d0a5 342 ep->setDeviceAddress(0);
donatien 0:bfed5767d0a5 343 } else {
donatien 0:bfed5767d0a5 344 ep->setDeviceAddress(dev->getAddress());
donatien 0:bfed5767d0a5 345 }
donatien 0:bfed5767d0a5 346
donatien 0:bfed5767d0a5 347 if (dev != NULL && dev->getSpeed()) {
donatien 0:bfed5767d0a5 348 DBG("add USBEndpoint: set speed");
donatien 0:bfed5767d0a5 349 ep->setSpeed(dev->getSpeed());
donatien 0:bfed5767d0a5 350 }
donatien 0:bfed5767d0a5 351
donatien 0:bfed5767d0a5 352 // queue the new USBEndpoint on the ED list
donatien 0:bfed5767d0a5 353 switch (ep->getType()) {
donatien 0:bfed5767d0a5 354
donatien 0:bfed5767d0a5 355 case CONTROL_ENDPOINT:
donatien 0:bfed5767d0a5 356 prevEd = ( HCED*) controlHeadED();
donatien 0:bfed5767d0a5 357 if (!prevEd) {
donatien 0:bfed5767d0a5 358 updateControlHeadED((uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 359 DBG("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 360 headControlEndpoint = ep;
donatien 0:bfed5767d0a5 361 tailControlEndpoint = ep;
donatien 0:bfed5767d0a5 362 return true;
donatien 0:bfed5767d0a5 363 }
donatien 0:bfed5767d0a5 364 tailControlEndpoint->queueEndpoint(ep);
donatien 0:bfed5767d0a5 365 tailControlEndpoint = ep;
donatien 0:bfed5767d0a5 366 return true;
donatien 0:bfed5767d0a5 367
donatien 0:bfed5767d0a5 368 case BULK_ENDPOINT:
donatien 0:bfed5767d0a5 369 prevEd = ( HCED*) bulkHeadED();
donatien 0:bfed5767d0a5 370 if (!prevEd) {
donatien 0:bfed5767d0a5 371 updateBulkHeadED((uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 372 //DBG("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 373 headBulkEndpoint = ep;
donatien 0:bfed5767d0a5 374 tailBulkEndpoint = ep;
donatien 0:bfed5767d0a5 375 break;
donatien 0:bfed5767d0a5 376 }
donatien 0:bfed5767d0a5 377 tailBulkEndpoint->queueEndpoint(ep);
donatien 0:bfed5767d0a5 378 tailBulkEndpoint = ep;
donatien 0:bfed5767d0a5 379 break;
donatien 0:bfed5767d0a5 380
donatien 0:bfed5767d0a5 381 case INTERRUPT_ENDPOINT:
donatien 0:bfed5767d0a5 382 prevEd = ( HCED*) interruptHeadED();
donatien 0:bfed5767d0a5 383 if (!prevEd) {
donatien 0:bfed5767d0a5 384 updateInterruptHeadED((uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 385 //DBG("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
donatien 0:bfed5767d0a5 386 headInterruptEndpoint = ep;
donatien 0:bfed5767d0a5 387 tailInterruptEndpoint = ep;
donatien 0:bfed5767d0a5 388 break;
donatien 0:bfed5767d0a5 389 }
donatien 0:bfed5767d0a5 390 tailInterruptEndpoint->queueEndpoint(ep);
donatien 0:bfed5767d0a5 391 tailInterruptEndpoint = ep;
donatien 0:bfed5767d0a5 392 break;
donatien 0:bfed5767d0a5 393 default:
donatien 0:bfed5767d0a5 394 return false;
donatien 0:bfed5767d0a5 395 }
donatien 0:bfed5767d0a5 396
donatien 0:bfed5767d0a5 397 dev->addEndpoint(intf_nb, ep);
donatien 0:bfed5767d0a5 398 //printBulk();
donatien 0:bfed5767d0a5 399 //printInt();
donatien 0:bfed5767d0a5 400
donatien 0:bfed5767d0a5 401 return true;
donatien 0:bfed5767d0a5 402 }
donatien 0:bfed5767d0a5 403
donatien 0:bfed5767d0a5 404
donatien 0:bfed5767d0a5 405 int USBHost::findDevice(USBDeviceConnected * dev) {
donatien 0:bfed5767d0a5 406 for (int i = 0; i < MAX_DEVICE_NB; i++) {
donatien 0:bfed5767d0a5 407 if (dev == &devices[i]) {
donatien 0:bfed5767d0a5 408 return i;
donatien 0:bfed5767d0a5 409 }
donatien 0:bfed5767d0a5 410 }
donatien 0:bfed5767d0a5 411 return -1;
donatien 0:bfed5767d0a5 412 }
donatien 0:bfed5767d0a5 413
donatien 0:bfed5767d0a5 414 void USBHost::printBulk() {
donatien 0:bfed5767d0a5 415 HCED * hced = (HCED *)bulkHeadED();
donatien 0:bfed5767d0a5 416 HCTD * hctd = NULL;
donatien 0:bfed5767d0a5 417 printf("---------State of Bulk:--------\r\n");
donatien 0:bfed5767d0a5 418 while (hced != NULL) {
donatien 0:bfed5767d0a5 419 printf("hced: %p\r\n", hced);
donatien 0:bfed5767d0a5 420 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
donatien 0:bfed5767d0a5 421 while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
donatien 0:bfed5767d0a5 422 printf("\thctd: %p\r\n", hctd);
donatien 0:bfed5767d0a5 423 hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
donatien 0:bfed5767d0a5 424 }
donatien 0:bfed5767d0a5 425 printf("\thctd: %p\r\n", hctd);
donatien 0:bfed5767d0a5 426 hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
donatien 0:bfed5767d0a5 427 }
donatien 0:bfed5767d0a5 428 printf("--------------------\r\n");
donatien 0:bfed5767d0a5 429 }
donatien 0:bfed5767d0a5 430
donatien 0:bfed5767d0a5 431 void USBHost::printInt() {
donatien 0:bfed5767d0a5 432 HCED * hced = (HCED *)interruptHeadED();
donatien 0:bfed5767d0a5 433 HCTD * hctd = NULL;
donatien 0:bfed5767d0a5 434 printf("---------State of Int:--------\r\n");
donatien 0:bfed5767d0a5 435 while (hced != NULL) {
donatien 0:bfed5767d0a5 436 printf("hced: %p\r\n", hced);
donatien 0:bfed5767d0a5 437 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
donatien 0:bfed5767d0a5 438 while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
donatien 0:bfed5767d0a5 439 printf("\thctd: %p\r\n", hctd);
donatien 0:bfed5767d0a5 440 hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
donatien 0:bfed5767d0a5 441 }
donatien 0:bfed5767d0a5 442 printf("\thctd: %p\r\n", hctd);
donatien 0:bfed5767d0a5 443 hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
donatien 0:bfed5767d0a5 444 }
donatien 0:bfed5767d0a5 445 printf("--------------------\r\n");
donatien 0:bfed5767d0a5 446 }
donatien 0:bfed5767d0a5 447
donatien 0:bfed5767d0a5 448
donatien 0:bfed5767d0a5 449 // add a transfer on the TD linked list
donatien 0:bfed5767d0a5 450 USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) {
donatien 0:bfed5767d0a5 451
donatien 0:bfed5767d0a5 452 // allocate a TD which will be freed in TDcompletion
donatien 0:bfed5767d0a5 453 volatile HCTD * td = ed->getNextTD();
donatien 0:bfed5767d0a5 454 if (td == NULL) {
donatien 0:bfed5767d0a5 455 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 456 }
donatien 0:bfed5767d0a5 457
donatien 0:bfed5767d0a5 458 DBG("Next td = %p",td);
donatien 0:bfed5767d0a5 459
donatien 0:bfed5767d0a5 460 uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
donatien 0:bfed5767d0a5 461
donatien 0:bfed5767d0a5 462 uint32_t td_toggle;
donatien 0:bfed5767d0a5 463
donatien 0:bfed5767d0a5 464 if (ed->getType() == CONTROL_ENDPOINT) {
donatien 0:bfed5767d0a5 465 if (ed->isSetup()) {
donatien 0:bfed5767d0a5 466 td_toggle = TD_TOGGLE_0;
donatien 0:bfed5767d0a5 467 } else {
donatien 0:bfed5767d0a5 468 td_toggle = TD_TOGGLE_1;
donatien 0:bfed5767d0a5 469 }
donatien 0:bfed5767d0a5 470 } else {
donatien 0:bfed5767d0a5 471 td_toggle = 0;
donatien 0:bfed5767d0a5 472 }
donatien 0:bfed5767d0a5 473
donatien 0:bfed5767d0a5 474 DBG("Buf=%d, len=%d", buf, len);
donatien 0:bfed5767d0a5 475 td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
donatien 0:bfed5767d0a5 476 td->currBufPtr = (uint32_t) buf;
donatien 0:bfed5767d0a5 477 td->bufEnd = (uint32_t)(buf + (len - 1));
donatien 0:bfed5767d0a5 478
donatien 0:bfed5767d0a5 479 DBG("Now do queue transfer on ep %p", ed);
donatien 0:bfed5767d0a5 480
donatien 0:bfed5767d0a5 481 ed->queueTransfer();
donatien 0:bfed5767d0a5 482
donatien 0:bfed5767d0a5 483 DBG("Enable list if needed");
donatien 0:bfed5767d0a5 484
donatien 0:bfed5767d0a5 485 switch (ed->getType()) {
donatien 0:bfed5767d0a5 486 case CONTROL_ENDPOINT:
donatien 0:bfed5767d0a5 487 enableControlList();
donatien 0:bfed5767d0a5 488 break;
donatien 0:bfed5767d0a5 489 case BULK_ENDPOINT:
donatien 0:bfed5767d0a5 490 enableBulkList();
donatien 0:bfed5767d0a5 491 break;
donatien 0:bfed5767d0a5 492 case INTERRUPT_ENDPOINT:
donatien 0:bfed5767d0a5 493 //printInt();
donatien 0:bfed5767d0a5 494 enableInterruptList();
donatien 0:bfed5767d0a5 495 break;
donatien 0:bfed5767d0a5 496 }
donatien 0:bfed5767d0a5 497
donatien 0:bfed5767d0a5 498 DBG("Wait for HC to process TD");
donatien 0:bfed5767d0a5 499
donatien 0:bfed5767d0a5 500
donatien 0:bfed5767d0a5 501 return USB_TYPE_PROCESSING;
donatien 0:bfed5767d0a5 502 }
donatien 0:bfed5767d0a5 503
donatien 0:bfed5767d0a5 504
donatien 0:bfed5767d0a5 505
donatien 0:bfed5767d0a5 506 USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf) {
donatien 0:bfed5767d0a5 507 return controlRead( dev,
donatien 0:bfed5767d0a5 508 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 509 GET_DESCRIPTOR,
donatien 0:bfed5767d0a5 510 (DEVICE_DESCRIPTOR << 8) | (0),
donatien 0:bfed5767d0a5 511 0,
donatien 0:bfed5767d0a5 512 buf,
donatien 0:bfed5767d0a5 513 DEVICE_DESCRIPTOR_LENGTH);
donatien 0:bfed5767d0a5 514 }
donatien 0:bfed5767d0a5 515
donatien 0:bfed5767d0a5 516 USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t * len_conf_descr) {
donatien 0:bfed5767d0a5 517 USB_TYPE res;
donatien 0:bfed5767d0a5 518 uint16_t total_conf_descr_length = 0;
donatien 0:bfed5767d0a5 519
donatien 0:bfed5767d0a5 520 // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
donatien 0:bfed5767d0a5 521 res = controlRead( dev,
donatien 0:bfed5767d0a5 522 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 523 GET_DESCRIPTOR,
donatien 0:bfed5767d0a5 524 (CONFIGURATION_DESCRIPTOR << 8) | (0),
donatien 0:bfed5767d0a5 525 0,
donatien 0:bfed5767d0a5 526 buf,
donatien 0:bfed5767d0a5 527 CONFIGURATION_DESCRIPTOR_LENGTH);
donatien 0:bfed5767d0a5 528
donatien 0:bfed5767d0a5 529 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 530 ERR("GET CONF 1 DESCR FAILED");
donatien 0:bfed5767d0a5 531 return res;
donatien 0:bfed5767d0a5 532 }
donatien 0:bfed5767d0a5 533 total_conf_descr_length = buf[2] | (buf[3] << 8);
donatien 0:bfed5767d0a5 534 if (len_conf_descr != NULL) {
donatien 0:bfed5767d0a5 535 *len_conf_descr = total_conf_descr_length;
donatien 0:bfed5767d0a5 536 }
donatien 0:bfed5767d0a5 537 DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
donatien 0:bfed5767d0a5 538
donatien 0:bfed5767d0a5 539 return controlRead( dev,
donatien 0:bfed5767d0a5 540 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 541 GET_DESCRIPTOR,
donatien 0:bfed5767d0a5 542 (CONFIGURATION_DESCRIPTOR << 8) | (0),
donatien 0:bfed5767d0a5 543 0,
donatien 0:bfed5767d0a5 544 buf,
donatien 0:bfed5767d0a5 545 total_conf_descr_length);
donatien 0:bfed5767d0a5 546
donatien 0:bfed5767d0a5 547 }
donatien 0:bfed5767d0a5 548
donatien 0:bfed5767d0a5 549 USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf) {
donatien 0:bfed5767d0a5 550 return controlWrite( dev,
donatien 0:bfed5767d0a5 551 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 552 SET_CONFIGURATION,
donatien 0:bfed5767d0a5 553 conf,
donatien 0:bfed5767d0a5 554 0,
donatien 0:bfed5767d0a5 555 NULL,
donatien 0:bfed5767d0a5 556 0);
donatien 0:bfed5767d0a5 557
donatien 0:bfed5767d0a5 558 }
donatien 0:bfed5767d0a5 559
donatien 0:bfed5767d0a5 560
donatien 0:bfed5767d0a5 561 // enumerate a device with the control USBEndpoint
donatien 0:bfed5767d0a5 562 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) {
donatien 0:bfed5767d0a5 563 uint8_t data[384];
donatien 0:bfed5767d0a5 564 uint16_t total_conf_descr_length = 0;
donatien 0:bfed5767d0a5 565 USB_TYPE res;
donatien 0:bfed5767d0a5 566
donatien 0:bfed5767d0a5 567 DBG("data = %p", data);
donatien 0:bfed5767d0a5 568
donatien 0:bfed5767d0a5 569 if (dev->isEnumerated()) {
donatien 0:bfed5767d0a5 570 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 571 }
donatien 0:bfed5767d0a5 572
donatien 0:bfed5767d0a5 573 // first step: get the size of USBEndpoint 0
donatien 0:bfed5767d0a5 574 DBG("Get size of EP 0");
donatien 0:bfed5767d0a5 575 res = controlRead( dev,
donatien 0:bfed5767d0a5 576 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 577 GET_DESCRIPTOR,
donatien 0:bfed5767d0a5 578 (DEVICE_DESCRIPTOR << 8) | (0),
donatien 0:bfed5767d0a5 579 0,
donatien 0:bfed5767d0a5 580 data,
donatien 0:bfed5767d0a5 581 8);
donatien 0:bfed5767d0a5 582
donatien 0:bfed5767d0a5 583 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 584 ERR("Control read failed!!");
donatien 0:bfed5767d0a5 585 return res;
donatien 0:bfed5767d0a5 586 }
donatien 0:bfed5767d0a5 587 dev->setSizeControlEndpoint(data[7]);
donatien 0:bfed5767d0a5 588 DBG("size control USBEndpoint: %d", dev->getSizeControlEndpoint());
donatien 0:bfed5767d0a5 589
donatien 0:bfed5767d0a5 590 DBG("Now set addr");
donatien 0:bfed5767d0a5 591 // second step: set an address to the device
donatien 0:bfed5767d0a5 592 res = controlWrite( dev,
donatien 0:bfed5767d0a5 593 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
donatien 0:bfed5767d0a5 594 SET_ADDRESS,
donatien 0:bfed5767d0a5 595 dev->getAddress(),
donatien 0:bfed5767d0a5 596 0,
donatien 0:bfed5767d0a5 597 NULL,
donatien 0:bfed5767d0a5 598 0);
donatien 0:bfed5767d0a5 599
donatien 0:bfed5767d0a5 600 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 601 DBG("SET ADDR FAILED");
donatien 0:bfed5767d0a5 602 freeDevice(dev);
donatien 0:bfed5767d0a5 603 return res;
donatien 0:bfed5767d0a5 604 }
donatien 0:bfed5767d0a5 605 dev->activeAddress();
donatien 0:bfed5767d0a5 606
donatien 0:bfed5767d0a5 607
donatien 0:bfed5767d0a5 608 // third step: get the whole device descriptor to see vid, pid
donatien 0:bfed5767d0a5 609 res = getDeviceDescriptor(dev, data);
donatien 0:bfed5767d0a5 610
donatien 0:bfed5767d0a5 611 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 612 DBG("GET DEV DESCR FAILED");
donatien 0:bfed5767d0a5 613 return res;
donatien 0:bfed5767d0a5 614 }
donatien 0:bfed5767d0a5 615 dev->setClass(data[4]);
donatien 0:bfed5767d0a5 616 dev->setSubClass(data[5]);
donatien 0:bfed5767d0a5 617 dev->setProtocol(data[6]);
donatien 0:bfed5767d0a5 618 dev->setVid(data[8] | (data[9] << 8));
donatien 0:bfed5767d0a5 619 dev->setPid(data[10] | (data[11] << 8));
donatien 0:bfed5767d0a5 620 DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
donatien 0:bfed5767d0a5 621
donatien 0:bfed5767d0a5 622 pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
donatien 0:bfed5767d0a5 623
donatien 0:bfed5767d0a5 624 res = getConfigurationDescriptor(dev, data, &total_conf_descr_length);
donatien 0:bfed5767d0a5 625 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 626 return res;
donatien 0:bfed5767d0a5 627 }
donatien 0:bfed5767d0a5 628
donatien 0:bfed5767d0a5 629 // Parse the configuration descriptor
donatien 0:bfed5767d0a5 630 parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
donatien 0:bfed5767d0a5 631
donatien 0:bfed5767d0a5 632
donatien 0:bfed5767d0a5 633 // sixth step: set configuration (only 1 supported)
donatien 0:bfed5767d0a5 634 res = setConfiguration(dev, 1);
donatien 0:bfed5767d0a5 635
donatien 0:bfed5767d0a5 636 if (res != USB_TYPE_OK) {
donatien 0:bfed5767d0a5 637 DBG("SET CONF FAILED");
donatien 0:bfed5767d0a5 638 freeDevice(dev);
donatien 0:bfed5767d0a5 639 return res;
donatien 0:bfed5767d0a5 640 }
donatien 0:bfed5767d0a5 641
donatien 0:bfed5767d0a5 642 // Now the device is enumerated!
donatien 0:bfed5767d0a5 643 dev->setEnumerated();
donatien 0:bfed5767d0a5 644 DBG("device enumerated!!!!");
donatien 0:bfed5767d0a5 645
donatien 0:bfed5767d0a5 646 // Some devices may require this delay
donatien 0:bfed5767d0a5 647 Thread::wait(100);
donatien 0:bfed5767d0a5 648
donatien 0:bfed5767d0a5 649 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 650 }
donatien 0:bfed5767d0a5 651
donatien 0:bfed5767d0a5 652 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
donatien 0:bfed5767d0a5 653 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) {
donatien 0:bfed5767d0a5 654 uint32_t index = 0;
donatien 0:bfed5767d0a5 655 uint32_t len_desc = 0;
donatien 0:bfed5767d0a5 656 uint8_t id = 0;
donatien 0:bfed5767d0a5 657 int nb_endpoints_used = 0;
donatien 0:bfed5767d0a5 658 USBEndpoint * ep = NULL;
donatien 0:bfed5767d0a5 659 uint8_t intf_nb = 0;
donatien 0:bfed5767d0a5 660 bool parsing_intf = false;
donatien 0:bfed5767d0a5 661
donatien 0:bfed5767d0a5 662 while (index < len) {
donatien 0:bfed5767d0a5 663 len_desc = conf_descr[index];
donatien 0:bfed5767d0a5 664 id = conf_descr[index+1];
donatien 0:bfed5767d0a5 665 switch (id) {
donatien 0:bfed5767d0a5 666 case CONFIGURATION_DESCRIPTOR:
donatien 0:bfed5767d0a5 667 break;
donatien 0:bfed5767d0a5 668 case INTERFACE_DESCRIPTOR:
donatien 0:bfed5767d0a5 669 if(pEnumerator->parseInterface(intf_nb, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]))
donatien 0:bfed5767d0a5 670 {
donatien 0:bfed5767d0a5 671 if (intf_nb++ <= NB_MAX_INTF) {
donatien 0:bfed5767d0a5 672 dev->addInterface(intf_nb - 1, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
donatien 0:bfed5767d0a5 673 nb_endpoints_used = 0;
donatien 0:bfed5767d0a5 674 DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", intf_nb - 1, (void *)dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
donatien 0:bfed5767d0a5 675 } else {
donatien 0:bfed5767d0a5 676 DBG("Drop intf...");
donatien 0:bfed5767d0a5 677 }
donatien 0:bfed5767d0a5 678 parsing_intf = true;
donatien 0:bfed5767d0a5 679 }
donatien 0:bfed5767d0a5 680 else
donatien 0:bfed5767d0a5 681 {
donatien 0:bfed5767d0a5 682 parsing_intf = false;
donatien 0:bfed5767d0a5 683 }
donatien 0:bfed5767d0a5 684 break;
donatien 0:bfed5767d0a5 685 case ENDPOINT_DESCRIPTOR:
donatien 0:bfed5767d0a5 686 DBG("Ep DESC");
donatien 0:bfed5767d0a5 687 if (parsing_intf && (intf_nb <= NB_MAX_INTF) ) {
donatien 0:bfed5767d0a5 688 if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
donatien 0:bfed5767d0a5 689 if( pEnumerator->useEndpoint(intf_nb - 1, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) )
donatien 0:bfed5767d0a5 690 {
donatien 0:bfed5767d0a5 691 // if the USBEndpoint is isochronous -> skip it (TODO: fix this)
donatien 0:bfed5767d0a5 692 if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
donatien 0:bfed5767d0a5 693 ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
donatien 0:bfed5767d0a5 694 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
donatien 0:bfed5767d0a5 695 conf_descr[index + 4] | (conf_descr[index + 5] << 8),
donatien 0:bfed5767d0a5 696 conf_descr[index + 2] & 0x0f);
donatien 0:bfed5767d0a5 697 DBG("ADD USBEndpoint %p, on interf %d on device %p", (void *)ep, intf_nb - 1, (void *)dev);
donatien 0:bfed5767d0a5 698 if (ep != NULL && dev != NULL) {
donatien 0:bfed5767d0a5 699 addEndpoint(dev, intf_nb - 1, ep);
donatien 0:bfed5767d0a5 700 } else {
donatien 0:bfed5767d0a5 701 DBG("EP NULL");
donatien 0:bfed5767d0a5 702 }
donatien 0:bfed5767d0a5 703 nb_endpoints_used++;
donatien 0:bfed5767d0a5 704 } else {
donatien 0:bfed5767d0a5 705 DBG("ISO USBEndpoint NOT SUPPORTED");
donatien 0:bfed5767d0a5 706 }
donatien 0:bfed5767d0a5 707 }
donatien 0:bfed5767d0a5 708 }
donatien 0:bfed5767d0a5 709 }
donatien 0:bfed5767d0a5 710 //DBG("USBEndpoint DESCR");
donatien 0:bfed5767d0a5 711 break;
donatien 0:bfed5767d0a5 712 case HID_DESCRIPTOR:
donatien 0:bfed5767d0a5 713 lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
donatien 0:bfed5767d0a5 714 break;
donatien 0:bfed5767d0a5 715 default:
donatien 0:bfed5767d0a5 716 break;
donatien 0:bfed5767d0a5 717 }
donatien 0:bfed5767d0a5 718 index += len_desc;
donatien 0:bfed5767d0a5 719 }
donatien 0:bfed5767d0a5 720 }
donatien 0:bfed5767d0a5 721
donatien 0:bfed5767d0a5 722
donatien 0:bfed5767d0a5 723 USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:bfed5767d0a5 724 USB_TYPE res;
donatien 0:bfed5767d0a5 725
donatien 0:bfed5767d0a5 726 if (dev == NULL || ep == NULL) {
donatien 0:bfed5767d0a5 727 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 728 }
donatien 0:bfed5767d0a5 729
donatien 0:bfed5767d0a5 730 if ((ep->getDir() != IN) || (ep->getType() != BULK_ENDPOINT)) {
donatien 0:bfed5767d0a5 731 DBG("wrong dir or bad USBEndpoint type");
donatien 0:bfed5767d0a5 732 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 733 }
donatien 0:bfed5767d0a5 734 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:bfed5767d0a5 735 DBG("USBEndpoint addr and device addr don't match");
donatien 0:bfed5767d0a5 736 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 737 }
donatien 0:bfed5767d0a5 738 addTransfer(ep, buf, len);
donatien 0:bfed5767d0a5 739 if (blocking) {
donatien 0:bfed5767d0a5 740 unlock();
donatien 0:bfed5767d0a5 741 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 742 lock();
donatien 0:bfed5767d0a5 743 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 744 return res;
donatien 0:bfed5767d0a5 745 }
donatien 0:bfed5767d0a5 746 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 747 }
donatien 0:bfed5767d0a5 748 return USB_TYPE_PROCESSING;
donatien 0:bfed5767d0a5 749 }
donatien 0:bfed5767d0a5 750
donatien 0:bfed5767d0a5 751 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:bfed5767d0a5 752 USB_TYPE res;
donatien 0:bfed5767d0a5 753
donatien 0:bfed5767d0a5 754 if (dev == NULL || ep == NULL) {
donatien 0:bfed5767d0a5 755 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 756 }
donatien 0:bfed5767d0a5 757
donatien 0:bfed5767d0a5 758 if ((ep->getDir() != OUT) || (ep->getType() != BULK_ENDPOINT)) {
donatien 0:bfed5767d0a5 759 DBG("wrong dir or bad USBEndpoint type");
donatien 0:bfed5767d0a5 760 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 761 }
donatien 0:bfed5767d0a5 762 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:bfed5767d0a5 763 DBG("USBEndpoint addr and device addr don't match");
donatien 0:bfed5767d0a5 764 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 765 }
donatien 0:bfed5767d0a5 766 addTransfer(ep, buf, len);
donatien 0:bfed5767d0a5 767 if (blocking) {
donatien 0:bfed5767d0a5 768 unlock();
donatien 0:bfed5767d0a5 769 while ((res = control->getState()) == USB_TYPE_PROCESSING)
donatien 0:bfed5767d0a5 770 {
donatien 0:bfed5767d0a5 771 DBG("!!!!!!!!!!!!!wait bulkwrite");
donatien 0:bfed5767d0a5 772 Thread::wait(100);
donatien 0:bfed5767d0a5 773 }
donatien 0:bfed5767d0a5 774 lock();
donatien 0:bfed5767d0a5 775 DBG("!!!!!!!!!!!!! bulkwrite finished");
donatien 0:bfed5767d0a5 776 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 777 return res;
donatien 0:bfed5767d0a5 778 }
donatien 0:bfed5767d0a5 779 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 780 }
donatien 0:bfed5767d0a5 781 return USB_TYPE_PROCESSING;
donatien 0:bfed5767d0a5 782 }
donatien 0:bfed5767d0a5 783
donatien 0:bfed5767d0a5 784 USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:bfed5767d0a5 785 USB_TYPE res;
donatien 0:bfed5767d0a5 786
donatien 0:bfed5767d0a5 787 if (dev == NULL || ep == NULL) {
donatien 0:bfed5767d0a5 788 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 789 }
donatien 0:bfed5767d0a5 790
donatien 0:bfed5767d0a5 791 if (ep->getState() != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 792 return ep->getState();
donatien 0:bfed5767d0a5 793 }
donatien 0:bfed5767d0a5 794
donatien 0:bfed5767d0a5 795 if ((ep->getDir() != OUT) || (ep->getType() != INTERRUPT_ENDPOINT)) {
donatien 0:bfed5767d0a5 796 ERR("wrong dir or bad USBEndpoint type: %d, %d", ep->getDir(), ep->getType());
donatien 0:bfed5767d0a5 797 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 798 }
donatien 0:bfed5767d0a5 799 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:bfed5767d0a5 800 ERR("USBEndpoint addr and device addr don't match");
donatien 0:bfed5767d0a5 801 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 802 }
donatien 0:bfed5767d0a5 803 addTransfer(ep, buf, len);
donatien 0:bfed5767d0a5 804 if (blocking) {
donatien 0:bfed5767d0a5 805 while ((res = ep->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 806 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 807 return res;
donatien 0:bfed5767d0a5 808 }
donatien 0:bfed5767d0a5 809 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 810 }
donatien 0:bfed5767d0a5 811 return USB_TYPE_PROCESSING;
donatien 0:bfed5767d0a5 812 }
donatien 0:bfed5767d0a5 813
donatien 0:bfed5767d0a5 814 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:bfed5767d0a5 815 USB_TYPE res;
donatien 0:bfed5767d0a5 816
donatien 0:bfed5767d0a5 817 if (dev == NULL || ep == NULL) {
donatien 0:bfed5767d0a5 818 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 819 }
donatien 0:bfed5767d0a5 820
donatien 0:bfed5767d0a5 821 if (ep->getState() != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 822 return ep->getState();
donatien 0:bfed5767d0a5 823 }
donatien 0:bfed5767d0a5 824
donatien 0:bfed5767d0a5 825 if ((ep->getDir() != IN) || (ep->getType() != INTERRUPT_ENDPOINT)) {
donatien 0:bfed5767d0a5 826 ERR("wrong dir or bad USBEndpoint type");
donatien 0:bfed5767d0a5 827 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 828 }
donatien 0:bfed5767d0a5 829
donatien 0:bfed5767d0a5 830 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:bfed5767d0a5 831 ERR("USBEndpoint addr and device addr don't match");
donatien 0:bfed5767d0a5 832 return USB_TYPE_ERROR;
donatien 0:bfed5767d0a5 833 }
donatien 0:bfed5767d0a5 834 addTransfer(ep, buf, len);
donatien 0:bfed5767d0a5 835 if (blocking) {
donatien 0:bfed5767d0a5 836 while ((res = ep->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 837 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 838 return res;
donatien 0:bfed5767d0a5 839 }
donatien 0:bfed5767d0a5 840 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 841 }
donatien 0:bfed5767d0a5 842 return USB_TYPE_PROCESSING;
donatien 0:bfed5767d0a5 843 }
donatien 0:bfed5767d0a5 844
donatien 0:bfed5767d0a5 845
donatien 0:bfed5767d0a5 846 USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
donatien 0:bfed5767d0a5 847 int length_transfer = len;
donatien 0:bfed5767d0a5 848 //DBG("want to transfer: %d bytes\r\n", length_transfer);
donatien 0:bfed5767d0a5 849 USB_TYPE res;
donatien 0:bfed5767d0a5 850 control->setSpeed(dev->getSpeed());
donatien 0:bfed5767d0a5 851 control->setSize(dev->getSizeControlEndpoint());
donatien 0:bfed5767d0a5 852 if (dev->isActiveAddress()) {
donatien 0:bfed5767d0a5 853 control->setDeviceAddress(dev->getAddress());
donatien 0:bfed5767d0a5 854 } else {
donatien 0:bfed5767d0a5 855 control->setDeviceAddress(0);
donatien 0:bfed5767d0a5 856 }
donatien 0:bfed5767d0a5 857 fillControlBuf(requestType, request, value, index, len);
donatien 0:bfed5767d0a5 858 /* DBG("will call transfer: ");
donatien 0:bfed5767d0a5 859 for (int i = 0; i < 8; i++) {
donatien 0:bfed5767d0a5 860 DBG("%02X ", setupPacket[i]);
donatien 0:bfed5767d0a5 861 }*/
donatien 0:bfed5767d0a5 862 control->setNextToken(TD_SETUP);
donatien 0:bfed5767d0a5 863 addTransfer(control, (uint8_t*)setupPacket, 8);
donatien 0:bfed5767d0a5 864 DBG("Now wait for TD to be processed");
donatien 0:bfed5767d0a5 865 unlock();
donatien 0:bfed5767d0a5 866 DBG("Unlocked");
donatien 0:bfed5767d0a5 867 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 868 lock();
donatien 0:bfed5767d0a5 869 DBG("TD processed with result %d", res);
donatien 0:bfed5767d0a5 870 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 871 return res;
donatien 0:bfed5767d0a5 872 }
donatien 0:bfed5767d0a5 873
donatien 0:bfed5767d0a5 874 if (length_transfer) {
donatien 0:bfed5767d0a5 875 DBG("In data to be transfered...");
donatien 0:bfed5767d0a5 876 control->setNextToken(TD_IN);
donatien 0:bfed5767d0a5 877 addTransfer(control, (uint8_t *)buf, length_transfer);
donatien 0:bfed5767d0a5 878 unlock();
donatien 0:bfed5767d0a5 879 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 880 lock();
donatien 0:bfed5767d0a5 881 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 882 return res;
donatien 0:bfed5767d0a5 883 }
donatien 0:bfed5767d0a5 884 }
donatien 0:bfed5767d0a5 885
donatien 0:bfed5767d0a5 886 DBG("Transfer NULL packet (OUT)");
donatien 0:bfed5767d0a5 887 control->setNextToken(TD_OUT);
donatien 0:bfed5767d0a5 888 addTransfer(control, NULL, 0);
donatien 0:bfed5767d0a5 889 unlock();
donatien 0:bfed5767d0a5 890 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 891 lock();
donatien 0:bfed5767d0a5 892 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 893 return res;
donatien 0:bfed5767d0a5 894 }
donatien 0:bfed5767d0a5 895 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 896 }
donatien 0:bfed5767d0a5 897
donatien 0:bfed5767d0a5 898
donatien 0:bfed5767d0a5 899 USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
donatien 0:bfed5767d0a5 900 control->setSpeed(dev->getSpeed());
donatien 0:bfed5767d0a5 901
donatien 0:bfed5767d0a5 902 int length_transfer = len;
donatien 0:bfed5767d0a5 903 USB_TYPE res;
donatien 0:bfed5767d0a5 904
donatien 0:bfed5767d0a5 905 control->setSize(dev->getSizeControlEndpoint());
donatien 0:bfed5767d0a5 906 if (dev->isActiveAddress()) {
donatien 0:bfed5767d0a5 907 control->setDeviceAddress(dev->getAddress());
donatien 0:bfed5767d0a5 908 } else {
donatien 0:bfed5767d0a5 909 control->setDeviceAddress(0);
donatien 0:bfed5767d0a5 910 }
donatien 0:bfed5767d0a5 911 fillControlBuf(requestType, request, value, index, len);
donatien 0:bfed5767d0a5 912 /*DBG("will call transfer: ");
donatien 0:bfed5767d0a5 913 for (int i = 0; i < 8; i++) {
donatien 0:bfed5767d0a5 914 printf("%01X ", setupPacket[i]);
donatien 0:bfed5767d0a5 915 }
donatien 0:bfed5767d0a5 916 printf("\r\n");*/
donatien 0:bfed5767d0a5 917 control->setNextToken(TD_SETUP);
donatien 0:bfed5767d0a5 918 addTransfer(control, (uint8_t*)setupPacket, 8);
donatien 0:bfed5767d0a5 919 unlock();
donatien 0:bfed5767d0a5 920 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 921 lock();
donatien 0:bfed5767d0a5 922 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 923 return res;
donatien 0:bfed5767d0a5 924 }
donatien 0:bfed5767d0a5 925
donatien 0:bfed5767d0a5 926 if (length_transfer) {
donatien 0:bfed5767d0a5 927 control->setNextToken(TD_OUT);
donatien 0:bfed5767d0a5 928 addTransfer(control, (uint8_t *)buf, length_transfer);
donatien 0:bfed5767d0a5 929 unlock();
donatien 0:bfed5767d0a5 930 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 931 lock();
donatien 0:bfed5767d0a5 932 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 933 return res;
donatien 0:bfed5767d0a5 934 }
donatien 0:bfed5767d0a5 935 }
donatien 0:bfed5767d0a5 936
donatien 0:bfed5767d0a5 937 control->setNextToken(TD_IN);
donatien 0:bfed5767d0a5 938 addTransfer(control, NULL, 0);
donatien 0:bfed5767d0a5 939 unlock();
donatien 0:bfed5767d0a5 940 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:bfed5767d0a5 941 lock();
donatien 0:bfed5767d0a5 942 if (res != USB_TYPE_IDLE) {
donatien 0:bfed5767d0a5 943 return res;
donatien 0:bfed5767d0a5 944 }
donatien 0:bfed5767d0a5 945 return USB_TYPE_OK;
donatien 0:bfed5767d0a5 946 }
donatien 0:bfed5767d0a5 947
donatien 0:bfed5767d0a5 948
donatien 0:bfed5767d0a5 949 void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, int len) {
donatien 0:bfed5767d0a5 950 #ifdef __BIG_ENDIAN
donatien 0:bfed5767d0a5 951 #error "Must implement BE to LE conv here"
donatien 0:bfed5767d0a5 952 #endif
donatien 0:bfed5767d0a5 953 setupPacket[0] = requestType;
donatien 0:bfed5767d0a5 954 setupPacket[1] = request;
donatien 0:bfed5767d0a5 955 //We are in LE so it's fine
donatien 0:bfed5767d0a5 956 *((uint32_t*)&setupPacket[2]) = value;
donatien 0:bfed5767d0a5 957 *((uint32_t*)&setupPacket[4]) = index;
donatien 0:bfed5767d0a5 958 *((uint32_t*)&setupPacket[6]) = (uint32_t) len;
donatien 0:bfed5767d0a5 959 }
donatien 0:bfed5767d0a5 960