USB Host WAN Dongle library

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Mon Jul 30 13:51:34 2012 +0000
Revision:
8:0d1ec493842c
Parent:
7:c4483d48fe96
Child:
9:c9e9817c398c
Vodafone K3772-Z support!

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 0:ae46a0638b2c 91 Endpoint * 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 0:ae46a0638b2c 172 addEndpoint(NULL, 0, (Endpoint*)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 0:ae46a0638b2c 205 Endpoint * 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 0:ae46a0638b2c 213 DBG("Freeing endpoint");
donatien 0:ae46a0638b2c 214 ed = (HCED *)ep->getHCED();
donatien 0:ae46a0638b2c 215 ed->control |= (1 << 13); //sKip bit
donatien 0:ae46a0638b2c 216 DBG("Dequeueing endpoint");
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 0:ae46a0638b2c 224 DBG("Freeing endpoint 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 0:ae46a0638b2c 237 void USBHost::unqueueEndpoint(Endpoint * ep) {
donatien 0:ae46a0638b2c 238 Endpoint * prec = NULL;
donatien 0:ae46a0638b2c 239 Endpoint * 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 0:ae46a0638b2c 246 DBG("endpoint unqueued: %p", (void *)ep->getHCED());
donatien 0:ae46a0638b2c 247 break;
donatien 0:ae46a0638b2c 248 }
donatien 0:ae46a0638b2c 249 current = (i == 0) ? (Endpoint*)headBulkEndpoint : (Endpoint*)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 0:ae46a0638b2c 296 // create an endpoint descriptor. the endpoint is not linked
donatien 0:ae46a0638b2c 297 Endpoint * 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 0:ae46a0638b2c 305 // search a free endpoint
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 0:ae46a0638b2c 311 DBG("Endpoint 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 0:ae46a0638b2c 328 // link the endpoint to the linked list and attach an endpoint to a device
donatien 0:ae46a0638b2c 329 bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, Endpoint * 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 0:ae46a0638b2c 339 // set device address in the endpoint 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 0:ae46a0638b2c 347 DBG("add endpoint: set speed");
donatien 0:ae46a0638b2c 348 ep->setSpeed(dev->getSpeed());
donatien 0:ae46a0638b2c 349 }
donatien 0:ae46a0638b2c 350
donatien 0:ae46a0638b2c 351 // queue the new endpoint 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 0:ae46a0638b2c 358 DBG("First control endpoint: %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 0:ae46a0638b2c 371 //DBG("First bulk endpoint: %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 0:ae46a0638b2c 384 //DBG("First interrupt endpoint: %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 0:ae46a0638b2c 449 USB_TYPE USBHost::addTransfer(Endpoint * 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 0:ae46a0638b2c 560 // enumerate a device with the control endpoint
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 0:ae46a0638b2c 572 // first step: get the size of endpoint 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 0:ae46a0638b2c 587 DBG("size control Endpoint: %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 0:ae46a0638b2c 657 Endpoint * 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 6:075e36a3463e 690 // if the endpoint 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 6:075e36a3463e 696 DBG("ADD ENDPOINT %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 6:075e36a3463e 704 DBG("ISO ENDPOINT NOT SUPPORTED");
donatien 0:ae46a0638b2c 705 }
donatien 0:ae46a0638b2c 706 }
donatien 0:ae46a0638b2c 707 }
donatien 0:ae46a0638b2c 708 }
donatien 3:4394986752db 709 //DBG("ENDPOINT 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 0:ae46a0638b2c 722 USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, Endpoint * 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 0:ae46a0638b2c 730 DBG("wrong dir or bad endpoint type");
donatien 0:ae46a0638b2c 731 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 732 }
donatien 0:ae46a0638b2c 733 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:ae46a0638b2c 734 DBG("endpoint 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 0:ae46a0638b2c 750 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, Endpoint * 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 0:ae46a0638b2c 758 DBG("wrong dir or bad endpoint type");
donatien 0:ae46a0638b2c 759 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 760 }
donatien 0:ae46a0638b2c 761 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 0:ae46a0638b2c 762 DBG("endpoint 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 0:ae46a0638b2c 783 USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, Endpoint * 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 0:ae46a0638b2c 795 ERR("wrong dir or bad endpoint 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 0:ae46a0638b2c 799 ERR("endpoint 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 0:ae46a0638b2c 813 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, Endpoint * 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 0:ae46a0638b2c 825 ERR("wrong dir or bad endpoint 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 0:ae46a0638b2c 830 ERR("endpoint 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