1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2011, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
34 Implementation of USB device functions on a UDP controller.
\r
36 See \ref usbd_api_method USBD API Methods.
\r
39 /** \addtogroup usbd_hal
\r
42 /*---------------------------------------------------------------------------
\r
44 *---------------------------------------------------------------------------*/
\r
47 #include "USBD_HAL.h"
\r
49 #include <stdbool.h>
\r
54 /*---------------------------------------------------------------------------
\r
56 *---------------------------------------------------------------------------*/
\r
60 /** Maximum number of endpoints interrupts. */
\r
61 #define NUM_IT_MAX \
\r
62 ((UDPHS->UDPHS_IPFEATURES & UDPHS_IPFEATURES_EPT_NBR_MAX_Msk) ? \
\r
63 (UDPHS->UDPHS_IPFEATURES & UDPHS_IPFEATURES_EPT_NBR_MAX_Msk) : 16)
\r
64 /** Maximum number of endpoint DMA interrupts */
\r
65 #define NUM_IT_MAX_DMA \
\r
66 ((UDPHS->UDPHS_IPFEATURES \
\r
67 & UDPHS_IPFEATURES_DMA_CHANNEL_NBR_Msk) \
\r
68 >>UDPHS_IPFEATURES_DMA_CHANNEL_NBR_Pos)
\r
69 /** Bits that should be shifted to access DMA control bits. */
\r
70 #define SHIFT_DMA 24
\r
71 /** Bits that should be shifted to access interrupt bits. */
\r
72 #define SHIFT_INTERUPT 8
\r
74 /** Max size of the FMA FIFO */
\r
75 #define DMA_MAX_FIFO_SIZE (65536/1)
\r
76 /** fifo space size in DW */
\r
77 #define EPT_VIRTUAL_SIZE 16384
\r
80 * \section endpoint_states_sec "UDP Endpoint states"
\r
82 * This page lists the endpoint states.
\r
84 * \subsection States
\r
85 * - UDPHS_ENDPOINT_DISABLED
\r
86 * - UDPHS_ENDPOINT_HALTED
\r
87 * - UDPHS_ENDPOINT_IDLE
\r
88 * - UDPHS_ENDPOINT_SENDING
\r
89 * - UDPHS_ENDPOINT_RECEIVING
\r
90 * - UDPHS_ENDPOINT_SENDINGM
\r
91 * - UDPHS_ENDPOINT_RECEIVINGM
\r
94 /** Endpoint states: Endpoint is disabled */
\r
95 #define UDPHS_ENDPOINT_DISABLED 0
\r
96 /** Endpoint states: Endpoint is halted (i.e. STALLs every request) */
\r
97 #define UDPHS_ENDPOINT_HALTED 1
\r
98 /** Endpoint states: Endpoint is idle (i.e. ready for transmission) */
\r
99 #define UDPHS_ENDPOINT_IDLE 2
\r
100 /** Endpoint states: Endpoint is sending data */
\r
101 #define UDPHS_ENDPOINT_SENDING 3
\r
102 /** Endpoint states: Endpoint is receiving data */
\r
103 #define UDPHS_ENDPOINT_RECEIVING 4
\r
104 /** Endpoint states: Endpoint is sending MBL */
\r
105 #define UDPHS_ENDPOINT_SENDINGM 5
\r
106 /** Endpoint states: Endpoint is receiving MBL */
\r
107 #define UDPHS_ENDPOINT_RECEIVINGM 6
\r
109 /** Get Number of buffer in Multi-Buffer-List
\r
110 * \param i input index
\r
111 * \param o output index
\r
112 * \param size list size
\r
114 #define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o)))
\r
116 /** Buffer list is full */
\r
118 /** Buffer list is null */
\r
121 /*---------------------------------------------------------------------------
\r
123 *---------------------------------------------------------------------------*/
\r
125 /** Describes header for UDP endpoint transfer. */
\r
127 /** Optional callback to invoke when the transfer completes. */
\r
129 /** Optional argument to the callback function. */
\r
131 /** Transfer type */
\r
133 /* Reserved to 32-b aligned */
\r
134 uint8_t reserved[3];
\r
137 /** Describes a transfer on a UDP endpoint. */
\r
140 /** Optional callback to invoke when the transfer completes. */
\r
141 TransferCallback fCallback;
\r
142 /** Optional argument to the callback function. */
\r
144 /** Transfer type */
\r
146 uint8_t reserved[3];
\r
147 /** Number of bytes which have been written into the UDP internal FIFO
\r
150 /** Pointer to a data buffer used for emission/reception. */
\r
152 /** Number of bytes which have been sent/received. */
\r
153 int32_t transferred;
\r
154 /** Number of bytes which have not been buffered/transferred yet. */
\r
158 /** Describes Multi Buffer List transfer on a UDP endpoint. */
\r
160 /** Optional callback to invoke when the transfer completes. */
\r
161 MblTransferCallback fCallback;
\r
162 /** Optional argument to the callback function. */
\r
164 /** Transfer type */
\r
166 /** List state (OK, FULL, NULL) (run time) */
\r
168 /** Multi-Buffer List size */
\r
170 /** Pointer to multi-buffer list */
\r
171 USBDTransferBuffer *pMbl;
\r
172 /** Offset number of buffers to start transfer */
\r
173 uint16_t offsetSize;
\r
174 /** Current processing buffer index (run time) */
\r
176 /** Loast loaded buffer index (run time) */
\r
178 /** Current buffer for input (run time) */
\r
183 * Describes the state of an endpoint of the UDP controller.
\r
188 /** Current endpoint state. */
\r
189 volatile uint8_t state;
\r
190 /** Current reception bank (0 or 1). */
\r
191 volatile uint8_t bank;
\r
192 /** Maximum packet size for the endpoint. */
\r
193 volatile uint16_t size;
\r
194 /** Describes an ongoing transfer (if current state is either
\r
195 * UDPHS_ENDPOINT_SENDING or UDPHS_ENDPOINT_RECEIVING) */
\r
197 TransferHeader transHdr;
\r
198 Transfer singleTransfer;
\r
199 MblTransfer mblTransfer;
\r
201 /** Special case for send a ZLP */
\r
213 } UdphsDmaDescriptor;
\r
215 /*---------------------------------------------------------------------------
\r
216 * Internal variables
\r
217 *---------------------------------------------------------------------------*/
\r
219 /** Holds the internal state for each endpoint of the UDP. */
\r
220 static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
\r
222 /** 7.1.20 Test Mode Support
\r
223 * Test codes for the USB HS test mode. */
\r
224 static const char test_packet_buffer[] = {
\r
225 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9
\r
226 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8
\r
227 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8
\r
228 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8
\r
229 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8
\r
230 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK
\r
233 /** Force FS mode */
\r
234 static const uint8_t forceUsbFS = 0;
\r
236 /** DMA link list */
\r
237 static UdphsDmaDescriptor dmaLL[5];
\r
238 static UdphsDmaDescriptor *pDmaLL;
\r
240 /*---------------------------------------------------------------------------
\r
241 * Internal Functions
\r
242 *---------------------------------------------------------------------------*/
\r
245 * Enables the clock of the UDP peripheral.
\r
246 * \return 1 if peripheral status changed.
\r
248 static uint8_t UDPHS_EnablePeripheralClock(void)
\r
250 if (!PMC_IsPeriphEnabled(ID_UDPHS)) {
\r
251 PMC_EnablePeripheral(ID_UDPHS);
\r
258 * Disables the UDP peripheral clock.
\r
260 static inline void UDPHS_DisablePeripheralClock(void)
\r
262 PMC_DisablePeripheral(ID_UDPHS);
\r
266 * Enables the 480MHz USB clock.
\r
268 static inline void UDPHS_EnableUsbClock(void)
\r
271 /* Enable 480Mhz UPLL */
\r
272 pPmc->CKGR_UCKR |= CKGR_UCKR_UPLLEN
\r
273 | CKGR_UCKR_UPLLCOUNT(0x3)
\r
274 | CKGR_UCKR_BIASCOUNT(0x1);
\r
275 /* Wait until UPLL is locked */
\r
276 while((pPmc->PMC_SR & PMC_SR_LOCKU) == 0);
\r
280 * Disables the 480MHz USB clock.
\r
282 static inline void UDPHS_DisableUsbClock(void)
\r
285 /* Disable System Clock */
\r
286 //pPmc->PMC_SCDR = PMC_SCDR_UDP;
\r
287 pPmc->CKGR_UCKR &= ~(uint32_t)CKGR_UCKR_UPLLEN;
\r
291 * Enables the BIAS.
\r
293 static inline void UDPHS_EnableBIAS(void)
\r
296 pPmc->CKGR_UCKR |= CKGR_UCKR_BIASEN;
\r
300 * Disables the BIAS.
\r
302 static inline void UDPHS_DisableBIAS(void)
\r
305 pPmc->CKGR_UCKR &= ~(uint32_t)CKGR_UCKR_BIASEN;
\r
309 * Handles a completed transfer on the given endpoint, invoking the
\r
310 * configured callback if any.
\r
311 * \param bEndpoint Number of the endpoint for which the transfer has completed.
\r
312 * \param bStatus Status code returned by the transfer operation
\r
314 static void UDPHS_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus)
\r
316 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
318 /* Check that endpoint was sending or receiving data */
\r
319 if ( (pEp->state == UDPHS_ENDPOINT_RECEIVING)
\r
320 || (pEp->state == UDPHS_ENDPOINT_SENDING) )
\r
322 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
323 uint32_t transferred = pXfr->transferred;
\r
324 uint32_t remaining = pXfr->remaining + pXfr->buffered;
\r
326 TRACE_DEBUG_WP("EoT ");
\r
327 if (pEp->state == UDPHS_ENDPOINT_SENDING)
\r
329 pEp->state = UDPHS_ENDPOINT_IDLE;
\r
331 pXfr->transferred = -1;
\r
332 pXfr->buffered = -1;
\r
333 pXfr->remaining = -1;
\r
335 /* Invoke callback */
\r
336 if (pXfr->fCallback)
\r
338 pXfr->fCallback(pXfr->pArgument, bStatus, transferred, remaining);
\r
342 TRACE_DEBUG_WP("NoCB ");
\r
345 else if ( (pEp->state == UDPHS_ENDPOINT_RECEIVINGM)
\r
346 || (pEp->state == UDPHS_ENDPOINT_SENDINGM) )
\r
348 MblTransfer *pXfr = (MblTransfer*)&(pEp->transfer);
\r
349 TRACE_DEBUG_WP("EoMT ");
\r
351 pEp->state = UDPHS_ENDPOINT_IDLE;
\r
352 pXfr->listState = 0;
\r
353 pXfr->outCurr = pXfr->inCurr = pXfr->outLast = 0;
\r
354 /* Invoke callback */
\r
355 if (pXfr->fCallback)
\r
357 pXfr->fCallback(pXfr->pArgument, bStatus);
\r
361 TRACE_DEBUG_WP("NoCB ");
\r
367 * Update multi-buffer-transfer descriptors.
\r
368 * \param pTransfer Pointer to instance MblTransfer.
\r
369 * \param size Size of bytes that processed.
\r
370 * \param forceEnd Force the buffer END.
\r
371 * \return 1 if current buffer ended.
\r
373 static uint8_t UDPHS_MblUpdate(MblTransfer *pTransfer,
\r
374 USBDTransferBuffer * pBi,
\r
378 /* Update transfer descriptor */
\r
379 pBi->remaining -= size;
\r
380 /* Check if list NULL */
\r
381 if (pTransfer->listState == MBL_NULL) {
\r
384 /* Check if current buffer ended */
\r
385 if (pBi->remaining == 0 || forceEnd || size == 0) {
\r
387 /* Process to next buffer */
\r
388 if ((++ pTransfer->outCurr) == pTransfer->listSize)
\r
389 pTransfer->outCurr = 0;
\r
390 /* Check buffer NULL case */
\r
391 if (pTransfer->outCurr == pTransfer->inCurr)
\r
392 pTransfer->listState = MBL_NULL;
\r
394 pTransfer->listState = 0;
\r
395 /* Continue transfer, prepare for next operation */
\r
396 pBi = &pTransfer->pMbl[pTransfer->outCurr];
\r
398 pBi->transferred = 0;
\r
399 pBi->remaining = pBi->size;
\r
407 * Transfers a data payload from the current tranfer buffer to the endpoint
\r
409 * \param bEndpoint Number of the endpoint which is sending data.
\r
411 static uint8_t UDPHS_MblWriteFifo(uint8_t bEndpoint)
\r
413 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
414 MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
\r
415 USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]);
\r
419 volatile uint8_t * pBytes;
\r
420 volatile uint8_t bufferEnd = 1;
\r
422 /* Get the number of bytes to send */
\r
423 size = pEndpoint->size;
\r
424 if (size > pBi->remaining) size = pBi->remaining;
\r
426 TRACE_DEBUG_WP("w%d.%d ", pTransfer->outCurr, size);
\r
428 /* Record last accessed buffer */
\r
429 pTransfer->outLast = pTransfer->outCurr;
\r
431 pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
\r
432 pBi->buffered += size;
\r
433 bufferEnd = UDPHS_MblUpdate(pTransfer, pBi, size, 0);
\r
435 /* Write packet in the FIFO buffer */
\r
436 pFifo = (uint8_t*)((uint32_t*)UDPHS_RAM_ADDR
\r
437 + (EPT_VIRTUAL_SIZE * bEndpoint));
\r
439 int32_t c8 = size >> 3;
\r
440 int32_t c1 = size & 0x7;
\r
441 for (; c8; c8 --) {
\r
442 *(pFifo++) = *(pBytes ++);
\r
443 *(pFifo++) = *(pBytes ++);
\r
444 *(pFifo++) = *(pBytes ++);
\r
445 *(pFifo++) = *(pBytes ++);
\r
447 *(pFifo++) = *(pBytes ++);
\r
448 *(pFifo++) = *(pBytes ++);
\r
449 *(pFifo++) = *(pBytes ++);
\r
450 *(pFifo++) = *(pBytes ++);
\r
452 for (; c1; c1 --) {
\r
453 *(pFifo++) = *(pBytes ++);
\r
461 * Transfers a data payload from an endpoint FIFO to the current transfer
\r
462 * buffer, if NULL packet received, the current buffer is ENDed.
\r
463 * \param bEndpoint Endpoint number.
\r
464 * \param wPacketSize Size of received data packet */
\r
465 * \return 1 if the buffer ENDed. */
\r
467 static uint8_t UDPHS_MblReadFifo(uint8_t bEndpoint, uint16_t wPacketSize)
\r
475 * Transfers a data payload from the current tranfer buffer to the endpoint
\r
477 * \param bEndpoint Number of the endpoint which is sending data.
\r
479 static void UDPHS_WritePayload(uint8_t bEndpoint, int32_t size)
\r
481 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
482 Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
\r
485 /* Get the number of bytes to send */
\r
486 if (size > pTransfer->remaining)
\r
488 size = pTransfer->remaining;
\r
491 /* Update transfer descriptor information */
\r
492 pTransfer->buffered += size;
\r
493 pTransfer->remaining -= size;
\r
495 /* Write packet in the FIFO buffer */
\r
496 pFifo = (uint8_t*)((uint32_t*)UDPHS_RAM_ADDR
\r
497 + (EPT_VIRTUAL_SIZE * bEndpoint));
\r
498 for (; size; size --)
\r
500 *(pFifo ++) = *(pTransfer->pData ++);
\r
505 * Transfers a data payload from an endpoint FIFO to the current transfer buffer
\r
506 * \param bEndpoint Endpoint number.
\r
507 * \param wPacketSize Size of received data packet
\r
509 static void UDPHS_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize)
\r
511 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
512 Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
\r
514 /* Check that the requested size is not bigger than the remaining transfer */
\r
515 if (wPacketSize > pTransfer->remaining) {
\r
517 pTransfer->buffered += wPacketSize - pTransfer->remaining;
\r
518 wPacketSize = pTransfer->remaining;
\r
521 /* Update transfer descriptor information */
\r
522 pTransfer->remaining -= wPacketSize;
\r
523 pTransfer->transferred += wPacketSize;
\r
525 /* Retrieve packet */
\r
526 pFifo = (uint8_t*)((uint32_t*)UDPHS_RAM_ADDR
\r
527 + (EPT_VIRTUAL_SIZE * bEndpoint));
\r
528 while (wPacketSize > 0)
\r
530 *(pTransfer->pData ++) = *(pFifo ++);
\r
536 * Received SETUP packet from endpoint 0 FIFO
\r
537 * \param pRequest Generic USB SETUP request sent over Control endpoints
\r
539 static void UDPHS_ReadRequest(USBGenericRequest *pRequest)
\r
541 uint32_t *pData = (uint32_t *)(void*)pRequest;
\r
542 volatile uint32_t *pFifo;
\r
543 pFifo = (volatile uint32_t*)UDPHS_RAM_ADDR;
\r
544 *pData ++ = *pFifo;
\r
545 pFifo = (volatile uint32_t*)UDPHS_RAM_ADDR;
\r
550 * Endpoint interrupt handler.
\r
551 * Handle IN/OUT transfers, received SETUP packets and STALLing
\r
552 * \param bEndpoint Index of endpoint
\r
554 static void UDPHS_EndpointHandler(uint8_t bEndpoint)
\r
556 Udphs *pUdp = UDPHS;
\r
557 UdphsEpt *pEpt = &pUdp->UDPHS_EPT[bEndpoint];
\r
558 //UdphsDma *pDma = &pUdp->UDPHS_DMA[bEndpoint];
\r
560 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
561 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
562 //MblTransfer *pMblt = (MblTransfer*)&(pEp->transfer);
\r
563 uint32_t status = pEpt->UDPHS_EPTSTA;
\r
564 uint32_t type = pEpt->UDPHS_EPTCFG & UDPHS_EPTCFG_EPT_TYPE_Msk;
\r
565 uint32_t reqBuf[2];
\r
566 USBGenericRequest *pReq = (USBGenericRequest *)reqBuf;
\r
569 TRACE_DEBUG_WP("Ep%d ", bEndpoint);
\r
570 //TRACE_DEBUG_WP("St:%x ", status);
\r
571 /* IN packet sent */
\r
572 if ( (pEpt->UDPHS_EPTCTL & UDPHS_EPTCTL_TX_PK_RDY)
\r
573 && (0 == (status & UDPHS_EPTSTA_TX_PK_RDY)) )
\r
575 TRACE_DEBUG_WP("Wr ");
\r
577 /* Multi-buffer-list transfer state */
\r
578 if ( pEp->state == UDPHS_ENDPOINT_SENDINGM )
\r
581 /* Sending state */
\r
582 else if ( pEp->state == UDPHS_ENDPOINT_SENDING )
\r
584 if (pXfr->buffered)
\r
586 pXfr->transferred += pXfr->buffered;
\r
587 pXfr->buffered = 0;
\r
589 if ( pXfr->buffered == 0
\r
590 && pXfr->transferred == 0
\r
591 && pXfr->remaining == 0
\r
592 && pEp->sendZLP == 0 )
\r
598 if ( pXfr->remaining
\r
599 || pEp->sendZLP == 1)
\r
603 /* Transfer remaining */
\r
604 TRACE_DEBUG_WP("%d ", pEp->size);
\r
605 /* Send next packet */
\r
606 UDPHS_WritePayload(bEndpoint, pEp->size);
\r
607 pEpt->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_TX_PK_RDY;
\r
611 TRACE_DEBUG_WP("l%d ", pXfr->transferred);
\r
612 /* Disable interrupt on none-control EP */
\r
613 if (type != UDPHS_EPTCFG_EPT_TYPE_CTRL8)
\r
615 pUdp->UDPHS_IEN &= ~(UDPHS_IEN_EPT_0 << bEndpoint);
\r
617 pEpt->UDPHS_EPTCTLDIS = UDPHS_EPTCTLDIS_TX_PK_RDY;
\r
619 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
\r
625 TRACE_DEBUG("Err Wr %d\n\r", pEp->sendZLP);
\r
628 /* OUT packet received */
\r
629 if ( UDPHS_EPTSTA_RX_BK_RDY & status )
\r
631 TRACE_DEBUG_WP("Rd ");
\r
633 /* NOT in receiving state */
\r
634 if (pEp->state != UDPHS_ENDPOINT_RECEIVING)
\r
636 /* Check if ACK received on a Control EP */
\r
637 if ( (UDPHS_EPTCFG_EPT_TYPE_CTRL8 == type)
\r
638 && (0 == (status & UDPHS_EPTSTA_BYTE_COUNT_Msk)) )
\r
640 TRACE_DEBUG_WP("Ack ");
\r
641 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_BK_RDY;
\r
642 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
\r
644 /* data has been STALLed */
\r
645 else if (UDPHS_EPTSTA_FRCESTALL & status)
\r
647 TRACE_DEBUG_WP("Discard ");
\r
648 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_BK_RDY;
\r
653 TRACE_DEBUG_WP("Nak ");
\r
654 pUdp->UDPHS_IEN &= ~(UDPHS_IEN_EPT_0 << bEndpoint);
\r
657 /* In read state */
\r
660 wPktSize = (uint16_t)((status & UDPHS_EPTSTA_BYTE_COUNT_Msk) >> UDPHS_EPTSTA_BYTE_COUNT_Pos);
\r
662 TRACE_DEBUG_WP("%d ", wPktSize);
\r
663 UDPHS_ReadPayload(bEndpoint, wPktSize);
\r
664 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_BK_RDY;
\r
665 /* Check if transfer is finished */
\r
666 if (pXfr->remaining == 0 || wPktSize < pEp->size)
\r
668 pEpt->UDPHS_EPTCTLDIS = UDPHS_EPTCTLDIS_RX_BK_RDY;
\r
670 /* Disable interrupt if not control EP */
\r
671 if (UDPHS_EPTCFG_EPT_TYPE_CTRL8 != type)
\r
673 pUdp->UDPHS_IEN &= ~(UDPHS_IEN_EPT_0 << bEndpoint);
\r
675 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
\r
680 if ( UDPHS_EPTSTA_STALL_SNT & status )
\r
683 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_STALL_SNT;
\r
686 if (type == UDPHS_EPTCFG_EPT_TYPE_ISO)
\r
688 TRACE_WARNING("IsoE[%d]\n\r", bEndpoint);
\r
690 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
\r
692 /* If EP is not halted, clear STALL */
\r
695 TRACE_WARNING("Stall[%d]\n\r", bEndpoint);
\r
697 if (pEp->state != UDPHS_ENDPOINT_HALTED)
\r
699 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_FRCESTALL;
\r
703 /* SETUP packet received */
\r
704 if ( UDPHS_EPTSTA_RX_SETUP & status )
\r
706 /* If a transfer was pending, complete it
\r
707 Handles the case where during the status phase of a control write
\r
708 transfer, the host receives the device ZLP and ack it, but the ack
\r
709 is not received by the device */
\r
710 if (pEp->state == UDPHS_ENDPOINT_RECEIVING
\r
711 || pEp->state == UDPHS_ENDPOINT_RECEIVINGM
\r
712 || pEp->state == UDPHS_ENDPOINT_SENDING
\r
713 || pEp->state == UDPHS_ENDPOINT_SENDINGM)
\r
715 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
\r
719 if (type == UDPHS_EPTCFG_EPT_TYPE_ISO)
\r
721 TRACE_WARNING("IsoFE[%d]\n\r", bEndpoint);
\r
722 /* Acknowledge setup packet */
\r
723 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_SETUP;
\r
727 TRACE_DEBUG_WP("Stup ");
\r
730 UDPHS_ReadRequest(pReq);
\r
731 /* Acknowledge setup packet */
\r
732 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_RX_SETUP;
\r
734 USBD_RequestHandler(bEndpoint, pReq);
\r
740 * DMA Single transfer
\r
741 * \param bEndpoint EP number.
\r
742 * \pXfr Pointer to transfer instance.
\r
743 * \dwCfg DMA Control configuration (excluding length).
\r
745 static inline void UDPHS_DmaSingle(uint8_t bEndpoint, Transfer *pXfr, uint32_t dwCfg)
\r
747 Udphs *pUdp = UDPHS;
\r
749 /* Single transfer */
\r
750 CP15_coherent_dcache_for_dma ((uint32_t)&pXfr->pData[pXfr->transferred], ((uint32_t)&pXfr->pData[pXfr->transferred]) + pXfr->buffered);
\r
751 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS =
\r
752 (uint32_t)&pXfr->pData[pXfr->transferred];
\r
753 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
\r
754 /* Interrupt enable */
\r
755 pUdp->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
\r
757 TRACE_DEBUG_WP("Dma[B%d:T%d] ", pXfr->buffered, pXfr->transferred);
\r
758 /* DMA Configure */
\r
759 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0;
\r
760 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0
\r
761 | UDPHS_DMACONTROL_BUFF_LENGTH(pXfr->buffered)
\r
765 * Endpoint DMA interrupt handler.
\r
766 * This function handles DMA interrupts.
\r
767 * \param bEndpoint Index of endpoint
\r
769 static void UDPHS_DmaHandler(uint8_t bEndpoint)
\r
771 Udphs *pUdp = UDPHS;
\r
772 //UdphsEpt *pHwEp = &pUdp->UDPHS_EPT[bEndpoint];
\r
774 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
775 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
778 int32_t iRemain, iXfred;
\r
779 uint8_t bRc = USBD_STATUS_SUCCESS;
\r
781 CP15_flush_dcache_for_dma ((uint32_t)&pXfr->pData[pXfr->transferred], ((uint32_t)&pXfr->pData[pXfr->transferred]) + pXfr->buffered);
\r
782 dwDmaSr = pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
\r
783 TRACE_DEBUG_WP("iDma%d,%x ", bEndpoint, dwDmaSr);
\r
785 if (pEp->state == UDPHS_ENDPOINT_SENDINGM)
\r
787 /* Not implemented */
\r
790 else if (pEp->state == UDPHS_ENDPOINT_RECEIVINGM)
\r
792 /* Not implemented */
\r
796 /* Disable DMA interrupt to avoid receiving 2 (B_EN and TR_EN) */
\r
797 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &= ~(UDPHS_DMACONTROL_END_TR_EN
\r
798 |UDPHS_DMACONTROL_END_B_EN);
\r
799 if (UDPHS_DMASTATUS_END_BF_ST & dwDmaSr)
\r
801 TRACE_DEBUG_WP("EoDmaB ");
\r
802 /* BUFF_COUNT holds the number of untransmitted bytes.
\r
803 BUFF_COUNT is equal to zero in case of good transfer */
\r
804 iRemain = (dwDmaSr & UDPHS_DMASTATUS_BUFF_COUNT_Msk)
\r
805 >> UDPHS_DMASTATUS_BUFF_COUNT_Pos;
\r
806 TRACE_DEBUG_WP("C%d ", iRemain);
\r
807 iXfred = pXfr->buffered - iRemain;
\r
809 pXfr->transferred += iXfred;
\r
810 pXfr->buffered = iRemain;
\r
811 pXfr->remaining -= iXfred;
\r
812 TRACE_DEBUG_WP("[B%d:T%d:R%d] ", pXfr->buffered, pXfr->transferred, pXfr->remaining);
\r
813 /* There is still data */
\r
814 if (pXfr->remaining + pXfr->buffered > 0)
\r
816 if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
\r
818 pXfr->buffered = DMA_MAX_FIFO_SIZE;
\r
822 pXfr->buffered = pXfr->remaining;
\r
824 /* Single transfer again */
\r
825 UDPHS_DmaSingle(bEndpoint, pXfr, UDPHS_DMACONTROL_END_TR_EN
\r
826 | UDPHS_DMACONTROL_END_TR_IT
\r
827 | UDPHS_DMACONTROL_END_B_EN
\r
828 | UDPHS_DMACONTROL_END_BUFFIT
\r
829 | UDPHS_DMACONTROL_CHANN_ENB);
\r
832 else if (UDPHS_DMASTATUS_END_TR_ST & dwDmaSr)
\r
834 TRACE_DEBUG_WP("EoDmaT ");
\r
835 pXfr->transferred = pXfr->buffered -
\r
836 ((dwDmaSr & UDPHS_DMASTATUS_BUFF_COUNT_Msk)
\r
837 >> UDPHS_DMASTATUS_BUFF_COUNT_Pos);
\r
838 pXfr->remaining = 0;
\r
840 TRACE_DEBUG_WP("[B%d:T%d] ", pXfr->buffered, pXfr->transferred);
\r
844 TRACE_ERROR("UDPHS_DmaHandler: ST 0x%X\n\r", (unsigned int)dwDmaSr);
\r
845 bRc = USBD_STATUS_ABORTED;
\r
848 if (pXfr->remaining == 0)
\r
850 UDPHS_EndOfTransfer(bEndpoint, bRc);
\r
857 * Sends data through a USB endpoint. Sets up the transfer descriptor,
\r
858 * writes one or two data payloads (depending on the number of FIFO bank
\r
859 * for the endpoint) and then starts the actual transfer. The operation is
\r
860 * complete when all the data has been sent.
\r
862 * *If the size of the buffer is greater than the size of the endpoint
\r
863 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
864 * must be kept allocated until the transfer is finished*. This means that
\r
865 * it is not possible to declare it on the stack (i.e. as a local variable
\r
866 * of a function which returns after starting a transfer).
\r
868 * \param pEndpoint Pointer to Endpoint struct.
\r
869 * \param pData Pointer to a buffer with the data to send.
\r
870 * \param dLength Size of the data buffer.
\r
871 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
872 * otherwise, the corresponding error status code.
\r
874 static inline uint8_t UDPHS_Write(uint8_t bEndpoint,
\r
878 Udphs *pUdp = UDPHS;
\r
879 UdphsEpt *pHwEp = &pUdp->UDPHS_EPT[bEndpoint];
\r
881 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
882 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
883 /* Return if busy */
\r
884 if (pEp->state != UDPHS_ENDPOINT_IDLE)
\r
886 return USBD_STATUS_LOCKED;
\r
888 /* Sending state */
\r
889 pEp->state = UDPHS_ENDPOINT_SENDING;
\r
890 TRACE_DEBUG_WP("Wr%d(%d) ", bEndpoint, dLength);
\r
892 /* Setup transfer descriptor */
\r
893 pXfr->pData = (void*) pData;
\r
894 pXfr->remaining = dLength;
\r
895 pXfr->buffered = 0;
\r
896 pXfr->transferred = 0;
\r
898 /* 1. DMA supported, 2. Not ZLP */
\r
899 if (CHIP_USB_ENDPOINTS_DMA(bEndpoint)
\r
900 && pXfr->remaining > 0)
\r
902 if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
\r
904 /* Transfer the max */
\r
905 pXfr->buffered = DMA_MAX_FIFO_SIZE;
\r
910 pXfr->buffered = pXfr->remaining;
\r
912 /* Single transfer */
\r
913 UDPHS_DmaSingle(bEndpoint, pXfr, UDPHS_DMACONTROL_END_B_EN
\r
914 | UDPHS_DMACONTROL_END_BUFFIT
\r
915 | UDPHS_DMACONTROL_CHANN_ENB);
\r
916 return USBD_STATUS_SUCCESS;
\r
921 pUdp->UDPHS_IEN |= ( UDPHS_IEN_EPT_0 << bEndpoint );
\r
922 pHwEp->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_TX_PK_RDY;
\r
923 return USBD_STATUS_SUCCESS;
\r
927 * Sends data through a USB endpoint. Sets up the transfer descriptor list,
\r
928 * writes one or two data payloads (depending on the number of FIFO bank
\r
929 * for the endpoint) and then starts the actual transfer. The operation is
\r
930 * complete when all the transfer buffer in the list has been sent.
\r
932 * *If the size of the buffer is greater than the size of the endpoint
\r
933 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
934 * must be kept allocated until the transfer is finished*. This means that
\r
935 * it is not possible to declare it on the stack (i.e. as a local variable
\r
936 * of a function which returns after starting a transfer).
\r
938 * \param pEndpoint Pointer to Endpoint struct.
\r
939 * \param pData Pointer to a buffer with the data to send.
\r
940 * \param dLength Size of the data buffer.
\r
941 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
942 * otherwise, the corresponding error status code.
\r
944 static inline uint8_t UDPHS_AddWr(uint8_t bEndpoint,
\r
948 Udphs *pUdp = UDPHS;
\r
949 UdphsEpt *pHwEp = &pUdp->UDPHS_EPT[bEndpoint];
\r
951 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
952 MblTransfer *pMbl = (MblTransfer*)&(pEp->transfer);
\r
953 USBDTransferBuffer *pTx;
\r
954 /* Check parameter */
\r
955 if (dLength >= 0x10000)
\r
957 return USBD_STATUS_INVALID_PARAMETER;
\r
959 /* Data in process */
\r
960 if (pEp->state > UDPHS_ENDPOINT_IDLE)
\r
961 { /* MBL transfer */
\r
962 if (pMbl->transType)
\r
964 if (pMbl->listState == MBL_FULL)
\r
966 return USBD_STATUS_LOCKED;
\r
971 return USBD_STATUS_LOCKED;
\r
975 TRACE_DEBUG_WP("AddW%d(%d) ", bEndpoint, dLength);
\r
976 /* Add buffer to buffer list and update index */
\r
977 pTx = &(pMbl->pMbl[pMbl->inCurr]);
\r
978 pTx->pBuffer = (uint8_t*)pData;
\r
979 pTx->size = pTx->remaining = dLength;
\r
980 pTx->transferred = pTx->buffered = 0;
\r
981 /* Update input index */
\r
982 if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0;
\r
983 else pMbl->inCurr ++;
\r
984 if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL;
\r
985 else pMbl->listState = 0;
\r
986 /* Start sending when offset achieved */
\r
987 if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize)
\r
988 >= pMbl->offsetSize
\r
989 && pEp->state == UDPHS_ENDPOINT_IDLE)
\r
991 uint8_t nbBanks = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
\r
994 pEp->state = UDPHS_ENDPOINT_SENDINGM;
\r
996 TRACE_DEBUG_WP("StartM ");
\r
998 /* Fill data into FIFO */
\r
1000 nbBanks && pMbl->pMbl[pMbl->inCurr].remaining;
\r
1003 UDPHS_MblWriteFifo(bEndpoint);
\r
1004 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_TX_PK_RDY;
\r
1007 /* Enable interrupt */
\r
1008 pUdp->UDPHS_IEN |= (UDPHS_IEN_EPT_0 << bEndpoint);
\r
1009 pHwEp->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_TX_PK_RDY;
\r
1013 return USBD_STATUS_SUCCESS;
\r
1017 * Reads incoming data on an USB endpoint This methods sets the transfer
\r
1018 * descriptor and activate the endpoint interrupt. The actual transfer is
\r
1019 * then carried out by the endpoint interrupt handler. The Read operation
\r
1020 * finishes either when the buffer is full, or a short packet (inferior to
\r
1021 * endpoint maximum size) is received.
\r
1023 * *The buffer must be kept allocated until the transfer is finished*.
\r
1024 * \param bEndpoint Endpoint number.
\r
1025 * \param pData Pointer to a data buffer.
\r
1026 * \param dLength Size of the data buffer in bytes.
\r
1027 * \return USBD_STATUS_SUCCESS if the read operation has been started;
\r
1028 * otherwise, the corresponding error code.
\r
1030 static inline uint8_t UDPHS_Read(uint8_t bEndpoint,
\r
1034 Udphs *pUdp = UDPHS;
\r
1035 UdphsEpt *pHwEp = &pUdp->UDPHS_EPT[bEndpoint];
\r
1037 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
1038 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
1039 /* Return if busy */
\r
1040 if (pEp->state != UDPHS_ENDPOINT_IDLE)
\r
1042 return USBD_STATUS_LOCKED;
\r
1044 /* Receiving state */
\r
1045 pEp->state = UDPHS_ENDPOINT_RECEIVING;
\r
1047 TRACE_DEBUG_WP("Rd%d(%d) ", bEndpoint, dLength);
\r
1048 /* Setup transfer descriptor */
\r
1049 pXfr->pData = (void*) pData;
\r
1050 pXfr->remaining = dLength;
\r
1051 pXfr->buffered = 0;
\r
1052 pXfr->transferred = 0;
\r
1055 /* If: 1. DMA supported, 2. Has data */
\r
1056 if (CHIP_USB_ENDPOINTS_DMA(bEndpoint)
\r
1057 && pXfr->remaining > 0)
\r
1059 /* DMA XFR size adjust */
\r
1060 if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
\r
1061 pXfr->buffered = DMA_MAX_FIFO_SIZE;
\r
1063 pXfr->buffered = pXfr->remaining;
\r
1064 /* Single transfer */
\r
1065 UDPHS_DmaSingle(bEndpoint, pXfr, UDPHS_DMACONTROL_END_TR_EN
\r
1066 | UDPHS_DMACONTROL_END_TR_IT
\r
1067 | UDPHS_DMACONTROL_END_B_EN
\r
1068 | UDPHS_DMACONTROL_END_BUFFIT
\r
1069 | UDPHS_DMACONTROL_CHANN_ENB);
\r
1070 return USBD_STATUS_SUCCESS;
\r
1075 pUdp->UDPHS_IEN |= ( UDPHS_IEN_EPT_0 << bEndpoint );
\r
1076 pHwEp->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_RX_BK_RDY;
\r
1078 return USBD_STATUS_SUCCESS;
\r
1082 * Reads incoming data on an USB endpoint This methods sets the transfer
\r
1083 * descriptor and activate the endpoint interrupt. The actual transfer is
\r
1084 * then carried out by the endpoint interrupt handler. The Read operation
\r
1085 * finishes either when the buffer is full, or a short packet (inferior to
\r
1086 * endpoint maximum size) is received.
\r
1088 * *The buffer must be kept allocated until the transfer is finished*.
\r
1089 * \param bEndpoint Endpoint number.
\r
1090 * \param pData Pointer to a data buffer.
\r
1091 * \param dLength Size of the data buffer in bytes.
\r
1092 * \return USBD_STATUS_SUCCESS if the read operation has been started;
\r
1093 * otherwise, the corresponding error code.
\r
1095 static inline uint8_t UDPHS_AddRd(uint8_t bEndpoint,
\r
1099 return USBD_STATUS_SW_NOT_SUPPORTED;
\r
1102 /*---------------------------------------------------------------------------
\r
1103 * Exported functions
\r
1104 *---------------------------------------------------------------------------*/
\r
1105 extern void USBD_IrqHandler(void);
\r
1107 * USBD (UDP) interrupt handler
\r
1108 * Manages device resume, suspend, end of bus reset.
\r
1109 * Forwards endpoint events to the appropriate handler.
\r
1111 void USBD_IrqHandler(void)
\r
1113 Udphs *pUdp = UDPHS;
\r
1118 status = pUdp->UDPHS_INTSTA;
\r
1119 status &= pUdp->UDPHS_IEN;
\r
1121 /* Handle all UDPHS interrupts */
\r
1122 TRACE_DEBUG_WP("\n\r%c ", USBD_HAL_IsHighSpeed() ? 'H' : 'F');
\r
1126 if (status & UDPHS_INTSTA_INT_SOF)
\r
1128 TRACE_DEBUG_WP("SOF ");
\r
1130 //USBD_SofHandler();
\r
1132 /* Acknowledge interrupt */
\r
1133 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_INT_SOF;
\r
1134 status &= ~(uint32_t)UDPHS_INTSTA_INT_SOF;
\r
1136 /* Suspend, treated last */
\r
1137 else if (status == UDPHS_INTSTA_DET_SUSPD)
\r
1139 TRACE_WARNING_WP("Susp ");
\r
1140 /* Enable wakeup */
\r
1141 pUdp->UDPHS_IEN |= (UDPHS_IEN_WAKE_UP | UDPHS_IEN_ENDOFRSM);
\r
1142 pUdp->UDPHS_IEN &= ~(uint32_t)UDPHS_IEN_DET_SUSPD;
\r
1144 /* Acknowledge interrupt */
\r
1145 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_DET_SUSPD | UDPHS_CLRINT_WAKE_UP;
\r
1147 USBD_SuspendHandler();
\r
1150 else if ( (status & UDPHS_INTSTA_WAKE_UP)
\r
1151 || (status & UDPHS_INTSTA_ENDOFRSM) )
\r
1153 USBD_ResumeHandler();
\r
1155 TRACE_INFO_WP("Rsm ");
\r
1157 /* Acknowledge interrupt */
\r
1158 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP
\r
1159 | UDPHS_CLRINT_ENDOFRSM
\r
1160 | UDPHS_CLRINT_DET_SUSPD;
\r
1162 pUdp->UDPHS_IEN |= UDPHS_IEN_ENDOFRSM | UDPHS_IEN_DET_SUSPD;
\r
1163 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_ENDOFRSM;
\r
1164 pUdp->UDPHS_IEN &= ~(uint32_t)UDPHS_IEN_WAKE_UP;
\r
1167 else if (status & UDPHS_INTSTA_ENDRESET)
\r
1169 TRACE_DEBUG_WP("EoB ");
\r
1170 /* Flush and enable the suspend interrupt */
\r
1171 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_WAKE_UP | UDPHS_CLRINT_DET_SUSPD;
\r
1172 pUdp->UDPHS_IEN |= UDPHS_IEN_DET_SUSPD;
\r
1174 /* Reset handler */
\r
1175 USBD_ResetHandler();
\r
1177 /* Acknowledge interrupt */
\r
1178 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_ENDRESET;
\r
1180 /* Upstream resume */
\r
1181 else if (status & UDPHS_INTSTA_UPSTR_RES)
\r
1183 TRACE_DEBUG_WP("ExtRes ");
\r
1184 /* Acknowledge interrupt */
\r
1185 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_UPSTR_RES;
\r
1191 for (numIt = 0; numIt < NUM_IT_MAX; numIt ++)
\r
1193 if (status & (1 << SHIFT_DMA << numIt))
\r
1195 UDPHS_DmaHandler(numIt);
\r
1197 else if (status & (UDPHS_INTSTA_EPT_0 << numIt))
\r
1199 UDPHS_EndpointHandler(numIt);
\r
1203 for (numIt = 0; numIt < NUM_IT_MAX; numIt ++)
\r
1205 if (status & (UDPHS_INTSTA_EPT_0 << numIt))
\r
1207 UDPHS_EndpointHandler(numIt);
\r
1213 /* Update interrupt status */
\r
1214 status = pUdp->UDPHS_INTSTA;
\r
1215 status &= pUdp->UDPHS_IEN;
\r
1217 TRACE_DEBUG_WP("\n\r");
\r
1220 TRACE_DEBUG_WP(" - ");
\r
1226 * \brief Reset endpoints and disable them.
\r
1227 * -# Terminate transfer if there is any, with given status;
\r
1228 * -# Reset the endpoint & disable it.
\r
1229 * \param bmEPs Bitmap for endpoints to reset.
\r
1230 * \param bStatus Status passed to terminate transfer on endpoint.
\r
1231 * \param bKeepCfg 1 to keep old endpoint configuration.
\r
1232 * \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint
\r
1233 if not keeping old configuration.
\r
1234 * \sa USBD_HAL_ConfigureEP().
\r
1236 void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg)
\r
1238 Udphs *pUdp = UDPHS;
\r
1241 Endpoint *pEndpoint;
\r
1242 uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
\r
1244 uint32_t epBit, epCfg;
\r
1246 for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++)
\r
1250 pHwEp = &pUdp->UDPHS_EPT[ep];
\r
1253 pUdp->UDPHS_IEN &= ~(epBit << SHIFT_INTERUPT);
\r
1254 /* Kill pending Banks ?? */
\r
1256 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1257 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1258 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1261 /* Reset transfer information */
\r
1262 pEndpoint = &(endpoints[ep]);
\r
1263 /* Reset endpoint state */
\r
1264 pEndpoint->bank = 0;
\r
1265 /* Endpoint configure */
\r
1266 epCfg = pHwEp->UDPHS_EPTCFG;
\r
1267 /* Reset endpoint */
\r
1268 pUdp->UDPHS_EPTRST = epBit;
\r
1269 /* Restore configure */
\r
1272 pHwEp->UDPHS_EPTCFG = epCfg;
\r
1276 pEndpoint->state = UDPHS_ENDPOINT_DISABLED;
\r
1279 /* Terminate transfer on this EP */
\r
1280 UDPHS_EndOfTransfer(ep, bStatus);
\r
1287 * Cancel pending READ/WRITE
\r
1288 * \param bmEPs Bitmap for endpoints to reset.
\r
1289 * \note EP callback is invoked with USBD_STATUS_CANCELED.
\r
1291 void USBD_HAL_CancelIo(uint32_t bmEPs)
\r
1293 Udphs *pUdp = UDPHS;
\r
1294 //UdphsEpt *pHwEp = NULL;
\r
1296 uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
\r
1299 for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++)
\r
1303 //pHwEp = &pUdp->UDPHS_EPT[ep];
\r
1306 pUdp->UDPHS_IEN &= ~(epBit << SHIFT_INTERUPT);
\r
1307 /* Kill pending Banks ?? */
\r
1309 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1310 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1311 pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
\r
1314 /* Terminate transfer on this EP */
\r
1315 UDPHS_EndOfTransfer(ep, USBD_STATUS_CANCELED);
\r
1322 * Configures an endpoint according to its endpoint Descriptor.
\r
1323 * \param pDescriptor Pointer to an endpoint descriptor.
\r
1324 * \return The endpoint address.
\r
1326 uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
\r
1328 Udphs *pUdp = UDPHS;
\r
1332 Endpoint *pEndpoint;
\r
1333 uint8_t bEndpoint;
\r
1335 uint8_t bEndpointDir;
\r
1336 //uint8_t bInterval = 0;
\r
1337 uint8_t bNbTrans = 1;
\r
1338 uint8_t bSizeEpt = 0;
\r
1339 uint8_t bHs = ((pUdp->UDPHS_INTSTA & UDPHS_INTSTA_SPEED) > 0);
\r
1341 /* NULL descriptor -> Control endpoint 0 */
\r
1342 if (pDescriptor == 0)
\r
1346 pEndpoint = &(endpoints[bEndpoint]);
\r
1347 pEpt = &(pUdp->UDPHS_EPT[0]);
\r
1348 bType = USBEndpointDescriptor_CONTROL;
\r
1350 pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
\r
1351 pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
\r
1353 /* Device descriptor -> Control endpoint 0 */
\r
1354 else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE)
\r
1356 USBDeviceDescriptor *pDevDesc = (USBDeviceDescriptor*)pDescriptor;
\r
1358 pEndpoint = &(endpoints[bEndpoint]);
\r
1359 pEpt = &(pUdp->UDPHS_EPT[0]);
\r
1360 bType = USBEndpointDescriptor_CONTROL;
\r
1362 pEndpoint->size =pDevDesc->bMaxPacketSize0;
\r
1363 pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
\r
1365 /* Endpoint descriptor */
\r
1368 /* The endpoint number */
\r
1369 bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
\r
1370 pEndpoint = &(endpoints[bEndpoint]);
\r
1371 pEpt = &(pUdp->UDPHS_EPT[bEndpoint]);
\r
1372 /* Transfer type: Control, Isochronous, Bulk, Interrupt */
\r
1373 bType = USBEndpointDescriptor_GetType(pDescriptor);
\r
1375 //bInterval = USBEndpointDescriptor_GetInterval(pDescriptor);
\r
1376 /* Direction, ignored for control endpoints */
\r
1377 bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
\r
1378 pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
\r
1379 pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
\r
1381 /* Convert descriptor value to EP configuration */
\r
1382 if (bHs) { /* HS Interval, *125us */
\r
1384 /* MPS: Bit12,11 specify NB_TRANS, as USB 2.0 Spec. */
\r
1385 bNbTrans = ((pEndpoint->size >> 11) & 0x3);
\r
1386 if (bNbTrans == 3)
\r
1391 /* Mask, bit 10..0 is the size */
\r
1392 pEndpoint->size &= 0x7FF;
\r
1396 //TRACE_DEBUG_WP("CfgE%d ", bEndpoint);
\r
1398 /* Abort the current transfer is the endpoint was configured and in
\r
1399 Write or Read state */
\r
1400 if( (pEndpoint->state == UDPHS_ENDPOINT_RECEIVING)
\r
1401 || (pEndpoint->state == UDPHS_ENDPOINT_SENDING)
\r
1402 || (pEndpoint->state == UDPHS_ENDPOINT_RECEIVINGM)
\r
1403 || (pEndpoint->state == UDPHS_ENDPOINT_SENDINGM) ) {
\r
1405 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
\r
1407 pEndpoint->state = UDPHS_ENDPOINT_IDLE;
\r
1409 /* Disable endpoint */
\r
1410 pEpt->UDPHS_EPTCTLDIS = UDPHS_EPTCTLDIS_SHRT_PCKT
\r
1411 | UDPHS_EPTCTLDIS_BUSY_BANK
\r
1412 | UDPHS_EPTCTLDIS_NAK_OUT
\r
1413 | UDPHS_EPTCTLDIS_NAK_IN
\r
1414 | UDPHS_EPTCTLDIS_STALL_SNT
\r
1415 | UDPHS_EPTCTLDIS_RX_SETUP
\r
1416 | UDPHS_EPTCTLDIS_TX_PK_RDY
\r
1417 | UDPHS_EPTCTLDIS_RX_BK_RDY
\r
1418 | UDPHS_EPTCTLDIS_ERR_OVFLW
\r
1419 | UDPHS_EPTCTLDIS_MDATA_RX
\r
1420 | UDPHS_EPTCTLDIS_DATAX_RX
\r
1421 | UDPHS_EPTCTLDIS_NYET_DIS
\r
1422 | UDPHS_EPTCTLDIS_INTDIS_DMA
\r
1423 | UDPHS_EPTCTLDIS_AUTO_VALID
\r
1424 | UDPHS_EPTCTLDIS_EPT_DISABL
\r
1426 /* Reset Endpoint Fifos */
\r
1427 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_TOGGLESQ | UDPHS_EPTCLRSTA_FRCESTALL;
\r
1428 pUdp->UDPHS_EPTRST = 1 << bEndpoint;
\r
1429 /* Configure endpoint size */
\r
1430 if( pEndpoint->size <= 8 )
\r
1432 else if ( pEndpoint->size <= 16 )
\r
1434 else if ( pEndpoint->size <= 32 )
\r
1436 else if ( pEndpoint->size <= 64 )
\r
1438 else if ( pEndpoint->size <= 128 )
\r
1440 else if ( pEndpoint->size <= 256 )
\r
1442 else if ( pEndpoint->size <= 512 )
\r
1444 else if ( pEndpoint->size <= 1024 )
\r
1447 /* Configure endpoint */
\r
1448 if (bType == USBEndpointDescriptor_CONTROL)
\r
1450 pUdp->UDPHS_IEN |= (UDPHS_IEN_EPT_0 << bEndpoint);
\r
1453 pEpt->UDPHS_EPTCFG = bSizeEpt
\r
1454 | ( bEndpointDir << 3)
\r
1456 | ((pEndpoint->bank) << 6)
\r
1457 | ( bNbTrans << 8)
\r
1459 while( (UDPHS_EPTCFG_EPT_MAPD & pEpt->UDPHS_EPTCFG) == 0 ) {
\r
1461 /* resolved by clearing the reset IT in good place */
\r
1462 TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint);
\r
1463 TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt);
\r
1464 TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir);
\r
1465 TRACE_ERROR("PB bType: 0x%X\n\r", bType);
\r
1466 TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank);
\r
1467 TRACE_ERROR("PB UDPHS_EPTCFG: 0x%X\n\r", (unsigned int)pEpt->UDPHS_EPTCFG);
\r
1471 if (bType == USBEndpointDescriptor_CONTROL)
\r
1473 pEpt->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_RX_BK_RDY
\r
1474 | UDPHS_EPTCTLENB_RX_SETUP
\r
1475 | UDPHS_EPTCTLENB_EPT_ENABL;
\r
1480 pEpt->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_EPT_ENABL;
\r
1482 pEpt->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_AUTO_VALID | UDPHS_EPTCTLENB_EPT_ENABL;
\r
1486 //TRACE_DEBUG_WP("<%x,%x,%x> ", pEpt->UDPHS_EPTCFG, pEpt->UDPHS_EPTCTL, pEpt->UDPHS_EPTSTA);
\r
1491 * Set callback for a USB endpoint for transfer (read/write).
\r
1493 * \param bEP Endpoint number.
\r
1494 * \param fCallback Optional callback function to invoke when the transfer is
\r
1496 * \param pCbData Optional pointer to data to the callback function.
\r
1497 * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy.
\r
1499 uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP,
\r
1500 TransferCallback fCallback,
\r
1503 Endpoint *pEndpoint = &(endpoints[bEP]);
\r
1504 TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer);
\r
1505 /* Check that the endpoint is not transferring */
\r
1506 if (pEndpoint->state > UDPHS_ENDPOINT_IDLE) {
\r
1507 return USBD_STATUS_LOCKED;
\r
1509 TRACE_DEBUG_WP("sXfrCb ");
\r
1510 /* Setup the transfer callback and extension data */
\r
1511 pTransfer->fCallback = (void*)fCallback;
\r
1512 pTransfer->pArgument = pCbData;
\r
1513 return USBD_STATUS_SUCCESS;
\r
1517 * Configure an endpoint to use multi-buffer-list transfer mode.
\r
1518 * The buffers can be added by _Read/_Write function.
\r
1519 * \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL.
\r
1520 * \param mblSize Multi-buffer list size (number of buffers can be queued)
\r
1521 * \param startOffset When number of buffer achieve this offset transfer start
\r
1523 uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint,
\r
1524 USBDTransferBuffer* pMbList,
\r
1526 uint16_t startOffset)
\r
1528 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
1529 MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer);
\r
1531 /* Check that the endpoint is not transferring */
\r
1532 if (pEndpoint->state > UDPHS_ENDPOINT_IDLE) {
\r
1533 return USBD_STATUS_LOCKED;
\r
1535 TRACE_DEBUG_WP("sMblXfr ");
\r
1536 /* Enable Multi-Buffer Transfer List */
\r
1538 /* Reset list items */
\r
1539 for (i = 0; i < mblSize; i --) {
\r
1540 pMbList[i].pBuffer = NULL;
\r
1541 pMbList[i].size = 0;
\r
1542 pMbList[i].transferred = 0;
\r
1543 pMbList[i].buffered = 0;
\r
1544 pMbList[i].remaining = 0;
\r
1546 /* Setup transfer */
\r
1547 pXfr->transType = 1;
\r
1548 pXfr->listState = 0; /* OK */
\r
1549 pXfr->listSize = mblSize;
\r
1550 pXfr->pMbl = pMbList;
\r
1551 pXfr->outCurr = pXfr->outLast = 0;
\r
1553 pXfr->offsetSize = startOffset;
\r
1555 /* Disable Multi-Buffer Transfer */
\r
1557 pXfr->transType = 0;
\r
1558 pXfr->pMbl = NULL;
\r
1559 pXfr->listSize = 0;
\r
1560 pXfr->offsetSize = 1;
\r
1562 return USBD_STATUS_SUCCESS;
\r
1566 * Sends data through a USB endpoint. Sets up the transfer descriptor,
\r
1567 * writes one or two data payloads (depending on the number of FIFO bank
\r
1568 * for the endpoint) and then starts the actual transfer. The operation is
\r
1569 * complete when all the data has been sent.
\r
1571 * *If the size of the buffer is greater than the size of the endpoint
\r
1572 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
1573 * must be kept allocated until the transfer is finished*. This means that
\r
1574 * it is not possible to declare it on the stack (i.e. as a local variable
\r
1575 * of a function which returns after starting a transfer).
\r
1577 * \param bEndpoint Endpoint number.
\r
1578 * \param pData Pointer to a buffer with the data to send.
\r
1579 * \param dLength Size of the data buffer.
\r
1580 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
1581 * otherwise, the corresponding error status code.
\r
1583 uint8_t USBD_HAL_Write( uint8_t bEndpoint,
\r
1584 const void *pData,
\r
1587 if (endpoints[bEndpoint].transfer.transHdr.transType)
\r
1588 return UDPHS_AddWr(bEndpoint, pData, dLength);
\r
1590 return UDPHS_Write(bEndpoint, pData, dLength);
\r
1594 * Special write function.
\r
1595 * Sends data through a USB endpoint. Sets up the transfer descriptor,
\r
1596 * writes header and one or two data payloads (depending on the number of
\r
1597 * FIFO bank for the endpoint) and then starts the actual transfer. The
\r
1598 * operation is complete when all the data has been sent.
\r
1600 * *If the size of the buffer is greater than the size of the endpoint
\r
1601 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
1602 * must be kept allocated until the transfer is finished*. This means that
\r
1603 * it is not possible to declare it on the stack (i.e. as a local variable
\r
1604 * of a function which returns after starting a transfer).
\r
1606 * \param bEndpoint Endpoint number.
\r
1607 * \param pData Pointer to a buffer with the data to send.
\r
1608 * \param dLength Size of the data buffer.
\r
1609 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
1610 * otherwise, the corresponding error status code.
\r
1612 uint8_t USBD_HAL_WrWithHdr(uint8_t bEndpoint,
\r
1613 const void * pHdr, uint8_t bHdrLen,
\r
1614 const void * pData,uint32_t dLength)
\r
1616 Udphs *pUdp = UDPHS;
\r
1617 UdphsEpt *pHwEp = &pUdp->UDPHS_EPT[bEndpoint];
\r
1618 Endpoint *pEp = &(endpoints[bEndpoint]);
\r
1619 Transfer *pXfr = (Transfer*)&(pEp->transfer);
\r
1620 /* Return if DMA is not supported */
\r
1621 if (!CHIP_USB_ENDPOINTS_DMA(bEndpoint))
\r
1623 return USBD_STATUS_HW_NOT_SUPPORTED;
\r
1627 /* Return if busy */
\r
1628 if (pEp->state != UDPHS_ENDPOINT_IDLE)
\r
1630 return USBD_STATUS_LOCKED;
\r
1632 /* Sending state */
\r
1633 pEp->state = UDPHS_ENDPOINT_SENDING;
\r
1634 TRACE_DEBUG_WP("Wr%d(%d+%d) ", bEndpoint, bHdrLen, dLength);
\r
1638 /* Setup transfer descriptor */
\r
1639 pXfr->pData = (void*) pData;
\r
1640 pXfr->remaining = bHdrLen + dLength;
\r
1641 pXfr->buffered = 0;
\r
1642 pXfr->transferred = 0;
\r
1644 /* 1. DMA supported always, 2. Not ZLP */
\r
1645 if (bHdrLen + dLength > 0)
\r
1647 uint8_t bNbTrans = (pHwEp->UDPHS_EPTCFG & UDPHS_EPTCFG_NB_TRANS_Msk)
\r
1648 >> UDPHS_EPTCFG_NB_TRANS_Pos;
\r
1649 if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
\r
1651 /* Transfer the max */
\r
1652 pXfr->buffered = DMA_MAX_FIFO_SIZE;
\r
1656 /* Good size, total size */
\r
1657 pXfr->buffered = pXfr->remaining;
\r
1660 /* LD1: header - load to fifo without interrupt */
\r
1661 /* Header discarded if exceed the DMA FIFO length */
\r
1662 //if (bHdrLen > DMA_MAX_FIFO_SIZE) bHdrLen = DMA_MAX_FIFO_SIZE;
\r
1663 pDmaLL[0].pNxtDesc = (void*)&pDmaLL[1];
\r
1664 pDmaLL[0].pAddr = (void*)pHdr;
\r
1665 pDmaLL[0].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1666 | UDPHS_DMACONTROL_BUFF_LENGTH(bHdrLen)
\r
1667 | UDPHS_DMACONTROL_LDNXT_DSC;
\r
1668 /* High bandwidth ISO EP, max size n*ep_size */
\r
1669 if (bNbTrans > 1) {
\r
1670 uint8_t* pU8 = (uint8_t*)pData;
\r
1671 uint32_t maxSize = bNbTrans * pEp->size;
\r
1672 dLength = pXfr->buffered - bHdrLen;
\r
1673 if (dLength > maxSize) dLength = maxSize;
\r
1674 #if 0 /* Prepare banks by 1 DMA descriptor -- NK if not standard EP size, works! */
\r
1675 /* LD2: data - load to fifo with interrupt */
\r
1676 pDmaLL[1].pNxtDesc = (void*)NULL;
\r
1677 pDmaLL[1].pAddr = (void*)pU8;
\r
1678 pDmaLL[1].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1679 | UDPHS_DMACONTROL_BUFF_LENGTH(dLength)
\r
1680 | UDPHS_DMACONTROL_END_B_EN
\r
1681 | UDPHS_DMACONTROL_END_BUFFIT;
\r
1683 uint32_t pktLen, ndxData = 0;
\r
1684 /* LD2: data - bank 0 */
\r
1685 pktLen = pEp->size - bHdrLen;
\r
1686 if (pktLen >= dLength) { /* It's the last DMA LLI */
\r
1687 pDmaLL[1].pNxtDesc = (void*)NULL;
\r
1688 pDmaLL[1].pAddr = (void*)pU8;
\r
1689 pDmaLL[1].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1690 | UDPHS_DMACONTROL_BUFF_LENGTH(dLength)
\r
1691 | UDPHS_DMACONTROL_END_B_EN
\r
1692 | UDPHS_DMACONTROL_END_BUFFIT;
\r
1695 pDmaLL[1].pNxtDesc = (void*)&pDmaLL[2];
\r
1696 pDmaLL[1].pAddr = (void*)pU8;
\r
1697 pDmaLL[1].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1698 | UDPHS_DMACONTROL_BUFF_LENGTH(pktLen)
\r
1699 | UDPHS_DMACONTROL_END_B_EN
\r
1700 | UDPHS_DMACONTROL_LDNXT_DSC;
\r
1701 dLength -= pktLen; ndxData += pktLen;
\r
1702 /* LD3: data - bank 1 */
\r
1703 pktLen = pEp->size;
\r
1704 if (pktLen >= dLength) { /* It's the last */
\r
1705 pDmaLL[1].pNxtDesc = (void*) NULL;
\r
1706 pDmaLL[1].pAddr = (void*)&pU8[ndxData];
\r
1707 pDmaLL[1].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1708 | UDPHS_DMACONTROL_BUFF_LENGTH(dLength)
\r
1709 | UDPHS_DMACONTROL_END_B_EN
\r
1710 | UDPHS_DMACONTROL_END_BUFFIT;
\r
1713 pDmaLL[2].pNxtDesc = (void*)&pDmaLL[3];
\r
1714 pDmaLL[2].pAddr = (void*)&pU8[ndxData];
\r
1715 pDmaLL[2].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1716 | UDPHS_DMACONTROL_BUFF_LENGTH(pktLen)
\r
1717 | UDPHS_DMACONTROL_END_B_EN
\r
1718 | UDPHS_DMACONTROL_LDNXT_DSC;
\r
1719 dLength -= pktLen; ndxData += pktLen;
\r
1720 /* LD4: data - bank 2 */
\r
1721 pDmaLL[3].pNxtDesc = (void*) NULL;
\r
1722 pDmaLL[3].pAddr = (void*)&pU8[ndxData];
\r
1723 pDmaLL[3].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1724 | UDPHS_DMACONTROL_BUFF_LENGTH(dLength)
\r
1725 | UDPHS_DMACONTROL_END_B_EN
\r
1726 | UDPHS_DMACONTROL_END_BUFFIT;
\r
1731 else { /* Normal, fill all data */
\r
1732 /* LD2: data - load to fifo with interrupt */
\r
1733 dLength = pXfr->buffered - bHdrLen;
\r
1734 pDmaLL[1].pNxtDesc = (void*)NULL;
\r
1735 pDmaLL[1].pAddr = (void*)pData;
\r
1736 pDmaLL[1].dwCtrl = UDPHS_DMACONTROL_CHANN_ENB
\r
1737 | UDPHS_DMACONTROL_BUFF_LENGTH(dLength)
\r
1738 | UDPHS_DMACONTROL_END_B_EN
\r
1739 | UDPHS_DMACONTROL_END_BUFFIT;
\r
1741 /* Interrupt enable */
\r
1742 pUdp->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
\r
1743 /* Start transfer with LLI */
\r
1744 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC = (uint32_t)pDmaLL;
\r
1745 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0;
\r
1746 pUdp->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = UDPHS_DMACONTROL_LDNXT_DSC;
\r
1747 return USBD_STATUS_SUCCESS;
\r
1752 pUdp->UDPHS_IEN |= ( UDPHS_IEN_EPT_0 << bEndpoint );
\r
1753 pHwEp->UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_TX_PK_RDY;
\r
1754 return USBD_STATUS_SUCCESS;
\r
1758 * Reads incoming data on an USB endpoint This methods sets the transfer
\r
1759 * descriptor and activate the endpoint interrupt. The actual transfer is
\r
1760 * then carried out by the endpoint interrupt handler. The Read operation
\r
1761 * finishes either when the buffer is full, or a short packet (inferior to
\r
1762 * endpoint maximum size) is received.
\r
1764 * *The buffer must be kept allocated until the transfer is finished*.
\r
1765 * \param bEndpoint Endpoint number.
\r
1766 * \param pData Pointer to a data buffer.
\r
1767 * \param dLength Size of the data buffer in bytes.
\r
1768 * \return USBD_STATUS_SUCCESS if the read operation has been started;
\r
1769 * otherwise, the corresponding error code.
\r
1771 uint8_t USBD_HAL_Read(uint8_t bEndpoint,
\r
1775 if (endpoints[bEndpoint].transfer.transHdr.transType)
\r
1776 return USBD_STATUS_SW_NOT_SUPPORTED;
\r
1778 return UDPHS_Read(bEndpoint, pData, dLength);
\r
1782 * \brief Enable Pull-up, connect.
\r
1784 * -# Enable HW access if needed
\r
1785 * -# Enable Pull-Up
\r
1786 * -# Disable HW access if needed
\r
1788 void USBD_HAL_Connect(void)
\r
1790 Udphs *pUdp = UDPHS;
\r
1792 uint8_t dis = UDPHS_EnablePeripheralClock();
\r
1793 pUdp->UDPHS_CTRL |= UDPHS_CTRL_PULLD_DIS;
\r
1794 pUdp->UDPHS_CTRL &= ~(uint32_t)UDPHS_CTRL_DETACH;
\r
1795 if (dis) UDPHS_DisablePeripheralClock();
\r
1799 * \brief Disable Pull-up, disconnect.
\r
1801 * -# Enable HW access if needed
\r
1802 * -# Disable PULL-Up
\r
1803 * -# Disable HW access if needed
\r
1805 void USBD_HAL_Disconnect(void)
\r
1807 Udphs *pUdp = UDPHS;
\r
1809 uint8_t dis = UDPHS_EnablePeripheralClock();
\r
1810 pUdp->UDPHS_CTRL |= UDPHS_CTRL_DETACH;
\r
1811 pUdp->UDPHS_CTRL &= ~(uint32_t)UDPHS_CTRL_PULLD_DIS;
\r
1812 if (dis) UDPHS_DisablePeripheralClock();
\r
1816 * Starts a remote wake-up procedure.
\r
1818 void USBD_HAL_RemoteWakeUp(void)
\r
1820 Udphs *pUdp = UDPHS;
\r
1822 UDPHS_EnablePeripheralClock();
\r
1823 UDPHS_EnableUsbClock();
\r
1825 TRACE_INFO_WP("RWUp ");
\r
1827 /* Activates a remote wakeup (edge on ESR), then clear ESR */
\r
1828 pUdp->UDPHS_CTRL |= UDPHS_CTRL_REWAKEUP;
\r
1829 while(pUdp->UDPHS_CTRL & UDPHS_CTRL_REWAKEUP)
\r
1831 TRACE_DEBUG_WP("w");
\r
1833 UDPHS_EnableBIAS();
\r
1837 * Sets the device address to the given value.
\r
1838 * \param address New device address.
\r
1840 void USBD_HAL_SetAddress(uint8_t address)
\r
1842 Udphs *pUdp = UDPHS;
\r
1846 pUdp->UDPHS_CTRL &= ~(uint32_t)UDPHS_CTRL_DEV_ADDR_Msk;
\r
1847 pUdp->UDPHS_CTRL |= address | UDPHS_CTRL_FADDR_EN;
\r
1851 pUdp->UDPHS_CTRL &= ~(uint32_t)UDPHS_CTRL_FADDR_EN;
\r
1856 * Sets the current device configuration.
\r
1857 * \param cfgnum - Configuration number to set.
\r
1859 void USBD_HAL_SetConfiguration(uint8_t cfgnum)
\r
1861 /* Nothing to do now */
\r
1866 * Initializes the USB HW Access driver.
\r
1868 void USBD_HAL_Init(void)
\r
1870 Udphs *pUdp = UDPHS;
\r
1875 /* DMA Link list should be 16-bytes aligned */
\r
1876 if ((uint32_t)dmaLL & 0xFFFFFFF0)
\r
1877 pDmaLL = (UdphsDmaDescriptor*)((uint32_t)&dmaLL[1] & 0xFFFFFFF0);
\r
1879 pDmaLL = (UdphsDmaDescriptor*)((uint32_t)&dmaLL[0]);
\r
1881 /* Must before USB & TXVC access! */
\r
1882 UDPHS_EnablePeripheralClock();
\r
1884 /* Reset & disable endpoints */
\r
1885 USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
\r
1887 /* Configure the pull-up on D+ and disconnect it */
\r
1888 pUdp->UDPHS_CTRL |= UDPHS_CTRL_DETACH;
\r
1889 pUdp->UDPHS_CTRL |= UDPHS_CTRL_PULLD_DIS;
\r
1892 pUdp->UDPHS_CTRL &= ~(uint32_t)UDPHS_CTRL_EN_UDPHS;
\r
1893 pUdp->UDPHS_CTRL |= UDPHS_CTRL_EN_UDPHS;
\r
1895 /* (XCHQ[2010.1.21], IP recomendation, setup clock after reset IP) */
\r
1896 UDPHS_EnableUsbClock();
\r
1898 /* Initialize DMA */
\r
1900 i < ((pUdp->UDPHS_IPFEATURES & UDPHS_IPFEATURES_DMA_CHANNEL_NBR_Msk) >> 4);
\r
1903 pEpt = &pUdp->UDPHS_EPT[i];
\r
1904 pDma = &pUdp->UDPHS_DMA[i];
\r
1906 pDma->UDPHS_DMACONTROL = 0;
\r
1907 /* Disable endpoint */
\r
1908 pEpt->UDPHS_EPTCTLDIS = (uint32_t)UDPHS_EPTCTLDIS_SHRT_PCKT
\r
1909 | UDPHS_EPTCTLDIS_BUSY_BANK
\r
1910 | UDPHS_EPTCTLDIS_NAK_OUT
\r
1911 | UDPHS_EPTCTLDIS_NAK_IN
\r
1912 | UDPHS_EPTCTLDIS_STALL_SNT
\r
1913 | UDPHS_EPTCTLDIS_RX_SETUP
\r
1914 | UDPHS_EPTCTLDIS_TX_PK_RDY
\r
1915 | UDPHS_EPTCTLDIS_TX_COMPLT
\r
1916 | UDPHS_EPTCTLDIS_RX_BK_RDY
\r
1917 | UDPHS_EPTCTLDIS_ERR_OVFLW
\r
1918 | UDPHS_EPTCTLDIS_MDATA_RX
\r
1919 | UDPHS_EPTCTLDIS_DATAX_RX
\r
1920 | UDPHS_EPTCTLDIS_NYET_DIS
\r
1921 | UDPHS_EPTCTLDIS_INTDIS_DMA
\r
1922 | UDPHS_EPTCTLDIS_AUTO_VALID
\r
1923 | UDPHS_EPTCTLDIS_EPT_DISABL
\r
1925 /* Clear status endpoint */
\r
1926 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_TOGGLESQ
\r
1927 | UDPHS_EPTCLRSTA_FRCESTALL
\r
1928 | UDPHS_EPTCLRSTA_RX_BK_RDY
\r
1929 | UDPHS_EPTCLRSTA_TX_COMPLT
\r
1930 | UDPHS_EPTCLRSTA_RX_SETUP
\r
1931 | UDPHS_EPTCLRSTA_STALL_SNT
\r
1932 | UDPHS_EPTCLRSTA_NAK_IN
\r
1933 | UDPHS_EPTCLRSTA_NAK_OUT
\r
1935 /* Reset endpoint config */
\r
1936 pEpt->UDPHS_EPTCTLENB = 0;
\r
1937 /* Reset DMA channel (Buffer count and Control field) */
\r
1938 pDma->UDPHS_DMACONTROL = UDPHS_DMACONTROL_LDNXT_DSC;
\r
1939 /* Reset DMA channel */
\r
1940 pDma->UDPHS_DMACONTROL = 0;
\r
1941 /* Clear DMA channel status (read to clear) */
\r
1942 pDma->UDPHS_DMASTATUS = pDma->UDPHS_DMASTATUS;
\r
1945 /* Force Full-Speed */
\r
1946 pUdp->UDPHS_TST = forceUsbFS ? UDPHS_TST_SPEED_CFG_FULL_SPEED : 0;
\r
1948 pUdp->UDPHS_IEN = 0;
\r
1949 pUdp->UDPHS_CLRINT = UDPHS_CLRINT_UPSTR_RES
\r
1950 | UDPHS_CLRINT_ENDOFRSM
\r
1951 | UDPHS_CLRINT_WAKE_UP
\r
1952 | UDPHS_CLRINT_ENDRESET
\r
1953 | UDPHS_CLRINT_INT_SOF
\r
1954 | UDPHS_CLRINT_MICRO_SOF
\r
1955 | UDPHS_CLRINT_DET_SUSPD
\r
1958 /* Enable interrupts */
\r
1959 pUdp->UDPHS_IEN = UDPHS_IEN_ENDOFRSM
\r
1960 | UDPHS_IEN_WAKE_UP
\r
1961 | UDPHS_IEN_DET_SUSPD;
\r
1963 /* Disable USB clocks */
\r
1964 UDPHS_DisableUsbClock();
\r
1968 * Causes the given endpoint to acknowledge the next packet it receives
\r
1969 * with a STALL handshake except setup request.
\r
1970 * \param bEP Endpoint number.
\r
1971 * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
\r
1973 uint8_t USBD_HAL_Stall(uint8_t bEP)
\r
1975 Udphs *pUdp = UDPHS;
\r
1976 UdphsEpt *pEpt = &pUdp->UDPHS_EPT[bEP];
\r
1978 Endpoint *pEndpoint = &(endpoints[bEP]);
\r
1980 /* Check that endpoint is in Idle state */
\r
1981 if (pEndpoint->state != UDPHS_ENDPOINT_IDLE)
\r
1983 TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP);
\r
1984 return USBD_STATUS_LOCKED;
\r
1986 /* STALL endpoint */
\r
1987 pEpt->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_FRCESTALL;
\r
1989 TRACE_DEBUG_WP("Stall%d ", bEP);
\r
1990 return USBD_STATUS_SUCCESS;
\r
1994 * Sets/Clear/Get the HALT state on the endpoint.
\r
1995 * In HALT state, the endpoint should keep stalling any packet.
\r
1996 * \param bEndpoint Endpoint number.
\r
1997 * \param ctl Control code CLR/HALT/READ.
\r
1998 * 0: Clear HALT state;
\r
1999 * 1: Set HALT state;
\r
2000 * .: Return HALT status.
\r
2001 * \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist,
\r
2002 * otherwise endpoint halt status.
\r
2004 uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
\r
2006 Udphs *pUdp = UDPHS;
\r
2007 UdphsEpt *pEpt = &pUdp->UDPHS_EPT[bEndpoint];
\r
2009 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
2010 uint8_t status = 0;
\r
2015 /* Check that endpoint is enabled and not already in Halt state */
\r
2016 if ((pEndpoint->state != UDPHS_ENDPOINT_DISABLED)
\r
2017 && (pEndpoint->state != UDPHS_ENDPOINT_HALTED))
\r
2020 TRACE_DEBUG_WP("Halt%d ", bEndpoint);
\r
2022 /* Abort the current transfer if necessary */
\r
2023 UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
\r
2025 /* Put endpoint into Halt state */
\r
2026 pEndpoint->state = UDPHS_ENDPOINT_HALTED;
\r
2027 pEpt->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_FRCESTALL;
\r
2030 if (CHIP_USB_ENDPOINTS_DMA(bEndpoint))
\r
2032 /* Enable the endpoint DMA interrupt */
\r
2033 pUdp->UDPHS_IEN |= ( 1 << SHIFT_DMA << bEndpoint );
\r
2037 /* Enable the endpoint interrupt */
\r
2038 pUdp->UDPHS_IEN |= ( UDPHS_IEN_EPT_0 << bEndpoint );
\r
2041 /* Enable the endpoint interrupt */
\r
2042 pUdp->UDPHS_IEN |= ( UDPHS_IEN_EPT_0 << bEndpoint );
\r
2047 else if (ctl == 0)
\r
2049 /* Check if the endpoint is halted */
\r
2050 if (pEndpoint->state == UDPHS_ENDPOINT_HALTED)
\r
2053 TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
\r
2055 /* Return endpoint to Idle state */
\r
2056 pEndpoint->state = UDPHS_ENDPOINT_IDLE;
\r
2058 /* Clear FORCESTALL flag */
\r
2059 pEpt->UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_TOGGLESQ
\r
2060 | UDPHS_EPTCLRSTA_FRCESTALL;
\r
2062 /* Reset Endpoint Fifos */
\r
2063 pUdp->UDPHS_EPTRST = (1 << bEndpoint);
\r
2067 /* Return Halt status */
\r
2068 if (pEndpoint->state == UDPHS_ENDPOINT_HALTED)
\r
2076 * Indicates if the device is running in high or full-speed. Always returns 0
\r
2077 * since UDP does not support high-speed mode.
\r
2079 uint8_t USBD_HAL_IsHighSpeed(void)
\r
2081 Udphs *pUdp = UDPHS;
\r
2082 return (pUdp->UDPHS_INTSTA & UDPHS_INTSTA_SPEED);
\r
2086 * Suspend USB Device HW Interface
\r
2088 * -# Disable transceiver
\r
2089 * -# Disable USB Clock
\r
2090 * -# Disable USB Peripheral
\r
2092 void USBD_HAL_Suspend(void)
\r
2094 /* The device enters the Suspended state */
\r
2095 UDPHS_DisableBIAS();
\r
2096 UDPHS_DisableUsbClock();
\r
2097 UDPHS_DisablePeripheralClock();
\r
2101 * Activate USB Device HW Interface
\r
2102 * -# Enable USB Peripheral
\r
2103 * -# Enable USB Clock
\r
2104 * -# Enable transceiver
\r
2106 void USBD_HAL_Activate(void)
\r
2108 UDPHS_EnablePeripheralClock();
\r
2109 UDPHS_EnableUsbClock();
\r
2110 UDPHS_EnableBIAS();
\r
2114 * Certification test for High Speed device.
\r
2115 * \param bIndex Test to be done
\r
2117 void USBD_HAL_Test( uint8_t bIndex )
\r
2119 Udphs *pUdp = UDPHS;
\r
2123 /* remove suspend for TEST */
\r
2124 pUdp->UDPHS_IEN &= ~UDPHS_IEN_DET_SUSPD;
\r
2125 /* force High Speed (remove suspend) */
\r
2126 pUdp->UDPHS_TST |= UDPHS_TST_SPEED_CFG_HIGH_SPEED;
\r
2128 switch( bIndex ) {
\r
2130 case USBFeatureRequest_TESTPACKET:
\r
2131 TRACE_DEBUG_WP("TEST_PACKET ");
\r
2133 pUdp->UDPHS_DMA[1].UDPHS_DMACONTROL = 0;
\r
2134 pUdp->UDPHS_DMA[2].UDPHS_DMACONTROL = 0;
\r
2136 /* Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank */
\r
2137 pUdp->UDPHS_EPT[2].UDPHS_EPTCFG = UDPHS_EPTCFG_EPT_SIZE_64
\r
2138 | UDPHS_EPTCFG_EPT_DIR
\r
2139 | UDPHS_EPTCFG_EPT_TYPE_BULK
\r
2140 | UDPHS_EPTCFG_BK_NUMBER_1;
\r
2141 while( (pUdp->UDPHS_EPT[2].UDPHS_EPTCFG & UDPHS_EPTCFG_EPT_MAPD) != UDPHS_EPTCFG_EPT_MAPD );
\r
2142 pUdp->UDPHS_EPT[2].UDPHS_EPTCTLENB = UDPHS_EPTCTLENB_EPT_ENABL;
\r
2145 pFifo = (uint8_t*)((uint32_t *)(UDPHS_RAM_ADDR) + (EPT_VIRTUAL_SIZE * 2));
\r
2146 for( i=0; i<sizeof(test_packet_buffer); i++) {
\r
2147 pFifo[i] = test_packet_buffer[i];
\r
2150 pUdp->UDPHS_TST |= UDPHS_TST_TST_PKT;
\r
2152 pUdp->UDPHS_EPT[2].UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_TX_PK_RDY;
\r
2155 case USBFeatureRequest_TESTJ:
\r
2156 TRACE_DEBUG_WP("TEST_J ");
\r
2157 pUdp->UDPHS_TST = UDPHS_TST_TST_J;
\r
2160 case USBFeatureRequest_TESTK:
\r
2161 TRACE_DEBUG_WP("TEST_K ");
\r
2162 pUdp->UDPHS_TST = UDPHS_TST_TST_K;
\r
2165 case USBFeatureRequest_TESTSE0NAK:
\r
2166 TRACE_DEBUG_WP("TEST_SEO_NAK ");
\r
2167 pUdp->UDPHS_IEN = 0; // for test
\r
2170 case USBFeatureRequest_TESTSENDZLP:
\r
2171 //while( 0 != (pUdp->UDPHS_EPT[0].UDPHS_EPTSTA & UDPHS_EPTSETSTA_TX_PK_RDY ) ) {}
\r
2172 pUdp->UDPHS_EPT[0].UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_TX_PK_RDY;
\r
2173 //while( 0 != (pUdp->UDPHS_EPT[0].UDPHS_EPTSTA & UDPHS_EPTSETSTA_TX_PK_RDY ) ) {}
\r
2174 TRACE_DEBUG_WP("SEND_ZLP ");
\r
2177 TRACE_DEBUG_WP("\n\r");
\r