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