📄 usb.c
字号:
}
ep[epnum].buffer.position += fifo_data;
}
if (event & (MCF5272_USB_EP0ISR_OUT_LVL | MCF5272_USB_EPNISR_FIFO_LVL))
{
/* Clear the FIFO Level Interrupt bits */
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EP0ISR_OUT_LVL
| MCF5272_USB_EPNISR_FIFO_LVL);
}
if (event & (MCF5272_USB_EP0ISR_OUT_EOT | MCF5272_USB_EPNISR_EOT))
{
/* The current transfer is complete */
/* Clear the EOT Interrupt bits */
MCF5272_WR_USB_EPISR(imm, epnum, 0
| MCF5272_USB_EP0ISR_OUT_EOT
| MCF5272_USB_EPNISR_EOT);
/* Call the Rx Handler */
usb_ep_rx_done(epnum,SUCCESS);
/* Free the buffer if it was malloc()ed */
if (ep[epnum].buffer.free)
{
ep[epnum].buffer.free = FALSE;
free(ep[epnum].buffer.start);
}
ep[epnum].buffer.length = 0;
ep[epnum].buffer.position = 0;
ep[epnum].buffer.start = 0;
}
}
/********************************************************************/
void
usb_bus_state_chg_service(uint32 event)
{
if (event & SUSPEND)
{
#if (DEBUG)
printf("The bus is suspended (J state)\n");
#endif
if (event & ENABLE_WAKEUP)
{
#if (DEBUG)
printf("Remote wakeup enabled.\n");
#endif
/* Set the Remote Wakeup flag */
fRemoteWakeup = 1;
}
}
if (event & RESUME)
{
#if (DEBUG)
printf("The bus has been resumed (K state)\n");
#endif
}
if (event & RESET)
{
#if (DEBUG)
printf("USB reset signal detected\n");
#endif
}
}
/********************************************************************/
void
usb_devcfg_service(void)
{
static uint8 last_addr = 0;
static uint8 last_config = 0;
static uint32 last_altsetting = 0;
uint8 flags, i, j, epnum;
USB_CONFIG_DESC *pCfgDesc;
USB_INTERFACE_DESC *pIfcDesc;
USB_ENDPOINT_DESC *pEpDesc;
MCF5272_IMM *imm = mcf5272_get_immp();
flags = 0;
if (last_addr != MCF5272_RD_USB_FAR(imm))
{
#if (DEBUG)
printf("Address change: old addr = %d, new addr = %d\n",
last_addr, MCF5272_RD_USB_FAR(imm));
#endif
last_addr = MCF5272_RD_USB_FAR(imm);
flags |= ADDRESS_CHG;
}
if (last_config != (MCF5272_RD_USB_EP0SR(imm) >> 12))
{
#if (DEBUG)
printf("Configuration change: old cfg = %d, new cfg = %d\n",
last_config, MCF5272_RD_USB_EP0SR(imm) >> 12);
#endif
last_config = (uint8)(MCF5272_RD_USB_EP0SR(imm) >> 12);
flags |= CONFIGURATION_CHG;
}
if (last_altsetting != (MCF5272_RD_USB_ASR(imm)))
{
#if (DEBUG)
printf("Interface change: old setting = %d, new setting = %d\n",
last_altsetting, MCF5272_RD_USB_ASR(imm));
#endif
last_altsetting = (MCF5272_RD_USB_ASR(imm));
flags |= INTERFACE_CHG;
}
if (flags & (INTERFACE_CHG | CONFIGURATION_CHG))
{
/* Initialize Endpoint settings for this configuration */
/* Start by marking all Endpoints as disabled (except EP0) */
for (i = 1; i < NUM_ENDPOINTS; i++)
ep[i].ttype = DISABLED;
/* Get pointer to active Configuration descriptor */
pCfgDesc = (USB_CONFIG_DESC *)usb_get_desc(last_config, -1, -1, -1);
/* Iterate through all the valid Interfaces in this Configuration */
for (i = 0; i < pCfgDesc->bNumInterfaces; i++)
{
pIfcDesc = (USB_INTERFACE_DESC *)usb_get_desc(last_config, i,
AltSetting(imm, i),
-1);
/* Iterate through all the valid Endpoints in this interface */
for (j = 0; j < pIfcDesc->bNumEndpoints; j++)
{
pEpDesc = (USB_ENDPOINT_DESC *)usb_get_desc(last_config, i,
AltSetting(imm, i),
j);
if (pEpDesc)
{
epnum = pEpDesc->bEndpointAddress & 0x0F;
/* See if this Endpoint is actually active */
if (!(MCF5272_RD_USB_EPISR(imm, epnum) &
MCF5272_USB_EPNISR_PRES))
return;
/* Set the new transfer type */
ep[epnum].ttype = pEpDesc->bmAttributes;
/* Set the current direction */
if (MCF5272_RD_USB_EPISR(imm, epnum) &
MCF5272_USB_EPNISR_DIR)
ep[epnum].dir = IN;
else
ep[epnum].dir = OUT;
/* Get the current packet size */
ep[epnum].packet_size = (uint16)(pEpDesc->wMaxPacketSizeL +
(pEpDesc->wMaxPacketSizeH << 8));
/* No buffer allocated yet */
ep[epnum].buffer.start = 0;
ep[epnum].buffer.position = 0;
ep[epnum].buffer.length = 0;
ep[epnum].buffer.free = 0;
if (ep[epnum].ttype == ISOCHRONOUS)
{
/* Set the FIFO length */
ep[epnum].fifo_length = ep[epnum].packet_size;
/* Enable ISO mode and set FIFO Level for interrupts */
MCF5272_WR_USB_EPCTL(imm, epnum, 0
| MCF5272_USB_EPNCTL_ISO_MODE
| MCF5272_USB_EPNCTL_FIFO_LVL(2));
/* Disable EOP and EOT interrupts, enable FIFO_LVL */
MCF5272_WR_USB_EPIMR(imm, epnum,
(MCF5272_RD_USB_EPIMR(imm, epnum)
& ~(MCF5272_USB_EPNISR_EOP
| MCF5272_USB_EPNISR_EOT))
| MCF5272_USB_EPNISR_FIFO_LVL);
}
else
{
/* Set the FIFO length */
ep[epnum].fifo_length = \
(uint16)(ep[epnum].packet_size * FIFO_DEPTH);
/* Disable ISO mode and set IN-BUSY (if IN EP)*/
if (ep[epnum].dir == IN)
{
/* 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_USB_EPNCTL_IN_BUSY);
}
else
{
MCF5272_WR_USB_EPCTL(imm, epnum, 0);
}
/* Enable EOP and EOT interrupts, disable FIFO_LVL */
MCF5272_WR_USB_EPIMR(imm, epnum,
(MCF5272_RD_USB_EPIMR(imm, epnum)
& ~MCF5272_USB_EPNISR_FIFO_LVL)
| MCF5272_USB_EPNISR_EOP
| MCF5272_USB_EPNISR_EOT);
}
}
}
}
usb_fifo_init();
}
/* Call application specific routine to notify of config/iface change */
usb_devcfg_notice(flags, last_config, last_altsetting);
}
/********************************************************************/
void
usb_vendreq_done(uint32 error)
{
MCF5272_IMM *imm = mcf5272_get_immp();
if (error)
/* This sends a single STALL as the handshake */
MCF5272_WR_USB_EP0CTL(imm,
MCF5272_RD_USB_EP0CTL(imm)
| MCF5272_USB_EP0CTL_CMD_OVER
| MCF5272_USB_EP0CTL_CMD_ERR);
else
MCF5272_WR_USB_EP0CTL(imm,
MCF5272_RD_USB_EP0CTL(imm)
| MCF5272_USB_EP0CTL_CMD_OVER);
return;
}
/********************************************************************/
void
usb_sort_ep_array(USB_EP_STATE *list[], int n)
{
/* Simple bubble sort function called by usb_fifo_init() */
int i, pass, sorted;
USB_EP_STATE *temp;
pass = 1;
do {
sorted = 1;
for (i = 0; i < n - pass; ++i)
{
if (list[i]->fifo_length < list[i+1]->fifo_length )
{
/* Exchange out-of-order pair */
temp = list[i];
list[i] = list[i + 1];
list[i+1] = temp;
sorted = 0;
}
}
++pass;
} while(!sorted);
}
/********************************************************************/
void
usb_make_power_of_two(uint32 *size)
{
/* Called by usb_fifo_init() */
int i, not_power_of_two = 0;
uint32 new_size = *size;
for (i = 0; new_size != 1; i++)
{
if (new_size & 0x0001)
not_power_of_two = 1;
new_size >>= 1;
}
new_size = 1 << (i + not_power_of_two);
if (new_size > 256)
new_size = 256;
*size = new_size;
}
/********************************************************************/
void
usb_fifo_init(void)
{
MCF5272_IMM *imm = mcf5272_get_immp();
USB_EP_STATE *pIN[NUM_ENDPOINTS];
USB_EP_STATE *pOUT[NUM_ENDPOINTS];
uint8 nIN, nOUT, i;
uint16 INpos, OUTpos;
/* Endpoint 0 is always present and bi-directional */
pIN[0] = &ep[0];
pOUT[0] = &ep[0];
nIN = nOUT = 1;
/* Sort the active endpoints by direction */
for (i = 1; i < NUM_ENDPOINTS; i++)
{
if (ep[i].ttype != DISABLED)
{
if (ep[i].dir == IN)
pIN[nIN++] = &ep[i];
else
pOUT[nOUT++] = &ep[i];
}
}
/* Make sure FIFO size is a power of 2; if not, make it so */
for (i = 0; i < nIN; i++)
usb_make_power_of_two( &(pIN[i]->fifo_length) );
for (i = 0; i < nOUT; i++)
usb_make_power_of_two( &(pOUT[i]->fifo_length) );
/* Sort the endpoints by FIFO length (decending) */
usb_sort_ep_array(pIN, nIN);
usb_sort_ep_array(pOUT, nOUT);
/* Calculate the FIFO address for each endpoint */
INpos = 0;
OUTpos = 0;
for (i = 0; i < nIN; i++)
{
pIN[i]->in_fifo_start = INpos;
INpos += pIN[i]->fifo_length;
}
for (i = 0; i < nOUT; i++)
{
pOUT[i]->out_fifo_start = OUTpos;
OUTpos += pOUT[i]->fifo_length;
}
/* Save the FIFO settings into the Configuration Registers */
/* Initialize Endpoint 0 IN FIFO */
MCF5272_WR_USB_IEP0CFG(imm, 0
| (ep[0].packet_size << 22)
| (ep[0].fifo_length << 11)
| ep[0].in_fifo_start);
/* Initialize Endpoint 0 OUT FIFO */
MCF5272_WR_USB_OEP0CFG(imm, 0
| (ep[0].packet_size << 22)
| (ep[0].fifo_length << 11)
| ep[0].out_fifo_start);
for (i = 1; i < NUM_ENDPOINTS; i++)
{
if (ep[i].ttype != DISABLED)
{
if (ep[i].dir == IN)
/* Initialize Endpoint i FIFO */
MCF5272_WR_USB_EPCFG(imm, i, 0
| (ep[i].packet_size << 22)
| (ep[i].fifo_length << 11)
| ep[i].in_fifo_start);
else
/* Initialize Endpoint i FIFO */
MCF5272_WR_USB_EPCFG(imm, i, 0
| (ep[i].packet_size << 22)
| (ep[i].fifo_length << 11)
| ep[i].out_fifo_start);
}
}
}
/********************************************************************/
uint32
usb_tx_data(uint32 epnum, uint8 *start, uint16 length)
{
MCF5272_IMM *imm = mcf5272_get_immp();
uint32 imr_mask, i;
/* Make sure there is data to send */
if (!start)
return 0;
/* Check the bounds on epnum */
if (epnum > NUM_ENDPOINTS)
return 0;
/* See if the EP is currently busy */
if (ep[epnum].buffer.start || (epnum && MCF5272_RD_USB_EPDPR(imm, epnum)))
return 0;
/* Make sure this is an IN endpoint */
if (epnum && !(MCF5272_RD_USB_EPISR(imm, epnum) & MCF5272_USB_EPNISR_DIR))
return 0;
/* Make sure this EP is not HALTed */
if (MCF5272_RD_USB_EPISR(imm, epnum) & MCF5272_USB_EPNISR_HALT)
return 0;
/* Setup the EP Buffer structure */
ep[epnum].buffer.start = start;
ep[epnum].buffer.length = length;
ep[epnum].buffer.position = 0;
/* Save off the current IMR */
imr_mask = MCF5272_RD_USB_EPIMR(imm, epnum);
/* Clear the EOT, EOP and FIFO_LVL mask bits */
MCF5272_WR_USB_EPIMR(imm, epnum, imr_mask &
~(MCF5272_USB_EPNISR_EOT
| MCF5272_USB_EPNISR_EOP
| MCF5272_USB_EPNISR_FIFO_LVL));
for (i = 0; i < ep[epnum].fifo_length; )
{
if ( (ep[epnum].buffer.length - i) <= 3 )
{
MCF5272_WR_USB_EPDR(imm, epnum, 8, ep[epnum].buffer.start[i]);
i++;
}
else
{
MCF5272_WR_USB_EPDR(imm, epnum, 32,
*(uint32 *)(&ep[epnum].buffer.start[i]));
i += 4;
}
if ( i == ep[epnum].buffer.length )
{
/* This is all of the data to be sent -> 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 = (uint16)i;
MCF5272_WR_USB_EPIMR(imm, epnum, imr_mask);
return 1;
}
/********************************************************************/
uint8*
usb_get_desc(int8 config, int8 iface, int8 setting, int8 ep)
{
/* Note:
* ep is the offset and not the physical endpoint number
* In order to get the config desc pointer, specify -1 for
* all other inputs except config
* In order to get the interface/alternate setting desc pointer,
* specify -1 for epNum
*/
int i;
uint8 *pDesc = (uint8 *)&Descriptors;
if (config != -1)
{
if (config > ((USB_DEVICE_DESC *)pDesc)->bNumConfigurations)
return 0;
/* Allow for non-standard desc between device and config desc */
while (pDesc[1] != CONFIGURATION)
pDesc += pDesc[0];
/* pDesc now points to Config 1 descriptor */
for (i = 1; i < config;)
{
pDesc += pDesc[0];
if (pDesc[1] == CONFIGURATION)
i++;
}
/* pDesc now points to the correct Configuration descriptor */
if ((iface != -1) && (setting != -1))
{
if (iface >= ((USB_CONFIG_DESC *)pDesc)->bNumInterfaces)
return 0;
/* Allow for non-standard desc between config and iface desc */
while (pDesc[1] != INTERFACE)
pDesc += pDesc[0];
/* pDesc now points to first Interface descriptor */
for (i = 0; i < iface;)
{
pDesc += pDesc[0];
if (pDesc[1] == INTERFACE && pDesc[3] == 0)
i++;
}
/* pDesc now points to correct Interface descriptor */
for (i = 0; i < setting;)
{
pDesc += pDesc[0];
if (pDesc[1] == INTERFACE)
{
if (pDesc[2] != iface)
return 0;
else
i++;
}
}
/* pDesc now points to correct Alternate Setting descriptor */
if (ep != -1)
{
if (ep >= pDesc[4])
return 0;
/* Allow for non-standard desc between iface and ep desc */
while (pDesc[1] != ENDPOINT)
pDesc += pDesc[0];
/* pDesc now points to first Endpoint descriptor */
for (i = 0; i < ep;)
{
pDesc += pDesc[0];
if (pDesc[1] == ENDPOINT)
i++;
}
/* pDesc now points to the correct Endpoint descriptor */
}
}
}
return (pDesc);
}
/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -