📄 usbdcore_mpc8xx.c
字号:
break; } else if (ret == -2) { if (usbp->usber & USB_E_TXB) { usbp->usber |= USB_E_TXB; } mpc8xx_udc_flush_tx_fifo (ep); return -1; } }; if (usbp->usber & USB_E_TXB) { usbp->usber |= USB_E_TXB; } /* ACK must be present <= 18bit times from TX */ if (ret == -1) { continue; } /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */ epi->sent += pkt_len; epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize); TOGGLE_TX_PID (ep_ref[ep].pid); if (epi->sent >= epi->tx_urb->actual_length) { epi->tx_urb->actual_length = 0; epi->sent = 0; if (ep_ref[ep].sc & EP_SEND_ZLP) { ep_ref[ep].sc &= ~EP_SEND_ZLP; } else { return 0; } } } ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent, epi->tx_urb->actual_length); return -1;}/* mpc8xx_udc_dump_request * * Dump a control request to console */static void mpc8xx_udc_dump_request (struct usb_device_request *request){ DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x " "wIndex:%04x wLength:%04x ?\n", request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength); return;}/* mpc8xx_udc_ep0_rx_setup * * Decode received ep0 SETUP packet. return non-zero on error */static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp){ unsigned int x = 0; struct urb *purb = ep_ref[0].urb; struct usb_endpoint_instance *epi = &udc_device->bus->endpoint_array[0]; for (; x < rx_cbdp->cbd_datlen; x++) { *(((unsigned char *) &ep_ref[0].urb->device_request) + x) = *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); } mpc8xx_udc_clear_rxbd (rx_cbdp); if (ep0_recv_setup (purb)) { mpc8xx_udc_dump_request (&purb->device_request); return -1; } if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { switch (purb->device_request.bRequest) { case USB_REQ_SET_ADDRESS: /* Send the Status OUT ZLP */ ep_ref[0].pid = TX_BD_PID_DATA1; purb->actual_length = 0; mpc8xx_udc_init_tx (epi, purb); mpc8xx_udc_ep_tx (epi); /* Move to the addressed state */ usbp->usaddr = udc_device->address; mpc8xx_udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED); return 0; case USB_REQ_SET_CONFIGURATION: if (!purb->device_request.wValue) { /* Respond at default address */ usbp->usaddr = 0x00; mpc8xx_udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED); } else { /* TODO: Support multiple configurations */ mpc8xx_udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED); for (x = 1; x < MAX_ENDPOINTS; x++) { if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { ep_ref[x].pid = TX_BD_PID_DATA0; } else { ep_ref[x].pid = RX_BD_PID_DATA0; } /* Set configuration must unstall endpoints */ usbp->usep[x] &= ~STALL_BITMASK; } } break; default: /* CDC/Vendor specific */ break; } /* Send ZLP as ACK in Status OUT phase */ ep_ref[0].pid = TX_BD_PID_DATA1; purb->actual_length = 0; mpc8xx_udc_init_tx (epi, purb); mpc8xx_udc_ep_tx (epi); } else { if (purb->actual_length) { ep_ref[0].pid = TX_BD_PID_DATA1; mpc8xx_udc_init_tx (epi, purb); if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) { ep_ref[0].sc |= EP_SEND_ZLP; } if (purb->device_request.wValue == USB_DESCRIPTOR_TYPE_DEVICE) { if (le16_to_cpu (purb->device_request.wLength) > purb->actual_length) { /* Send EP0_MAX_PACKET_SIZE bytes * unless correct size requested. */ if (purb->actual_length > epi->tx_packetSize) { purb->actual_length = epi->tx_packetSize; } } } mpc8xx_udc_ep_tx (epi); } else { /* Corrupt SETUP packet? */ ERR ("Zero length data or SETUP with DATA-IN phase ?\n"); return 1; } } return 0;}/* mpc8xx_udc_init_tx * * Setup some basic parameters for a TX transaction */static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, struct urb *tx_urb){ epi->sent = 0; epi->last = 0; epi->tx_urb = tx_urb;}/* mpc8xx_udc_ep0_rx * * Receive ep0/control USB data. Parse and possibly send a response. */static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp){ if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) { /* Unconditionally accept SETUP packets */ if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) { mpc8xx_udc_stall (0); } } else { mpc8xx_udc_clear_rxbd (rx_cbdp); if ((rx_cbdp->cbd_datlen - 2)) { /* SETUP with a DATA phase * outside of SETUP packet. * Reply with STALL. */ mpc8xx_udc_stall (0); } }}/* mpc8xx_udc_epn_rx * * Receive some data from cbd into USB system urb data abstraction * Upper layers should NAK if there is insufficient RX data space */static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp){ struct usb_endpoint_instance *epi = 0; struct urb *urb = 0; unsigned int x = 0; if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) { return 0; } /* USB 2.0 PDF section 8.6.4 * Discard data with invalid PID it is a resend. */ if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) { return 1; } TOGGLE_RX_PID (ep_ref[epid].pid); epi = &udc_device->bus->endpoint_array[epid]; urb = epi->rcv_urb; for (; x < (rx_cbdp->cbd_datlen - 2); x++) { *((unsigned char *) (urb->buffer + urb->actual_length + x)) = *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); } if (x) { usbd_rcv_complete (epi, x, 0); if (ep_ref[epid].urb->status == RECV_ERROR) { DBG ("RX error unset NAK\n"); udc_unset_nak (epid); } } return x;}/* mpc8xx_udc_clock_init * * Obtain a clock reference for Full Speed Signaling */static void mpc8xx_udc_clock_init (volatile immap_t * immr, volatile cpm8xx_t * cp){#if defined(CFG_USB_EXTC_CLK) /* This has been tested with a 48MHz crystal on CLK6 */ switch (CFG_USB_EXTC_CLK) { case 1: immr->im_ioport.iop_papar |= 0x0100; immr->im_ioport.iop_padir &= ~0x0100; cp->cp_sicr |= 0x24; break; case 2: immr->im_ioport.iop_papar |= 0x0200; immr->im_ioport.iop_padir &= ~0x0200; cp->cp_sicr |= 0x2D; break; case 3: immr->im_ioport.iop_papar |= 0x0400; immr->im_ioport.iop_padir &= ~0x0400; cp->cp_sicr |= 0x36; break; case 4: immr->im_ioport.iop_papar |= 0x0800; immr->im_ioport.iop_padir &= ~0x0800; cp->cp_sicr |= 0x3F; break; default: udc_state = STATE_ERROR; break; }#elif defined(CFG_USB_BRGCLK) /* This has been tested with brgclk == 50MHz */ int divisor = 0; if (gd->cpu_clk < 48000000L) { ERR ("brgclk is too slow for full-speed USB!\n"); udc_state = STATE_ERROR; return; } /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz) * but, can /probably/ live with close-ish alternative rates. */ divisor = (gd->cpu_clk / 48000000L) - 1; cp->cp_sicr &= ~0x0000003F; switch (CFG_USB_BRGCLK) { case 1: cp->cp_brgc1 |= (divisor | CPM_BRG_EN); cp->cp_sicr &= ~0x2F; break; case 2: cp->cp_brgc2 |= (divisor | CPM_BRG_EN); cp->cp_sicr |= 0x00000009; break; case 3: cp->cp_brgc3 |= (divisor | CPM_BRG_EN); cp->cp_sicr |= 0x00000012; break; case 4: cp->cp_brgc4 = (divisor | CPM_BRG_EN); cp->cp_sicr |= 0x0000001B; break; default: udc_state = STATE_ERROR; break; }#else#error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined"#endif}/* mpc8xx_udc_cbd_attach * * attach a cbd to and endpoint */static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size){ if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) { udc_state = STATE_ERROR; return; } if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT || (!tx_size && !rx_size)) { udc_state = STATE_ERROR; return; } /* Attach CBD to appropiate Parameter RAM Endpoint data structure */ if (rx_size) { endpoints[ep]->rbase = (u32) rx_cbd[rx_ct]; endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_ct++; if (!ep) { endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; rx_ct++; } else { rx_ct += 2; endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; rx_ct++; } /* Where we expect to RX data on this endpoint */ ep_ref[ep].prx = rx_cbd[rx_ct - 1]; } else { ep_ref[ep].prx = 0; endpoints[ep]->rbase = 0; endpoints[ep]->rbptr = 0; } if (tx_size) { endpoints[ep]->tbase = (u32) tx_cbd[tx_ct]; endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct]; tx_ct++; } else { endpoints[ep]->tbase = 0; endpoints[ep]->tbptr = 0; } endpoints[ep]->tstate = 0; endpoints[ep]->tbcnt = 0; endpoints[ep]->mrblr = EP_MAX_PKT; endpoints[ep]->rfcr = 0x18; endpoints[ep]->tfcr = 0x18; ep_ref[ep].sc |= EP_ATTACHED; DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, endpoints[ep]->tbase, endpoints[ep]->tbptr, ep_ref[ep].prx); return;}/* mpc8xx_udc_cbd_init * * Allocate space for a cbd and allocate TX/RX data space */static void mpc8xx_udc_cbd_init (void){ int i = 0; for (; i < TX_RING_SIZE; i++) { tx_cbd[i] = (cbd_t *) mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); } for (i = 0; i < RX_RING_SIZE; i++) { rx_cbd[i] = (cbd_t *) mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); } for (i = 0; i < TX_RING_SIZE; i++) { tx_cbd[i]->cbd_bufaddr = mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); tx_cbd[i]->cbd_datlen = 0x0000; } for (i = 0; i < RX_RING_SIZE; i++) { rx_cbd[i]->cbd_bufaddr = mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E); rx_cbd[i]->cbd_datlen = 0x0000; } return;}/* mpc8xx_udc_endpoint_init * * Attach an endpoint to some dpram */static void mpc8xx_udc_endpoint_init (void){ int i = 0; for (; i < MAX_ENDPOINTS; i++) { endpoints[i] = (usb_epb_t *) mpc8xx_udc_alloc (sizeof (usb_epb_t), 32); }}/* mpc8xx_udc_alloc * * Grab the address of some dpram */static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment){ u32 retaddr = address_base; while (retaddr % alignment) { retaddr++; } address_base += data_size; return retaddr;}#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -