USB Host WAN Dongle library

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Thu Aug 30 14:13:24 2012 +0000
Revision:
11:a0841fba0599
Parent:
10:08bce4cd973a
Child:
13:c154e7f2e42f
Added error checks in initialization code

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 0:ae46a0638b2c 24 #include "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])) {
donatien 0:ae46a0638b2c 288 return NULL;
donatien 0:ae46a0638b2c 289 }
donatien 0:ae46a0638b2c 290 return (USBDeviceConnected*)&devices[index];
donatien 0:ae46a0638b2c 291 }
donatien 0:ae46a0638b2c 292
donatien 0:ae46a0638b2c 293
donatien 0:ae46a0638b2c 294
donatien 9:c9e9817c398c 295 // create an USBEndpoint descriptor. the USBEndpoint is not linked
donatien 9:c9e9817c398c 296 USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) {
donatien 0:ae46a0638b2c 297 int i = 0;
donatien 0:ae46a0638b2c 298 HCED * ed = (HCED *)getED();
donatien 0:ae46a0638b2c 299 HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
donatien 0:ae46a0638b2c 300
donatien 0:ae46a0638b2c 301 memset((void *)td_list[0], 0x00, sizeof(HCTD));
donatien 0:ae46a0638b2c 302 memset((void *)td_list[1], 0x00, sizeof(HCTD));
donatien 0:ae46a0638b2c 303
donatien 9:c9e9817c398c 304 // search a free USBEndpoint
donatien 0:ae46a0638b2c 305 for (i = 0; i < MAX_ENDPOINT; i++) {
donatien 0:ae46a0638b2c 306 if (endpoints[i].getState() == USB_TYPE_FREE) {
donatien 0:ae46a0638b2c 307 DBG("Trying to create ep");
donatien 0:ae46a0638b2c 308 endpoints[i].init(ed, type, dir, size, addr, td_list);
donatien 0:ae46a0638b2c 309 //endpoints[i].queueTransfer(nullTd);
donatien 9:c9e9817c398c 310 DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d", &endpoints[i], type, dir, size, addr);
donatien 0:ae46a0638b2c 311 return &endpoints[i];
donatien 0:ae46a0638b2c 312 }
donatien 0:ae46a0638b2c 313 }
donatien 0:ae46a0638b2c 314 DBG("could not allocate more endpoints!!!!");
donatien 0:ae46a0638b2c 315 return NULL;
donatien 0:ae46a0638b2c 316 }
donatien 0:ae46a0638b2c 317
donatien 0:ae46a0638b2c 318
donatien 11:a0841fba0599 319 USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev) {
donatien 0:ae46a0638b2c 320 int index = findDevice(dev);
donatien 0:ae46a0638b2c 321 if ((index != -1) && (!deviceReset[index])) {
donatien 0:ae46a0638b2c 322 resetPort(dev->getHub(), dev->getPort());
donatien 0:ae46a0638b2c 323 deviceReset[index] = true;
donatien 11:a0841fba0599 324 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 325 }
donatien 11:a0841fba0599 326 return USB_TYPE_NOTFOUND;
donatien 0:ae46a0638b2c 327 }
donatien 0:ae46a0638b2c 328
donatien 9:c9e9817c398c 329 // link the USBEndpoint to the linked list and attach an USBEndpoint to a device
donatien 9:c9e9817c398c 330 bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) {
donatien 0:ae46a0638b2c 331
donatien 0:ae46a0638b2c 332 if (ep == NULL) {
donatien 0:ae46a0638b2c 333 return false;
donatien 0:ae46a0638b2c 334 }
donatien 0:ae46a0638b2c 335
donatien 0:ae46a0638b2c 336 DBG("New ep %p", ep);
donatien 0:ae46a0638b2c 337
donatien 0:ae46a0638b2c 338 HCED * prevEd;
donatien 0:ae46a0638b2c 339
donatien 9:c9e9817c398c 340 // set device address in the USBEndpoint descriptor
donatien 0:ae46a0638b2c 341 if (dev == NULL) {
donatien 0:ae46a0638b2c 342 ep->setDeviceAddress(0);
donatien 0:ae46a0638b2c 343 } else {
donatien 0:ae46a0638b2c 344 ep->setDeviceAddress(dev->getAddress());
donatien 0:ae46a0638b2c 345 }
donatien 0:ae46a0638b2c 346
donatien 0:ae46a0638b2c 347 if (dev != NULL && dev->getSpeed()) {
donatien 9:c9e9817c398c 348 DBG("add USBEndpoint: set speed");
donatien 0:ae46a0638b2c 349 ep->setSpeed(dev->getSpeed());
donatien 0:ae46a0638b2c 350 }
donatien 0:ae46a0638b2c 351
donatien 9:c9e9817c398c 352 // queue the new USBEndpoint on the ED list
donatien 0:ae46a0638b2c 353 switch (ep->getType()) {
donatien 0:ae46a0638b2c 354
donatien 0:ae46a0638b2c 355 case CONTROL_ENDPOINT:
donatien 0:ae46a0638b2c 356 prevEd = ( HCED*) controlHeadED();
donatien 0:ae46a0638b2c 357 if (!prevEd) {
donatien 0:ae46a0638b2c 358 updateControlHeadED((uint32_t) ep->getHCED());
donatien 9:c9e9817c398c 359 DBG("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
donatien 0:ae46a0638b2c 360 headControlEndpoint = ep;
donatien 0:ae46a0638b2c 361 tailControlEndpoint = ep;
donatien 0:ae46a0638b2c 362 return true;
donatien 0:ae46a0638b2c 363 }
donatien 0:ae46a0638b2c 364 tailControlEndpoint->queueEndpoint(ep);
donatien 0:ae46a0638b2c 365 tailControlEndpoint = ep;
donatien 0:ae46a0638b2c 366 return true;
donatien 0:ae46a0638b2c 367
donatien 0:ae46a0638b2c 368 case BULK_ENDPOINT:
donatien 0:ae46a0638b2c 369 prevEd = ( HCED*) bulkHeadED();
donatien 0:ae46a0638b2c 370 if (!prevEd) {
donatien 0:ae46a0638b2c 371 updateBulkHeadED((uint32_t) ep->getHCED());
donatien 9:c9e9817c398c 372 //DBG("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
donatien 0:ae46a0638b2c 373 headBulkEndpoint = ep;
donatien 0:ae46a0638b2c 374 tailBulkEndpoint = ep;
donatien 0:ae46a0638b2c 375 break;
donatien 0:ae46a0638b2c 376 }
donatien 0:ae46a0638b2c 377 tailBulkEndpoint->queueEndpoint(ep);
donatien 0:ae46a0638b2c 378 tailBulkEndpoint = ep;
donatien 0:ae46a0638b2c 379 break;
donatien 0:ae46a0638b2c 380
donatien 0:ae46a0638b2c 381 case INTERRUPT_ENDPOINT:
donatien 0:ae46a0638b2c 382 prevEd = ( HCED*) interruptHeadED();
donatien 0:ae46a0638b2c 383 if (!prevEd) {
donatien 0:ae46a0638b2c 384 updateInterruptHeadED((uint32_t) ep->getHCED());
donatien 9:c9e9817c398c 385 //DBG("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
donatien 0:ae46a0638b2c 386 headInterruptEndpoint = ep;
donatien 0:ae46a0638b2c 387 tailInterruptEndpoint = ep;
donatien 0:ae46a0638b2c 388 break;
donatien 0:ae46a0638b2c 389 }
donatien 0:ae46a0638b2c 390 tailInterruptEndpoint->queueEndpoint(ep);
donatien 0:ae46a0638b2c 391 tailInterruptEndpoint = ep;
donatien 0:ae46a0638b2c 392 break;
donatien 0:ae46a0638b2c 393 default:
donatien 0:ae46a0638b2c 394 return false;
donatien 0:ae46a0638b2c 395 }
donatien 0:ae46a0638b2c 396
donatien 0:ae46a0638b2c 397 dev->addEndpoint(intf_nb, ep);
donatien 0:ae46a0638b2c 398 //printBulk();
donatien 0:ae46a0638b2c 399 //printInt();
donatien 0:ae46a0638b2c 400
donatien 0:ae46a0638b2c 401 return true;
donatien 0:ae46a0638b2c 402 }
donatien 0:ae46a0638b2c 403
donatien 0:ae46a0638b2c 404
donatien 0:ae46a0638b2c 405 int USBHost::findDevice(USBDeviceConnected * dev) {
donatien 0:ae46a0638b2c 406 for (int i = 0; i < MAX_DEVICE_NB; i++) {
donatien 0:ae46a0638b2c 407 if (dev == &devices[i]) {
donatien 0:ae46a0638b2c 408 return i;
donatien 0:ae46a0638b2c 409 }
donatien 0:ae46a0638b2c 410 }
donatien 0:ae46a0638b2c 411 return -1;
donatien 0:ae46a0638b2c 412 }
donatien 0:ae46a0638b2c 413
donatien 0:ae46a0638b2c 414 void USBHost::printBulk() {
donatien 0:ae46a0638b2c 415 HCED * hced = (HCED *)bulkHeadED();
donatien 0:ae46a0638b2c 416 HCTD * hctd = NULL;
donatien 0:ae46a0638b2c 417 printf("---------State of Bulk:--------\r\n");
donatien 0:ae46a0638b2c 418 while (hced != NULL) {
donatien 0:ae46a0638b2c 419 printf("hced: %p\r\n", hced);
donatien 0:ae46a0638b2c 420 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
donatien 0:ae46a0638b2c 421 while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
donatien 0:ae46a0638b2c 422 printf("\thctd: %p\r\n", hctd);
donatien 0:ae46a0638b2c 423 hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
donatien 0:ae46a0638b2c 424 }
donatien 0:ae46a0638b2c 425 printf("\thctd: %p\r\n", hctd);
donatien 0:ae46a0638b2c 426 hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
donatien 0:ae46a0638b2c 427 }
donatien 0:ae46a0638b2c 428 printf("--------------------\r\n");
donatien 0:ae46a0638b2c 429 }
donatien 0:ae46a0638b2c 430
donatien 0:ae46a0638b2c 431 void USBHost::printInt() {
donatien 0:ae46a0638b2c 432 HCED * hced = (HCED *)interruptHeadED();
donatien 0:ae46a0638b2c 433 HCTD * hctd = NULL;
donatien 0:ae46a0638b2c 434 printf("---------State of Int:--------\r\n");
donatien 0:ae46a0638b2c 435 while (hced != NULL) {
donatien 0:ae46a0638b2c 436 printf("hced: %p\r\n", hced);
donatien 0:ae46a0638b2c 437 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
donatien 0:ae46a0638b2c 438 while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
donatien 0:ae46a0638b2c 439 printf("\thctd: %p\r\n", hctd);
donatien 0:ae46a0638b2c 440 hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
donatien 0:ae46a0638b2c 441 }
donatien 0:ae46a0638b2c 442 printf("\thctd: %p\r\n", hctd);
donatien 0:ae46a0638b2c 443 hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
donatien 0:ae46a0638b2c 444 }
donatien 0:ae46a0638b2c 445 printf("--------------------\r\n");
donatien 0:ae46a0638b2c 446 }
donatien 0:ae46a0638b2c 447
donatien 0:ae46a0638b2c 448
donatien 0:ae46a0638b2c 449 // add a transfer on the TD linked list
donatien 9:c9e9817c398c 450 USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) {
donatien 0:ae46a0638b2c 451
donatien 0:ae46a0638b2c 452 // allocate a TD which will be freed in TDcompletion
donatien 0:ae46a0638b2c 453 volatile HCTD * td = ed->getNextTD();
donatien 0:ae46a0638b2c 454 if (td == NULL) {
donatien 0:ae46a0638b2c 455 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 456 }
donatien 0:ae46a0638b2c 457
donatien 0:ae46a0638b2c 458 DBG("Next td = %p",td);
donatien 0:ae46a0638b2c 459
donatien 0:ae46a0638b2c 460 uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
donatien 0:ae46a0638b2c 461
donatien 0:ae46a0638b2c 462 uint32_t td_toggle;
donatien 0:ae46a0638b2c 463
donatien 0:ae46a0638b2c 464 if (ed->getType() == CONTROL_ENDPOINT) {
donatien 0:ae46a0638b2c 465 if (ed->isSetup()) {
donatien 0:ae46a0638b2c 466 td_toggle = TD_TOGGLE_0;
donatien 0:ae46a0638b2c 467 } else {
donatien 0:ae46a0638b2c 468 td_toggle = TD_TOGGLE_1;
donatien 0:ae46a0638b2c 469 }
donatien 0:ae46a0638b2c 470 } else {
donatien 0:ae46a0638b2c 471 td_toggle = 0;
donatien 0:ae46a0638b2c 472 }
donatien 0:ae46a0638b2c 473
donatien 0:ae46a0638b2c 474 DBG("Buf=%d, len=%d", buf, len);
donatien 0:ae46a0638b2c 475 td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
donatien 0:ae46a0638b2c 476 td->currBufPtr = (uint32_t) buf;
donatien 0:ae46a0638b2c 477 td->bufEnd = (uint32_t)(buf + (len - 1));
donatien 0:ae46a0638b2c 478
donatien 0:ae46a0638b2c 479 DBG("Now do queue transfer on ep %p", ed);
donatien 0:ae46a0638b2c 480
donatien 0:ae46a0638b2c 481 ed->queueTransfer();
donatien 0:ae46a0638b2c 482
donatien 0:ae46a0638b2c 483 DBG("Enable list if needed");
donatien 0:ae46a0638b2c 484
donatien 0:ae46a0638b2c 485 switch (ed->getType()) {
donatien 0:ae46a0638b2c 486 case CONTROL_ENDPOINT:
donatien 0:ae46a0638b2c 487 enableControlList();
donatien 0:ae46a0638b2c 488 break;
donatien 0:ae46a0638b2c 489 case BULK_ENDPOINT:
donatien 0:ae46a0638b2c 490 enableBulkList();
donatien 0:ae46a0638b2c 491 break;
donatien 0:ae46a0638b2c 492 case INTERRUPT_ENDPOINT:
donatien 0:ae46a0638b2c 493 //printInt();
donatien 0:ae46a0638b2c 494 enableInterruptList();
donatien 0:ae46a0638b2c 495 break;
donatien 0:ae46a0638b2c 496 }
donatien 0:ae46a0638b2c 497
donatien 0:ae46a0638b2c 498 DBG("Wait for HC to process TD");
donatien 0:ae46a0638b2c 499
donatien 0:ae46a0638b2c 500
donatien 0:ae46a0638b2c 501 return USB_TYPE_PROCESSING;
donatien 0:ae46a0638b2c 502 }
donatien 0:ae46a0638b2c 503
donatien 0:ae46a0638b2c 504
donatien 0:ae46a0638b2c 505
donatien 0:ae46a0638b2c 506 USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf) {
donatien 0:ae46a0638b2c 507 return controlRead( dev,
donatien 0:ae46a0638b2c 508 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 509 GET_DESCRIPTOR,
donatien 0:ae46a0638b2c 510 (DEVICE_DESCRIPTOR << 8) | (0),
donatien 0:ae46a0638b2c 511 0,
donatien 0:ae46a0638b2c 512 buf,
donatien 0:ae46a0638b2c 513 DEVICE_DESCRIPTOR_LENGTH);
donatien 0:ae46a0638b2c 514 }
donatien 0:ae46a0638b2c 515
donatien 8:0d1ec493842c 516 USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t * len_conf_descr) {
donatien 0:ae46a0638b2c 517 USB_TYPE res;
donatien 8:0d1ec493842c 518 uint16_t total_conf_descr_length = 0;
donatien 0:ae46a0638b2c 519
donatien 0:ae46a0638b2c 520 // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
donatien 0:ae46a0638b2c 521 res = controlRead( dev,
donatien 0:ae46a0638b2c 522 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 523 GET_DESCRIPTOR,
donatien 0:ae46a0638b2c 524 (CONFIGURATION_DESCRIPTOR << 8) | (0),
donatien 0:ae46a0638b2c 525 0,
donatien 0:ae46a0638b2c 526 buf,
donatien 0:ae46a0638b2c 527 CONFIGURATION_DESCRIPTOR_LENGTH);
donatien 0:ae46a0638b2c 528
donatien 0:ae46a0638b2c 529 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 530 ERR("GET CONF 1 DESCR FAILED");
donatien 0:ae46a0638b2c 531 return res;
donatien 0:ae46a0638b2c 532 }
donatien 0:ae46a0638b2c 533 total_conf_descr_length = buf[2] | (buf[3] << 8);
donatien 0:ae46a0638b2c 534 if (len_conf_descr != NULL) {
donatien 0:ae46a0638b2c 535 *len_conf_descr = total_conf_descr_length;
donatien 0:ae46a0638b2c 536 }
donatien 0:ae46a0638b2c 537 DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
donatien 0:ae46a0638b2c 538
donatien 0:ae46a0638b2c 539 return controlRead( dev,
donatien 0:ae46a0638b2c 540 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 541 GET_DESCRIPTOR,
donatien 0:ae46a0638b2c 542 (CONFIGURATION_DESCRIPTOR << 8) | (0),
donatien 0:ae46a0638b2c 543 0,
donatien 0:ae46a0638b2c 544 buf,
donatien 0:ae46a0638b2c 545 total_conf_descr_length);
donatien 0:ae46a0638b2c 546
donatien 0:ae46a0638b2c 547 }
donatien 0:ae46a0638b2c 548
donatien 0:ae46a0638b2c 549 USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf) {
donatien 0:ae46a0638b2c 550 return controlWrite( dev,
donatien 0:ae46a0638b2c 551 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 552 SET_CONFIGURATION,
donatien 0:ae46a0638b2c 553 conf,
donatien 0:ae46a0638b2c 554 0,
donatien 0:ae46a0638b2c 555 NULL,
donatien 0:ae46a0638b2c 556 0);
donatien 0:ae46a0638b2c 557
donatien 0:ae46a0638b2c 558 }
donatien 0:ae46a0638b2c 559
donatien 0:ae46a0638b2c 560
donatien 9:c9e9817c398c 561 // enumerate a device with the control USBEndpoint
donatien 6:075e36a3463e 562 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) {
donatien 8:0d1ec493842c 563 uint8_t data[384];
donatien 8:0d1ec493842c 564 uint16_t total_conf_descr_length = 0;
donatien 0:ae46a0638b2c 565 USB_TYPE res;
donatien 0:ae46a0638b2c 566
donatien 0:ae46a0638b2c 567 DBG("data = %p", data);
donatien 0:ae46a0638b2c 568
donatien 0:ae46a0638b2c 569 if (dev->isEnumerated()) {
donatien 0:ae46a0638b2c 570 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 571 }
donatien 0:ae46a0638b2c 572
donatien 9:c9e9817c398c 573 // first step: get the size of USBEndpoint 0
donatien 0:ae46a0638b2c 574 DBG("Get size of EP 0");
donatien 0:ae46a0638b2c 575 res = controlRead( dev,
donatien 0:ae46a0638b2c 576 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 577 GET_DESCRIPTOR,
donatien 0:ae46a0638b2c 578 (DEVICE_DESCRIPTOR << 8) | (0),
donatien 0:ae46a0638b2c 579 0,
donatien 0:ae46a0638b2c 580 data,
donatien 0:ae46a0638b2c 581 8);
donatien 0:ae46a0638b2c 582
donatien 0:ae46a0638b2c 583 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 584 ERR("Control read failed!!");
donatien 0:ae46a0638b2c 585 return res;
donatien 0:ae46a0638b2c 586 }
donatien 0:ae46a0638b2c 587 dev->setSizeControlEndpoint(data[7]);
donatien 9:c9e9817c398c 588 DBG("size control USBEndpoint: %d", dev->getSizeControlEndpoint());
donatien 6:075e36a3463e 589
donatien 0:ae46a0638b2c 590 DBG("Now set addr");
donatien 0:ae46a0638b2c 591 // second step: set an address to the device
donatien 0:ae46a0638b2c 592 res = controlWrite( dev,
donatien 0:ae46a0638b2c 593 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
donatien 0:ae46a0638b2c 594 SET_ADDRESS,
donatien 0:ae46a0638b2c 595 dev->getAddress(),
donatien 0:ae46a0638b2c 596 0,
donatien 0:ae46a0638b2c 597 NULL,
donatien 0:ae46a0638b2c 598 0);
donatien 0:ae46a0638b2c 599
donatien 0:ae46a0638b2c 600 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 601 DBG("SET ADDR FAILED");
donatien 0:ae46a0638b2c 602 freeDevice(dev);
donatien 0:ae46a0638b2c 603 return res;
donatien 0:ae46a0638b2c 604 }
donatien 0:ae46a0638b2c 605 dev->activeAddress();
donatien 0:ae46a0638b2c 606
donatien 0:ae46a0638b2c 607
donatien 0:ae46a0638b2c 608 // third step: get the whole device descriptor to see vid, pid
donatien 0:ae46a0638b2c 609 res = getDeviceDescriptor(dev, data);
donatien 0:ae46a0638b2c 610
donatien 0:ae46a0638b2c 611 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 612 DBG("GET DEV DESCR FAILED");
donatien 0:ae46a0638b2c 613 return res;
donatien 0:ae46a0638b2c 614 }
donatien 0:ae46a0638b2c 615 dev->setClass(data[4]);
donatien 0:ae46a0638b2c 616 dev->setSubClass(data[5]);
donatien 0:ae46a0638b2c 617 dev->setProtocol(data[6]);
donatien 0:ae46a0638b2c 618 dev->setVid(data[8] | (data[9] << 8));
donatien 0:ae46a0638b2c 619 dev->setPid(data[10] | (data[11] << 8));
donatien 0:ae46a0638b2c 620 DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
donatien 6:075e36a3463e 621
donatien 6:075e36a3463e 622 pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
donatien 0:ae46a0638b2c 623
donatien 0:ae46a0638b2c 624 res = getConfigurationDescriptor(dev, data, &total_conf_descr_length);
donatien 0:ae46a0638b2c 625 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 626 return res;
donatien 0:ae46a0638b2c 627 }
donatien 0:ae46a0638b2c 628
donatien 0:ae46a0638b2c 629 // Parse the configuration descriptor
donatien 6:075e36a3463e 630 parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
donatien 0:ae46a0638b2c 631
donatien 0:ae46a0638b2c 632
donatien 0:ae46a0638b2c 633 // sixth step: set configuration (only 1 supported)
donatien 0:ae46a0638b2c 634 res = setConfiguration(dev, 1);
donatien 0:ae46a0638b2c 635
donatien 0:ae46a0638b2c 636 if (res != USB_TYPE_OK) {
donatien 0:ae46a0638b2c 637 DBG("SET CONF FAILED");
donatien 0:ae46a0638b2c 638 freeDevice(dev);
donatien 0:ae46a0638b2c 639 return res;
donatien 0:ae46a0638b2c 640 }
donatien 0:ae46a0638b2c 641
donatien 0:ae46a0638b2c 642 // Now the device is enumerated!
donatien 0:ae46a0638b2c 643 dev->setEnumerated();
donatien 0:ae46a0638b2c 644 DBG("device enumerated!!!!");
donatien 0:ae46a0638b2c 645
donatien 0:ae46a0638b2c 646 // Some devices may require this delay
donatien 0:ae46a0638b2c 647 Thread::wait(100);
donatien 0:ae46a0638b2c 648
donatien 0:ae46a0638b2c 649 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 650 }
donatien 0:ae46a0638b2c 651
donatien 0:ae46a0638b2c 652 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
donatien 6:075e36a3463e 653 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) {
donatien 0:ae46a0638b2c 654 uint32_t index = 0;
donatien 0:ae46a0638b2c 655 uint32_t len_desc = 0;
donatien 0:ae46a0638b2c 656 uint8_t id = 0;
donatien 0:ae46a0638b2c 657 int nb_endpoints_used = 0;
donatien 9:c9e9817c398c 658 USBEndpoint * ep = NULL;
donatien 0:ae46a0638b2c 659 uint8_t intf_nb = 0;
donatien 6:075e36a3463e 660 bool parsing_intf = false;
donatien 0:ae46a0638b2c 661
donatien 0:ae46a0638b2c 662 while (index < len) {
donatien 0:ae46a0638b2c 663 len_desc = conf_descr[index];
donatien 0:ae46a0638b2c 664 id = conf_descr[index+1];
donatien 0:ae46a0638b2c 665 switch (id) {
donatien 0:ae46a0638b2c 666 case CONFIGURATION_DESCRIPTOR:
donatien 0:ae46a0638b2c 667 break;
donatien 0:ae46a0638b2c 668 case INTERFACE_DESCRIPTOR:
donatien 6:075e36a3463e 669 if(pEnumerator->parseInterface(intf_nb, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]))
donatien 6:075e36a3463e 670 {
donatien 6:075e36a3463e 671 if (intf_nb++ <= NB_MAX_INTF) {
donatien 6:075e36a3463e 672 dev->addInterface(intf_nb - 1, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
donatien 6:075e36a3463e 673 nb_endpoints_used = 0;
donatien 6:075e36a3463e 674 DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", intf_nb - 1, (void *)dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
donatien 6:075e36a3463e 675 } else {
donatien 6:075e36a3463e 676 DBG("Drop intf...");
donatien 6:075e36a3463e 677 }
donatien 6:075e36a3463e 678 parsing_intf = true;
donatien 6:075e36a3463e 679 }
donatien 6:075e36a3463e 680 else
donatien 6:075e36a3463e 681 {
donatien 6:075e36a3463e 682 parsing_intf = false;
donatien 0:ae46a0638b2c 683 }
donatien 0:ae46a0638b2c 684 break;
donatien 0:ae46a0638b2c 685 case ENDPOINT_DESCRIPTOR:
donatien 3:4394986752db 686 DBG("Ep DESC");
donatien 6:075e36a3463e 687 if (parsing_intf && (intf_nb <= NB_MAX_INTF) ) {
donatien 0:ae46a0638b2c 688 if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
donatien 6:075e36a3463e 689 if( pEnumerator->useEndpoint(intf_nb - 1, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) )
donatien 6:075e36a3463e 690 {
donatien 9:c9e9817c398c 691 // if the USBEndpoint is isochronous -> skip it (TODO: fix this)
donatien 6:075e36a3463e 692 if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
donatien 6:075e36a3463e 693 ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
donatien 6:075e36a3463e 694 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
donatien 6:075e36a3463e 695 conf_descr[index + 4] | (conf_descr[index + 5] << 8),
donatien 6:075e36a3463e 696 conf_descr[index + 2] & 0x0f);
donatien 9:c9e9817c398c 697 DBG("ADD USBEndpoint %p, on interf %d on device %p", (void *)ep, intf_nb - 1, (void *)dev);
donatien 6:075e36a3463e 698 if (ep != NULL && dev != NULL) {
donatien 6:075e36a3463e 699 addEndpoint(dev, intf_nb - 1, ep);
donatien 6:075e36a3463e 700 } else {
donatien 6:075e36a3463e 701 DBG("EP NULL");
donatien 6:075e36a3463e 702 }
donatien 6:075e36a3463e 703 nb_endpoints_used++;
donatien 0:ae46a0638b2c 704 } else {
donatien 9:c9e9817c398c 705 DBG("ISO USBEndpoint NOT SUPPORTED");
donatien 0:ae46a0638b2c 706 }
donatien 0:ae46a0638b2c 707 }
donatien 0:ae46a0638b2c 708 }
donatien 0:ae46a0638b2c 709 }
donatien 9:c9e9817c398c 710 //DBG("USBEndpoint DESCR");
donatien 0:ae46a0638b2c 711 break;
donatien 0:ae46a0638b2c 712 case HID_DESCRIPTOR:
donatien 0:ae46a0638b2c 713 lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
donatien 0:ae46a0638b2c 714 break;
donatien 0:ae46a0638b2c 715 default:
donatien 0:ae46a0638b2c 716 break;
donatien 0:ae46a0638b2c 717 }
donatien 0:ae46a0638b2c 718 index += len_desc;
donatien 0:ae46a0638b2c 719 }
donatien 0:ae46a0638b2c 720 }
donatien 0:ae46a0638b2c 721
donatien 0:ae46a0638b2c 722
donatien 9:c9e9817c398c 723 USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:ae46a0638b2c 724 USB_TYPE res;
donatien 0:ae46a0638b2c 725
donatien 0:ae46a0638b2c 726 if (dev == NULL || ep == NULL) {
donatien 0:ae46a0638b2c 727 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 728 }
donatien 0:ae46a0638b2c 729
donatien 0:ae46a0638b2c 730 if ((ep->getDir() != IN) || (ep->getType() != BULK_ENDPOINT)) {
donatien 9:c9e9817c398c 731 DBG("wrong dir or bad USBEndpoint type");
donatien 0:ae46a0638b2c 732 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 733 }
donatien 0:ae46a0638b2c 734 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 9:c9e9817c398c 735 DBG("USBEndpoint addr and device addr don't match");
donatien 0:ae46a0638b2c 736 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 737 }
donatien 0:ae46a0638b2c 738 addTransfer(ep, buf, len);
donatien 0:ae46a0638b2c 739 if (blocking) {
donatien 0:ae46a0638b2c 740 unlock();
donatien 0:ae46a0638b2c 741 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 742 lock();
donatien 0:ae46a0638b2c 743 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 744 return res;
donatien 0:ae46a0638b2c 745 }
donatien 0:ae46a0638b2c 746 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 747 }
donatien 0:ae46a0638b2c 748 return USB_TYPE_PROCESSING;
donatien 0:ae46a0638b2c 749 }
donatien 0:ae46a0638b2c 750
donatien 9:c9e9817c398c 751 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:ae46a0638b2c 752 USB_TYPE res;
donatien 0:ae46a0638b2c 753
donatien 0:ae46a0638b2c 754 if (dev == NULL || ep == NULL) {
donatien 0:ae46a0638b2c 755 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 756 }
donatien 0:ae46a0638b2c 757
donatien 0:ae46a0638b2c 758 if ((ep->getDir() != OUT) || (ep->getType() != BULK_ENDPOINT)) {
donatien 9:c9e9817c398c 759 DBG("wrong dir or bad USBEndpoint type");
donatien 0:ae46a0638b2c 760 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 761 }
donatien 0:ae46a0638b2c 762 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 9:c9e9817c398c 763 DBG("USBEndpoint addr and device addr don't match");
donatien 0:ae46a0638b2c 764 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 765 }
donatien 0:ae46a0638b2c 766 addTransfer(ep, buf, len);
donatien 0:ae46a0638b2c 767 if (blocking) {
donatien 0:ae46a0638b2c 768 unlock();
donatien 0:ae46a0638b2c 769 while ((res = control->getState()) == USB_TYPE_PROCESSING)
donatien 0:ae46a0638b2c 770 {
donatien 0:ae46a0638b2c 771 DBG("!!!!!!!!!!!!!wait bulkwrite");
donatien 0:ae46a0638b2c 772 Thread::wait(100);
donatien 0:ae46a0638b2c 773 }
donatien 0:ae46a0638b2c 774 lock();
donatien 0:ae46a0638b2c 775 DBG("!!!!!!!!!!!!! bulkwrite finished");
donatien 0:ae46a0638b2c 776 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 777 return res;
donatien 0:ae46a0638b2c 778 }
donatien 0:ae46a0638b2c 779 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 780 }
donatien 0:ae46a0638b2c 781 return USB_TYPE_PROCESSING;
donatien 0:ae46a0638b2c 782 }
donatien 0:ae46a0638b2c 783
donatien 9:c9e9817c398c 784 USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:ae46a0638b2c 785 USB_TYPE res;
donatien 0:ae46a0638b2c 786
donatien 0:ae46a0638b2c 787 if (dev == NULL || ep == NULL) {
donatien 0:ae46a0638b2c 788 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 789 }
donatien 0:ae46a0638b2c 790
donatien 0:ae46a0638b2c 791 if (ep->getState() != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 792 return ep->getState();
donatien 0:ae46a0638b2c 793 }
donatien 0:ae46a0638b2c 794
donatien 0:ae46a0638b2c 795 if ((ep->getDir() != OUT) || (ep->getType() != INTERRUPT_ENDPOINT)) {
donatien 9:c9e9817c398c 796 ERR("wrong dir or bad USBEndpoint type: %d, %d", ep->getDir(), ep->getType());
donatien 0:ae46a0638b2c 797 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 798 }
donatien 0:ae46a0638b2c 799 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 9:c9e9817c398c 800 ERR("USBEndpoint addr and device addr don't match");
donatien 0:ae46a0638b2c 801 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 802 }
donatien 0:ae46a0638b2c 803 addTransfer(ep, buf, len);
donatien 0:ae46a0638b2c 804 if (blocking) {
donatien 0:ae46a0638b2c 805 while ((res = ep->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 806 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 807 return res;
donatien 0:ae46a0638b2c 808 }
donatien 0:ae46a0638b2c 809 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 810 }
donatien 0:ae46a0638b2c 811 return USB_TYPE_PROCESSING;
donatien 0:ae46a0638b2c 812 }
donatien 0:ae46a0638b2c 813
donatien 9:c9e9817c398c 814 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
donatien 0:ae46a0638b2c 815 USB_TYPE res;
donatien 0:ae46a0638b2c 816
donatien 0:ae46a0638b2c 817 if (dev == NULL || ep == NULL) {
donatien 0:ae46a0638b2c 818 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 819 }
donatien 0:ae46a0638b2c 820
donatien 0:ae46a0638b2c 821 if (ep->getState() != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 822 return ep->getState();
donatien 0:ae46a0638b2c 823 }
donatien 0:ae46a0638b2c 824
donatien 0:ae46a0638b2c 825 if ((ep->getDir() != IN) || (ep->getType() != INTERRUPT_ENDPOINT)) {
donatien 9:c9e9817c398c 826 ERR("wrong dir or bad USBEndpoint type");
donatien 0:ae46a0638b2c 827 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 828 }
donatien 0:ae46a0638b2c 829
donatien 0:ae46a0638b2c 830 if (dev->getAddress() != ep->getDeviceAddress()) {
donatien 9:c9e9817c398c 831 ERR("USBEndpoint addr and device addr don't match");
donatien 0:ae46a0638b2c 832 return USB_TYPE_ERROR;
donatien 0:ae46a0638b2c 833 }
donatien 0:ae46a0638b2c 834 addTransfer(ep, buf, len);
donatien 0:ae46a0638b2c 835 if (blocking) {
donatien 0:ae46a0638b2c 836 while ((res = ep->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 837 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 838 return res;
donatien 0:ae46a0638b2c 839 }
donatien 0:ae46a0638b2c 840 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 841 }
donatien 0:ae46a0638b2c 842 return USB_TYPE_PROCESSING;
donatien 0:ae46a0638b2c 843 }
donatien 0:ae46a0638b2c 844
donatien 0:ae46a0638b2c 845
donatien 0:ae46a0638b2c 846 USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
donatien 0:ae46a0638b2c 847 int length_transfer = len;
donatien 0:ae46a0638b2c 848 //DBG("want to transfer: %d bytes\r\n", length_transfer);
donatien 0:ae46a0638b2c 849 USB_TYPE res;
donatien 0:ae46a0638b2c 850 control->setSpeed(dev->getSpeed());
donatien 0:ae46a0638b2c 851 control->setSize(dev->getSizeControlEndpoint());
donatien 0:ae46a0638b2c 852 if (dev->isActiveAddress()) {
donatien 0:ae46a0638b2c 853 control->setDeviceAddress(dev->getAddress());
donatien 0:ae46a0638b2c 854 } else {
donatien 0:ae46a0638b2c 855 control->setDeviceAddress(0);
donatien 0:ae46a0638b2c 856 }
donatien 0:ae46a0638b2c 857 fillControlBuf(requestType, request, value, index, len);
donatien 0:ae46a0638b2c 858 /* DBG("will call transfer: ");
donatien 0:ae46a0638b2c 859 for (int i = 0; i < 8; i++) {
donatien 0:ae46a0638b2c 860 DBG("%02X ", setupPacket[i]);
donatien 0:ae46a0638b2c 861 }*/
donatien 0:ae46a0638b2c 862 control->setNextToken(TD_SETUP);
donatien 0:ae46a0638b2c 863 addTransfer(control, (uint8_t*)setupPacket, 8);
donatien 0:ae46a0638b2c 864 DBG("Now wait for TD to be processed");
donatien 0:ae46a0638b2c 865 unlock();
donatien 0:ae46a0638b2c 866 DBG("Unlocked");
donatien 0:ae46a0638b2c 867 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 868 lock();
donatien 0:ae46a0638b2c 869 DBG("TD processed with result %d", res);
donatien 0:ae46a0638b2c 870 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 871 return res;
donatien 0:ae46a0638b2c 872 }
donatien 0:ae46a0638b2c 873
donatien 0:ae46a0638b2c 874 if (length_transfer) {
donatien 0:ae46a0638b2c 875 DBG("In data to be transfered...");
donatien 0:ae46a0638b2c 876 control->setNextToken(TD_IN);
donatien 0:ae46a0638b2c 877 addTransfer(control, (uint8_t *)buf, length_transfer);
donatien 0:ae46a0638b2c 878 unlock();
donatien 0:ae46a0638b2c 879 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 880 lock();
donatien 0:ae46a0638b2c 881 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 882 return res;
donatien 0:ae46a0638b2c 883 }
donatien 0:ae46a0638b2c 884 }
donatien 0:ae46a0638b2c 885
donatien 0:ae46a0638b2c 886 DBG("Transfer NULL packet (OUT)");
donatien 0:ae46a0638b2c 887 control->setNextToken(TD_OUT);
donatien 0:ae46a0638b2c 888 addTransfer(control, NULL, 0);
donatien 0:ae46a0638b2c 889 unlock();
donatien 0:ae46a0638b2c 890 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 891 lock();
donatien 0:ae46a0638b2c 892 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 893 return res;
donatien 0:ae46a0638b2c 894 }
donatien 0:ae46a0638b2c 895 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 896 }
donatien 0:ae46a0638b2c 897
donatien 0:ae46a0638b2c 898
donatien 0:ae46a0638b2c 899 USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
donatien 0:ae46a0638b2c 900 control->setSpeed(dev->getSpeed());
donatien 0:ae46a0638b2c 901
donatien 0:ae46a0638b2c 902 int length_transfer = len;
donatien 0:ae46a0638b2c 903 USB_TYPE res;
donatien 0:ae46a0638b2c 904
donatien 0:ae46a0638b2c 905 control->setSize(dev->getSizeControlEndpoint());
donatien 0:ae46a0638b2c 906 if (dev->isActiveAddress()) {
donatien 0:ae46a0638b2c 907 control->setDeviceAddress(dev->getAddress());
donatien 0:ae46a0638b2c 908 } else {
donatien 0:ae46a0638b2c 909 control->setDeviceAddress(0);
donatien 0:ae46a0638b2c 910 }
donatien 0:ae46a0638b2c 911 fillControlBuf(requestType, request, value, index, len);
donatien 0:ae46a0638b2c 912 /*DBG("will call transfer: ");
donatien 0:ae46a0638b2c 913 for (int i = 0; i < 8; i++) {
donatien 0:ae46a0638b2c 914 printf("%01X ", setupPacket[i]);
donatien 0:ae46a0638b2c 915 }
donatien 0:ae46a0638b2c 916 printf("\r\n");*/
donatien 0:ae46a0638b2c 917 control->setNextToken(TD_SETUP);
donatien 0:ae46a0638b2c 918 addTransfer(control, (uint8_t*)setupPacket, 8);
donatien 0:ae46a0638b2c 919 unlock();
donatien 0:ae46a0638b2c 920 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 921 lock();
donatien 0:ae46a0638b2c 922 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 923 return res;
donatien 0:ae46a0638b2c 924 }
donatien 0:ae46a0638b2c 925
donatien 0:ae46a0638b2c 926 if (length_transfer) {
donatien 0:ae46a0638b2c 927 control->setNextToken(TD_OUT);
donatien 0:ae46a0638b2c 928 addTransfer(control, (uint8_t *)buf, length_transfer);
donatien 0:ae46a0638b2c 929 unlock();
donatien 0:ae46a0638b2c 930 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 931 lock();
donatien 0:ae46a0638b2c 932 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 933 return res;
donatien 0:ae46a0638b2c 934 }
donatien 0:ae46a0638b2c 935 }
donatien 0:ae46a0638b2c 936
donatien 0:ae46a0638b2c 937 control->setNextToken(TD_IN);
donatien 0:ae46a0638b2c 938 addTransfer(control, NULL, 0);
donatien 0:ae46a0638b2c 939 unlock();
donatien 0:ae46a0638b2c 940 while ((res = control->getState()) == USB_TYPE_PROCESSING);
donatien 0:ae46a0638b2c 941 lock();
donatien 0:ae46a0638b2c 942 if (res != USB_TYPE_IDLE) {
donatien 0:ae46a0638b2c 943 return res;
donatien 0:ae46a0638b2c 944 }
donatien 0:ae46a0638b2c 945 return USB_TYPE_OK;
donatien 0:ae46a0638b2c 946 }
donatien 0:ae46a0638b2c 947
donatien 0:ae46a0638b2c 948
donatien 0:ae46a0638b2c 949 void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, int len) {
donatien 0:ae46a0638b2c 950 #ifdef __BIG_ENDIAN
donatien 0:ae46a0638b2c 951 #error "Must implement BE to LE conv here"
donatien 0:ae46a0638b2c 952 #endif
donatien 0:ae46a0638b2c 953 setupPacket[0] = requestType;
donatien 0:ae46a0638b2c 954 setupPacket[1] = request;
donatien 0:ae46a0638b2c 955 //We are in LE so it's fine
donatien 0:ae46a0638b2c 956 *((uint32_t*)&setupPacket[2]) = value;
donatien 0:ae46a0638b2c 957 *((uint32_t*)&setupPacket[4]) = index;
donatien 0:ae46a0638b2c 958 *((uint32_t*)&setupPacket[6]) = (uint32_t) len;
donatien 0:ae46a0638b2c 959 }
donatien 0:ae46a0638b2c 960