📄 usb.c
字号:
/*
* File: usb.c
* Purpose: Provide common USB routines
*
* Notes:
*
*/
#include "usb.h"
/********************************************************************/
/*
* Initialize the USB host for operation. This initialization sets
* up the USB host to detect when a device is connected.
*
* Parameters:
* port USB module to initialize
*/
void
usb_host_init(int port)
{
/* Initialize the clock divider for the USB */
MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBDIV;
/* --- Start HOST controller --- */
#ifdef DEBUG_PRINT
printf("Set host mode.\n");
#endif
MCF_USB_USBMODE(port) = (MCF_USB_USBMODE_ES | MCF_USB_USBMODE_CM_HOST);
MCF_USB_USBCMD(port) = ( 0
| MCF_USB_USBCMD_ASP(3)
| MCF_USB_USBCMD_ITC(0) );
#ifdef DEBUG_PRINT
printf("Set RUN bit.\n");
#endif
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_RS;
/* Apply port power. This does not initialize the transceiver.
* If ULPI is being used it should be initialized before this point. */
MCF_USB_PORTSC(port) = ( MCF_USB_PORTSC(port)
| MCF_USB_PORTSC_PP );
#ifdef DEBUG_PRINT
printf("USB host initialized. Waiting for device connect.\n\n");
#endif
}
/********************************************************************/
/*
* Initialize the USB device for operation. This initialization performs
* basic configuration to prepare the device for connection to a host.
* Since currently only one USB port supports device operation, the port
* for the device init is set at the beginning of this function. If future
* devices implement more than one USB device port then this can be changed
* to a passed in parameter.
*
* Parameters:
*/
uint32
usb_device_init(void)
{
uint32 ep_list_addr;
int port = USB_OTG;
/* Initialize the clock divider for the USB */
MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBDIV;
//--- Set Device Mode ---//
#ifdef DEBUG_PRINT
printf("Set device mode.\n");
#endif
MCF_USB_USBMODE(port) = (MCF_USB_USBMODE_ES | MCF_USB_USBMODE_CM_DEVICE);
/*--- Intial Configuration ---*/
MCF_USB_USBCMD(port) &= ~( MCF_USB_USBCMD_ITC(0xFF)); // Set interrupt threshold control = 0
MCF_USB_USBMODE(port) |= MCF_USB_USBMODE_SLOM; // Setup Lockouts Off
/* Initialize EP0 to handle enumeration. This function will also allocate
* memory to be used for the device endpoint list. */
ep_list_addr = usb_device_ep0_init();
/* Initialize queue head for EP0 IN (device to host) */
usb_ep_qh_init(ep_list_addr, EP_QH0_IN, 0, 0x40, 0, 1);
/* Initialize queue head for EP0 OUT (host to device) */
usb_ep_qh_init(ep_list_addr, EP_QH0_OUT, 0, 0x40, 0, 1);
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_RS; // RUN controller
/* Enable a valid B session to allow device to connect to a host. */
MCF_CCM_UOCSR = ( 0
| MCF_CCM_UOCSR_BVLD );
#ifdef DEBUG_PRINT
printf("USB device initialized.\n");
#endif
return ep_list_addr;
}
/********************************************************************/
/*
* This function allocates memory in the heap to use as the device
* endpoint list. Then the function will initialize endpoint 0 so that
* it is ready to respond to the host for enumeration.
* Since currently only one USB port supports device operation, the port
* for the device init is set at the beginning of this function. If future
* devices implement more than one USB device port then this can be changed
* to a passed in parameter.
*
* Parameters:
* eplistaddr return a pointer to the device endpoint list
*/
uint32
usb_device_ep0_init(void)
{
int i, port = USB_OTG;
uint32 eplistaddr;
/* Allocate space for the device endpoint list*/
/*
* The USB requires the endpoint listb to be aligned on a 2kbyte boundary.
* In order to accomplish this, the data is over-allocated and
* adjusted.
*/
eplistaddr = (uint32)malloc(sizeof(2048)*2);
eplistaddr = (eplistaddr + 2048) & 0xFFFFF800;
/* Set the device endpoint list address */
MCF_USB_EPLISTADDR(port) = eplistaddr;
/* Clear the entire ep list */
for ( i =0; i < 0x10; i++)
*((uint32 *)(eplistaddr + (i*4))) = 0;
/* Configure EP0. Only the required EP0 for control traffic is initialized at this time. */
MCF_USB_EPCR0(port) |= (MCF_USB_EPCR_TXE | MCF_USB_EPCR_RXE); // Enable TX/RX of EP0
return eplistaddr;
}
/********************************************************************/
/*
* Initialize the periodic schedule. This function creates an empty
* frame list for the periodic schedule, points the periodic base
* address to the empty frame list, and enables the periodic schedule.
*
* Parameters:
* port USB module to initialize
* frame_list_size size of the frame list for the periodic schedule
* periodic_base pointer to the start of the allocated frame list
*/
uint32
periodic_schedule_init(int port, uint32 frame_list_size)
{
uint32 i;
uint32 periodic_base;
uint32 malloc_addr;
/* Disable the asynchronous schedule */
// MCF_USB_USBCMD(port) &= ~MCF_USB_USBCMD_ASE;
/* Initialize the USBCMD register for the desired size of the frame list */
switch (frame_list_size)
{ case 1024:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_1024;
break;
case 512:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_512;
break;
case 256:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_256;
break;
case 128:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_128;
break;
case 64:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_64;
break;
case 32:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_32;
break;
case 16:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_16;
break;
case 8:
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_8;
break;
default:
printf("ERR!! Invalid frame list size\n");
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_FS_1024; /* Use the max size by default */
break;
}
/*
* The USB requires the frame list to be aligned on an 8Kbyte boundary.
* In order to accomplish this, the data is over-allocated according to
* the largest possible frame list size and adjusted.
*/
/* Allocate memory for the frame list */
malloc_addr = (uint32)malloc(1024*4);
periodic_base = (uint32)((malloc_addr + 0x1000) & 0xFFFFF000);
/* Fill the frame list with link pointers marked as invalid
* since we don't have any traffic to send yet.
*/
for ( i=0; i<(frame_list_size*4); i=i+4)
*(uint32 *)(periodic_base+i) = 1;
/* Initialize the Periodic base address register */
MCF_USB_PERIODICLISTBASE(port) = periodic_base;
/* Enable the periodic schedule */
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_PSE;
/* Wait for periodic schedule to enable */
while (!(MCF_USB_USBSTS(port) & MCF_USB_USBSTS_PS));
#ifdef DEBUG_PRINT
printf("Periodic schedule is enabled.\n");
#endif
return periodic_base;
}
/********************************************************************/
/*
* Issue a USB reset to the specified port.
*
* Parameters:
* port USB module to send reset
*/
void
send_usb_reset(int port)
{
MCF_USB_PORTSC(port) |= MCF_USB_PORTSC_PR; // Set Port Reset
#ifdef DEBUG_PRINT
printf("Start reset.\n");
printf("PORTSC = 0x%08x\n",MCF_USB_PORTSC(port));
#endif
/* Wait for reset to finish */
while (MCF_USB_PORTSC(port) & MCF_USB_PORTSC_PR);
#ifdef DEBUG_PRINT
printf("USB reset complete.\n\n");
#endif
}
/********************************************************************/
/*
* USB device response to a USB bus reset.
*
* Parameters:
*/
void usb_bus_reset(void)
{
int port = USB_OTG;
uint32 temp;
// printf("USBSTS = 0x%08x\n",MCF_USB_USBSTS(port));
/* Clear all setup token semaphores */
temp = MCF_USB_EPSETUPSR(port);
MCF_USB_EPSETUPSR(port) = temp;
#ifdef DEBUG_PRINT
printf("EPSETUPSR = 0x%08x\n",MCF_USB_EPSETUPSR(port));
#endif
/* Clear all complete status bits */
temp = MCF_USB_EPCOMPLETE(port);
MCF_USB_EPCOMPLETE(port) = temp;
#ifdef DEBUG_PRINT
printf("EPCOMPLETE = 0x%08x\n",MCF_USB_EPCOMPLETE(port));
#endif
/* Wait for all primed status to clear */
while (MCF_USB_EPPRIME(port));
#ifdef DEBUG_PRINT
printf("EPPRIME = 0x%08x\n",MCF_USB_EPPRIME(port));
#endif
/* Flush all endpoints */
MCF_USB_EPFLUSH(port) = 0xFFFFFFFF;
/* Wait for host to stop signalling reset */
while (MCF_USB_PORTSC(port) & MCF_USB_PORTSC_PR);
/* Clear reset status bit */
MCF_USB_USBSTS(port) |= MCF_USB_USBSTS_URI | MCF_USB_USBSTS_UI;
#ifdef DEBUG_PRINT
printf("\n\nUSB Bus Reset Complete!!!\n");
printf("USBSTS = 0x%08x\n",MCF_USB_USBSTS(port));
#endif
}
/********************************************************************/
/*
* USB device function to return the data from a setup packet.
*
* Parameters:
* ep_list_addr pointer to the device endpoint list address
* setup03 bytes 0-3 of the setup packet
* setup47 bytes 4-7 of the setup packet
*/
void get_setup_packet(uint32 ep_list_addr, uint32* setup03, uint32* setup47)
{
int port = USB_OTG;
/* Wait for setup */
// while (!(MCF_USB_USBSTS(port) & MCF_USB_USBSTS_UI ));
while(!(MCF_USB_EPSETUPSR(port) & MCF_USB_EPSETUPSR_EPSETUPSTAT(1)));
/* Verify that transaction is a SETUP on EP0 */
// if (MCF_USB_EPSETUPSR(port) != 1)
// printf("\nERR!!! Expected SETUP on EP0 not received!\n");
/* Clear setup identification */
MCF_USB_EPSETUPSR(port) |= MCF_USB_EPSETUPSR_EPSETUPSTAT(1);
/* Set setup tripwire */
MCF_USB_USBCMD(port) |= MCF_USB_USBCMD_SUTW;
/* Get the actual setup data. The data is returned little endian
* so it needs to be byte swapped.
*/
*(uint32 *)setup03 = swap32(*(uint32 *)(ep_list_addr+0x28));
*(uint32 *)setup47 = swap32(*(uint32 *)(ep_list_addr+0x2C));
/* Wait for SUTW bit to set */
while ( !(MCF_USB_USBCMD(port) & MCF_USB_USBCMD_SUTW));
/* Clear SUTW bit */
MCF_USB_USBCMD(port) &= ~MCF_USB_USBCMD_SUTW;
/* Wait for EPSETUP to clear */
while (MCF_USB_EPSETUPSR(port) & MCF_USB_EPSETUPSR_EPSETUPSTAT(1));
}
/********************************************************************/
int swap32(int data)
{
uint32 swapped = 0;
swapped |= data & 0x000000ff;
swapped <<= 8;
data >>= 8;
swapped |= data & 0x000000ff;
swapped <<= 8;
data >>= 8;
swapped |= data & 0x000000ff;
swapped <<= 8;
data >>= 8;
swapped |= data & 0x000000ff;
return(swapped);
}
/********************************************************************/
/*
* Return the speed of the USB port.
*
* Parameters:
* port USB module to send reset
*/
int
get_port_speed(int port)
{
int speed;
/* Wait for connect */
while(!( MCF_USB_PORTSC(port) & MCF_USB_PORTSC_CCS));
/* Determine the speed we are connected at. */
speed = (MCF_USB_PORTSC(port) & MCF_USB_PORTSC_PSPD(0x3));
#ifdef DEBUG_PRINT
switch (speed)
{ case MCF_USB_PORTSC_PSPD_FULL:
printf("Connected at full-speed\n");
break;
case MCF_USB_PORTSC_PSPD_LOW:
printf("Connected at low-speed\n");
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -