📄 wmmx.c
字号:
usbd_tx_complete_irq(endpoint, 0); if (config->size < endpoint->tx_packetSize) return; else { wmmx_start_n_dma(config->ep, endpoint); }}static void wmmx_start_n(unsigned int phys_ep, struct usb_endpoint_instance *endpoint){ if (endpoint->tx_urb) { int last; struct urb *urb = endpoint->tx_urb; if ((last = MIN(urb->actual_length - (endpoint->sent + endpoint->last), endpoint->tx_packetSize))) { int size = last; u32 *data = (u32*)(urb->buffer + endpoint->sent + endpoint->last); u32 *cp; int remain = 0; u8 *rd; WMMX_XFER(WMMX_XFER_DIR_IN, last, (char *)data); cp = data; remain = size & 0x03; size &= ~0x03; while (size > 0) { UDCDN(phys_ep) = *cp++; size -= 4; } if (remain) { volatile u8 *reg = (volatile u8 *)PUDCDN(phys_ep); rd = (u8 *)cp; while (remain--) { *reg = *rd++; } } if ((last < endpoint->tx_packetSize) || ((endpoint->tx_urb->actual_length - endpoint->sent) == last)) { if (last != endpoint->tx_packetSize) { UDCCSN(phys_ep) = (UDCCSN(phys_ep) & UDCCSR_WR_MASK) | UDCCSR_SP; } } endpoint->last += last; } else { usbd_tx_complete_irq (endpoint, 0); } }}static void wmmx_in_n(unsigned int phys_ep, struct usb_endpoint_instance *endpoint){ int udccsn; wmmx_ep_reset_interrupt_status(phys_ep); /* if TPC update tx urb and clear TPC */ if ((udccsn = UDCCSN(phys_ep)) & UDCCSR_PC) { UDCCSN(phys_ep) = (UDCCSN(phys_ep) & UDCCSR_WR_MASK) | UDCCSR_PC; usbd_tx_complete_irq(endpoint, 0); } if (udccsn & UDCCSR_FS) { wmmx_start_n(phys_ep, endpoint); } /* clear underrun, not much we can do about it */ if (udccsn & UDCCSR_TRN) { UDCCSN(phys_ep) = (UDCCSN(phys_ep) & UDCCSR_WR_MASK) | UDCCSR_TRN; }}static void wmmx_usb_dma_rx_irq(int dmach, void* dev_id, struct pt_regs *regs){ unsigned int dcsr = DCSR(dmach); struct wmmx_usb_dma_config *config = wmmx_dmach_to_configs[dmach]; struct usb_endpoint_instance *endpoint = config->endpoint; unsigned int phys_ep = config->ep; DCSR(dmach) &= ~DCSR_RUN; if (dcsr & DCSR_BUSERR) { DCSR(dmach) |= DCSR_BUSERR; printk(KERN_ERR"DMA bus error\n"); } else if (dcsr & DCSR_ENRINTR) { DCSR(dmach) |= DCSR_ENDINTR; if (!endpoint->rcv_urb) { endpoint->rcv_urb = first_urb_detached(&endpoint->rdy); } if (endpoint->rcv_urb) { int len; int stop_accumulation; unsigned char* cp = endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length; if (UDCCSN(config->ep) & UDCCSR_SP) { len = endpoint->rcv_packetSize - (DCMD(dmach) & DCMD_LENGTH); } else { len = endpoint->rcv_packetSize; } memcpy(cp, config->dma_buffer, len); stop_accumulation = ((ep_maps[phys_ep].accum_size > 0) && (endpoint->rcv_urb->actual_length + len == ep_maps[phys_ep].accum_size)); WMMX_XFER(WMMX_XFER_DIR_OUT, len, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length); usbd_rcv_complete_irq (endpoint, len, 0); /* simulate ZLP to stop accumulating the data */ if (stop_accumulation) { usbd_rcv_complete_irq (endpoint, 0, 0); } if (len == 0) { UDCCSN(config->ep) = UDCCSR_SP | UDCCSR_PC | ((UDCCSN(config->ep) & UDCCSR_WR_MASK)); } else if (len < endpoint->rcv_packetSize) { UDCCSN(config->ep) = UDCCSR_PC | ((UDCCSN(config->ep) & UDCCSR_WR_MASK)); } } } else printk(KERN_ERR"DCSR(%d) = 0x%08x\n", dmach, DCSR(dmach)); /* Listen to the request */ DCSR(dmach) = DCSR_NODESC | DCSR_EORIRQEN; DTADR(dmach) = wmmx_usb_dma_configs[config->ep].dma_phys_buffer; DSADR(dmach) = PHYS_UDCDN(config->ep); DCMD(dmach) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_ENDIRQEN | DCMD_BURST32 | DCMD_WIDTH4 | (endpoint->rcv_packetSize & DCMD_LENGTH); DRCMRUDC(config->ep) = dmach | DRCMR_MAPVLD; DCSR(dmach) |= DCSR_RUN;}void wmmx_ep0recv(struct usb_endpoint_instance *endpoint, volatile u32 udccsr0){ struct urb *urb = endpoint->rcv_urb; int retval; WMMX_REGS(udccsr0, " <-- setup data recv"); /* check for premature status stage */ if (!(udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_IPR)) { if (urb->device_request.wLength == urb->actual_length) { retval = usbd_recv_setup(ep0_urb); if (retval != 0) { UDCCSR0 = UDCCSR0_FST; endpoint->state = WAIT_FOR_SETUP; WMMX_REGS(udccsr0, " --> bad setup FST"); } } else { urb->actual_length = 0; } endpoint->state = WAIT_FOR_SETUP; } /* receive more data */ if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { int size = urb->device_request.wLength; u32* cp = (u32*) (urb->buffer + urb->actual_length); while (size > 0) { *cp++ = UDCDN(0); size -= 4; } /* resize the actual length of URB structure. */ urb->actual_length += urb->device_request.wLength; UDCCSR0 |= UDCCSR0_OPC; /* to allow to enter a premature STATUS IN stage */ UDCCSR0 |= UDCCSR0_IPR; } return;}void wmmx_ep0xmit(struct usb_endpoint_instance *endpoint, volatile u32 udccsr0){ int short_packet; int size; struct urb *urb = endpoint->tx_urb; WMMX_REGS(udccsr0, " --> xmit"); /* check for premature status stage - host abandoned previous IN */ if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { /* clear tx fifo and opr */ UDCCSR0 |= UDCCSR0_FTF | UDCCSR0_OPC; endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; endpoint->rcv_urb = NULL; WMMX_REGS(UDCCSR0, " <-- xmit premature status"); return; } /* check for stall */ if (udccsr0 & UDCCSR0_SST) { /* clear stall and tx fifo */ UDCCSR0 |= UDCCSR0_SST | UDCCSR0_FTF; endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; endpoint->rcv_urb = NULL; WMMX_REGS(UDCCSR0, " <-- xmit stall"); return; } if (NULL == urb) { size = 0; } else { endpoint->last = size = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); } short_packet = (size < endpoint->tx_packetSize); WMMX_XMIT(size); if (size > 0 && urb->buffer) { u32* cp = (u32*)(urb->buffer + endpoint->sent); int remain = 0; u8 *rd; remain = size & 0x03; size &= ~0x3; while (size) { UDCDN(0) = *cp++; size -= 4; } if (remain) { volatile u8 *reg = (volatile u8 *)PUDCDN(0); rd = (u8 *)cp; while (remain--) { *reg = *rd++; } } } if (!endpoint->tx_urb || (endpoint->last < endpoint->tx_packetSize)) { /* Tell the UDC we are at the end of the packet. */ UDCCSR0 |= UDCCSR0_IPR; endpoint->state = WAIT_FOR_OUT_STATUS; WMMX_REGS(UDCCSR0, " <-- xmit wait for status"); } else if ((endpoint->last == endpoint->tx_packetSize) && ((endpoint->last + endpoint->sent) == endpoint->tx_urb->actual_length) && ((endpoint->tx_urb->actual_length) < le16_to_cpu(endpoint->tx_urb->device_request.wLength))) { endpoint->state = DATA_STATE_NEED_ZLP; WMMX_REGS(UDCCSR0, " <-- xmit need zlp"); } else { WMMX_REGS(UDCCSR0, " <-- xmit not finished"); }}void wmmx_ep0setup(struct usb_endpoint_instance *endpoint, u32 udccsr0){ if ((udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC | UDCCSR0_RNE)) == (UDCCSR0_SA | UDCCSR0_OPC | UDCCSR0_RNE)) { u32 dummy; int count; int len; int retval; u32 *cp = (u32 *)&ep0_urb->device_request; WMMX_REGS(udccsr0, " --> setup"); count = len = UDCBCN(0); if (count > 8) { dbg_rx(6, "Received a setup packet(len(%d)>8\n", len); if (!(winhost_flag || udcbegin_flag)) { printk(KERN_INFO "Received a setup packet(len(%d)>8)\n", len); } count = 8; } while (count > 0) { *cp++ = UDCDN(0); count -= 4; len -= 4; } while (len > 0) { dummy = UDCDN(0); len -= 4; } WMMX_SETUP(&ep0_urb->device_request); if (((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu(ep0_urb->device_request.wLength) != 0) { endpoint->state = DATA_STATE_RECV; ep0_urb->actual_length = 0; endpoint->rcv_urb = ep0_urb; UDCCSR0 = UDCCSR0_SA | UDCCSR0_OPC; WMMX_REGS(udccsr0, " <-- setup recv"); return; } retval = usbd_recv_setup(ep0_urb); if (retval) { UDCCSR0 = UDCCSR0_FST; endpoint->state = WAIT_FOR_SETUP; WMMX_REGS(udccsr0, " --> bad SETUP FST"); } if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { UDCCSR0 |= UDCCSR0_IPR; WMMX_REGS(UDCCSR0," <-- setup nodata"); } else { /* Control Read */ if (!le16_to_cpu(ep0_urb->device_request.wLength)) { udc_stall_ep(0); WMMX_REGS(UDCCSR0, " <-- setup stalling " "zero wLength"); return; } /* verify that we have non-zero length response */ if (!ep0_urb->actual_length) { udc_stall_ep (0); WMMX_REGS(UDCCSR0," <-- setup stalling " "zero response"); return; } endpoint->tx_urb = ep0_urb; endpoint->sent = 0; endpoint->last = 0; endpoint->state = DATA_STATE_XMIT; wmmx_ep0xmit(endpoint, UDCCSR0); /* Clear SA and OPR bits */ UDCCSR0 = UDCCSR0_SA | UDCCSR0_OPC; WMMX_REGS(UDCCSR0," <-- setup data"); } }}static void wmmx_ep0(struct usb_endpoint_instance *endpoint, u32 udccsr0){ int j = 0; WMMX_REGS(udccsr0," --> ep0"); if ((endpoint->state != DATA_STATE_PENDING_XMIT) && (udccsr0 & UDCCSR0_SST)) { wmmx_ep_reset_interrupt_status(0); UDCCSR0 |= UDCCSR0_SST; WMMX_REGS(udccsr0," --> ep0 clear SST"); if (endpoint) { endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; endpoint->rcv_urb = NULL; } return; } if (!endpoint) { wmmx_ep_reset_interrupt_status(0); UDCCSR0 |= UDCCSR0_IPR | UDCCSR0_OPC | UDCCSR0_SA; WMMX_REGS(UDCCSR0," ep0 NULL"); return; } if (endpoint->tx_urb) { usbd_tx_complete_irq (endpoint, 0); if (!endpoint->tx_urb) { if (endpoint->state != DATA_STATE_NEED_ZLP) { endpoint->state = WAIT_FOR_OUT_STATUS; } } } if ((endpoint->state != DATA_STATE_PENDING_XMIT) && (endpoint->state != WAIT_FOR_SETUP) && (udccsr0 & UDCCSR0_SA)) { WMMX_REGS(udccsr0," --> ep0 early SA"); endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; endpoint->rcv_urb = NULL; } WMMX_REGS(endpoint->state," -- endpoint state"); switch (endpoint->state) { case DATA_STATE_NEED_ZLP: UDCCSR0 |= UDCCSR0_IPR; endpoint->state = WAIT_FOR_OUT_STATUS; break; case WAIT_FOR_OUT_STATUS: if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA)) == UDCCSR0_OPC) { UDCCSR0 |= UDCCSR0_OPC; } WMMX_REGS(UDCCSR0," --> ep0 WAIT for STATUS"); endpoint->state = WAIT_FOR_SETUP; case WAIT_FOR_SETUP: do { wmmx_ep0setup(endpoint, UDCCSR0); if (endpoint->state == DATA_STATE_PENDING_XMIT) { if (udccsr0 & UDCCSR0_SST) { wmmx_ep_reset_interrupt_status(0); UDCCSR0 = UDCCSR0_SST | UDCCSR0_OPC | UDCCSR0_SA; return; } break; } if (udccsr0 & UDCCSR0_SST) { wmmx_ep_reset_interrupt_status(0); UDCCSR0 |= UDCCSR0_SST | UDCCSR0_OPC | UDCCSR0_SA; WMMX_REGS(udccsr0," --> ep0 clear SST"); if (endpoint) { endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; endpoint->rcv_urb = NULL; } return; } if (j++ > 2) { u32 udccsr0 = UDCCSR0; WMMX_REGS(udccsr0," ep0 wait"); if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) == (UDCCSR0_OPC | UDCCSR0_SA)) { UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA); WMMX_REGS(UDCCSR0," ep0 force"); } else { UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA); WMMX_REGS(UDCCSR0," ep0 force and return"); break; } } } while (UDCCSR0 & (UDCCSR0_OPC | UDCCSR0_RNE)); break; case DATA_STATE_XMIT: wmmx_ep0xmit(endpoint, UDCCSR0); break; case DATA_STATE_PENDING_XMIT: wmmx_ep0xmit(endpoint, UDCCSR0); case DATA_STATE_RECV: wmmx_ep0recv(endpoint, UDCCSR0); break; } wmmx_ep_reset_interrupt_status(0); WMMX_REGS(endpoint->state," -- endpoint state result"); WMMX_REGS(UDCCSR0," <-- ep0");}static __inline__ int endpoints_have_interrupt(void){ u32 udcisr0, udcisr1; udcisr0 = UDCISR0; udcisr1 = UDCISR1; if (udcisr0) return 1; if (udcisr1) return 1; return 0;}/* * Bulverde UDC Interrupt Handler */static void wmmx_int_hndlr (int irq, void *dev_id, struct pt_regs *regs){ u32 udcisr0, udcisr1; int udccr = UDCCR; int ep; udc_interrupts++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -