USB Host WAN Dongle library

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Committer:
donatien
Date:
Thu Aug 30 09:15:55 2012 +0000
Revision:
10:08bce4cd973a
Parent:
9:c9e9817c398c
Child:
11:a0841fba0599
Fixed reinitialization issues

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