USB Host Library for Sprint Dongles

Fork of USBHostWANDongleSprint_bleedingedge by Donatien Garnier

Legacy Warning

This is an mbed 2 libary. To learn more about mbed OS 5, visit the docs.

Committer:
donatien
Date:
Mon Dec 10 18:18:35 2012 +0000
Revision:
9:2a7b7333245f
Parent:
3:9ec92dd8a8cb
Merge

Who changed what in which revision?

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