📄 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: * xcvr USB_PHY_ULPI or USB_PHY_FSLS */void usb_host_init(int xcvr){ /* Initialize the clock divider for the USB */ //MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBDIV; /* Use external clock source if PLL isn't a multiple of 60MHz */ if (FSYS_MHZ % 60) MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_USBSRC; /* --- Start HOST controller --- */ #ifdef DEBUG_PRINT printf("Set host mode.\n"); #endif MCF_USB_USBMODE = 0 | MCF_USB_USBMODE_ES | MCF_USB_USBMODE_CM_HOST; MCF_USB_USBCMD = 0 | MCF_USB_USBCMD_ASP(3) | MCF_USB_USBCMD_ITC(0); #ifdef DEBUG_PRINT printf("Set RUN bit.\n"); #endif MCF_USB_USBCMD |= MCF_USB_USBCMD_RS; ASSERT(xcvr == USB_PHY_ULPI || xcvr == USB_PHY_FSLS); if (xcvr == USB_PHY_ULPI) { /* Enable the required ULPI signals */ MCF_GPIO_PAR_DMA = MCF_GPIO_PAR_DMA & MCF_GPIO_PAR_DMA_DACK1_MASK | MCF_GPIO_PAR_DMA_DACK1_ULPI_DIR; MCF_GPIO_PAR_USB = 0 | MCF_GPIO_PAR_USB_VBUSEN_ULPI_NXT | MCF_GPIO_PAR_USB_VBUSOC_ULPI_STP; MCF_GPIO_PAR_FEC = MCF_GPIO_PAR_FEC & MCF_GPIO_PAR_FEC_FEC0_MASK | MCF_GPIO_PAR_FEC_FEC0_RMII_ULPI; /* Turn on the port */ MCF_USB_PORTSC = 0 | MCF_USB_PORTSC_PTS_ULPI /* external ULPI transceiver */ | MCF_USB_PORTSC_PP; } else /* (xcvr == USB_PHY_FSLS) */ { /* Enable VBUS_EN and VBUS_OC signals */ MCF_GPIO_PAR_USB = 0 | MCF_GPIO_PAR_USB_VBUSEN_VBUSEN | MCF_GPIO_PAR_USB_VBUSOC_VBUSOC; /* Setup USB_VBUS_OC signal to be active-low */ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBOC; /* Turn on the port */ MCF_USB_PORTSC = 0 | MCF_USB_PORTSC_PTS_FS_LS /* on-chip FS/LS transceiver */ | 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: * xcvr USB_PHY_ULPI or USB_PHY_FSLS */uint32 usb_device_init(int xcvr){ uint32 ep_list_addr;// int port = USB_OTG; /* Initialize the clock divider for the USB */ //MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBDIV; /* Use external clock source if PLL isn't a multiple of 60MHz */ if (FSYS_MHZ % 60) MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_USBSRC; //else // MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBSRC; /* Enable the correct transceiver */ ASSERT(xcvr == USB_PHY_ULPI || xcvr == USB_PHY_FSLS); if (xcvr == USB_PHY_ULPI) { /* Enable the required ULPI signals */ MCF_GPIO_PAR_DMA = MCF_GPIO_PAR_DMA & MCF_GPIO_PAR_DMA_DACK1_MASK | MCF_GPIO_PAR_DMA_DACK1_ULPI_DIR; MCF_GPIO_PAR_USB = 0 | MCF_GPIO_PAR_USB_VBUSEN_ULPI_NXT | MCF_GPIO_PAR_USB_VBUSOC_ULPI_STP; MCF_GPIO_PAR_FEC = MCF_GPIO_PAR_FEC & MCF_GPIO_PAR_FEC_FEC0_MASK | MCF_GPIO_PAR_FEC_FEC0_RMII_ULPI; /* Turn on the port */ MCF_USB_PORTSC = 0 | MCF_USB_PORTSC_PTS_ULPI; /* external ULPI transceiver */ } else /* (xcvr == USB_PHY_FSLS) */ { /* Insure that the MIC2026 ENB signal isn't asserted */ /*MCF_GPIO_PAR_USB = 0 | MCF_GPIO_PAR_USB_VBUSEN_GPIO | MCF_GPIO_PAR_USB_VBUSOC_GPIO; MCF_GPIO_PODR_USB = 0; MCF_GPIO_PDDR_USB = MCF_GPIO_PDDR_USB_PDDR1; */ /* Enable USB controller to control FSLS PHY internal D+ pull-up */ //MCF_CCM_MISCCR |= MCF_CCM_MISCCR_USBPUE; /* Turn on the port */ MCF_USB_PORTSC |= MCF_USB_PORTSC_PTS_FS_LS; /* on-chip FS/LS transceiver */ } //--- Set Device Mode ---// #ifdef DEBUG_PRINT printf("Set device mode.\n"); #endif MCF_USB_USBMODE = (MCF_USB_USBMODE_ES | MCF_USB_USBMODE_CM_DEVICE); /*--- Intial Configuration ---*/ MCF_USB_USBCMD &= ~( MCF_USB_USBCMD_ITC(0xFF)); // Set interrupt threshold control = 0 MCF_USB_USBMODE |= 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 |= MCF_USB_USBCMD_RS; // RUN controller /* Enable a valid B session to allow device to connect to a host. */ MCF_CCM_UOCSR = 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(2048*2); eplistaddr = (eplistaddr + 2048) & 0xFFFFF800; /* Set the device endpoint list address */ MCF_USB_EPLISTADDR = 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 |= (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 &= ~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 |= MCF_USB_USBCMD_FS_1024; break; case 512: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_512; break; case 256: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_256; break; case 128: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_128; break; case 64: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_64; break; case 32: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_32; break; case 16: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_16; break; case 8: MCF_USB_USBCMD |= MCF_USB_USBCMD_FS_8; break; default: printf("ERR!! Invalid frame list size\n"); MCF_USB_USBCMD |= 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 = periodic_base; /* Enable the periodic schedule */ MCF_USB_USBCMD |= MCF_USB_USBCMD_PSE; /* Wait for periodic schedule to enable */ while (!(MCF_USB_USBSTS & 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 |= MCF_USB_PORTSC_PR; // Set Port Reset #ifdef DEBUG_PRINT printf("Start reset.\n"); printf("PORTSC = 0x%08x\n",MCF_USB_PORTSC); #endif /* Wait for reset to finish */ while (MCF_USB_PORTSC & 0x100);//MCF_USB_PORTSC_PR); #ifdef DEBUG_PRINT printf("PORTSC = 0x%08x\n",MCF_USB_PORTSC); 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); /* Clear all setup token semaphores */ temp = MCF_USB_EPSETUPSR; MCF_USB_EPSETUPSR = temp; #ifdef DEBUG_PRINT printf("EPSETUPSR = 0x%08x\n",MCF_USB_EPSETUPSR); #endif /* Clear all complete status bits */ temp = MCF_USB_EPCOMPLETE; MCF_USB_EPCOMPLETE = temp; #ifdef DEBUG_PRINT printf("EPCOMPLETE = 0x%08x\n",MCF_USB_EPCOMPLETE); #endif /* Wait for all primed status to clear */ while (MCF_USB_EPPRIME); #ifdef DEBUG_PRINT printf("EPPRIME = 0x%08x\n",MCF_USB_EPPRIME); #endif /* Flush all endpoints */ MCF_USB_EPFLUSH = 0xFFFFFFFF; /* Wait for host to stop signalling reset */ while (MCF_USB_PORTSC & 0x100);//MCF_USB_PORTSC_PR); /* Clear reset status bit */ MCF_USB_USBSTS |= 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); #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 & MCF_USB_USBSTS_UI )); while(!(MCF_USB_EPSETUPSR & MCF_USB_EPSETUPSR_EPSETUPSTAT(1))); /* Verify that transaction is a SETUP on EP0 */// if (MCF_USB_EPSETUPSR != 1)// printf("\nERR!!! Expected SETUP on EP0 not received!\n"); /* Clear setup identification */ MCF_USB_EPSETUPSR |= MCF_USB_EPSETUPSR_EPSETUPSTAT(1); /* Set setup tripwire */ MCF_USB_USBCMD |= 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 & MCF_USB_USBCMD_SUTW)); /* Clear SUTW bit */ MCF_USB_USBCMD &= ~MCF_USB_USBCMD_SUTW; /* Wait for EPSETUP to clear */ while (MCF_USB_EPSETUPSR & MCF_USB_EPSETUPSR_EPSETUPSTAT(1));}/********************************************************************/int swap32(int data){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -