Forked to make modifications to bring the USBHID into USB compliance and add additional features.

Dependents:   HW4_AudioControl

Fork of USBDevice by mbed official

As of Revision 18 everything in the USBHID specification is now implemented, except Multi-reports.

Revision comments for changelist 18

USBHID.cpp

  • Added SET_PROTOCOL support
  • Added GET_PROTOCOL support
  • protocolSate is set to 1 by default to match USB HID specification. This variable should be checked to determine which format theinput report should have. 1 - Use the user specified report format. 0 - Use the BOOT protocol report format.

Revision comments for changelist 16

  • HID_REPORT transformed from structure to class. This was done for several reasons.
  1. When multiple reports are used the 64 byte size for every report becomes a problem.
  2. The length value should always remain the same for a report, Make the constructor set the vale at the same time it allocates memory for the DATA area.
  • By default the data will be an array of MAX_HID_REPORT_SIZE like the structure,
  • When given a length argument, the hid_report.length will be set, and hid_report.data will be an array of the size given.
  • Length zero causes data to be NULL
  • Mostly backwards compatible. The definition of a destructor caused a compiler error in USBMouse::update and USBMousekeyboard::update. This error was caused by instatiation of HID_REPORT in the middle of an IF logic statement. These files have been modified. The error complained that the logic skipped object initialization. The HID_REPORT has been moved to the class definition. Since both ABSOLUTE and RELATIVE modes used the HID_REPORT, this seems to make more sense. Previously the hid_report would be instatiated in <class>::mousesend and <class>::update.

Revision comments for changelist 14

USBdevice.cpp

  • Modified USB device state to change from Configure when disconnect is called.
  • Modified the call back function for when the suspend state changes. This should be used to turn off peripherals to conserve power.

Revision comments for changelist 13

USBdevice.cpp

  • ) Changed DEBUG messages to be more descriptive for string descriptor
  • ) Bug fix: Control Transfers did not actually transfer the data from Buffer to transfer->ptr

USBHIDTypes.h

  • ) Added ALL CLASS request to KEYWORD list
  • ) Added KEYWORDS for report type

USBHID.h

  • ) Added a new constructor to specify size of feature report
  • ) Added HID_REPORT inputReport and featureReport
  • ) Added data structures to support IDLE rate
  • ) Added data structures to support callback functions

USBHID.cpp

  • ) Changed constructor to initialize new feature data structures
  • ) Implemented Set_IDLE/GET_IDLE and the periodic resend of non-changed data
  • ) Implemented HID specification required control transfer GET_REPORT
  • ) Fixed issue where Intreput transfers and control transfers did not access the same data structures.
  • ) Implemented Feature reports
  • ) Implemented Callback Hooks for get_report/set_report actions.
  • ) Added callback hooks for interupt actions in the new functions.
  • ) interupt transfer can now write to outputReport
  • ) Modified SET_REPORT code to function for multiple types.
  • ) Refactored some code in preperation to add multi report support
Test NumberTest DescriptionTest ResultNotes
1Use USBmouse to verify backward compatibility of constructor and methodsPass
2Test SET_REPORT can set a feature reportPass
3Test GET_REPORT can retrieve a feature reportPass
4Test SET_IDLE sets up a reoccuring triggerPassIOCTL_SET_POLL_FREQUENCY_MSEC does not function for the windows HID driver. A Special test program is used to rearm the IDLE rate after windows sets it to zero
5Test SET_IDLE disables a triggerPassWindows automatically sends this command to a HID device when it is inserted.
6Enabled DEBUG in USBDevice.cpp and generated str descriptor requests.Pass
7Test SET_REPORT can set an output reportPass
8Test GET_REPORT can retrieve an output reportPass
9ReadFile, accesses the input_reportPass
10WriteFile accesses the output_report, via interupt transfer when ep1_out is used.Pass
11WriteFile accesses the output_report, via control transfer when ep1_out is NOT used.Not Tested
12Callback hooks trigger independently for each type of set_report/get_reportPass
13New constructor sets feature_report sizePass
14Control transfer SET_REPORT and writeFile access the same data structureBUGThe same data structure is accessed, but the data transfer size is different. The writeFile strips the leading byte which is the report ID, The Control transfer keeps the byte.
15Control transfer GET_REPORT and readFile access the same data structureBUGThe same dtat structure is accessed, but the data transfer size is different. The readFile strips the leading byte which is the report ID, The Control transfer keeps the byte.
16Test GET_IDLE retrieves the IDLE rateUnknownWindows HID driver does not implement IOCTL_HID_GET_POLL_FREQUENCY_MSEC
Committer:
jakowisp
Date:
Thu Aug 08 08:02:46 2013 +0000
Revision:
18:cb3afa532fcd
Parent:
14:00cd29199e0e
Default ProtocolState was incorrectly being set to 0:Boot when the HID specification states that the default should be 1:Report

Who changed what in which revision?

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