00001 /* ---------------------------------------------------------------------------- */ 00002 /* Atmel Microcontroller Software Support */ 00003 /* SAM Software Package License */ 00004 /* ---------------------------------------------------------------------------- */ 00005 /* Copyright (c) 2015, Atmel Corporation */ 00006 /* */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without */ 00010 /* modification, are permitted provided that the following condition is met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, */ 00013 /* this list of conditions and the disclaimer below. */ 00014 /* */ 00015 /* Atmel's name may not be used to endorse or promote products derived from */ 00016 /* this software without specific prior written permission. */ 00017 /* */ 00018 /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ 00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ 00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ 00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ 00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ 00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ 00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ 00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ 00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00028 /* ---------------------------------------------------------------------------- */ 00029 00030 /** \file 00031 * 00032 * \section Purpose 00033 * 00034 * Implementation of USB device functions on a UDP controller. 00035 * 00036 * See \ref usbd_api "USBD API Methods". 00037 */ 00038 00039 /** \addtogroup usbd_interface 00040 *@{ 00041 */ 00042 00043 /*--------------------------------------------------------------------------- 00044 * Headers 00045 *---------------------------------------------------------------------------*/ 00046 00047 #include "USBD.h" 00048 #include "USBD_HAL.h" 00049 00050 #include <USBLib_Trace.h> 00051 00052 /*--------------------------------------------------------------------------- 00053 * Definitions 00054 *---------------------------------------------------------------------------*/ 00055 00056 /*--------------------------------------------------------------------------- 00057 * Internal variables 00058 *---------------------------------------------------------------------------*/ 00059 00060 /** Device current state. */ 00061 static uint8_t deviceState; 00062 /** Indicates the previous device state */ 00063 static uint8_t previousDeviceState; 00064 00065 uint8_t ForceFS = 0; 00066 00067 /*--------------------------------------------------------------------------- 00068 * Internal Functions 00069 *---------------------------------------------------------------------------*/ 00070 00071 /*--------------------------------------------------------------------------- 00072 * Exported functions 00073 *---------------------------------------------------------------------------*/ 00074 00075 /*--------------------------------------------------------------------------- 00076 * USBD: Event handlers 00077 *---------------------------------------------------------------------------*/ 00078 00079 /** 00080 * Handle the USB suspend event, should be invoked whenever 00081 * HW reports a suspend signal. 00082 */ 00083 void USBD_SuspendHandler(void) 00084 { 00085 /* Don't do anything if the device is already suspended */ 00086 if (deviceState != USBD_STATE_SUSPENDED) { 00087 00088 /* Switch to the Suspended state */ 00089 previousDeviceState = deviceState; 00090 deviceState = USBD_STATE_SUSPENDED; 00091 00092 /* Suspend HW interface */ 00093 USBD_HAL_Suspend(); 00094 00095 /* Invoke the User Suspended callback (Suspend System?) */ 00096 if (NULL != (void *)USBDCallbacks_Suspended) 00097 USBDCallbacks_Suspended(); 00098 } 00099 } 00100 00101 /** 00102 * Handle the USB resume event, should be invoked whenever 00103 * HW reports a resume signal. 00104 */ 00105 void USBD_ResumeHandler(void) 00106 { 00107 /* Don't do anything if the device was not suspended */ 00108 if (deviceState == USBD_STATE_SUSPENDED) { 00109 /* Active the device */ 00110 USBD_HAL_Activate(); 00111 deviceState = previousDeviceState; 00112 00113 if (deviceState >= USBD_STATE_DEFAULT) { 00114 /* Invoke the Resume callback */ 00115 if (NULL != (void *)USBDCallbacks_Resumed) 00116 USBDCallbacks_Resumed(); 00117 } 00118 } 00119 } 00120 00121 /** 00122 * Handle the USB reset event, should be invoked whenever 00123 * HW found USB reset signal on bus, which usually is called 00124 * "end of bus reset" status. 00125 */ 00126 void USBD_ResetHandler() 00127 { 00128 /* The device enters the Default state */ 00129 deviceState = USBD_STATE_DEFAULT; 00130 /* Active the USB HW */ 00131 USBD_HAL_Activate(); 00132 /* Only EP0 enabled */ 00133 USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0); 00134 USBD_ConfigureEndpoint(0); 00135 00136 /* Invoke the Reset callback */ 00137 if (NULL != (void *)USBDCallbacks_Reset) 00138 USBDCallbacks_Reset(); 00139 } 00140 00141 /** 00142 * Handle the USB setup package received, should be invoked 00143 * when an endpoint got a setup package as request. 00144 * \param bEndpoint Endpoint number. 00145 * \param pRequest Pointer to content of request. 00146 */ 00147 void USBD_RequestHandler(uint8_t bEndpoint, 00148 const USBGenericRequest *pRequest) 00149 { 00150 if (bEndpoint != 0) { 00151 TRACE_WARNING("EP%d request not supported, default EP only", 00152 bEndpoint); 00153 } else if (NULL != (void *)USBDCallbacks_RequestReceived) 00154 USBDCallbacks_RequestReceived(pRequest); 00155 } 00156 00157 /*--------------------------------------------------------------------------- 00158 * USBD: Library interface 00159 *---------------------------------------------------------------------------*/ 00160 00161 /** 00162 * Configures an endpoint according to its Endpoint Descriptor. 00163 * \param pDescriptor Pointer to an Endpoint descriptor. 00164 */ 00165 void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor) 00166 { 00167 USBD_HAL_ConfigureEP(pDescriptor); 00168 } 00169 00170 /** 00171 * Sends data through a USB endpoint. Sets up the transfer descriptor, 00172 * writes one or two data payloads (depending on the number of FIFO bank 00173 * for the endpoint) and then starts the actual transfer. The operation is 00174 * complete when all the data has been sent. 00175 * 00176 * *If the size of the buffer is greater than the size of the endpoint 00177 * (or twice the size if the endpoint has two FIFO banks), then the buffer 00178 * must be kept allocated until the transfer is finished*. This means that 00179 * it is not possible to declare it on the stack (i.e. as a local variable 00180 * of a function which returns after starting a transfer). 00181 * 00182 * \param bEndpoint Endpoint number. 00183 * \param pData Pointer to a buffer with the data to send. 00184 * \param dLength Size of the data buffer. 00185 * \param fCallback Optional callback function to invoke when the transfer is 00186 * complete. 00187 * \param pArgument Optional argument to the callback function. 00188 * \return USBD_STATUS_SUCCESS if the transfer has been started; 00189 * otherwise, the corresponding error status code. 00190 */ 00191 uint8_t USBD_Write(uint8_t bEndpoint, 00192 const void *pData, 00193 uint32_t dLength, 00194 TransferCallback fCallback, 00195 void *pArgument) 00196 { 00197 USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument); 00198 return USBD_HAL_Write(bEndpoint, pData, dLength); 00199 } 00200 #if 0 00201 /** 00202 * Sends data frames through a USB endpoint. Sets up the transfer descriptor 00203 * list, writes one or two data payloads (depending on the number of FIFO bank 00204 * for the endpoint) and then starts the actual transfer. The operation is 00205 * complete when all the data has been sent. 00206 * 00207 * *If the size of the frame is greater than the size of the endpoint 00208 * (or twice the size if the endpoint has two FIFO banks), then the buffer 00209 * must be kept allocated until the frame is finished*. This means that 00210 * it is not possible to declare it on the stack (i.e. as a local variable 00211 * of a function which returns after starting a transfer). 00212 * 00213 * \param bEndpoint Endpoint number. 00214 * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes 00215 * the buffer list to send. 00216 * \param wListSize Size of the frame list. 00217 * \param bCircList Circle the list. 00218 * \param wStartNdx For circled list only, the first buffer index to transfer. 00219 * \param fCallback Optional callback function to invoke when the transfer is 00220 * complete. 00221 * \param pArgument Optional argument to the callback function. 00222 * \return USBD_STATUS_SUCCESS if the transfer has been started; 00223 * otherwise, the corresponding error status code. 00224 * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse 00225 */ 00226 uint8_t USBD_MblWrite(uint8_t bEndpoint, 00227 void *pMbl, 00228 uint16_t wListSize, 00229 uint8_t bCircList, 00230 uint16_t wStartNdx, 00231 MblTransferCallback fCallback, 00232 void *pArgument) 00233 { 00234 Endpoint *pEndpoint = &(endpoints[bEndpoint]); 00235 MblTransfer *pTransfer = (MblTransfer *) & (pEndpoint->transfer); 00236 uint16_t i; 00237 00238 /* EP0 is not suitable for Mbl */ 00239 00240 if (bEndpoint == 0) 00241 00242 return USBD_STATUS_INVALID_PARAMETER; 00243 00244 /* Check that the endpoint is in Idle state */ 00245 00246 if (pEndpoint->state != UDP_ENDPOINT_IDLE) 00247 00248 return USBD_STATUS_LOCKED; 00249 00250 pEndpoint->state = UDP_ENDPOINT_SENDINGM; 00251 00252 TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize); 00253 00254 /* Start from first if not circled list */ 00255 00256 if (!bCircList) wStartNdx = 0; 00257 00258 /* Setup the transfer descriptor */ 00259 00260 pTransfer->pMbl = (USBDTransferBuffer *)pMbl; 00261 pTransfer->listSize = wListSize; 00262 pTransfer->fCallback = fCallback; 00263 pTransfer->pArgument = pArgument; 00264 pTransfer->currBuffer = wStartNdx; 00265 pTransfer->freedBuffer = 0; 00266 pTransfer->pLastLoaded = &(((USBDTransferBuffer *)pMbl)[wStartNdx]); 00267 pTransfer->circList = bCircList; 00268 pTransfer->allUsed = 0; 00269 00270 /* Clear all buffer */ 00271 00272 for (i = 0; i < wListSize; i ++) { 00273 00274 pTransfer->pMbl[i].transferred = 0; 00275 pTransfer->pMbl[i].buffered = 0; 00276 pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size; 00277 } 00278 00279 /* Send the first packet */ 00280 00281 while ((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY) == UDP_CSR_TXPKTRDY); 00282 00283 UDP_MblWriteFifo(bEndpoint); 00284 SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); 00285 00286 /* If double buffering is enabled and there is data remaining, */ 00287 00288 /* prepare another packet */ 00289 00290 if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) 00291 && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) 00292 00293 UDP_MblWriteFifo(bEndpoint); 00294 00295 /* Enable interrupt on endpoint */ 00296 00297 UDP->UDP_IER = 1 << bEndpoint; 00298 00299 return USBD_STATUS_SUCCESS; 00300 } 00301 #endif 00302 /** 00303 * Reads incoming data on an USB endpoint This methods sets the transfer 00304 * descriptor and activate the endpoint interrupt. The actual transfer is 00305 * then carried out by the endpoint interrupt handler. The Read operation 00306 * finishes either when the buffer is full, or a short packet (inferior to 00307 * endpoint maximum size) is received. 00308 * 00309 * *The buffer must be kept allocated until the transfer is finished*. 00310 * \param bEndpoint Endpoint number. 00311 * \param pData Pointer to a data buffer. 00312 * \param dLength Size of the data buffer in bytes. 00313 * \param fCallback Optional end-of-transfer callback function. 00314 * \param pArgument Optional argument to the callback function. 00315 * \return USBD_STATUS_SUCCESS if the read operation has been started; 00316 * otherwise, the corresponding error code. 00317 */ 00318 uint8_t USBD_Read(uint8_t bEndpoint, 00319 void *pData, 00320 uint32_t dLength, 00321 TransferCallback fCallback, 00322 void *pArgument) 00323 { 00324 USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument); 00325 return USBD_HAL_Read(bEndpoint, pData, dLength); 00326 } 00327 #if 0 00328 /** 00329 * Reuse first used/released buffer with new buffer address and size to be used 00330 * in transfer again. Only valid when frame list is ringed. Can be used for 00331 * both read & write. 00332 * \param bEndpoint Endpoint number. 00333 * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last). 00334 * \param wNewSize Size of the data buffer 00335 */ 00336 uint8_t USBD_MblReuse(uint8_t bEndpoint, 00337 uint8_t *pNewBuffer, 00338 uint16_t wNewSize) 00339 { 00340 Endpoint *pEndpoint = &(endpoints[bEndpoint]); 00341 MblTransfer *pTransfer = (MblTransfer *)&(pEndpoint->transfer); 00342 USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]); 00343 00344 TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r", 00345 bEndpoint, pEndpoint->state, pTransfer->circList); 00346 00347 /* Only for Multi-buffer-circle list */ 00348 00349 if (bEndpoint != 0 00350 && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM 00351 || pEndpoint->state == UDP_ENDPOINT_SENDINGM) 00352 && pTransfer->circList) { 00353 } else 00354 00355 return USBD_STATUS_WRONG_STATE; 00356 00357 /* Check if there is freed buffer */ 00358 00359 if (pTransfer->freedBuffer == pTransfer->currBuffer 00360 && !pTransfer->allUsed) 00361 00362 return USBD_STATUS_LOCKED; 00363 00364 /* Update transfer information */ 00365 00366 if ((++ pTransfer->freedBuffer) == pTransfer->listSize) 00367 pTransfer->freedBuffer = 0; 00368 00369 if (pNewBuffer) { 00370 pBi->pBuffer = pNewBuffer; 00371 pBi->size = wNewSize; 00372 } 00373 00374 pBi->buffered = 0; 00375 pBi->transferred = 0; 00376 pBi->remaining = pBi->size; 00377 00378 /* At least one buffer is not processed */ 00379 00380 pTransfer->allUsed = 0; 00381 return USBD_STATUS_SUCCESS; 00382 } 00383 #endif 00384 /** 00385 * Sets the HALT feature on the given endpoint (if not already in this state). 00386 * \param bEndpoint Endpoint number. 00387 */ 00388 void USBD_Halt(uint8_t bEndpoint) 00389 { 00390 USBD_HAL_Halt(bEndpoint, 1); 00391 } 00392 00393 /** 00394 * Clears the Halt feature on the given endpoint. 00395 * \param bEndpoint Index of endpoint 00396 */ 00397 void USBD_Unhalt(uint8_t bEndpoint) 00398 { 00399 USBD_HAL_Halt(bEndpoint, 0); 00400 } 00401 00402 /** 00403 * Returns the current Halt status of an endpoint. 00404 * \param bEndpoint Index of endpoint 00405 * \return 1 if the endpoint is currently halted; otherwise 0 00406 */ 00407 uint8_t USBD_IsHalted(uint8_t bEndpoint) 00408 { 00409 return USBD_HAL_Halt(bEndpoint, 0xFF); 00410 } 00411 00412 /** 00413 * Indicates if the device is running in high or full-speed. Always returns 0 00414 * since UDP does not support high-speed mode. 00415 */ 00416 uint8_t USBD_IsHighSpeed(void) 00417 { 00418 return USBD_HAL_IsHighSpeed(); 00419 } 00420 00421 /** 00422 * Causes the given endpoint to acknowledge the next packet it receives 00423 * with a STALL handshake. 00424 * \param bEndpoint Endpoint number. 00425 * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED. 00426 */ 00427 uint8_t USBD_Stall(uint8_t bEndpoint) 00428 00429 { 00430 return USBD_HAL_Stall(bEndpoint); 00431 } 00432 00433 /** 00434 * Sets the device address to the given value. 00435 * \param address New device address. 00436 */ 00437 void USBD_SetAddress(uint8_t address) 00438 { 00439 TRACE_INFO_WP("SetAddr(%d) ", address); 00440 00441 USBD_HAL_SetAddress(address); 00442 00443 if (address == 0) 00444 deviceState = USBD_STATE_DEFAULT; 00445 else 00446 deviceState = USBD_STATE_ADDRESS; 00447 } 00448 00449 /** 00450 * Sets the current device configuration. 00451 * \param cfgnum - Configuration number to set. 00452 */ 00453 void USBD_SetConfiguration(uint8_t cfgnum) 00454 { 00455 TRACE_INFO_WP("SetCfg(%d) ", cfgnum); 00456 00457 USBD_HAL_SetConfiguration(cfgnum); 00458 00459 if (cfgnum != 0) 00460 deviceState = USBD_STATE_CONFIGURED; 00461 else { 00462 deviceState = USBD_STATE_ADDRESS; 00463 /* Reset all endpoints but Control 0 */ 00464 USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0); 00465 } 00466 } 00467 00468 /*--------------------------------------------------------------------------- 00469 * USBD: Library API 00470 *---------------------------------------------------------------------------*/ 00471 00472 /** 00473 * Starts a remote wake-up procedure. 00474 */ 00475 void USBD_RemoteWakeUp(void) 00476 { 00477 /* Device is NOT suspended */ 00478 if (deviceState != USBD_STATE_SUSPENDED) { 00479 TRACE_INFO("USBD_RemoteWakeUp: Device is not suspended\n\r"); 00480 return; 00481 } 00482 00483 USBD_HAL_Activate(); 00484 USBD_HAL_RemoteWakeUp(); 00485 } 00486 00487 /** 00488 * Connects the pull-up on the D+ line of the USB. 00489 */ 00490 void USBD_Connect(void) 00491 { 00492 TRACE_INFO(" Connect -"); 00493 USBD_HAL_Connect(); 00494 } 00495 00496 /** 00497 * Disconnects the pull-up from the D+ line of the USB. 00498 */ 00499 void USBD_Disconnect(void) 00500 { 00501 TRACE_INFO(" DisConnect -"); 00502 USBD_HAL_Disconnect(); 00503 00504 /* Device returns to the Powered state */ 00505 00506 if (deviceState > USBD_STATE_POWERED) 00507 00508 deviceState = USBD_STATE_POWERED; 00509 00510 if (previousDeviceState > USBD_STATE_POWERED) 00511 00512 previousDeviceState = USBD_STATE_POWERED; 00513 } 00514 00515 /** 00516 * Initializes the USB driver. 00517 */ 00518 void USBD_Init(void) 00519 { 00520 TRACE_INFO_WP("USBD_Init\n\r"); 00521 00522 /* HW Layer Initialize */ 00523 USBD_HAL_Init(); 00524 00525 /* Device is in the Attached state */ 00526 deviceState = USBD_STATE_SUSPENDED; 00527 previousDeviceState = USBD_STATE_POWERED; 00528 00529 /* Upper Layer Initialize */ 00530 if (NULL != (void *)USBDCallbacks_Initialized) 00531 USBDCallbacks_Initialized(); 00532 } 00533 00534 /** 00535 * Returns the current state of the USB device. 00536 * \return Device current state. 00537 */ 00538 uint8_t USBD_GetState(void) 00539 { 00540 return deviceState; 00541 } 00542 00543 /** 00544 * Certification test for High Speed device. 00545 * \param bIndex Test to be done 00546 */ 00547 void USBD_Test(uint8_t bIndex) 00548 { 00549 USBD_HAL_Test(bIndex); 00550 } 00551 00552 00553 void USBD_ForceFullSpeed(void) 00554 { 00555 ForceFS = 1; 00556 } 00557 00558 /**@}*/