Mike R / USBDevice

Dependents:   frdm_Slider_Keyboard idd_hw2_figlax_PanType idd_hw2_appachu_finger_chording idd_hw3_AngieWangAntonioDeLimaFernandesDanielLim_BladeSymphony ... more

Fork of USBDevice by mbed official

Committer:
mjr
Date:
Mon Jan 11 21:07:25 2016 +0000
Revision:
37:c5ac4ccf6597
Parent:
36:20bb47609697
Child:
39:d684a8ce5d88
Fixed numerous race conditions and other bugs in KL25Z USB HAL.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
samux 1:80ab0d068708 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
samux 1:80ab0d068708 2 *
samux 1:80ab0d068708 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
samux 1:80ab0d068708 4 * and associated documentation files (the "Software"), to deal in the Software without
samux 1:80ab0d068708 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
samux 1:80ab0d068708 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
samux 1:80ab0d068708 7 * Software is furnished to do so, subject to the following conditions:
samux 1:80ab0d068708 8 *
samux 1:80ab0d068708 9 * The above copyright notice and this permission notice shall be included in all copies or
samux 1:80ab0d068708 10 * substantial portions of the Software.
samux 1:80ab0d068708 11 *
samux 1:80ab0d068708 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
samux 1:80ab0d068708 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
samux 1:80ab0d068708 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
samux 1:80ab0d068708 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
samux 1:80ab0d068708 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
samux 1:80ab0d068708 17 */
samux 1:80ab0d068708 18
samux 1:80ab0d068708 19 #include "stdint.h"
samux 1:80ab0d068708 20
samux 1:80ab0d068708 21 #include "USBEndpoints.h"
samux 1:80ab0d068708 22 #include "USBDevice.h"
samux 1:80ab0d068708 23 #include "USBDescriptor.h"
samux 1:80ab0d068708 24
samux 1:80ab0d068708 25 //#define DEBUG
mjr 37:c5ac4ccf6597 26 #ifdef DEBUG
mjr 37:c5ac4ccf6597 27 #define printd(fmt, ...) printf(fmt, __VA_ARGS__)
mjr 37:c5ac4ccf6597 28 #else
mjr 37:c5ac4ccf6597 29 #define printd(fmt, ...)
mjr 37:c5ac4ccf6597 30 #endif
samux 1:80ab0d068708 31
samux 1:80ab0d068708 32 /* Device status */
samux 1:80ab0d068708 33 #define DEVICE_STATUS_SELF_POWERED (1U<<0)
samux 1:80ab0d068708 34 #define DEVICE_STATUS_REMOTE_WAKEUP (1U<<1)
samux 1:80ab0d068708 35
samux 1:80ab0d068708 36 /* Endpoint status */
samux 1:80ab0d068708 37 #define ENDPOINT_STATUS_HALT (1U<<0)
samux 1:80ab0d068708 38
samux 1:80ab0d068708 39 /* Standard feature selectors */
samux 1:80ab0d068708 40 #define DEVICE_REMOTE_WAKEUP (1)
samux 1:80ab0d068708 41 #define ENDPOINT_HALT (0)
samux 1:80ab0d068708 42
samux 1:80ab0d068708 43 /* Macro to convert wIndex endpoint number to physical endpoint number */
samux 1:80ab0d068708 44 #define WINDEX_TO_PHYSICAL(endpoint) (((endpoint & 0x0f) << 1) + \
samux 1:80ab0d068708 45 ((endpoint & 0x80) ? 1 : 0))
samux 1:80ab0d068708 46
samux 1:80ab0d068708 47
samux 1:80ab0d068708 48 bool USBDevice::requestGetDescriptor(void)
samux 1:80ab0d068708 49 {
samux 1:80ab0d068708 50 bool success = false;
mjr 37:c5ac4ccf6597 51 printd("get descr: type: %d\r\n", DESCRIPTOR_TYPE(transfer.setup.wValue));
samux 1:80ab0d068708 52 switch (DESCRIPTOR_TYPE(transfer.setup.wValue))
samux 1:80ab0d068708 53 {
samux 1:80ab0d068708 54 case DEVICE_DESCRIPTOR:
samux 1:80ab0d068708 55 if (deviceDesc() != NULL)
samux 1:80ab0d068708 56 {
samux 1:80ab0d068708 57 if ((deviceDesc()[0] == DEVICE_DESCRIPTOR_LENGTH) \
samux 1:80ab0d068708 58 && (deviceDesc()[1] == DEVICE_DESCRIPTOR))
samux 1:80ab0d068708 59 {
mjr 37:c5ac4ccf6597 60 printd("device descr\r\n");
samux 1:80ab0d068708 61 transfer.remaining = DEVICE_DESCRIPTOR_LENGTH;
samux 1:80ab0d068708 62 transfer.ptr = deviceDesc();
samux 1:80ab0d068708 63 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 64 success = true;
samux 1:80ab0d068708 65 }
samux 1:80ab0d068708 66 }
samux 1:80ab0d068708 67 break;
samux 1:80ab0d068708 68 case CONFIGURATION_DESCRIPTOR:
samux 1:80ab0d068708 69 if (configurationDesc() != NULL)
samux 1:80ab0d068708 70 {
samux 1:80ab0d068708 71 if ((configurationDesc()[0] == CONFIGURATION_DESCRIPTOR_LENGTH) \
samux 1:80ab0d068708 72 && (configurationDesc()[1] == CONFIGURATION_DESCRIPTOR))
samux 1:80ab0d068708 73 {
mjr 37:c5ac4ccf6597 74 printd("conf descr request\r\n");
mjr 37:c5ac4ccf6597 75
samux 1:80ab0d068708 76 /* Get wTotalLength */
samux 1:80ab0d068708 77 transfer.remaining = configurationDesc()[2] \
samux 1:80ab0d068708 78 | (configurationDesc()[3] << 8);
samux 1:80ab0d068708 79
samux 1:80ab0d068708 80 transfer.ptr = configurationDesc();
samux 1:80ab0d068708 81 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 82 success = true;
samux 1:80ab0d068708 83 }
samux 1:80ab0d068708 84 }
samux 1:80ab0d068708 85 break;
samux 1:80ab0d068708 86 case STRING_DESCRIPTOR:
mjr 37:c5ac4ccf6597 87 printd("str descriptor\r\n");
samux 1:80ab0d068708 88 switch (DESCRIPTOR_INDEX(transfer.setup.wValue))
samux 1:80ab0d068708 89 {
samux 1:80ab0d068708 90 case STRING_OFFSET_LANGID:
mjr 37:c5ac4ccf6597 91 printd("1\r\n");
samux 1:80ab0d068708 92 transfer.remaining = stringLangidDesc()[0];
samux 1:80ab0d068708 93 transfer.ptr = stringLangidDesc();
samux 1:80ab0d068708 94 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 95 success = true;
samux 1:80ab0d068708 96 break;
samux 1:80ab0d068708 97 case STRING_OFFSET_IMANUFACTURER:
mjr 37:c5ac4ccf6597 98 printd("2\r\n");
samux 1:80ab0d068708 99 transfer.remaining = stringImanufacturerDesc()[0];
samux 1:80ab0d068708 100 transfer.ptr = stringImanufacturerDesc();
samux 1:80ab0d068708 101 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 102 success = true;
mbed_official 25:7c72828865f3 103 break;
samux 1:80ab0d068708 104 case STRING_OFFSET_IPRODUCT:
mjr 37:c5ac4ccf6597 105 printd("3\r\n");
samux 1:80ab0d068708 106 transfer.remaining = stringIproductDesc()[0];
samux 1:80ab0d068708 107 transfer.ptr = stringIproductDesc();
samux 1:80ab0d068708 108 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 109 success = true;
mbed_official 25:7c72828865f3 110 break;
samux 1:80ab0d068708 111 case STRING_OFFSET_ISERIAL:
mjr 37:c5ac4ccf6597 112 printd("4\r\n");
samux 1:80ab0d068708 113 transfer.remaining = stringIserialDesc()[0];
samux 1:80ab0d068708 114 transfer.ptr = stringIserialDesc();
samux 1:80ab0d068708 115 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 116 success = true;
mbed_official 25:7c72828865f3 117 break;
samux 1:80ab0d068708 118 case STRING_OFFSET_ICONFIGURATION:
mjr 37:c5ac4ccf6597 119 printd("5\r\n");
samux 1:80ab0d068708 120 transfer.remaining = stringIConfigurationDesc()[0];
samux 1:80ab0d068708 121 transfer.ptr = stringIConfigurationDesc();
samux 1:80ab0d068708 122 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 123 success = true;
mbed_official 25:7c72828865f3 124 break;
samux 1:80ab0d068708 125 case STRING_OFFSET_IINTERFACE:
mjr 37:c5ac4ccf6597 126 printd("6\r\n");
samux 1:80ab0d068708 127 transfer.remaining = stringIinterfaceDesc()[0];
samux 1:80ab0d068708 128 transfer.ptr = stringIinterfaceDesc();
samux 1:80ab0d068708 129 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 130 success = true;
mbed_official 25:7c72828865f3 131 break;
samux 1:80ab0d068708 132 }
samux 1:80ab0d068708 133 break;
mjr 37:c5ac4ccf6597 134
samux 1:80ab0d068708 135 case INTERFACE_DESCRIPTOR:
mjr 37:c5ac4ccf6597 136 printd("interface descr\r\n");
mjr 37:c5ac4ccf6597 137 break;
mjr 37:c5ac4ccf6597 138
samux 1:80ab0d068708 139 case ENDPOINT_DESCRIPTOR:
samux 1:80ab0d068708 140 /* TODO: Support is optional, not implemented here */
mjr 37:c5ac4ccf6597 141 printd("endpoint descr\r\n");
samux 1:80ab0d068708 142 break;
mjr 37:c5ac4ccf6597 143
samux 1:80ab0d068708 144 default:
mjr 37:c5ac4ccf6597 145 printd("ERROR - unknown descriptor type in GET DESCRIPTOR\r\n");
samux 1:80ab0d068708 146 break;
samux 1:80ab0d068708 147 }
samux 1:80ab0d068708 148
samux 1:80ab0d068708 149 return success;
samux 1:80ab0d068708 150 }
samux 1:80ab0d068708 151
samux 1:80ab0d068708 152 void USBDevice::decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet)
samux 1:80ab0d068708 153 {
samux 1:80ab0d068708 154 /* Fill in the elements of a SETUP_PACKET structure from raw data */
samux 1:80ab0d068708 155 packet->bmRequestType.dataTransferDirection = (data[0] & 0x80) >> 7;
samux 1:80ab0d068708 156 packet->bmRequestType.Type = (data[0] & 0x60) >> 5;
samux 1:80ab0d068708 157 packet->bmRequestType.Recipient = data[0] & 0x1f;
samux 1:80ab0d068708 158 packet->bRequest = data[1];
samux 1:80ab0d068708 159 packet->wValue = (data[2] | (uint16_t)data[3] << 8);
samux 1:80ab0d068708 160 packet->wIndex = (data[4] | (uint16_t)data[5] << 8);
samux 1:80ab0d068708 161 packet->wLength = (data[6] | (uint16_t)data[7] << 8);
samux 1:80ab0d068708 162 }
samux 1:80ab0d068708 163
samux 1:80ab0d068708 164
samux 1:80ab0d068708 165 bool USBDevice::controlOut(void)
samux 1:80ab0d068708 166 {
samux 1:80ab0d068708 167 /* Control transfer data OUT stage */
samux 1:80ab0d068708 168 uint8_t buffer[MAX_PACKET_SIZE_EP0];
samux 1:80ab0d068708 169 uint32_t packetSize;
samux 1:80ab0d068708 170
samux 1:80ab0d068708 171 /* Check we should be transferring data OUT */
samux 1:80ab0d068708 172 if (transfer.direction != HOST_TO_DEVICE)
samux 1:80ab0d068708 173 {
mjr 30:2f8f4c3822a1 174 #if defined(TARGET_KL25Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D5M) | defined(TARGET_K64F)
mjr 29:b502c11a3dff 175 /*
mjr 29:b502c11a3dff 176 * We seem to have a pending device-to-host transfer. The host must have
mjr 29:b502c11a3dff 177 * sent a new control request without waiting for us to finish processing
mjr 29:b502c11a3dff 178 * the previous one. This appears to happen when we're connected to certain
mjr 34:884405d998bb 179 * USB 3.0 host chip sets. Do a zero-length send to tell the host we're not
mjr 29:b502c11a3dff 180 * ready for the new request - that'll make it resend - and then just
mjr 29:b502c11a3dff 181 * pretend we were successful here so that the pending transfer can finish.
mjr 29:b502c11a3dff 182 */
mjr 36:20bb47609697 183 EP0write(0, 0);
mjr 31:81f57ea86f8f 184
mjr 36:20bb47609697 185 /* execute our pending transfer */
mjr 31:81f57ea86f8f 186 controlIn();
mjr 31:81f57ea86f8f 187
mjr 37:c5ac4ccf6597 188 /* indicate failure */
mjr 31:81f57ea86f8f 189 return false;
mjr 29:b502c11a3dff 190 #else
mjr 31:81f57ea86f8f 191 /* for other platforms, count on the HAL to handle this case */
mjr 31:81f57ea86f8f 192 return false;
mjr 29:b502c11a3dff 193 #endif
samux 1:80ab0d068708 194 }
samux 1:80ab0d068708 195
samux 1:80ab0d068708 196 /* Read from endpoint */
samux 1:80ab0d068708 197 packetSize = EP0getReadResult(buffer);
samux 1:80ab0d068708 198
samux 1:80ab0d068708 199 /* Check if transfer size is valid */
samux 1:80ab0d068708 200 if (packetSize > transfer.remaining)
samux 1:80ab0d068708 201 {
samux 1:80ab0d068708 202 /* Too big */
samux 1:80ab0d068708 203 return false;
samux 1:80ab0d068708 204 }
samux 1:80ab0d068708 205
samux 1:80ab0d068708 206 /* Update transfer */
samux 1:80ab0d068708 207 transfer.ptr += packetSize;
samux 1:80ab0d068708 208 transfer.remaining -= packetSize;
samux 1:80ab0d068708 209
samux 1:80ab0d068708 210 /* Check if transfer has completed */
samux 1:80ab0d068708 211 if (transfer.remaining == 0)
samux 1:80ab0d068708 212 {
samux 1:80ab0d068708 213 /* Transfer completed */
samux 1:80ab0d068708 214 if (transfer.notify)
samux 1:80ab0d068708 215 {
samux 1:80ab0d068708 216 /* Notify class layer. */
samux 1:80ab0d068708 217 USBCallback_requestCompleted(buffer, packetSize);
samux 1:80ab0d068708 218 transfer.notify = false;
samux 1:80ab0d068708 219 }
samux 1:80ab0d068708 220 /* Status stage */
samux 1:80ab0d068708 221 EP0write(NULL, 0);
samux 1:80ab0d068708 222 }
samux 1:80ab0d068708 223 else
samux 1:80ab0d068708 224 {
samux 1:80ab0d068708 225 EP0read();
samux 1:80ab0d068708 226 }
samux 1:80ab0d068708 227
samux 1:80ab0d068708 228 return true;
samux 1:80ab0d068708 229 }
samux 1:80ab0d068708 230
samux 1:80ab0d068708 231 bool USBDevice::controlIn(void)
samux 1:80ab0d068708 232 {
samux 1:80ab0d068708 233 /* Control transfer data IN stage */
samux 1:80ab0d068708 234 uint32_t packetSize;
samux 1:80ab0d068708 235
samux 1:80ab0d068708 236 /* Check if transfer has completed (status stage transactions */
samux 1:80ab0d068708 237 /* also have transfer.remaining == 0) */
samux 1:80ab0d068708 238 if (transfer.remaining == 0)
samux 1:80ab0d068708 239 {
samux 1:80ab0d068708 240 if (transfer.zlp)
samux 1:80ab0d068708 241 {
samux 1:80ab0d068708 242 /* Send zero length packet */
samux 1:80ab0d068708 243 EP0write(NULL, 0);
samux 1:80ab0d068708 244 transfer.zlp = false;
samux 1:80ab0d068708 245 }
samux 1:80ab0d068708 246
samux 1:80ab0d068708 247 /* Transfer completed */
samux 1:80ab0d068708 248 if (transfer.notify)
samux 1:80ab0d068708 249 {
samux 1:80ab0d068708 250 /* Notify class layer. */
samux 1:80ab0d068708 251 USBCallback_requestCompleted(NULL, 0);
samux 1:80ab0d068708 252 transfer.notify = false;
samux 1:80ab0d068708 253 }
samux 1:80ab0d068708 254
samux 1:80ab0d068708 255 EP0read();
samux 8:335f2506f422 256 EP0readStage();
samux 1:80ab0d068708 257
samux 1:80ab0d068708 258 /* Completed */
mjr 36:20bb47609697 259 transfer.direction = HOST_TO_DEVICE;
samux 1:80ab0d068708 260 return true;
samux 1:80ab0d068708 261 }
samux 1:80ab0d068708 262
samux 1:80ab0d068708 263 /* Check we should be transferring data IN */
samux 1:80ab0d068708 264 if (transfer.direction != DEVICE_TO_HOST)
samux 1:80ab0d068708 265 {
samux 1:80ab0d068708 266 return false;
samux 1:80ab0d068708 267 }
samux 1:80ab0d068708 268
samux 1:80ab0d068708 269 packetSize = transfer.remaining;
samux 1:80ab0d068708 270
samux 1:80ab0d068708 271 if (packetSize > MAX_PACKET_SIZE_EP0)
samux 1:80ab0d068708 272 {
samux 1:80ab0d068708 273 packetSize = MAX_PACKET_SIZE_EP0;
samux 1:80ab0d068708 274 }
samux 1:80ab0d068708 275
samux 1:80ab0d068708 276 /* Write to endpoint */
samux 1:80ab0d068708 277 EP0write(transfer.ptr, packetSize);
samux 1:80ab0d068708 278
samux 1:80ab0d068708 279 /* Update transfer */
samux 1:80ab0d068708 280 transfer.ptr += packetSize;
samux 1:80ab0d068708 281 transfer.remaining -= packetSize;
mjr 36:20bb47609697 282
mjr 36:20bb47609697 283 /* are we done? */
mjr 36:20bb47609697 284 if (transfer.remaining == 0)
mjr 36:20bb47609697 285 transfer.direction = HOST_TO_DEVICE;
samux 1:80ab0d068708 286
mjr 36:20bb47609697 287 /* success */
samux 1:80ab0d068708 288 return true;
samux 1:80ab0d068708 289 }
samux 1:80ab0d068708 290
samux 1:80ab0d068708 291 bool USBDevice::requestSetAddress(void)
samux 1:80ab0d068708 292 {
samux 1:80ab0d068708 293 /* Set the device address */
samux 1:80ab0d068708 294 setAddress(transfer.setup.wValue);
samux 1:80ab0d068708 295
samux 1:80ab0d068708 296 if (transfer.setup.wValue == 0)
samux 1:80ab0d068708 297 {
samux 1:80ab0d068708 298 device.state = DEFAULT;
samux 1:80ab0d068708 299 }
samux 1:80ab0d068708 300 else
samux 1:80ab0d068708 301 {
samux 1:80ab0d068708 302 device.state = ADDRESS;
samux 1:80ab0d068708 303 }
samux 1:80ab0d068708 304
samux 1:80ab0d068708 305 return true;
samux 1:80ab0d068708 306 }
samux 1:80ab0d068708 307
samux 1:80ab0d068708 308 bool USBDevice::requestSetConfiguration(void)
samux 1:80ab0d068708 309 {
samux 1:80ab0d068708 310
samux 1:80ab0d068708 311 device.configuration = transfer.setup.wValue;
samux 1:80ab0d068708 312 /* Set the device configuration */
samux 1:80ab0d068708 313 if (device.configuration == 0)
samux 1:80ab0d068708 314 {
samux 1:80ab0d068708 315 /* Not configured */
samux 1:80ab0d068708 316 unconfigureDevice();
samux 1:80ab0d068708 317 device.state = ADDRESS;
samux 1:80ab0d068708 318 }
samux 1:80ab0d068708 319 else
samux 1:80ab0d068708 320 {
samux 1:80ab0d068708 321 if (USBCallback_setConfiguration(device.configuration))
samux 1:80ab0d068708 322 {
samux 1:80ab0d068708 323 /* Valid configuration */
samux 1:80ab0d068708 324 configureDevice();
samux 1:80ab0d068708 325 device.state = CONFIGURED;
samux 1:80ab0d068708 326 }
samux 1:80ab0d068708 327 else
samux 1:80ab0d068708 328 {
samux 1:80ab0d068708 329 return false;
samux 1:80ab0d068708 330 }
samux 1:80ab0d068708 331 }
samux 1:80ab0d068708 332
samux 1:80ab0d068708 333 return true;
samux 1:80ab0d068708 334 }
samux 1:80ab0d068708 335
samux 1:80ab0d068708 336 bool USBDevice::requestGetConfiguration(void)
samux 1:80ab0d068708 337 {
samux 1:80ab0d068708 338 /* Send the device configuration */
samux 1:80ab0d068708 339 transfer.ptr = &device.configuration;
samux 1:80ab0d068708 340 transfer.remaining = sizeof(device.configuration);
samux 1:80ab0d068708 341 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 342 return true;
samux 1:80ab0d068708 343 }
samux 1:80ab0d068708 344
samux 1:80ab0d068708 345 bool USBDevice::requestGetInterface(void)
samux 1:80ab0d068708 346 {
samux 1:80ab0d068708 347 /* Return the selected alternate setting for an interface */
samux 1:80ab0d068708 348
samux 1:80ab0d068708 349 if (device.state != CONFIGURED)
samux 1:80ab0d068708 350 {
samux 1:80ab0d068708 351 return false;
samux 1:80ab0d068708 352 }
samux 1:80ab0d068708 353
samux 1:80ab0d068708 354 /* Send the alternate setting */
samux 1:80ab0d068708 355 transfer.setup.wIndex = currentInterface;
samux 1:80ab0d068708 356 transfer.ptr = &currentAlternate;
samux 1:80ab0d068708 357 transfer.remaining = sizeof(currentAlternate);
samux 1:80ab0d068708 358 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 359 return true;
samux 1:80ab0d068708 360 }
samux 1:80ab0d068708 361
samux 1:80ab0d068708 362 bool USBDevice::requestSetInterface(void)
samux 1:80ab0d068708 363 {
samux 1:80ab0d068708 364 bool success = false;
samux 1:80ab0d068708 365 if(USBCallback_setInterface(transfer.setup.wIndex, transfer.setup.wValue))
samux 1:80ab0d068708 366 {
samux 1:80ab0d068708 367 success = true;
samux 1:80ab0d068708 368 currentInterface = transfer.setup.wIndex;
mbed_official 25:7c72828865f3 369 currentAlternate = transfer.setup.wValue;
samux 1:80ab0d068708 370 }
samux 1:80ab0d068708 371 return success;
samux 1:80ab0d068708 372 }
samux 1:80ab0d068708 373
samux 1:80ab0d068708 374 bool USBDevice::requestSetFeature()
samux 1:80ab0d068708 375 {
samux 1:80ab0d068708 376 bool success = false;
samux 1:80ab0d068708 377
samux 1:80ab0d068708 378 if (device.state != CONFIGURED)
samux 1:80ab0d068708 379 {
samux 1:80ab0d068708 380 /* Endpoint or interface must be zero */
samux 1:80ab0d068708 381 if (transfer.setup.wIndex != 0)
samux 1:80ab0d068708 382 {
samux 1:80ab0d068708 383 return false;
samux 1:80ab0d068708 384 }
samux 1:80ab0d068708 385 }
samux 1:80ab0d068708 386
samux 1:80ab0d068708 387 switch (transfer.setup.bmRequestType.Recipient)
samux 1:80ab0d068708 388 {
samux 1:80ab0d068708 389 case DEVICE_RECIPIENT:
samux 1:80ab0d068708 390 /* TODO: Remote wakeup feature not supported */
samux 1:80ab0d068708 391 break;
samux 1:80ab0d068708 392 case ENDPOINT_RECIPIENT:
samux 1:80ab0d068708 393 if (transfer.setup.wValue == ENDPOINT_HALT)
samux 1:80ab0d068708 394 {
samux 1:80ab0d068708 395 /* TODO: We should check that the endpoint number is valid */
samux 1:80ab0d068708 396 stallEndpoint(
samux 1:80ab0d068708 397 WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
samux 1:80ab0d068708 398 success = true;
samux 1:80ab0d068708 399 }
samux 1:80ab0d068708 400 break;
samux 1:80ab0d068708 401 default:
samux 1:80ab0d068708 402 break;
samux 1:80ab0d068708 403 }
samux 1:80ab0d068708 404
samux 1:80ab0d068708 405 return success;
samux 1:80ab0d068708 406 }
samux 1:80ab0d068708 407
samux 1:80ab0d068708 408 bool USBDevice::requestClearFeature()
samux 1:80ab0d068708 409 {
samux 1:80ab0d068708 410 bool success = false;
samux 1:80ab0d068708 411
samux 1:80ab0d068708 412 if (device.state != CONFIGURED)
samux 1:80ab0d068708 413 {
samux 1:80ab0d068708 414 /* Endpoint or interface must be zero */
samux 1:80ab0d068708 415 if (transfer.setup.wIndex != 0)
samux 1:80ab0d068708 416 {
samux 1:80ab0d068708 417 return false;
samux 1:80ab0d068708 418 }
samux 1:80ab0d068708 419 }
samux 1:80ab0d068708 420
samux 1:80ab0d068708 421 switch (transfer.setup.bmRequestType.Recipient)
samux 1:80ab0d068708 422 {
samux 1:80ab0d068708 423 case DEVICE_RECIPIENT:
samux 1:80ab0d068708 424 /* TODO: Remote wakeup feature not supported */
samux 1:80ab0d068708 425 break;
samux 1:80ab0d068708 426 case ENDPOINT_RECIPIENT:
samux 1:80ab0d068708 427 /* TODO: We should check that the endpoint number is valid */
samux 1:80ab0d068708 428 if (transfer.setup.wValue == ENDPOINT_HALT)
samux 1:80ab0d068708 429 {
samux 1:80ab0d068708 430 unstallEndpoint( WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
samux 1:80ab0d068708 431 success = true;
samux 1:80ab0d068708 432 }
samux 1:80ab0d068708 433 break;
samux 1:80ab0d068708 434 default:
samux 1:80ab0d068708 435 break;
samux 1:80ab0d068708 436 }
samux 1:80ab0d068708 437
samux 1:80ab0d068708 438 return success;
samux 1:80ab0d068708 439 }
samux 1:80ab0d068708 440
samux 1:80ab0d068708 441 bool USBDevice::requestGetStatus(void)
samux 1:80ab0d068708 442 {
samux 1:80ab0d068708 443 static uint16_t status;
samux 1:80ab0d068708 444 bool success = false;
samux 1:80ab0d068708 445
samux 1:80ab0d068708 446 if (device.state != CONFIGURED)
samux 1:80ab0d068708 447 {
samux 1:80ab0d068708 448 /* Endpoint or interface must be zero */
samux 1:80ab0d068708 449 if (transfer.setup.wIndex != 0)
samux 1:80ab0d068708 450 {
samux 1:80ab0d068708 451 return false;
samux 1:80ab0d068708 452 }
samux 1:80ab0d068708 453 }
samux 1:80ab0d068708 454
samux 1:80ab0d068708 455 switch (transfer.setup.bmRequestType.Recipient)
samux 1:80ab0d068708 456 {
samux 1:80ab0d068708 457 case DEVICE_RECIPIENT:
samux 1:80ab0d068708 458 /* TODO: Currently only supports self powered devices */
samux 1:80ab0d068708 459 status = DEVICE_STATUS_SELF_POWERED;
samux 1:80ab0d068708 460 success = true;
samux 1:80ab0d068708 461 break;
samux 1:80ab0d068708 462 case INTERFACE_RECIPIENT:
samux 1:80ab0d068708 463 status = 0;
samux 1:80ab0d068708 464 success = true;
samux 1:80ab0d068708 465 break;
samux 1:80ab0d068708 466 case ENDPOINT_RECIPIENT:
samux 1:80ab0d068708 467 /* TODO: We should check that the endpoint number is valid */
samux 1:80ab0d068708 468 if (getEndpointStallState(
samux 1:80ab0d068708 469 WINDEX_TO_PHYSICAL(transfer.setup.wIndex)))
samux 1:80ab0d068708 470 {
samux 1:80ab0d068708 471 status = ENDPOINT_STATUS_HALT;
samux 1:80ab0d068708 472 }
samux 1:80ab0d068708 473 else
samux 1:80ab0d068708 474 {
samux 1:80ab0d068708 475 status = 0;
samux 1:80ab0d068708 476 }
samux 1:80ab0d068708 477 success = true;
samux 1:80ab0d068708 478 break;
samux 1:80ab0d068708 479 default:
samux 1:80ab0d068708 480 break;
samux 1:80ab0d068708 481 }
samux 1:80ab0d068708 482
samux 1:80ab0d068708 483 if (success)
samux 1:80ab0d068708 484 {
mbed_official 25:7c72828865f3 485 /* Send the status */
samux 1:80ab0d068708 486 transfer.ptr = (uint8_t *)&status; /* Assumes little endian */
samux 1:80ab0d068708 487 transfer.remaining = sizeof(status);
samux 1:80ab0d068708 488 transfer.direction = DEVICE_TO_HOST;
samux 1:80ab0d068708 489 }
mbed_official 25:7c72828865f3 490
samux 1:80ab0d068708 491 return success;
samux 1:80ab0d068708 492 }
samux 1:80ab0d068708 493
samux 1:80ab0d068708 494 bool USBDevice::requestSetup(void)
samux 1:80ab0d068708 495 {
samux 1:80ab0d068708 496 bool success = false;
samux 1:80ab0d068708 497
samux 1:80ab0d068708 498 /* Process standard requests */
samux 1:80ab0d068708 499 if ((transfer.setup.bmRequestType.Type == STANDARD_TYPE))
samux 1:80ab0d068708 500 {
samux 1:80ab0d068708 501 switch (transfer.setup.bRequest)
samux 1:80ab0d068708 502 {
samux 1:80ab0d068708 503 case GET_STATUS:
samux 1:80ab0d068708 504 success = requestGetStatus();
samux 1:80ab0d068708 505 break;
samux 1:80ab0d068708 506 case CLEAR_FEATURE:
samux 1:80ab0d068708 507 success = requestClearFeature();
samux 1:80ab0d068708 508 break;
samux 1:80ab0d068708 509 case SET_FEATURE:
samux 1:80ab0d068708 510 success = requestSetFeature();
samux 1:80ab0d068708 511 break;
samux 1:80ab0d068708 512 case SET_ADDRESS:
mjr 37:c5ac4ccf6597 513 success = requestSetAddress();
samux 1:80ab0d068708 514 break;
samux 1:80ab0d068708 515 case GET_DESCRIPTOR:
samux 1:80ab0d068708 516 success = requestGetDescriptor();
samux 1:80ab0d068708 517 break;
samux 1:80ab0d068708 518 case SET_DESCRIPTOR:
samux 1:80ab0d068708 519 /* TODO: Support is optional, not implemented here */
samux 1:80ab0d068708 520 success = false;
samux 1:80ab0d068708 521 break;
samux 1:80ab0d068708 522 case GET_CONFIGURATION:
samux 1:80ab0d068708 523 success = requestGetConfiguration();
samux 1:80ab0d068708 524 break;
samux 1:80ab0d068708 525 case SET_CONFIGURATION:
samux 1:80ab0d068708 526 success = requestSetConfiguration();
samux 1:80ab0d068708 527 break;
samux 1:80ab0d068708 528 case GET_INTERFACE:
samux 1:80ab0d068708 529 success = requestGetInterface();
samux 1:80ab0d068708 530 break;
samux 1:80ab0d068708 531 case SET_INTERFACE:
samux 1:80ab0d068708 532 success = requestSetInterface();
samux 1:80ab0d068708 533 break;
samux 1:80ab0d068708 534 default:
samux 1:80ab0d068708 535 break;
samux 1:80ab0d068708 536 }
samux 1:80ab0d068708 537 }
samux 1:80ab0d068708 538
samux 1:80ab0d068708 539 return success;
samux 1:80ab0d068708 540 }
samux 1:80ab0d068708 541
samux 1:80ab0d068708 542 bool USBDevice::controlSetup(void)
samux 1:80ab0d068708 543 {
samux 1:80ab0d068708 544 bool success = false;
samux 1:80ab0d068708 545
samux 1:80ab0d068708 546 /* Control transfer setup stage */
samux 1:80ab0d068708 547 uint8_t buffer[MAX_PACKET_SIZE_EP0];
samux 1:80ab0d068708 548
samux 1:80ab0d068708 549 EP0setup(buffer);
samux 1:80ab0d068708 550
samux 1:80ab0d068708 551 /* Initialise control transfer state */
samux 1:80ab0d068708 552 decodeSetupPacket(buffer, &transfer.setup);
samux 1:80ab0d068708 553 transfer.ptr = NULL;
samux 1:80ab0d068708 554 transfer.remaining = 0;
mjr 36:20bb47609697 555 transfer.direction = HOST_TO_DEVICE;
samux 1:80ab0d068708 556 transfer.zlp = false;
samux 1:80ab0d068708 557 transfer.notify = false;
mbed_official 25:7c72828865f3 558
mjr 37:c5ac4ccf6597 559 printd("dataTransferDirection: %d\r\nType: %d\r\nRecipient: %d\r\nbRequest: %d\r\nwValue: %d\r\nwIndex: %d\r\nwLength: %d\r\n",
mjr 37:c5ac4ccf6597 560 transfer.setup.bmRequestType.dataTransferDirection,
mjr 37:c5ac4ccf6597 561 transfer.setup.bmRequestType.Type,
mjr 37:c5ac4ccf6597 562 transfer.setup.bmRequestType.Recipient,
mjr 37:c5ac4ccf6597 563 transfer.setup.bRequest,
mjr 37:c5ac4ccf6597 564 transfer.setup.wValue,
mjr 37:c5ac4ccf6597 565 transfer.setup.wIndex,
mjr 37:c5ac4ccf6597 566 transfer.setup.wLength);
samux 1:80ab0d068708 567
samux 1:80ab0d068708 568 /* Class / vendor specific */
samux 1:80ab0d068708 569 success = USBCallback_request();
samux 1:80ab0d068708 570
samux 1:80ab0d068708 571 if (!success)
samux 1:80ab0d068708 572 {
samux 1:80ab0d068708 573 /* Standard requests */
samux 1:80ab0d068708 574 if (!requestSetup())
samux 1:80ab0d068708 575 {
mjr 37:c5ac4ccf6597 576 printd("requestSetup() failed: type=%d, req=%d\r\n", (int)transfer.setup.bmRequestType.Type, (int)transfer.setup.bRequest);
samux 1:80ab0d068708 577 return false;
samux 1:80ab0d068708 578 }
samux 1:80ab0d068708 579 }
samux 1:80ab0d068708 580
samux 1:80ab0d068708 581 /* Check transfer size and direction */
mjr 36:20bb47609697 582 if (transfer.setup.wLength > 0)
samux 1:80ab0d068708 583 {
samux 1:80ab0d068708 584 if (transfer.setup.bmRequestType.dataTransferDirection \
samux 1:80ab0d068708 585 == DEVICE_TO_HOST)
samux 1:80ab0d068708 586 {
samux 1:80ab0d068708 587 /* IN data stage is required */
samux 1:80ab0d068708 588 if (transfer.direction != DEVICE_TO_HOST)
samux 1:80ab0d068708 589 {
mjr 37:c5ac4ccf6597 590 printd("controlSetup transfer direction wrong 1\r\n");
samux 1:80ab0d068708 591 return false;
samux 1:80ab0d068708 592 }
samux 1:80ab0d068708 593
samux 1:80ab0d068708 594 /* Transfer must be less than or equal to the size */
samux 1:80ab0d068708 595 /* requested by the host */
samux 1:80ab0d068708 596 if (transfer.remaining > transfer.setup.wLength)
samux 1:80ab0d068708 597 {
samux 1:80ab0d068708 598 transfer.remaining = transfer.setup.wLength;
samux 1:80ab0d068708 599 }
samux 1:80ab0d068708 600 }
samux 1:80ab0d068708 601 else
samux 1:80ab0d068708 602 {
mbed_official 25:7c72828865f3 603
samux 1:80ab0d068708 604 /* OUT data stage is required */
samux 1:80ab0d068708 605 if (transfer.direction != HOST_TO_DEVICE)
samux 1:80ab0d068708 606 {
mjr 37:c5ac4ccf6597 607 printd("controlSetup transfer direction wrong 2: type=%d, req=%d\r\n", (int)transfer.setup.bmRequestType.Type, (int)transfer.setup.bRequest);
samux 1:80ab0d068708 608 return false;
samux 1:80ab0d068708 609 }
samux 1:80ab0d068708 610
samux 1:80ab0d068708 611 /* Transfer must be equal to the size requested by the host */
samux 1:80ab0d068708 612 if (transfer.remaining != transfer.setup.wLength)
samux 1:80ab0d068708 613 {
mjr 37:c5ac4ccf6597 614 printd("controlSetup remaining length wrong: return len=%d, type=%d, req=%d, wvalue=%d, windex=%x, wlength=%d\r\n",
mjr 37:c5ac4ccf6597 615 transfer.remaining, transfer.setup.bmRequestType.Type, transfer.setup.bRequest, transfer.setup.wValue, transfer.setup.wIndex, transfer.setup.wLength);
samux 1:80ab0d068708 616 return false;
samux 1:80ab0d068708 617 }
samux 1:80ab0d068708 618 }
samux 1:80ab0d068708 619 }
samux 1:80ab0d068708 620 else
samux 1:80ab0d068708 621 {
samux 1:80ab0d068708 622 /* No data stage; transfer size must be zero */
samux 1:80ab0d068708 623 if (transfer.remaining != 0)
samux 1:80ab0d068708 624 {
mjr 37:c5ac4ccf6597 625 printd("controlSetup remaining length must be zero: return len=%d, type=%d, req=%d, wvalue=%d, windex=%x, wlength=%d\r\n",
mjr 37:c5ac4ccf6597 626 (int)transfer.remaining, (int)transfer.setup.bmRequestType.Type, (int)transfer.setup.bRequest, (int)transfer.setup.wValue, (int)transfer.setup.wIndex, (int)transfer.setup.wLength);
samux 1:80ab0d068708 627 return false;
samux 1:80ab0d068708 628 }
samux 1:80ab0d068708 629 }
samux 1:80ab0d068708 630
samux 1:80ab0d068708 631 /* Data or status stage if applicable */
mjr 36:20bb47609697 632 if (transfer.setup.wLength > 0)
samux 1:80ab0d068708 633 {
samux 1:80ab0d068708 634 if (transfer.setup.bmRequestType.dataTransferDirection \
samux 1:80ab0d068708 635 == DEVICE_TO_HOST)
samux 1:80ab0d068708 636 {
samux 1:80ab0d068708 637 /* Check if we'll need to send a zero length packet at */
samux 1:80ab0d068708 638 /* the end of this transfer */
samux 1:80ab0d068708 639 if (transfer.setup.wLength > transfer.remaining)
samux 1:80ab0d068708 640 {
samux 1:80ab0d068708 641 /* Device wishes to transfer less than host requested */
samux 1:80ab0d068708 642 if ((transfer.remaining % MAX_PACKET_SIZE_EP0) == 0)
samux 1:80ab0d068708 643 {
samux 1:80ab0d068708 644 /* Transfer is a multiple of EP0 max packet size */
samux 1:80ab0d068708 645 transfer.zlp = true;
samux 1:80ab0d068708 646 }
samux 1:80ab0d068708 647 }
samux 1:80ab0d068708 648
samux 1:80ab0d068708 649 /* IN stage */
samux 1:80ab0d068708 650 controlIn();
samux 1:80ab0d068708 651 }
samux 1:80ab0d068708 652 else
samux 1:80ab0d068708 653 {
samux 1:80ab0d068708 654 /* OUT stage */
samux 1:80ab0d068708 655 EP0read();
samux 1:80ab0d068708 656 }
samux 1:80ab0d068708 657 }
samux 1:80ab0d068708 658 else
samux 1:80ab0d068708 659 {
samux 1:80ab0d068708 660 /* Status stage */
samux 1:80ab0d068708 661 EP0write(NULL, 0);
samux 1:80ab0d068708 662 }
samux 1:80ab0d068708 663
samux 1:80ab0d068708 664 return true;
samux 1:80ab0d068708 665 }
samux 1:80ab0d068708 666
samux 1:80ab0d068708 667 void USBDevice::busReset(void)
samux 1:80ab0d068708 668 {
samux 1:80ab0d068708 669 device.state = DEFAULT;
samux 1:80ab0d068708 670 device.configuration = 0;
samux 1:80ab0d068708 671 device.suspended = false;
samux 1:80ab0d068708 672
samux 1:80ab0d068708 673 /* Call class / vendor specific busReset function */
samux 1:80ab0d068708 674 USBCallback_busReset();
samux 1:80ab0d068708 675 }
samux 1:80ab0d068708 676
samux 1:80ab0d068708 677 void USBDevice::EP0setupCallback(void)
samux 1:80ab0d068708 678 {
samux 1:80ab0d068708 679 /* Endpoint 0 setup event */
samux 1:80ab0d068708 680 if (!controlSetup())
samux 1:80ab0d068708 681 {
samux 1:80ab0d068708 682 /* Protocol stall */
samux 1:80ab0d068708 683 EP0stall();
samux 1:80ab0d068708 684 }
samux 1:80ab0d068708 685 }
samux 1:80ab0d068708 686
samux 1:80ab0d068708 687 void USBDevice::EP0out(void)
samux 1:80ab0d068708 688 {
samux 1:80ab0d068708 689 /* Endpoint 0 OUT data event */
samux 1:80ab0d068708 690 if (!controlOut())
samux 1:80ab0d068708 691 {
mjr 29:b502c11a3dff 692 /* Protocol stall; this will stall both endpoints */
samux 1:80ab0d068708 693 EP0stall();
samux 1:80ab0d068708 694 }
samux 1:80ab0d068708 695 }
samux 1:80ab0d068708 696
samux 1:80ab0d068708 697 void USBDevice::EP0in(void)
samux 1:80ab0d068708 698 {
samux 1:80ab0d068708 699 /* Endpoint 0 IN data event */
samux 1:80ab0d068708 700 if (!controlIn())
samux 1:80ab0d068708 701 {
samux 1:80ab0d068708 702 /* Protocol stall; this will stall both endpoints */
samux 1:80ab0d068708 703 EP0stall();
samux 1:80ab0d068708 704 }
samux 1:80ab0d068708 705 }
samux 1:80ab0d068708 706
samux 1:80ab0d068708 707 bool USBDevice::configured(void)
samux 1:80ab0d068708 708 {
samux 1:80ab0d068708 709 /* Returns true if device is in the CONFIGURED state */
samux 1:80ab0d068708 710 return (device.state == CONFIGURED);
samux 1:80ab0d068708 711 }
samux 1:80ab0d068708 712
mbed_official 18:78bdbce94509 713 void USBDevice::connect(bool blocking)
samux 1:80ab0d068708 714 {
samux 1:80ab0d068708 715 /* Connect device */
samux 1:80ab0d068708 716 USBHAL::connect();
mbed_official 25:7c72828865f3 717
mbed_official 18:78bdbce94509 718 if (blocking) {
mjr 37:c5ac4ccf6597 719 /* Block until configured */
mjr 37:c5ac4ccf6597 720 while (!configured()) { }
mbed_official 18:78bdbce94509 721 }
samux 1:80ab0d068708 722 }
samux 1:80ab0d068708 723
samux 1:80ab0d068708 724 void USBDevice::disconnect(void)
samux 1:80ab0d068708 725 {
samux 1:80ab0d068708 726 /* Disconnect device */
samux 1:80ab0d068708 727 USBHAL::disconnect();
mbed_official 26:8ef73dd868a0 728
mbed_official 26:8ef73dd868a0 729 /* Set initial device state */
mbed_official 26:8ef73dd868a0 730 device.state = POWERED;
mbed_official 26:8ef73dd868a0 731 device.configuration = 0;
mbed_official 26:8ef73dd868a0 732 device.suspended = false;
samux 1:80ab0d068708 733 }
samux 1:80ab0d068708 734
samux 1:80ab0d068708 735 CONTROL_TRANSFER * USBDevice::getTransferPtr(void)
samux 1:80ab0d068708 736 {
samux 1:80ab0d068708 737 return &transfer;
samux 1:80ab0d068708 738 }
samux 1:80ab0d068708 739
samux 1:80ab0d068708 740 bool USBDevice::addEndpoint(uint8_t endpoint, uint32_t maxPacket)
samux 1:80ab0d068708 741 {
samux 1:80ab0d068708 742 return realiseEndpoint(endpoint, maxPacket, 0);
samux 1:80ab0d068708 743 }
samux 1:80ab0d068708 744
samux 1:80ab0d068708 745 bool USBDevice::addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket)
samux 1:80ab0d068708 746 {
samux 1:80ab0d068708 747 /* For interrupt endpoints only */
samux 1:80ab0d068708 748 return realiseEndpoint(endpoint, maxPacket, RATE_FEEDBACK_MODE);
samux 1:80ab0d068708 749 }
samux 1:80ab0d068708 750
mjr 33:b0a3f6b27b07 751 uint8_t * USBDevice::findDescriptor(uint8_t descriptorType, int idx)
samux 1:80ab0d068708 752 {
samux 1:80ab0d068708 753 /* Find a descriptor within the list of descriptors */
samux 1:80ab0d068708 754 /* following a configuration descriptor. */
samux 1:80ab0d068708 755 uint16_t wTotalLength;
samux 1:80ab0d068708 756 uint8_t *ptr;
samux 1:80ab0d068708 757
samux 1:80ab0d068708 758 if (configurationDesc() == NULL)
samux 1:80ab0d068708 759 {
samux 1:80ab0d068708 760 return NULL;
samux 1:80ab0d068708 761 }
samux 1:80ab0d068708 762
samux 1:80ab0d068708 763 /* Check this is a configuration descriptor */
samux 1:80ab0d068708 764 if ((configurationDesc()[0] != CONFIGURATION_DESCRIPTOR_LENGTH) \
samux 1:80ab0d068708 765 || (configurationDesc()[1] != CONFIGURATION_DESCRIPTOR))
samux 1:80ab0d068708 766 {
samux 1:80ab0d068708 767 return NULL;
samux 1:80ab0d068708 768 }
samux 1:80ab0d068708 769
samux 1:80ab0d068708 770 wTotalLength = configurationDesc()[2] | (configurationDesc()[3] << 8);
samux 1:80ab0d068708 771
samux 1:80ab0d068708 772 /* Check there are some more descriptors to follow */
samux 1:80ab0d068708 773 if (wTotalLength <= (CONFIGURATION_DESCRIPTOR_LENGTH+2))
samux 1:80ab0d068708 774 /* +2 is for bLength and bDescriptorType of next descriptor */
samux 1:80ab0d068708 775 {
bogdanm 11:eeb3cbbaa996 776 return NULL;
samux 1:80ab0d068708 777 }
samux 1:80ab0d068708 778
samux 1:80ab0d068708 779 /* Start at first descriptor after the configuration descriptor */
samux 1:80ab0d068708 780 ptr = &(configurationDesc()[CONFIGURATION_DESCRIPTOR_LENGTH]);
samux 1:80ab0d068708 781
samux 1:80ab0d068708 782 do {
samux 1:80ab0d068708 783 if (ptr[1] /* bDescriptorType */ == descriptorType)
samux 1:80ab0d068708 784 {
mjr 33:b0a3f6b27b07 785 // Found - if the index has reached zero, it's the one we're
mjr 33:b0a3f6b27b07 786 // looking for; if not, just decrement the index and keep looking.
mjr 33:b0a3f6b27b07 787 if (idx == 0)
mjr 33:b0a3f6b27b07 788 return ptr;
mjr 33:b0a3f6b27b07 789 else
mjr 33:b0a3f6b27b07 790 --idx;
samux 1:80ab0d068708 791 }
samux 1:80ab0d068708 792
samux 1:80ab0d068708 793 /* Skip to next descriptor */
samux 1:80ab0d068708 794 ptr += ptr[0]; /* bLength */
samux 1:80ab0d068708 795 } while (ptr < (configurationDesc() + wTotalLength));
samux 1:80ab0d068708 796
samux 1:80ab0d068708 797 /* Reached end of the descriptors - not found */
samux 1:80ab0d068708 798 return NULL;
samux 1:80ab0d068708 799 }
samux 1:80ab0d068708 800
samux 1:80ab0d068708 801
samux 1:80ab0d068708 802 void USBDevice::connectStateChanged(unsigned int connected)
samux 1:80ab0d068708 803 {
samux 1:80ab0d068708 804 }
samux 1:80ab0d068708 805
samux 1:80ab0d068708 806 void USBDevice::suspendStateChanged(unsigned int suspended)
samux 1:80ab0d068708 807 {
samux 1:80ab0d068708 808 }
samux 1:80ab0d068708 809
samux 1:80ab0d068708 810
samux 1:80ab0d068708 811 USBDevice::USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release){
mbed_official 25:7c72828865f3 812 VENDOR_ID = vendor_id;
mbed_official 25:7c72828865f3 813 PRODUCT_ID = product_id;
samux 1:80ab0d068708 814 PRODUCT_RELEASE = product_release;
samux 1:80ab0d068708 815
samux 1:80ab0d068708 816 /* Set initial device state */
samux 1:80ab0d068708 817 device.state = POWERED;
samux 1:80ab0d068708 818 device.configuration = 0;
samux 1:80ab0d068708 819 device.suspended = false;
samux 1:80ab0d068708 820 };
samux 1:80ab0d068708 821
samux 1:80ab0d068708 822
samux 1:80ab0d068708 823 bool USBDevice::readStart(uint8_t endpoint, uint32_t maxSize)
samux 1:80ab0d068708 824 {
samux 1:80ab0d068708 825 return endpointRead(endpoint, maxSize) == EP_PENDING;
samux 1:80ab0d068708 826 }
samux 1:80ab0d068708 827
samux 1:80ab0d068708 828
samux 1:80ab0d068708 829 bool USBDevice::write(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize)
samux 1:80ab0d068708 830 {
samux 1:80ab0d068708 831 EP_STATUS result;
samux 1:80ab0d068708 832
samux 1:80ab0d068708 833 if (size > maxSize)
samux 1:80ab0d068708 834 {
samux 1:80ab0d068708 835 return false;
samux 1:80ab0d068708 836 }
mbed_official 25:7c72828865f3 837
mbed_official 25:7c72828865f3 838
samux 1:80ab0d068708 839 if(!configured()) {
samux 1:80ab0d068708 840 return false;
samux 1:80ab0d068708 841 }
mbed_official 25:7c72828865f3 842
samux 1:80ab0d068708 843 /* Send report */
mjr 34:884405d998bb 844 do {
mjr 34:884405d998bb 845 result = endpointWrite(endpoint, buffer, size);
mjr 34:884405d998bb 846 } while ((result == EP_BUSY) && configured());
samux 1:80ab0d068708 847
samux 1:80ab0d068708 848 if (result != EP_PENDING)
samux 1:80ab0d068708 849 {
samux 1:80ab0d068708 850 return false;
samux 1:80ab0d068708 851 }
samux 1:80ab0d068708 852
samux 1:80ab0d068708 853 /* Wait for completion */
samux 1:80ab0d068708 854 do {
samux 1:80ab0d068708 855 result = endpointWriteResult(endpoint);
samux 1:80ab0d068708 856 } while ((result == EP_PENDING) && configured());
samux 1:80ab0d068708 857
samux 1:80ab0d068708 858 return (result == EP_COMPLETED);
samux 1:80ab0d068708 859 }
samux 1:80ab0d068708 860
samux 1:80ab0d068708 861
samux 1:80ab0d068708 862 bool USBDevice::writeNB(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize)
samux 1:80ab0d068708 863 {
samux 1:80ab0d068708 864 EP_STATUS result;
samux 1:80ab0d068708 865
samux 1:80ab0d068708 866 if (size > maxSize)
samux 1:80ab0d068708 867 {
samux 1:80ab0d068708 868 return false;
samux 1:80ab0d068708 869 }
mbed_official 25:7c72828865f3 870
samux 1:80ab0d068708 871 if(!configured()) {
samux 1:80ab0d068708 872 return false;
samux 1:80ab0d068708 873 }
samux 1:80ab0d068708 874
samux 1:80ab0d068708 875 /* Send report */
samux 1:80ab0d068708 876 result = endpointWrite(endpoint, buffer, size);
samux 1:80ab0d068708 877
samux 1:80ab0d068708 878 if (result != EP_PENDING)
samux 1:80ab0d068708 879 {
samux 1:80ab0d068708 880 return false;
samux 1:80ab0d068708 881 }
samux 1:80ab0d068708 882
samux 1:80ab0d068708 883 result = endpointWriteResult(endpoint);
samux 1:80ab0d068708 884
samux 1:80ab0d068708 885 return (result == EP_COMPLETED);
samux 1:80ab0d068708 886 }
samux 1:80ab0d068708 887
mjr 32:a8eb758f4074 888 bool USBDevice::writeTO(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize, int timeout_ms)
mjr 32:a8eb758f4074 889 {
mjr 32:a8eb758f4074 890 EP_STATUS result;
mjr 32:a8eb758f4074 891
mjr 32:a8eb758f4074 892 if (size > maxSize)
mjr 32:a8eb758f4074 893 {
mjr 32:a8eb758f4074 894 return false;
mjr 32:a8eb758f4074 895 }
mjr 32:a8eb758f4074 896
mjr 32:a8eb758f4074 897
mjr 32:a8eb758f4074 898 if(!configured()) {
mjr 32:a8eb758f4074 899 return false;
mjr 32:a8eb758f4074 900 }
mjr 34:884405d998bb 901
mjr 34:884405d998bb 902 /* set up a timer for monitoring the timeout period */
mjr 34:884405d998bb 903 Timer t;
mjr 34:884405d998bb 904 t.start();
mjr 32:a8eb758f4074 905
mjr 32:a8eb758f4074 906 /* Send report */
mjr 34:884405d998bb 907 do {
mjr 34:884405d998bb 908 result = endpointWrite(endpoint, buffer, size);
mjr 34:884405d998bb 909 } while ((result == EP_BUSY) && configured() && t.read_ms() < timeout_ms);
mjr 34:884405d998bb 910
mjr 32:a8eb758f4074 911 if (result != EP_PENDING)
mjr 32:a8eb758f4074 912 {
mjr 32:a8eb758f4074 913 return false;
mjr 32:a8eb758f4074 914 }
mjr 32:a8eb758f4074 915
mjr 32:a8eb758f4074 916 /* Wait for completion or timeout */
mjr 32:a8eb758f4074 917 do {
mjr 32:a8eb758f4074 918 result = endpointWriteResult(endpoint);
mjr 32:a8eb758f4074 919 } while ((result == EP_PENDING) && configured() && t.read_ms() < timeout_ms);
mjr 32:a8eb758f4074 920
mjr 32:a8eb758f4074 921 return (result == EP_COMPLETED);
mjr 32:a8eb758f4074 922 }
mjr 32:a8eb758f4074 923
samux 1:80ab0d068708 924 bool USBDevice::readEP(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize)
samux 1:80ab0d068708 925 {
samux 1:80ab0d068708 926 EP_STATUS result;
mbed_official 25:7c72828865f3 927
samux 1:80ab0d068708 928 if(!configured()) {
samux 1:80ab0d068708 929 return false;
samux 1:80ab0d068708 930 }
samux 1:80ab0d068708 931
samux 1:80ab0d068708 932 /* Wait for completion */
samux 1:80ab0d068708 933 do {
samux 1:80ab0d068708 934 result = endpointReadResult(endpoint, buffer, size);
samux 1:80ab0d068708 935 } while ((result == EP_PENDING) && configured());
samux 1:80ab0d068708 936
samux 1:80ab0d068708 937 return (result == EP_COMPLETED);
samux 1:80ab0d068708 938 }
samux 1:80ab0d068708 939
samux 1:80ab0d068708 940
samux 1:80ab0d068708 941 bool USBDevice::readEP_NB(uint8_t endpoint, uint8_t * buffer, uint32_t * size, uint32_t maxSize)
samux 1:80ab0d068708 942 {
samux 1:80ab0d068708 943 EP_STATUS result;
mbed_official 25:7c72828865f3 944
samux 1:80ab0d068708 945 if(!configured()) {
samux 1:80ab0d068708 946 return false;
samux 1:80ab0d068708 947 }
samux 1:80ab0d068708 948
samux 1:80ab0d068708 949 result = endpointReadResult(endpoint, buffer, size);
mbed_official 25:7c72828865f3 950
samux 1:80ab0d068708 951 return (result == EP_COMPLETED);
samux 1:80ab0d068708 952 }
samux 1:80ab0d068708 953
samux 1:80ab0d068708 954
samux 1:80ab0d068708 955
samux 1:80ab0d068708 956 uint8_t * USBDevice::deviceDesc() {
samux 1:80ab0d068708 957 static uint8_t deviceDescriptor[] = {
samux 1:80ab0d068708 958 DEVICE_DESCRIPTOR_LENGTH, /* bLength */
samux 1:80ab0d068708 959 DEVICE_DESCRIPTOR, /* bDescriptorType */
samux 1:80ab0d068708 960 LSB(USB_VERSION_2_0), /* bcdUSB (LSB) */
samux 1:80ab0d068708 961 MSB(USB_VERSION_2_0), /* bcdUSB (MSB) */
samux 1:80ab0d068708 962 0x00, /* bDeviceClass */
samux 1:80ab0d068708 963 0x00, /* bDeviceSubClass */
samux 1:80ab0d068708 964 0x00, /* bDeviceprotocol */
samux 1:80ab0d068708 965 MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */
bogdanm 11:eeb3cbbaa996 966 (uint8_t)(LSB(VENDOR_ID)), /* idVendor (LSB) */
bogdanm 11:eeb3cbbaa996 967 (uint8_t)(MSB(VENDOR_ID)), /* idVendor (MSB) */
bogdanm 11:eeb3cbbaa996 968 (uint8_t)(LSB(PRODUCT_ID)), /* idProduct (LSB) */
bogdanm 11:eeb3cbbaa996 969 (uint8_t)(MSB(PRODUCT_ID)), /* idProduct (MSB) */
bogdanm 11:eeb3cbbaa996 970 (uint8_t)(LSB(PRODUCT_RELEASE)), /* bcdDevice (LSB) */
bogdanm 11:eeb3cbbaa996 971 (uint8_t)(MSB(PRODUCT_RELEASE)), /* bcdDevice (MSB) */
samux 1:80ab0d068708 972 STRING_OFFSET_IMANUFACTURER, /* iManufacturer */
samux 1:80ab0d068708 973 STRING_OFFSET_IPRODUCT, /* iProduct */
samux 1:80ab0d068708 974 STRING_OFFSET_ISERIAL, /* iSerialNumber */
samux 1:80ab0d068708 975 0x01 /* bNumConfigurations */
samux 1:80ab0d068708 976 };
samux 1:80ab0d068708 977 return deviceDescriptor;
samux 1:80ab0d068708 978 }
samux 1:80ab0d068708 979
samux 1:80ab0d068708 980 uint8_t * USBDevice::stringLangidDesc() {
samux 1:80ab0d068708 981 static uint8_t stringLangidDescriptor[] = {
samux 1:80ab0d068708 982 0x04, /*bLength*/
samux 1:80ab0d068708 983 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
mbed_official 17:bbd6dac92961 984 0x09,0x04, /*bString Lang ID - 0x0409 - English*/
samux 1:80ab0d068708 985 };
samux 1:80ab0d068708 986 return stringLangidDescriptor;
samux 1:80ab0d068708 987 }
samux 1:80ab0d068708 988
samux 1:80ab0d068708 989 uint8_t * USBDevice::stringImanufacturerDesc() {
samux 1:80ab0d068708 990 static uint8_t stringImanufacturerDescriptor[] = {
samux 1:80ab0d068708 991 0x12, /*bLength*/
samux 1:80ab0d068708 992 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
samux 1:80ab0d068708 993 'm',0,'b',0,'e',0,'d',0,'.',0,'o',0,'r',0,'g',0, /*bString iManufacturer - mbed.org*/
samux 1:80ab0d068708 994 };
samux 1:80ab0d068708 995 return stringImanufacturerDescriptor;
samux 1:80ab0d068708 996 }
samux 1:80ab0d068708 997
samux 1:80ab0d068708 998 uint8_t * USBDevice::stringIserialDesc() {
samux 1:80ab0d068708 999 static uint8_t stringIserialDescriptor[] = {
samux 1:80ab0d068708 1000 0x16, /*bLength*/
samux 1:80ab0d068708 1001 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
samux 1:80ab0d068708 1002 '0',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0, /*bString iSerial - 0123456789*/
samux 1:80ab0d068708 1003 };
samux 1:80ab0d068708 1004 return stringIserialDescriptor;
samux 1:80ab0d068708 1005 }
samux 1:80ab0d068708 1006
samux 1:80ab0d068708 1007 uint8_t * USBDevice::stringIConfigurationDesc() {
samux 1:80ab0d068708 1008 static uint8_t stringIconfigurationDescriptor[] = {
samux 1:80ab0d068708 1009 0x06, /*bLength*/
samux 1:80ab0d068708 1010 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
samux 1:80ab0d068708 1011 '0',0,'1',0, /*bString iConfiguration - 01*/
samux 1:80ab0d068708 1012 };
samux 1:80ab0d068708 1013 return stringIconfigurationDescriptor;
samux 1:80ab0d068708 1014 }
samux 1:80ab0d068708 1015
samux 1:80ab0d068708 1016 uint8_t * USBDevice::stringIinterfaceDesc() {
samux 1:80ab0d068708 1017 static uint8_t stringIinterfaceDescriptor[] = {
samux 1:80ab0d068708 1018 0x08, /*bLength*/
samux 1:80ab0d068708 1019 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
samux 1:80ab0d068708 1020 'U',0,'S',0,'B',0, /*bString iInterface - USB*/
samux 1:80ab0d068708 1021 };
samux 1:80ab0d068708 1022 return stringIinterfaceDescriptor;
samux 1:80ab0d068708 1023 }
samux 1:80ab0d068708 1024
samux 1:80ab0d068708 1025 uint8_t * USBDevice::stringIproductDesc() {
samux 1:80ab0d068708 1026 static uint8_t stringIproductDescriptor[] = {
samux 1:80ab0d068708 1027 0x16, /*bLength*/
samux 1:80ab0d068708 1028 STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
samux 1:80ab0d068708 1029 'U',0,'S',0,'B',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 /*bString iProduct - USB DEVICE*/
samux 1:80ab0d068708 1030 };
samux 1:80ab0d068708 1031 return stringIproductDescriptor;
samux 1:80ab0d068708 1032 }