local fork (temporary)

Dependents:   VodafoneUSBModem_bleedingedge2

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Tue Jul 31 10:37:16 2012 +0000
Revision:
9:c9e9817c398c
Parent:
8:0d1ec493842c
Child:
10:08bce4cd973a
Child:
12:a712bad7a979
Renamed Endpoint->USBEndpoint because it conflicted with the Socket API! Made some weird symbols mixups happen that made everything explode when the first USB endpoint was allocated.

Who changed what in which revision?

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