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