1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2008, 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 "USBD API Methods".
\r
39 /** \addtogroup usbd_interface
\r
43 /*---------------------------------------------------------------------------
\r
45 *---------------------------------------------------------------------------*/
\r
48 #include "USBD_HAL.h"
\r
50 #include <USBLib_Trace.h>
\r
52 /*---------------------------------------------------------------------------
\r
54 *---------------------------------------------------------------------------*/
\r
56 /*---------------------------------------------------------------------------
\r
57 * Internal variables
\r
58 *---------------------------------------------------------------------------*/
\r
60 /** Device current state. */
\r
61 static uint8_t deviceState;
\r
62 /** Indicates the previous device state */
\r
63 static uint8_t previousDeviceState;
\r
65 /*---------------------------------------------------------------------------
\r
66 * Internal Functions
\r
67 *---------------------------------------------------------------------------*/
\r
69 /*---------------------------------------------------------------------------
\r
70 * Exported functions
\r
71 *---------------------------------------------------------------------------*/
\r
73 /*---------------------------------------------------------------------------
\r
74 * USBD: Event handlers
\r
75 *---------------------------------------------------------------------------*/
\r
78 * Handle the USB suspend event, should be invoked whenever
\r
79 * HW reports a suspend signal.
\r
81 void USBD_SuspendHandler(void)
\r
83 /* Don't do anything if the device is already suspended */
\r
84 if (deviceState != USBD_STATE_SUSPENDED) {
\r
86 /* Switch to the Suspended state */
\r
87 previousDeviceState = deviceState;
\r
88 deviceState = USBD_STATE_SUSPENDED;
\r
90 /* Suspend HW interface */
\r
93 /* Invoke the User Suspended callback (Suspend System?) */
\r
94 if (NULL != USBDCallbacks_Suspended)
\r
95 USBDCallbacks_Suspended();
\r
100 * Handle the USB resume event, should be invoked whenever
\r
101 * HW reports a resume signal.
\r
103 void USBD_ResumeHandler(void)
\r
105 /* Don't do anything if the device was not suspended */
\r
106 if (deviceState == USBD_STATE_SUSPENDED) {
\r
107 /* Active the device */
\r
108 USBD_HAL_Activate();
\r
109 deviceState = previousDeviceState;
\r
110 if (deviceState >= USBD_STATE_DEFAULT) {
\r
111 /* Invoke the Resume callback */
\r
112 if (NULL != USBDCallbacks_Resumed)
\r
113 USBDCallbacks_Resumed();
\r
119 * Handle the USB reset event, should be invoked whenever
\r
120 * HW found USB reset signal on bus, which usually is called
\r
121 * "end of bus reset" status.
\r
123 void USBD_ResetHandler()
\r
125 /* The device enters the Default state */
\r
126 deviceState = USBD_STATE_DEFAULT;
\r
127 /* Active the USB HW */
\r
128 USBD_HAL_Activate();
\r
129 /* Only EP0 enabled */
\r
130 USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
\r
131 USBD_ConfigureEndpoint(0);
\r
132 /* Invoke the Reset callback */
\r
133 if (NULL != USBDCallbacks_Reset)
\r
134 USBDCallbacks_Reset();
\r
138 * Handle the USB setup package received, should be invoked
\r
139 * when an endpoint got a setup package as request.
\r
140 * \param bEndpoint Endpoint number.
\r
141 * \param pRequest Pointer to content of request.
\r
143 void USBD_RequestHandler(uint8_t bEndpoint,
\r
144 const USBGenericRequest* pRequest)
\r
146 if (bEndpoint != 0) {
\r
147 TRACE_WARNING("EP%d request not supported, default EP only",
\r
150 else if (NULL != USBDCallbacks_RequestReceived) {
\r
151 USBDCallbacks_RequestReceived(pRequest);
\r
155 /*---------------------------------------------------------------------------
\r
156 * USBD: Library interface
\r
157 *---------------------------------------------------------------------------*/
\r
160 * Configures an endpoint according to its Endpoint Descriptor.
\r
161 * \param pDescriptor Pointer to an Endpoint descriptor.
\r
163 void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
\r
165 USBD_HAL_ConfigureEP(pDescriptor);
\r
169 * Sends data through a USB endpoint. Sets up the transfer descriptor,
\r
170 * writes one or two data payloads (depending on the number of FIFO bank
\r
171 * for the endpoint) and then starts the actual transfer. The operation is
\r
172 * complete when all the data has been sent.
\r
174 * *If the size of the buffer is greater than the size of the endpoint
\r
175 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
176 * must be kept allocated until the transfer is finished*. This means that
\r
177 * it is not possible to declare it on the stack (i.e. as a local variable
\r
178 * of a function which returns after starting a transfer).
\r
180 * \param bEndpoint Endpoint number.
\r
181 * \param pData Pointer to a buffer with the data to send.
\r
182 * \param dLength Size of the data buffer.
\r
183 * \param fCallback Optional callback function to invoke when the transfer is
\r
185 * \param pArgument Optional argument to the callback function.
\r
186 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
187 * otherwise, the corresponding error status code.
\r
189 uint8_t USBD_Write( uint8_t bEndpoint,
\r
192 TransferCallback fCallback,
\r
195 USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);
\r
196 return USBD_HAL_Write(bEndpoint, pData, dLength);
\r
200 * Sends data frames through a USB endpoint. Sets up the transfer descriptor
\r
201 * list, writes one or two data payloads (depending on the number of FIFO bank
\r
202 * for the endpoint) and then starts the actual transfer. The operation is
\r
203 * complete when all the data has been sent.
\r
205 * *If the size of the frame is greater than the size of the endpoint
\r
206 * (or twice the size if the endpoint has two FIFO banks), then the buffer
\r
207 * must be kept allocated until the frame is finished*. This means that
\r
208 * it is not possible to declare it on the stack (i.e. as a local variable
\r
209 * of a function which returns after starting a transfer).
\r
211 * \param bEndpoint Endpoint number.
\r
212 * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes
\r
213 * the buffer list to send.
\r
214 * \param wListSize Size of the frame list.
\r
215 * \param bCircList Circle the list.
\r
216 * \param wStartNdx For circled list only, the first buffer index to transfer.
\r
217 * \param fCallback Optional callback function to invoke when the transfer is
\r
219 * \param pArgument Optional argument to the callback function.
\r
220 * \return USBD_STATUS_SUCCESS if the transfer has been started;
\r
221 * otherwise, the corresponding error status code.
\r
222 * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse
\r
224 uint8_t USBD_MblWrite( uint8_t bEndpoint,
\r
226 uint16_t wListSize,
\r
228 uint16_t wStartNdx,
\r
229 MblTransferCallback fCallback,
\r
232 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
233 MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
\r
236 /* EP0 is not suitable for Mbl */
\r
238 if (bEndpoint == 0) {
\r
240 return USBD_STATUS_INVALID_PARAMETER;
\r
243 /* Check that the endpoint is in Idle state */
\r
245 if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
\r
247 return USBD_STATUS_LOCKED;
\r
249 pEndpoint->state = UDP_ENDPOINT_SENDINGM;
\r
251 TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);
\r
253 /* Start from first if not circled list */
\r
255 if (!bCircList) wStartNdx = 0;
\r
257 /* Setup the transfer descriptor */
\r
259 pTransfer->pMbl = (USBDTransferBuffer*)pMbl;
\r
260 pTransfer->listSize = wListSize;
\r
261 pTransfer->fCallback = fCallback;
\r
262 pTransfer->pArgument = pArgument;
\r
263 pTransfer->currBuffer = wStartNdx;
\r
264 pTransfer->freedBuffer = 0;
\r
265 pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
\r
266 pTransfer->circList = bCircList;
\r
267 pTransfer->allUsed = 0;
\r
269 /* Clear all buffer */
\r
271 for (i = 0; i < wListSize; i ++) {
\r
273 pTransfer->pMbl[i].transferred = 0;
\r
274 pTransfer->pMbl[i].buffered = 0;
\r
275 pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size;
\r
278 /* Send the first packet */
\r
280 while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
\r
281 UDP_MblWriteFifo(bEndpoint);
\r
282 SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
\r
284 /* If double buffering is enabled and there is data remaining, */
\r
286 /* prepare another packet */
\r
288 if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
\r
289 && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {
\r
291 UDP_MblWriteFifo(bEndpoint);
\r
294 /* Enable interrupt on endpoint */
\r
296 UDP->UDP_IER = 1 << bEndpoint;
\r
298 return USBD_STATUS_SUCCESS;
\r
302 * Reads incoming data on an USB endpoint This methods sets the transfer
\r
303 * descriptor and activate the endpoint interrupt. The actual transfer is
\r
304 * then carried out by the endpoint interrupt handler. The Read operation
\r
305 * finishes either when the buffer is full, or a short packet (inferior to
\r
306 * endpoint maximum size) is received.
\r
308 * *The buffer must be kept allocated until the transfer is finished*.
\r
309 * \param bEndpoint Endpoint number.
\r
310 * \param pData Pointer to a data buffer.
\r
311 * \param dLength Size of the data buffer in bytes.
\r
312 * \param fCallback Optional end-of-transfer callback function.
\r
313 * \param pArgument Optional argument to the callback function.
\r
314 * \return USBD_STATUS_SUCCESS if the read operation has been started;
\r
315 * otherwise, the corresponding error code.
\r
317 uint8_t USBD_Read(uint8_t bEndpoint,
\r
320 TransferCallback fCallback,
\r
323 USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);
\r
324 return USBD_HAL_Read(bEndpoint, pData, dLength);
\r
328 * Reuse first used/released buffer with new buffer address and size to be used
\r
329 * in transfer again. Only valid when frame list is ringed. Can be used for
\r
330 * both read & write.
\r
331 * \param bEndpoint Endpoint number.
\r
332 * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).
\r
333 * \param wNewSize Size of the data buffer
\r
335 uint8_t USBD_MblReuse( uint8_t bEndpoint,
\r
336 uint8_t *pNewBuffer,
\r
337 uint16_t wNewSize )
\r
339 Endpoint *pEndpoint = &(endpoints[bEndpoint]);
\r
340 MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
\r
341 USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);
\r
343 TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",
\r
344 bEndpoint, pEndpoint->state, pTransfer->circList);
\r
346 /* Only for Multi-buffer-circle list */
\r
349 && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM
\r
350 || pEndpoint->state == UDP_ENDPOINT_SENDINGM)
\r
351 && pTransfer->circList) {
\r
355 return USBD_STATUS_WRONG_STATE;
\r
358 /* Check if there is freed buffer */
\r
360 if (pTransfer->freedBuffer == pTransfer->currBuffer
\r
361 && !pTransfer->allUsed) {
\r
363 return USBD_STATUS_LOCKED;
\r
366 /* Update transfer information */
\r
368 if ((++ pTransfer->freedBuffer) == pTransfer->listSize)
\r
369 pTransfer->freedBuffer = 0;
\r
371 pBi->pBuffer = pNewBuffer;
\r
372 pBi->size = wNewSize;
\r
375 pBi->transferred = 0;
\r
376 pBi->remaining = pBi->size;
\r
378 /* At least one buffer is not processed */
\r
380 pTransfer->allUsed = 0;
\r
381 return USBD_STATUS_SUCCESS;
\r
385 * Sets the HALT feature on the given endpoint (if not already in this state).
\r
386 * \param bEndpoint Endpoint number.
\r
388 void USBD_Halt(uint8_t bEndpoint)
\r
390 USBD_HAL_Halt(bEndpoint, 1);
\r
394 * Clears the Halt feature on the given endpoint.
\r
395 * \param bEndpoint Index of endpoint
\r
397 void USBD_Unhalt(uint8_t bEndpoint)
\r
399 USBD_HAL_Halt(bEndpoint, 0);
\r
403 * Returns the current Halt status of an endpoint.
\r
404 * \param bEndpoint Index of endpoint
\r
405 * \return 1 if the endpoint is currently halted; otherwise 0
\r
407 uint8_t USBD_IsHalted(uint8_t bEndpoint)
\r
409 return USBD_HAL_Halt(bEndpoint, 0xFF);
\r
413 * Indicates if the device is running in high or full-speed. Always returns 0
\r
414 * since UDP does not support high-speed mode.
\r
416 uint8_t USBD_IsHighSpeed(void)
\r
418 return USBD_HAL_IsHighSpeed();
\r
422 * Causes the given endpoint to acknowledge the next packet it receives
\r
423 * with a STALL handshake.
\r
424 * \param bEndpoint Endpoint number.
\r
425 * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
\r
427 uint8_t USBD_Stall(uint8_t bEndpoint)
\r
430 return USBD_HAL_Stall(bEndpoint);
\r
434 * Sets the device address to the given value.
\r
435 * \param address New device address.
\r
437 void USBD_SetAddress(uint8_t address)
\r
439 TRACE_INFO_WP("SetAddr(%d) ", address);
\r
441 USBD_HAL_SetAddress(address);
\r
442 if (address == 0) deviceState = USBD_STATE_DEFAULT;
\r
443 else deviceState = USBD_STATE_ADDRESS;
\r
447 * Sets the current device configuration.
\r
448 * \param cfgnum - Configuration number to set.
\r
450 void USBD_SetConfiguration(uint8_t cfgnum)
\r
452 TRACE_INFO_WP("SetCfg(%d) ", cfgnum);
\r
454 USBD_HAL_SetConfiguration(cfgnum);
\r
457 deviceState = USBD_STATE_CONFIGURED;
\r
460 deviceState = USBD_STATE_ADDRESS;
\r
461 /* Reset all endpoints but Control 0 */
\r
462 USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0);
\r
466 /*---------------------------------------------------------------------------
\r
467 * USBD: Library API
\r
468 *---------------------------------------------------------------------------*/
\r
471 * Starts a remote wake-up procedure.
\r
473 void USBD_RemoteWakeUp(void)
\r
475 /* Device is NOT suspended */
\r
476 if (deviceState != USBD_STATE_SUSPENDED) {
\r
478 TRACE_INFO("USBD_RemoteWakeUp: Device is not suspended\n\r");
\r
481 USBD_HAL_Activate();
\r
482 USBD_HAL_RemoteWakeUp();
\r
486 * Connects the pull-up on the D+ line of the USB.
\r
488 void USBD_Connect(void)
\r
490 USBD_HAL_Connect();
\r
494 * Disconnects the pull-up from the D+ line of the USB.
\r
496 void USBD_Disconnect(void)
\r
498 USBD_HAL_Disconnect();
\r
500 /* Device returns to the Powered state */
\r
502 if (deviceState > USBD_STATE_POWERED) {
\r
504 deviceState = USBD_STATE_POWERED;
\r
507 if (previousDeviceState > USBD_STATE_POWERED) {
\r
509 previousDeviceState = USBD_STATE_POWERED;
\r
514 * Initializes the USB driver.
\r
516 void USBD_Init(void)
\r
518 TRACE_INFO_WP("USBD_Init\n\r");
\r
520 /* HW Layer Initialize */
\r
523 /* Device is in the Attached state */
\r
524 deviceState = USBD_STATE_SUSPENDED;
\r
525 previousDeviceState = USBD_STATE_POWERED;
\r
527 /* Upper Layer Initialize */
\r
528 if (NULL != USBDCallbacks_Initialized)
\r
529 USBDCallbacks_Initialized();
\r
533 * Returns the current state of the USB device.
\r
534 * \return Device current state.
\r
536 uint8_t USBD_GetState(void)
\r
538 return deviceState;
\r
542 * Certification test for High Speed device.
\r
543 * \param bIndex Test to be done
\r
545 void USBD_Test(uint8_t bIndex)
\r
547 USBD_HAL_Test(bIndex);
\r