| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000 |
- #include "usbd_vendor.h"
- #include "usbd_desc.h"
- #include "usbd_ctlreq.h"
- #include "usbd_vendor_desc.h"
- static uint8_t USBD_VENDOR_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
- static uint8_t USBD_VENDOR_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
- static uint8_t USBD_VENDOR_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req);
- static uint8_t USBD_VENDOR_Error (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
- static uint8_t USBD_VENDOR_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * );
- static uint8_t USBD_VENDOR_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * );
- /* Vendor interface class callbacks structure */
- const USBD_ClassTypeDef USBD_VENDOR =
- {
- .Init = USBD_VENDOR_Init,
- .DeInit = USBD_VENDOR_DeInit,
- .Error = USBD_VENDOR_Error,
- .Setup = USBD_VENDOR_Setup,
- .EP0_TxSent = USBD_VENDOR_EP0_TxSent,
- .EP0_RxReady = USBD_VENDOR_EP0_RxReady,
- .DataIn = NULL,
- .DataOut = NULL,
- .SOF = NULL,
- .pDesc = &USBD_VENDOR_DescriptorHandlers,
- };
- /**
- * @brief USBD_VENDOR_Init
- * Initialize the Vendor interface
- * @param pdev: device instance
- * @param cfgidx: Configuration index
- * @retval status
- */
- static uint8_t USBD_VENDOR_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx)
- {
- uint8_t ret = USBD_OK;
- USBD_VENDOR_HandleTypeDef *hvendor;
- pdev->pClassData = USBD_malloc(sizeof (USBD_VENDOR_HandleTypeDef));
-
- if(pdev->pClassData == NULL)
- {
- ret = USBD_FAIL;
- }
- else
- {
- hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
-
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- usb_create_transfer( &hvendor->ep0_tx_transfer,
- &hvendor->ep0_tx_buffer[0],
- sizeof(hvendor->ep0_tx_buffer),
- NULL, pdev );
-
- usb_create_transfer( &hvendor->ep0_rx_transfer,
- &hvendor->ep0_rx_buffer[0],
- sizeof(hvendor->ep0_rx_buffer),
- NULL, pdev );
- if( 0 == pUserIface->fUsbInit() )
- {
- if( USBD_STATE_DEFAULT == pdev->dev_state ) // useless
- {
- if( NULL != pUserIface->fResetEvent )
- {
- pUserIface->fResetEvent();
- }
- }
- if( pdev->dev_state == USBD_STATE_CONFIGURED )
- {
- if( NULL != pUserIface->fSetIface )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call SetInterface callback
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = NULL;
- #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
- ret = USBD_CallGetDescriptorHandler( pdev,
- eGetDescriptorHandlerType_Config,
- &pbuf,
- &len );
- #else
- USBD_CallGetDescriptorHandlerAlt( ret, pdev, pDescBytePtr, nConfDescLength, GetConfigDescriptor );
- #endif
- if( USBD_OK == ret )
- {
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
-
- size_t ifidx = 0;
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
-
- if( pDescHeader->bLength == 0 ) break;
-
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- if( ! pUserIface->fSetIface( cfgidx, ifidx++, ifdesc ) )
- {
- ret = USBD_FAIL;
- break;
- }
- }
-
- nConfDescLength -= pDescHeader->bLength;
-
- pDescBytePtr += (pDescHeader->bLength);
- }
- (void)conf;
- }
- //--------------------------------------------------------------------------------------
- }
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- return ret;
- }
- /*
- static const sUSBInterfaceDescriptor_t * USBD_VENDOR_SearchInterfaceDescriptor( USBD_HandleTypeDef *pdev, uint8_t cfgidx, uint8_t nIf )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call ClearInterface callback
- (void)cfgidx; // to do - use cfgidx to get configuration descriptor
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = (const uint8_t * )pdev->pClass->GetFSConfigDescriptor(&nConfDescLength);
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
-
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
-
- if( pDescHeader->bLength == 0 ) break;
-
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- if( ifdesc->bInterfaceNumber == nIf )
- {
- return ifdesc;
- }
- }
-
- nConfDescLength -= pDescHeader->bLength;
-
- pDescBytePtr += (pDescHeader->bLength);
- }
- //--------------------------------------------------------------------------------------
- return NULL;
- }
- */
- /**
- * @brief USBD_VENDOR_DeInit
- * DeInitialize the Vendor layer
- * @param pdev: device instance
- * @param cfgidx: Configuration index
- * @retval status
- */
- static uint8_t USBD_VENDOR_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx)
- {
- uint8_t ret = USBD_OK;
-
- /* DeInit physical Interface components */
- if(pdev->pClassData != NULL)
- {
- if( pdev->pUserData != NULL )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fClrIface )
- {
- if( ((pdev->dev_old_state == USBD_STATE_CONFIGURED)
- || (pdev->dev_old_state == USBD_STATE_SUSPENDED) )
- && ((pdev->dev_state != USBD_STATE_CONFIGURED)
- || (pdev->dev_state != USBD_STATE_SUSPENDED) ) )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call ClearInterface callback
- (void)cfgidx; // to do - use cfgidx to get configuration descriptor
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = NULL;
- #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
- ret = USBD_CallGetDescriptorHandler( pdev,
- eGetDescriptorHandlerType_Config,
- &pbuf,
- &len );
- #else
- USBD_CallGetDescriptorHandlerAlt( ret, pdev, pDescBytePtr, nConfDescLength, GetConfigDescriptor );
- #endif
- if( USBD_OK == ret )
- {
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
- size_t ifidx = 0;
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
- if( pDescHeader->bLength == 0 ) break;
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- pUserIface->fClrIface( cfgidx, ifidx++, ifdesc );
- }
- nConfDescLength -= pDescHeader->bLength;
- pDescBytePtr += (pDescHeader->bLength);
- }
- (void)conf;
- }
- //--------------------------------------------------------------------------------------
- }
- }
- if( USBD_STATE_DEFAULT == pdev->dev_state )
- {
- if( NULL != pUserIface->fResetEvent )
- {
- pUserIface->fResetEvent();
- }
- }
-
- pUserIface->fUsbDeInit();
- USBD_free(pdev->pClassData);
- pdev->pClassData = NULL;
- }
- }
-
- return ret;
- }
- static uint8_t USBD_VENDOR_Error (USBD_HandleTypeDef *pdev, uint8_t epnum)
- {
- if(pdev->pClassData != NULL)
- {
- if( pdev->pUserData != NULL )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- if( epnum == 0 )
- {
- if( NULL != pUserIface->fUsbSetup )
- {
- pUserIface->fUsbSetup( &pdev->request, false, false );
- }
- }
- else
- {
- if( NULL != pUserIface->fDataErrHandler )
- {
- pUserIface->fDataErrHandler( epnum, 0 );
- }
- }
- }
- }
- return USBD_OK;
- }
- /**
- * @brief USBD_VENDOR_Setup
- * Handle the vendor specific requests
- * @param pdev: instance
- * @param req: usb requests
- * @retval status
- */
- #if VENDOR_USE_COMMON_SETUP
- static uint8_t USBD_VENDOR_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req)
- {
- uint8_t ret = USBD_OK;
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- if( NULL == pUserIface->fUsbSetup )
- {
- return USBD_FAIL; // @fUsbSetup is missing
- }
-
- if( NULL == hvendor)
- {
- return USBD_FAIL;
- }
- // SETUP filtering:
- if( ! pUserIface->fUsbSetup( req, true, false ) )
- {
- return USBD_FAIL; // do not call @fUsbSetup second time
- }
- else
- {
- // Checking request type
- switch (req->bmRequest & USB_REQ_TYPE_MASK)
- {
- case USB_REQ_TYPE_VENDOR : // Vendor I/O
- {
- if (req->wLength > 0)
- {
- if (req->bmRequest & 0x80)
- {
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &hvendor->ep0_tx_transfer,
- &hvendor->ep0_tx_buffer[0],
- sizeof(hvendor->ep0_tx_buffer),
- NULL, pdev );
- #endif
- ret = USBD_COMMON_Setup_DataProcess( pdev, req, &hvendor->ep0_tx_transfer );
- }
- else
- {
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &hvendor->ep0_rx_transfer,
- &hvendor->ep0_rx_buffer[0],
- sizeof(hvendor->ep0_rx_buffer),
- NULL, pdev );
- #endif
- ret = USBD_COMMON_Setup_DataProcess( pdev, req, &hvendor->ep0_rx_transfer );
- }
- }
- else
- {
- USBD_CtlSendStatus( pdev ); // need answer for ZeroLength requests
- }
- }
- break;
- case USB_REQ_TYPE_STANDARD:
- {
- switch (req->bRequest)
- {
- case USB_REQ_GET_INTERFACE:
- {
- if( NULL != pUserIface->fGetIface )
- {
- uint8_t nIf = req->wIndex;
- uint8_t ifalt = 0;
-
- if( pUserIface->fGetIface( pdev->dev_config, nIf, &ifalt ) )
- {
- USBD_CtlSendData (pdev, &ifalt, sizeof(ifalt));
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- break;
-
- case USB_REQ_SET_INTERFACE:
- break;
- }
- }
- break;
- default:
- break;
- }
- }
- if( ret != USBD_OK )
- {
- pUserIface->fUsbSetup( req, false, false );
- }
- return ret;
- }
- #else
- static uint8_t USBD_VENDOR_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req)
- {
- uint8_t ret = USBD_OK;
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- if( NULL == pUserIface->fUsbSetup )
- {
- return USBD_FAIL; // @fUsbSetup is missing
- }
- if( NULL == hvendor)
- {
- return USBD_FAIL;
- }
-
- // SETUP filtering:
- if( ! pUserIface->fUsbSetup( req, true, false ) )
- {
- return USBD_FAIL; // do not call @fUsbSetup second time
- }
- else
- {
- switch (req->bmRequest & USB_REQ_TYPE_MASK)
- {
- case USB_REQ_TYPE_VENDOR : // Vendor I/O
- {
- if (req->wLength > 0)
- {
- if (req->bmRequest & 0x80)
- {
- /*if( req->wLength > 0 ) --- extra checking fixed 22/05/19 */
- {
- // DataIN stage preparing
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &hvendor->ep0_tx_transfer,
- &hvendor->ep0_tx_buffer[0],
- sizeof(hvendor->ep0_tx_buffer),
- NULL, pdev );
- #endif
-
- if( usb_validate_transfer( &hvendor->ep0_tx_transfer ) )
- {
- // First packet in the stage: reset the transfer
- usb_reset_transfer( &hvendor->ep0_tx_transfer );
-
- // Single-transfer mode only:
- // Whole transfer is limited by the @ep0_tx_transfer size
- size_t nBytesProcessed = pUserIface->fUsbCtlEpTx( (const tUSBSetupPacket_t*)req,
- &hvendor->ep0_tx_transfer,
- 0,
- req->wLength );
- // User can perform move semantic on @ep0_tx_transfer transfer
- // This is an error condition, let's check it:
- #warning Check
- if( usb_validate_transfer( &hvendor->ep0_tx_transfer ) )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_in[0];
- // If SETUP data stage assumes trasmitting more than one MAX_PACKET bytes,
- // this packet must include MAX_PACKET bytes (not to be "short packet")
- size_t min_limit = ((req->wLength > pep->maxpacket)?(pep->maxpacket-1):(0));
-
- // Actually, @ep0_tx_transfer can store more data than @nBytesProcessed.
- // @nBytesProcessed: bytes processed by last @fUsbCtlEpTx call.
- // Just check it for zero:
- if( nBytesProcessed > 0 )
- {
- // Check the transfer for minimal bytes limit:
- if( min_limit < usb_count_transfer( &hvendor->ep0_tx_transfer ) )
- {
- // truncate the transfer in case if the transfer size is
- // greater than requested length.
- usb_truncate_transfer( &hvendor->ep0_tx_transfer, req->wLength );
- USBD_CtlSendData (pdev,
- (const uint8_t *)hvendor->ep0_tx_transfer.pReadData,
- req->wLength );
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- }
- else
- {
- // DataOUT stage preparing
- if( req->wLength > 0 )
- {
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &hvendor->ep0_rx_transfer,
- &hvendor->ep0_rx_buffer[0],
- sizeof(hvendor->ep0_rx_buffer),
- NULL, pdev );
- #endif
- if( usb_validate_transfer( &hvendor->ep0_rx_transfer ) )
- {
- // Reset the RX-transfer
- usb_reset_transfer( &hvendor->ep0_rx_transfer );
-
- // Begin receiving first packet
- USBD_CtlPrepareRx (pdev,
- (uint8_t *)hvendor->ep0_rx_transfer.pWriteData,
- req->wLength );
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- }
- }
- else
- {
- USBD_CtlSendStatus( pdev ); // need answer for ZeroLength requests
- }
- }
- break;
- case USB_REQ_TYPE_STANDARD:
- {
- switch (req->bRequest)
- {
- case USB_REQ_GET_INTERFACE:
- {
- if( NULL != pUserIface->fGetIface )
- {
- uint8_t nIf = req->wIndex;
- uint8_t ifalt = 0;
-
- if( pUserIface->fGetIface( pdev->dev_config, nIf, &ifalt ) )
- {
- USBD_CtlSendData (pdev, &ifalt, sizeof(ifalt));
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- break;
-
- case USB_REQ_SET_INTERFACE:
- break;
- }
- }
- break;
- default:
- break;
- }
- }
- if( ret != USBD_OK )
- {
- pUserIface->fUsbSetup( req, false, false );
- }
- return ret;
- }
- #endif
- // USBD_VENDOR_EP0_RxReady()
- // This function is called when a packet via CONTROL protocol had been received from host
- // This function continues the transmitting
- #if VENDOR_USE_COMMON_EP0RXREADY
- static uint8_t USBD_VENDOR_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- return USBD_COMMON_EP0_RxReady( pdev, &hvendor->ep0_rx_transfer, pnBytesRollback );
- }
- #else
- static uint8_t USBD_VENDOR_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- USBD_EndpointTypeDef * pep = &pdev->ep_out[0];
- USBD_StatusTypeDef ret = USBD_FAIL;
- sUSBTransfer_t * rx = &hvendor->ep0_rx_transfer;
- if( pdev->pUserData != NULL && usb_validate_transfer(rx) )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fUsbCtlEpRx )
- {
- size_t nBytesReceived = ((pep->rem_length > pep->maxpacket)?pep->maxpacket:pep->rem_length);
- size_t nBytesRemaining = (pep->rem_length - nBytesReceived);
- // Since the core uses raw @ep0_rx_transfer->pWriteData pointer, it is required to update the transfer information.
- // Use 'virutal write' to shift the pointer:
- usb_transfer_virtual_write( rx, nBytesReceived );
- // Check if the trasfer have enough free space for receiving another packet?
- // Or maybe it is a last packet?
- if( (usb_space_transfer(rx) < MIN(nBytesRemaining, pep->maxpacket)) || (0 == nBytesRemaining) )
- {
- // No, there no enough free space
- // Need to call user handler.
- // Retirieve actual amount of data in transfer
- size_t nBytesInTransfer = usb_count_transfer(rx);
- // Calculate current data offset
- size_t nOffset = (pep->total_length - nBytesRemaining - nBytesInTransfer);
-
- // pass the data to user
- size_t nBytesProcessed = pUserIface->fUsbCtlEpRx( &pdev->request,
- rx,
- nOffset,
- nBytesRemaining + nBytesInTransfer );
- // user can perform move semantic on transfer @rx.
- // It is valid condition if no remaining bytes left only.
- // Let's check it:
- bool bValid = usb_validate_transfer( rx );
- #warning Check
- if( 0 == nBytesRemaining || bValid )
- {
- // Actually, it does not matter, what exactly the function @fUsbCtlEpRx returns.
- // The only that matters is the amount of data in the transfer.
- // Just check the return value for zero:
- if( nBytesProcessed > 0 )
- {
- // By default ( usb_count_transfer() is ZERO ) ==> @nCompressed equals to the number of bytes in the transfer before user handler call.
- size_t nCompressed = nBytesInTransfer;
-
- // It is required that the transfer be valid only if @nBytesRemaining greater than zero
- if( bValid )
- {
- // If the transfer still contains data, it means user didn't perform full read.
- if( usb_count_transfer(rx) > 0 )
- {
- // it is required to compress the data in the transfer
- // optimize the transfer to compress stored data
- nCompressed = usb_transfer_compress( rx );
- // @bNeedPacketSpace - true if the core deadly needs at least MAX_PACKET free bytes in transfer
- bool bNeedPacketSpace = false;
- // After compressing: check if the transfer have enough space for next packet?
- if( usb_space_transfer(rx) >= MIN(nBytesRemaining, pep->maxpacket) )
- {
- // yes, ok
- ret = USBD_OK;
- }
- else
- {
- // nope, user didn't read enough data from the transfer to free enough space for next packet
- // Need to free at least MAX_PACKET free bytes in transfer
- bNeedPacketSpace = true;
- }
- // try to call user handler again:
- if( bNeedPacketSpace || (0 == nBytesRemaining) )
- {
- // Here: two reasons:
- // 1) if it is required to free MAX_PACKET bytes in transfer for next packet
- // 2) or this is a last packet: last chance to retrieve data. It is required to feed all data to user... Even if he resists!!!! >:D
- // For USB-core it does not matter if user processed all bytes or not...
- // There no incoming packets expected.
- // The only problem is to send a confirmation for this transaction.
- // As soon user process all bytes from the transfer @rx, this function returns control to the
- // core to send a confirmation.
- // Ok, lets feed user..
- while( nBytesProcessed > 0 )
- {
- nBytesInTransfer = usb_count_transfer(rx);
- size_t nLeftBytes = nBytesInTransfer + ((bNeedPacketSpace)?nBytesRemaining:0);
- size_t nOffset = (pep->total_length - nLeftBytes);
- // Call user handler, again...
- nBytesProcessed = pUserIface->fUsbCtlEpRx( &pdev->request,
- rx,
- nOffset,
- nLeftBytes );
-
- // user can perform move semantic on transfer @rx.
- // It is valid condition if no remaining bytes left only.
- // Let's check it:
- #warning Check
- if( 0 == nBytesRemaining || usb_validate_transfer( rx ) )
- {
- // ~~~ do not do this here, extra compressing possible (reduces performance) ~~ /* usb_transfer_compress( rx ); */
- // ~~~ do not do this here, extra compressing possible (reduces performance) ~~ /* nCompressed += (nBytesInTransfer - usb_count_transfer(rx)); */
- // Reason 1: (only if @bNeedPacketSpace is true)
- // check if the transfer has enough data for next packet
- if( bNeedPacketSpace
- && (usb_space_transfer(rx) >= MIN(nBytesRemaining, pep->maxpacket)) )
- {
- // Reason 1: exit, because transfer has enough free space for next packet
- // User have read data portion from the transfer, need to compress it again
- // Need to update @nCompressed variable to take in account new pointer to the free memory.
- usb_transfer_compress( rx );
- nCompressed += (nBytesInTransfer - usb_count_transfer(rx));
- ret = USBD_OK;
- break;
- }
- else
- {
- // User have read data portion from the transfer, need to compress it again
- // Need to update @nCompressed variable to take in account new pointer to the free memory.
- usb_transfer_compress( rx );
- nCompressed += (nBytesInTransfer - usb_count_transfer(rx));
- }
- // check if the transfer is still not empty
- if( 0 == usb_count_transfer(rx) )
- {
- // Reason 2: exit if transfer is empty
- // Empty! => Success (nBytesProcessed>0)
- break; // yee, at last!
- }
- }
- else
- {
- // Failed!
- ret = USBD_FAIL;
- }
- }
- // Check the last user call status
- if( 0 == nBytesProcessed )
- {
- // Failed!
- ret = USBD_FAIL;
- }
- }
- }
- else
- {
- // ~~~~~~~~~~~~ ADDED 18/04/19
- // Check if the trasfer have enough free space for receiving another packet?
- // Or maybe it is a last packet?
- if( (usb_space_transfer(rx) < MIN(nBytesRemaining, pep->maxpacket)) )
- {
- // it is required to compress the data in the transfer
- // optimize the transfer to compress stored data
- nCompressed = usb_transfer_compress( rx );
- }
- // ~~~~~~~~~~~~
- ret = USBD_OK;
- }
- }
- else
- {
- // If there no bytes left to receive
- // it is normal that the transfer is invalid (user may use move semantic)
- if( 0 == nBytesRemaining )
- {
- ret = USBD_OK;
- }
- }
- // let the core know how many excaclty bytes is required to shift the pointer back.
- if( (USBD_OK == ret) && (NULL != pnBytesRollback) )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- else
- {
- // user must not return zero to proceed
- usb_reset_transfer( rx );
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- // yep, there is free space for the next packet, let's receive it
- ret = USBD_CONTINUE;
- }
- }
- }
- return ret;
- }
- #endif
- // USBD_VENDOR_EP0_TxSent()
- // This function is called when at least one packet via CONTROL protocol had been sent to the host
- // This function continues the transmitting
- #if VENDOR_USE_COMMON_EP0TXSENT
- static uint8_t USBD_VENDOR_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- return USBD_COMMON_EP0_TxSent( pdev, &hvendor->ep0_tx_transfer, pnBytesRollback );
- }
- #else
- static uint8_t USBD_VENDOR_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_VENDOR_HandleTypeDef *hvendor = (USBD_VENDOR_HandleTypeDef*) pdev->pClassData;
- #if CONFIG_USB_VENDOR_DUMMYREAD
- memset( hvendor->ep0_tx_transfer.pDefaultBuffer, 0xAA, hvendor->ep0_tx_transfer.size );
- return USBD_OK;
- #endif
- USBD_EndpointTypeDef * pep = &pdev->ep_in[0];
- sUSBTransfer_t * tx = &hvendor->ep0_tx_transfer;
- uint8_t ret = USBD_FAIL;
- if( pdev->pUserData != NULL && usb_validate_transfer(tx) )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fUsbCtlEpTx )
- {
- // Due to the low-level driver uses dry transfer->@pReadData pointer, the
- // tranfer object must be modified.
- size_t nBytesRequested = 0;
- if( 0 == pep->rem_length )
- {
- // Update transfer information:
- // If @pep->rem_length is zero, the last packet sent was a last packet
- // The size of the short packet is a remainder of the division the
- // full transaction size and the endpoint size.
- // If the result of operation is non zero, the last packet was a short packet.
- // If the result of operation is zero, the last packet was full packet
- size_t last_packet_size = (pep->total_length % pep->maxpacket);
- if( last_packet_size == 0 )
- {
- last_packet_size = pep->maxpacket;
- }
- usb_transfer_virtual_read( tx, last_packet_size );
- }
- else
- {
- nBytesRequested = MIN( pep->maxpacket, pep->rem_length );
- // Update transfer information:
- // If @pep->rem_length is non zero, the last packet send was a full packet.
- // The size of full packet is pep->maxpacket
- usb_transfer_virtual_read( tx, pep->maxpacket );
- }
- // // Update transfer information:
- // usb_transfer_virtual_read( tx,
- // // The variable @nBytesRequested have quite confusing name, but this argument
- // // requires the length of already sent data. Actually the number of bytes already sent
- // // is numerially equals to @nBytesRequested
- // nBytesRequested // for pep->rem_length >= pep->maxpacket: the pep->maxpacket bytes just have been sent
- // ); // for pep->rem_length < pep->maxpacket: the pep->rem_length bytes just have been sent
- //
- // If the transaction is still not completed:
- if( pep->rem_length == 0 )
- {
- // transfer full reset
- usb_reset_transfer( tx );
- ret = USBD_OK;
- }
- else
- {
- size_t nBytesLeft = usb_count_transfer( tx );
- // If the transfer has enougth data to send another packet:
- if( nBytesLeft >= nBytesRequested )
- {
- ret = USBD_CONTINUE; // ask the core to continue sending the transfer (without rollback)
- }
- else
- {
- if( nBytesLeft > 0 )
- {
- // optimize the transfer to compress stored data
-
- size_t nCompressed = usb_transfer_compress( tx );
- if( NULL != pnBytesRollback )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- else
- {
- // // transfer full reset
- // usb_reset_transfer( tx );
- size_t nCompressed = usb_transfer_compress( tx );
- if( NULL != pnBytesRollback )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- size_t nOffset = (pep->total_length - pep->rem_length + nBytesLeft);
- size_t nBytesProcessed = pUserIface->fUsbCtlEpTx( &pdev->request,
- tx,
- nOffset,
- pep->rem_length );
-
- // User can perform move semantic on the @tx transfer.
- // This is an error condition, let's check it:
- #warning Check
- if( usb_validate_transfer( tx ) )
- {
- // Actually, does not matter what exactly the function @fUsbCtlEpTx returns,
- // because only transfer size really matters ( usb_count_transfer() ).
- // Just check the return value for zero:
- if( nBytesProcessed > 0 )
- {
- // If more than one FULL packet is required to send:
- if( pep->rem_length >= pep->maxpacket )
- {
- // This packet must be full: transfer must contain at least @pep->maxpacket bytes
- if( usb_count_transfer( tx ) >= pep->maxpacket )
- {
- ret = USBD_OK;
- }
- }
- else
- // No, it is required to send "short packet"
- {
- // This packet must be short: transfer must contain exactly @pep->rem_length bytes
- if( usb_count_transfer( tx ) == pep->rem_length )
- {
- ret = USBD_OK;
- }
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- }
- }
- }
- return ret;
- }
- #endif
|