Forked to make modifications to bring the USBHID into USB compliance and add additional features.
Fork of USBDevice by
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.
- When multiple reports are used the 64 byte size for every report becomes a problem.
- 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 Number | Test Description | Test Result | Notes | ||||||
1 | Use USBmouse to verify backward compatibility of constructor and methods | Pass | |||||||
2 | Test SET_REPORT can set a feature report | Pass | |||||||
3 | Test GET_REPORT can retrieve a feature report | Pass | |||||||
4 | Test SET_IDLE sets up a reoccuring trigger | Pass | IOCTL_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 | ||||||
5 | Test SET_IDLE disables a trigger | Pass | Windows automatically sends this command to a HID device when it is inserted. | ||||||
6 | Enabled DEBUG in USBDevice.cpp and generated str descriptor requests. | Pass | |||||||
7 | Test SET_REPORT can set an output report | Pass | |||||||
8 | Test GET_REPORT can retrieve an output report | Pass | |||||||
9 | ReadFile, accesses the input_report | Pass | |||||||
10 | WriteFile accesses the output_report, via interupt transfer when ep1_out is used. | Pass | |||||||
11 | WriteFile accesses the output_report, via control transfer when ep1_out is NOT used. | Not Tested | |||||||
12 | Callback hooks trigger independently for each type of set_report/get_report | Pass | |||||||
13 | New constructor sets feature_report size | Pass | |||||||
14 | Control transfer SET_REPORT and writeFile access the same data structure | BUG | The 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. | ||||||
15 | Control transfer GET_REPORT and readFile access the same data structure | BUG | The 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. | ||||||
16 | Test GET_IDLE retrieves the IDLE rate | Unknown | Windows HID driver does not implement IOCTL_HID_GET_POLL_FREQUENCY_MSEC |
USBDevice/USBHAL_LPC11U.cpp@3:6d85e04fb59f, 2012-10-14 (annotated)
- Committer:
- samux
- Date:
- Sun Oct 14 12:38:56 2012 +0000
- Revision:
- 3:6d85e04fb59f
- Parent:
- 1:80ab0d068708
- Child:
- 8:335f2506f422
move EnableIRQ to connect() - add MEDIA_REMOVAL handling
Who changed what in which revision?
User | Revision | Line number | New 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 | #ifdef TARGET_LPC11U24 |
samux | 1:80ab0d068708 | 20 | |
samux | 1:80ab0d068708 | 21 | #include "USBHAL.h" |
samux | 1:80ab0d068708 | 22 | |
samux | 1:80ab0d068708 | 23 | USBHAL * USBHAL::instance; |
samux | 1:80ab0d068708 | 24 | |
samux | 1:80ab0d068708 | 25 | |
samux | 1:80ab0d068708 | 26 | // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1) |
samux | 1:80ab0d068708 | 27 | #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1) |
samux | 1:80ab0d068708 | 28 | |
samux | 1:80ab0d068708 | 29 | // Convert physical endpoint number to register bit |
samux | 1:80ab0d068708 | 30 | #define EP(endpoint) (1UL<<endpoint) |
samux | 1:80ab0d068708 | 31 | |
samux | 1:80ab0d068708 | 32 | // Convert physical to logical |
samux | 1:80ab0d068708 | 33 | #define PHY_TO_LOG(endpoint) ((endpoint)>>1) |
samux | 1:80ab0d068708 | 34 | |
samux | 1:80ab0d068708 | 35 | // Get endpoint direction |
samux | 1:80ab0d068708 | 36 | #define IN_EP(endpoint) ((endpoint) & 1U ? true : false) |
samux | 1:80ab0d068708 | 37 | #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true) |
samux | 1:80ab0d068708 | 38 | |
samux | 1:80ab0d068708 | 39 | // USB RAM |
samux | 1:80ab0d068708 | 40 | #define USB_RAM_START (0x20004000) |
samux | 1:80ab0d068708 | 41 | #define USB_RAM_SIZE (0x00000800) |
samux | 1:80ab0d068708 | 42 | |
samux | 1:80ab0d068708 | 43 | // SYSAHBCLKCTRL |
samux | 1:80ab0d068708 | 44 | #define CLK_USB (1UL<<14) |
samux | 1:80ab0d068708 | 45 | #define CLK_USBRAM (1UL<<27) |
samux | 1:80ab0d068708 | 46 | |
samux | 1:80ab0d068708 | 47 | // USB Information register |
samux | 1:80ab0d068708 | 48 | #define FRAME_NR(a) ((a) & 0x7ff) // Frame number |
samux | 1:80ab0d068708 | 49 | |
samux | 1:80ab0d068708 | 50 | // USB Device Command/Status register |
samux | 1:80ab0d068708 | 51 | #define DEV_ADDR_MASK (0x7f) // Device address |
samux | 1:80ab0d068708 | 52 | #define DEV_ADDR(a) ((a) & DEV_ADDR_MASK) |
samux | 1:80ab0d068708 | 53 | #define DEV_EN (1UL<<7) // Device enable |
samux | 1:80ab0d068708 | 54 | #define SETUP (1UL<<8) // SETUP token received |
samux | 1:80ab0d068708 | 55 | #define PLL_ON (1UL<<9) // PLL enabled in suspend |
samux | 1:80ab0d068708 | 56 | #define DCON (1UL<<16) // Device status - connect |
samux | 1:80ab0d068708 | 57 | #define DSUS (1UL<<17) // Device status - suspend |
samux | 1:80ab0d068708 | 58 | #define DCON_C (1UL<<24) // Connect change |
samux | 1:80ab0d068708 | 59 | #define DSUS_C (1UL<<25) // Suspend change |
samux | 1:80ab0d068708 | 60 | #define DRES_C (1UL<<26) // Reset change |
samux | 1:80ab0d068708 | 61 | #define VBUSDEBOUNCED (1UL<<28) // Vbus detected |
samux | 1:80ab0d068708 | 62 | |
samux | 1:80ab0d068708 | 63 | // Endpoint Command/Status list |
samux | 1:80ab0d068708 | 64 | #define CMDSTS_A (1UL<<31) // Active |
samux | 1:80ab0d068708 | 65 | #define CMDSTS_D (1UL<<30) // Disable |
samux | 1:80ab0d068708 | 66 | #define CMDSTS_S (1UL<<29) // Stall |
samux | 1:80ab0d068708 | 67 | #define CMDSTS_TR (1UL<<28) // Toggle Reset |
samux | 1:80ab0d068708 | 68 | #define CMDSTS_RF (1UL<<27) // Rate Feedback mode |
samux | 1:80ab0d068708 | 69 | #define CMDSTS_TV (1UL<<27) // Toggle Value |
samux | 1:80ab0d068708 | 70 | #define CMDSTS_T (1UL<<26) // Endpoint Type |
samux | 1:80ab0d068708 | 71 | #define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes |
samux | 1:80ab0d068708 | 72 | #define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address |
samux | 1:80ab0d068708 | 73 | |
samux | 1:80ab0d068708 | 74 | #define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer |
samux | 1:80ab0d068708 | 75 | |
samux | 1:80ab0d068708 | 76 | // USB Non-endpoint interrupt sources |
samux | 1:80ab0d068708 | 77 | #define FRAME_INT (1UL<<30) |
samux | 1:80ab0d068708 | 78 | #define DEV_INT (1UL<<31) |
samux | 1:80ab0d068708 | 79 | |
samux | 1:80ab0d068708 | 80 | static volatile int epComplete = 0; |
samux | 1:80ab0d068708 | 81 | |
samux | 1:80ab0d068708 | 82 | // One entry for a double-buffered logical endpoint in the endpoint |
samux | 1:80ab0d068708 | 83 | // command/status list. Endpoint 0 is single buffered, out[1] is used |
samux | 1:80ab0d068708 | 84 | // for the SETUP packet and in[1] is not used |
samux | 1:80ab0d068708 | 85 | typedef __packed struct { |
samux | 1:80ab0d068708 | 86 | uint32_t out[2]; |
samux | 1:80ab0d068708 | 87 | uint32_t in[2]; |
samux | 1:80ab0d068708 | 88 | } EP_COMMAND_STATUS; |
samux | 1:80ab0d068708 | 89 | |
samux | 1:80ab0d068708 | 90 | typedef __packed struct { |
samux | 1:80ab0d068708 | 91 | uint8_t out[MAX_PACKET_SIZE_EP0]; |
samux | 1:80ab0d068708 | 92 | uint8_t in[MAX_PACKET_SIZE_EP0]; |
samux | 1:80ab0d068708 | 93 | uint8_t setup[SETUP_PACKET_SIZE]; |
samux | 1:80ab0d068708 | 94 | } CONTROL_TRANSFER; |
samux | 1:80ab0d068708 | 95 | |
samux | 1:80ab0d068708 | 96 | typedef __packed struct { |
samux | 1:80ab0d068708 | 97 | uint32_t maxPacket; |
samux | 1:80ab0d068708 | 98 | uint32_t buffer[2]; |
samux | 1:80ab0d068708 | 99 | uint32_t options; |
samux | 1:80ab0d068708 | 100 | } EP_STATE; |
samux | 1:80ab0d068708 | 101 | |
samux | 1:80ab0d068708 | 102 | static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS]; |
samux | 1:80ab0d068708 | 103 | |
samux | 1:80ab0d068708 | 104 | // Pointer to the endpoint command/status list |
samux | 1:80ab0d068708 | 105 | static EP_COMMAND_STATUS *ep = NULL; |
samux | 1:80ab0d068708 | 106 | |
samux | 1:80ab0d068708 | 107 | // Pointer to endpoint 0 data (IN/OUT and SETUP) |
samux | 1:80ab0d068708 | 108 | static CONTROL_TRANSFER *ct = NULL; |
samux | 1:80ab0d068708 | 109 | |
samux | 1:80ab0d068708 | 110 | // Shadow DEVCMDSTAT register to avoid accidentally clearing flags or |
samux | 1:80ab0d068708 | 111 | // initiating a remote wakeup event. |
samux | 1:80ab0d068708 | 112 | static volatile uint32_t devCmdStat; |
samux | 1:80ab0d068708 | 113 | |
samux | 1:80ab0d068708 | 114 | // Pointers used to allocate USB RAM |
samux | 1:80ab0d068708 | 115 | static uint32_t usbRamPtr = USB_RAM_START; |
samux | 1:80ab0d068708 | 116 | static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here |
samux | 1:80ab0d068708 | 117 | |
samux | 1:80ab0d068708 | 118 | #define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m)) |
samux | 1:80ab0d068708 | 119 | |
samux | 1:80ab0d068708 | 120 | void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size); |
samux | 1:80ab0d068708 | 121 | void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) { |
samux | 1:80ab0d068708 | 122 | if (size > 0) { |
samux | 1:80ab0d068708 | 123 | do { |
samux | 1:80ab0d068708 | 124 | *dst++ = *src++; |
samux | 1:80ab0d068708 | 125 | } while (--size > 0); |
samux | 1:80ab0d068708 | 126 | } |
samux | 1:80ab0d068708 | 127 | } |
samux | 1:80ab0d068708 | 128 | |
samux | 1:80ab0d068708 | 129 | |
samux | 1:80ab0d068708 | 130 | USBHAL::USBHAL(void) { |
samux | 1:80ab0d068708 | 131 | NVIC_DisableIRQ(USB_IRQn); |
samux | 1:80ab0d068708 | 132 | |
samux | 1:80ab0d068708 | 133 | // nUSB_CONNECT output |
samux | 1:80ab0d068708 | 134 | LPC_IOCON->PIO0_6 = 0x00000001; |
samux | 1:80ab0d068708 | 135 | |
samux | 1:80ab0d068708 | 136 | // Enable clocks (USB registers, USB RAM) |
samux | 1:80ab0d068708 | 137 | LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM; |
samux | 1:80ab0d068708 | 138 | |
samux | 1:80ab0d068708 | 139 | // Ensure device disconnected (DCON not set) |
samux | 1:80ab0d068708 | 140 | LPC_USB->DEVCMDSTAT = 0; |
samux | 1:80ab0d068708 | 141 | |
samux | 1:80ab0d068708 | 142 | // to ensure that the USB host sees the device as |
samux | 1:80ab0d068708 | 143 | // disconnected if the target CPU is reset. |
samux | 1:80ab0d068708 | 144 | wait(0.3); |
samux | 1:80ab0d068708 | 145 | |
samux | 1:80ab0d068708 | 146 | // Reserve space in USB RAM for endpoint command/status list |
samux | 1:80ab0d068708 | 147 | // Must be 256 byte aligned |
samux | 1:80ab0d068708 | 148 | usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256); |
samux | 1:80ab0d068708 | 149 | ep = (EP_COMMAND_STATUS *)usbRamPtr; |
samux | 1:80ab0d068708 | 150 | usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS); |
samux | 1:80ab0d068708 | 151 | LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00; |
samux | 1:80ab0d068708 | 152 | |
samux | 1:80ab0d068708 | 153 | // Reserve space in USB RAM for Endpoint 0 |
samux | 1:80ab0d068708 | 154 | // Must be 64 byte aligned |
samux | 1:80ab0d068708 | 155 | usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64); |
samux | 1:80ab0d068708 | 156 | ct = (CONTROL_TRANSFER *)usbRamPtr; |
samux | 1:80ab0d068708 | 157 | usbRamPtr += sizeof(CONTROL_TRANSFER); |
samux | 1:80ab0d068708 | 158 | LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000; |
samux | 1:80ab0d068708 | 159 | |
samux | 1:80ab0d068708 | 160 | // Setup command/status list for EP0 |
samux | 1:80ab0d068708 | 161 | ep[0].out[0] = 0; |
samux | 1:80ab0d068708 | 162 | ep[0].in[0] = 0; |
samux | 1:80ab0d068708 | 163 | ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup); |
samux | 1:80ab0d068708 | 164 | |
samux | 1:80ab0d068708 | 165 | // Route all interrupts to IRQ, some can be routed to |
samux | 1:80ab0d068708 | 166 | // USB_FIQ if you wish. |
samux | 1:80ab0d068708 | 167 | LPC_USB->INTROUTING = 0; |
samux | 1:80ab0d068708 | 168 | |
samux | 1:80ab0d068708 | 169 | // Set device address 0, enable USB device, no remote wakeup |
samux | 1:80ab0d068708 | 170 | devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS; |
samux | 1:80ab0d068708 | 171 | LPC_USB->DEVCMDSTAT = devCmdStat; |
samux | 1:80ab0d068708 | 172 | |
samux | 1:80ab0d068708 | 173 | // Enable interrupts for device events and EP0 |
samux | 1:80ab0d068708 | 174 | LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT; |
samux | 1:80ab0d068708 | 175 | instance = this; |
samux | 1:80ab0d068708 | 176 | |
samux | 1:80ab0d068708 | 177 | //attach IRQ handler and enable interrupts |
samux | 1:80ab0d068708 | 178 | NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); |
samux | 1:80ab0d068708 | 179 | } |
samux | 1:80ab0d068708 | 180 | |
samux | 1:80ab0d068708 | 181 | USBHAL::~USBHAL(void) { |
samux | 1:80ab0d068708 | 182 | // Ensure device disconnected (DCON not set) |
samux | 1:80ab0d068708 | 183 | LPC_USB->DEVCMDSTAT = 0; |
samux | 1:80ab0d068708 | 184 | |
samux | 1:80ab0d068708 | 185 | // Disable USB interrupts |
samux | 1:80ab0d068708 | 186 | NVIC_DisableIRQ(USB_IRQn); |
samux | 1:80ab0d068708 | 187 | } |
samux | 1:80ab0d068708 | 188 | |
samux | 1:80ab0d068708 | 189 | void USBHAL::connect(void) { |
samux | 3:6d85e04fb59f | 190 | NVIC_EnableIRQ(USB_IRQn); |
samux | 1:80ab0d068708 | 191 | devCmdStat |= DCON; |
samux | 1:80ab0d068708 | 192 | LPC_USB->DEVCMDSTAT = devCmdStat; |
samux | 1:80ab0d068708 | 193 | } |
samux | 1:80ab0d068708 | 194 | |
samux | 1:80ab0d068708 | 195 | void USBHAL::disconnect(void) { |
samux | 3:6d85e04fb59f | 196 | NVIC_DisableIRQ(USB_IRQn); |
samux | 1:80ab0d068708 | 197 | devCmdStat &= ~DCON; |
samux | 1:80ab0d068708 | 198 | LPC_USB->DEVCMDSTAT = devCmdStat; |
samux | 1:80ab0d068708 | 199 | } |
samux | 1:80ab0d068708 | 200 | |
samux | 1:80ab0d068708 | 201 | void USBHAL::configureDevice(void) { |
samux | 1:80ab0d068708 | 202 | } |
samux | 1:80ab0d068708 | 203 | |
samux | 1:80ab0d068708 | 204 | void USBHAL::unconfigureDevice(void) { |
samux | 1:80ab0d068708 | 205 | } |
samux | 1:80ab0d068708 | 206 | |
samux | 1:80ab0d068708 | 207 | void USBHAL::EP0setup(uint8_t *buffer) { |
samux | 1:80ab0d068708 | 208 | // Copy setup packet data |
samux | 1:80ab0d068708 | 209 | USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE); |
samux | 1:80ab0d068708 | 210 | } |
samux | 1:80ab0d068708 | 211 | |
samux | 1:80ab0d068708 | 212 | void USBHAL::EP0read(void) { |
samux | 1:80ab0d068708 | 213 | // Start an endpoint 0 read |
samux | 1:80ab0d068708 | 214 | |
samux | 1:80ab0d068708 | 215 | // The USB ISR will call USBDevice_EP0out() when a packet has been read, |
samux | 1:80ab0d068708 | 216 | // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to |
samux | 1:80ab0d068708 | 217 | // read the data. |
samux | 1:80ab0d068708 | 218 | |
samux | 1:80ab0d068708 | 219 | ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \ |
samux | 1:80ab0d068708 | 220 | | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out); |
samux | 1:80ab0d068708 | 221 | } |
samux | 1:80ab0d068708 | 222 | |
samux | 1:80ab0d068708 | 223 | uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) { |
samux | 1:80ab0d068708 | 224 | // Complete an endpoint 0 read |
samux | 1:80ab0d068708 | 225 | uint32_t bytesRead; |
samux | 1:80ab0d068708 | 226 | |
samux | 1:80ab0d068708 | 227 | // Find how many bytes were read |
samux | 1:80ab0d068708 | 228 | bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]); |
samux | 1:80ab0d068708 | 229 | |
samux | 1:80ab0d068708 | 230 | // Copy data |
samux | 1:80ab0d068708 | 231 | USBMemCopy(buffer, ct->out, bytesRead); |
samux | 1:80ab0d068708 | 232 | return bytesRead; |
samux | 1:80ab0d068708 | 233 | } |
samux | 1:80ab0d068708 | 234 | |
samux | 1:80ab0d068708 | 235 | void USBHAL::EP0write(uint8_t *buffer, uint32_t size) { |
samux | 1:80ab0d068708 | 236 | // Start and endpoint 0 write |
samux | 1:80ab0d068708 | 237 | |
samux | 1:80ab0d068708 | 238 | // The USB ISR will call USBDevice_EP0in() when the data has |
samux | 1:80ab0d068708 | 239 | // been written, the USBDevice layer then calls |
samux | 1:80ab0d068708 | 240 | // USBBusInterface_EP0getWriteResult() to complete the transaction. |
samux | 1:80ab0d068708 | 241 | |
samux | 1:80ab0d068708 | 242 | // Copy data |
samux | 1:80ab0d068708 | 243 | USBMemCopy(ct->in, buffer, size); |
samux | 1:80ab0d068708 | 244 | |
samux | 1:80ab0d068708 | 245 | // Start transfer |
samux | 1:80ab0d068708 | 246 | ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \ |
samux | 1:80ab0d068708 | 247 | | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in); |
samux | 1:80ab0d068708 | 248 | } |
samux | 1:80ab0d068708 | 249 | |
samux | 1:80ab0d068708 | 250 | |
samux | 1:80ab0d068708 | 251 | EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) { |
samux | 1:80ab0d068708 | 252 | uint8_t bf = 0; |
samux | 1:80ab0d068708 | 253 | uint32_t flags = 0; |
samux | 1:80ab0d068708 | 254 | |
samux | 1:80ab0d068708 | 255 | //check which buffer must be filled |
samux | 1:80ab0d068708 | 256 | if (LPC_USB->EPBUFCFG & EP(endpoint)) { |
samux | 1:80ab0d068708 | 257 | // Double buffered |
samux | 1:80ab0d068708 | 258 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 259 | bf = 1; |
samux | 1:80ab0d068708 | 260 | } else { |
samux | 1:80ab0d068708 | 261 | bf = 0; |
samux | 1:80ab0d068708 | 262 | } |
samux | 1:80ab0d068708 | 263 | } |
samux | 1:80ab0d068708 | 264 | |
samux | 1:80ab0d068708 | 265 | // if isochronous endpoint, T = 1 |
samux | 1:80ab0d068708 | 266 | if(endpointState[endpoint].options & ISOCHRONOUS) |
samux | 1:80ab0d068708 | 267 | { |
samux | 1:80ab0d068708 | 268 | flags |= CMDSTS_T; |
samux | 1:80ab0d068708 | 269 | } |
samux | 1:80ab0d068708 | 270 | |
samux | 1:80ab0d068708 | 271 | //Active the endpoint for reading |
samux | 1:80ab0d068708 | 272 | ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \ |
samux | 1:80ab0d068708 | 273 | | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags; |
samux | 1:80ab0d068708 | 274 | return EP_PENDING; |
samux | 1:80ab0d068708 | 275 | } |
samux | 1:80ab0d068708 | 276 | |
samux | 1:80ab0d068708 | 277 | EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) { |
samux | 1:80ab0d068708 | 278 | |
samux | 1:80ab0d068708 | 279 | uint8_t bf = 0; |
samux | 1:80ab0d068708 | 280 | |
samux | 1:80ab0d068708 | 281 | if (!(epComplete & EP(endpoint))) |
samux | 1:80ab0d068708 | 282 | return EP_PENDING; |
samux | 1:80ab0d068708 | 283 | else { |
samux | 1:80ab0d068708 | 284 | epComplete &= ~EP(endpoint); |
samux | 1:80ab0d068708 | 285 | |
samux | 1:80ab0d068708 | 286 | //check which buffer has been filled |
samux | 1:80ab0d068708 | 287 | if (LPC_USB->EPBUFCFG & EP(endpoint)) { |
samux | 1:80ab0d068708 | 288 | // Double buffered (here we read the previous buffer which was used) |
samux | 1:80ab0d068708 | 289 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 290 | bf = 0; |
samux | 1:80ab0d068708 | 291 | } else { |
samux | 1:80ab0d068708 | 292 | bf = 1; |
samux | 1:80ab0d068708 | 293 | } |
samux | 1:80ab0d068708 | 294 | } |
samux | 1:80ab0d068708 | 295 | |
samux | 1:80ab0d068708 | 296 | // Find how many bytes were read |
samux | 1:80ab0d068708 | 297 | *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf])); |
samux | 1:80ab0d068708 | 298 | |
samux | 1:80ab0d068708 | 299 | // Copy data |
samux | 1:80ab0d068708 | 300 | USBMemCopy(data, ct->out, *bytesRead); |
samux | 1:80ab0d068708 | 301 | return EP_COMPLETED; |
samux | 1:80ab0d068708 | 302 | } |
samux | 1:80ab0d068708 | 303 | } |
samux | 1:80ab0d068708 | 304 | |
samux | 1:80ab0d068708 | 305 | void USBHAL::EP0getWriteResult(void) { |
samux | 1:80ab0d068708 | 306 | // Complete an endpoint 0 write |
samux | 1:80ab0d068708 | 307 | |
samux | 1:80ab0d068708 | 308 | // Nothing required for this target |
samux | 1:80ab0d068708 | 309 | return; |
samux | 1:80ab0d068708 | 310 | } |
samux | 1:80ab0d068708 | 311 | |
samux | 1:80ab0d068708 | 312 | void USBHAL::EP0stall(void) { |
samux | 1:80ab0d068708 | 313 | ep[0].in[0] = CMDSTS_S; |
samux | 1:80ab0d068708 | 314 | ep[0].out[0] = CMDSTS_S; |
samux | 1:80ab0d068708 | 315 | } |
samux | 1:80ab0d068708 | 316 | |
samux | 1:80ab0d068708 | 317 | void USBHAL::setAddress(uint8_t address) { |
samux | 1:80ab0d068708 | 318 | devCmdStat &= ~DEV_ADDR_MASK; |
samux | 1:80ab0d068708 | 319 | devCmdStat |= DEV_ADDR(address); |
samux | 1:80ab0d068708 | 320 | LPC_USB->DEVCMDSTAT = devCmdStat; |
samux | 1:80ab0d068708 | 321 | } |
samux | 1:80ab0d068708 | 322 | |
samux | 1:80ab0d068708 | 323 | EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { |
samux | 1:80ab0d068708 | 324 | uint32_t flags = 0; |
samux | 1:80ab0d068708 | 325 | uint32_t bf; |
samux | 1:80ab0d068708 | 326 | |
samux | 1:80ab0d068708 | 327 | // Validate parameters |
samux | 1:80ab0d068708 | 328 | if (data == NULL) { |
samux | 1:80ab0d068708 | 329 | return EP_INVALID; |
samux | 1:80ab0d068708 | 330 | } |
samux | 1:80ab0d068708 | 331 | |
samux | 1:80ab0d068708 | 332 | if (endpoint > LAST_PHYSICAL_ENDPOINT) { |
samux | 1:80ab0d068708 | 333 | return EP_INVALID; |
samux | 1:80ab0d068708 | 334 | } |
samux | 1:80ab0d068708 | 335 | |
samux | 1:80ab0d068708 | 336 | if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { |
samux | 1:80ab0d068708 | 337 | return EP_INVALID; |
samux | 1:80ab0d068708 | 338 | } |
samux | 1:80ab0d068708 | 339 | |
samux | 1:80ab0d068708 | 340 | if (size > endpointState[endpoint].maxPacket) { |
samux | 1:80ab0d068708 | 341 | return EP_INVALID; |
samux | 1:80ab0d068708 | 342 | } |
samux | 1:80ab0d068708 | 343 | |
samux | 1:80ab0d068708 | 344 | if (LPC_USB->EPBUFCFG & EP(endpoint)) { |
samux | 1:80ab0d068708 | 345 | // Double buffered |
samux | 1:80ab0d068708 | 346 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 347 | bf = 1; |
samux | 1:80ab0d068708 | 348 | } else { |
samux | 1:80ab0d068708 | 349 | bf = 0; |
samux | 1:80ab0d068708 | 350 | } |
samux | 1:80ab0d068708 | 351 | } else { |
samux | 1:80ab0d068708 | 352 | // Single buffered |
samux | 1:80ab0d068708 | 353 | bf = 0; |
samux | 1:80ab0d068708 | 354 | } |
samux | 1:80ab0d068708 | 355 | |
samux | 1:80ab0d068708 | 356 | // Check if already active |
samux | 1:80ab0d068708 | 357 | if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { |
samux | 1:80ab0d068708 | 358 | return EP_INVALID; |
samux | 1:80ab0d068708 | 359 | } |
samux | 1:80ab0d068708 | 360 | |
samux | 1:80ab0d068708 | 361 | // Check if stalled |
samux | 1:80ab0d068708 | 362 | if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 363 | return EP_STALLED; |
samux | 1:80ab0d068708 | 364 | } |
samux | 1:80ab0d068708 | 365 | |
samux | 1:80ab0d068708 | 366 | // Copy data to USB RAM |
samux | 1:80ab0d068708 | 367 | USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size); |
samux | 1:80ab0d068708 | 368 | |
samux | 1:80ab0d068708 | 369 | // Add options |
samux | 1:80ab0d068708 | 370 | if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) { |
samux | 1:80ab0d068708 | 371 | flags |= CMDSTS_RF; |
samux | 1:80ab0d068708 | 372 | } |
samux | 1:80ab0d068708 | 373 | |
samux | 1:80ab0d068708 | 374 | if (endpointState[endpoint].options & ISOCHRONOUS) { |
samux | 1:80ab0d068708 | 375 | flags |= CMDSTS_T; |
samux | 1:80ab0d068708 | 376 | } |
samux | 1:80ab0d068708 | 377 | |
samux | 1:80ab0d068708 | 378 | // Add transfer |
samux | 1:80ab0d068708 | 379 | ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \ |
samux | 1:80ab0d068708 | 380 | endpointState[endpoint].buffer[bf]) \ |
samux | 1:80ab0d068708 | 381 | | CMDSTS_NBYTES(size) | CMDSTS_A | flags; |
samux | 1:80ab0d068708 | 382 | |
samux | 1:80ab0d068708 | 383 | return EP_PENDING; |
samux | 1:80ab0d068708 | 384 | } |
samux | 1:80ab0d068708 | 385 | |
samux | 1:80ab0d068708 | 386 | EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) { |
samux | 1:80ab0d068708 | 387 | uint32_t bf; |
samux | 1:80ab0d068708 | 388 | // Validate parameters |
samux | 1:80ab0d068708 | 389 | |
samux | 1:80ab0d068708 | 390 | if (endpoint > LAST_PHYSICAL_ENDPOINT) { |
samux | 1:80ab0d068708 | 391 | return EP_INVALID; |
samux | 1:80ab0d068708 | 392 | } |
samux | 1:80ab0d068708 | 393 | |
samux | 1:80ab0d068708 | 394 | if (OUT_EP(endpoint)) { |
samux | 1:80ab0d068708 | 395 | return EP_INVALID; |
samux | 1:80ab0d068708 | 396 | } |
samux | 1:80ab0d068708 | 397 | |
samux | 1:80ab0d068708 | 398 | if (LPC_USB->EPBUFCFG & EP(endpoint)) { |
samux | 1:80ab0d068708 | 399 | // Double buffered // TODO: FIX THIS |
samux | 1:80ab0d068708 | 400 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 401 | bf = 1; |
samux | 1:80ab0d068708 | 402 | } else { |
samux | 1:80ab0d068708 | 403 | bf = 0; |
samux | 1:80ab0d068708 | 404 | } |
samux | 1:80ab0d068708 | 405 | } else { |
samux | 1:80ab0d068708 | 406 | // Single buffered |
samux | 1:80ab0d068708 | 407 | bf = 0; |
samux | 1:80ab0d068708 | 408 | } |
samux | 1:80ab0d068708 | 409 | |
samux | 1:80ab0d068708 | 410 | // Check if endpoint still active |
samux | 1:80ab0d068708 | 411 | if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { |
samux | 1:80ab0d068708 | 412 | return EP_PENDING; |
samux | 1:80ab0d068708 | 413 | } |
samux | 1:80ab0d068708 | 414 | |
samux | 1:80ab0d068708 | 415 | // Check if stalled |
samux | 1:80ab0d068708 | 416 | if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 417 | return EP_STALLED; |
samux | 1:80ab0d068708 | 418 | } |
samux | 1:80ab0d068708 | 419 | |
samux | 1:80ab0d068708 | 420 | return EP_COMPLETED; |
samux | 1:80ab0d068708 | 421 | } |
samux | 1:80ab0d068708 | 422 | |
samux | 1:80ab0d068708 | 423 | void USBHAL::stallEndpoint(uint8_t endpoint) { |
samux | 1:80ab0d068708 | 424 | |
samux | 1:80ab0d068708 | 425 | // TODO: should this clear active bit? |
samux | 1:80ab0d068708 | 426 | |
samux | 1:80ab0d068708 | 427 | if (IN_EP(endpoint)) { |
samux | 1:80ab0d068708 | 428 | ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S; |
samux | 1:80ab0d068708 | 429 | ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S; |
samux | 1:80ab0d068708 | 430 | } else { |
samux | 1:80ab0d068708 | 431 | ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S; |
samux | 1:80ab0d068708 | 432 | ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S; |
samux | 1:80ab0d068708 | 433 | } |
samux | 1:80ab0d068708 | 434 | } |
samux | 1:80ab0d068708 | 435 | |
samux | 1:80ab0d068708 | 436 | void USBHAL::unstallEndpoint(uint8_t endpoint) { |
samux | 1:80ab0d068708 | 437 | if (LPC_USB->EPBUFCFG & EP(endpoint)) { |
samux | 1:80ab0d068708 | 438 | // Double buffered |
samux | 1:80ab0d068708 | 439 | if (IN_EP(endpoint)) { |
samux | 1:80ab0d068708 | 440 | ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0 |
samux | 1:80ab0d068708 | 441 | ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0 |
samux | 1:80ab0d068708 | 442 | |
samux | 1:80ab0d068708 | 443 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 444 | ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 445 | } else { |
samux | 1:80ab0d068708 | 446 | ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 447 | } |
samux | 1:80ab0d068708 | 448 | } else { |
samux | 1:80ab0d068708 | 449 | ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0 |
samux | 1:80ab0d068708 | 450 | ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0 |
samux | 1:80ab0d068708 | 451 | |
samux | 1:80ab0d068708 | 452 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 453 | ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 454 | } else { |
samux | 1:80ab0d068708 | 455 | ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 456 | } |
samux | 1:80ab0d068708 | 457 | } |
samux | 1:80ab0d068708 | 458 | } else { |
samux | 1:80ab0d068708 | 459 | // Single buffered |
samux | 1:80ab0d068708 | 460 | if (IN_EP(endpoint)) { |
samux | 1:80ab0d068708 | 461 | ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 462 | } else { |
samux | 1:80ab0d068708 | 463 | ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0 |
samux | 1:80ab0d068708 | 464 | } |
samux | 1:80ab0d068708 | 465 | } |
samux | 1:80ab0d068708 | 466 | } |
samux | 1:80ab0d068708 | 467 | |
samux | 1:80ab0d068708 | 468 | bool USBHAL::getEndpointStallState(unsigned char endpoint) { |
samux | 1:80ab0d068708 | 469 | if (IN_EP(endpoint)) { |
samux | 1:80ab0d068708 | 470 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 471 | if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 472 | return true; |
samux | 1:80ab0d068708 | 473 | } |
samux | 1:80ab0d068708 | 474 | } else { |
samux | 1:80ab0d068708 | 475 | if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 476 | return true; |
samux | 1:80ab0d068708 | 477 | } |
samux | 1:80ab0d068708 | 478 | } |
samux | 1:80ab0d068708 | 479 | } else { |
samux | 1:80ab0d068708 | 480 | if (LPC_USB->EPINUSE & EP(endpoint)) { |
samux | 1:80ab0d068708 | 481 | if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 482 | return true; |
samux | 1:80ab0d068708 | 483 | } |
samux | 1:80ab0d068708 | 484 | } else { |
samux | 1:80ab0d068708 | 485 | if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) { |
samux | 1:80ab0d068708 | 486 | return true; |
samux | 1:80ab0d068708 | 487 | } |
samux | 1:80ab0d068708 | 488 | } |
samux | 1:80ab0d068708 | 489 | } |
samux | 1:80ab0d068708 | 490 | |
samux | 1:80ab0d068708 | 491 | return false; |
samux | 1:80ab0d068708 | 492 | } |
samux | 1:80ab0d068708 | 493 | |
samux | 1:80ab0d068708 | 494 | bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) { |
samux | 1:80ab0d068708 | 495 | uint32_t tmpEpRamPtr; |
samux | 1:80ab0d068708 | 496 | |
samux | 1:80ab0d068708 | 497 | if (endpoint > LAST_PHYSICAL_ENDPOINT) { |
samux | 1:80ab0d068708 | 498 | return false; |
samux | 1:80ab0d068708 | 499 | } |
samux | 1:80ab0d068708 | 500 | |
samux | 1:80ab0d068708 | 501 | // Not applicable to the control endpoints |
samux | 1:80ab0d068708 | 502 | if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { |
samux | 1:80ab0d068708 | 503 | return false; |
samux | 1:80ab0d068708 | 504 | } |
samux | 1:80ab0d068708 | 505 | |
samux | 1:80ab0d068708 | 506 | // Allocate buffers in USB RAM |
samux | 1:80ab0d068708 | 507 | tmpEpRamPtr = epRamPtr; |
samux | 1:80ab0d068708 | 508 | |
samux | 1:80ab0d068708 | 509 | // Must be 64 byte aligned |
samux | 1:80ab0d068708 | 510 | tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); |
samux | 1:80ab0d068708 | 511 | |
samux | 1:80ab0d068708 | 512 | if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { |
samux | 1:80ab0d068708 | 513 | // Out of memory |
samux | 1:80ab0d068708 | 514 | return false; |
samux | 1:80ab0d068708 | 515 | } |
samux | 1:80ab0d068708 | 516 | |
samux | 1:80ab0d068708 | 517 | // Allocate first buffer |
samux | 1:80ab0d068708 | 518 | endpointState[endpoint].buffer[0] = tmpEpRamPtr; |
samux | 1:80ab0d068708 | 519 | tmpEpRamPtr += maxPacket; |
samux | 1:80ab0d068708 | 520 | |
samux | 1:80ab0d068708 | 521 | if (!(options & SINGLE_BUFFERED)) { |
samux | 1:80ab0d068708 | 522 | // Must be 64 byte aligned |
samux | 1:80ab0d068708 | 523 | tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); |
samux | 1:80ab0d068708 | 524 | |
samux | 1:80ab0d068708 | 525 | if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { |
samux | 1:80ab0d068708 | 526 | // Out of memory |
samux | 1:80ab0d068708 | 527 | return false; |
samux | 1:80ab0d068708 | 528 | } |
samux | 1:80ab0d068708 | 529 | |
samux | 1:80ab0d068708 | 530 | // Allocate second buffer |
samux | 1:80ab0d068708 | 531 | endpointState[endpoint].buffer[1] = tmpEpRamPtr; |
samux | 1:80ab0d068708 | 532 | tmpEpRamPtr += maxPacket; |
samux | 1:80ab0d068708 | 533 | } |
samux | 1:80ab0d068708 | 534 | |
samux | 1:80ab0d068708 | 535 | // Commit to this USB RAM allocation |
samux | 1:80ab0d068708 | 536 | epRamPtr = tmpEpRamPtr; |
samux | 1:80ab0d068708 | 537 | |
samux | 1:80ab0d068708 | 538 | // Remaining endpoint state values |
samux | 1:80ab0d068708 | 539 | endpointState[endpoint].maxPacket = maxPacket; |
samux | 1:80ab0d068708 | 540 | endpointState[endpoint].options = options; |
samux | 1:80ab0d068708 | 541 | |
samux | 1:80ab0d068708 | 542 | // Enable double buffering if required |
samux | 1:80ab0d068708 | 543 | if (options & SINGLE_BUFFERED) { |
samux | 1:80ab0d068708 | 544 | LPC_USB->EPBUFCFG &= ~EP(endpoint); |
samux | 1:80ab0d068708 | 545 | } else { |
samux | 1:80ab0d068708 | 546 | // Double buffered |
samux | 1:80ab0d068708 | 547 | LPC_USB->EPBUFCFG |= EP(endpoint); |
samux | 1:80ab0d068708 | 548 | } |
samux | 1:80ab0d068708 | 549 | |
samux | 1:80ab0d068708 | 550 | // Enable interrupt |
samux | 1:80ab0d068708 | 551 | LPC_USB->INTEN |= EP(endpoint); |
samux | 1:80ab0d068708 | 552 | |
samux | 1:80ab0d068708 | 553 | // Enable endpoint |
samux | 1:80ab0d068708 | 554 | unstallEndpoint(endpoint); |
samux | 1:80ab0d068708 | 555 | return true; |
samux | 1:80ab0d068708 | 556 | } |
samux | 1:80ab0d068708 | 557 | |
samux | 1:80ab0d068708 | 558 | void USBHAL::remoteWakeup(void) { |
samux | 1:80ab0d068708 | 559 | // Clearing DSUS bit initiates a remote wakeup if the |
samux | 1:80ab0d068708 | 560 | // device is currently enabled and suspended - otherwise |
samux | 1:80ab0d068708 | 561 | // it has no effect. |
samux | 1:80ab0d068708 | 562 | LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS; |
samux | 1:80ab0d068708 | 563 | } |
samux | 1:80ab0d068708 | 564 | |
samux | 1:80ab0d068708 | 565 | |
samux | 1:80ab0d068708 | 566 | static void disableEndpoints(void) { |
samux | 1:80ab0d068708 | 567 | uint32_t logEp; |
samux | 1:80ab0d068708 | 568 | |
samux | 1:80ab0d068708 | 569 | // Ref. Table 158 "When a bus reset is received, software |
samux | 1:80ab0d068708 | 570 | // must set the disable bit of all endpoints to 1". |
samux | 1:80ab0d068708 | 571 | |
samux | 1:80ab0d068708 | 572 | for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) { |
samux | 1:80ab0d068708 | 573 | ep[logEp].out[0] = CMDSTS_D; |
samux | 1:80ab0d068708 | 574 | ep[logEp].out[1] = CMDSTS_D; |
samux | 1:80ab0d068708 | 575 | ep[logEp].in[0] = CMDSTS_D; |
samux | 1:80ab0d068708 | 576 | ep[logEp].in[1] = CMDSTS_D; |
samux | 1:80ab0d068708 | 577 | } |
samux | 1:80ab0d068708 | 578 | |
samux | 1:80ab0d068708 | 579 | // Start of USB RAM for endpoints > 0 |
samux | 1:80ab0d068708 | 580 | epRamPtr = usbRamPtr; |
samux | 1:80ab0d068708 | 581 | } |
samux | 1:80ab0d068708 | 582 | |
samux | 1:80ab0d068708 | 583 | |
samux | 1:80ab0d068708 | 584 | |
samux | 1:80ab0d068708 | 585 | void USBHAL::_usbisr(void) { |
samux | 1:80ab0d068708 | 586 | instance->usbisr(); |
samux | 1:80ab0d068708 | 587 | } |
samux | 1:80ab0d068708 | 588 | |
samux | 1:80ab0d068708 | 589 | void USBHAL::usbisr(void) { |
samux | 1:80ab0d068708 | 590 | // Start of frame |
samux | 1:80ab0d068708 | 591 | if (LPC_USB->INTSTAT & FRAME_INT) { |
samux | 1:80ab0d068708 | 592 | // Clear SOF interrupt |
samux | 1:80ab0d068708 | 593 | LPC_USB->INTSTAT = FRAME_INT; |
samux | 1:80ab0d068708 | 594 | |
samux | 1:80ab0d068708 | 595 | // SOF event, read frame number |
samux | 1:80ab0d068708 | 596 | SOF(FRAME_NR(LPC_USB->INFO)); |
samux | 1:80ab0d068708 | 597 | } |
samux | 1:80ab0d068708 | 598 | |
samux | 1:80ab0d068708 | 599 | // Device state |
samux | 1:80ab0d068708 | 600 | if (LPC_USB->INTSTAT & DEV_INT) { |
samux | 1:80ab0d068708 | 601 | LPC_USB->INTSTAT = DEV_INT; |
samux | 1:80ab0d068708 | 602 | |
samux | 1:80ab0d068708 | 603 | if (LPC_USB->DEVCMDSTAT & DSUS_C) { |
samux | 1:80ab0d068708 | 604 | // Suspend status changed |
samux | 1:80ab0d068708 | 605 | LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C; |
samux | 1:80ab0d068708 | 606 | if((LPC_USB->DEVCMDSTAT & DSUS) != 0) { |
samux | 1:80ab0d068708 | 607 | suspendStateChanged(1); |
samux | 1:80ab0d068708 | 608 | } |
samux | 1:80ab0d068708 | 609 | } |
samux | 1:80ab0d068708 | 610 | |
samux | 1:80ab0d068708 | 611 | if (LPC_USB->DEVCMDSTAT & DRES_C) { |
samux | 1:80ab0d068708 | 612 | // Bus reset |
samux | 1:80ab0d068708 | 613 | LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C; |
samux | 1:80ab0d068708 | 614 | |
samux | 1:80ab0d068708 | 615 | suspendStateChanged(0); |
samux | 1:80ab0d068708 | 616 | |
samux | 1:80ab0d068708 | 617 | // Disable endpoints > 0 |
samux | 1:80ab0d068708 | 618 | disableEndpoints(); |
samux | 1:80ab0d068708 | 619 | |
samux | 1:80ab0d068708 | 620 | // Bus reset event |
samux | 1:80ab0d068708 | 621 | busReset(); |
samux | 1:80ab0d068708 | 622 | } |
samux | 1:80ab0d068708 | 623 | } |
samux | 1:80ab0d068708 | 624 | |
samux | 1:80ab0d068708 | 625 | // Endpoint 0 |
samux | 1:80ab0d068708 | 626 | if (LPC_USB->INTSTAT & EP(EP0OUT)) { |
samux | 1:80ab0d068708 | 627 | // Clear EP0OUT/SETUP interrupt |
samux | 1:80ab0d068708 | 628 | LPC_USB->INTSTAT = EP(EP0OUT); |
samux | 1:80ab0d068708 | 629 | |
samux | 1:80ab0d068708 | 630 | // Check if SETUP |
samux | 1:80ab0d068708 | 631 | if (LPC_USB->DEVCMDSTAT & SETUP) { |
samux | 1:80ab0d068708 | 632 | // Clear Active and Stall bits for EP0 |
samux | 1:80ab0d068708 | 633 | // Documentation does not make it clear if we must use the |
samux | 1:80ab0d068708 | 634 | // EPSKIP register to achieve this, Fig. 16 and NXP reference |
samux | 1:80ab0d068708 | 635 | // code suggests we can just clear the Active bits - check with |
samux | 1:80ab0d068708 | 636 | // NXP to be sure. |
samux | 1:80ab0d068708 | 637 | ep[0].in[0] = 0; |
samux | 1:80ab0d068708 | 638 | ep[0].out[0] = 0; |
samux | 1:80ab0d068708 | 639 | |
samux | 1:80ab0d068708 | 640 | // Clear EP0IN interrupt |
samux | 1:80ab0d068708 | 641 | LPC_USB->INTSTAT = EP(EP0IN); |
samux | 1:80ab0d068708 | 642 | |
samux | 1:80ab0d068708 | 643 | // Clear SETUP (and INTONNAK_CI/O) in device status register |
samux | 1:80ab0d068708 | 644 | LPC_USB->DEVCMDSTAT = devCmdStat | SETUP; |
samux | 1:80ab0d068708 | 645 | |
samux | 1:80ab0d068708 | 646 | // EP0 SETUP event (SETUP data received) |
samux | 1:80ab0d068708 | 647 | EP0setupCallback(); |
samux | 1:80ab0d068708 | 648 | } else { |
samux | 1:80ab0d068708 | 649 | // EP0OUT ACK event (OUT data received) |
samux | 1:80ab0d068708 | 650 | EP0out(); |
samux | 1:80ab0d068708 | 651 | } |
samux | 1:80ab0d068708 | 652 | } |
samux | 1:80ab0d068708 | 653 | |
samux | 1:80ab0d068708 | 654 | if (LPC_USB->INTSTAT & EP(EP0IN)) { |
samux | 1:80ab0d068708 | 655 | // Clear EP0IN interrupt |
samux | 1:80ab0d068708 | 656 | LPC_USB->INTSTAT = EP(EP0IN); |
samux | 1:80ab0d068708 | 657 | |
samux | 1:80ab0d068708 | 658 | // EP0IN ACK event (IN data sent) |
samux | 1:80ab0d068708 | 659 | EP0in(); |
samux | 1:80ab0d068708 | 660 | } |
samux | 1:80ab0d068708 | 661 | |
samux | 1:80ab0d068708 | 662 | if (LPC_USB->INTSTAT & EP(EP1IN)) { |
samux | 1:80ab0d068708 | 663 | // Clear EP1IN interrupt |
samux | 1:80ab0d068708 | 664 | LPC_USB->INTSTAT = EP(EP1IN); |
samux | 1:80ab0d068708 | 665 | epComplete |= EP(EP1IN); |
samux | 1:80ab0d068708 | 666 | if (EP1_IN_callback()) |
samux | 1:80ab0d068708 | 667 | epComplete &= ~EP(EP1IN); |
samux | 1:80ab0d068708 | 668 | } |
samux | 1:80ab0d068708 | 669 | |
samux | 1:80ab0d068708 | 670 | if (LPC_USB->INTSTAT & EP(EP1OUT)) { |
samux | 1:80ab0d068708 | 671 | // Clear EP1OUT interrupt |
samux | 1:80ab0d068708 | 672 | LPC_USB->INTSTAT = EP(EP1OUT); |
samux | 1:80ab0d068708 | 673 | epComplete |= EP(EP1OUT); |
samux | 1:80ab0d068708 | 674 | if (EP1_OUT_callback()) |
samux | 1:80ab0d068708 | 675 | epComplete &= ~EP(EP1OUT); |
samux | 1:80ab0d068708 | 676 | } |
samux | 1:80ab0d068708 | 677 | |
samux | 1:80ab0d068708 | 678 | if (LPC_USB->INTSTAT & EP(EP2IN)) { |
samux | 1:80ab0d068708 | 679 | // Clear EPBULK_IN interrupt |
samux | 1:80ab0d068708 | 680 | LPC_USB->INTSTAT = EP(EP2IN); |
samux | 1:80ab0d068708 | 681 | epComplete |= EP(EP2IN); |
samux | 1:80ab0d068708 | 682 | if (EP2_IN_callback()) |
samux | 1:80ab0d068708 | 683 | epComplete &= ~EP(EP2IN); |
samux | 1:80ab0d068708 | 684 | } |
samux | 1:80ab0d068708 | 685 | |
samux | 1:80ab0d068708 | 686 | if (LPC_USB->INTSTAT & EP(EP2OUT)) { |
samux | 1:80ab0d068708 | 687 | // Clear EPBULK_OUT interrupt |
samux | 1:80ab0d068708 | 688 | LPC_USB->INTSTAT = EP(EP2OUT); |
samux | 1:80ab0d068708 | 689 | epComplete |= EP(EP2OUT); |
samux | 1:80ab0d068708 | 690 | //Call callback function. If true, clear epComplete |
samux | 1:80ab0d068708 | 691 | if (EP2_OUT_callback()) |
samux | 1:80ab0d068708 | 692 | epComplete &= ~EP(EP2OUT); |
samux | 1:80ab0d068708 | 693 | } |
samux | 1:80ab0d068708 | 694 | |
samux | 1:80ab0d068708 | 695 | if (LPC_USB->INTSTAT & EP(EP3IN)) { |
samux | 1:80ab0d068708 | 696 | // Clear EP3_IN interrupt |
samux | 1:80ab0d068708 | 697 | LPC_USB->INTSTAT = EP(EP3IN); |
samux | 1:80ab0d068708 | 698 | epComplete |= EP(EP3IN); |
samux | 1:80ab0d068708 | 699 | if (EP3_IN_callback()) |
samux | 1:80ab0d068708 | 700 | epComplete &= ~EP(EP3IN); |
samux | 1:80ab0d068708 | 701 | } |
samux | 1:80ab0d068708 | 702 | |
samux | 1:80ab0d068708 | 703 | if (LPC_USB->INTSTAT & EP(EP3OUT)) { |
samux | 1:80ab0d068708 | 704 | // Clear EP3_OUT interrupt |
samux | 1:80ab0d068708 | 705 | LPC_USB->INTSTAT = EP(EP3OUT); |
samux | 1:80ab0d068708 | 706 | epComplete |= EP(EP3OUT); |
samux | 1:80ab0d068708 | 707 | //Call callback function. If true, clear epComplete |
samux | 1:80ab0d068708 | 708 | if (EP3_OUT_callback()) |
samux | 1:80ab0d068708 | 709 | epComplete &= ~EP(EP3OUT); |
samux | 1:80ab0d068708 | 710 | } |
samux | 1:80ab0d068708 | 711 | } |
samux | 1:80ab0d068708 | 712 | |
samux | 1:80ab0d068708 | 713 | #endif |