local fork (temporary)

Dependents:   VodafoneUSBModem_bleedingedge2

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Committer:
ashleymills
Date:
Fri Apr 26 16:52:02 2013 +0000
Revision:
27:4de37cd81412
Parent:
17:b8739fd10faf
Some dead code removed.

Who changed what in which revision?

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