pcan_pro_x/Src/pcanpro_usbd.c

444 lines
13 KiB
C

#include <assert.h>
#include "usbd_ctlreq.h"
#include "usbd_ioreq.h"
#include "usbd_conf.h"
#include "usbd_helper.h"
#include "pcanpro_protocol.h"
#include "pcanpro_usbd.h"
static struct t_class_data pcanpro_data = { 0 };
struct t_pcanpro_description
{
USB_CONFIGURATION_DESCRIPTOR con0;
USB_INTERFACE_DESCRIPTOR if0;
USB_ENDPOINT_DESCRIPTOR ep1_i0;
USB_ENDPOINT_DESCRIPTOR ep2_i0;
USB_ENDPOINT_DESCRIPTOR ep3_i0;
USB_ENDPOINT_DESCRIPTOR ep4_i0;
#if ( PCAN_PRO ) || ( PCAN_PRO_FD ) || ( PCAN_X6)
USB_ENDPOINT_DESCRIPTOR ep5_i0;
USB_ENDPOINT_DESCRIPTOR ep6_i0;
#endif
#if INCLUDE_LIN_INTERFACE
USB_INTERFACE_DESCRIPTOR if1;
USB_ENDPOINT_DESCRIPTOR ep1_i1;
USB_ENDPOINT_DESCRIPTOR ep2_i1;
USB_ENDPOINT_DESCRIPTOR ep3_i1;
USB_ENDPOINT_DESCRIPTOR ep4_i1;
USB_ENDPOINT_DESCRIPTOR ep5_i1;
USB_ENDPOINT_DESCRIPTOR ep6_i1;
#endif
};
#if defined ( __ICCARM__ )
#pragma data_alignment=4
#endif
__ALIGN_BEGIN static const USB_DEVICE_QUALIFIER_DESCRIPTOR dev_qua __ALIGN_END =
{
.bLength = sizeof( USB_DEVICE_QUALIFIER_DESCRIPTOR ),
.bDescriptorType = USB_QUALIFIER_DESCRIPTOR_TYPE,
.bcdUSB = 0x0200, /* 2.0 */
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.bNumConfigurations = 1,
.bReserved = 0,
};
#if defined ( __ICCARM__ )
#pragma data_alignment=4
#endif
__ALIGN_BEGIN static struct t_pcanpro_description pcanpro_dev __ALIGN_END =
{
.con0 =
{
.bLength = sizeof( USB_CONFIGURATION_DESCRIPTOR ),
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE,
.wTotalLength = sizeof( struct t_pcanpro_description ),
#if INCLUDE_LIN_INTERFACE
.bNumInterfaces = 2,
#else
.bNumInterfaces = 1,
#endif
.bConfigurationValue = 1,
.iConfiguration = 4,
.bmAttributes = USB_CONFIG_BUS_POWERED,
.MaxPower = 120, /* = 240mA */
},
/* CAN INTERFACE */
.if0 =
{
.bLength = sizeof( USB_INTERFACE_DESCRIPTOR ),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
#if ( PCAN_PRO ) || ( PCAN_PRO_FD ) || ( PCAN_X6)
.bNumEndpoints = 6,
#else
.bNumEndpoints = 4,
#endif
.bInterfaceClass = 0,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 5,
},
.ep1_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_CMDIN,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep2_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_CMDOUT,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep3_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGIN_CH1,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep4_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGOUT_CH1,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
#if ( PCAN_PRO ) || ( PCAN_PRO_FD ) || ( PCAN_X6)
.ep5_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGIN_CH2, /* not used */
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep6_i0 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = PCAN_USB_EP_MSGOUT_CH2,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
#endif
#if INCLUDE_LIN_INTERFACE
/* LIN INTERFACE */
.if1 =
{
.bLength = sizeof( USB_INTERFACE_DESCRIPTOR ),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE,
.bInterfaceNumber = 1,
.bAlternateSetting = 0,
.bNumEndpoints = 6,
.bInterfaceClass = 0,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 6,
},
.ep1_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x84,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep2_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x04,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep3_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x85,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep4_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x05,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep5_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x86,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
},
.ep6_i1 =
{
.bLength = sizeof( USB_ENDPOINT_DESCRIPTOR ),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE,
.bEndpointAddress = 0x06,
.bmAttributes = USB_ENDPOINT_TYPE_BULK,
.wMaxPacketSize = 64,/* FS: 64, HS: 512 */
.bInterval = 0,
}
#endif
};
static uint8_t device_init( USBD_HandleTypeDef *pdev, uint8_t cfgidx )
{
USB_ENDPOINT_DESCRIPTOR *p_ep = &pcanpro_dev.ep1_i0;
for( int i = 0; i < pcanpro_dev.if0.bNumEndpoints; i++ )
{
uint8_t ep_addr = p_ep[i].bEndpointAddress;
if( p_ep[i].bmAttributes == USB_ENDPOINT_TYPE_BULK )
{
if( pdev->dev_speed == USBD_SPEED_FULL )
p_ep[i].wMaxPacketSize = PCAN_FS_MAX_BULK_PACKET_SIZE;
else if( pdev->dev_speed == USBD_SPEED_HIGH )
p_ep[i].wMaxPacketSize = PCAN_HS_MAX_BULK_PACKET_SIZE;
else
assert( 0 );
}
USBD_LL_OpenEP( pdev, ep_addr,
p_ep[i].bmAttributes,
p_ep[i].wMaxPacketSize );
if( ( ep_addr & 0x80 ) != 0 )
pdev->ep_in[ep_addr & EP_ADDR_MSK].is_used = 1;
else
pdev->ep_out[ep_addr & EP_ADDR_MSK].is_used = 1;
}
pdev->pClassData = (void*)&pcanpro_data;
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_CMDOUT, pcanpro_data.cmd_ep_buffer, sizeof( pcanpro_data.cmd_ep_buffer ) );
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_MSGOUT_CH1, pcanpro_data.data1_ep_buffer, sizeof( pcanpro_data.data1_ep_buffer ) );
USBD_LL_PrepareReceive( pdev, PCAN_USB_EP_MSGOUT_CH2, pcanpro_data.data2_ep_buffer, sizeof( pcanpro_data.data2_ep_buffer ) );
return USBD_OK;
}
static uint8_t device_deinit( USBD_HandleTypeDef *pdev, uint8_t cfgidx )
{
USB_ENDPOINT_DESCRIPTOR const *p_ep = &pcanpro_dev.ep1_i0;
for( int i = 0; i < pcanpro_dev.if0.bNumEndpoints; i++ )
{
uint8_t ep_addr = p_ep[i].bEndpointAddress;
USBD_LL_FlushEP( pdev, ep_addr );
USBD_LL_CloseEP( pdev, ep_addr );
if( ( ep_addr & 0x80 ) != 0 )
pdev->ep_in[ep_addr & EP_ADDR_MSK].is_used = 0;
else
pdev->ep_out[ep_addr & EP_ADDR_MSK].is_used = 0;
}
pdev->pClassData = (void*)0;
#if 0
PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
USB_DevDisconnect( hpcd->Instance );
HAL_Delay( 250 );
USB_DevConnect( hpcd->Instance );
#endif
return USBD_OK;
}
static uint8_t device_setup( USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req )
{
switch( req->bmRequest & USB_REQ_TYPE_MASK )
{
case USB_REQ_TYPE_VENDOR:
return pcan_protocol_device_setup( pdev, req );
case USB_REQ_TYPE_CLASS:
return USBD_OK;
case USB_REQ_TYPE_STANDARD:
return USBD_OK;
default:
USBD_CtlError( pdev, req );
return USBD_FAIL;
}
}
static uint8_t device_ep0_rx_ready( USBD_HandleTypeDef *pdev )
{
pcan_ep0_receive();
return USBD_OK;
}
static uint8_t device_data_in( USBD_HandleTypeDef *pdev, uint8_t epnum )
{
struct t_class_data *p_data = (void*)pdev->pClassData;
if( pdev->pClassData == 0 )
return USBD_FAIL;
/* use ZLP */
#if 1
PCD_HandleTypeDef *hpcd = pdev->pData;
uint32_t len = pdev->ep_in[epnum].total_length;
/* packet is multiple of maxpacket, so tell host what all transfer is done */
if( len && ( len % hpcd->IN_ep[epnum].maxpacket ) == 0U )
{
/* update the packet total length */
pdev->ep_in[epnum].total_length = 0U;
/* send ZLP */
USBD_LL_Transmit( pdev, epnum, NULL, 0U );
}
else
{
/* tx done, no active transfer */
p_data->ep_tx_in_use[epnum] = 0;
}
#else
pdev->ep_in[epnum].total_length = 0U;
p_data->ep_tx_in_use[epnum] = 0;
#endif
return USBD_OK;
}
static uint8_t device_data_out( USBD_HandleTypeDef *pdev, uint8_t epnum )
{
int size;
if( pdev->pClassData == 0 )
return USBD_FAIL;
size = USBD_LL_GetRxDataSize( pdev, epnum );
if( epnum == PCAN_USB_EP_CMDOUT )
{
pcan_protocol_process_data( epnum, pcanpro_data.cmd_ep_buffer, size );
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.cmd_ep_buffer, sizeof( pcanpro_data.cmd_ep_buffer ) );
}
else if( epnum == PCAN_USB_EP_MSGOUT_CH1 )
{
pcan_protocol_process_data( epnum, pcanpro_data.data1_ep_buffer, size );
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.data1_ep_buffer, sizeof( pcanpro_data.data1_ep_buffer ) );
}
else if( epnum == PCAN_USB_EP_MSGOUT_CH2 )
{
pcan_protocol_process_data( epnum, pcanpro_data.data2_ep_buffer, size );
USBD_LL_PrepareReceive( pdev, epnum, pcanpro_data.data2_ep_buffer, sizeof( pcanpro_data.data2_ep_buffer ) );
}
else
{
return USBD_FAIL;
}
return USBD_OK;
}
static uint8_t *device_get_hs_cfg( uint16_t *length )
{
*length = sizeof( struct t_pcanpro_description );
return (void*)&pcanpro_dev;
}
static uint8_t *device_get_fs_cfg( uint16_t *length )
{
*length = sizeof( struct t_pcanpro_description );
return (void*)&pcanpro_dev;
}
static uint8_t *device_get_other_speed_cfg( uint16_t *length )
{
*length = sizeof( struct t_pcanpro_description );
return (void*)&pcanpro_dev;
}
uint8_t *device_get_device_qualifier( uint16_t *length )
{
*length = sizeof( USB_DEVICE_QUALIFIER_DESCRIPTOR );
return (void*)&dev_qua;
}
static uint8_t sof_handler( struct _USBD_HandleTypeDef *pdev )
{
uint32_t USBx_BASE = (uint32_t)(((PCD_HandleTypeDef *)pdev->pData)->Instance);
(void)USBx_BASE;
//vn_data_handler_sof( (USBx_DEVICE->DSTS>>8u)&0x3FFFu );
return USBD_OK;
}
static uint8_t *device_get_user_string( USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length )
{
__ALIGN_BEGIN static uint8_t USBD_StrDesc[64] __ALIGN_END;
UNUSED( pdev );
switch( index )
{
case 6:
#if PCAN_PRO_FD
USBD_GetString((uint8_t *)"PCAN-USB Pro FD LIN", USBD_StrDesc, length );
break;
#elif PCAN_PRO
USBD_GetString((uint8_t *)"PCAN-USB-PRO LIN Device", USBD_StrDesc, length );
break;
#else
/* fallthrough */
#endif
default:
USBD_GetString((uint8_t *)"UNHANDLED", USBD_StrDesc, length );
break;
}
return USBD_StrDesc;
}
USBD_ClassTypeDef usbd_pcanpro =
{
.Init = device_init,
.DeInit = device_deinit,
.Setup = device_setup,
.EP0_TxSent = 0,
.EP0_RxReady = device_ep0_rx_ready,
.DataIn = device_data_in,
.DataOut = device_data_out,
.SOF = sof_handler,
.IsoINIncomplete = 0,
.IsoOUTIncomplete = 0,
.GetHSConfigDescriptor = device_get_hs_cfg,
.GetFSConfigDescriptor = device_get_fs_cfg,
.GetOtherSpeedConfigDescriptor = device_get_other_speed_cfg,
.GetDeviceQualifierDescriptor = device_get_device_qualifier,
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
.GetUsrStrDescriptor = device_get_user_string,
#endif
};