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:
9:354942d2fa38
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 8:335f2506f422 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
samux 8:335f2506f422 2 *
samux 8:335f2506f422 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
samux 8:335f2506f422 4 * and associated documentation files (the "Software"), to deal in the Software without
samux 8:335f2506f422 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
samux 8:335f2506f422 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
samux 8:335f2506f422 7 * Software is furnished to do so, subject to the following conditions:
samux 8:335f2506f422 8 *
samux 8:335f2506f422 9 * The above copyright notice and this permission notice shall be included in all copies or
samux 8:335f2506f422 10 * substantial portions of the Software.
samux 8:335f2506f422 11 *
samux 8:335f2506f422 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
samux 8:335f2506f422 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
samux 8:335f2506f422 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
samux 8:335f2506f422 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
samux 8:335f2506f422 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
samux 8:335f2506f422 17 */
samux 8:335f2506f422 18
samux 8:335f2506f422 19 #if defined(TARGET_KL25Z)
samux 8:335f2506f422 20
samux 8:335f2506f422 21 #include "USBHAL.h"
samux 8:335f2506f422 22
samux 8:335f2506f422 23 USBHAL * USBHAL::instance;
samux 8:335f2506f422 24
samux 8:335f2506f422 25 static volatile int epComplete = 0;
samux 8:335f2506f422 26
samux 8:335f2506f422 27 // Convert physical endpoint number to register bit
samux 8:335f2506f422 28 #define EP(endpoint) (1<<(endpoint))
samux 8:335f2506f422 29
samux 8:335f2506f422 30 // Convert physical to logical
samux 8:335f2506f422 31 #define PHY_TO_LOG(endpoint) ((endpoint)>>1)
samux 8:335f2506f422 32
samux 8:335f2506f422 33 // Get endpoint direction
samux 8:335f2506f422 34 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
samux 8:335f2506f422 35 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
samux 8:335f2506f422 36
samux 8:335f2506f422 37 #define BD_OWN_MASK (1<<7)
samux 8:335f2506f422 38 #define BD_DATA01_MASK (1<<6)
samux 8:335f2506f422 39 #define BD_KEEP_MASK (1<<5)
samux 8:335f2506f422 40 #define BD_NINC_MASK (1<<4)
samux 8:335f2506f422 41 #define BD_DTS_MASK (1<<3)
samux 8:335f2506f422 42 #define BD_STALL_MASK (1<<2)
samux 8:335f2506f422 43
samux 8:335f2506f422 44 #define TX 1
samux 8:335f2506f422 45 #define RX 0
samux 8:335f2506f422 46 #define ODD 0
samux 8:335f2506f422 47 #define EVEN 1
samux 8:335f2506f422 48 // this macro waits a physical endpoint number
samux 8:335f2506f422 49 #define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 * odd)))
samux 8:335f2506f422 50
samux 8:335f2506f422 51 #define SETUP_TOKEN 0x0D
samux 8:335f2506f422 52 #define IN_TOKEN 0x09
samux 8:335f2506f422 53 #define OUT_TOKEN 0x01
samux 8:335f2506f422 54 #define TOK_PID(idx) ((bdt[idx].info >> 2) & 0x0F)
samux 8:335f2506f422 55
samux 8:335f2506f422 56 // for each endpt: 8 bytes
samux 8:335f2506f422 57 typedef struct BDT {
samux 8:335f2506f422 58 uint8_t info; // BD[0:7]
samux 8:335f2506f422 59 uint8_t dummy; // RSVD: BD[8:15]
samux 8:335f2506f422 60 uint16_t byte_count; // BD[16:32]
samux 8:335f2506f422 61 uint32_t address; // Addr
samux 8:335f2506f422 62 } BDT;
samux 8:335f2506f422 63
samux 8:335f2506f422 64
samux 8:335f2506f422 65 // there are:
samux 8:335f2506f422 66 // * 16 bidirectionnal endpt -> 32 physical endpt
samux 8:335f2506f422 67 // * as there are ODD and EVEN buffer -> 32*2 bdt
samux 8:335f2506f422 68 __attribute__((__aligned__(512))) BDT bdt[NUMBER_OF_PHYSICAL_ENDPOINTS * 2];
samux 9:354942d2fa38 69 uint8_t * endpoint_buffer[(NUMBER_OF_PHYSICAL_ENDPOINTS - 2) * 2];
samux 9:354942d2fa38 70 uint8_t * endpoint_buffer_iso[2*2];
samux 8:335f2506f422 71
samux 8:335f2506f422 72 static uint8_t set_addr = 0;
samux 8:335f2506f422 73 static uint8_t addr = 0;
samux 8:335f2506f422 74
samux 8:335f2506f422 75 static uint32_t Data1 = 0x55555555;
samux 8:335f2506f422 76
samux 8:335f2506f422 77 static uint32_t frameNumber() {
samux 8:335f2506f422 78 return((USB0->FRMNUML | (USB0->FRMNUMH << 8) & 0x07FF));
samux 8:335f2506f422 79 }
samux 8:335f2506f422 80
samux 8:335f2506f422 81 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
samux 8:335f2506f422 82 return 0;
samux 8:335f2506f422 83 }
samux 8:335f2506f422 84
samux 8:335f2506f422 85 USBHAL::USBHAL(void) {
samux 8:335f2506f422 86 // Disable IRQ
samux 8:335f2506f422 87 NVIC_DisableIRQ(USB0_IRQn);
samux 8:335f2506f422 88
samux 8:335f2506f422 89 // fill in callback array
samux 8:335f2506f422 90 epCallback[0] = &USBHAL::EP1_OUT_callback;
samux 8:335f2506f422 91 epCallback[1] = &USBHAL::EP1_IN_callback;
samux 8:335f2506f422 92 epCallback[2] = &USBHAL::EP2_OUT_callback;
samux 8:335f2506f422 93 epCallback[3] = &USBHAL::EP2_IN_callback;
samux 8:335f2506f422 94 epCallback[4] = &USBHAL::EP3_OUT_callback;
samux 8:335f2506f422 95 epCallback[5] = &USBHAL::EP3_IN_callback;
samux 8:335f2506f422 96 epCallback[6] = &USBHAL::EP4_OUT_callback;
samux 8:335f2506f422 97 epCallback[7] = &USBHAL::EP4_IN_callback;
samux 8:335f2506f422 98 epCallback[8] = &USBHAL::EP5_OUT_callback;
samux 8:335f2506f422 99 epCallback[9] = &USBHAL::EP5_IN_callback;
samux 8:335f2506f422 100 epCallback[10] = &USBHAL::EP6_OUT_callback;
samux 8:335f2506f422 101 epCallback[11] = &USBHAL::EP6_IN_callback;
samux 8:335f2506f422 102 epCallback[12] = &USBHAL::EP7_OUT_callback;
samux 8:335f2506f422 103 epCallback[13] = &USBHAL::EP7_IN_callback;
samux 8:335f2506f422 104 epCallback[14] = &USBHAL::EP8_OUT_callback;
samux 8:335f2506f422 105 epCallback[15] = &USBHAL::EP8_IN_callback;
samux 8:335f2506f422 106 epCallback[16] = &USBHAL::EP9_OUT_callback;
samux 8:335f2506f422 107 epCallback[17] = &USBHAL::EP9_IN_callback;
samux 8:335f2506f422 108 epCallback[18] = &USBHAL::EP10_OUT_callback;
samux 8:335f2506f422 109 epCallback[19] = &USBHAL::EP10_IN_callback;
samux 8:335f2506f422 110 epCallback[20] = &USBHAL::EP11_OUT_callback;
samux 8:335f2506f422 111 epCallback[21] = &USBHAL::EP11_IN_callback;
samux 8:335f2506f422 112 epCallback[22] = &USBHAL::EP12_OUT_callback;
samux 8:335f2506f422 113 epCallback[23] = &USBHAL::EP12_IN_callback;
samux 8:335f2506f422 114 epCallback[24] = &USBHAL::EP13_OUT_callback;
samux 8:335f2506f422 115 epCallback[25] = &USBHAL::EP13_IN_callback;
samux 8:335f2506f422 116 epCallback[26] = &USBHAL::EP14_OUT_callback;
samux 8:335f2506f422 117 epCallback[27] = &USBHAL::EP14_IN_callback;
samux 8:335f2506f422 118 epCallback[28] = &USBHAL::EP15_OUT_callback;
samux 8:335f2506f422 119 epCallback[29] = &USBHAL::EP15_IN_callback;
samux 8:335f2506f422 120
samux 8:335f2506f422 121
samux 8:335f2506f422 122 // choose usb src as PLL
samux 8:335f2506f422 123 SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
samux 8:335f2506f422 124
samux 8:335f2506f422 125 // enable OTG clock
samux 8:335f2506f422 126 SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
samux 8:335f2506f422 127
samux 8:335f2506f422 128 // Attach IRQ
samux 8:335f2506f422 129 instance = this;
samux 8:335f2506f422 130 NVIC_SetVector(USB0_IRQn, (uint32_t)&_usbisr);
samux 8:335f2506f422 131 NVIC_EnableIRQ(USB0_IRQn);
samux 8:335f2506f422 132
samux 8:335f2506f422 133 // USB Module Configuration
samux 8:335f2506f422 134 // Reset USB Module
samux 8:335f2506f422 135 USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
samux 8:335f2506f422 136 while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
samux 8:335f2506f422 137
samux 8:335f2506f422 138 // Set BDT Base Register
samux 8:335f2506f422 139 USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
samux 8:335f2506f422 140 USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
samux 8:335f2506f422 141 USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
samux 8:335f2506f422 142
samux 8:335f2506f422 143 // Clear interrupt flag
samux 8:335f2506f422 144 USB0->ISTAT = 0xff;
samux 8:335f2506f422 145
samux 8:335f2506f422 146 // USB Interrupt Enablers
samux 8:335f2506f422 147 USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK |
samux 8:335f2506f422 148 USB_INTEN_SOFTOKEN_MASK |
samux 8:335f2506f422 149 USB_INTEN_ERROREN_MASK |
samux 8:335f2506f422 150 USB_INTEN_USBRSTEN_MASK;
samux 8:335f2506f422 151
samux 8:335f2506f422 152 // Disable weak pull downs
samux 8:335f2506f422 153 USB0->USBCTRL &= ~(USB_USBCTRL_PDE_MASK | USB_USBCTRL_SUSP_MASK);
samux 8:335f2506f422 154
samux 8:335f2506f422 155 USB0->USBTRC0 |= 0x40;
samux 8:335f2506f422 156 }
samux 8:335f2506f422 157
samux 8:335f2506f422 158 USBHAL::~USBHAL(void) { }
samux 8:335f2506f422 159
samux 8:335f2506f422 160 void USBHAL::connect(void) {
samux 8:335f2506f422 161 // enable USB
samux 8:335f2506f422 162 USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
samux 8:335f2506f422 163 // Pull up enable
samux 8:335f2506f422 164 USB0->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
samux 8:335f2506f422 165 }
samux 8:335f2506f422 166
samux 8:335f2506f422 167 void USBHAL::disconnect(void) {
samux 8:335f2506f422 168 // disable USB
samux 8:335f2506f422 169 USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
samux 8:335f2506f422 170 // Pull up disable
samux 8:335f2506f422 171 USB0->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
samux 8:335f2506f422 172 }
samux 8:335f2506f422 173
samux 8:335f2506f422 174 void USBHAL::configureDevice(void) {
samux 8:335f2506f422 175 // not needed
samux 8:335f2506f422 176 }
samux 8:335f2506f422 177
samux 8:335f2506f422 178 void USBHAL::unconfigureDevice(void) {
samux 8:335f2506f422 179 // not needed
samux 8:335f2506f422 180 }
samux 8:335f2506f422 181
samux 8:335f2506f422 182 void USBHAL::setAddress(uint8_t address) {
samux 8:335f2506f422 183 // we don't set the address now otherwise the usb controller does not ack
samux 8:335f2506f422 184 // we set a flag instead
samux 8:335f2506f422 185 // see usbisr when an IN token is received
samux 8:335f2506f422 186 set_addr = 1;
samux 8:335f2506f422 187 addr = address;
samux 8:335f2506f422 188 }
samux 8:335f2506f422 189
samux 8:335f2506f422 190 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
samux 8:335f2506f422 191 uint32_t handshake_flag = 0;
samux 8:335f2506f422 192 uint8_t * buf;
samux 8:335f2506f422 193
samux 8:335f2506f422 194 if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
samux 8:335f2506f422 195 return false;
samux 8:335f2506f422 196 }
samux 8:335f2506f422 197
samux 8:335f2506f422 198 uint32_t log_endpoint = PHY_TO_LOG(endpoint);
samux 8:335f2506f422 199
samux 8:335f2506f422 200 if ((flags & ISOCHRONOUS) == 0) {
samux 8:335f2506f422 201 handshake_flag = USB_ENDPT_EPHSHK_MASK;
samux 9:354942d2fa38 202 if (IN_EP(endpoint)) {
samux 9:354942d2fa38 203 endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD )] = (uint8_t *) malloc (64*2);
samux 8:335f2506f422 204 buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD )][0];
samux 9:354942d2fa38 205 } else {
samux 9:354942d2fa38 206 endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD )] = (uint8_t *) malloc (64*2);
samux 8:335f2506f422 207 buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD )][0];
samux 9:354942d2fa38 208 }
samux 8:335f2506f422 209 } else {
samux 9:354942d2fa38 210 if (IN_EP(endpoint)) {
samux 9:354942d2fa38 211 endpoint_buffer_iso[2] = (uint8_t *) malloc (1023*2);
samux 8:335f2506f422 212 buf = &endpoint_buffer_iso[2][0];
samux 9:354942d2fa38 213 } else {
samux 9:354942d2fa38 214 endpoint_buffer_iso[0] = (uint8_t *) malloc (1023*2);
samux 8:335f2506f422 215 buf = &endpoint_buffer_iso[0][0];
samux 9:354942d2fa38 216 }
samux 8:335f2506f422 217 }
samux 8:335f2506f422 218
samux 8:335f2506f422 219 // IN endpt -> device to host (TX)
samux 8:335f2506f422 220 if (IN_EP(endpoint)) {
samux 8:335f2506f422 221 USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint)
samux 8:335f2506f422 222 USB_ENDPT_EPTXEN_MASK; // en TX (IN) tran
samux 8:335f2506f422 223 bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].address = (uint32_t) buf;
samux 8:335f2506f422 224 bdt[EP_BDT_IDX(log_endpoint, TX, EVEN)].address = 0;
samux 8:335f2506f422 225 }
samux 8:335f2506f422 226 // OUT endpt -> host to device (RX)
samux 8:335f2506f422 227 else {
samux 8:335f2506f422 228 USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint)
samux 8:335f2506f422 229 USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran.
samux 8:335f2506f422 230 bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket;
samux 8:335f2506f422 231 bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf;
samux 8:335f2506f422 232 bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_OWN_MASK | BD_DTS_MASK;
samux 8:335f2506f422 233 bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0;
samux 8:335f2506f422 234 }
samux 8:335f2506f422 235
samux 8:335f2506f422 236 Data1 |= (1 << endpoint);
samux 8:335f2506f422 237
samux 8:335f2506f422 238 return true;
samux 8:335f2506f422 239 }
samux 8:335f2506f422 240
samux 8:335f2506f422 241 // read setup packet
samux 8:335f2506f422 242 void USBHAL::EP0setup(uint8_t *buffer) {
samux 8:335f2506f422 243 uint32_t sz;
samux 8:335f2506f422 244 endpointReadResult(EP0OUT, buffer, &sz);
samux 8:335f2506f422 245 }
samux 8:335f2506f422 246
samux 8:335f2506f422 247 void USBHAL::EP0readStage(void) {
samux 8:335f2506f422 248 Data1 &= ~1UL; // set DATA0
samux 8:335f2506f422 249 bdt[0].info = (BD_DTS_MASK | BD_OWN_MASK);
samux 8:335f2506f422 250 }
samux 8:335f2506f422 251
samux 8:335f2506f422 252 void USBHAL::EP0read(void) {
samux 8:335f2506f422 253 uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(EP0OUT), RX, 0);
samux 8:335f2506f422 254 bdt[idx].byte_count = MAX_PACKET_SIZE_EP0;
samux 8:335f2506f422 255 }
samux 8:335f2506f422 256
samux 8:335f2506f422 257 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
samux 8:335f2506f422 258 uint32_t sz;
samux 8:335f2506f422 259 endpointReadResult(EP0OUT, buffer, &sz);
samux 8:335f2506f422 260 return sz;
samux 8:335f2506f422 261 }
samux 8:335f2506f422 262
samux 8:335f2506f422 263 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
samux 8:335f2506f422 264 endpointWrite(EP0IN, buffer, size);
samux 8:335f2506f422 265 }
samux 8:335f2506f422 266
samux 8:335f2506f422 267 void USBHAL::EP0getWriteResult(void) {
samux 8:335f2506f422 268 }
samux 8:335f2506f422 269
samux 8:335f2506f422 270 void USBHAL::EP0stall(void) {
samux 8:335f2506f422 271 stallEndpoint(EP0OUT);
samux 8:335f2506f422 272 }
samux 8:335f2506f422 273
samux 8:335f2506f422 274 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
samux 8:335f2506f422 275 endpoint = PHY_TO_LOG(endpoint);
samux 8:335f2506f422 276 uint32_t idx = EP_BDT_IDX(endpoint, RX, 0);
samux 8:335f2506f422 277 bdt[idx].byte_count = maximumSize;
samux 8:335f2506f422 278 return EP_PENDING;
samux 8:335f2506f422 279 }
samux 8:335f2506f422 280
samux 8:335f2506f422 281 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
samux 8:335f2506f422 282 uint32_t n, sz, idx, setup = 0;
samux 8:335f2506f422 283 uint8_t not_iso;
samux 8:335f2506f422 284 uint8_t * ep_buf;
samux 8:335f2506f422 285
samux 8:335f2506f422 286 uint32_t log_endpoint = PHY_TO_LOG(endpoint);
samux 8:335f2506f422 287
samux 8:335f2506f422 288 if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
samux 8:335f2506f422 289 return EP_INVALID;
samux 8:335f2506f422 290 }
samux 8:335f2506f422 291
samux 8:335f2506f422 292 // if read on a IN endpoint -> error
samux 8:335f2506f422 293 if (IN_EP(endpoint)) {
samux 8:335f2506f422 294 return EP_INVALID;
samux 8:335f2506f422 295 }
samux 8:335f2506f422 296
samux 8:335f2506f422 297 idx = EP_BDT_IDX(log_endpoint, RX, 0);
samux 8:335f2506f422 298 sz = bdt[idx].byte_count;
samux 8:335f2506f422 299 not_iso = USB0->ENDPOINT[log_endpoint].ENDPT & USB_ENDPT_EPHSHK_MASK;
samux 8:335f2506f422 300
samux 8:335f2506f422 301 //for isochronous endpoint, we don't wait an interrupt
samux 8:335f2506f422 302 if ((log_endpoint != 0) && not_iso && !(epComplete & EP(endpoint))) {
samux 8:335f2506f422 303 return EP_PENDING;
samux 8:335f2506f422 304 }
samux 8:335f2506f422 305
samux 8:335f2506f422 306 if ((log_endpoint == 0) && (TOK_PID(idx) == SETUP_TOKEN)) {
samux 8:335f2506f422 307 setup = 1;
samux 8:335f2506f422 308 }
samux 8:335f2506f422 309
samux 8:335f2506f422 310 // non iso endpoint
samux 8:335f2506f422 311 if (not_iso) {
samux 8:335f2506f422 312 ep_buf = endpoint_buffer[idx];
samux 8:335f2506f422 313 } else {
samux 8:335f2506f422 314 ep_buf = endpoint_buffer_iso[0];
samux 8:335f2506f422 315 }
samux 8:335f2506f422 316
samux 8:335f2506f422 317 for (n = 0; n < sz; n++) {
samux 8:335f2506f422 318 buffer[n] = ep_buf[n];
samux 8:335f2506f422 319 }
samux 8:335f2506f422 320
samux 8:335f2506f422 321 if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) {
samux 8:335f2506f422 322 if (setup && (buffer[6] == 0)) // if no setup data stage,
samux 8:335f2506f422 323 Data1 &= ~1UL; // set DATA0
samux 8:335f2506f422 324 else
samux 8:335f2506f422 325 Data1 ^= (1 << endpoint);
samux 8:335f2506f422 326 }
samux 8:335f2506f422 327
samux 8:335f2506f422 328 if (((Data1 >> endpoint) & 1)) {
samux 8:335f2506f422 329 bdt[idx].info = BD_DTS_MASK | BD_DATA01_MASK | BD_OWN_MASK;
samux 8:335f2506f422 330 }
samux 8:335f2506f422 331 else {
samux 8:335f2506f422 332 bdt[idx].info = BD_DTS_MASK | BD_OWN_MASK;
samux 8:335f2506f422 333 }
samux 8:335f2506f422 334
samux 8:335f2506f422 335 USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
samux 8:335f2506f422 336 *bytesRead = sz;
samux 8:335f2506f422 337
samux 8:335f2506f422 338 epComplete &= ~EP(endpoint);
samux 8:335f2506f422 339 return EP_COMPLETED;
samux 8:335f2506f422 340 }
samux 8:335f2506f422 341
samux 8:335f2506f422 342 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
samux 8:335f2506f422 343 uint32_t idx, n;
samux 8:335f2506f422 344 uint8_t * ep_buf;
samux 8:335f2506f422 345
samux 8:335f2506f422 346 if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
samux 8:335f2506f422 347 return EP_INVALID;
samux 8:335f2506f422 348 }
samux 8:335f2506f422 349
samux 8:335f2506f422 350 // if write on a OUT endpoint -> error
samux 8:335f2506f422 351 if (OUT_EP(endpoint)) {
samux 8:335f2506f422 352 return EP_INVALID;
samux 8:335f2506f422 353 }
samux 8:335f2506f422 354
samux 8:335f2506f422 355 idx = EP_BDT_IDX(PHY_TO_LOG(endpoint), TX, 0);
samux 8:335f2506f422 356 bdt[idx].byte_count = size;
samux 8:335f2506f422 357
samux 8:335f2506f422 358
samux 8:335f2506f422 359 // non iso endpoint
samux 8:335f2506f422 360 if (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPHSHK_MASK) {
samux 8:335f2506f422 361 ep_buf = endpoint_buffer[idx];
samux 8:335f2506f422 362 } else {
samux 8:335f2506f422 363 ep_buf = endpoint_buffer_iso[2];
samux 8:335f2506f422 364 }
samux 8:335f2506f422 365
samux 8:335f2506f422 366 for (n = 0; n < size; n++) {
samux 8:335f2506f422 367 ep_buf[n] = data[n];
samux 8:335f2506f422 368 }
samux 8:335f2506f422 369
samux 8:335f2506f422 370 if ((Data1 >> endpoint) & 1) {
samux 8:335f2506f422 371 bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
samux 8:335f2506f422 372 } else {
samux 8:335f2506f422 373 bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
samux 8:335f2506f422 374 }
samux 8:335f2506f422 375
samux 8:335f2506f422 376 Data1 ^= (1 << endpoint);
samux 8:335f2506f422 377
samux 8:335f2506f422 378 return EP_PENDING;
samux 8:335f2506f422 379 }
samux 8:335f2506f422 380
samux 8:335f2506f422 381 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
samux 8:335f2506f422 382 if (epComplete & EP(endpoint)) {
samux 8:335f2506f422 383 epComplete &= ~EP(endpoint);
samux 8:335f2506f422 384 return EP_COMPLETED;
samux 8:335f2506f422 385 }
samux 8:335f2506f422 386
samux 8:335f2506f422 387 return EP_PENDING;
samux 8:335f2506f422 388 }
samux 8:335f2506f422 389
samux 8:335f2506f422 390 void USBHAL::stallEndpoint(uint8_t endpoint) {
samux 8:335f2506f422 391 USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT |= USB_ENDPT_EPSTALL_MASK;
samux 8:335f2506f422 392 }
samux 8:335f2506f422 393
samux 8:335f2506f422 394 void USBHAL::unstallEndpoint(uint8_t endpoint) {
samux 8:335f2506f422 395 USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
samux 8:335f2506f422 396 }
samux 8:335f2506f422 397
samux 8:335f2506f422 398 bool USBHAL::getEndpointStallState(uint8_t endpoint) {
samux 8:335f2506f422 399 uint8_t stall = (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPSTALL_MASK);
samux 8:335f2506f422 400 return (stall) ? true : false;
samux 8:335f2506f422 401 }
samux 8:335f2506f422 402
samux 8:335f2506f422 403 void USBHAL::remoteWakeup(void) {
samux 8:335f2506f422 404 // [TODO]
samux 8:335f2506f422 405 }
samux 8:335f2506f422 406
samux 8:335f2506f422 407
samux 8:335f2506f422 408 void USBHAL::_usbisr(void) {
samux 8:335f2506f422 409 instance->usbisr();
samux 8:335f2506f422 410 }
samux 8:335f2506f422 411
samux 8:335f2506f422 412
samux 8:335f2506f422 413 void USBHAL::usbisr(void) {
samux 8:335f2506f422 414 uint8_t i;
samux 8:335f2506f422 415 uint8_t istat = USB0->ISTAT;
samux 8:335f2506f422 416
samux 8:335f2506f422 417 // reset interrupt
samux 8:335f2506f422 418 if (istat & USB_ISTAT_USBRST_MASK) {
samux 8:335f2506f422 419 // disable all endpt
samux 8:335f2506f422 420 for(i = 0; i < 16; i++) {
samux 8:335f2506f422 421 USB0->ENDPOINT[i].ENDPT = 0x00;
samux 8:335f2506f422 422 }
samux 8:335f2506f422 423
samux 8:335f2506f422 424 // enable control endpoint
samux 8:335f2506f422 425 realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
samux 8:335f2506f422 426 realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
samux 8:335f2506f422 427
samux 8:335f2506f422 428 Data1 = 0x55555555;
samux 8:335f2506f422 429 USB0->CTL |= USB_CTL_ODDRST_MASK;
samux 8:335f2506f422 430
samux 8:335f2506f422 431 USB0->ISTAT = 0xFF; // clear all interrupt status flags
samux 8:335f2506f422 432 USB0->ERRSTAT = 0xFF; // clear all error flags
samux 8:335f2506f422 433 USB0->ERREN = 0xFF; // enable error interrupt sources
samux 8:335f2506f422 434 USB0->ADDR = 0x00; // set default address
samux 8:335f2506f422 435
samux 8:335f2506f422 436 return;
samux 8:335f2506f422 437 }
samux 8:335f2506f422 438
samux 8:335f2506f422 439 // resume interrupt
samux 8:335f2506f422 440 if (istat & USB_ISTAT_RESUME_MASK) {
samux 8:335f2506f422 441 USB0->ISTAT = USB_ISTAT_RESUME_MASK;
samux 8:335f2506f422 442 }
samux 8:335f2506f422 443
samux 8:335f2506f422 444 // SOF interrupt
samux 8:335f2506f422 445 if (istat & USB_ISTAT_SOFTOK_MASK) {
samux 8:335f2506f422 446 USB0->ISTAT = USB_ISTAT_SOFTOK_MASK;
samux 8:335f2506f422 447 // SOF event, read frame number
samux 8:335f2506f422 448 SOF(frameNumber());
samux 8:335f2506f422 449 }
samux 8:335f2506f422 450
samux 8:335f2506f422 451 // stall interrupt
samux 8:335f2506f422 452 if (istat & 1<<7) {
samux 8:335f2506f422 453 if (USB0->ENDPOINT[0].ENDPT & USB_ENDPT_EPSTALL_MASK)
samux 8:335f2506f422 454 USB0->ENDPOINT[0].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
samux 8:335f2506f422 455 USB0->ISTAT |= USB_ISTAT_STALL_MASK;
samux 8:335f2506f422 456 }
samux 8:335f2506f422 457
samux 8:335f2506f422 458 // token interrupt
samux 8:335f2506f422 459 if (istat & 1<<3) {
samux 8:335f2506f422 460 uint32_t num = (USB0->STAT >> 4) & 0x0F;
samux 8:335f2506f422 461 uint32_t dir = (USB0->STAT >> 3) & 0x01;
samux 8:335f2506f422 462 uint32_t ev_odd = (USB0->STAT >> 2) & 0x01;
samux 8:335f2506f422 463
samux 8:335f2506f422 464 // setup packet
samux 8:335f2506f422 465 if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
samux 8:335f2506f422 466 Data1 &= ~0x02;
samux 8:335f2506f422 467 bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK;
samux 8:335f2506f422 468 bdt[EP_BDT_IDX(0, TX, ODD)].info &= ~BD_OWN_MASK;
samux 8:335f2506f422 469
samux 8:335f2506f422 470 // EP0 SETUP event (SETUP data received)
samux 8:335f2506f422 471 EP0setupCallback();
samux 8:335f2506f422 472
samux 8:335f2506f422 473 } else {
samux 8:335f2506f422 474 // OUT packet
samux 8:335f2506f422 475 if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == OUT_TOKEN) {
samux 8:335f2506f422 476 if (num == 0)
samux 8:335f2506f422 477 EP0out();
samux 8:335f2506f422 478 else {
samux 8:335f2506f422 479 epComplete |= (1 << EP(num));
samux 8:335f2506f422 480 if ((instance->*(epCallback[EP(num) - 2]))()) {
samux 8:335f2506f422 481 epComplete &= ~(1 << EP(num));
samux 8:335f2506f422 482 }
samux 8:335f2506f422 483 }
samux 8:335f2506f422 484 }
samux 8:335f2506f422 485
samux 8:335f2506f422 486 // IN packet
samux 8:335f2506f422 487 if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == IN_TOKEN) {
samux 8:335f2506f422 488 if (num == 0) {
samux 8:335f2506f422 489 EP0in();
samux 8:335f2506f422 490 if (set_addr == 1) {
samux 8:335f2506f422 491 USB0->ADDR = addr & 0x7F;
samux 8:335f2506f422 492 set_addr = 0;
samux 8:335f2506f422 493 }
samux 8:335f2506f422 494 }
samux 8:335f2506f422 495 else {
samux 8:335f2506f422 496 epComplete |= (1 << (EP(num) + 1));
samux 8:335f2506f422 497 if ((instance->*(epCallback[EP(num) + 1 - 2]))()) {
samux 8:335f2506f422 498 epComplete &= ~(1 << (EP(num) + 1));
samux 8:335f2506f422 499 }
samux 8:335f2506f422 500 }
samux 8:335f2506f422 501 }
samux 8:335f2506f422 502 }
samux 8:335f2506f422 503
samux 8:335f2506f422 504 USB0->ISTAT = USB_ISTAT_TOKDNE_MASK;
samux 8:335f2506f422 505 }
samux 8:335f2506f422 506
samux 8:335f2506f422 507 // sleep interrupt
samux 8:335f2506f422 508 if (istat & 1<<4) {
samux 8:335f2506f422 509 USB0->ISTAT |= USB_ISTAT_SLEEP_MASK;
samux 8:335f2506f422 510 }
samux 8:335f2506f422 511
samux 8:335f2506f422 512 // error interrupt
samux 8:335f2506f422 513 if (istat & USB_ISTAT_ERROR_MASK) {
samux 8:335f2506f422 514 USB0->ERRSTAT = 0xFF;
samux 8:335f2506f422 515 USB0->ISTAT |= USB_ISTAT_ERROR_MASK;
samux 8:335f2506f422 516 }
samux 8:335f2506f422 517 }
samux 8:335f2506f422 518
samux 8:335f2506f422 519
samux 8:335f2506f422 520 #endif