MIDI Stop Controller V1.0 suitable for driving Hauptwerk digital organ software. Written for the KL25Z uses BusInOut and will drive up to 16 illuminated push buttons each switch uses a single I/O pin to both drive the LED and act as a switch input. Pressing a button will alternately send MIDI note on / off messages and turn the LED on or off. If corresponding MIDI note on/off messages are received these will be used to drive the LEDs in preference to the locally generated LED signals. The MIDI channel used to send can be selected by jumpers on 4 pins of the J2 header.

Dependencies:   mbed

Committer:
djbottrill
Date:
Sat Sep 14 21:32:06 2013 +0000
Revision:
0:aac55e1fc12f
V1.0 MIDI Stop Controller

Who changed what in which revision?

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