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