ME11B Sample Code in Maxim Integrated Team

Dependencies:   BMI160 max32630hsp3 MemoryLCD USBDevice

Fork of Host_Software_MAX32664GWEB_HR_EXTENDED by Seyhmus Cacina

Committer:
seyhmus.cacina
Date:
Mon Mar 18 10:21:53 2019 +0300
Revision:
0:ac4dea3e2894
ME11B Sample Code First Commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
seyhmus.cacina 0:ac4dea3e2894 1 /* Copyright 2015 Silicon Labs, http://www.silabs.com
seyhmus.cacina 0:ac4dea3e2894 2 *
seyhmus.cacina 0:ac4dea3e2894 3 * Licensed under the Apache License, Version 2.0 (the "License");
seyhmus.cacina 0:ac4dea3e2894 4 * you may not use this file except in compliance with the License.
seyhmus.cacina 0:ac4dea3e2894 5 * You may obtain a copy of the License at
seyhmus.cacina 0:ac4dea3e2894 6 *
seyhmus.cacina 0:ac4dea3e2894 7 * http://www.apache.org/licenses/LICENSE-2.0
seyhmus.cacina 0:ac4dea3e2894 8 *
seyhmus.cacina 0:ac4dea3e2894 9 * Unless required by applicable law or agreed to in writing, software
seyhmus.cacina 0:ac4dea3e2894 10 * distributed under the License is distributed on an "AS IS" BASIS,
seyhmus.cacina 0:ac4dea3e2894 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
seyhmus.cacina 0:ac4dea3e2894 12 * See the License for the specific language governing permissions and
seyhmus.cacina 0:ac4dea3e2894 13 * limitations under the License.
seyhmus.cacina 0:ac4dea3e2894 14 */
seyhmus.cacina 0:ac4dea3e2894 15
seyhmus.cacina 0:ac4dea3e2894 16 #if defined TARGET_EFM32GG_STK3700 || \
seyhmus.cacina 0:ac4dea3e2894 17 defined TARGET_EFM32LG_STK3600 || \
seyhmus.cacina 0:ac4dea3e2894 18 defined TARGET_EFM32WG_STK3800 || \
seyhmus.cacina 0:ac4dea3e2894 19 defined TARGET_EFM32HG_STK3400
seyhmus.cacina 0:ac4dea3e2894 20
seyhmus.cacina 0:ac4dea3e2894 21 #include "USBHAL.h"
seyhmus.cacina 0:ac4dea3e2894 22 #include "em_usb.h"
seyhmus.cacina 0:ac4dea3e2894 23 #include "em_usbtypes.h"
seyhmus.cacina 0:ac4dea3e2894 24 #include "em_usbhal.h"
seyhmus.cacina 0:ac4dea3e2894 25 #include "em_usbd.h"
seyhmus.cacina 0:ac4dea3e2894 26
seyhmus.cacina 0:ac4dea3e2894 27 #include "sleepmodes.h"
seyhmus.cacina 0:ac4dea3e2894 28
seyhmus.cacina 0:ac4dea3e2894 29 enum USBISRCommand {
seyhmus.cacina 0:ac4dea3e2894 30 CMD_HANDLED = 0,
seyhmus.cacina 0:ac4dea3e2894 31 CMD_EP0SETUP,
seyhmus.cacina 0:ac4dea3e2894 32 CMD_EP0IN,
seyhmus.cacina 0:ac4dea3e2894 33 CMD_EP0OUT,
seyhmus.cacina 0:ac4dea3e2894 34 CMD_EP_XFER_COMPLETED,
seyhmus.cacina 0:ac4dea3e2894 35 CMD_SOF,
seyhmus.cacina 0:ac4dea3e2894 36 CMD_BUSRESET,
seyhmus.cacina 0:ac4dea3e2894 37 CMD_SUSPEND_STATE_CHANGED,
seyhmus.cacina 0:ac4dea3e2894 38 CMD_ENUM_END_MARKER
seyhmus.cacina 0:ac4dea3e2894 39 };
seyhmus.cacina 0:ac4dea3e2894 40
seyhmus.cacina 0:ac4dea3e2894 41 enum IEPStatus {
seyhmus.cacina 0:ac4dea3e2894 42 NOT_CONFIGURED = 0,
seyhmus.cacina 0:ac4dea3e2894 43 IDLE = 1,
seyhmus.cacina 0:ac4dea3e2894 44 READ_PENDING = 2,
seyhmus.cacina 0:ac4dea3e2894 45 WRITE_PENDING = 3,
seyhmus.cacina 0:ac4dea3e2894 46 READ_COMPLETE = 4,
seyhmus.cacina 0:ac4dea3e2894 47 WRITE_COMPLETE = 5,
seyhmus.cacina 0:ac4dea3e2894 48 FAILED_INVALID = 6,
seyhmus.cacina 0:ac4dea3e2894 49 FAILED_STALLED = 7
seyhmus.cacina 0:ac4dea3e2894 50 };
seyhmus.cacina 0:ac4dea3e2894 51
seyhmus.cacina 0:ac4dea3e2894 52 typedef struct {
seyhmus.cacina 0:ac4dea3e2894 53 IEPStatus status;
seyhmus.cacina 0:ac4dea3e2894 54 uint32_t byte_count;
seyhmus.cacina 0:ac4dea3e2894 55 uint32_t max_packet;
seyhmus.cacina 0:ac4dea3e2894 56 USB_XferCompleteCb_TypeDef intern_cb;
seyhmus.cacina 0:ac4dea3e2894 57 uint8_t *data_buf;
seyhmus.cacina 0:ac4dea3e2894 58 } ep_state_t;
seyhmus.cacina 0:ac4dea3e2894 59
seyhmus.cacina 0:ac4dea3e2894 60 USBHAL * USBHAL::instance;
seyhmus.cacina 0:ac4dea3e2894 61 static uint8_t ep0setupdata[8];
seyhmus.cacina 0:ac4dea3e2894 62 static ep_state_t ep_state[NUMBER_OF_ENDPOINTS];
seyhmus.cacina 0:ac4dea3e2894 63 #ifdef USB_USE_DYNAMIC_MEMORY
seyhmus.cacina 0:ac4dea3e2894 64 static uint8_t ep0in_data_buf[MAX_PACKET_SIZE_EP0] __attribute__ ((aligned (4)));
seyhmus.cacina 0:ac4dea3e2894 65 static uint8_t ep0out_data_buf[MAX_PACKET_SIZE_EP0]; // FIXME: does this need to be this big?
seyhmus.cacina 0:ac4dea3e2894 66 #else
seyhmus.cacina 0:ac4dea3e2894 67 static uint8_t ep_data_buf[NUMBER_OF_ENDPOINTS][64] __attribute__ ((aligned (4)));
seyhmus.cacina 0:ac4dea3e2894 68 #endif
seyhmus.cacina 0:ac4dea3e2894 69
seyhmus.cacina 0:ac4dea3e2894 70 static void run_cmd(USBISRCommand cmd, uint32_t param);
seyhmus.cacina 0:ac4dea3e2894 71 static void (*isrptr)() = NULL;
seyhmus.cacina 0:ac4dea3e2894 72 static USBISRCommand usb_isrcmd = CMD_HANDLED;
seyhmus.cacina 0:ac4dea3e2894 73 static uint32_t usb_isrcmd_param = 0;
seyhmus.cacina 0:ac4dea3e2894 74
seyhmus.cacina 0:ac4dea3e2894 75 extern "C" void usbhal_allow_em2(bool allow_em2);
seyhmus.cacina 0:ac4dea3e2894 76
seyhmus.cacina 0:ac4dea3e2894 77 #ifdef DEBUG_USB_API
seyhmus.cacina 0:ac4dea3e2894 78 #define TRACE(fmt,...) printf("USB: %s: " fmt "\n", __func__, __VA_ARGS__);
seyhmus.cacina 0:ac4dea3e2894 79 #define TRACE_FUNC_IN printf("USB: > %s\n",__func__);
seyhmus.cacina 0:ac4dea3e2894 80 #define TRACE_FUNC_IN_P(fmt, ...) printf("USB: > %s: " fmt "\n", __func__, __VA_ARGS__);
seyhmus.cacina 0:ac4dea3e2894 81 #else
seyhmus.cacina 0:ac4dea3e2894 82 #define TRACE(fmt,...)
seyhmus.cacina 0:ac4dea3e2894 83 #define TRACE_FUNC_IN
seyhmus.cacina 0:ac4dea3e2894 84 #define TRACE_FUNC_IN_P(fmt, ...)
seyhmus.cacina 0:ac4dea3e2894 85 #endif
seyhmus.cacina 0:ac4dea3e2894 86
seyhmus.cacina 0:ac4dea3e2894 87 static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize);
seyhmus.cacina 0:ac4dea3e2894 88
seyhmus.cacina 0:ac4dea3e2894 89 static int usbhal_xfer_complete_cb(uint8_t epaddr, USB_Status_TypeDef status,
seyhmus.cacina 0:ac4dea3e2894 90 uint32_t xferred, uint32_t remaining);
seyhmus.cacina 0:ac4dea3e2894 91 static void usbhal_free_buffers(void);
seyhmus.cacina 0:ac4dea3e2894 92
seyhmus.cacina 0:ac4dea3e2894 93 /* Internal EP transfer complete callbacks */
seyhmus.cacina 0:ac4dea3e2894 94 #define EPCB(n) static int usbhal_xfer_complete_cb_##n(USB_Status_TypeDef status, \
seyhmus.cacina 0:ac4dea3e2894 95 uint32_t xferred, uint32_t remaining) { \
seyhmus.cacina 0:ac4dea3e2894 96 return usbhal_xfer_complete_cb(n, status, xferred, remaining); \
seyhmus.cacina 0:ac4dea3e2894 97 }
seyhmus.cacina 0:ac4dea3e2894 98 /* ------^ */
seyhmus.cacina 0:ac4dea3e2894 99 EPCB(EP0OUT)
seyhmus.cacina 0:ac4dea3e2894 100 EPCB(EP0IN)
seyhmus.cacina 0:ac4dea3e2894 101 EPCB(EP1OUT)
seyhmus.cacina 0:ac4dea3e2894 102 EPCB(EP1IN)
seyhmus.cacina 0:ac4dea3e2894 103 EPCB(EP2OUT)
seyhmus.cacina 0:ac4dea3e2894 104 EPCB(EP2IN)
seyhmus.cacina 0:ac4dea3e2894 105 EPCB(EP3OUT)
seyhmus.cacina 0:ac4dea3e2894 106 EPCB(EP3IN)
seyhmus.cacina 0:ac4dea3e2894 107 #ifndef TARGET_EFM32HG_STK3400
seyhmus.cacina 0:ac4dea3e2894 108 EPCB(EP4OUT)
seyhmus.cacina 0:ac4dea3e2894 109 EPCB(EP4IN)
seyhmus.cacina 0:ac4dea3e2894 110 EPCB(EP5OUT)
seyhmus.cacina 0:ac4dea3e2894 111 EPCB(EP5IN)
seyhmus.cacina 0:ac4dea3e2894 112 EPCB(EP6OUT)
seyhmus.cacina 0:ac4dea3e2894 113 EPCB(EP6IN)
seyhmus.cacina 0:ac4dea3e2894 114 #endif
seyhmus.cacina 0:ac4dea3e2894 115
seyhmus.cacina 0:ac4dea3e2894 116 static inline bool is_aligned(const void *pointer, size_t byte_count)
seyhmus.cacina 0:ac4dea3e2894 117 {
seyhmus.cacina 0:ac4dea3e2894 118 return ((uintptr_t)pointer % byte_count == 0);
seyhmus.cacina 0:ac4dea3e2894 119 }
seyhmus.cacina 0:ac4dea3e2894 120
seyhmus.cacina 0:ac4dea3e2894 121 USBHAL::USBHAL(void)
seyhmus.cacina 0:ac4dea3e2894 122 {
seyhmus.cacina 0:ac4dea3e2894 123 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 124
seyhmus.cacina 0:ac4dea3e2894 125 isrptr = &USBHAL::_usbisr;
seyhmus.cacina 0:ac4dea3e2894 126
seyhmus.cacina 0:ac4dea3e2894 127 if (instance) {
seyhmus.cacina 0:ac4dea3e2894 128 TRACE("Assert self failed! instance=%p", instance);
seyhmus.cacina 0:ac4dea3e2894 129 abort();
seyhmus.cacina 0:ac4dea3e2894 130 }
seyhmus.cacina 0:ac4dea3e2894 131 instance = this;
seyhmus.cacina 0:ac4dea3e2894 132
seyhmus.cacina 0:ac4dea3e2894 133 // When USB is active, we can't go below EM1. This block may
seyhmus.cacina 0:ac4dea3e2894 134 // be dynamically removed/reinstated to allow deeper sleep.
seyhmus.cacina 0:ac4dea3e2894 135 usbhal_allow_em2(false);
seyhmus.cacina 0:ac4dea3e2894 136
seyhmus.cacina 0:ac4dea3e2894 137 // When in suspend / Vbus off we can go to EM2, but never below
seyhmus.cacina 0:ac4dea3e2894 138 // that as long as USB is being used. Despite the name the call here
seyhmus.cacina 0:ac4dea3e2894 139 // blocks entering modes _below_ EM2, but allows EM2.
seyhmus.cacina 0:ac4dea3e2894 140 blockSleepMode(EM2);
seyhmus.cacina 0:ac4dea3e2894 141
seyhmus.cacina 0:ac4dea3e2894 142 epCallback[EP0OUT] = NULL;
seyhmus.cacina 0:ac4dea3e2894 143 epCallback[EP0IN ] = NULL;
seyhmus.cacina 0:ac4dea3e2894 144 epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 145 epCallback[EP1IN ] = &USBHAL::EP1_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 146 epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 147 epCallback[EP2IN ] = &USBHAL::EP2_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 148 epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 149 epCallback[EP3IN ] = &USBHAL::EP3_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 150 #ifndef TARGET_EFM32HG_STK3400
seyhmus.cacina 0:ac4dea3e2894 151 epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 152 epCallback[EP4IN ] = &USBHAL::EP4_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 153 epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 154 epCallback[EP5IN ] = &USBHAL::EP5_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 155 epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback;
seyhmus.cacina 0:ac4dea3e2894 156 epCallback[EP6IN ] = &USBHAL::EP6_IN_callback;
seyhmus.cacina 0:ac4dea3e2894 157 #endif
seyhmus.cacina 0:ac4dea3e2894 158
seyhmus.cacina 0:ac4dea3e2894 159 memset(ep_state, 0, sizeof(ep_state));
seyhmus.cacina 0:ac4dea3e2894 160
seyhmus.cacina 0:ac4dea3e2894 161 ep_state[EP0OUT].intern_cb = usbhal_xfer_complete_cb_EP0OUT;
seyhmus.cacina 0:ac4dea3e2894 162 ep_state[EP0IN ].intern_cb = usbhal_xfer_complete_cb_EP0IN;
seyhmus.cacina 0:ac4dea3e2894 163 ep_state[EP1OUT].intern_cb = usbhal_xfer_complete_cb_EP1OUT;
seyhmus.cacina 0:ac4dea3e2894 164 ep_state[EP1IN ].intern_cb = usbhal_xfer_complete_cb_EP1IN;
seyhmus.cacina 0:ac4dea3e2894 165 ep_state[EP2OUT].intern_cb = usbhal_xfer_complete_cb_EP2OUT;
seyhmus.cacina 0:ac4dea3e2894 166 ep_state[EP2IN ].intern_cb = usbhal_xfer_complete_cb_EP2IN;
seyhmus.cacina 0:ac4dea3e2894 167 ep_state[EP3OUT].intern_cb = usbhal_xfer_complete_cb_EP3OUT;
seyhmus.cacina 0:ac4dea3e2894 168 ep_state[EP3IN ].intern_cb = usbhal_xfer_complete_cb_EP3IN;
seyhmus.cacina 0:ac4dea3e2894 169 #ifndef TARGET_EFM32HG_STK3400
seyhmus.cacina 0:ac4dea3e2894 170 ep_state[EP4OUT].intern_cb = usbhal_xfer_complete_cb_EP4OUT;
seyhmus.cacina 0:ac4dea3e2894 171 ep_state[EP4IN ].intern_cb = usbhal_xfer_complete_cb_EP4IN;
seyhmus.cacina 0:ac4dea3e2894 172 ep_state[EP5OUT].intern_cb = usbhal_xfer_complete_cb_EP5OUT;
seyhmus.cacina 0:ac4dea3e2894 173 ep_state[EP5IN ].intern_cb = usbhal_xfer_complete_cb_EP5IN;
seyhmus.cacina 0:ac4dea3e2894 174 ep_state[EP6OUT].intern_cb = usbhal_xfer_complete_cb_EP6OUT;
seyhmus.cacina 0:ac4dea3e2894 175 ep_state[EP6IN ].intern_cb = usbhal_xfer_complete_cb_EP6IN;
seyhmus.cacina 0:ac4dea3e2894 176 #endif
seyhmus.cacina 0:ac4dea3e2894 177
seyhmus.cacina 0:ac4dea3e2894 178 #ifdef USB_USE_DYNAMIC_MEMORY
seyhmus.cacina 0:ac4dea3e2894 179 ep_state[EP0OUT].data_buf = ep0out_data_buf;
seyhmus.cacina 0:ac4dea3e2894 180 ep_state[EP0IN].data_buf = ep0in_data_buf;
seyhmus.cacina 0:ac4dea3e2894 181 #else
seyhmus.cacina 0:ac4dea3e2894 182 for (int i=0 ; i<NUMBER_OF_ENDPOINTS ; i++) {
seyhmus.cacina 0:ac4dea3e2894 183 ep_state[i].data_buf = ep_data_buf[i];
seyhmus.cacina 0:ac4dea3e2894 184 }
seyhmus.cacina 0:ac4dea3e2894 185 #endif
seyhmus.cacina 0:ac4dea3e2894 186 }
seyhmus.cacina 0:ac4dea3e2894 187
seyhmus.cacina 0:ac4dea3e2894 188 USBHAL::~USBHAL(void)
seyhmus.cacina 0:ac4dea3e2894 189 {
seyhmus.cacina 0:ac4dea3e2894 190 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 191 USBD_AbortAllTransfers();
seyhmus.cacina 0:ac4dea3e2894 192 USBD_Disconnect();
seyhmus.cacina 0:ac4dea3e2894 193 usbhal_free_buffers();
seyhmus.cacina 0:ac4dea3e2894 194
seyhmus.cacina 0:ac4dea3e2894 195 usbhal_allow_em2(true);
seyhmus.cacina 0:ac4dea3e2894 196 unblockSleepMode(EM2);
seyhmus.cacina 0:ac4dea3e2894 197 }
seyhmus.cacina 0:ac4dea3e2894 198
seyhmus.cacina 0:ac4dea3e2894 199 extern "C" void usbhal_allow_em2(bool allow_em2)
seyhmus.cacina 0:ac4dea3e2894 200 {
seyhmus.cacina 0:ac4dea3e2894 201 if (allow_em2) {
seyhmus.cacina 0:ac4dea3e2894 202 // unblockSleepMode is safe to call even if we would unblock
seyhmus.cacina 0:ac4dea3e2894 203 // an already unblocked mode, so no checks here.
seyhmus.cacina 0:ac4dea3e2894 204 unblockSleepMode(EM1);
seyhmus.cacina 0:ac4dea3e2894 205 } else {
seyhmus.cacina 0:ac4dea3e2894 206 blockSleepMode(EM1);
seyhmus.cacina 0:ac4dea3e2894 207 }
seyhmus.cacina 0:ac4dea3e2894 208 }
seyhmus.cacina 0:ac4dea3e2894 209
seyhmus.cacina 0:ac4dea3e2894 210 static void usbhal_reset_cb(void)
seyhmus.cacina 0:ac4dea3e2894 211 {
seyhmus.cacina 0:ac4dea3e2894 212 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 213 run_cmd(CMD_BUSRESET, 0);
seyhmus.cacina 0:ac4dea3e2894 214 }
seyhmus.cacina 0:ac4dea3e2894 215
seyhmus.cacina 0:ac4dea3e2894 216 #ifdef DEBUG_USB_API
seyhmus.cacina 0:ac4dea3e2894 217 static const char *usbstate[] = { "NONE", "ATTACHED", "POWERED", "DEFAULT",
seyhmus.cacina 0:ac4dea3e2894 218 "ADDRESSED", "CONFIGURED", "SUSPENDED", "???" };
seyhmus.cacina 0:ac4dea3e2894 219 #endif
seyhmus.cacina 0:ac4dea3e2894 220
seyhmus.cacina 0:ac4dea3e2894 221 static void usbhal_state_change_cb(USBD_State_TypeDef oldState,
seyhmus.cacina 0:ac4dea3e2894 222 USBD_State_TypeDef newState)
seyhmus.cacina 0:ac4dea3e2894 223 {
seyhmus.cacina 0:ac4dea3e2894 224 TRACE("state changed %s -> %s", usbstate[oldState], usbstate[newState]);
seyhmus.cacina 0:ac4dea3e2894 225
seyhmus.cacina 0:ac4dea3e2894 226 if (oldState == USBD_STATE_SUSPENDED) {
seyhmus.cacina 0:ac4dea3e2894 227 run_cmd(CMD_SUSPEND_STATE_CHANGED, 0);
seyhmus.cacina 0:ac4dea3e2894 228 }
seyhmus.cacina 0:ac4dea3e2894 229
seyhmus.cacina 0:ac4dea3e2894 230 if (newState == USBD_STATE_SUSPENDED) {
seyhmus.cacina 0:ac4dea3e2894 231 run_cmd(CMD_SUSPEND_STATE_CHANGED, 1);
seyhmus.cacina 0:ac4dea3e2894 232 }
seyhmus.cacina 0:ac4dea3e2894 233
seyhmus.cacina 0:ac4dea3e2894 234 // Should call connectStateChanged from here as well but there is
seyhmus.cacina 0:ac4dea3e2894 235 // no documentation on when to actually do so. (And the implementation
seyhmus.cacina 0:ac4dea3e2894 236 // in USBDevice.cpp is a stub)
seyhmus.cacina 0:ac4dea3e2894 237
seyhmus.cacina 0:ac4dea3e2894 238 // HACK! Since connectStateChanged is not used, indicate the loss
seyhmus.cacina 0:ac4dea3e2894 239 // off connection by reporting a bus reset. This causes USBDevice
seyhmus.cacina 0:ac4dea3e2894 240 // to realise that at least it's not in CONFIGURED anymore, and
seyhmus.cacina 0:ac4dea3e2894 241 // stop trying to read/write in a busyloop.
seyhmus.cacina 0:ac4dea3e2894 242 if (newState == USBD_STATE_NONE) {
seyhmus.cacina 0:ac4dea3e2894 243 run_cmd(CMD_BUSRESET, 0);
seyhmus.cacina 0:ac4dea3e2894 244 }
seyhmus.cacina 0:ac4dea3e2894 245 }
seyhmus.cacina 0:ac4dea3e2894 246
seyhmus.cacina 0:ac4dea3e2894 247 static int usbhal_setupcmd_cb(const USB_Setup_TypeDef *setup)
seyhmus.cacina 0:ac4dea3e2894 248 {
seyhmus.cacina 0:ac4dea3e2894 249 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 250 if (!setup) {
seyhmus.cacina 0:ac4dea3e2894 251 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 252 return USB_STATUS_REQ_ERR;
seyhmus.cacina 0:ac4dea3e2894 253 }
seyhmus.cacina 0:ac4dea3e2894 254
seyhmus.cacina 0:ac4dea3e2894 255 memcpy(ep0setupdata, setup, 8);
seyhmus.cacina 0:ac4dea3e2894 256 run_cmd(CMD_EP0SETUP, 0);
seyhmus.cacina 0:ac4dea3e2894 257
seyhmus.cacina 0:ac4dea3e2894 258 return USB_STATUS_OK;
seyhmus.cacina 0:ac4dea3e2894 259 }
seyhmus.cacina 0:ac4dea3e2894 260
seyhmus.cacina 0:ac4dea3e2894 261 static void usbhal_sof_cb(uint16_t frameNum)
seyhmus.cacina 0:ac4dea3e2894 262 {
seyhmus.cacina 0:ac4dea3e2894 263 run_cmd(CMD_SOF, frameNum);
seyhmus.cacina 0:ac4dea3e2894 264 }
seyhmus.cacina 0:ac4dea3e2894 265
seyhmus.cacina 0:ac4dea3e2894 266 static void usbhal_free_buffers(void)
seyhmus.cacina 0:ac4dea3e2894 267 {
seyhmus.cacina 0:ac4dea3e2894 268 #ifdef USB_USE_DYNAMIC_MEMORY
seyhmus.cacina 0:ac4dea3e2894 269 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 270
seyhmus.cacina 0:ac4dea3e2894 271 for (int i=EP1OUT ; i<NUMBER_OF_ENDPOINTS ; i++ ) {
seyhmus.cacina 0:ac4dea3e2894 272 if (ep_state[i].data_buf) {
seyhmus.cacina 0:ac4dea3e2894 273 free(ep_state[i].data_buf);
seyhmus.cacina 0:ac4dea3e2894 274 ep_state[i].data_buf = NULL;
seyhmus.cacina 0:ac4dea3e2894 275 }
seyhmus.cacina 0:ac4dea3e2894 276 }
seyhmus.cacina 0:ac4dea3e2894 277 #endif
seyhmus.cacina 0:ac4dea3e2894 278 }
seyhmus.cacina 0:ac4dea3e2894 279
seyhmus.cacina 0:ac4dea3e2894 280 void USBHAL::connect(void)
seyhmus.cacina 0:ac4dea3e2894 281 {
seyhmus.cacina 0:ac4dea3e2894 282 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 283
seyhmus.cacina 0:ac4dea3e2894 284 // Init datastructures must be static - driver will use these even after the init function exits!
seyhmus.cacina 0:ac4dea3e2894 285
seyhmus.cacina 0:ac4dea3e2894 286 static const uint8_t buffer_multiplier[] = { 1 }; // Mult 1 for control EP
seyhmus.cacina 0:ac4dea3e2894 287 static const USBD_Callbacks_TypeDef usbd_callbacks = {
seyhmus.cacina 0:ac4dea3e2894 288 .usbReset = usbhal_reset_cb,
seyhmus.cacina 0:ac4dea3e2894 289 .usbStateChange = usbhal_state_change_cb,
seyhmus.cacina 0:ac4dea3e2894 290 .setupCmd = usbhal_setupcmd_cb,
seyhmus.cacina 0:ac4dea3e2894 291 .isSelfPowered = NULL,
seyhmus.cacina 0:ac4dea3e2894 292 .sofInt = usbhal_sof_cb
seyhmus.cacina 0:ac4dea3e2894 293 };
seyhmus.cacina 0:ac4dea3e2894 294
seyhmus.cacina 0:ac4dea3e2894 295 USBD_Init_TypeDef initdata = {
seyhmus.cacina 0:ac4dea3e2894 296 .deviceDescriptor = NULL,
seyhmus.cacina 0:ac4dea3e2894 297 .configDescriptor = NULL,
seyhmus.cacina 0:ac4dea3e2894 298 .stringDescriptors = NULL,
seyhmus.cacina 0:ac4dea3e2894 299 .numberOfStrings = 0,
seyhmus.cacina 0:ac4dea3e2894 300 .bufferingMultiplier = buffer_multiplier,
seyhmus.cacina 0:ac4dea3e2894 301 .callbacks = &usbd_callbacks,
seyhmus.cacina 0:ac4dea3e2894 302 .reserved = 0
seyhmus.cacina 0:ac4dea3e2894 303 };
seyhmus.cacina 0:ac4dea3e2894 304
seyhmus.cacina 0:ac4dea3e2894 305 int ret = USBD_Init(&initdata);
seyhmus.cacina 0:ac4dea3e2894 306
seyhmus.cacina 0:ac4dea3e2894 307 TRACE("init = %d, devicedesc = %lx, configdesc = %lx", ret,
seyhmus.cacina 0:ac4dea3e2894 308 (uint32_t) initdata.deviceDescriptor,
seyhmus.cacina 0:ac4dea3e2894 309 (uint32_t) initdata.configDescriptor);
seyhmus.cacina 0:ac4dea3e2894 310
seyhmus.cacina 0:ac4dea3e2894 311 EFM_ASSERT(ret == USB_STATUS_OK);
seyhmus.cacina 0:ac4dea3e2894 312 }
seyhmus.cacina 0:ac4dea3e2894 313
seyhmus.cacina 0:ac4dea3e2894 314 void USBHAL::disconnect(void)
seyhmus.cacina 0:ac4dea3e2894 315 {
seyhmus.cacina 0:ac4dea3e2894 316 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 317 USBD_Disconnect();
seyhmus.cacina 0:ac4dea3e2894 318 }
seyhmus.cacina 0:ac4dea3e2894 319
seyhmus.cacina 0:ac4dea3e2894 320 void USBHAL::configureDevice(void)
seyhmus.cacina 0:ac4dea3e2894 321 {
seyhmus.cacina 0:ac4dea3e2894 322 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 323 USBD_SetUsbState(USBD_STATE_CONFIGURED);
seyhmus.cacina 0:ac4dea3e2894 324 }
seyhmus.cacina 0:ac4dea3e2894 325
seyhmus.cacina 0:ac4dea3e2894 326 void USBHAL::unconfigureDevice(void)
seyhmus.cacina 0:ac4dea3e2894 327 {
seyhmus.cacina 0:ac4dea3e2894 328 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 329 USBD_SetUsbState(USBD_STATE_DEFAULT);
seyhmus.cacina 0:ac4dea3e2894 330 usbhal_free_buffers();
seyhmus.cacina 0:ac4dea3e2894 331 }
seyhmus.cacina 0:ac4dea3e2894 332
seyhmus.cacina 0:ac4dea3e2894 333 void USBHAL::setAddress(uint8_t address)
seyhmus.cacina 0:ac4dea3e2894 334 {
seyhmus.cacina 0:ac4dea3e2894 335 TRACE_FUNC_IN_P("addr 0x%x", (unsigned)address);
seyhmus.cacina 0:ac4dea3e2894 336 USBD_SetAddress(address);
seyhmus.cacina 0:ac4dea3e2894 337 }
seyhmus.cacina 0:ac4dea3e2894 338
seyhmus.cacina 0:ac4dea3e2894 339 void USBHAL::remoteWakeup(void)
seyhmus.cacina 0:ac4dea3e2894 340 {
seyhmus.cacina 0:ac4dea3e2894 341 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 342 USBD_RemoteWakeup();
seyhmus.cacina 0:ac4dea3e2894 343 }
seyhmus.cacina 0:ac4dea3e2894 344
seyhmus.cacina 0:ac4dea3e2894 345 void USBHAL::EP0setup(uint8_t *buffer)
seyhmus.cacina 0:ac4dea3e2894 346 {
seyhmus.cacina 0:ac4dea3e2894 347 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 348 EFM_ASSERT(buffer);
seyhmus.cacina 0:ac4dea3e2894 349 if (buffer) {
seyhmus.cacina 0:ac4dea3e2894 350 memcpy(buffer, ep0setupdata, 8);
seyhmus.cacina 0:ac4dea3e2894 351 }
seyhmus.cacina 0:ac4dea3e2894 352 }
seyhmus.cacina 0:ac4dea3e2894 353
seyhmus.cacina 0:ac4dea3e2894 354 void USBHAL::EP0read(void)
seyhmus.cacina 0:ac4dea3e2894 355 {
seyhmus.cacina 0:ac4dea3e2894 356 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 357 (void)internEndpointRead(0, MAX_PACKET_SIZE_EP0);
seyhmus.cacina 0:ac4dea3e2894 358 }
seyhmus.cacina 0:ac4dea3e2894 359
seyhmus.cacina 0:ac4dea3e2894 360 void USBHAL::EP0readStage(void)
seyhmus.cacina 0:ac4dea3e2894 361 {
seyhmus.cacina 0:ac4dea3e2894 362 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 363 // Not needed
seyhmus.cacina 0:ac4dea3e2894 364 }
seyhmus.cacina 0:ac4dea3e2894 365
seyhmus.cacina 0:ac4dea3e2894 366 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
seyhmus.cacina 0:ac4dea3e2894 367 {
seyhmus.cacina 0:ac4dea3e2894 368 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 369 EFM_ASSERT(buffer);
seyhmus.cacina 0:ac4dea3e2894 370
seyhmus.cacina 0:ac4dea3e2894 371 uint32_t read = 0;
seyhmus.cacina 0:ac4dea3e2894 372 endpointReadResult(0, buffer, &read);
seyhmus.cacina 0:ac4dea3e2894 373 return read;
seyhmus.cacina 0:ac4dea3e2894 374 }
seyhmus.cacina 0:ac4dea3e2894 375
seyhmus.cacina 0:ac4dea3e2894 376 static int usbhal_xfer_complete_cb(uint8_t ep, USB_Status_TypeDef status,
seyhmus.cacina 0:ac4dea3e2894 377 uint32_t xferred, uint32_t remaining)
seyhmus.cacina 0:ac4dea3e2894 378 {
seyhmus.cacina 0:ac4dea3e2894 379 TRACE_FUNC_IN_P("ep 0x%x, status %u, xferred %lu, rem %lu",
seyhmus.cacina 0:ac4dea3e2894 380 ep, status, xferred, remaining);
seyhmus.cacina 0:ac4dea3e2894 381
seyhmus.cacina 0:ac4dea3e2894 382 if (ep >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 383 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 384 return USB_STATUS_REQ_ERR;
seyhmus.cacina 0:ac4dea3e2894 385 }
seyhmus.cacina 0:ac4dea3e2894 386
seyhmus.cacina 0:ac4dea3e2894 387 switch (ep) {
seyhmus.cacina 0:ac4dea3e2894 388 case EP0OUT:
seyhmus.cacina 0:ac4dea3e2894 389 if (ep_state[EP0OUT].status == READ_PENDING) {
seyhmus.cacina 0:ac4dea3e2894 390 ep_state[EP0OUT].status = READ_COMPLETE;
seyhmus.cacina 0:ac4dea3e2894 391 ep_state[EP0OUT].byte_count = xferred;
seyhmus.cacina 0:ac4dea3e2894 392 // drop zlp
seyhmus.cacina 0:ac4dea3e2894 393 if (xferred == 0) {
seyhmus.cacina 0:ac4dea3e2894 394 break;
seyhmus.cacina 0:ac4dea3e2894 395 }
seyhmus.cacina 0:ac4dea3e2894 396 }
seyhmus.cacina 0:ac4dea3e2894 397 run_cmd(CMD_EP0OUT, 0);
seyhmus.cacina 0:ac4dea3e2894 398 break;
seyhmus.cacina 0:ac4dea3e2894 399
seyhmus.cacina 0:ac4dea3e2894 400 case EP0IN:
seyhmus.cacina 0:ac4dea3e2894 401 run_cmd(CMD_EP0IN, 0);
seyhmus.cacina 0:ac4dea3e2894 402 break;
seyhmus.cacina 0:ac4dea3e2894 403
seyhmus.cacina 0:ac4dea3e2894 404 default:
seyhmus.cacina 0:ac4dea3e2894 405 bool write = ep & 1;
seyhmus.cacina 0:ac4dea3e2894 406
seyhmus.cacina 0:ac4dea3e2894 407 if (status == USB_STATUS_OK) {
seyhmus.cacina 0:ac4dea3e2894 408 if (!write && ep_state[ep].status == READ_PENDING) {
seyhmus.cacina 0:ac4dea3e2894 409 ep_state[ep].status = READ_COMPLETE;
seyhmus.cacina 0:ac4dea3e2894 410 ep_state[ep].byte_count = xferred;
seyhmus.cacina 0:ac4dea3e2894 411 } else if (write && ep_state[ep].status == WRITE_PENDING) {
seyhmus.cacina 0:ac4dea3e2894 412 ep_state[ep].status = WRITE_COMPLETE;
seyhmus.cacina 0:ac4dea3e2894 413 } else {
seyhmus.cacina 0:ac4dea3e2894 414 ep_state[ep].status = FAILED_INVALID;
seyhmus.cacina 0:ac4dea3e2894 415 }
seyhmus.cacina 0:ac4dea3e2894 416 } else {
seyhmus.cacina 0:ac4dea3e2894 417 ep_state[ep].status = FAILED_INVALID;
seyhmus.cacina 0:ac4dea3e2894 418 }
seyhmus.cacina 0:ac4dea3e2894 419
seyhmus.cacina 0:ac4dea3e2894 420 if (ep_state[ep].status != FAILED_INVALID) {
seyhmus.cacina 0:ac4dea3e2894 421 run_cmd(CMD_EP_XFER_COMPLETED, ep);
seyhmus.cacina 0:ac4dea3e2894 422 }
seyhmus.cacina 0:ac4dea3e2894 423 break;
seyhmus.cacina 0:ac4dea3e2894 424 }
seyhmus.cacina 0:ac4dea3e2894 425
seyhmus.cacina 0:ac4dea3e2894 426 return USB_STATUS_OK;
seyhmus.cacina 0:ac4dea3e2894 427 }
seyhmus.cacina 0:ac4dea3e2894 428
seyhmus.cacina 0:ac4dea3e2894 429 void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
seyhmus.cacina 0:ac4dea3e2894 430 {
seyhmus.cacina 0:ac4dea3e2894 431 //TRACE_FUNC_IN_P("buffer %lx, size %lu", (uint32_t) buffer, size);
seyhmus.cacina 0:ac4dea3e2894 432
seyhmus.cacina 0:ac4dea3e2894 433 int ret;
seyhmus.cacina 0:ac4dea3e2894 434 USB_XferCompleteCb_TypeDef cb = ep_state[EP0IN].intern_cb;
seyhmus.cacina 0:ac4dea3e2894 435
seyhmus.cacina 0:ac4dea3e2894 436 EFM_ASSERT((buffer != NULL) || (size == 0));
seyhmus.cacina 0:ac4dea3e2894 437 EFM_ASSERT(size <= MAX_PACKET_SIZE_EP0);
seyhmus.cacina 0:ac4dea3e2894 438
seyhmus.cacina 0:ac4dea3e2894 439 if (!buffer || size == 0) {
seyhmus.cacina 0:ac4dea3e2894 440 // No callback after writing EP0 ZLP
seyhmus.cacina 0:ac4dea3e2894 441 cb = NULL;
seyhmus.cacina 0:ac4dea3e2894 442 }
seyhmus.cacina 0:ac4dea3e2894 443
seyhmus.cacina 0:ac4dea3e2894 444 if (buffer && !is_aligned(buffer,4)) {
seyhmus.cacina 0:ac4dea3e2894 445 // Copy unaligned data to write-buffer before USBD_Write
seyhmus.cacina 0:ac4dea3e2894 446 memcpy(ep_state[EP0IN].data_buf, buffer, size);
seyhmus.cacina 0:ac4dea3e2894 447 ret = USBD_Write(0, ep_state[EP0IN].data_buf, size, cb);
seyhmus.cacina 0:ac4dea3e2894 448 } else {
seyhmus.cacina 0:ac4dea3e2894 449 ret = USBD_Write(0, buffer, size, cb);
seyhmus.cacina 0:ac4dea3e2894 450 }
seyhmus.cacina 0:ac4dea3e2894 451
seyhmus.cacina 0:ac4dea3e2894 452 if (ret != USB_STATUS_OK) {
seyhmus.cacina 0:ac4dea3e2894 453 TRACE("FAILED - ret %d", ret);
seyhmus.cacina 0:ac4dea3e2894 454 }
seyhmus.cacina 0:ac4dea3e2894 455 }
seyhmus.cacina 0:ac4dea3e2894 456
seyhmus.cacina 0:ac4dea3e2894 457 void USBHAL::EP0stall(void)
seyhmus.cacina 0:ac4dea3e2894 458 {
seyhmus.cacina 0:ac4dea3e2894 459 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 460 USBD_StallEp0();
seyhmus.cacina 0:ac4dea3e2894 461 }
seyhmus.cacina 0:ac4dea3e2894 462
seyhmus.cacina 0:ac4dea3e2894 463 static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize)
seyhmus.cacina 0:ac4dea3e2894 464 {
seyhmus.cacina 0:ac4dea3e2894 465 //TRACE_FUNC_IN_P("endpoint 0x%x, size %ld, cb %d", (unsigned)ep, maxSize, useCallback);
seyhmus.cacina 0:ac4dea3e2894 466
seyhmus.cacina 0:ac4dea3e2894 467 if (ep >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 468 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 469 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 470 }
seyhmus.cacina 0:ac4dea3e2894 471
seyhmus.cacina 0:ac4dea3e2894 472 ep_state[ep].status = READ_PENDING;
seyhmus.cacina 0:ac4dea3e2894 473
seyhmus.cacina 0:ac4dea3e2894 474 int ret = USBD_Read(USB_EP_TO_ADDR(ep), ep_state[ep].data_buf, maxSize,
seyhmus.cacina 0:ac4dea3e2894 475 ep_state[ep].intern_cb);
seyhmus.cacina 0:ac4dea3e2894 476
seyhmus.cacina 0:ac4dea3e2894 477 if (ret == USB_STATUS_OK) {
seyhmus.cacina 0:ac4dea3e2894 478 return EP_PENDING;
seyhmus.cacina 0:ac4dea3e2894 479 } else {
seyhmus.cacina 0:ac4dea3e2894 480 TRACE("FAILED - ret %d", ret);
seyhmus.cacina 0:ac4dea3e2894 481
seyhmus.cacina 0:ac4dea3e2894 482 if (ret == USB_STATUS_EP_STALLED) {
seyhmus.cacina 0:ac4dea3e2894 483 return EP_STALLED;
seyhmus.cacina 0:ac4dea3e2894 484 } else {
seyhmus.cacina 0:ac4dea3e2894 485 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 486 }
seyhmus.cacina 0:ac4dea3e2894 487 }
seyhmus.cacina 0:ac4dea3e2894 488 }
seyhmus.cacina 0:ac4dea3e2894 489
seyhmus.cacina 0:ac4dea3e2894 490 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
seyhmus.cacina 0:ac4dea3e2894 491 {
seyhmus.cacina 0:ac4dea3e2894 492 return internEndpointRead(endpoint, maximumSize);
seyhmus.cacina 0:ac4dea3e2894 493 }
seyhmus.cacina 0:ac4dea3e2894 494
seyhmus.cacina 0:ac4dea3e2894 495 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead)
seyhmus.cacina 0:ac4dea3e2894 496 {
seyhmus.cacina 0:ac4dea3e2894 497 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 498
seyhmus.cacina 0:ac4dea3e2894 499 if (endpoint >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 500 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 501 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 502 }
seyhmus.cacina 0:ac4dea3e2894 503
seyhmus.cacina 0:ac4dea3e2894 504 EFM_ASSERT(data);
seyhmus.cacina 0:ac4dea3e2894 505 EFM_ASSERT(bytesRead);
seyhmus.cacina 0:ac4dea3e2894 506 if (!data || !bytesRead) {
seyhmus.cacina 0:ac4dea3e2894 507 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 508 }
seyhmus.cacina 0:ac4dea3e2894 509
seyhmus.cacina 0:ac4dea3e2894 510 switch (ep_state[endpoint].status) {
seyhmus.cacina 0:ac4dea3e2894 511 case READ_PENDING:
seyhmus.cacina 0:ac4dea3e2894 512 return EP_PENDING;
seyhmus.cacina 0:ac4dea3e2894 513
seyhmus.cacina 0:ac4dea3e2894 514 case READ_COMPLETE:
seyhmus.cacina 0:ac4dea3e2894 515 memcpy(data, ep_state[endpoint].data_buf, ep_state[endpoint].byte_count);
seyhmus.cacina 0:ac4dea3e2894 516 *bytesRead = ep_state[endpoint].byte_count;
seyhmus.cacina 0:ac4dea3e2894 517 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 518 return EP_COMPLETED;
seyhmus.cacina 0:ac4dea3e2894 519
seyhmus.cacina 0:ac4dea3e2894 520 case FAILED_STALLED:
seyhmus.cacina 0:ac4dea3e2894 521 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 522 return EP_STALLED;
seyhmus.cacina 0:ac4dea3e2894 523
seyhmus.cacina 0:ac4dea3e2894 524 default:
seyhmus.cacina 0:ac4dea3e2894 525 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 526 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 527 }
seyhmus.cacina 0:ac4dea3e2894 528 }
seyhmus.cacina 0:ac4dea3e2894 529
seyhmus.cacina 0:ac4dea3e2894 530 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
seyhmus.cacina 0:ac4dea3e2894 531 {
seyhmus.cacina 0:ac4dea3e2894 532 TRACE_FUNC_IN_P("endpoint 0x%x, data 0x%lx, size %lu", (unsigned )endpoint, (uint32_t)data, size);
seyhmus.cacina 0:ac4dea3e2894 533
seyhmus.cacina 0:ac4dea3e2894 534 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
seyhmus.cacina 0:ac4dea3e2894 535 EFM_ASSERT(endpoint > EP0IN);
seyhmus.cacina 0:ac4dea3e2894 536 EFM_ASSERT(size <= ep_state[endpoint].max_packet);
seyhmus.cacina 0:ac4dea3e2894 537 EFM_ASSERT(data);
seyhmus.cacina 0:ac4dea3e2894 538
seyhmus.cacina 0:ac4dea3e2894 539 uint8_t ep = USB_EP_TO_INDEX(endpoint);
seyhmus.cacina 0:ac4dea3e2894 540
seyhmus.cacina 0:ac4dea3e2894 541 if (endpoint >= NUMBER_OF_ENDPOINTS || endpoint <= EP0IN) {
seyhmus.cacina 0:ac4dea3e2894 542 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 543 }
seyhmus.cacina 0:ac4dea3e2894 544
seyhmus.cacina 0:ac4dea3e2894 545 if (size > ep_state[endpoint].max_packet) {
seyhmus.cacina 0:ac4dea3e2894 546 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 547 }
seyhmus.cacina 0:ac4dea3e2894 548
seyhmus.cacina 0:ac4dea3e2894 549 if (!data) {
seyhmus.cacina 0:ac4dea3e2894 550 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 551 }
seyhmus.cacina 0:ac4dea3e2894 552
seyhmus.cacina 0:ac4dea3e2894 553 memcpy(ep_state[ep].data_buf, data, size);
seyhmus.cacina 0:ac4dea3e2894 554
seyhmus.cacina 0:ac4dea3e2894 555 ep_state[ep].status = WRITE_PENDING;
seyhmus.cacina 0:ac4dea3e2894 556 int ret = USBD_Write(USB_EP_TO_ADDR(endpoint), ep_state[ep].data_buf, size, ep_state[ep].intern_cb);
seyhmus.cacina 0:ac4dea3e2894 557
seyhmus.cacina 0:ac4dea3e2894 558 if (ret == USB_STATUS_EP_STALLED) {
seyhmus.cacina 0:ac4dea3e2894 559 ep_state[ep].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 560 return EP_STALLED;
seyhmus.cacina 0:ac4dea3e2894 561 } else if (ret != USB_STATUS_OK) {
seyhmus.cacina 0:ac4dea3e2894 562 ep_state[ep].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 563 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 564 }
seyhmus.cacina 0:ac4dea3e2894 565
seyhmus.cacina 0:ac4dea3e2894 566 return EP_PENDING;
seyhmus.cacina 0:ac4dea3e2894 567 }
seyhmus.cacina 0:ac4dea3e2894 568
seyhmus.cacina 0:ac4dea3e2894 569 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
seyhmus.cacina 0:ac4dea3e2894 570 {
seyhmus.cacina 0:ac4dea3e2894 571 if (endpoint >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 572 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 573 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 574 }
seyhmus.cacina 0:ac4dea3e2894 575
seyhmus.cacina 0:ac4dea3e2894 576 switch (ep_state[endpoint].status) {
seyhmus.cacina 0:ac4dea3e2894 577 case WRITE_PENDING:
seyhmus.cacina 0:ac4dea3e2894 578 return EP_PENDING;
seyhmus.cacina 0:ac4dea3e2894 579
seyhmus.cacina 0:ac4dea3e2894 580 case WRITE_COMPLETE:
seyhmus.cacina 0:ac4dea3e2894 581 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 582 return EP_COMPLETED;
seyhmus.cacina 0:ac4dea3e2894 583
seyhmus.cacina 0:ac4dea3e2894 584 case FAILED_STALLED:
seyhmus.cacina 0:ac4dea3e2894 585 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 586 return EP_STALLED;
seyhmus.cacina 0:ac4dea3e2894 587
seyhmus.cacina 0:ac4dea3e2894 588 default:
seyhmus.cacina 0:ac4dea3e2894 589 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 590 return EP_INVALID;
seyhmus.cacina 0:ac4dea3e2894 591 }
seyhmus.cacina 0:ac4dea3e2894 592 }
seyhmus.cacina 0:ac4dea3e2894 593
seyhmus.cacina 0:ac4dea3e2894 594 void USBHAL::stallEndpoint(uint8_t endpoint)
seyhmus.cacina 0:ac4dea3e2894 595 {
seyhmus.cacina 0:ac4dea3e2894 596 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 597
seyhmus.cacina 0:ac4dea3e2894 598 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
seyhmus.cacina 0:ac4dea3e2894 599 EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
seyhmus.cacina 0:ac4dea3e2894 600
seyhmus.cacina 0:ac4dea3e2894 601 USBD_StallEp(USB_EP_TO_ADDR(endpoint));
seyhmus.cacina 0:ac4dea3e2894 602 }
seyhmus.cacina 0:ac4dea3e2894 603
seyhmus.cacina 0:ac4dea3e2894 604 void USBHAL::unstallEndpoint(uint8_t endpoint)
seyhmus.cacina 0:ac4dea3e2894 605 {
seyhmus.cacina 0:ac4dea3e2894 606 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 607
seyhmus.cacina 0:ac4dea3e2894 608 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
seyhmus.cacina 0:ac4dea3e2894 609 EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
seyhmus.cacina 0:ac4dea3e2894 610
seyhmus.cacina 0:ac4dea3e2894 611 USBD_UnStallEp(USB_EP_TO_ADDR(endpoint));
seyhmus.cacina 0:ac4dea3e2894 612 }
seyhmus.cacina 0:ac4dea3e2894 613
seyhmus.cacina 0:ac4dea3e2894 614 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options)
seyhmus.cacina 0:ac4dea3e2894 615 {
seyhmus.cacina 0:ac4dea3e2894 616 TRACE_FUNC_IN_P("endpoint %d, packetsize %ld, options 0x%lx", endpoint,
seyhmus.cacina 0:ac4dea3e2894 617 maxPacket, options);
seyhmus.cacina 0:ac4dea3e2894 618
seyhmus.cacina 0:ac4dea3e2894 619 int mult = 1; // RX/TX buffer size multiplier
seyhmus.cacina 0:ac4dea3e2894 620 int type = USB_EPTYPE_INTR;
seyhmus.cacina 0:ac4dea3e2894 621
seyhmus.cacina 0:ac4dea3e2894 622 if (endpoint >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 623 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 624 return false;
seyhmus.cacina 0:ac4dea3e2894 625 }
seyhmus.cacina 0:ac4dea3e2894 626
seyhmus.cacina 0:ac4dea3e2894 627 if (endpoint == EP0IN || endpoint == EP0OUT) {
seyhmus.cacina 0:ac4dea3e2894 628 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 629 return false;
seyhmus.cacina 0:ac4dea3e2894 630 }
seyhmus.cacina 0:ac4dea3e2894 631
seyhmus.cacina 0:ac4dea3e2894 632 ep_state[endpoint].max_packet = 0;
seyhmus.cacina 0:ac4dea3e2894 633
seyhmus.cacina 0:ac4dea3e2894 634 if (endpoint == EPISO_OUT || endpoint == EPISO_IN) {
seyhmus.cacina 0:ac4dea3e2894 635 if (maxPacket > MAX_PACKET_SIZE_EPISO) {
seyhmus.cacina 0:ac4dea3e2894 636 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 637 return false;
seyhmus.cacina 0:ac4dea3e2894 638 }
seyhmus.cacina 0:ac4dea3e2894 639 } else if ((maxPacket > MAX_PACKET_SIZE_EPBULK) || (maxPacket > MAX_PACKET_SIZE_EPINT)) {
seyhmus.cacina 0:ac4dea3e2894 640 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 641 return false;
seyhmus.cacina 0:ac4dea3e2894 642 }
seyhmus.cacina 0:ac4dea3e2894 643
seyhmus.cacina 0:ac4dea3e2894 644 // USBDevice performs a read right after creating the endpoints,
seyhmus.cacina 0:ac4dea3e2894 645 // before calling configureDevice. The read will fail since
seyhmus.cacina 0:ac4dea3e2894 646 // at that point the device state is still ADDRESSED. Workaround
seyhmus.cacina 0:ac4dea3e2894 647 // is to force configured state here.
seyhmus.cacina 0:ac4dea3e2894 648 //
seyhmus.cacina 0:ac4dea3e2894 649 // This relies on USBDevice to not call realiseEndpoint unless
seyhmus.cacina 0:ac4dea3e2894 650 // it is transitioning to the CONFIGURED state.
seyhmus.cacina 0:ac4dea3e2894 651 USBD_SetUsbState(USBD_STATE_CONFIGURED);
seyhmus.cacina 0:ac4dea3e2894 652
seyhmus.cacina 0:ac4dea3e2894 653 // Why doesn't this function have a type param? This is silly...
seyhmus.cacina 0:ac4dea3e2894 654 switch (endpoint) {
seyhmus.cacina 0:ac4dea3e2894 655 case EPBULK_OUT:
seyhmus.cacina 0:ac4dea3e2894 656 case EPBULK_IN:
seyhmus.cacina 0:ac4dea3e2894 657 type = USB_EPTYPE_BULK;
seyhmus.cacina 0:ac4dea3e2894 658 mult = 2;
seyhmus.cacina 0:ac4dea3e2894 659 break;
seyhmus.cacina 0:ac4dea3e2894 660 case EPINT_OUT:
seyhmus.cacina 0:ac4dea3e2894 661 case EPINT_IN:
seyhmus.cacina 0:ac4dea3e2894 662 type = USB_EPTYPE_INTR;
seyhmus.cacina 0:ac4dea3e2894 663 mult = 1;
seyhmus.cacina 0:ac4dea3e2894 664 break;
seyhmus.cacina 0:ac4dea3e2894 665 case EPISO_OUT:
seyhmus.cacina 0:ac4dea3e2894 666 case EPISO_IN:
seyhmus.cacina 0:ac4dea3e2894 667 type = USB_EPTYPE_ISOC;
seyhmus.cacina 0:ac4dea3e2894 668 mult = 2; // ?
seyhmus.cacina 0:ac4dea3e2894 669 break;
seyhmus.cacina 0:ac4dea3e2894 670 }
seyhmus.cacina 0:ac4dea3e2894 671
seyhmus.cacina 0:ac4dea3e2894 672 // Some options force the endpoint to a specific type
seyhmus.cacina 0:ac4dea3e2894 673 if( options & ISOCHRONOUS ) {
seyhmus.cacina 0:ac4dea3e2894 674 type = USB_EPTYPE_ISOC;
seyhmus.cacina 0:ac4dea3e2894 675 mult = 2; // ?
seyhmus.cacina 0:ac4dea3e2894 676 } else if ( options & RATE_FEEDBACK_MODE ) {
seyhmus.cacina 0:ac4dea3e2894 677 // No support for whatever rate feedback is, but for interrupt only
seyhmus.cacina 0:ac4dea3e2894 678 type = USB_EPTYPE_INTR;
seyhmus.cacina 0:ac4dea3e2894 679 mult = 1;
seyhmus.cacina 0:ac4dea3e2894 680 }
seyhmus.cacina 0:ac4dea3e2894 681
seyhmus.cacina 0:ac4dea3e2894 682 #ifdef USB_USE_DYNAMIC_MEMORY
seyhmus.cacina 0:ac4dea3e2894 683 if (ep_state[endpoint].data_buf) {
seyhmus.cacina 0:ac4dea3e2894 684 free(ep_state[endpoint].data_buf);
seyhmus.cacina 0:ac4dea3e2894 685 }
seyhmus.cacina 0:ac4dea3e2894 686
seyhmus.cacina 0:ac4dea3e2894 687 ep_state[endpoint].data_buf = (uint8_t *)malloc(maxPacket);
seyhmus.cacina 0:ac4dea3e2894 688
seyhmus.cacina 0:ac4dea3e2894 689 if (!ep_state[endpoint].data_buf) {
seyhmus.cacina 0:ac4dea3e2894 690 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 691 return false;
seyhmus.cacina 0:ac4dea3e2894 692 }
seyhmus.cacina 0:ac4dea3e2894 693 #endif
seyhmus.cacina 0:ac4dea3e2894 694
seyhmus.cacina 0:ac4dea3e2894 695 int ret = USBD_AddEndpoint(USB_EP_TO_ADDR(endpoint), type, maxPacket, mult);
seyhmus.cacina 0:ac4dea3e2894 696
seyhmus.cacina 0:ac4dea3e2894 697 if (ret == USB_STATUS_OK) {
seyhmus.cacina 0:ac4dea3e2894 698 ep_state[endpoint].status = IDLE;
seyhmus.cacina 0:ac4dea3e2894 699 ep_state[endpoint].max_packet = maxPacket;
seyhmus.cacina 0:ac4dea3e2894 700 return true;
seyhmus.cacina 0:ac4dea3e2894 701 } else {
seyhmus.cacina 0:ac4dea3e2894 702 return false;
seyhmus.cacina 0:ac4dea3e2894 703 }
seyhmus.cacina 0:ac4dea3e2894 704 }
seyhmus.cacina 0:ac4dea3e2894 705
seyhmus.cacina 0:ac4dea3e2894 706 bool USBHAL::getEndpointStallState(unsigned char endpoint)
seyhmus.cacina 0:ac4dea3e2894 707 {
seyhmus.cacina 0:ac4dea3e2894 708 TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 709 if (endpoint >= NUMBER_OF_ENDPOINTS) {
seyhmus.cacina 0:ac4dea3e2894 710 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 711 return false;
seyhmus.cacina 0:ac4dea3e2894 712 }
seyhmus.cacina 0:ac4dea3e2894 713 return USBD_EpIsStalled(USB_EP_TO_ADDR(endpoint));
seyhmus.cacina 0:ac4dea3e2894 714 }
seyhmus.cacina 0:ac4dea3e2894 715
seyhmus.cacina 0:ac4dea3e2894 716 static void run_cmd(USBISRCommand cmd, uint32_t param)
seyhmus.cacina 0:ac4dea3e2894 717 {
seyhmus.cacina 0:ac4dea3e2894 718 if (usb_isrcmd != CMD_HANDLED || cmd >= CMD_ENUM_END_MARKER) {
seyhmus.cacina 0:ac4dea3e2894 719 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 720 abort();
seyhmus.cacina 0:ac4dea3e2894 721 }
seyhmus.cacina 0:ac4dea3e2894 722
seyhmus.cacina 0:ac4dea3e2894 723 usb_isrcmd = cmd;
seyhmus.cacina 0:ac4dea3e2894 724 usb_isrcmd_param = param;
seyhmus.cacina 0:ac4dea3e2894 725 isrptr();
seyhmus.cacina 0:ac4dea3e2894 726 }
seyhmus.cacina 0:ac4dea3e2894 727
seyhmus.cacina 0:ac4dea3e2894 728 void USBHAL::_usbisr(void)
seyhmus.cacina 0:ac4dea3e2894 729 {
seyhmus.cacina 0:ac4dea3e2894 730 EFM_ASSERT(instance);
seyhmus.cacina 0:ac4dea3e2894 731 instance->usbisr();
seyhmus.cacina 0:ac4dea3e2894 732 }
seyhmus.cacina 0:ac4dea3e2894 733
seyhmus.cacina 0:ac4dea3e2894 734 void USBHAL::usbisr(void)
seyhmus.cacina 0:ac4dea3e2894 735 {
seyhmus.cacina 0:ac4dea3e2894 736 //TRACE_FUNC_IN;
seyhmus.cacina 0:ac4dea3e2894 737
seyhmus.cacina 0:ac4dea3e2894 738 // This "ISR" is used just to route callbacks from SiL USB driver
seyhmus.cacina 0:ac4dea3e2894 739 // callback context (which can not call protected/private USBHAL
seyhmus.cacina 0:ac4dea3e2894 740 // methods), to the actual USBHAL.
seyhmus.cacina 0:ac4dea3e2894 741
seyhmus.cacina 0:ac4dea3e2894 742 EFM_ASSERT(usb_isrcmd != CMD_HANDLED);
seyhmus.cacina 0:ac4dea3e2894 743 switch (usb_isrcmd) {
seyhmus.cacina 0:ac4dea3e2894 744 case CMD_EP0SETUP:
seyhmus.cacina 0:ac4dea3e2894 745 this->EP0setupCallback();
seyhmus.cacina 0:ac4dea3e2894 746 break;
seyhmus.cacina 0:ac4dea3e2894 747 case CMD_EP0IN:
seyhmus.cacina 0:ac4dea3e2894 748 this->EP0in();
seyhmus.cacina 0:ac4dea3e2894 749 break;
seyhmus.cacina 0:ac4dea3e2894 750 case CMD_EP0OUT:
seyhmus.cacina 0:ac4dea3e2894 751 this->EP0out();
seyhmus.cacina 0:ac4dea3e2894 752 break;
seyhmus.cacina 0:ac4dea3e2894 753 case CMD_BUSRESET:
seyhmus.cacina 0:ac4dea3e2894 754 this->busReset();
seyhmus.cacina 0:ac4dea3e2894 755 break;
seyhmus.cacina 0:ac4dea3e2894 756 case CMD_EP_XFER_COMPLETED:
seyhmus.cacina 0:ac4dea3e2894 757 if (epCallback[usb_isrcmd_param] && instance) {
seyhmus.cacina 0:ac4dea3e2894 758 (instance->*(epCallback[usb_isrcmd_param]))();
seyhmus.cacina 0:ac4dea3e2894 759 }
seyhmus.cacina 0:ac4dea3e2894 760 break;
seyhmus.cacina 0:ac4dea3e2894 761 case CMD_SOF:
seyhmus.cacina 0:ac4dea3e2894 762 this->SOF(usb_isrcmd_param);
seyhmus.cacina 0:ac4dea3e2894 763 break;
seyhmus.cacina 0:ac4dea3e2894 764 case CMD_SUSPEND_STATE_CHANGED:
seyhmus.cacina 0:ac4dea3e2894 765 this->suspendStateChanged(usb_isrcmd_param);
seyhmus.cacina 0:ac4dea3e2894 766 break;
seyhmus.cacina 0:ac4dea3e2894 767 default:
seyhmus.cacina 0:ac4dea3e2894 768 EFM_ASSERT(false);
seyhmus.cacina 0:ac4dea3e2894 769 break;
seyhmus.cacina 0:ac4dea3e2894 770 }
seyhmus.cacina 0:ac4dea3e2894 771 usb_isrcmd = CMD_HANDLED;
seyhmus.cacina 0:ac4dea3e2894 772 }
seyhmus.cacina 0:ac4dea3e2894 773 #endif
seyhmus.cacina 0:ac4dea3e2894 774
seyhmus.cacina 0:ac4dea3e2894 775 // End of file