📄 usb.c
字号:
/*********************************************************************
*
* Copyright:
* MOTOROLA, INC. All Rights Reserved.
* You are hereby granted a copyright license to use, modify, and
* distribute the SOFTWARE so long as this entire notice is
* retained without alteration in any modified and/or redistributed
* versions, and that such modified versions are clearly identified
* as such. No licenses are granted by implication, estoppel or
* otherwise under any patents or trademarks of Motorola, Inc. This
* software is provided on an "AS IS" basis and without warranty.
*
* To the maximum extent permitted by applicable law, MOTOROLA
* DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
* PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH REGARD TO THE
* SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY
* ACCOMPANYING WRITTEN MATERIALS.
*
* To the maximum extent permitted by applicable law, IN NO EVENT
* SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING
* WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS
* INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY
* LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
*
* Motorola assumes no responsibility for the maintenance and support
* of this software
********************************************************************/
/*
* File: usb.c
* Purpose: Device Driver for the USB module of the MCF5272
*/
#include "mcf5272.h"
#include "init.h"
/********************************************************************/
/* Global Endpoint Status Structures */
USB_EP_STATE ep[NUM_ENDPOINTS];
/* Global Remote Wakeup Flag */
volatile int fRemoteWakeup = 0;
/* Global USB Descriptor Data (application specific) */
extern USB_DEVICE_DESC Descriptors;
/********************************************************************/
void
usb_init(void)
{
uint32 i, DescSize;
uint32 *pConfigRam;
uint32 *pDevDesc;
MCF5272_IMM *imm = mcf5272_get_immp();
/* Initialize Descriptor pointers and variables */
pConfigRam = (uint32 *)((uint32)imm + MCF5272_USB_CFG_RAM);
pDevDesc = (uint32 *)usb_get_desc(-1, -1, -1, -1);
DescSize = usb_get_desc_size() + 3;
/* Initialize Endpoint status structures */
ep[0].ttype = CONTROL;
ep[0].packet_size = ((USB_DEVICE_DESC *)pDevDesc)->bMaxPacketSize0;
ep[0].fifo_length = (uint16)(ep[0].packet_size * FIFO_DEPTH);
ep[0].buffer.start = 0;
ep[0].buffer.free = 0;
/* Set the EP0 IN-BUSY bit -- This is only required on
pre-2K75N masks. This bit is set by HW beginning with
the 2K75N silicon. */
MCF5272_WR_USB_EP0CTL(imm, MCF5272_RD_USB_EP0CTL(imm)
| MCF5272_USB_EP0CTL_IN_BUSY);
for (i = 1; i < NUM_ENDPOINTS; i++)
ep[i].ttype = DISABLED;
/* Invalidate Configuration RAM and disable Endpoint 0 */
MCF5272_WR_USB_EP0CTL(imm, 0);
/* Load the Configuration RAM with the descriptors */
for (i = 0; i < (DescSize/4); i++)
pConfigRam[i] = pDevDesc[i];
/* Initialize FIFOs */
usb_fifo_init();
/* Initialize the Interrupts */
usb_isr_init();
/* Enable USB controller, Config RAM, EXT AFE */
#if (DEBUG)
MCF5272_WR_USB_EP0CTL(imm, 0
| MCF5272_USB_EP0CTL_DEBUG
/* | MCF5272_USB_EP0CTL_AFE_EN */
| MCF5272_USB_EP0CTL_USB_EN
| MCF5272_USB_EP0CTL_CFG_RAM_VAL);
#else
MCF5272_WR_USB_EP0CTL(imm, 0
/* | MCF5272_USB_EP0CTL_AFE_EN */
| MCF5272_USB_EP0CTL_USB_EN
| MCF5272_USB_EP0CTL_CFG_RAM_VAL);
#endif
/* Enable desired interrupts on EP0 */
MCF5272_WR_USB_EP0IMR(imm, 0
| MCF5272_USB_EP0IMR_DEV_CFG_EN
| MCF5272_USB_EP0IMR_VEND_REQ_EN
| MCF5272_USB_EP0IMR_WAKE_CHG_EN
| MCF5272_USB_EP0IMR_RESUME_EN
| MCF5272_USB_EP0IMR_SUSPEND_EN
| MCF5272_USB_EP0IMR_RESET_EN
| MCF5272_USB_EP0IMR_OUT_EOT_EN
| MCF5272_USB_EP0IMR_OUT_EOP_EN
| MCF5272_USB_EP0IMR_IN_EOT_EN
| MCF5272_USB_EP0IMR_IN_EOP_EN
| MCF5272_USB_EP0IMR_UNHALT_EN
| MCF5272_USB_EP0IMR_HALT_EN);
}
/********************************************************************/
void
usb_isr_init(void)
{
MCF5272_IMM *imm = mcf5272_get_immp();
/* Clear any pending interrupts in all Endpoints */
MCF5272_WR_USB_EP0ISR(imm, 0x0001FFFF);
MCF5272_WR_USB_EP1ISR(imm, 0x001F);
MCF5272_WR_USB_EP2ISR(imm, 0x001F);
MCF5272_WR_USB_EP3ISR(imm, 0x001F);
MCF5272_WR_USB_EP4ISR(imm, 0x001F);
MCF5272_WR_USB_EP5ISR(imm, 0x001F);
MCF5272_WR_USB_EP6ISR(imm, 0x001F);
MCF5272_WR_USB_EP7ISR(imm, 0x001F);
/* Enable all interrupts on all Endpoints */
/* These will be altered on configuration/interface changes */
MCF5272_WR_USB_EP0IMR(imm, 0x0001FFFF);
MCF5272_WR_USB_EP1IMR(imm, 0x001F);
MCF5272_WR_USB_EP2IMR(imm, 0x001F);
MCF5272_WR_USB_EP3IMR(imm, 0x001F);
MCF5272_WR_USB_EP4IMR(imm, 0x001F);
MCF5272_WR_USB_EP5IMR(imm, 0x001F);
MCF5272_WR_USB_EP6IMR(imm, 0x001F);
MCF5272_WR_USB_EP7IMR(imm, 0x001F);
/* Initialize Interrupt Control Registers */
MCF5272_WR_SIM_ICR2(imm, 0
| (0x00008888)
| (USB_EP0_LEVEL << 12)
| (USB_EP1_LEVEL << 8)
| (USB_EP2_LEVEL << 4)
| (USB_EP3_LEVEL << 0));
MCF5272_WR_SIM_ICR3(imm, 0
| (0x88880000)
| (USB_EP4_LEVEL << 28)
| (USB_EP5_LEVEL << 24)
| (USB_EP6_LEVEL << 20)
| (USB_EP7_LEVEL << 16));
}
/********************************************************************/
void
usb_endpoint0_isr(void)
{
MCF5272_IMM *imm = mcf5272_get_immp();
uint32 event;
event = MCF5272_RD_USB_EP0ISR(imm) & MCF5272_RD_USB_EP0IMR(imm);
if (event & MCF5272_USB_EP0ISR_DEV_CFG)
{
usb_devcfg_service();
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_DEV_CFG);
}
if (event & MCF5272_USB_EP0ISR_VEND_REQ)
{
/* Is this a GET_DESCRIPTOR(String) request? */
if ((MCF5272_RD_USB_DRR1(imm) & 0xFF00 >> 8) == GET_DESCRIPTOR)
{
/* To do: Return STRING Descriptor if it exists */
printf("Host requested the String Descriptor\n");
while (1) ;
}
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_VEND_REQ);
usb_vendreq_service(
(uint8)(MCF5272_RD_USB_DRR1(imm) & 0xFF),
(uint8)(MCF5272_RD_USB_DRR1(imm) >> 8),
(uint16)(MCF5272_RD_USB_DRR1(imm) >> 16),
(uint16)(MCF5272_RD_USB_DRR2(imm) & 0xFFFF),
(uint16)(MCF5272_RD_USB_DRR2(imm) >> 16));
}
if (event & MCF5272_USB_EP0ISR_FRM_MAT)
{
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_FRM_MAT);
}
if (event & MCF5272_USB_EP0ISR_ASOF)
{
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_ASOF);
}
if (event & MCF5272_USB_EP0ISR_SOF)
{
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_SOF);
}
if (event & MCF5272_USB_EP0ISR_WAKE_CHG)
{
if (MCF5272_RD_USB_EP0SR(imm) & MCF5272_USB_EP0SR_WAKE_ST)
{
/* Enable Wake-on-Ring */
MCF5272_WR_USB_EP0CTL(imm,
MCF5272_RD_USB_EP0CTL(imm)
| MCF5272_USB_EP0CTL_WOR_EN);
/* Wake-on-Ring function is invoked when /INT1 pin is 0 */
MCF5272_WR_USB_EP0CTL(imm,
MCF5272_RD_USB_EP0CTL(imm)
& ~MCF5272_USB_EP0CTL_WOR_LVL);
#if (DEBUG)
printf("Wake-on-Ring enabled.\n");
#endif
}
else
{
/* Disable Wake-on-Ring */
MCF5272_WR_USB_EP0CTL(imm,
MCF5272_RD_USB_EP0CTL(imm)
& ~MCF5272_USB_EP0CTL_WOR_EN);
#if (DEBUG)
printf("Wake-on-Ring disabled.\n");
#endif
}
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_WAKE_CHG);
}
if (event & MCF5272_USB_EP0ISR_RESUME)
{
usb_bus_state_chg_service(RESUME);
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_RESUME);
}
if (event & MCF5272_USB_EP0ISR_SUSPEND)
{
if (MCF5272_RD_USB_EP0SR(imm) & MCF5272_USB_EP0SR_WAKE_ST)
usb_bus_state_chg_service(SUSPEND | ENABLE_WAKEUP);
else
usb_bus_state_chg_service(SUSPEND);
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_SUSPEND);
}
if (event & MCF5272_USB_EP0ISR_RESET)
{
usb_bus_state_chg_service(RESET);
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_RESET);
}
if (event & ( MCF5272_USB_EP0ISR_OUT_EOT
| MCF5272_USB_EP0ISR_OUT_EOP
| MCF5272_USB_EP0ISR_OUT_LVL))
{
usb_out_service(0, event);
}
if (event & ( MCF5272_USB_EP0ISR_IN_EOT
| MCF5272_USB_EP0ISR_IN_EOP
| MCF5272_USB_EP0ISR_IN_LVL))
{
usb_in_service(0, event);
}
if (event & MCF5272_USB_EP0ISR_UNHALT)
{
#if (DEBUG)
printf("Endpoint 0 has been UNHALTed\n");
#endif
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_UNHALT);
}
if (event & MCF5272_USB_EP0ISR_HALT)
{
#if (DEBUG)
printf("Endpoint 0 has been HALTed\n");
#endif
/* Clear this interrupt bit */
MCF5272_WR_USB_EP0ISR(imm, MCF5272_USB_EP0ISR_HALT);
}
}
/********************************************************************/
void
usb_endpoint_isr(uint32 epnum)
{
int event;
MCF5272_IMM *imm = mcf5272_get_immp();
#if (DEBUG)
printf("Received interrupt for Endpoint %d\n",epnum);
#endif
event = MCF5272_RD_USB_EPISR(imm, epnum)
& MCF5272_RD_USB_EPIMR(imm, epnum);
if (event & ( MCF5272_USB_EPNISR_EOT
| MCF5272_USB_EPNISR_EOP
| MCF5272_USB_EPNISR_FIFO_LVL))
{
/* IN Endpoint */
if (MCF5272_RD_USB_EPISR(imm, epnum) & MCF5272_USB_EPNISR_DIR)
usb_in_service(epnum, event);
/* OUT Endpoint */
else
usb_out_service(epnum,event);
}
if (event & MCF5272_USB_EPNISR_HALT)
{
/* Call Project specific routine */
usb_ep_halt(epnum);
MCF5272_WR_USB_EPISR(imm, epnum, MCF5272_USB_EPNISR_HALT);
}
if (event & MCF5272_USB_EPNISR_UNHALT)
{
/* Call Project specific routine */
usb_ep_unhalt(epnum);
MCF5272_WR_USB_EPISR(imm, epnum, MCF5272_USB_EPNISR_UNHALT);
}
}
/********************************************************************/
void
usb_in_service(uint32 epnum, uint32 event)
{
MCF5272_IMM *imm = mcf5272_get_immp();
uint16 i;
uint32 free_space;
#if (DEBUG)
if (event & MCF5272_USB_EP0ISR_IN_EOT)
printf("Received IN_EOT for EP #%d\n",epnum);
if (event & MCF5272_USB_EP0ISR_IN_EOP)
printf("Received IN_EOP for EP #%d\n",epnum);
if (event & MCF5272_USB_EP0ISR_IN_LVL)
printf("Received IN_LVL for EP #%d\n",epnum);
#endif
/* Clear the FIFO Level interrupt now */
if (event & MCF5272_USB_EPNISR_FIFO_LVL)
MCF5272_WR_USB_EPISR(imm, epnum, MCF5272_USB_EPNISR_FIFO_LVL);
if (event & (MCF5272_USB_EPNISR_EOP | MCF5272_USB_EPNISR_FIFO_LVL))
{
/* Clear this interrupt bit */
MCF5272_WR_USB_EPISR(imm, epnum, MCF5272_USB_EPNISR_EOP);
if (ep[epnum].buffer.position < ep[epnum].buffer.length)
{
/* USBEPDP0 only monitors the OUT FIFO */
if (epnum == 0)
free_space = ep[0].packet_size;
else
free_space = (uint16)(ep[epnum].fifo_length \
- MCF5272_RD_USB_EPDPR(imm, epnum));
for (i = ep[epnum].buffer.position; \
i < ep[epnum].buffer.position + free_space; )
{
/* Write from the buffer to the FIFO */
if ((((ep[epnum].buffer.position + free_space) - i) > 3)
&& ((i + 4) < ep[epnum].buffer.length))
{
MCF5272_WR_USB_EPDR(imm, epnum, 32,
*(uint32 *)(&ep[epnum].buffer.start[i]));
i += 4;
}
else
{
MCF5272_WR_USB_EPDR(imm,epnum,8,ep[epnum].buffer.start[i]);
i++;
}
if ( i >= ep[epnum].buffer.length )
{
/* All done -> Clear the IN-BUSY bit */
MCF5272_WR_USB_EPCTL(imm, epnum,
MCF5272_RD_USB_EPCTL(imm, epnum)
& ~MCF5272_USB_EPNCTL_IN_BUSY);
break;
}
}
ep[epnum].buffer.position = i;
}
}
if ((event & MCF5272_USB_EPNISR_FIFO_LVL) &&
(ep[epnum].ttype == ISOCHRONOUS))
{
/* Clear this interrupt bit */
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EPNISR_FIFO_LVL );
if (ep[epnum].buffer.start &&
(ep[epnum].buffer.length == ep[epnum].buffer.position))
{
usb_ep_tx_done(epnum);
ep[epnum].buffer.start = 0;
ep[epnum].buffer.length = 0;
ep[epnum].buffer.position = 0;
ep[epnum].buffer.free = 0;
}
}
if (event & MCF5272_USB_EPNISR_EOT)
{
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EPNISR_EOT);
if (ep[epnum].buffer.start)
{
if (ep[epnum].buffer.free)
free(ep[epnum].buffer.start);
/* Call the Tx Handler */
usb_ep_tx_done(epnum);
}
ep[epnum].buffer.start = 0;
ep[epnum].buffer.length = 0;
ep[epnum].buffer.position = 0;
ep[epnum].buffer.free = 0;
/* Set the IN-BUSY bit
This is only required on pre-2K75N masks. This bit is set by
HW beginning with the 2K75N silicon. */
MCF5272_WR_USB_EPCTL(imm, epnum, MCF5272_RD_USB_EPCTL(imm, epnum)
| MCF5272_USB_EPNCTL_IN_BUSY);
}
}
/********************************************************************/
void
usb_out_service(uint32 epnum, uint32 event)
{
MCF5272_IMM *imm = mcf5272_get_immp();
uint32 i;
uint16 fifo_data;
#if (DEBUG)
if (event & (MCF5272_USB_EP0ISR_OUT_EOT | MCF5272_USB_EPNISR_EOT))
printf("Received OUT_EOT on EP%d\n",epnum);
if (event & (MCF5272_USB_EP0ISR_OUT_EOP | MCF5272_USB_EPNISR_EOP))
printf("Received OUT_EOP on EP%d\n",epnum);
if (event & (MCF5272_USB_EP0ISR_OUT_LVL | MCF5272_USB_EPNISR_FIFO_LVL))
printf("Received OUT_LVL on EP%d\n",epnum);
#endif
if (event & (MCF5272_USB_EP0ISR_OUT_LVL | MCF5272_USB_EPNISR_FIFO_LVL))
{
/* Clear the FIFO Level Interrupt bits now */
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EP0ISR_OUT_LVL
| MCF5272_USB_EPNISR_FIFO_LVL);
}
if (event & ( MCF5272_USB_EP0ISR_OUT_LVL
| MCF5272_USB_EPNISR_FIFO_LVL
| MCF5272_USB_EP0ISR_OUT_EOP
| MCF5272_USB_EPNISR_EOP))
{
/* Clear the EOP interrupt bits */
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EP0ISR_OUT_EOP
| MCF5272_USB_EPNISR_EOP);
/* Read the Data Present register */
fifo_data = MCF5272_RD_USB_EPDPR(imm, epnum);
if (ep[epnum].buffer.start &&
(ep[epnum].buffer.position + fifo_data > ep[epnum].buffer.length))
{
/* Buffer is going to overflow! */
/* To do: realloc() to avoid this problem */
usb_ep_rx_done(epnum,OVERFLOW_ERROR);
ep[epnum].buffer.start = 0;
}
if (ep[epnum].buffer.start == 0)
{
/* No Buffer allocated! */
ep[epnum].buffer.start = (uint8 *) malloc(BUFFER_SIZE);
if (!ep[epnum].buffer.start)
{
/* Could not allocate buffer */
usb_ep_rx_done(epnum,MALLOC_ERROR);
return;
}
ep[epnum].buffer.free = TRUE;
ep[epnum].buffer.length = BUFFER_SIZE;
ep[epnum].buffer.position = 0;
}
/* Read the data from the FIFO into the buffer */
for (i = ep[epnum].buffer.position; \
i < ep[epnum].buffer.position + fifo_data;)
{
if (ep[epnum].buffer.position + fifo_data - i > 3)
{
*((uint32 *)(&ep[epnum].buffer.start[i])) =
MCF5272_RD_USB_EPDR(imm, epnum,32);
i += 4;
}
else
{
ep[epnum].buffer.start[i] =
MCF5272_RD_USB_EPDR(imm, epnum,8);
i++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -