Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 1 | /* ----------------------------------------------------------------------------
|
| 2 | * ATMEL Microcontroller Software Support
|
| 3 | * ----------------------------------------------------------------------------
|
| 4 | * Copyright (c) 2008, Atmel Corporation
|
| 5 | *
|
| 6 | * All rights reserved.
|
| 7 | *
|
| 8 | * Redistribution and use in source and binary forms, with or without
|
| 9 | * modification, are permitted provided that the following conditions are met:
|
| 10 | *
|
| 11 | * - Redistributions of source code must retain the above copyright notice,
|
| 12 | * this list of conditions and the disclaimer below.
|
| 13 | *
|
| 14 | * Atmel's name may not be used to endorse or promote products derived from
|
| 15 | * this software without specific prior written permission.
|
| 16 | *
|
| 17 | * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
| 20 | * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
| 23 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
| 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 27 | * ----------------------------------------------------------------------------
|
| 28 | */
|
| 29 |
|
| 30 | /**
|
| 31 |
|
| 32 | \file
|
| 33 |
|
| 34 | \section Purpose
|
| 35 |
|
| 36 | Implementation of USB device functions on a UDP controller.
|
| 37 |
|
| 38 | See \ref usbd_api_method USBD API Methods.
|
| 39 | */
|
| 40 |
|
| 41 | /** \addtogroup usbd_hal
|
| 42 | *@{*/
|
| 43 |
|
| 44 | /*---------------------------------------------------------------------------
|
| 45 | * Headers
|
| 46 | *---------------------------------------------------------------------------*/
|
| 47 |
|
| 48 | #include "chip.h"
|
| 49 | #include "USBD_HAL.h"
|
| 50 |
|
| 51 | #include <stdbool.h>
|
| 52 | #include <stdint.h>
|
| 53 | #include <stdio.h>
|
| 54 |
|
| 55 | /*---------------------------------------------------------------------------
|
| 56 | * Definitions
|
| 57 | *---------------------------------------------------------------------------*/
|
| 58 |
|
| 59 | /** Indicates chip has an UDP Full Speed. */
|
| 60 | #define CHIP_USB_UDP
|
| 61 |
|
| 62 | /** Indicates chip has an internal pull-up. */
|
| 63 | #define CHIP_USB_PULLUP_INTERNAL
|
| 64 |
|
| 65 | /** Number of USB endpoints */
|
| 66 | #define CHIP_USB_NUMENDPOINTS 8
|
| 67 |
|
| 68 | /** Endpoints max paxcket size */
|
| 69 | #define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \
|
| 70 | ((i == 0) ? 64 : \
|
| 71 | ((i == 1) ? 64 : \
|
| 72 | ((i == 2) ? 64 : \
|
| 73 | ((i == 3) ? 64 : \
|
| 74 | ((i == 4) ? 512 : \
|
| 75 | ((i == 5) ? 512 : \
|
| 76 | ((i == 6) ? 64 : \
|
| 77 | ((i == 7) ? 64 : 0 ))))))))
|
| 78 |
|
| 79 | /** Endpoints Number of Bank */
|
| 80 | #define CHIP_USB_ENDPOINTS_BANKS(i) \
|
| 81 | ((i == 0) ? 1 : \
|
| 82 | ((i == 1) ? 2 : \
|
| 83 | ((i == 2) ? 2 : \
|
| 84 | ((i == 3) ? 1 : \
|
| 85 | ((i == 4) ? 2 : \
|
| 86 | ((i == 5) ? 2 : \
|
| 87 | ((i == 6) ? 2 : \
|
| 88 | ((i == 7) ? 2 : 0 ))))))))
|
| 89 |
|
| 90 | /**
|
| 91 | * \section UDP_registers_sec "UDP Register field values"
|
| 92 | *
|
| 93 | * This section lists the initialize values of UDP registers.
|
| 94 | *
|
| 95 | * \subsection Values
|
| 96 | * - UDP_RXDATA
|
| 97 | */
|
| 98 | /** Bit mask for both banks of the UDP_CSR register. */
|
| 99 | #define UDP_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1)
|
| 100 |
|
| 101 | /**
|
| 102 | * \section endpoint_states_sec "UDP Endpoint states"
|
| 103 | *
|
| 104 | * This page lists the endpoint states.
|
| 105 | *
|
| 106 | * \subsection States
|
| 107 | * - UDP_ENDPOINT_DISABLED
|
| 108 | * - UDP_ENDPOINT_HALTED
|
| 109 | * - UDP_ENDPOINT_IDLE
|
| 110 | * - UDP_ENDPOINT_SENDING
|
| 111 | * - UDP_ENDPOINT_RECEIVING
|
| 112 | * - UDP_ENDPOINT_SENDINGM
|
| 113 | * - UDP_ENDPOINT_RECEIVINGM
|
| 114 | */
|
| 115 |
|
| 116 | /** Endpoint states: Endpoint is disabled */
|
| 117 | #define UDP_ENDPOINT_DISABLED 0
|
| 118 | /** Endpoint states: Endpoint is halted (i.e. STALLs every request) */
|
| 119 | #define UDP_ENDPOINT_HALTED 1
|
| 120 | /** Endpoint states: Endpoint is idle (i.e. ready for transmission) */
|
| 121 | #define UDP_ENDPOINT_IDLE 2
|
| 122 | /** Endpoint states: Endpoint is sending data */
|
| 123 | #define UDP_ENDPOINT_SENDING 3
|
| 124 | /** Endpoint states: Endpoint is receiving data */
|
| 125 | #define UDP_ENDPOINT_RECEIVING 4
|
| 126 | /** Endpoint states: Endpoint is sending MBL */
|
| 127 | #define UDP_ENDPOINT_SENDINGM 5
|
| 128 | /** Endpoint states: Endpoint is receiving MBL */
|
| 129 | #define UDP_ENDPOINT_RECEIVINGM 6
|
| 130 |
|
| 131 | /**
|
| 132 | * \section udp_csr_register_access_sec "UDP CSR register access"
|
| 133 | *
|
| 134 | * This page lists the macros to access UDP CSR register.
|
| 135 | *
|
| 136 | * \comment
|
| 137 | * In a preemptive environment, set or clear the flag and wait for a time of
|
| 138 | * 1 UDPCK clock cycle and 1 peripheral clock cycle. However, RX_DATA_BK0,
|
| 139 | * TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and
|
| 140 | * 5 peripheral clock cycles before accessing DPR.
|
| 141 | * See datasheet
|
| 142 | *
|
| 143 | * !Macros
|
| 144 | * - CLEAR_CSR
|
| 145 | * - SET_CSR
|
| 146 | */
|
| 147 |
|
| 148 | #if defined ( __CC_ARM )
|
| 149 | #define nop() {volatile int h; for(h=0;h<10;h++){}}
|
| 150 | #elif defined ( __ICCARM__ )
|
| 151 | #include <intrinsics.h>
|
| 152 | #define nop() (__no_operation())
|
| 153 | #elif defined ( __GNUC__ )
|
| 154 | #define nop() __asm__ __volatile__ ( "nop" )
|
| 155 | #endif
|
| 156 |
|
| 157 |
|
| 158 | /** Bitmap for all status bits in CSR. */
|
| 159 | #define REG_NO_EFFECT_1_ALL UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \
|
| 160 | |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \
|
| 161 | |UDP_CSR_TXCOMP
|
| 162 |
|
| 163 | /**
|
| 164 | * Sets the specified bit(s) in the UDP_CSR register.
|
| 165 | *
|
| 166 | * \param endpoint The endpoint number of the CSR to process.
|
| 167 | * \param flags The bitmap to set to 1.
|
| 168 | */
|
| 169 | #define SET_CSR(endpoint, flags) \
|
| 170 | { \
|
| 171 | volatile uint32_t reg; \
|
| 172 | int32_t nop_count ; \
|
| 173 | reg = UDP->UDP_CSR[endpoint] ; \
|
| 174 | reg |= REG_NO_EFFECT_1_ALL; \
|
| 175 | reg |= (flags); \
|
| 176 | UDP->UDP_CSR[endpoint] = reg; \
|
| 177 | for( nop_count=0; nop_count<15; nop_count++ ) {\
|
| 178 | nop();\
|
| 179 | }\
|
| 180 | }
|
| 181 |
|
| 182 | /**
|
| 183 | * Clears the specified bit(s) in the UDP_CSR register.
|
| 184 | *
|
| 185 | * \param endpoint The endpoint number of the CSR to process.
|
| 186 | * \param flags The bitmap to clear to 0.
|
| 187 | */
|
| 188 | #define CLEAR_CSR(endpoint, flags) \
|
| 189 | { \
|
| 190 | volatile uint32_t reg; \
|
| 191 | int32_t nop_count ; \
|
| 192 | reg = UDP->UDP_CSR[endpoint]; \
|
| 193 | reg |= REG_NO_EFFECT_1_ALL; \
|
| 194 | reg &= ~((uint32_t)(flags)); \
|
| 195 | UDP->UDP_CSR[endpoint] = reg; \
|
| 196 | for( nop_count=0; nop_count<15; nop_count++ ) {\
|
| 197 | nop();\
|
| 198 | }\
|
| 199 | }
|
| 200 |
|
| 201 |
|
| 202 | /** Get Number of buffer in Multi-Buffer-List
|
| 203 | * \param i input index
|
| 204 | * \param o output index
|
| 205 | * \param size list size
|
| 206 | */
|
| 207 | #define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o)))
|
| 208 |
|
| 209 | /** Buffer list is full */
|
| 210 | #define MBL_FULL 1
|
| 211 | /** Buffer list is null */
|
| 212 | #define MBL_NULL 2
|
| 213 |
|
| 214 | /*---------------------------------------------------------------------------
|
| 215 | * Types
|
| 216 | *---------------------------------------------------------------------------*/
|
| 217 |
|
| 218 | /** Describes header for UDP endpoint transfer. */
|
| 219 | typedef struct {
|
| 220 | /** Optional callback to invoke when the transfer completes. */
|
| 221 | void* fCallback;
|
| 222 | /** Optional argument to the callback function. */
|
| 223 | void* pArgument;
|
| 224 | /** Transfer type */
|
| 225 | uint8_t transType;
|
| 226 | } TransferHeader;
|
| 227 |
|
| 228 | /** Describes a transfer on a UDP endpoint. */
|
| 229 | typedef struct {
|
| 230 |
|
| 231 | /** Optional callback to invoke when the transfer completes. */
|
| 232 | TransferCallback fCallback;
|
| 233 | /** Optional argument to the callback function. */
|
| 234 | void *pArgument;
|
| 235 | /** Transfer type */
|
| 236 | uint16_t transType;
|
| 237 | /** Number of bytes which have been written into the UDP internal FIFO
|
| 238 | * buffers. */
|
| 239 | int16_t buffered;
|
| 240 | /** Pointer to a data buffer used for emission/reception. */
|
| 241 | uint8_t *pData;
|
| 242 | /** Number of bytes which have been sent/received. */
|
| 243 | int32_t transferred;
|
| 244 | /** Number of bytes which have not been buffered/transferred yet. */
|
| 245 | int32_t remaining;
|
| 246 | } Transfer;
|
| 247 |
|
| 248 | /** Describes Multi Buffer List transfer on a UDP endpoint. */
|
| 249 | typedef struct {
|
| 250 | /** Optional callback to invoke when the transfer completes. */
|
| 251 | MblTransferCallback fCallback;
|
| 252 | /** Optional argument to the callback function. */
|
| 253 | void *pArgument;
|
| 254 | /** Transfer type */
|
| 255 | volatile uint8_t transType;
|
| 256 | /** List state (OK, FULL, NULL) (run time) */
|
| 257 | uint8_t listState;
|
| 258 | /** Multi-Buffer List size */
|
| 259 | uint16_t listSize;
|
| 260 | /** Pointer to multi-buffer list */
|
| 261 | USBDTransferBuffer *pMbl;
|
| 262 | /** Offset number of buffers to start transfer */
|
| 263 | uint16_t offsetSize;
|
| 264 | /** Current processing buffer index (run time) */
|
| 265 | uint16_t outCurr;
|
| 266 | /** Loast loaded buffer index (run time) */
|
| 267 | uint16_t outLast;
|
| 268 | /** Current buffer for input (run time) */
|
| 269 | uint16_t inCurr;
|
| 270 | } MblTransfer;
|
| 271 |
|
| 272 | /**
|
| 273 | * Describes the state of an endpoint of the UDP controller.
|
| 274 | */
|
| 275 | typedef struct {
|
| 276 |
|
| 277 | /* CSR */
|
| 278 | //uint32_t CSR;
|
| 279 | /** Current endpoint state. */
|
| 280 | volatile uint8_t state;
|
| 281 | /** Current reception bank (0 or 1). */
|
| 282 | volatile uint8_t bank;
|
| 283 | /** Maximum packet size for the endpoint. */
|
| 284 | volatile uint16_t size;
|
| 285 | /** Describes an ongoing transfer (if current state is either
|
| 286 | * UDP_ENDPOINT_SENDING or UDP_ENDPOINT_RECEIVING) */
|
| 287 | union {
|
| 288 | TransferHeader transHdr;
|
| 289 | Transfer singleTransfer;
|
| 290 | MblTransfer mblTransfer;
|
| 291 | } transfer;
|
| 292 | } Endpoint;
|
| 293 |
|
| 294 | /*---------------------------------------------------------------------------
|
| 295 | * Internal variables
|
| 296 | *---------------------------------------------------------------------------*/
|
| 297 |
|
| 298 | /** Holds the internal state for each endpoint of the UDP. */
|
| 299 | static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
|
| 300 |
|
| 301 | /*---------------------------------------------------------------------------
|
| 302 | * Internal Functions
|
| 303 | *---------------------------------------------------------------------------*/
|
| 304 |
|
| 305 | /**
|
| 306 | * Enables the clock of the UDP peripheral.
|
| 307 | * \return 1 if peripheral status changed.
|
| 308 | */
|
| 309 | static uint8_t UDP_EnablePeripheralClock(void)
|
| 310 | {
|
| 311 | if (!PMC_IsPeriphEnabled(ID_UDP)) {
|
| 312 | PMC_EnablePeripheral(ID_UDP);
|
| 313 | return 1;
|
| 314 | }
|
| 315 | return 0;
|
| 316 | }
|
| 317 |
|
| 318 | /**
|
| 319 | * Disables the UDP peripheral clock.
|
| 320 | */
|
| 321 | static inline void UDP_DisablePeripheralClock(void)
|
| 322 | {
|
| 323 | PMC_DisablePeripheral(ID_UDP);
|
| 324 | }
|
| 325 |
|
| 326 | /**
|
| 327 | * Enables the 48MHz USB clock.
|
| 328 | */
|
| 329 | static inline void UDP_EnableUsbClock(void)
|
| 330 | {
|
| 331 | REG_PMC_SCER = PMC_SCER_UDP;
|
| 332 | }
|
| 333 |
|
| 334 | /**
|
| 335 | * Disables the 48MHz USB clock.
|
| 336 | */
|
| 337 | static inline void UDP_DisableUsbClock(void)
|
| 338 | {
|
| 339 | REG_PMC_SCDR = PMC_SCER_UDP;
|
| 340 | }
|
| 341 |
|
| 342 | /**
|
| 343 | * Enables the UDP transceiver.
|
| 344 | */
|
| 345 | static inline void UDP_EnableTransceiver(void)
|
| 346 | {
|
| 347 | UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_TXVDIS;
|
| 348 | }
|
| 349 |
|
| 350 | /**
|
| 351 | * Disables the UDP transceiver.
|
| 352 | */
|
| 353 | static inline void UDP_DisableTransceiver(void)
|
| 354 | {
|
| 355 | UDP->UDP_TXVC |= UDP_TXVC_TXVDIS;
|
| 356 | }
|
| 357 |
|
| 358 | /**
|
| 359 | * Handles a completed transfer on the given endpoint, invoking the
|
| 360 | * configured callback if any.
|
| 361 | * \param bEndpoint Number of the endpoint for which the transfer has completed.
|
| 362 | * \param bStatus Status code returned by the transfer operation
|
| 363 | */
|
| 364 | static void UDP_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus)
|
| 365 | {
|
| 366 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 367 |
|
| 368 | // Check that endpoint was sending or receiving data
|
| 369 | if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
| 370 | || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
|
| 371 |
|
| 372 | Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer);
|
| 373 | uint32_t transferred = pTransfer->transferred;
|
| 374 | uint32_t remaining = pTransfer->remaining + pTransfer->buffered;
|
| 375 |
|
| 376 | TRACE_DEBUG_WP("EoT ");
|
| 377 |
|
| 378 | /* Endpoint returns in Idle state */
|
| 379 | pEndpoint->state = UDP_ENDPOINT_IDLE;
|
| 380 | /* Reset descriptor values */
|
| 381 | pTransfer->pData = 0;
|
| 382 | pTransfer->transferred = -1;
|
| 383 | pTransfer->buffered = -1;
|
| 384 | pTransfer->remaining = -1;
|
| 385 |
|
| 386 | // Invoke callback is present
|
| 387 | if (pTransfer->fCallback != 0) {
|
| 388 |
|
| 389 | ((TransferCallback) pTransfer->fCallback)
|
| 390 | (pTransfer->pArgument,
|
| 391 | bStatus,
|
| 392 | transferred,
|
| 393 | remaining);
|
| 394 | }
|
| 395 | else {
|
| 396 | TRACE_DEBUG_WP("NoCB ");
|
| 397 | }
|
| 398 | }
|
| 399 | else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
|
| 400 | || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
|
| 401 |
|
| 402 | MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
|
| 403 |
|
| 404 | TRACE_DEBUG_WP("EoMT ");
|
| 405 |
|
| 406 | /* Endpoint returns in Idle state */
|
| 407 | pEndpoint->state = UDP_ENDPOINT_IDLE;
|
| 408 | /* Reset transfer descriptor */
|
| 409 | if (pTransfer->transType) {
|
| 410 | MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
|
| 411 | pMblt->listState = 0;
|
| 412 | pMblt->outCurr = pMblt->inCurr = pMblt->outLast = 0;
|
| 413 | }
|
| 414 | /* Invoke callback */
|
| 415 | if (pTransfer->fCallback != 0) {
|
| 416 |
|
| 417 | ((MblTransferCallback) pTransfer->fCallback)
|
| 418 | (pTransfer->pArgument,
|
| 419 | bStatus);
|
| 420 | }
|
| 421 | else {
|
| 422 | TRACE_DEBUG_WP("NoCB ");
|
| 423 | }
|
| 424 | }
|
| 425 | }
|
| 426 |
|
| 427 | /**
|
| 428 | * Clears the correct reception flag (bank 0 or bank 1) of an endpoint
|
| 429 | * \param bEndpoint Index of endpoint
|
| 430 | */
|
| 431 | static void UDP_ClearRxFlag(uint8_t bEndpoint)
|
| 432 | {
|
| 433 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 434 |
|
| 435 | // Clear flag and change banks
|
| 436 | if (pEndpoint->bank == 0) {
|
| 437 |
|
| 438 | CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK0);
|
| 439 | // Swap bank if in dual-fifo mode
|
| 440 | if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) {
|
| 441 |
|
| 442 | pEndpoint->bank = 1;
|
| 443 | }
|
| 444 | }
|
| 445 | else {
|
| 446 |
|
| 447 | CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK1);
|
| 448 | pEndpoint->bank = 0;
|
| 449 | }
|
| 450 | }
|
| 451 |
|
| 452 | /**
|
| 453 | * Update multi-buffer-transfer descriptors.
|
| 454 | * \param pTransfer Pointer to instance MblTransfer.
|
| 455 | * \param size Size of bytes that processed.
|
| 456 | * \param forceEnd Force the buffer END.
|
| 457 | * \return 1 if current buffer ended.
|
| 458 | */
|
| 459 | static uint8_t UDP_MblUpdate(MblTransfer *pTransfer,
|
| 460 | USBDTransferBuffer * pBi,
|
| 461 | uint16_t size,
|
| 462 | uint8_t forceEnd)
|
| 463 | {
|
| 464 | /* Update transfer descriptor */
|
| 465 | pBi->remaining -= size;
|
| 466 | /* Check if list NULL */
|
| 467 | if (pTransfer->listState == MBL_NULL) {
|
| 468 | return 1;
|
| 469 | }
|
| 470 | /* Check if current buffer ended */
|
| 471 | if (pBi->remaining == 0 || forceEnd || size == 0) {
|
| 472 |
|
| 473 | /* Process to next buffer */
|
| 474 | if ((++ pTransfer->outCurr) == pTransfer->listSize)
|
| 475 | pTransfer->outCurr = 0;
|
| 476 | /* Check buffer NULL case */
|
| 477 | if (pTransfer->outCurr == pTransfer->inCurr)
|
| 478 | pTransfer->listState = MBL_NULL;
|
| 479 | else {
|
| 480 | pTransfer->listState = 0;
|
| 481 | /* Continue transfer, prepare for next operation */
|
| 482 | pBi = &pTransfer->pMbl[pTransfer->outCurr];
|
| 483 | pBi->buffered = 0;
|
| 484 | pBi->transferred = 0;
|
| 485 | pBi->remaining = pBi->size;
|
| 486 | }
|
| 487 | return 1;
|
| 488 | }
|
| 489 | return 0;
|
| 490 | }
|
| 491 |
|
| 492 | /**
|
| 493 | * Transfers a data payload from the current tranfer buffer to the endpoint
|
| 494 | * FIFO
|
| 495 | * \param bEndpoint Number of the endpoint which is sending data.
|
| 496 | */
|
| 497 | static uint8_t UDP_MblWriteFifo(uint8_t bEndpoint)
|
| 498 | {
|
| 499 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 500 | MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
|
| 501 | USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]);
|
| 502 | int32_t size;
|
| 503 |
|
| 504 | volatile uint8_t * pBytes;
|
| 505 | volatile uint8_t bufferEnd = 1;
|
| 506 |
|
| 507 | /* Get the number of bytes to send */
|
| 508 | size = pEndpoint->size;
|
| 509 | if (size > pBi->remaining) size = pBi->remaining;
|
| 510 |
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 511 | TRACE_DEBUG_WP("w%d.%" PRId32 " ", pTransfer->outCurr, size);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 512 |
|
| 513 | /* Record last accessed buffer */
|
| 514 | pTransfer->outLast = pTransfer->outCurr;
|
| 515 |
|
| 516 | pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
|
| 517 | pBi->buffered += size;
|
| 518 | bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0);
|
| 519 |
|
| 520 | /* Write packet in the FIFO buffer */
|
| 521 | if (size) {
|
| 522 | int32_t c8 = size >> 3;
|
| 523 | int32_t c1 = size & 0x7;
|
| 524 | for (; c8; c8 --) {
|
| 525 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 526 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 527 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 528 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 529 |
|
| 530 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 531 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 532 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 533 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 534 | }
|
| 535 | for (; c1; c1 --) {
|
| 536 | UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
| 537 | }
|
| 538 | }
|
| 539 | return bufferEnd;
|
| 540 | }
|
| 541 |
|
| 542 | /**
|
| 543 | * Transfers a data payload from the current tranfer buffer to the endpoint
|
| 544 | * FIFO
|
| 545 | * \param bEndpoint Number of the endpoint which is sending data.
|
| 546 | */
|
| 547 | static void UDP_WritePayload(uint8_t bEndpoint)
|
| 548 | {
|
| 549 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 550 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 551 | int32_t size;
|
| 552 |
|
| 553 | // Get the number of bytes to send
|
| 554 | size = pEndpoint->size;
|
| 555 | if (size > pTransfer->remaining) {
|
| 556 |
|
| 557 | size = pTransfer->remaining;
|
| 558 | }
|
| 559 |
|
| 560 | // Update transfer descriptor information
|
| 561 | pTransfer->buffered += size;
|
| 562 | pTransfer->remaining -= size;
|
| 563 |
|
| 564 | // Write packet in the FIFO buffer
|
| 565 | while (size > 0) {
|
| 566 |
|
| 567 | UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData);
|
| 568 | pTransfer->pData++;
|
| 569 | size--;
|
| 570 | }
|
| 571 | }
|
| 572 |
|
| 573 |
|
| 574 | /**
|
| 575 | * Transfers a data payload from an endpoint FIFO to the current transfer buffer
|
| 576 | * \param bEndpoint Endpoint number.
|
| 577 | * \param wPacketSize Size of received data packet
|
| 578 | */
|
| 579 | static void UDP_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize)
|
| 580 | {
|
| 581 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 582 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 583 |
|
| 584 | // Check that the requested size is not bigger than the remaining transfer
|
| 585 | if (wPacketSize > pTransfer->remaining) {
|
| 586 |
|
| 587 | pTransfer->buffered += wPacketSize - pTransfer->remaining;
|
| 588 | wPacketSize = pTransfer->remaining;
|
| 589 | }
|
| 590 |
|
| 591 | // Update transfer descriptor information
|
| 592 | pTransfer->remaining -= wPacketSize;
|
| 593 | pTransfer->transferred += wPacketSize;
|
| 594 |
|
| 595 | // Retrieve packet
|
| 596 | while (wPacketSize > 0) {
|
| 597 |
|
| 598 | *(pTransfer->pData) = (uint8_t) UDP->UDP_FDR[bEndpoint];
|
| 599 | pTransfer->pData++;
|
| 600 | wPacketSize--;
|
| 601 | }
|
| 602 | }
|
| 603 |
|
| 604 | /**
|
| 605 | * Received SETUP packet from endpoint 0 FIFO
|
| 606 | * \param pRequest Generic USB SETUP request sent over Control endpoints
|
| 607 | */
|
| 608 | static void UDP_ReadRequest(USBGenericRequest *pRequest)
|
| 609 | {
|
| 610 | uint8_t *pData = (uint8_t *)pRequest;
|
| 611 | uint32_t i;
|
| 612 |
|
| 613 | // Copy packet
|
| 614 | for (i = 0; i < 8; i++) {
|
| 615 |
|
| 616 | *pData = (uint8_t) UDP->UDP_FDR[0];
|
| 617 | pData++;
|
| 618 | }
|
| 619 | }
|
| 620 |
|
| 621 | /**
|
| 622 | * Checks if an ongoing transfer on an endpoint has been completed.
|
| 623 | * \param bEndpoint Endpoint number.
|
| 624 | * \return 1 if the current transfer on the given endpoint is complete;
|
| 625 | * otherwise 0.
|
| 626 | */
|
| 627 | static uint8_t UDP_IsTransferFinished(uint8_t bEndpoint)
|
| 628 | {
|
| 629 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 630 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 631 |
|
| 632 | // Check if it is a Control endpoint
|
| 633 | // -> Control endpoint must always finish their transfer with a zero-length
|
| 634 | // packet
|
| 635 | if ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) {
|
| 636 |
|
| 637 | return (pTransfer->buffered < pEndpoint->size);
|
| 638 | }
|
| 639 | // Other endpoints only need to transfer all the data
|
| 640 | else {
|
| 641 |
|
| 642 | return (pTransfer->buffered <= pEndpoint->size)
|
| 643 | && (pTransfer->remaining == 0);
|
| 644 | }
|
| 645 | }
|
| 646 |
|
| 647 | /**
|
| 648 | * Endpoint interrupt handler.
|
| 649 | * Handle IN/OUT transfers, received SETUP packets and STALLing
|
| 650 | * \param bEndpoint Index of endpoint
|
| 651 | */
|
| 652 | static void UDP_EndpointHandler(uint8_t bEndpoint)
|
| 653 | {
|
| 654 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 655 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 656 | MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
|
| 657 | uint32_t status = UDP->UDP_CSR[bEndpoint];
|
| 658 | uint16_t wPacketSize;
|
| 659 | USBGenericRequest request;
|
| 660 |
|
| 661 | TRACE_DEBUG_WP("E%d ", bEndpoint);
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 662 | TRACE_DEBUG_WP("st:0x%" PRIX32 " ", status);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 663 |
|
| 664 | // Handle interrupts
|
| 665 | // IN packet sent
|
| 666 | if ((status & UDP_CSR_TXCOMP) != 0) {
|
| 667 |
|
| 668 | TRACE_DEBUG_WP("Wr ");
|
| 669 |
|
| 670 | // Check that endpoint was in MBL Sending state
|
| 671 | if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) {
|
| 672 |
|
| 673 | USBDTransferBuffer * pMbli = &(pMblt->pMbl[pMblt->outLast]);
|
| 674 | uint8_t bufferEnd = 0;
|
| 675 |
|
| 676 | TRACE_DEBUG_WP("TxM%d.%d ", pMblt->listState, pMbli->buffered);
|
| 677 |
|
| 678 | // End of transfer ?
|
| 679 | if (pMblt->listState == MBL_NULL && pMbli->buffered == 0) {
|
| 680 |
|
| 681 | pMbli->transferred += pMbli->buffered;
|
| 682 | pMbli->buffered = 0;
|
| 683 |
|
| 684 | // Disable interrupt
|
| 685 | UDP->UDP_IDR = 1 << bEndpoint;
|
| 686 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
| 687 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 688 | }
|
| 689 | else {
|
| 690 |
|
| 691 | // Transfer remaining data
|
| 692 | TRACE_DEBUG_WP("%d ", pEndpoint->size);
|
| 693 |
|
| 694 | if (pMbli->buffered > pEndpoint->size) {
|
| 695 | pMbli->transferred += pEndpoint->size;
|
| 696 | pMbli->buffered -= pEndpoint->size;
|
| 697 | }
|
| 698 | else {
|
| 699 | pMbli->transferred += pMbli->buffered;
|
| 700 | pMbli->buffered = 0;
|
| 701 | }
|
| 702 |
|
| 703 | // Send next packet
|
| 704 | if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
|
| 705 |
|
| 706 | // No double buffering
|
| 707 | bufferEnd = UDP_MblWriteFifo(bEndpoint);
|
| 708 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 709 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 710 | }
|
| 711 | else {
|
| 712 | // Double buffering
|
| 713 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 714 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 715 | bufferEnd = UDP_MblWriteFifo(bEndpoint);
|
| 716 | }
|
| 717 |
|
| 718 | if (bufferEnd && pMblt->fCallback) {
|
| 719 | ((MblTransferCallback) pTransfer->fCallback)
|
| 720 | (pTransfer->pArgument,
|
| 721 | USBD_STATUS_PARTIAL_DONE);
|
| 722 | }
|
| 723 | }
|
| 724 | }
|
| 725 | // Check that endpoint was in Sending state
|
| 726 | else if (pEndpoint->state == UDP_ENDPOINT_SENDING) {
|
| 727 |
|
| 728 | // End of transfer ?
|
| 729 | if (UDP_IsTransferFinished(bEndpoint)) {
|
| 730 |
|
| 731 | pTransfer->transferred += pTransfer->buffered;
|
| 732 | pTransfer->buffered = 0;
|
| 733 |
|
| 734 | // Disable interrupt if this is not a control endpoint
|
| 735 | if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
|
| 736 |
|
| 737 | UDP->UDP_IDR = 1 << bEndpoint;
|
| 738 | }
|
| 739 |
|
| 740 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
| 741 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 742 | }
|
| 743 | else {
|
| 744 |
|
| 745 | // Transfer remaining data
|
| 746 | TRACE_DEBUG_WP(" %d ", pEndpoint->size);
|
| 747 |
|
| 748 | pTransfer->transferred += pEndpoint->size;
|
| 749 | pTransfer->buffered -= pEndpoint->size;
|
| 750 |
|
| 751 | // Send next packet
|
| 752 | if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
|
| 753 |
|
| 754 | // No double buffering
|
| 755 | UDP_WritePayload(bEndpoint);
|
| 756 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 757 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 758 | }
|
| 759 | else {
|
| 760 | // Double buffering
|
| 761 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 762 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 763 | UDP_WritePayload(bEndpoint);
|
| 764 | }
|
| 765 | }
|
| 766 | }
|
| 767 | else {
|
| 768 | // Acknowledge interrupt
|
| 769 | TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state);
|
| 770 | CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
| 771 | }
|
| 772 | }
|
| 773 |
|
| 774 | // OUT packet received
|
| 775 | if ((status & UDP_CSR_RXDATA_BK) != 0) {
|
| 776 |
|
| 777 | TRACE_DEBUG_WP("Rd ");
|
| 778 |
|
| 779 | // Check that the endpoint is in Receiving state
|
| 780 | if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
|
| 781 |
|
| 782 | // Check if an ACK has been received on a Control endpoint
|
| 783 | if (((status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL)
|
| 784 | && ((status & UDP_CSR_RXBYTECNT_Msk) == 0)) {
|
| 785 |
|
| 786 | // Acknowledge the data and finish the current transfer
|
| 787 | UDP_ClearRxFlag(bEndpoint);
|
| 788 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
| 789 | }
|
| 790 | // Check if the data has been STALLed
|
| 791 | else if ((status & UDP_CSR_FORCESTALL) != 0) {
|
| 792 |
|
| 793 | // Discard STALLed data
|
| 794 | TRACE_DEBUG_WP("Discard ");
|
| 795 | UDP_ClearRxFlag(bEndpoint);
|
| 796 | }
|
| 797 | // NAK the data
|
| 798 | else {
|
| 799 |
|
| 800 | TRACE_DEBUG_WP("Nak ");
|
| 801 | UDP->UDP_IDR = 1 << bEndpoint;
|
| 802 | }
|
| 803 | }
|
| 804 | // Endpoint is in Read state
|
| 805 | else {
|
| 806 |
|
| 807 | // Retrieve data and store it into the current transfer buffer
|
| 808 | wPacketSize = (uint16_t) (status >> 16);
|
| 809 | TRACE_DEBUG_WP("%d ", wPacketSize);
|
| 810 | UDP_ReadPayload(bEndpoint, wPacketSize);
|
| 811 | UDP_ClearRxFlag(bEndpoint);
|
| 812 |
|
| 813 | // Check if the transfer is finished
|
| 814 | if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
|
| 815 |
|
| 816 | // Disable interrupt if this is not a control endpoint
|
| 817 | if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
|
| 818 |
|
| 819 | UDP->UDP_IDR = 1 << bEndpoint;
|
| 820 | }
|
| 821 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
| 822 | }
|
| 823 | }
|
| 824 | }
|
| 825 |
|
| 826 | // STALL sent
|
| 827 | if ((status & UDP_CSR_STALLSENTISOERROR) != 0) {
|
| 828 |
|
| 829 | CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR);
|
| 830 |
|
| 831 | if ( (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_IN
|
| 832 | || (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_OUT ) {
|
| 833 |
|
| 834 | TRACE_WARNING("Isoe [%d] ", bEndpoint);
|
| 835 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
|
| 836 | }
|
| 837 | else {
|
| 838 |
|
| 839 | TRACE_WARNING("Sta 0x%X [%d] ", (int)status, bEndpoint);
|
| 840 |
|
| 841 | if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
|
| 842 |
|
| 843 | TRACE_WARNING( "_ " );
|
| 844 | // If the endpoint is not halted, clear the STALL condition
|
| 845 | CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
| 846 | }
|
| 847 | }
|
| 848 | }
|
| 849 |
|
| 850 | // SETUP packet received
|
| 851 | if ((status & UDP_CSR_RXSETUP) != 0) {
|
| 852 |
|
| 853 | TRACE_DEBUG_WP("Stp ");
|
| 854 |
|
| 855 | // If a transfer was pending, complete it
|
| 856 | // Handles the case where during the status phase of a control write
|
| 857 | // transfer, the host receives the device ZLP and ack it, but the ack
|
| 858 | // is not received by the device
|
| 859 | if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
| 860 | || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
|
| 861 |
|
| 862 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
| 863 | }
|
| 864 | // Copy the setup packet
|
| 865 | UDP_ReadRequest(&request);
|
| 866 |
|
| 867 | // Set the DIR bit before clearing RXSETUP in Control IN sequence
|
| 868 | if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {
|
| 869 |
|
| 870 | SET_CSR(bEndpoint, UDP_CSR_DIR);
|
| 871 | }
|
| 872 | // Acknowledge setup packet
|
| 873 | CLEAR_CSR(bEndpoint, UDP_CSR_RXSETUP);
|
| 874 |
|
| 875 | // Forward the request to the upper layer
|
| 876 | USBD_RequestHandler(0, &request);
|
| 877 | }
|
| 878 |
|
| 879 | }
|
| 880 |
|
| 881 | /**
|
| 882 | * Sends data through a USB endpoint. Sets up the transfer descriptor,
|
| 883 | * writes one or two data payloads (depending on the number of FIFO bank
|
| 884 | * for the endpoint) and then starts the actual transfer. The operation is
|
| 885 | * complete when all the data has been sent.
|
| 886 | *
|
| 887 | * *If the size of the buffer is greater than the size of the endpoint
|
| 888 | * (or twice the size if the endpoint has two FIFO banks), then the buffer
|
| 889 | * must be kept allocated until the transfer is finished*. This means that
|
| 890 | * it is not possible to declare it on the stack (i.e. as a local variable
|
| 891 | * of a function which returns after starting a transfer).
|
| 892 | *
|
| 893 | * \param pEndpoint Pointer to Endpoint struct.
|
| 894 | * \param pData Pointer to a buffer with the data to send.
|
| 895 | * \param dLength Size of the data buffer.
|
| 896 | * \return USBD_STATUS_SUCCESS if the transfer has been started;
|
| 897 | * otherwise, the corresponding error status code.
|
| 898 | */
|
| 899 | static inline uint8_t UDP_Write(uint8_t bEndpoint,
|
| 900 | const void *pData,
|
| 901 | uint32_t dLength)
|
| 902 | {
|
| 903 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 904 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 905 |
|
| 906 | /* Check that the endpoint is in Idle state */
|
| 907 | if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
| 908 |
|
| 909 | return USBD_STATUS_LOCKED;
|
| 910 | }
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 911 | TRACE_DEBUG_WP("Write%d(%" PRIu32 ") ", bEndpoint, dLength);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 912 |
|
Christina Quast | f51e0d2 | 2015-01-03 21:51:24 +0100 | [diff] [blame] | 913 | /* int i;
|
| 914 | for (i = 0; i < dLength; i++) {
|
| 915 | if (!(i%16)) {
|
| 916 | printf("\n\r");
|
| 917 | }
|
| 918 | printf("0x%x ", ((uint8_t*)pData)[i]);
|
| 919 | }
|
| 920 | printf("\n\r");
|
| 921 | */
|
| 922 |
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 923 | /* Setup the transfer descriptor */
|
| 924 | pTransfer->pData = (void *) pData;
|
| 925 | pTransfer->remaining = dLength;
|
| 926 | pTransfer->buffered = 0;
|
| 927 | pTransfer->transferred = 0;
|
| 928 |
|
| 929 | /* Send the first packet */
|
| 930 | pEndpoint->state = UDP_ENDPOINT_SENDING;
|
| 931 | while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
|
| 932 | UDP_WritePayload(bEndpoint);
|
| 933 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 934 |
|
| 935 | /* If double buffering is enabled and there is data remaining,
|
| 936 | prepare another packet */
|
| 937 | if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) {
|
| 938 |
|
| 939 | UDP_WritePayload(bEndpoint);
|
| 940 | }
|
| 941 |
|
| 942 | /* Enable interrupt on endpoint */
|
| 943 | UDP->UDP_IER = 1 << bEndpoint;
|
| 944 |
|
| 945 | return USBD_STATUS_SUCCESS;
|
| 946 | }
|
| 947 |
|
| 948 | /**
|
| 949 | * Sends data through a USB endpoint. Sets up the transfer descriptor list,
|
| 950 | * writes one or two data payloads (depending on the number of FIFO bank
|
| 951 | * for the endpoint) and then starts the actual transfer. The operation is
|
| 952 | * complete when all the transfer buffer in the list has been sent.
|
| 953 | *
|
| 954 | * *If the size of the buffer is greater than the size of the endpoint
|
| 955 | * (or twice the size if the endpoint has two FIFO banks), then the buffer
|
| 956 | * must be kept allocated until the transfer is finished*. This means that
|
| 957 | * it is not possible to declare it on the stack (i.e. as a local variable
|
| 958 | * of a function which returns after starting a transfer).
|
| 959 | *
|
| 960 | * \param pEndpoint Pointer to Endpoint struct.
|
| 961 | * \param pData Pointer to a buffer with the data to send.
|
| 962 | * \param dLength Size of the data buffer.
|
| 963 | * \return USBD_STATUS_SUCCESS if the transfer has been started;
|
| 964 | * otherwise, the corresponding error status code.
|
| 965 | */
|
| 966 | static inline uint8_t UDP_AddWr(uint8_t bEndpoint,
|
| 967 | const void *pData,
|
| 968 | uint32_t dLength)
|
| 969 | {
|
| 970 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 971 | MblTransfer *pMbl = (MblTransfer*)&(pEndpoint->transfer);
|
| 972 | USBDTransferBuffer *pTx;
|
| 973 |
|
| 974 | /* Check parameter */
|
| 975 | if (dLength >= 0x10000)
|
| 976 | return USBD_STATUS_INVALID_PARAMETER;
|
| 977 |
|
| 978 | /* Data in progressing */
|
| 979 | if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
| 980 | /* If list full */
|
| 981 | if (pMbl->listState == MBL_FULL) {
|
| 982 | return USBD_STATUS_LOCKED;
|
| 983 | }
|
| 984 | }
|
| 985 |
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 986 | TRACE_DEBUG_WP("AddW%d(%" PRIu32 ") ", bEndpoint, dLength);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 987 |
|
| 988 | /* Add buffer to buffer list and update index */
|
| 989 | pTx = &(pMbl->pMbl[pMbl->inCurr]);
|
| 990 | pTx->pBuffer = (uint8_t*)pData;
|
| 991 | pTx->size = pTx->remaining = dLength;
|
| 992 | pTx->transferred = pTx->buffered = 0;
|
| 993 | /* Update input index */
|
| 994 | if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0;
|
| 995 | else pMbl->inCurr ++;
|
| 996 | if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL;
|
| 997 | else pMbl->listState = 0;
|
| 998 | /* Start sending when offset achieved */
|
| 999 | if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize)
|
| 1000 | >= pMbl->offsetSize
|
| 1001 | && pEndpoint->state == UDP_ENDPOINT_IDLE) {
|
| 1002 | TRACE_DEBUG_WP("StartT ");
|
| 1003 | /* Change state */
|
| 1004 | pEndpoint->state = UDP_ENDPOINT_SENDINGM;
|
| 1005 | while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
|
| 1006 | /* Send first packet */
|
| 1007 | UDP_MblWriteFifo(bEndpoint);
|
| 1008 | SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
| 1009 | /* If double buffering is enabled and there is remaining, continue */
|
| 1010 | if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
|
| 1011 | && pMbl->pMbl[pMbl->outCurr].remaining) {
|
| 1012 | UDP_MblWriteFifo(bEndpoint);
|
| 1013 | }
|
| 1014 | /* Enable interrupt on endpoint */
|
| 1015 | UDP->UDP_IER = 1 << bEndpoint;
|
| 1016 | }
|
| 1017 |
|
| 1018 | return USBD_STATUS_SUCCESS;
|
| 1019 | }
|
| 1020 |
|
| 1021 | /**
|
| 1022 | * Reads incoming data on an USB endpoint This methods sets the transfer
|
| 1023 | * descriptor and activate the endpoint interrupt. The actual transfer is
|
| 1024 | * then carried out by the endpoint interrupt handler. The Read operation
|
| 1025 | * finishes either when the buffer is full, or a short packet (inferior to
|
| 1026 | * endpoint maximum size) is received.
|
| 1027 | *
|
| 1028 | * *The buffer must be kept allocated until the transfer is finished*.
|
| 1029 | * \param bEndpoint Endpoint number.
|
| 1030 | * \param pData Pointer to a data buffer.
|
| 1031 | * \param dLength Size of the data buffer in bytes.
|
| 1032 | * \return USBD_STATUS_SUCCESS if the read operation has been started;
|
| 1033 | * otherwise, the corresponding error code.
|
| 1034 | */
|
| 1035 | static inline uint8_t UDP_Read(uint8_t bEndpoint,
|
| 1036 | void *pData,
|
| 1037 | uint32_t dLength)
|
| 1038 | {
|
| 1039 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 1040 | Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
| 1041 |
|
| 1042 | /* Return if the endpoint is not in IDLE state */
|
| 1043 | if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
| 1044 |
|
| 1045 | return USBD_STATUS_LOCKED;
|
| 1046 | }
|
| 1047 |
|
| 1048 | /* Endpoint enters Receiving state */
|
| 1049 | pEndpoint->state = UDP_ENDPOINT_RECEIVING;
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 1050 | TRACE_DEBUG_WP("Read%d(%" PRIu32 ") ", bEndpoint, dLength);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 1051 |
|
Christina Quast | f51e0d2 | 2015-01-03 21:51:24 +0100 | [diff] [blame] | 1052 | /* int i;
|
| 1053 | for (i = 0; i < dLength; i++) {
|
| 1054 | if (!(i%16)) {
|
| 1055 | printf("\n\r");
|
| 1056 | }
|
| 1057 | printf("0x%x ", ((uint8_t*)pData)[i]);
|
| 1058 | }
|
| 1059 | printf("\n\r");
|
| 1060 | */
|
| 1061 |
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 1062 | /* Set the transfer descriptor */
|
| 1063 | pTransfer->pData = pData;
|
| 1064 | pTransfer->remaining = dLength;
|
| 1065 | pTransfer->buffered = 0;
|
| 1066 | pTransfer->transferred = 0;
|
| 1067 |
|
| 1068 | /* Enable interrupt on endpoint */
|
| 1069 | UDP->UDP_IER = 1 << bEndpoint;
|
| 1070 |
|
| 1071 | return USBD_STATUS_SUCCESS;
|
| 1072 | }
|
| 1073 |
|
| 1074 |
|
| 1075 | /*---------------------------------------------------------------------------
|
| 1076 | * Exported functions
|
| 1077 | *---------------------------------------------------------------------------*/
|
| 1078 |
|
| 1079 | /**
|
| 1080 | * USBD (UDP) interrupt handler
|
| 1081 | * Manages device resume, suspend, end of bus reset.
|
| 1082 | * Forwards endpoint events to the appropriate handler.
|
| 1083 | */
|
| 1084 | void USBD_IrqHandler(void)
|
| 1085 | {
|
| 1086 | uint32_t status;
|
| 1087 | int32_t eptnum = 0;
|
| 1088 |
|
| 1089 | /* Enable peripheral ? */
|
| 1090 | //UDP_EnablePeripheralClock();
|
| 1091 |
|
| 1092 | /* Get interrupt status
|
| 1093 | Some interrupts may get masked depending on the device state */
|
| 1094 | status = UDP->UDP_ISR;
|
| 1095 | status &= UDP->UDP_IMR;
|
Christina Quast | f51e0d2 | 2015-01-03 21:51:24 +0100 | [diff] [blame] | 1096 |
|
Christina Quast | 23c0013 | 2015-01-27 15:17:37 +0100 | [diff] [blame] | 1097 | TRACE_DEBUG("status; 0x%" PRIx32 , status);
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 1098 |
|
| 1099 | if (USBD_GetState() < USBD_STATE_POWERED) {
|
| 1100 |
|
| 1101 | status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM;
|
| 1102 | UDP->UDP_ICR = ~status;
|
| 1103 | }
|
| 1104 |
|
| 1105 | /* Return immediately if there is no interrupt to service */
|
| 1106 | if (status == 0) {
|
| 1107 |
|
| 1108 | TRACE_DEBUG_WP(".\n\r");
|
| 1109 | return;
|
| 1110 | }
|
| 1111 |
|
| 1112 | /* Toggle USB LED if the device is active */
|
| 1113 | if (USBD_GetState() >= USBD_STATE_POWERED) {
|
| 1114 |
|
| 1115 | //LED_Set(USBD_LEDUSB);
|
| 1116 | }
|
| 1117 |
|
| 1118 | /* Service interrupts */
|
| 1119 |
|
| 1120 | /** / Start Of Frame (SOF) */
|
| 1121 | //if (ISSET(dStatus, UDP_ISR_SOFINT)) {
|
| 1122 | //
|
| 1123 | // TRACE_DEBUG("SOF");
|
| 1124 | //
|
| 1125 | // // Invoke the SOF callback
|
| 1126 | // USB_StartOfFrameCallback(pUsb);
|
| 1127 | //
|
| 1128 | // // Acknowledge interrupt
|
| 1129 | // UDP->UDP_ICR = UDP_ICR_SOFINT;
|
| 1130 | // dStatus &= ~UDP_ISR_SOFINT;
|
| 1131 | //}
|
| 1132 | /* Resume (Wakeup) */
|
| 1133 | if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) {
|
| 1134 |
|
| 1135 | TRACE_INFO_WP("Res ");
|
| 1136 | /* Clear and disable resume interrupts */
|
| 1137 | UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
|
| 1138 | UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM;
|
| 1139 | /* Do resome operations */
|
| 1140 | USBD_ResumeHandler();
|
| 1141 | }
|
| 1142 |
|
| 1143 | /* Suspend
|
| 1144 | This interrupt is always treated last (hence the '==') */
|
| 1145 | if (status == UDP_ISR_RXSUSP) {
|
| 1146 |
|
| 1147 | TRACE_INFO_WP("Susp ");
|
| 1148 | /* Enable wakeup */
|
| 1149 | UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM;
|
| 1150 | /* Acknowledge interrupt */
|
| 1151 | UDP->UDP_ICR = UDP_ICR_RXSUSP;
|
| 1152 | /* Do suspend operations */
|
| 1153 | USBD_SuspendHandler();
|
| 1154 | }
|
| 1155 | /* End of bus reset */
|
| 1156 | else if ((status & UDP_ISR_ENDBUSRES) != 0) {
|
| 1157 |
|
| 1158 | TRACE_INFO_WP("EoBRes ");
|
| 1159 | /* Flush and enable the Suspend interrupt */
|
| 1160 | UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
|
| 1161 | UDP->UDP_IER = UDP_IER_RXSUSP;
|
| 1162 |
|
| 1163 | /* Do RESET operations */
|
| 1164 | USBD_ResetHandler();
|
| 1165 |
|
| 1166 | /* Acknowledge end of bus reset interrupt */
|
| 1167 | UDP->UDP_ICR = UDP_ICR_ENDBUSRES;
|
| 1168 | }
|
| 1169 | /* Endpoint interrupts */
|
| 1170 | else {
|
| 1171 |
|
| 1172 | status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1);
|
| 1173 | while (status != 0) {
|
| 1174 |
|
| 1175 | /* Check if endpoint has a pending interrupt */
|
| 1176 | if ((status & (1 << eptnum)) != 0) {
|
| 1177 |
|
| 1178 | UDP_EndpointHandler(eptnum);
|
| 1179 | status &= ~(1 << eptnum);
|
| 1180 |
|
| 1181 | if (status != 0) {
|
| 1182 |
|
| 1183 | TRACE_INFO_WP("\n\r - ");
|
| 1184 | }
|
| 1185 | }
|
| 1186 | eptnum++;
|
| 1187 | }
|
| 1188 | }
|
| 1189 |
|
| 1190 | /* Toggle LED back to its previous state */
|
| 1191 | TRACE_DEBUG_WP("!");
|
| 1192 | TRACE_INFO_WP("\n\r");
|
| 1193 | if (USBD_GetState() >= USBD_STATE_POWERED) {
|
| 1194 |
|
| 1195 | //LED_Clear(USBD_LEDUSB);
|
| 1196 | }
|
| 1197 | }
|
| 1198 |
|
| 1199 | /**
|
| 1200 | * \brief Reset endpoints and disable them.
|
| 1201 | * -# Terminate transfer if there is any, with given status;
|
| 1202 | * -# Reset the endpoint & disable it.
|
| 1203 | * \param bmEPs Bitmap for endpoints to reset.
|
| 1204 | * \param bStatus Status passed to terminate transfer on endpoint.
|
| 1205 | * \param bKeepCfg 1 to keep old endpoint configuration.
|
| 1206 | * \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint
|
| 1207 | if not keeping old configuration.
|
| 1208 | * \sa USBD_HAL_ConfigureEP().
|
| 1209 | */
|
| 1210 | void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg)
|
| 1211 | {
|
| 1212 | Endpoint *pEndpoint;
|
| 1213 | uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
|
| 1214 | uint8_t ep;
|
| 1215 | uint32_t epBit, epCfg;
|
| 1216 | for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
|
| 1217 | if (tmp & epBit) {
|
| 1218 |
|
| 1219 | /* Disable ISR */
|
| 1220 | UDP->UDP_IDR = epBit;
|
| 1221 | /* Kill pending TXPKTREADY */
|
| 1222 | CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
|
| 1223 |
|
| 1224 | /* Reset transfer information */
|
| 1225 | pEndpoint = &(endpoints[ep]);
|
| 1226 | /* Reset endpoint state */
|
| 1227 | pEndpoint->bank = 0;
|
| 1228 | /* Endpoint configure */
|
| 1229 | epCfg = UDP->UDP_CSR[ep];
|
| 1230 | /* Reset endpoint */
|
| 1231 | UDP->UDP_RST_EP |= epBit;
|
| 1232 | UDP->UDP_RST_EP &= ~epBit;
|
| 1233 | /* Restore configure */
|
| 1234 | if (bKeepCfg) {
|
| 1235 | //SET_CSR(ep, pEndpoint->CSR);
|
| 1236 | SET_CSR(ep, epCfg);
|
| 1237 | }
|
| 1238 | else {
|
| 1239 | //pEndpoint->CSR = 0;
|
| 1240 | pEndpoint->state = UDP_ENDPOINT_DISABLED;
|
| 1241 | }
|
| 1242 |
|
| 1243 | /* Terminate transfer on this EP */
|
| 1244 | UDP_EndOfTransfer(ep, bStatus);
|
| 1245 | }
|
| 1246 | epBit <<= 1;
|
| 1247 | }
|
| 1248 | /* Reset EPs */
|
| 1249 | // UDP->UDP_RST_EP |= bmEPs;
|
| 1250 | // UDP->UDP_RST_EP &= ~bmEPs;
|
| 1251 | }
|
| 1252 |
|
| 1253 | /**
|
| 1254 | * Cancel pending READ/WRITE
|
| 1255 | * \param bmEPs Bitmap for endpoints to reset.
|
| 1256 | * \note EP callback is invoked with USBD_STATUS_CANCELED.
|
| 1257 | */
|
| 1258 | void USBD_HAL_CancelIo(uint32_t bmEPs)
|
| 1259 | {
|
| 1260 | uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
|
| 1261 | uint8_t ep;
|
| 1262 | uint32_t epBit;
|
| 1263 | for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
|
| 1264 | if (tmp & epBit) {
|
| 1265 |
|
| 1266 | /* Disable ISR */
|
| 1267 | UDP->UDP_IDR = epBit;
|
| 1268 | /* Kill pending TXPKTREADY */
|
| 1269 | CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
|
| 1270 |
|
| 1271 | /* Terminate transfer on this EP */
|
| 1272 | UDP_EndOfTransfer(ep, USBD_STATUS_CANCELED);
|
| 1273 | }
|
| 1274 | epBit <<= 1;
|
| 1275 | }
|
| 1276 | }
|
| 1277 |
|
| 1278 | /**
|
| 1279 | * Configures an endpoint according to its endpoint Descriptor.
|
| 1280 | * \param pDescriptor Pointer to an endpoint descriptor.
|
| 1281 | */
|
| 1282 | uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
|
| 1283 | {
|
| 1284 | Endpoint *pEndpoint;
|
| 1285 | uint8_t bEndpoint;
|
| 1286 | uint8_t bType;
|
| 1287 | uint8_t bEndpointDir;
|
| 1288 |
|
| 1289 | /* NULL descriptor -> Control endpoint 0 in default */
|
| 1290 | if (pDescriptor == 0) {
|
| 1291 | bEndpoint = 0;
|
| 1292 | pEndpoint = &(endpoints[bEndpoint]);
|
| 1293 | bType= USBEndpointDescriptor_CONTROL;
|
| 1294 | bEndpointDir = 0;
|
| 1295 | pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
|
| 1296 | }
|
| 1297 | /* Device descriptor -> Specific Control EP */
|
| 1298 | else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE) {
|
| 1299 | bEndpoint = 0;
|
| 1300 | pEndpoint = &(endpoints[bEndpoint]);
|
| 1301 | bType = USBEndpointDescriptor_CONTROL;
|
| 1302 | bEndpointDir = 0;
|
| 1303 | pEndpoint->size = ((USBDeviceDescriptor *)pDescriptor)->bMaxPacketSize0;
|
| 1304 | }
|
| 1305 | /* Not endpoint descriptor, ERROR! */
|
| 1306 | else if (pDescriptor->bDescriptorType != USBGenericDescriptor_ENDPOINT) {
|
| 1307 | return 0xFF;
|
| 1308 | }
|
| 1309 | else {
|
| 1310 | bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
|
| 1311 | pEndpoint = &(endpoints[bEndpoint]);
|
| 1312 | bType = USBEndpointDescriptor_GetType(pDescriptor);
|
| 1313 | bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
|
| 1314 | pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
|
| 1315 | }
|
| 1316 |
|
| 1317 | /* Abort the current transfer is the endpoint was configured and in
|
| 1318 | Write or Read state */
|
| 1319 | if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
| 1320 | || (pEndpoint->state == UDP_ENDPOINT_SENDING)
|
| 1321 | || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
|
| 1322 | || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) {
|
| 1323 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
|
| 1324 | }
|
| 1325 | pEndpoint->state = UDP_ENDPOINT_IDLE;
|
| 1326 |
|
| 1327 | /* Reset Endpoint Fifos */
|
| 1328 | UDP->UDP_RST_EP |= (1 << bEndpoint);
|
| 1329 | UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
| 1330 |
|
| 1331 | /* Configure endpoint */
|
| 1332 | SET_CSR(bEndpoint, (uint32_t)UDP_CSR_EPEDS
|
| 1333 | | (bType << 8) | (bEndpointDir << 10));
|
| 1334 | if (bType != USBEndpointDescriptor_CONTROL) {
|
| 1335 |
|
| 1336 | }
|
| 1337 | else {
|
| 1338 |
|
| 1339 | UDP->UDP_IER = (1 << bEndpoint);
|
| 1340 | }
|
| 1341 |
|
| 1342 | TRACE_INFO_WP("CfgEp%d ", bEndpoint);
|
| 1343 | return bEndpoint;
|
| 1344 | }
|
| 1345 |
|
| 1346 | /**
|
| 1347 | * Set callback for a USB endpoint for transfer (read/write).
|
| 1348 | *
|
| 1349 | * \param bEP Endpoint number.
|
| 1350 | * \param fCallback Optional callback function to invoke when the transfer is
|
| 1351 | * complete.
|
| 1352 | * \param pCbData Optional pointer to data to the callback function.
|
| 1353 | * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy.
|
| 1354 | */
|
| 1355 | uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP,
|
| 1356 | TransferCallback fCallback,
|
| 1357 | void *pCbData)
|
| 1358 | {
|
| 1359 | Endpoint *pEndpoint = &(endpoints[bEP]);
|
| 1360 | TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer);
|
| 1361 | /* Check that the endpoint is not transferring */
|
| 1362 | if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
| 1363 | return USBD_STATUS_LOCKED;
|
| 1364 | }
|
| 1365 | TRACE_DEBUG_WP("sXfrCb ");
|
| 1366 | /* Setup the transfer callback and extension data */
|
| 1367 | pTransfer->fCallback = (void*)fCallback;
|
| 1368 | pTransfer->pArgument = pCbData;
|
| 1369 | return USBD_STATUS_SUCCESS;
|
| 1370 | }
|
| 1371 |
|
| 1372 | /**
|
| 1373 | * Configure an endpoint to use multi-buffer-list transfer mode.
|
| 1374 | * The buffers can be added by _Read/_Write function.
|
| 1375 | * \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL.
|
| 1376 | * \param mblSize Multi-buffer list size (number of buffers can be queued)
|
| 1377 | * \param startOffset When number of buffer achieve this offset transfer start
|
| 1378 | */
|
| 1379 | uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint,
|
| 1380 | USBDTransferBuffer* pMbList,
|
| 1381 | uint16_t mblSize,
|
| 1382 | uint16_t startOffset)
|
| 1383 | {
|
| 1384 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 1385 | MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer);
|
| 1386 | uint16_t i;
|
| 1387 | /* Check that the endpoint is not transferring */
|
| 1388 | if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
| 1389 | return USBD_STATUS_LOCKED;
|
| 1390 | }
|
| 1391 | TRACE_DEBUG_WP("sMblXfr ");
|
| 1392 | /* Enable Multi-Buffer Transfer List */
|
| 1393 | if (pMbList) {
|
| 1394 | /* Reset list items */
|
| 1395 | for (i = 0; i < mblSize; i --) {
|
| 1396 | pMbList[i].pBuffer = NULL;
|
| 1397 | pMbList[i].size = 0;
|
| 1398 | pMbList[i].transferred = 0;
|
| 1399 | pMbList[i].buffered = 0;
|
| 1400 | pMbList[i].remaining = 0;
|
| 1401 | }
|
| 1402 | /* Setup transfer */
|
| 1403 | pXfr->transType = 1;
|
| 1404 | pXfr->listState = 0; /* OK */
|
| 1405 | pXfr->listSize = mblSize;
|
| 1406 | pXfr->pMbl = pMbList;
|
| 1407 | pXfr->outCurr = pXfr->outLast = 0;
|
| 1408 | pXfr->inCurr = 0;
|
| 1409 | pXfr->offsetSize = startOffset;
|
| 1410 | }
|
| 1411 | /* Disable Multi-Buffer Transfer */
|
| 1412 | else {
|
| 1413 | pXfr->transType = 0;
|
| 1414 | pXfr->pMbl = NULL;
|
| 1415 | pXfr->listSize = 0;
|
| 1416 | pXfr->offsetSize = 1;
|
| 1417 | }
|
| 1418 | return USBD_STATUS_SUCCESS;
|
| 1419 | }
|
| 1420 |
|
| 1421 | /**
|
| 1422 | * Sends data through a USB endpoint. Sets up the transfer descriptor,
|
| 1423 | * writes one or two data payloads (depending on the number of FIFO bank
|
| 1424 | * for the endpoint) and then starts the actual transfer. The operation is
|
| 1425 | * complete when all the data has been sent.
|
| 1426 | *
|
| 1427 | * *If the size of the buffer is greater than the size of the endpoint
|
| 1428 | * (or twice the size if the endpoint has two FIFO banks), then the buffer
|
| 1429 | * must be kept allocated until the transfer is finished*. This means that
|
| 1430 | * it is not possible to declare it on the stack (i.e. as a local variable
|
| 1431 | * of a function which returns after starting a transfer).
|
| 1432 | *
|
| 1433 | * \param bEndpoint Endpoint number.
|
| 1434 | * \param pData Pointer to a buffer with the data to send.
|
| 1435 | * \param dLength Size of the data buffer.
|
| 1436 | * \return USBD_STATUS_SUCCESS if the transfer has been started;
|
| 1437 | * otherwise, the corresponding error status code.
|
| 1438 | */
|
| 1439 | uint8_t USBD_HAL_Write( uint8_t bEndpoint,
|
| 1440 | const void *pData,
|
| 1441 | uint32_t dLength)
|
| 1442 | {
|
| 1443 | if (endpoints[bEndpoint].transfer.transHdr.transType)
|
| 1444 | return UDP_AddWr(bEndpoint, pData, dLength);
|
| 1445 | else
|
| 1446 | return UDP_Write(bEndpoint, pData, dLength);
|
| 1447 | }
|
| 1448 |
|
| 1449 | /**
|
| 1450 | * Reads incoming data on an USB endpoint This methods sets the transfer
|
| 1451 | * descriptor and activate the endpoint interrupt. The actual transfer is
|
| 1452 | * then carried out by the endpoint interrupt handler. The Read operation
|
| 1453 | * finishes either when the buffer is full, or a short packet (inferior to
|
| 1454 | * endpoint maximum size) is received.
|
| 1455 | *
|
| 1456 | * *The buffer must be kept allocated until the transfer is finished*.
|
| 1457 | * \param bEndpoint Endpoint number.
|
| 1458 | * \param pData Pointer to a data buffer.
|
| 1459 | * \param dLength Size of the data buffer in bytes.
|
| 1460 | * \return USBD_STATUS_SUCCESS if the read operation has been started;
|
| 1461 | * otherwise, the corresponding error code.
|
| 1462 | */
|
| 1463 | uint8_t USBD_HAL_Read(uint8_t bEndpoint,
|
| 1464 | void *pData,
|
| 1465 | uint32_t dLength)
|
| 1466 | {
|
| 1467 | if (endpoints[bEndpoint].transfer.transHdr.transType)
|
| 1468 | return USBD_STATUS_SW_NOT_SUPPORTED;
|
| 1469 | else
|
| 1470 | return UDP_Read(bEndpoint, pData, dLength);
|
| 1471 | }
|
| 1472 |
|
| 1473 | /**
|
| 1474 | * \brief Enable Pull-up, connect.
|
| 1475 | *
|
| 1476 | * -# Enable HW access if needed
|
| 1477 | * -# Enable Pull-Up
|
| 1478 | * -# Disable HW access if needed
|
| 1479 | */
|
| 1480 | void USBD_HAL_Connect(void)
|
| 1481 | {
|
| 1482 | uint8_t dis = UDP_EnablePeripheralClock();
|
| 1483 | UDP->UDP_TXVC |= UDP_TXVC_PUON;
|
| 1484 | if (dis) UDP_DisablePeripheralClock();
|
| 1485 | }
|
| 1486 |
|
| 1487 | /**
|
| 1488 | * \brief Disable Pull-up, disconnect.
|
| 1489 | *
|
| 1490 | * -# Enable HW access if needed
|
| 1491 | * -# Disable PULL-Up
|
| 1492 | * -# Disable HW access if needed
|
| 1493 | */
|
| 1494 | void USBD_HAL_Disconnect(void)
|
| 1495 | {
|
| 1496 | uint8_t dis = UDP_EnablePeripheralClock();
|
| 1497 | UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
|
| 1498 | if (dis) UDP_DisablePeripheralClock();
|
| 1499 | }
|
| 1500 |
|
| 1501 | /**
|
| 1502 | * Starts a remote wake-up procedure.
|
| 1503 | */
|
| 1504 | void USBD_HAL_RemoteWakeUp(void)
|
| 1505 | {
|
| 1506 | UDP_EnablePeripheralClock();
|
| 1507 | UDP_EnableUsbClock();
|
| 1508 | UDP_EnableTransceiver();
|
| 1509 |
|
| 1510 | TRACE_INFO_WP("RWUp ");
|
| 1511 |
|
| 1512 | // Activates a remote wakeup (edge on ESR), then clear ESR
|
| 1513 | UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR;
|
| 1514 | UDP->UDP_GLB_STAT &= ~(uint32_t)UDP_GLB_STAT_ESR;
|
| 1515 | }
|
| 1516 |
|
| 1517 | /**
|
| 1518 | * Sets the device address to the given value.
|
| 1519 | * \param address New device address.
|
| 1520 | */
|
| 1521 | void USBD_HAL_SetAddress(uint8_t address)
|
| 1522 | {
|
| 1523 | /* Set address */
|
| 1524 | UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk);
|
| 1525 | /* If the address is 0, the device returns to the Default state */
|
| 1526 | if (address == 0) UDP->UDP_GLB_STAT = 0;
|
| 1527 | /* If the address is non-zero, the device enters the Address state */
|
| 1528 | else UDP->UDP_GLB_STAT = UDP_GLB_STAT_FADDEN;
|
| 1529 | }
|
| 1530 |
|
| 1531 | /**
|
| 1532 | * Sets the current device configuration.
|
| 1533 | * \param cfgnum - Configuration number to set.
|
| 1534 | */
|
| 1535 | void USBD_HAL_SetConfiguration(uint8_t cfgnum)
|
| 1536 | {
|
| 1537 | /* If the configuration number if non-zero, the device enters the
|
| 1538 | Configured state */
|
| 1539 | if (cfgnum != 0) UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG;
|
| 1540 | /* If the configuration number is zero, the device goes back to the Address
|
| 1541 | state */
|
| 1542 | else {
|
| 1543 | UDP->UDP_GLB_STAT = UDP_FADDR_FEN;
|
| 1544 | }
|
| 1545 | }
|
| 1546 |
|
| 1547 | /**
|
| 1548 | * Initializes the USB HW Access driver.
|
| 1549 | */
|
| 1550 | void USBD_HAL_Init(void)
|
| 1551 | {
|
Christina Quast | f51e0d2 | 2015-01-03 21:51:24 +0100 | [diff] [blame] | 1552 | TRACE_DEBUG("%s\n\r", "USBD_HAL_Init");
|
| 1553 |
|
Christina Quast | 8be71e4 | 2014-12-02 13:06:01 +0100 | [diff] [blame] | 1554 | /* Must before USB & TXVC access! */
|
| 1555 | UDP_EnablePeripheralClock();
|
| 1556 |
|
| 1557 | /* Reset & disable endpoints */
|
| 1558 | USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
|
| 1559 |
|
| 1560 | /* Configure the pull-up on D+ and disconnect it */
|
| 1561 | UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
|
| 1562 |
|
| 1563 | UDP_EnableUsbClock();
|
| 1564 |
|
| 1565 | UDP->UDP_IDR = 0xFE;
|
| 1566 | UDP->UDP_IER = UDP_IER_WAKEUP;
|
| 1567 | }
|
| 1568 |
|
| 1569 | /**
|
| 1570 | * Causes the given endpoint to acknowledge the next packet it receives
|
| 1571 | * with a STALL handshake except setup request.
|
| 1572 | * \param bEP Endpoint number.
|
| 1573 | * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
|
| 1574 | */
|
| 1575 | uint8_t USBD_HAL_Stall(uint8_t bEP)
|
| 1576 | {
|
| 1577 | Endpoint *pEndpoint = &(endpoints[bEP]);
|
| 1578 |
|
| 1579 | /* Check that endpoint is in Idle state */
|
| 1580 | if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
| 1581 | TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP);
|
| 1582 | return USBD_STATUS_LOCKED;
|
| 1583 | }
|
| 1584 | /* STALL endpoint */
|
| 1585 | SET_CSR(bEP, UDP_CSR_FORCESTALL);
|
| 1586 | TRACE_DEBUG_WP("Stall%d ", bEP);
|
| 1587 | return USBD_STATUS_SUCCESS;
|
| 1588 | }
|
| 1589 |
|
| 1590 | /**
|
| 1591 | * Sets/Clear/Get the HALT state on the endpoint.
|
| 1592 | * In HALT state, the endpoint should keep stalling any packet.
|
| 1593 | * \param bEndpoint Endpoint number.
|
| 1594 | * \param ctl Control code CLR/HALT/READ.
|
| 1595 | * 0: Clear HALT state;
|
| 1596 | * 1: Set HALT state;
|
| 1597 | * .: Return HALT status.
|
| 1598 | * \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist,
|
| 1599 | * otherwise endpoint halt status.
|
| 1600 | */
|
| 1601 | uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
|
| 1602 | {
|
| 1603 | Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
| 1604 | uint8_t status = 0;
|
| 1605 |
|
| 1606 | /* SET Halt */
|
| 1607 | if (ctl == 1) {
|
| 1608 | /* Check that endpoint is enabled and not already in Halt state */
|
| 1609 | if ((pEndpoint->state != UDP_ENDPOINT_DISABLED)
|
| 1610 | && (pEndpoint->state != UDP_ENDPOINT_HALTED)) {
|
| 1611 |
|
| 1612 | TRACE_DEBUG_WP("Halt%d ", bEndpoint);
|
| 1613 |
|
| 1614 | /* Abort the current transfer if necessary */
|
| 1615 | UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
|
| 1616 |
|
| 1617 | /* Put endpoint into Halt state */
|
| 1618 | SET_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
| 1619 | pEndpoint->state = UDP_ENDPOINT_HALTED;
|
| 1620 |
|
| 1621 | /* Enable the endpoint interrupt */
|
| 1622 | UDP->UDP_IER = 1 << bEndpoint;
|
| 1623 | }
|
| 1624 | }
|
| 1625 | /* CLEAR Halt */
|
| 1626 | else if (ctl == 0) {
|
| 1627 | /* Check if the endpoint is halted */
|
| 1628 | //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
|
| 1629 | if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
|
| 1630 |
|
| 1631 | TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
|
| 1632 |
|
| 1633 | /* Return endpoint to Idle state */
|
| 1634 | pEndpoint->state = UDP_ENDPOINT_IDLE;
|
| 1635 |
|
| 1636 | /* Clear FORCESTALL flag */
|
| 1637 | CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
| 1638 |
|
| 1639 | /* Reset Endpoint Fifos, beware this is a 2 steps operation */
|
| 1640 | UDP->UDP_RST_EP |= 1 << bEndpoint;
|
| 1641 | UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
| 1642 | }
|
| 1643 | }
|
| 1644 |
|
| 1645 | /* Return Halt status */
|
| 1646 | if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
|
| 1647 | status = 1;
|
| 1648 | }
|
| 1649 | return( status );
|
| 1650 | }
|
| 1651 |
|
| 1652 | /**
|
| 1653 | * Indicates if the device is running in high or full-speed. Always returns 0
|
| 1654 | * since UDP does not support high-speed mode.
|
| 1655 | */
|
| 1656 | uint8_t USBD_HAL_IsHighSpeed(void)
|
| 1657 | {
|
| 1658 | return 0;
|
| 1659 | }
|
| 1660 |
|
| 1661 | /**
|
| 1662 | * Suspend USB Device HW Interface
|
| 1663 | *
|
| 1664 | * -# Disable transceiver
|
| 1665 | * -# Disable USB Clock
|
| 1666 | * -# Disable USB Peripheral
|
| 1667 | */
|
| 1668 | void USBD_HAL_Suspend(void)
|
| 1669 | {
|
| 1670 | /* The device enters the Suspended state */
|
| 1671 | UDP_DisableTransceiver();
|
| 1672 | UDP_DisableUsbClock();
|
| 1673 | UDP_DisablePeripheralClock();
|
| 1674 | }
|
| 1675 |
|
| 1676 | /**
|
| 1677 | * Activate USB Device HW Interface
|
| 1678 | * -# Enable USB Peripheral
|
| 1679 | * -# Enable USB Clock
|
| 1680 | * -# Enable transceiver
|
| 1681 | */
|
| 1682 | void USBD_HAL_Activate(void)
|
| 1683 | {
|
| 1684 | UDP_EnablePeripheralClock();
|
| 1685 | UDP_EnableUsbClock();
|
| 1686 | UDP_EnableTransceiver();
|
| 1687 | }
|
| 1688 |
|
| 1689 | /**@}*/
|
| 1690 |
|