USBDevice

Dependents:   QEI_X1_LCD_test3 macnica_test

Committer:
toucyy
Date:
Thu Apr 18 07:49:37 2013 +0000
Revision:
0:2d8d0b73e1ff
[mbed] converted /QEI_HelloWorld/USBDevice

Who changed what in which revision?

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