📄 usb.c
字号:
/****************************************************************************
*
* Copyright (c) 2006-2007 by CMX Systems, Inc.
*
* This software is copyrighted by and is the sole property of
* CMX. All rights, title, ownership, or other interests
* in the software remain the property of CMX. This
* software may only be used in accordance with the corresponding
* license agreement. Any unauthorized use, duplication, transmission,
* distribution, or disclosure of this software is expressly forbidden.
*
* This Copyright notice may not be removed or modified without prior
* written consent of CMX.
*
* CMX reserves the right to modify this software without notice.
*
* CMX Systems, Inc.
* 12276 San Jose Blvd. #511
* Jacksonville, FL 32223
* USA
*
* Tel: (904) 880-1840
* Fax: (904) 880-1632
* http: www.cmx.com
* email: cmx@cmx.com
*
***************************************************************************/
#include "hcc_types.h"
#include "mcf51xx_reg.h"
#include "usb.h"
//#include "target.h"
/*****************************************************************************
* Local types.
*****************************************************************************/
typedef struct {
volatile hcc_u32 tlength;
volatile hcc_u32 maxlength;
void * volatile address;
volatile usb_callback_t data_func;
hcc_u16 psize;
hcc_u32 data0_tx;
hcc_u32 data0_rx;
volatile hcc_u8 state;
volatile hcc_u8 flags;
volatile hcc_u8 error;
hcc_u8 next_rx;
hcc_u8 next_tx;
} ep_info_t;
/*****************************************************************************
* Macro definitions.
*****************************************************************************/
#define DIR_TX BIT7
#define SOF_PID_VALUE 0xd
/* Note: BIT3 shows if the data packet is data0 or data1. */
#define DATA_PID_VALUE 0x3
#define DATA0_PID_VALUE 0x3
#define DATA1_PID_VALUE 0xb
#define MCF_USB_ENDPT(ep) (((hcc_u8*)&MCF_USB_ENDPT0)[ep<<2])
#define MCF_USB_ENDPT_EP_HSHK BIT0
#define MCF_USB_ENDPT_EP_STALL BIT1
#define MCF_USB_ENDPT_EP_TX_EN BIT2
#define MCF_USB_ENDPT_EP_RX_EN BIT3
#define MCF_USB_ENDPT_EP_CTL_DIS BIT4
#define MCF_USB_ENDPT_RETRY_DIS BIT6
#define MCF_USB_ENDPT_HOST_WO_HUB BIT7
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/* Control endpoint state machine state values. */
#define EPST_IDLE 0x0
#define EPST_DATA_TX 0x1
#define EPST_DATA_TX_LAST 0x2
#define EPST_DATA_RX 0x3
#define EPST_STATUS_TX 0x4
#define EPST_STATUS_RX 0x5
#define EPST_TX_STOP 0x6
#define EPST_ABORT_TX 0x7
#define EPST_DATA_TX_WAIT_DB 0x8
#define EPST_DATA_TX_EMPTY_DB 0x9
/* Standard USB feature selector values. */
#define FEAT_ENDPOINT_HALT 0u
#define FEAT_DEVICE_REMOTE_WAKEUP 1u
/* Endpoint flag bits. */
#define EPFL_ERROR (hcc_u8)BIT0 /* There was an error during the ongoing
transfer. */
#define EPFL_ZPACKET (hcc_u8)BIT1 /* After the last data packet an additional zero
length packet needs to be transmitted to close
the transfer. */
/* This macro shall evaluate to a uint32 pointer to the start address of the
buffer descriptor table (BDT). The BDT has 32 bytes for each endpoint.
The BDT shall be alignet to 512 byte boundary! */
extern hcc_u32 _BDT_MAP[];
#define BDT_BASE ((hcc_u32*)(_BDT_MAP))
#define BDT_CTL_RX(ep, b) (BDT_BASE[((ep)<<3)+((b)<<1)+0])
#define BDT_ADR_RX(ep, b) (BDT_BASE[((ep)<<3)+((b)<<1)+1])
#define BDT_CTL_TX(ep, b) (BDT_BASE[((ep)<<3)+((b)<<1)+4])
#define BDT_ADR_TX(ep, b) (BDT_BASE[((ep)<<3)+((b)<<1)+5])
#define BDT_CTL_STALL BIT2
#define BDT_CTL_DTS BIT3
#define BDT_CTL_DATA BIT6
#define BDT_CTL_OWN BIT7
/*****************************************************************************
* Global variables.
*****************************************************************************/
/* N/A */
/*****************************************************************************
* Module variables.
*****************************************************************************/
static volatile hcc_u8 usb_current_config;
static volatile hcc_u8 usb_state;
static volatile hcc_u8 new_address;
static ep_info_t ep_info[16];
/*****************************************************************************
* Function predefinitions.
*****************************************************************************/
static void enter_default_state(void);
static void disable_ep_rx(hcc_u8);
static void disable_ep_tx(hcc_u8);
static void ready_ep_rx(hcc_u8, hcc_u8);
static void ready_ep_tx(hcc_u8, hcc_u8);
static hcc_u8 select_tx_buf(hcc_u8 ep);
static void send_zero_packet(hcc_u8 ep);
static void _usb_send(hcc_u8 ep);
static void _usb_receive(hcc_u8 ep);
static callback_state_t cb_set_address(void);
static callback_state_t usb_stm_ctrl0(void);
static hcc_u8 usb_setup_ep(hcc_u8 addr, hcc_u8 type, hcc_u8 ep, hcc_u16 psize);
extern void enable_usb_pull_up();
/*****************************************************************************
* Name:
* usb_get_rx_pptr
* In:
* ep: number of endpoint.
* Out:
* Pointer to the packet buffer containing data of the last received packet.
*
* Description:
* Returns te number of bytes that are left of the transfer. If
* usb_ep_is_busy returns false, then the transfer was aborted either
* by the host or by the application.
*****************************************************************************/
hcc_u8* usb_get_rx_pptr(hcc_u8 ep)
{
hcc_u8 cur_buf=(hcc_u8)(MCF_USB_STAT & MCF_USB_STAT_ODD ? 1 : 0);
return((hcc_u8 *)(RD_LE32(&BDT_ADR_RX(ep, cur_buf))));
}
/*****************************************************************************
* Name:
* select_tx_buf
* In:
* ep: number of endpoint.
* Out:
* The index of the next tx buffer.
*
* Description:
* Returns te number of bytes that are left of the transfer. If
* usb_ep_is_busy returns false, then the transfer was aborted either
* by the host or by the application.
*****************************************************************************/
static hcc_u8 select_tx_buf(hcc_u8 ep)
{
/* SHALL ONLY BE CALLED WITH USB INTERRUPTS DISABLED. */
hcc_u8 buf;
hcc_u32 ctl;
/* Find out which buffer shall be used. */
ctl=(RD_LE32(&BDT_CTL_TX(ep, 0)) & BDT_CTL_OWN)
| (RD_LE32(&BDT_CTL_TX(ep, 1)) & BDT_CTL_OWN) << 1;
switch(ctl)
{
case 0: /* No buffer is used by the USB module. Fill the one
we think is the next. */
buf=ep_info[ep].next_tx;
ep_info[ep].next_tx ^= 0x1;
break;
case BDT_CTL_OWN: /* Buffer 0 is used by the USB. */
buf=1;
ep_info[ep].next_tx=0;
break;
case BDT_CTL_OWN<<1: /* Buffer 1 is used by the USB. */
buf=0;
ep_info[ep].next_tx=1;
break;
default: /* Both buffers are used by the usb. This is
an error. */
CMX_ASSERT(0);
}
return(buf);
}
/*****************************************************************************
* Name:
* usb_get_done
* In:
* ep: number of endpoint.
* Out:
* The number of bytes the endpoint tansferred.
*
* Description:
* Returns te number of bytes that were transferred.
*****************************************************************************/
hcc_u32 usb_get_done(hcc_u8 ep)
{
return(ep_info[ep].maxlength-ep_info[ep].tlength);
}
/*****************************************************************************
* Name:
* usb_ep_is_busy
* In:
* ep: number of endpoint.
* Out:
* nonzero if endpoint is buys (a transfer is ongoing).
*
* Description:
*
*****************************************************************************/
hcc_u8 usb_ep_is_busy(hcc_u8 ep)
{
return(ep_info[ep].state != EPST_IDLE ? (hcc_u8)1 : (hcc_u8)0);
}
/*****************************************************************************
* Name:
* usb_get_state
* In:
* N/A
* Out:
* Current USB state. See USBST_xxx in usb.h
*
* Description:
*
*****************************************************************************/
hcc_u8 usb_get_state(void)
{
return(usb_state);
}
/*****************************************************************************
* Name:
* usb_ep_error
* In:
* ep: number fo endpoint
* Out:
* Endpoint specific error code. (See USBEPERR_xx macro definitions in usb.h)
*
* Description:
*
*****************************************************************************/
hcc_u8 usb_ep_error(hcc_u8 ep)
{
hcc_u8 tmp=ep_info[ep].error;
ep_info[ep].error=USBEPERR_NONE;
return(tmp);
}
/*****************************************************************************
* Name:
* send_zero_packet
* In:
* N/A
* Out:
* N/A
*
* Description:
* Will send a zero length data packet.
*
* Assumptions:
* ep is the index of a TX endpoint.
*****************************************************************************/
static void send_zero_packet(hcc_u8 ep)
{
hcc_u8 buf;
buf=select_tx_buf(ep);
/* Write packet length. */
WR_LE32(&BDT_CTL_TX(ep, buf), 0);
/* Make buffer ready for transmission. */
ready_ep_tx(ep, buf);
}
/*****************************************************************************
* Name:
* usb_init
* In:
* None
* Out:
* 0 - if all ok
* !0 - if failed
*
* Description:
* Initialises the usb driver. Will set the interrupt level.
* Note: clock source is the system clock (48MHz).
*****************************************************************************/
hcc_u8 usb_init(void)
{
/* Reset USB module first. */
USBTRC0_USBRESET = 1;
while (USBTRC0_USBRESET) {};
/* exit suspend and select USB clock source
* If you program CLK_SRC bits as 2’b11 in the USB_CTRL register then MCGPLLSCK is connected to the USB 48 Mhz clock.
* If you program CLK_SRC bits to 2’b00 then the usb_alt_clk input pin to the chip is used as the USB 48 Mhz clock . This is the PTG0 pad. (Pin number 32 for 80LQFP)
* Plz ignore programmation 2’b01,2’b10 for CLK_SRC bit. They are reserved.
*/
MCF_USB_USB_CTRL = MCF_USB_USB_CTRL_CLKSRC_SYS;
/* Disable all USB interrupts. */
MCF_USB_INT_ENB = 0x0;
/* Disable all OTG interupts. */
MCF_USB_OTG_INT_EN = 0x0;
/* Disable all USB error interrupts. */
MCF_USB_ERR_ENB = 0x0;
/* Put USB to default state. */
enter_default_state();
/* Clear any pending OTG interupts. */
MCF_USB_OTG_INT_STAT = 0xff;
/* Clear any pending USB interrupts.*/
MCF_USB_INT_STAT = 0xff;
/* Clear any pending USB error interrupt. */
MCF_USB_ERR_STAT = 0xff;
/* Enable USB interrupts. */
MCF_USB_INT_ENB = MCF_USB_INT_ENB_SLEEP | MCF_USB_INT_ENB_TOK_DNE
| MCF_USB_INT_ENB_ERROR | MCF_USB_INT_ENB_USB_RST
| MCF_USB_INT_ENB_STALL;
/* Set BDT address. */
MCF_USB_BDT_PAGE_01 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 8);
MCF_USB_BDT_PAGE_02 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 16);
MCF_USB_BDT_PAGE_03 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 24);
/* Enable USB PHY before enabling USB module */
//USBTRC0 = USBTRC0_USBVREN_MASK;
enable_usb_pull_up();
/* Enable USB functionality*/
MCF_USB_CTL = MCF_USB_CTL_USB_EN_SOF_EN;
return(0);
}
/*****************************************************************************
* Name:
* usb_stop
* In:
* n/a
* Out:
* n/a
*
* Description:
* Stops USB driver.
*****************************************************************************/
void usb_stop(void)
{
/* Disable all USB interrupts. */
MCF_USB_INT_ENB = 0x0;
/* Disable all OTG interupts. */
MCF_USB_OTG_INT_EN = 0x0;
/* Disable all USB error interrupts. */
MCF_USB_ERR_ENB = 0x0;
/* Clear any pending OTG interupts. */
MCF_USB_OTG_INT_STAT = 0xff;
/* Clear any pending USB interrupts.*/
MCF_USB_INT_STAT = 0xff;
/* Clear any pending USB error interrupt. */
MCF_USB_ERR_STAT = 0xff;
MCF_USB_USB_CTRL=0;
/* Disable USB module. */
MCF_USB_CTL = 0;
enter_default_state();
usb_setup_ep(0, EP_TYPE_DISABLE, 0, 0);
usb_state=USBST_DISABLED;
}
/*****************************************************************************
* Name:
* usb_setup_ep
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -