usb device

Committer:
ppo
Date:
Sat May 14 17:24:10 2022 +0000
Revision:
0:c1e89c49eae5
commit

Who changed what in which revision?

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