partly working USB Device lib for STM32F746NG Discovery both Interface are working

Dependents:   DISCO-F746NG-USB_Device McLighTT project_Keyboard_to_the_Keyboard MIDIInstrumentPADProject ... more

Committer:
DieterGraef
Date:
Sun Jul 31 17:47:35 2016 +0000
Revision:
0:0a2eaa300982
partly working USB Device library - serial and MIDI is working

Who changed what in which revision?

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