📄 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 + -