/******************************************************************************* Copyright (c) 2014, Infineon Technologies AG ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification,are permitted provided that the following conditions are met: ** ** *Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. ** *Redistributions in binary form must reproduce the above copyright notice, ** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. ** *Neither the name of the copyright holders nor the names of its contributors ** may be used to endorse or promote products derived from this software without** specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ** POSSIBILITY OF SUCH DAMAGE. ** ** To improve the quality of the software, users are encouraged to share ** modifications, enhancements or bug fixes with Infineon Technologies AG ** dave@infineon.com). ** *******************************************************************************/ /** * @file WinUSB.c * * @brief winusb device framework */ #include "WinUSB.h" /** * Buffer to hold transmit and receive data **/ uint8_t tx_buf[TX_BUF_SIZE]; uint8_t rx_buf[RX_BUF_SIZE]; /* USB runtime structure*/ XMC_USBD_t USB_runtime = { .usbd = USB0, .usbd_max_num_eps = XMC_USBD_MAX_NUM_EPS_6, .usbd_transfer_mode = XMC_USBD_USE_DMA, .cb_xmc_device_event = USBD_SignalDeviceEventHandler, .cb_endpoint_event = USBD_SignalEndpointEvent_Handler }; /*WinUSB endpoint info data structure*/ USBD_WINUSB_Info_t WinUSBInfo = { .Config = { .InEndpoint = { .Address = ENDPOINT_DIR_IN | WINUSB_TX_EPNUM, .Size = WINUSB_TXRX_EPSIZE, .Type = EP_TYPE_BULK }, .OutEndpoint = { .Address = ENDPOINT_DIR_OUT | WINUSB_RX_EPNUM, .Size = WINUSB_TXRX_EPSIZE, .Type = EP_TYPE_BULK } } }; /******************************************************************************* ** Public Function Definitions ** *******************************************************************************/ void USB0_0_IRQHandler(void) { XMC_USBD_IRQHandler(&USB_runtime); } /*The function initializes the USB core layer and register call backs. */ void USB_Init(void) { USBD_Initialize(&USB_runtime); /* Interrupts configuration*/ NVIC_SetPriority(USB0_0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 63, 0)); NVIC_ClearPendingIRQ(USB0_0_IRQn); NVIC_EnableIRQ(USB0_0_IRQn); /* USB Connection*/ USB_Attach(); } /*The WinUSB API to write data to USB host*/ USBD_WINUSB_Status_t USBD_WINUSB_WriteData(uint8_t ep, const void *Buffer, uint16_t Length) { USBD_WINUSB_Status_t Status = USBD_WINUSB_STATUS_SUCCESS; uint8_t sts; /*make sure it is IN endpoint*/ ep |= ENDPOINT_DIR_MASK; if (Length > 0) { do { /* leave if device is not configured */ if (USB_DeviceState != DEVICE_STATE_Configured) { Status = USBD_WINUSB_STATUS_NOT_READY; break; } /* Selecet winusb in endpoint */ Endpoint_SelectEndpoint(ep); /* Leave if endpoint is not ready */ if (!Endpoint_IsINReady()) { Status = USBD_WINUSB_STATUS_NOT_READY; break; } /* write data to endpoint and then flush the data */ sts = Endpoint_Write_Stream_LE(Buffer,Length,NULL); if (sts != ENDPOINT_RWSTREAM_NoError ) { Status = USBD_WINUSB_STATUS_FAILURE; break; } Endpoint_ClearIN(); }while(0); } else { Status = USBD_WINUSB_STATUS_FAILURE; } return Status; } /*The WinUSB API to read data from USB host*/ USBD_WINUSB_Status_t USBD_WINUSB_ReadData(uint8_t ep,void *Buffer,uint16_t Length) { USBD_WINUSB_Status_t Status = USBD_WINUSB_STATUS_SUCCESS; uint8_t sts; if (Length > 0) { do { /* Leave if device is not configured */ if (USB_DeviceState != DEVICE_STATE_Configured) { Status = (USBD_WINUSB_Status_t)ENDPOINT_RWSTREAM_DeviceDisconnected; break; } /* Select the winusb out endpoint */ Endpoint_SelectEndpoint(ep); /* leave if no out is received */ if (true != Endpoint_IsOUTReceived()) { Status = USBD_WINUSB_STATUS_NOT_READY; break; } /* read data from endpoint and start new read operation */ sts = Endpoint_Read_Stream_LE(Buffer,Length,NULL); if (sts != ENDPOINT_RWSTREAM_NoError) { Status = USBD_WINUSB_STATUS_FAILURE; break; } Endpoint_ClearOUT(); }while(0); } else { Status = USBD_WINUSB_STATUS_FAILURE; } return Status; } /*The WinUSB API to check the data reception from USB host*/ uint16_t USBD_WINUSB_BytesReceived(uint8_t ep) { uint16_t bytes = 0; /* Leave if device is not configured */ if (USB_DeviceState == DEVICE_STATE_Configured) { /* Select the winusb out endpoint */ Endpoint_SelectEndpoint(ep); /* check if we have out received and if we have data. if is empty out * packet, flush */ if (true == Endpoint_IsOUTReceived()) { if (0 == Endpoint_BytesInEndpoint()) { Endpoint_ClearOUT(); bytes = 0; } else { bytes = Endpoint_BytesInEndpoint(); } } } return bytes; } /*The API to configure the USB end points*/ void USBD_WINUSB_ConfigureEndpoints(USBD_WINUSB_Info_t* const WinUSBInfo) { /* configure in endpoint */ Endpoint_ConfigureEndpointTable(&WinUSBInfo->Config.InEndpoint,1); /* configure out endpoint */ Endpoint_ConfigureEndpointTable(&WinUSBInfo->Config.OutEndpoint,1); } /*The USB device control request call back. * This can be used by the customers to handle the class/vendor specific * USB requests * */ void EVENT_USB_Device_ControlRequest() { uint16_t Length = 0; uint16_t index = USB_ControlRequest.wIndex; /* Serve Microsoft vendor control request */ if (MS_GET_DESCRIPTOR == (USB_ControlRequest.bmRequestType & REQTYPE_VENDOR && USB_ControlRequest.bRequest)) { /* Send comapt_ID descriptor for automatic winusb detection */ if (Extended_Compat_ID == index) { Endpoint_ClearSETUP(); if (USB_ControlRequest.wLength < Compat_ID.dwLength) { Length = USB_ControlRequest.wLength; } else { Length = Compat_ID.dwLength; } Endpoint_Write_Control_Stream_LE(&Compat_ID,Length); } /* Send Extended Properties to get allways the same device GUID */ if ((USB_ControlRequest.bmRequestType & REQREC_INTERFACE) && (Extended_Properties == index)) { Endpoint_ClearSETUP(); if (USB_ControlRequest.wLength < Properties.dwLength) { Length = USB_ControlRequest.wLength; } else { Length = Properties.dwLength; } Endpoint_Write_Control_Stream_LE(&Properties,Length); } } } /* * USB device configuration changed event call back. * Here we reconfigure the USB end points. * */ void EVENT_USB_Device_ConfigurationChanged() { uint8_t i; /* Clear configured flag */ for (i = 1;i < USB_runtime.usbd_max_num_eps;i++) { device.Endpoints[i].IsConfigured = 0; } USBD_SetEndpointBuffer(WinUSBInfo.Config.InEndpoint.Address,tx_buf,TX_BUF_SIZE); USBD_SetEndpointBuffer(WinUSBInfo.Config.OutEndpoint.Address,rx_buf,RX_BUF_SIZE); USBD_WINUSB_ConfigureEndpoints(&WinUSBInfo); /* Unconfigure all enabled but not used endpoints */ for (i = 1;i < USB_runtime.usbd_max_num_eps;i++) { USBD_Endpoint_t *ep = &device.Endpoints[i]; if ((0U == ep->IsConfigured) && (1U == ep->IsEnabled)) { device.Driver->EndpointUnconfigure(ep->Number); } } device.IsConfigured = 1; USB_DeviceState = DEVICE_STATE_Configured; } /** Event handler for the library USB Disconnection event. */ void EVENT_USB_Device_Reset(void) { if(device.IsConfigured) { USB_Init(); device.IsConfigured=0; } }