📄 usb.c
字号:
case MCF_USB_PORTSC_PSPD_HIGH:
printf("Connected at high-speed\n");
break;
default:
printf("Invalid port speed\n");
break;
}
printf("PORTSC = 0x%08x\n",MCF_USB_PORTSC(port));
#endif
return speed;
}
/********************************************************************/
/*
* Disable the asynchronous and periodic lists.
*
* Parameters:
* port USB module to send reset
*/
void
disable_async_per_schedules(int port)
{
/* Disable the asynchronous schedule */
MCF_USB_USBCMD(port) &= ~MCF_USB_USBCMD_ASE;
/* Wait for asynchronous enable bit to clear */
while (MCF_USB_USBCMD(port) & MCF_USB_USBCMD_ASE);
/* Disable the periodic schedule schedule */
MCF_USB_USBCMD(port) &= ~MCF_USB_USBCMD_PSE;
/* Wait for periodic schedule enable bit to clear */
while (MCF_USB_USBCMD(port) & MCF_USB_USBCMD_PSE);
}
/********************************************************************/
/*
* Function to send an IN packet to the host while in USB device mode.
*
* Parameters:
* eplistaddr pointer to the device endpoint list
* epnum endpoint number to use
* buf data to be sent to host
* size amount of data to be transferred in bytes
*/
void
usb_device_send_control_packet(uint32 eplistaddr, uint32 epnum, uint8* buf, uint32 size)
{
int port = USB_OTG;
USB_DTD * usb_dtd1, * usb_dtd2;
uint8 * recv_buf[MAX_USB_DESC_SIZE];
/* Initialize dTD to send device descriptor */
usb_dtd1 = usb_dtd_init(size, 0, 0, (uint32*) buf);
/* Point the endpoint IN QH to the dTD */
((USB_EP_QH*)(eplistaddr + EP_QH_IN(epnum)))->next_dtd = (uint32)usb_dtd1;
/* Prime Tx buffer for control endpoint */
MCF_USB_EPPRIME(port) |= MCF_USB_EPPRIME_PETB(1<<epnum);
/* Wait for prime to complete */
// while (MCF_USB_EPPRIME(port) & MCF_USB_EPPRIME_PETB(1<<epnum));
/* Initialize dTD for receive. The host won't actually send anything,
but a dTD needs to be setup to correctly deal with the 0 byte OUT
packet the host sends after receiving the IN data. */
usb_dtd2 = usb_dtd_init(0x40, 1, 0, (uint32*) recv_buf);
/* Point the endpoint OUT QH to the dTD */
((USB_EP_QH*)(eplistaddr + EP_QH_OUT(epnum)))->next_dtd = (uint32)usb_dtd2;
/* Prime Rx buffer for control endpoint */
MCF_USB_EPPRIME(port) |= MCF_USB_EPPRIME_PERB(1<<epnum);
/* Wait for prime to complete */
// while (MCF_USB_EPPRIME(port) & MCF_USB_EPPRIME_PERB(1<<epnum));
/* Wait for OUT to complete */
while (!(MCF_USB_USBSTS(port) & MCF_USB_USBSTS_UI ));
/* Clear interrupt */
MCF_USB_USBSTS(port) |= MCF_USB_USBSTS_UI;
/* Return memory for dTDs to heap */
free((void *)usb_dtd1->malloc_ptr);
free((void *)usb_dtd2->malloc_ptr);
}
/********************************************************************/
/*
* Function to send an zero length IN packet to the host while in USB device mode.
*
* Parameters:
* eplistaddr pointer to the device endpoint list
* epnum endpoint number to use
*/
void
usb_device_send_zero_len_packet(uint32 eplistaddr, uint32 epnum)
{
int port = USB_OTG;
USB_DTD * usb_dtd1;
uint8 * empty_buf[1];
/* Set up dTD for zero length packet */
/* Initialize dTD */
usb_dtd1 = usb_dtd_init(0, 1, 0, (uint32*) empty_buf);
/* Point the endpoint IN QH to the dTD */
((USB_EP_QH*)(eplistaddr + EP_QH_IN(epnum)))->next_dtd = (uint32)usb_dtd1;
/* Prime Tx buffer for control endpoint */
MCF_USB0_EPPRIME |= MCF_USB_EPPRIME_PETB(1<<epnum);
/* Wait for prime to complete */
while (MCF_USB_EPPRIME(port) & MCF_USB_EPPRIME_PETB(1<<epnum));
/* Wait for IN to complete */
while (!(MCF_USB_USBSTS(port) & MCF_USB_USBSTS_UI ));
/* Clear interrupt */
MCF_USB_USBSTS(port) |= MCF_USB_USBSTS_UI;
/* Return memory for dTDs to heap */
free((void *)usb_dtd1->malloc_ptr);
}
/********************************************************************/
/*
* Allocate memory for a qTD and initialize the qTD.
* This function assumes the qTD is the last in the list so
* the next qTD pointer is not initialized.
*
* Parameters:
* trans_sz number of bytes to be transferred
* ioc interrupt on complete flag
* pid PID code for the transfer (
* buffer_ptr pointer to the data buffer
*/
USB_QTD *
usb_qtd_init(uint32 trans_sz, uint32 ioc, uint32 pid, uint32 * buffer_ptr)
{
USB_QTD *usb_qtd;
uint32 token;
uint32 malloc_addr;
/*
* The USB requires qTDs to be aligned on a 64 byte boundary.
* In order to accomplish this, the data is over-allocated and
* adjusted.
*/
malloc_addr = (uint32)malloc(sizeof(USB_QTD)*2);
usb_qtd = (USB_QTD *)((malloc_addr + 32) & 0xFFFFFFE0);
usb_qtd->next_qtd = 0xDEAD0001;
usb_qtd->alt_qtd = 0x1;
switch (pid)
{
case SETUP_PID:
token = USB_QTD_TOKEN_PID_SETUP;
break;
case OUT_PID:
token = (USB_QTD_TOKEN_DT | USB_QTD_TOKEN_PID_OUT);
break;
case IN_PID:
token = (USB_QTD_TOKEN_DT | USB_QTD_TOKEN_PID_IN);
break;
default:
#ifdef DEBUG_PRINT
printf("ERR!! Invalid PID\n");
#endif
break;
}
if (trans_sz > MAX_QTD_TRANS_SIZE)
#ifdef DEBUG_PRINT
printf("ERR!! Invalid transfer size.\n");
#endif
if (ioc)
token |= USB_QTD_TOKEN_IOC;
usb_qtd->qtd_token = (token
| USB_QTD_TOKEN_TRANS_SIZE(trans_sz)
| USB_QTD_TOKEN_CERR(0x3)
| USB_QTD_TOKEN_STAT_ACTIVE );
usb_qtd->qtd_buf0 = (uint32) buffer_ptr;
usb_qtd->qtd_buf1 = 0;
usb_qtd->qtd_buf2 = 0;
usb_qtd->qtd_buf3 = 0;
usb_qtd->qtd_buf4 = 0;
usb_qtd->malloc_ptr = malloc_addr;
return usb_qtd;
}
/********************************************************************/
/*
* Allocate memory for a QH and initialize the QH.
* This function assumes the QH is the only one in the horizontoal list so
* the horizontal link pointer points to the queue head. This function
* doesn't initialize the qTD pointer either. This must be done later.
*
* Parameters:
* max_packet maximum packet length for the endpoint
* head used to mark the QH as the first in the linked list (not used for interrupt QHs)
* eps end point speed
* epnum end pont number
* dev_addr device address
* smask interrupt schedule mask (only used for periodic schedule QHs)
*/
USB_QH *
usb_qh_init(uint32 max_packet, uint32 head, uint32 eps, uint32 epnum,
uint32 dev_addr, uint32 smask)
{
USB_QH *usb_qh;
uint32 token;
uint32 malloc_addr;
/*
* The USB requires queue heads to be aligned on a 64 byte boundary.
* In order to accomplish this, the data is over-allocated and
* adjusted.
*/
malloc_addr = (uint32)malloc(sizeof(USB_QH)*2);
usb_qh = (USB_QH *)((malloc_addr + 32) & 0xFFFFFFE0);
usb_qh->qh_link_ptr = (((uint32) usb_qh)
| USB_QH_LINK_PTR_TYP_QH );
if (max_packet > MAX_QH_PACKET_SIZE )
#ifdef DEBUG_PRINT
printf("ERR!! Invalid packet size.\n");
#endif
switch (eps)
{
case EPS_FULL:
token = USB_QH_EP_CHAR_EPS_FULL;
break;
case EPS_LOW:
token = USB_QH_EP_CHAR_EPS_LOW;
break;
case EPS_HIGH:
token = USB_QH_EP_CHAR_EPS_HIGH;
break;
default:
#ifdef DEBUG_PRINT
printf("ERR!! Invalid EPS\n");
#endif
break;
}
if (head)
token |= USB_QH_EP_CHAR_H;
usb_qh->ep_char = ( token
| USB_QH_EP_CHAR_MAX_PACKET(max_packet)
| USB_QH_EP_CHAR_DTC
| USB_QH_EP_CHAR_EP(epnum)
| USB_QH_EP_CHAR_DEV_ADDR(dev_addr) );
/* Set interrupt to occur every 8ms */
usb_qh->ep_cap = (USB_QH_EP_CAP_MULT_ONE
| USB_QH_EP_CAP_UFRAME_SMASK(smask));
usb_qh->curr_qtd = 0;
usb_qh->next_qtd = 1;
usb_qh->alt_qtd = 0;
usb_qh->qtd_token = 0;
usb_qh->qtd_buf0 = 0;
usb_qh->qtd_buf1 = 0;
usb_qh->qtd_buf2 = 0;
usb_qh->qtd_buf3 = 0;
usb_qh->qtd_buf4 = 0;
usb_qh->malloc_ptr = malloc_addr;
return usb_qh;
}
/********************************************************************/
/*
* Initialize an endpoint QH. The space for the endpoint queue heads is
* allocated when the endpoint list is created, so this function does not
* call malloc.
*
* Parameters:
* eplistaddr location of the endpoint list
* offset offset within the endpoint list for the EP_QH (there are macros for this)
* mult number of packets per transcation, should be 0 for non-ISO endpoints
* max_packet maximum packet length for the endpoint
* ios flag to enable interrupts on incoming setup packets
* next_dtd ponter to the first dtd for the ep_qh
*/
void usb_ep_qh_init(uint32 eplistaddr, uint32 offset, uint32 mult, uint32 max_packet,
uint32 ios, uint32 next_dtd)
{
USB_EP_QH* usb_ep_qh;
uint32 token;
/* Create a pointer to the endpoint queue head being initialized */
usb_ep_qh = (USB_EP_QH*) (eplistaddr + offset);
if (max_packet > MAX_QH_PACKET_SIZE )
#ifdef DEBUG_PRINT
printf("ERR!! Invalid packet size.\n");
#endif
if (ios)
token = USB_EP_QH_EP_CHAR_IOS;
else
token = 0;
usb_ep_qh->ep_char = ( token
| USB_EP_QH_EP_CHAR_MULT(mult)
| USB_EP_QH_EP_CHAR_MAX_PACKET(max_packet));
usb_ep_qh->curr_dtd = 0;
usb_ep_qh->next_dtd = next_dtd;
usb_ep_qh->dtd_token = 0;
usb_ep_qh->dtd_buf0 = 0;
usb_ep_qh->dtd_buf1 = 0;
usb_ep_qh->dtd_buf2 = 0;
usb_ep_qh->dtd_buf3 = 0;
usb_ep_qh->dtd_buf4 = 0;
}
/********************************************************************/
/*
* Allocate memory for a device transfer descriptor (dTD) and initialize
* the dTD. This function assumes the dTD is the last in the list so
* the next dTD pointer is marked as invalid.
*
* Parameters:
* trans_sz number of bytes to be transferred
* ioc interrupt on complete flag
* pid PID code for the transfer (
* buffer_ptr pointer to the data buffer
*/
USB_DTD *
usb_dtd_init(uint32 trans_sz, uint32 ioc, uint32 multo, uint32 * buffer_ptr)
{
USB_DTD *usb_dtd;
uint32 token;
uint32 malloc_addr;
/*
* The USB requires dTDs to be aligned on a 64 byte boundary.
* In order to accomplish this, the data is over-allocated and
* adjusted.
*/
malloc_addr = (uint32)malloc(sizeof(USB_DTD)*2);
usb_dtd = (USB_DTD *)((malloc_addr + 32) & 0xFFFFFFE0);
usb_dtd->next_dtd = 0xDEAD0001;
if (trans_sz > MAX_DTD_TRANS_SIZE)
#ifdef DEBUG_PRINT
printf("ERR!! Invalid transfer size.\n");
#endif
if (ioc)
token = USB_DTD_TOKEN_IOC;
else
token = 0;
usb_dtd->dtd_token = (token
| USB_DTD_TOKEN_TOTAL_BYTES(trans_sz)
| USB_DTD_TOKEN_MULTO(multo)
| USB_DTD_TOKEN_STAT_ACTIVE );
usb_dtd->dtd_buf0 = (uint32) buffer_ptr;
usb_dtd->dtd_buf1 = 0;
usb_dtd->dtd_buf2 = 0;
usb_dtd->dtd_buf3 = 0;
usb_dtd->dtd_buf4 = 0;
usb_dtd->malloc_ptr = malloc_addr;
return usb_dtd;
}
/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -