USBDevice stack

Dependents:   erg USBSerial_HelloWorld Slingshot SuperScanner ... more

Committer:
samux
Date:
Wed May 30 18:28:11 2012 +0000
Revision:
0:140cdf8e2d60

        

Who changed what in which revision?

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