/* ********************************************************************************************************* * uC/USB-Host * The Embedded USB Host Stack * * Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com * * SPDX-License-Identifier: APACHE-2.0 * * This software is subject to an open source license and is distributed by * Silicon Laboratories Inc. pursuant to the terms of the Apache License, * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. * ********************************************************************************************************* */ /* ********************************************************************************************************* * * FUTURE TECHNOLOGY DEVICES INTERNATIONAL CLASS * * Filename : usbh_ftdi.c * Version : V3.42.01 * Note(s) : The reference document "API for FTxxxx Devices Application Note AN_115" can be * requested from FTDI after signing a Non-Disclosure Agreement (NDA). ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define USBH_FTDI_MODULE #define MICRIUM_SOURCE #include "usbh_ftdi.h" #include "../../Source/usbh_core.h" /* ********************************************************************************************************* * LOCAL DEFINES ********************************************************************************************************* */ /* ********************************************************************************************************* * FTDI VENDOR ID * * Note(s) : (1) See "API for FTxxxx Devices Application Note AN_115", April 04 2011, Version 1.1, * section 2. * * (2) The 'idVendor' field of the device descriptor may contain this value. * ********************************************************************************************************* */ #define USBH_FTDI_ID_VENDOR 0x0403u /* ********************************************************************************************************* * FTDI PRODUCT IDs * * Note(s) : (1) See "API for FTxxxx Devices Application Note AN_115", April 04 2011, Version 1.1, * section 2. * * (2) The 'idProduct' field of the device descriptor may contain one of these values. * ********************************************************************************************************* */ #define USBH_FTDI_ID_PRODUCT_FT8U232AM 0x6001u #define USBH_FTDI_ID_PRODUCT_FT232B 0x6001u #define USBH_FTDI_ID_PRODUCT_FT2232D 0x6010u #define USBH_FTDI_ID_PRODUCT_FT232R 0x6001u #define USBH_FTDI_ID_PRODUCT_FT2232H 0x6010u #define USBH_FTDI_ID_PRODUCT_FT4232H 0x6011u #define USBH_FTDI_ID_PRODUCT_FT232H 0x6014u /* ********************************************************************************************************* * CLASS-SPECIFIC REQUESTS * * Note(s) : (1) See "API for FTxxxx Devices Application Note AN_115", April 04 2011, Version 1.1, * section 3. * * (2) The 'bRequest' field of a class-specific setup request may contain one of these values. * ********************************************************************************************************* */ #define USBH_FTDI_REQ_RESET 0x00u #define USBH_FTDI_REQ_SET_MODEM_CTRL 0x01u #define USBH_FTDI_REQ_SET_FLOW_CTRL 0x02u #define USBH_FTDI_REQ_SET_BAUD_RATE 0x03u #define USBH_FTDI_REQ_SET_DATA 0x04u #define USBH_FTDI_REQ_GET_MODEM_STATUS 0x05u /* ********************************************************************************************************* * USBH_FTDI_FNCT * * Note(s) : (1) FTDI device main structure. * ********************************************************************************************************* */ typedef struct usbh_ftdi_fnct { USBH_FTDI_HANDLE Handle; /* Handle of FTDI dev struct. */ USBH_DEV *DevPtr; /* Ptr to dev struct. */ USBH_IF *IF_Ptr; /* Ptr to IF struct. */ USBH_EP BulkInEP; /* Bulk IN EP. */ USBH_EP BulkOutEP; /* Bulk OUT EP. */ CPU_INT08U Port; /* Holds cur port. */ CPU_INT08U State; /* Holds cur dev state. */ CPU_INT32U MaxPktSize; /* Holds max pkt size. */ USBH_HMUTEX RxHMutex; /* Handle on RX mutex. */ USBH_FTDI_ASYNC_TX_FNCT DataTxNotifyPtr; /* Ptr to TX callback fnct. */ void *DataTxNotifyArgPtr; /* Ptr to TX notify arg. */ USBH_FTDI_ASYNC_RX_FNCT DataRxNotifyPtr; /* Ptr to RX callback fnct. */ void *DataRxNotifyArgPtr; /* Ptr to RX notify arg. */ void *DataRxBuf; /* Ptr to data RX buf. */ USBH_FTDI_SERIAL_STATUS *SerialStatusPtr; /* Ptr to serial status. */ CPU_INT32U RxBufLen; /* Size of RX buf. */ CPU_INT32U XferLen; /* Tot len of data rx'd in octets. */ CPU_INT16U LastBytes; /* Last two bytes of last RX pkt. */ } USBH_FTDI_FNCT; /* ********************************************************************************************************* * LOCAL CONSTANTS ********************************************************************************************************* */ static USBH_CLASS_DRV USBH_FTDI_ClassDrv; /* FTDI Class drv API. */ /* ********************************************************************************************************* * LOCAL DATA TYPES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL TABLES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL GLOBAL VARIABLES ********************************************************************************************************* */ static USBH_FTDI_FNCT USBH_FTDI_DevTbl[USBH_FTDI_CFG_MAX_DEV]; static MEM_POOL USBH_FTDI_DevPool; static USBH_DEV *USBH_FTDI_DevPtrPrev; /* Last conn'd dev addr. */ static CPU_INT08U USBH_FTDI_PortCnt; /* Cnt nbr of port of a dev. */ /* ********************************************************************************************************* * LOCAL MACROS ********************************************************************************************************* */ #define USBH_FTDI_HANDLE_IX_GET(ftdi_handle) ((CPU_INT08U)ftdi_handle); /* ********************************************************************************************************* * USBH CLASS DRIVER API PROTOTYPES ********************************************************************************************************* */ static void USBH_FTDI_GlobalInit (USBH_ERR *p_err); static void *USBH_FTDI_ProbeIF (USBH_DEV *p_dev, USBH_IF *p_if, USBH_ERR *p_err); static void USBH_FTDI_Suspend (void *p_class_dev); static void USBH_FTDI_Resume (void *p_class_dev); static void USBH_FTDI_Disconn (void *p_class_dev); static void USBH_FTDI_ClassDevNotify(void *p_class_dev, CPU_INT08U state, void *p_ctx); /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */ static void USBH_FTDI_StdReq (USBH_FTDI_HANDLE ftdi_handle, CPU_INT08U request, CPU_INT16U value, CPU_INT08U index, USBH_ERR *p_err); static void USBH_FTDI_DataTxCmpl (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U xfer_len, void *p_arg, USBH_ERR err); static void USBH_FTDI_DataRxCmpl (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U xfer_len, void *p_arg, USBH_ERR err); /* ********************************************************************************************************* * LOCAL CONFIGURATION ERRORS ********************************************************************************************************* */ /* ********************************************************************************************************* * FTDI CLASS DRIVER ********************************************************************************************************* */ static USBH_CLASS_DRV USBH_FTDI_ClassDrv = { (CPU_INT08U *)"FTDI", USBH_FTDI_GlobalInit, 0, USBH_FTDI_ProbeIF, USBH_FTDI_Suspend, USBH_FTDI_Resume, USBH_FTDI_Disconn }; /* ********************************************************************************************************* ********************************************************************************************************* * GLOBAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * USBH_FTDI_Init() * * Description : Initialize the global variables of the FTDI Class. * * Argument(s) : p_ftdi_callbacks Callback functions structure to notify application when a FTDI device * is connected/disconnected. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Interface is of FTDI type. * USBH_ERR_DEV_ALLOC, Cannot allocate FTDI device. * * ----- RETURNED BY USBH_ClassDrvReg() : ----- * USBH_ERR_INVALID_ARG, If invalid argument(s) passed to 'p_host'/'p_class_drv'. * USBH_ERR_CLASS_DRV_ALLOC, If maximum class driver limit reached. * * ----- RETURNED BY USBH_OS_MutexCreate() : ----- * USBH_ERR_ALLOC, Cannot allocate mutex. * USBH_ERR_OS_SIGNAL_CREATE Cannot create mutex. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ void USBH_FTDI_Init (USBH_FTDI_CALLBACKS *p_ftdi_callbacks, USBH_ERR *p_err) { CPU_SIZE_T octets_reqd; CPU_INT08U ix; LIB_ERR err_lib; Mem_PoolCreate( &USBH_FTDI_DevPool, (void *)USBH_FTDI_DevTbl, (sizeof(USBH_FTDI_FNCT) * USBH_FTDI_CFG_MAX_DEV), USBH_FTDI_CFG_MAX_DEV, sizeof(USBH_FTDI_FNCT), sizeof(CPU_ALIGN), &octets_reqd, &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { *p_err = USBH_ERR_ALLOC; return; } for (ix = 0u; ix < USBH_FTDI_CFG_MAX_DEV; ix++) { *p_err = USBH_OS_MutexCreate(&USBH_FTDI_DevTbl[ix].RxHMutex); if (*p_err != USBH_ERR_NONE) { return; } USBH_FTDI_DevTbl[ix].Handle = (USBH_FTDI_HANDLE)ix; USBH_FTDI_DevTbl[ix].State = USBH_CLASS_DEV_STATE_NONE; } USBH_FTDI_DevPtrPrev = (void *)0; USBH_FTDI_PortCnt = 0u; *p_err = USBH_ClassDrvReg( &USBH_FTDI_ClassDrv, USBH_FTDI_ClassDevNotify, (void *)p_ftdi_callbacks); } /* ********************************************************************************************************* * USBH_FTDI_Reset() * * Description : Reset the communication port. * * Argument(s) : ftdi_handle Handle on FTDI device. * * reset_ctrl Select buffer to reset. This is a bitmap of the following possible values: * * USBH_FTDI_RESET_CTRL_SIO, Reset SIO (Resets both RX and TX buffer). * USBH_FTDI_RESET_CTRL_RX, Purge RX buffer. * USBH_FTDI_RESET_CTRL_TX Purge TX buffer. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'reset_ctrl'. * * ----- RETURNED BY USBH_FTDI_StdReq() : ----- * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller error code Otherwise. * * Return(s) : None. * * Note(s) : For more information on the 'Reset' request, see 'API for FTxxxx Devices Application * Note AN_115, April 04 2011, Version 1.1, section 3.1'. ********************************************************************************************************* */ void USBH_FTDI_Reset (USBH_FTDI_HANDLE ftdi_handle, CPU_INT16U reset_ctrl, USBH_ERR *p_err) { if ((reset_ctrl != USBH_FTDI_RESET_CTRL_SIO) && (reset_ctrl != USBH_FTDI_RESET_CTRL_RX) && (reset_ctrl != USBH_FTDI_RESET_CTRL_TX)) { *p_err = USBH_ERR_INVALID_ARG; return; } USBH_FTDI_StdReq(ftdi_handle, /* Send Reset req. */ USBH_FTDI_REQ_RESET, reset_ctrl, 0u, p_err); } /* ********************************************************************************************************* * USBH_FTDI_ModemCtrlSet() * * Description : Set modem control register of the communication port. * * Argument(s) : ftdi_handle Handle on FTDI device. * * modem_ctrl Modem control value. This is a bitmap of the following possible values: * * USBH_FTDI_MODEM_CTRL_DTR_SET, Set DTR state. * USBH_FTDI_MODEM_CTRL_DTR_RESET, Reset DTR state. * USBH_FTDI_MODEM_CTRL_DTR_ENABLED, Use DTR state. * USBH_FTDI_MODEM_CTRL_DTR_DISABLED, Disable DTR state. * * USBH_FTDI_MODEM_CTRL_RTS_SET, Set RTS state. * USBH_FTDI_MODEM_CTRL_RTS_RESET, Reset RTS state. * USBH_FTDI_MODEM_CTRL_RTS_ENABLED, Use RTS state. * USBH_FTDI_MODEM_CTRL_RTS_DISABLED Disable RTS state. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'modem_ctrl'. * * ----- RETURNED BY USBH_FTDI_StdReq() : ----- * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller error code Otherwise. * * Return(s) : None. * * Note(s) : For more information on the 'ModemCtrl' request, see 'API for FTxxxx Devices Application * Note AN_115, April 04 2011, Version 1.1, section 3.2'. ********************************************************************************************************* */ void USBH_FTDI_ModemCtrlSet (USBH_FTDI_HANDLE ftdi_handle, CPU_INT16U modem_ctrl, USBH_ERR *p_err) { if ((modem_ctrl & 0xFCFCu) != 0u) { *p_err = USBH_ERR_INVALID_ARG; return; } USBH_FTDI_StdReq(ftdi_handle, /* Send ModemCtrl req. */ USBH_FTDI_REQ_SET_MODEM_CTRL, modem_ctrl, 0u, p_err); } /* ********************************************************************************************************* * USBH_FTDI_FlowCtrlSet() * * Description : Set flow control handshaking for the communication port. * * Argument(s) : ftdi_handle Handle on FTDI device. * * protocol Protocol to set. This is a bitmap of the following possible values: * * USBH_FTDI_PROTOCOL_RTS_CTS, Enable output handshaking using RTS/CTS. * USBH_FTDI_PROTOCOL_DTR_DSR, Enable output handshaking using DTR/DSR. * USBH_FTDI_PROTOCOL_XON_XOFF Enable Xon/Xoff handshaking. * * xon_char Xon character. * * xoff_char Xoff character. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'xon_char'/ * 'xoff_char'/'protocol'. * * ----- RETURNED BY USBH_FTDI_StdReq() : ----- * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller error code Otherwise. * * Return(s) : None. * * Note(s) : For more information on the 'SetFlowCtrl' request, see 'API for FTxxxx Devices * Application Note AN_115, April 04 2011, Version 1.1, section 3.3'. ********************************************************************************************************* */ void USBH_FTDI_FlowCtrlSet (USBH_FTDI_HANDLE ftdi_handle, CPU_INT08U protocol, CPU_INT08U xon_char, CPU_INT08U xoff_char, USBH_ERR *p_err) { CPU_INT16U value; if ((protocol != USBH_FTDI_PROTOCOL_RTS_CTS) && (protocol != USBH_FTDI_PROTOCOL_DTR_DSR) && (protocol != USBH_FTDI_PROTOCOL_XON_XOFF) && (protocol != DEF_BIT_NONE)) { *p_err = USBH_ERR_INVALID_ARG; return; } value = (CPU_INT16U)(((CPU_INT16U)xoff_char << 8u) | xon_char); USBH_FTDI_StdReq(ftdi_handle, /* Send SetFlowCtrl req. */ USBH_FTDI_REQ_SET_FLOW_CTRL, value, protocol, p_err); } /* ********************************************************************************************************* * USBH_FTDI_BaudRateSet() * * Description : Set baud rate of the communication port. * * Argument(s) : ftdi_handle Handle on FTDI device. * * baud_rate Baud rate to set. * * USBH_FTDI_BAUD_RATE_300, Set baud rate to 300 bits/sec. * USBH_FTDI_BAUD_RATE_600, Set baud rate to 600 bits/sec. * USBH_FTDI_BAUD_RATE_1200, Set baud rate to 1200 bits/sec. * USBH_FTDI_BAUD_RATE_2400, Set baud rate to 2400 bits/sec. * USBH_FTDI_BAUD_RATE_4800, Set baud rate to 4800 bits/sec. * USBH_FTDI_BAUD_RATE_9600, Set baud rate to 9600 bits/sec. * USBH_FTDI_BAUD_RATE_19200, Set baud rate to 19200 bits/sec. * USBH_FTDI_BAUD_RATE_38400, Set baud rate to 38400 bits/sec. * USBH_FTDI_BAUD_RATE_57600, Set baud rate to 57600 bits/sec. * USBH_FTDI_BAUD_RATE_115200, Set baud rate to 115200 bits/sec. * USBH_FTDI_BAUD_RATE_230400, Set baud rate to 230400 bits/sec. * USBH_FTDI_BAUD_RATE_460800, Set baud rate to 460800 bits/sec. * USBH_FTDI_BAUD_RATE_921600 Set baud rate to 921600 bits/sec. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'baud_rate'. * * ----- RETURNED BY USBH_FTDI_StdReq() : ----- * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller error code Otherwise. * * Return(s) : None. * * Note(s) : For more information on the 'SetBaudRate' request, see 'API for FTxxxx Devices * Application Note AN_115, April 04 2011, Version 1.1, section 3.4'. ********************************************************************************************************* */ void USBH_FTDI_BaudRateSet (USBH_FTDI_HANDLE ftdi_handle, CPU_INT16U baud_rate, USBH_ERR *p_err) { if ((baud_rate != USBH_FTDI_BAUD_RATE_300) && (baud_rate != USBH_FTDI_BAUD_RATE_600) && (baud_rate != USBH_FTDI_BAUD_RATE_1200) && (baud_rate != USBH_FTDI_BAUD_RATE_2400) && (baud_rate != USBH_FTDI_BAUD_RATE_4800) && (baud_rate != USBH_FTDI_BAUD_RATE_9600) && (baud_rate != USBH_FTDI_BAUD_RATE_19200) && (baud_rate != USBH_FTDI_BAUD_RATE_38400) && (baud_rate != USBH_FTDI_BAUD_RATE_57600) && (baud_rate != USBH_FTDI_BAUD_RATE_115200) && (baud_rate != USBH_FTDI_BAUD_RATE_230400) && (baud_rate != USBH_FTDI_BAUD_RATE_460800) && (baud_rate != USBH_FTDI_BAUD_RATE_921600)) { *p_err = USBH_ERR_INVALID_ARG; return; } USBH_FTDI_StdReq(ftdi_handle, /* Send SetBaudRate req. */ USBH_FTDI_REQ_SET_BAUD_RATE, baud_rate, 0u, p_err); } /* ********************************************************************************************************* * USBH_FTDI_DataSet() * * Description : Set data characteristics of the communication port. * * Argument(s) : ftdi_handle Handle on FTDI device. * * data_size Number of data bits. * * parity Parity to use. * * USBH_FTDI_DATA_PARITY_NONE, Do not use the parity bit. * USBH_FTDI_DATA_PARITY_ODD, Use odd parity bit. * USBH_FTDI_DATA_PARITY_EVEN, Use even parity bit. * USBH_FTDI_DATA_PARITY_MARK, Use mark parity bit. * USBH_FTDI_DATA_PARITY_SPACE Use space parity bit. * * stop_bits Number of stop bits. * * USBH_FTDI_DATA_STOP_BITS_1, Use 1 stop bit. * USBH_FTDI_DATA_STOP_BITS_2 Use 2 stop bit. * * break_bit Send break. * * USBH_FTDI_DATA_BREAK_ENABLED, Send break. * USBH_FTDI_DATA_BREAK_DISABLED Stop break. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'parity'/ * 'stop_bits'/'break_bit'. * * ----- RETURNED BY USBH_FTDI_StdReq() : ----- * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller error code Otherwise. * * Return(s) : None. * * Note(s) : For more information on the 'SetData' request, see 'API for FTxxxx Devices Application * Note AN_115, April 04 2011, Version 1.1, section 3.5'. ********************************************************************************************************* */ void USBH_FTDI_DataSet (USBH_FTDI_HANDLE ftdi_handle, CPU_INT08U data_size, CPU_INT08U parity, CPU_INT08U stop_bits, CPU_INT08U break_bit, USBH_ERR *p_err) { CPU_INT16U value; if ((parity != USBH_FTDI_DATA_PARITY_NONE) && (parity != USBH_FTDI_DATA_PARITY_ODD) && (parity != USBH_FTDI_DATA_PARITY_EVEN) && (parity != USBH_FTDI_DATA_PARITY_MARK) && (parity != USBH_FTDI_DATA_PARITY_SPACE)) { *p_err = USBH_ERR_INVALID_ARG; return; } if ((stop_bits != USBH_FTDI_DATA_STOP_BITS_1) && (stop_bits != USBH_FTDI_DATA_STOP_BITS_2)) { *p_err = USBH_ERR_INVALID_ARG; return; } if ((break_bit != USBH_FTDI_DATA_BREAK_ENABLED) && (break_bit != USBH_FTDI_DATA_BREAK_DISABLED)) { *p_err = USBH_ERR_INVALID_ARG; return; } value = (CPU_INT16U)(((CPU_INT16U)(parity | stop_bits | break_bit) << 8u) | data_size); USBH_FTDI_StdReq(ftdi_handle, /* Send SetData req. */ USBH_FTDI_REQ_SET_DATA, value, 0u, p_err); } /* ********************************************************************************************************* * USBH_FTDI_ModemStatusGet() * * Description : Retrieve the current value of the serial status register. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_serial_status Pointer to USBH_FTDI_SERIAL_STATUS structure that will be filled by this function. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'/ * 'p_serial_status'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * Host controller drivers error code, Otherwise. * * Return(s) : None. * * Note(s) : (1) The device updates the serial status every 16 milliseconds. * * (2) The following masks may be used to determine if a bit of the modem status is set: * * USBH_FTDI_MODEM_STATUS_FS * USBH_FTDI_MODEM_STATUS_HS * USBH_FTDI_MODEM_STATUS_CLEAR_TO_SEND * USBH_FTDI_MODEM_STATUS_DATA_SET_READY * USBH_FTDI_MODEM_STATUS_RING_INDICATOR * USBH_FTDI_MODEM_STATUS_DATA_CARRIER_DETECT * * (3) The following masks may be used to determine if a bit of the line status is set: * * USBH_FTDI_LINE_STATUS_RX_OVERFLOW_ERROR * USBH_FTDI_LINE_STATUS_PARITY_ERROR * USBH_FTDI_LINE_STATUS_FRAMING_ERROR * USBH_FTDI_LINE_STATUS_BREAK_INTERRUPT * USBH_FTDI_LINE_STATUS_TX_REGISTER_EMPTY * USBH_FTDI_LINE_STATUS_TX_EMPTY * * (4) For more information on the 'GetModemStat' request, see 'API for FTxxxx Devices * Application Note AN_115, April 04 2011, Version 1.1, section 3.6'. ********************************************************************************************************* */ void USBH_FTDI_ModemStatusGet (USBH_FTDI_HANDLE ftdi_handle, USBH_FTDI_SERIAL_STATUS *p_serial_status, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; CPU_INT08U status[USBH_FTDI_SERIAL_STATUS_LEN]; if (p_serial_status == (void *)0){ *p_err = USBH_ERR_INVALID_ARG; return; } ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return; } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return; } (void)USBH_CtrlRx( p_ftdi_fnct->DevPtr, /* Send GET_MODEM_STATUS req. */ USBH_FTDI_REQ_GET_MODEM_STATUS, (USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_VENDOR | USBH_REQ_RECIPIENT_DEV), 0u, p_ftdi_fnct->Port, (void *)&status, USBH_FTDI_SERIAL_STATUS_LEN, USBH_CFG_STD_REQ_TIMEOUT, p_err); if (*p_err != USBH_ERR_NONE) { return; } p_serial_status->ModemStatus = status[0u]; p_serial_status->LineStatus = status[1u]; } /* ********************************************************************************************************* * USBH_FTDI_Tx() * * Description : Send data to FTDI device. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_buf Pointer to buffer that contains the data to transfer. * * buf_len Buffer length, in octets. * * timeout Timeout, in milliseconds. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Data successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'/ * 'buf_len'. * USBH_ERR_NULL_PTR, Invalid null pointer passed to 'p_buf'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * * ----- RETURNED BY USBH_BulkTx() : ----- * USBH_ERR_NONE, Bulk transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE, Endpoint type is not Bulk or direction is not OUT. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * Host controller drivers error code Otherwise. * * Return(s) : Number of octets transferred, if NO error(s). * * 0, otherwise. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_FTDI_Tx (USBH_FTDI_HANDLE ftdi_handle, void *p_buf, CPU_INT32U buf_len, CPU_INT16U timeout, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; CPU_INT32U xfer_len; if (buf_len == 0u) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } if (p_buf == (void *)0) { *p_err = USBH_ERR_NULL_PTR; return (0u); } ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return (0u); } xfer_len = USBH_BulkTx(&p_ftdi_fnct->BulkOutEP, /* Send data through specified EP to FTDI dev. */ p_buf, buf_len, timeout, p_err); if (*p_err != USBH_ERR_NONE) { /* Reset EP if err occurred. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, &p_ftdi_fnct->BulkOutEP); if (*p_err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(&p_ftdi_fnct->BulkOutEP); } return (0u); } return (xfer_len); } /* ********************************************************************************************************* * USBH_FTDI_TxAsync() * * Description : Send data to FTDI device. This function is non blocking. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_buf Pointer to buffer of data that will be sent. * * buf_len Buffer length in octets. * * tx_cmpl_notify Function that will be invoked upon completion of transmit operation. * * p_arg Pointer to argument that will be passed as parameter of 'tx_cmpl_notify'. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, If data successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'/ * 'buf_len'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * USBH_ERR_NULL_PTR, Invalid null pointer passed to 'p_buf'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * * ----- RETURNED BY USBH_BulkTxAsync() : ----- * USBH_ERR_NONE, If request is successfully submitted. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE, If endpoint type is not bulk or direction is * not OUT. * USBH_ERR_EP_INVALID_STATE, If endpoint is not opened. * USBH_ERR_ALLOC, If URB cannot be allocated. * USBH_ERR_UNKNOWN, If unknown error occured. * Host controller drivers error code Otherwise. * * Return(s) : None. * * Note(s) : (1) Asynchronous transmit is not thread safe. Hence, it is not safe to call this function * from more than 1 application task at the same time for the same device. It is however * safe to call it from the completion callback. ********************************************************************************************************* */ void USBH_FTDI_TxAsync (USBH_FTDI_HANDLE ftdi_handle, void *p_buf, CPU_INT32U buf_len, USBH_FTDI_ASYNC_TX_FNCT tx_cmpl_notify, void *p_arg, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; if (buf_len == 0u) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_buf == (void *)0) { *p_err = USBH_ERR_NULL_PTR; return; } ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return; } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return; } p_ftdi_fnct->DataTxNotifyPtr = tx_cmpl_notify; p_ftdi_fnct->DataTxNotifyArgPtr = p_arg; *p_err = USBH_BulkTxAsync( &p_ftdi_fnct->BulkOutEP, /* Send data through specified EP to FTDI dev. */ p_buf, buf_len, USBH_FTDI_DataTxCmpl, (void *)p_ftdi_fnct); if (*p_err != USBH_ERR_NONE) { /* Reset EP if an err occurred. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, &p_ftdi_fnct->BulkOutEP); if (*p_err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(&p_ftdi_fnct->BulkOutEP); } } } /* ********************************************************************************************************* * USBH_FTDI_Rx() * * Description : Receive data from FTDI device. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_buf Pointer to data buffer to hold received data. * * buf_len Buffer length, in octets. * * timeout Timeout, in milliseconds. * * p_serial_status Pointer to USBH_FTDI_SERIAL_STATUS structure that will be filled by this function. * This argument can be null. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Data successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'/ * 'buf_len'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * USBH_ERR_NULL_PTR, Invalid null pointer passed to 'p_buf'. * * * ----- RETURNED BY USBH_BulkRx() : ----- * USBH_ERR_NONE Bulk transfer successfully received. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * Host controller drivers error code Otherwise. * * Return(s) : Number of octets received, if NO error(s). * * 0, otherwise. * * Note(s) : (1) The following masks may be used to determine if a bit of the modem status is set: * * USBH_FTDI_MODEM_STATUS_FS * USBH_FTDI_MODEM_STATUS_HS * USBH_FTDI_MODEM_STATUS_CLEAR_TO_SEND * USBH_FTDI_MODEM_STATUS_DATA_SET_READY * USBH_FTDI_MODEM_STATUS_RING_INDICATOR * USBH_FTDI_MODEM_STATUS_DATA_CARRIER_DETECT * * (2) The following masks may be used to determine if a bit of the line status is set: * * USBH_FTDI_LINE_STATUS_RX_OVERFLOW_ERROR * USBH_FTDI_LINE_STATUS_PARITY_ERROR * USBH_FTDI_LINE_STATUS_FRAMING_ERROR * USBH_FTDI_LINE_STATUS_BREAK_INTERRUPT * USBH_FTDI_LINE_STATUS_TX_REGISTER_EMPTY * USBH_FTDI_LINE_STATUS_TX_EMPTY * * (3) The received data in 'p_buf' is in little-endian. * * (4) The FTDI device always add a status of two bytes at the beginning of every packet. * This function manage those status bytes in order to get the latest status followed * by the data in 'p_buf'. * This only applies when the application requests more than max packet size (MPS) - 2 bytes of data. * * +----+----+----+----+-----+---------+---------+-----+----- * (a) Receive first pkt in buffer. | S0 | S1 | D0 | D1 | ... | MPS - 2 | MPS - 1 | MPS | ... * +----+----+----+----+-----+---------+---------+-----+----- * | | * v v * +---------+-----+ * (b) Save the last two bytes of data. | MPS - 1 | MPS | * +---------+-----+ * * +----+----+----+----+-----+---------+-----+-----+---------+---------+----- * (c) Receive next pkt in buffer. | S0 | S1 | D0 | D1 | ... | MPS - 2 | S2 | S3 | MPS + 1 | MPS + 2 | ... * +----+----+----+----+-----+---------+-----+-----+---------+---------+----- * * +----+----+----+----+-----+---------+---------+-----+---------+---------+----- * (d) Update the status. | S2 | S3 | D0 | D1 | ... | MPS - 2 | S2 | S3 | MPS + 1 | MPS + 2 | ... * +----+----+----+----+-----+---------+---------+-----+---------+---------+----- * ^ ^ * | | * +---------+-----+ * (e) Restore the two bytes of data. | MPS - 1 | MPS | * +---------+-----+ * * (f) Repeat step (b) to (e) until the end of the buffer is reached or the last transfer size is * smaller than maxPktSize. * ********************************************************************************************************* */ CPU_INT32U USBH_FTDI_Rx (USBH_FTDI_HANDLE ftdi_handle, void *p_buf, CPU_INT32U buf_len, CPU_INT16U timeout, USBH_FTDI_SERIAL_STATUS *p_serial_status, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; CPU_INT32U xfer_len; CPU_INT32U xfer_len_cur; CPU_INT32U buf_len_cur; CPU_INT16U data; CPU_INT08U *p_buf_cur08; CPU_INT32U pkt_size_rem; CPU_INT32U nbr_pkt; CPU_INT32U ix; if (buf_len < 2u) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } if (p_buf == (void *)0) { *p_err = USBH_ERR_NULL_PTR; return (0u); } ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return (0u); } p_buf_cur08 = (CPU_INT08U *)p_buf; /* Get max nbr of rx pkt allowed. */ nbr_pkt = 1u + ((buf_len - 1u) / p_ftdi_fnct->MaxPktSize); (void)USBH_OS_MutexLock(p_ftdi_fnct->RxHMutex); for (ix = 0u; ix < nbr_pkt; ix++) { if (ix == 0u) { /* If first pkt. */ buf_len_cur = (nbr_pkt > 1u) ? p_ftdi_fnct->MaxPktSize : buf_len; } else { /* Ensure rx buf is large enough for another pkt. */ if (buf_len < (xfer_len + p_ftdi_fnct->MaxPktSize)) { buf_len_cur = (buf_len - xfer_len); } else { buf_len_cur = p_ftdi_fnct->MaxPktSize; } /* Save last two bytes of data. */ MEM_VAL_COPY_16(&data, (p_buf_cur08 - USBH_FTDI_SERIAL_STATUS_LEN)); if (p_serial_status != (void *)0) { /* Chk for line status error. */ if ((DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_RX_OVERFLOW_ERROR) == DEF_YES) || (DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_PARITY_ERROR) == DEF_YES) || (DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_FRAMING_ERROR) == DEF_YES)) { MEM_VAL_COPY_16(p_buf, p_buf_cur08); *p_err = USBH_ERR_FTDI_LINE; break; } } p_buf_cur08 -= USBH_FTDI_SERIAL_STATUS_LEN; } /* Rx pkt through specified EP. */ xfer_len_cur = USBH_BulkRx( &p_ftdi_fnct->BulkInEP, (void *)p_buf_cur08, buf_len_cur, timeout, p_err); if (*p_err != USBH_ERR_NONE) { /* Reset EP if err occurred. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, &p_ftdi_fnct->BulkInEP); if (*p_err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(&p_ftdi_fnct->BulkInEP); } (void)USBH_OS_MutexUnlock(p_ftdi_fnct->RxHMutex); return (0u); } if (ix == 0u) { /* If first pkt. */ xfer_len = xfer_len_cur; } else { xfer_len += (xfer_len_cur - USBH_FTDI_SERIAL_STATUS_LEN); MEM_VAL_COPY_16(p_buf, p_buf_cur08); /* Update status. */ MEM_VAL_COPY_16(p_buf_cur08, &data); /* Restore two bytes of data. */ } p_buf_cur08 += p_ftdi_fnct->MaxPktSize; if (p_serial_status != (void *)0) { p_serial_status->ModemStatus = *((CPU_INT08U *)p_buf); p_serial_status->LineStatus = *((CPU_INT08U *)p_buf + 1u); } pkt_size_rem = ((xfer_len - USBH_FTDI_SERIAL_STATUS_LEN) % (p_ftdi_fnct->MaxPktSize - USBH_FTDI_SERIAL_STATUS_LEN)); if ((xfer_len_cur == USBH_FTDI_SERIAL_STATUS_LEN) || /* Stop transfer if RX size is smaller than maxPktSize. */ (pkt_size_rem != 0u)) { break; } } (void)USBH_OS_MutexUnlock(p_ftdi_fnct->RxHMutex); return (xfer_len); } /* ********************************************************************************************************* * USBH_FTDI_RxAsync() * * Description : Receive data from FTDI device. This function is non blocking. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_buf Pointer to data buffer to hold received data. * * buf_len Buffer length in octets. * * p_serial_status Pointer to USBH_FTDI_SERIAL_STATUS structure that will be filled by this function. * This argument can be null. * * rx_cmpl_notify Function that will be invoked upon completion of receive operation. * * p_arg Pointer to argument that will be passed as parameter of 'rx_cmpl_notify'. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, If data successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'/ * 'buf_len'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * USBH_ERR_NULL_PTR, Invalid null pointer passed to 'p_buf'. * * ----- RETURNED BY USBH_BulkRxAsync() : ----- * USBH_ERR_NONE, If request is successfully submitted. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE, If endpoint type is not Bulk or direction is * not IN. * USBH_ERR_EP_INVALID_STATE, If endpoint is not opened. * USBH_ERR_ALLOC, If URB cannot be allocated. * USBH_ERR_UNKNOWN, If unknown error occured. * Host controller drivers error code Otherwise. * * Return(s) : None. * * Note(s) : (1) The following masks may be used to determine if a bit of the modem status is set: * * USBH_FTDI_MODEM_STATUS_FS * USBH_FTDI_MODEM_STATUS_HS * USBH_FTDI_MODEM_STATUS_CLEAR_TO_SEND * USBH_FTDI_MODEM_STATUS_DATA_SET_READY * USBH_FTDI_MODEM_STATUS_RING_INDICATOR * USBH_FTDI_MODEM_STATUS_DATA_CARRIER_DETECT * * (2) The following masks may be used to determine if a bit of the line status is set: * * USBH_FTDI_LINE_STATUS_RX_OVERFLOW_ERROR * USBH_FTDI_LINE_STATUS_PARITY_ERROR * USBH_FTDI_LINE_STATUS_FRAMING_ERROR * USBH_FTDI_LINE_STATUS_BREAK_INTERRUPT * USBH_FTDI_LINE_STATUS_TX_REGISTER_EMPTY * USBH_FTDI_LINE_STATUS_TX_EMPTY * * (3) Asynchronous receive is not thread safe. Hence, it is not safe to call this function * from more than 1 application task at the same time for the same device. It is however * safe to call it from the completion callback. ********************************************************************************************************* */ void USBH_FTDI_RxAsync (USBH_FTDI_HANDLE ftdi_handle, void *p_buf, CPU_INT32U buf_len, USBH_FTDI_SERIAL_STATUS *p_serial_status, USBH_FTDI_ASYNC_RX_FNCT rx_cmpl_notify, void *p_arg, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; if (buf_len < 2u) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_buf == (void *)0) { *p_err = USBH_ERR_NULL_PTR; return; } ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return; } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return; } p_ftdi_fnct->DataRxNotifyPtr = rx_cmpl_notify; p_ftdi_fnct->DataRxNotifyArgPtr = p_arg; p_ftdi_fnct->DataRxBuf = p_buf; p_ftdi_fnct->RxBufLen = buf_len; p_ftdi_fnct->SerialStatusPtr = p_serial_status; p_ftdi_fnct->XferLen = 0u; if (buf_len > p_ftdi_fnct->MaxPktSize) { buf_len = p_ftdi_fnct->MaxPktSize; } *p_err = USBH_BulkRxAsync( &p_ftdi_fnct->BulkInEP, /* Rx first pkt through specified EP. */ p_buf, buf_len, USBH_FTDI_DataRxCmpl, (void *)p_ftdi_fnct); if (*p_err != USBH_ERR_NONE) { (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, &p_ftdi_fnct->BulkInEP); if (*p_err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(&p_ftdi_fnct->BulkInEP); } } } /* ********************************************************************************************************* * USBH_FTDI_DevGet() * * Description : Retrieves the device informations. * * Argument(s) : ftdi_handle Handle on FTDI device. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, If device informations retrieved successfully. * USBH_ERR_INVALID_ARG Invalid argument passed to 'ftdi_handle' * * Return(s) : Pointer to FTDI device. * * Note(s) : None. * ********************************************************************************************************* */ USBH_DEV *USBH_FTDI_DevGet (USBH_FTDI_HANDLE ftdi_handle, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; *p_err = USBH_ERR_NONE; ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return ((USBH_DEV *)0); } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return ((USBH_DEV *)0); } return(p_ftdi_fnct->DevPtr); } /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTION ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * USBH_FTDI_GlobalInit() * * Description : Not used but it has to be called by the host stack. * * Argument(s) : p_err Returns 'USBH_ERR_NONE'. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_GlobalInit (USBH_ERR *p_err) { *p_err = USBH_ERR_NONE; } /* ********************************************************************************************************* * USBH_FTDI_ProbeIF() * * Description : Determine if the interface is FTDI class interface. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to interface. * * p_err Variable that will receive the return error code from this function. * USBH_ERR_NONE, Interface is of FTDI type. * USBH_ERR_DEV_ALLOC, Cannot allocate FTDI device. * USBH_ERR_CLASS_DRV_NOT_FOUND, Interface is not of FTDI type. * * ----- RETURNED BY USBH_IF_DescGet() : ----- * USBH_ERR_INVALID_ARG, Invalid argument passed to 'alt_ix'. * * ----- RETURNED BY USBH_BulkInOpen() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * ----- RETURNED BY USBH_BulkOutOpen() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error Otherwise. * * Return(s) : p_ftdi_dev, If device has a FTDI class interface. * 0 Otherwise. * * Note(s) : (1) The 'bInterfaceClass' field of a FTDI device is 'Vendor Specific'. So, the 'Vendor ID' * and the 'Product ID' must be parsed as well to ensure connected device is FTDI. * * (2) The port number is determined by increasing 'USBH_FTDI_PortCnt' every time a device * with the same address is probed. If a new device is connected, this counter is reset * to '0'. ********************************************************************************************************* */ static void *USBH_FTDI_ProbeIF (USBH_DEV *p_dev, USBH_IF *p_if, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; USBH_DEV_DESC dev_desc; USBH_IF_DESC if_desc; LIB_ERR err_lib; *p_err = USBH_IF_DescGet(p_if, 0u, &if_desc); /* Get IF desc from IF. */ if (*p_err != USBH_ERR_NONE) { return ((void *)0); } USBH_DevDescGet(p_dev, &dev_desc); /* Get dev desc. */ /* bInterfaceClass must be Vendor Specific. */ if (if_desc.bInterfaceClass != USBH_CLASS_CODE_VENDOR_SPECIFIC) { p_ftdi_fnct = (USBH_FTDI_FNCT *)0; *p_err = USBH_ERR_CLASS_DRV_NOT_FOUND; /* idVendor must be FTDI or burned Vendor ID. */ } else if ((dev_desc.idVendor != USBH_FTDI_ID_VENDOR) && (dev_desc.idVendor != USBH_FTDI_CFG_ID_VENDOR_CUSTOM)) { p_ftdi_fnct = (USBH_FTDI_FNCT *)0; *p_err = USBH_ERR_CLASS_DRV_NOT_FOUND; /* idProduct must be FT8U232AM, FT232B, FT2232D, FT232R,*/ /* FT2232H, FT4232H, FT232H or burned Product ID. */ } else if ((dev_desc.idProduct != USBH_FTDI_ID_PRODUCT_FT232R) && (dev_desc.idProduct != USBH_FTDI_ID_PRODUCT_FT2232D) && (dev_desc.idProduct != USBH_FTDI_ID_PRODUCT_FT4232H) && (dev_desc.idProduct != USBH_FTDI_ID_PRODUCT_FT232H) && (dev_desc.idProduct != USBH_FTDI_CFG_ID_PRODUCT_CUSTOM)) { p_ftdi_fnct = (USBH_FTDI_FNCT *)0; *p_err = USBH_ERR_CLASS_DRV_NOT_FOUND; } else { /* Alloc a dev from FTDI fnct pool. */ p_ftdi_fnct = (USBH_FTDI_FNCT *)Mem_PoolBlkGet(&USBH_FTDI_DevPool, sizeof(USBH_FTDI_FNCT), &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { *p_err = USBH_ERR_DEV_ALLOC; return ((void *)0); } p_ftdi_fnct->State = USBH_CLASS_DEV_STATE_CONN; p_ftdi_fnct->DevPtr = p_dev; p_ftdi_fnct->IF_Ptr = p_if; if (USBH_FTDI_DevPtrPrev == p_dev) { /* Determine serial port of actual IF. See note (2). */ USBH_FTDI_PortCnt++; p_ftdi_fnct->Port = USBH_FTDI_PortCnt; } else { p_ftdi_fnct->Port = 0u; USBH_FTDI_PortCnt = 1u; } USBH_FTDI_DevPtrPrev = p_dev; *p_err = USBH_BulkInOpen(p_ftdi_fnct->DevPtr, /* Open Bulk IN EP. */ p_ftdi_fnct->IF_Ptr, &p_ftdi_fnct->BulkInEP); if (*p_err != USBH_ERR_NONE) { USBH_FTDI_Disconn(p_ftdi_fnct); return ((void *)0); } p_ftdi_fnct->MaxPktSize = (CPU_INT32U)USBH_EP_MaxPktSizeGet(&p_ftdi_fnct->BulkInEP); *p_err = USBH_BulkOutOpen(p_ftdi_fnct->DevPtr, /* Open Bulk OUT EP. */ p_ftdi_fnct->IF_Ptr, &p_ftdi_fnct->BulkOutEP); if (*p_err != USBH_ERR_NONE) { USBH_FTDI_Disconn(p_ftdi_fnct); return ((void *)0); } } return ((void *)p_ftdi_fnct); } /* ********************************************************************************************************* * USBH_FTDI_Suspend() * * Description : Suspend FTDI device. * * Argument(s) : p_class_dev Pointer to FTDI device. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_Suspend (void *p_class_dev) { USBH_FTDI_FNCT *p_ftdi_fnct; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_class_dev; p_ftdi_fnct->State = USBH_CLASS_DEV_STATE_SUSPEND; } /* ********************************************************************************************************* * USBH_FTDI_Resume() * * Description : Resume FTDI device. * * Argument(s) : p_class_dev Pointer to FTDI device. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_Resume (void *p_class_dev) { USBH_FTDI_FNCT *p_ftdi_fnct; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_class_dev; p_ftdi_fnct->State = USBH_CLASS_DEV_STATE_CONN; } /* ********************************************************************************************************* * USBH_FTDI_Disconn() * * Description : Handle disconnection of FTDI device. * * Argument(s) : p_class_dev Pointer to FTDI device. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_Disconn (void *p_class_dev) { USBH_FTDI_FNCT *p_ftdi_fnct; LIB_ERR err_lib; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_class_dev; (void)USBH_EP_Close(&p_ftdi_fnct->BulkInEP); /* Close bulk EPs. */ (void)USBH_EP_Close(&p_ftdi_fnct->BulkOutEP); p_ftdi_fnct->State = USBH_CLASS_DEV_STATE_DISCONN; if (USBH_FTDI_DevPtrPrev == p_ftdi_fnct->DevPtr) { USBH_FTDI_DevPtrPrev = (USBH_DEV *)0; } USBH_FTDI_PortCnt = 0u; Mem_PoolBlkFree( &USBH_FTDI_DevPool, (void *)p_ftdi_fnct, &err_lib); } /* ********************************************************************************************************* * USBH_FTDI_ClassDevNotify() * * Description : Handle device state change notification. * * Argument(s) : p_class_dev, Pointer to FTDI device. * * state, State of the FTDI device. * * p_ctx Pointer to FTDI functions. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_ClassDevNotify (void *p_class_dev, CPU_INT08U state, void *p_ctx) { USBH_FTDI_CALLBACKS *p_ftdi_callbacks; USBH_FTDI_FNCT *p_ftdi_fnct; p_ftdi_callbacks = (USBH_FTDI_CALLBACKS *)p_ctx; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_class_dev; switch (state) { case USBH_CLASS_DEV_STATE_CONN: p_ftdi_callbacks->ConnNotifyPtr(p_ftdi_fnct->Handle); break; case USBH_CLASS_DEV_STATE_DISCONN: p_ftdi_callbacks->DisconnNotifyPtr(p_ftdi_fnct->Handle); break; default: break; } } /* ********************************************************************************************************* * USBH_FTDI_StdReq() * * Description : Send standard FTDI control request to device. * * Argument(s) : ftdi_handle, Pointer to FTDI device. * * request, FTDI control request type. * * value, Value of the wValue field. * * h_index, High-Byte value of the wIndex field. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE, Control transfer successfully transmitted. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'ftdi_handle'. * USBH_ERR_DEV_NOT_READY, Device is not ready. * * ----- RETURNED BY USBH_CtrlTx() : ----- * USBH_ERR_NONE, Control transfer successfully completed. * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code Otherwise. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_StdReq (USBH_FTDI_HANDLE ftdi_handle, CPU_INT08U request, CPU_INT16U value, CPU_INT08U h_index, USBH_ERR *p_err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U ftdi_ix; CPU_INT16U index; ftdi_ix = USBH_FTDI_HANDLE_IX_GET(ftdi_handle); if (ftdi_ix >= USBH_FTDI_CFG_MAX_DEV) { *p_err = USBH_ERR_INVALID_ARG; return; } p_ftdi_fnct = &USBH_FTDI_DevTbl[ftdi_ix]; if (p_ftdi_fnct->DevPtr == (void *)0) { *p_err = USBH_ERR_INVALID_ARG; return; } if (p_ftdi_fnct->State != USBH_CLASS_DEV_STATE_CONN) { *p_err = USBH_ERR_DEV_NOT_READY; return; } index = (CPU_INT16U)(((CPU_INT16U)h_index << 8u) | p_ftdi_fnct->Port); (void)USBH_CtrlTx( p_ftdi_fnct->DevPtr, /* Send ctrl req. */ request, (USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_VENDOR | USBH_REQ_RECIPIENT_DEV), value, index, (void *)0, 0u, USBH_CFG_STD_REQ_TIMEOUT, p_err); } /* ********************************************************************************************************* * USBH_FTDI_DataTxCmpl() * * Description : Asynchronous data transfer completion function. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to transmit buffer. * * buf_len Buffer length in octets. * * xfer_len Number of octets transferred. * * p_arg Asynchronous function argument. * * err Status of transaction. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FTDI_DataTxCmpl (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U xfer_len, void *p_arg, USBH_ERR err) { USBH_FTDI_FNCT *p_ftdi_fnct; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_arg; if (err != USBH_ERR_NONE) { /* Chk status of transaction. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, p_ep); if (err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(p_ep); } } p_ftdi_fnct->DataTxNotifyPtr(p_ftdi_fnct->Handle, /* Notify the app. */ p_ftdi_fnct->DataTxNotifyArgPtr, p_buf, xfer_len, err); } /* ********************************************************************************************************* * USBH_FTDI_DataRxCmpl() * * Description : Asynchronous data receive completion function. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to transmit buffer. * * buf_len Buffer length in octets. * * xfer_len Number of octets transferred. * * p_arg Asynchronous function argument. * * err Status of transaction. * * Return(s) : None. * * Note(s) : (1) The received data in 'p_buf' is in little-endian. * * (2) The FTDI device always add a status of two bytes at the beginning of every packet. * This function manage those status bytes in order to get the latest status followed * by the data in 'p_buf'. * This only applies when the application requests more than max packet size (MPS) - 2 bytes of data. * * +----+----+----+----+-----+---------+---------+-----+----- * (a) Receive first pkt in buffer. | S0 | S1 | D0 | D1 | ... | MPS - 2 | MPS - 1 | MPS | ... * +----+----+----+----+-----+---------+---------+-----+----- * | | * v v * +---------+-----+ * (b) Save the last two bytes of data. | MPS - 1 | MPS | * +---------+-----+ * * +----+----+----+----+-----+---------+-----+-----+---------+---------+----- * (c) Receive next pkt in buffer. | S0 | S1 | D0 | D1 | ... | MPS - 2 | S2 | S3 | MPS + 1 | MPS + 2 | ... * +----+----+----+----+-----+---------+-----+-----+---------+---------+----- * * +----+----+----+----+-----+---------+---------+-----+---------+---------+----- * (d) Update the status. | S2 | S3 | D0 | D1 | ... | MPS - 2 | S2 | S3 | MPS + 1 | MPS + 2 | ... * +----+----+----+----+-----+---------+---------+-----+---------+---------+----- * ^ ^ * | | * +---------+-----+ * (e) Restore the two bytes of data. | MPS - 1 | MPS | * +---------+-----+ * * (f) Repeat step (b) to (e) until the end of the buffer is reached or the last transfer size is * smaller than maxPktSize. * ********************************************************************************************************* */ static void USBH_FTDI_DataRxCmpl (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U xfer_len, void *p_arg, USBH_ERR err) { USBH_FTDI_FNCT *p_ftdi_fnct; CPU_INT08U *p_buf_cur; CPU_INT32U rem_buf_size; USBH_FTDI_SERIAL_STATUS *p_serial_status; p_ftdi_fnct = (USBH_FTDI_FNCT *)p_arg; if (err == USBH_ERR_NONE) { p_serial_status = p_ftdi_fnct->SerialStatusPtr; p_buf_cur = (CPU_INT08U *)p_buf; if (p_serial_status != (void *)0) { p_serial_status->ModemStatus = *(p_buf_cur); p_serial_status->LineStatus = *(p_buf_cur + 1u); /* Chk line status. */ if ((DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_RX_OVERFLOW_ERROR) == DEF_YES) || (DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_PARITY_ERROR) == DEF_YES) || (DEF_BIT_IS_SET(p_serial_status->LineStatus, USBH_FTDI_LINE_STATUS_FRAMING_ERROR) == DEF_YES)) { MEM_VAL_COPY_16(p_ftdi_fnct->DataRxBuf, p_buf_cur); err = USBH_ERR_FTDI_LINE; } } } else { /* Chk status of transaction. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, p_ep); if (err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(p_ep); } } if (err == USBH_ERR_NONE) { /* Organize data to get last two bytes status followed */ /* by raw data rx'd. */ if (p_ftdi_fnct->XferLen > (p_ftdi_fnct->MaxPktSize - 1u)) { MEM_VAL_COPY_16(p_ftdi_fnct->DataRxBuf, p_buf_cur); /* Update status. */ MEM_VAL_COPY_16(p_buf_cur, &p_ftdi_fnct->LastBytes);/* Restore two bytes of data. */ p_ftdi_fnct->XferLen += (xfer_len - USBH_FTDI_SERIAL_STATUS_LEN); } else { p_ftdi_fnct->XferLen += xfer_len; } p_buf_cur += p_ftdi_fnct->MaxPktSize; rem_buf_size = (p_ftdi_fnct->RxBufLen - p_ftdi_fnct->XferLen); if ((xfer_len == p_ftdi_fnct->MaxPktSize) && (p_ftdi_fnct->MaxPktSize <= rem_buf_size)) { /* Save last two bytes of data. */ MEM_VAL_COPY_16(&p_ftdi_fnct->LastBytes, (p_buf_cur - USBH_FTDI_SERIAL_STATUS_LEN)); /* Req following pkt. */ err = USBH_BulkRxAsync( &p_ftdi_fnct->BulkInEP, (p_buf_cur - USBH_FTDI_SERIAL_STATUS_LEN), buf_len, USBH_FTDI_DataRxCmpl, (void *)p_ftdi_fnct); if (err != USBH_ERR_NONE) { /* Reset EP if an err occurred. */ (void)USBH_EP_Reset(p_ftdi_fnct->DevPtr, &p_ftdi_fnct->BulkOutEP); if (err == USBH_ERR_EP_STALL) { (void)USBH_EP_StallClr(&p_ftdi_fnct->BulkOutEP); } } else { return; } } } p_ftdi_fnct->DataRxNotifyPtr(p_ftdi_fnct->Handle, /* Notify the app. */ p_ftdi_fnct->DataRxNotifyArgPtr, p_ftdi_fnct->DataRxBuf, p_ftdi_fnct->XferLen, p_ftdi_fnct->SerialStatusPtr, err); }