📄 pxa.c
字号:
/* Stop DMA */ DCSR(usb_pxa_dma_out.dmach) &= ~DCSR_RUN; /* TODO: busy-wait until DMA is really stopped ? */ if (dcsr & DCSR_BUSERR) /* Is there a way to handle this error somehow ? */ printk (KERN_WARNING "PXA: Bus error in USB RX DMA " "- USB data transfer may be incorrect\n"); else if (dcsr & DCSR_ENDINTR) { DMA_TRACEMSG ("PXA: normal IRQ\n"); if (!usb_pxa_dma_out.endpoint->rcv_urb) { usb_pxa_dma_out.endpoint->rcv_urb = first_urb_detached (&usb_pxa_dma_out.endpoint->rdy); } if (usb_pxa_dma_out.endpoint->rcv_urb) { int recvsize; unsigned char *cp = usb_pxa_dma_out.endpoint->rcv_urb->buffer + usb_pxa_dma_out.endpoint->rcv_urb->actual_length; /* Copy all new data to current urb buffer */ memcpy (cp, usb_pxa_dma_out.dma_buf, DMA_OUT_BUFSIZE); if (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 1] == 0xff) { /* May be end-of-urb data - must calculate FCS and compare with FCS calculated on the host side */ __u32 oldfcs, newfcs; /* See usbdnet.c for explanation of this */ oldfcs = (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 2] << 24) | (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 3] << 16) | (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 4] << 8) | (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 5]); newfcs = fcs_compute32 (usb_pxa_dma_out.endpoint->rcv_urb->buffer, usb_pxa_dma_out.endpoint->rcv_urb->actual_length + DMA_OUT_BUFSIZE - 5, CRC32_INITFCS); newfcs = ~newfcs; /* If FCSs are equal, the last byte of new data is 0xff mark and will be ignored */ recvsize = (oldfcs == newfcs) ? (DMA_OUT_BUFSIZE - 1) : DMA_OUT_BUFSIZE; } else recvsize = DMA_OUT_BUFSIZE; DMA_TRACEMSG ("PXA: urb exists, real size %d\n", recvsize); usbd_rcv_complete_irq (usb_pxa_dma_out.endpoint, recvsize, 0); } } /* clear RPC and interrupt */ UDCCSN(usb_pxa_dma_out.ep) |= UDCCS_BO_RPC; pxa_ep_reset_irs(usb_pxa_dma_out.ep); /* Clear end-of-interrupt */ DCSR(usb_pxa_dma_out.dmach) |= DCSR_ENDINTR; /* Reinitialize and restart DMA */ pxa_rx_dma_hw_init (); DCSR(usb_pxa_dma_out.dmach) |= DCSR_RUN;}#endif /* CONFIG_USBD_PXA_DMA_OUT */static __inline__ void pxa_out_n(int ep, struct usb_endpoint_instance *endpoint){ if (UDCCSN(ep) & UDCCS_BO_RPC) { if (endpoint) { if (!endpoint->rcv_urb) { endpoint->rcv_urb = first_urb_detached (&endpoint->rdy); } if (endpoint->rcv_urb) { int len = 0; unsigned char *cp = endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length; if (cp) { // read available bytes (max packetsize) into urb buffer int count = MIN(UBCRN(ep) + 1, endpoint->rcv_packetSize); while (count--) { len++; *cp++ = UDDRN(ep); } } else { printk(KERN_INFO"read[%d:%d] bad arguements\n", udc_interrupts, jifs()); pxa_out_flush(ep); } // fall through if error of any type, len = 0 usbd_rcv_complete_irq (endpoint, len, 0); } else { pxa_out_flush(ep); } } } // clear RPC and interrupt UDCCSN(ep) = UDCCS_BO_RPC; pxa_ep_reset_irs(ep);}/* ********************************************************************************************* *//* Bulk IN (tx) */#ifdef CONFIG_USBD_PXA_DMA_INstatic usb_pxa_dma_t usb_pxa_dma_in = {-1, NULL, 0, 0, NULL, 0};static void pxa_tx_dma_irq (int dmach, void *dev_id, struct pt_regs *regs){ int dcsr = DCSR(usb_pxa_dma_in.dmach); /* Stop DMA */ DCSR(usb_pxa_dma_in.dmach) &= ~DCSR_RUN; DMA_TRACEMSG ("PXA: in dma IRQ, DCSR 0x%x\n", dcsr); if (dcsr & DCSR_BUSERR) /* I don't know better way to handle DMA bus error... */ printk (KERN_WARNING "PXA: Bus error in USB TX DMA " "- USB data transfer may be incorrect\n"); else if (dcsr & DCSR_ENDINTR) { /* All seems ok, checking for we have short packet transmitted */ if ((usb_pxa_dma_in.size < usb_pxa_dma_in.endpoint->tx_packetSize) || ((usb_pxa_dma_in.endpoint->tx_urb->actual_length - usb_pxa_dma_in.endpoint->sent ) == usb_pxa_dma_in.size)) { UDCCSN(usb_pxa_dma_in.ep) |= UDCCS_BI_TSP; } usb_pxa_dma_in.endpoint->last += usb_pxa_dma_in.size; } /* Clear end-of-interrupt */ DCSR(usb_pxa_dma_in.dmach) |= DCSR_ENDINTR; /* Now we can re-enable irq */ pxa_enable_ep_interrupt (usb_pxa_dma_in.ep);}static void __inline__ pxa_start_n_dma_hw (int ep, struct usb_endpoint_instance *endpoint, char *mem, int size){ /* Prepare for DMA */ memcpy (usb_pxa_dma_in.dma_buf, mem, size); usb_pxa_dma_in.ep = ep; usb_pxa_dma_in.endpoint = endpoint; usb_pxa_dma_in.size = size; /* Setup DMA */ DCSR(usb_pxa_dma_in.dmach) |= DCSR_NODESC; DCMD(usb_pxa_dma_in.dmach) = DCMD_FLOWTRG | DCMD_INCSRCADDR | DCMD_WIDTH1 | DCMD_BURST32 | DCMD_ENDIRQEN | size; DSADR(usb_pxa_dma_in.dmach) = usb_pxa_dma_in.dma_buf_phys; DTADR(usb_pxa_dma_in.dmach) = _UDDRN[ep]; /* Map DMA (FIXME: assume ep is 1) */ DRCMR25 = usb_pxa_dma_in.dmach | DRCMR_MAPVLD; /* Start DMA */ DCSR(usb_pxa_dma_in.dmach) |= DCSR_RUN;}static void pxa_start_n_dma (unsigned int ep, struct usb_endpoint_instance *endpoint){ /* We must disable irq for this endpoint */ pxa_disable_ep_interrupt (ep); if (endpoint->tx_urb) { struct urb *urb = endpoint->tx_urb; int last = MIN(urb->actual_length - (endpoint->sent + endpoint->last), endpoint->tx_packetSize); if (last) { pxa_start_n_dma_hw (ep, endpoint, urb->buffer + endpoint->sent + endpoint->last, last); return; } } /* Do nothing with DMA - re-enable irq */ pxa_enable_ep_interrupt (ep);}#endif /* CONFIG_USBD_PXA_DMA_IN */static void __inline__ pxa_start_n (unsigned int 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; unsigned char *cp = urb->buffer + endpoint->sent + endpoint->last; while (size--) { UDDRN(ep) = *cp++; } if (( last < endpoint->tx_packetSize ) || ( (endpoint->tx_urb->actual_length - endpoint->sent ) == last )) { UDCCSN(ep) = UDCCS_BI_TSP; } endpoint->last += last; } }}static void __inline__ pxa_in_n (unsigned int ep, struct usb_endpoint_instance *endpoint){ int udccsn; pxa_ep_reset_irs(ep); // if TPC update tx urb and clear TPC if ((udccsn = UDCCSN(ep)) & UDCCS_BI_TPC) { UDCCSN(ep) = UDCCS_BI_TPC; usbd_tx_complete_irq(endpoint, 0); } if (udccsn & UDCCS_BI_TFS) { pxa_start_n(ep, endpoint); } // clear underrun, not much we can do about it if (udccsn & UDCCS_BI_TUR) { UDCCSN(ep) = UDCCS_BI_TUR; }}/* ********************************************************************************************* *//* Control (endpoint zero) */#ifdef CONFIG_USBD_EP0_SUPPORT/* Changed by Stanley */void pxa_ep0recv(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){ int size=0; struct urb *urb = endpoint->rcv_urb; unsigned char* cp = (unsigned char*) (urb->buffer + urb->actual_length); PXA_REGS(udccs0, " <-- setup data recv");#ifdef EP0_DEBUG printk("%d %x %x\n", urb->actual_length, urb->buffer, cp ); printk("udccs0=0x%x\n", udccs0 );#endif // check for premature status stage if ( !(udccs0&UDCCS0_OPR) && !(udccs0&UDCCS0_IPR) ) { if ( urb->device_request.wLength == urb->actual_length ) {#ifdef EP0_DEBUG printk(KERN_INFO"pxa_ep0recv: UDC ep0 receive all data.\n");#endif usbd_recv_setup(ep0_urb); } else {#ifdef EP0_DEBUG printk(KERN_INFO"pxa_ep0recv: Get a premature status in stage.\n"); printk(KERN_INFO"pxa_ep0recv: request.wLength=0x%x, actual_length=0x%x\n", urb->device_request.wLength, urb->actual_length );#endif if ( urb->buffer ) kfree( urb->buffer ); } endpoint->state = WAIT_FOR_SETUP; } // receive more data if (( udccs0 & UDCCS0_OPR ) && !(UDCCS0 & UDCCS0_SA) ) { while ( UDCCS0&UDCCS0_RNE ) { *cp++ = UDDRN(0); urb->actual_length++; } /* Do we need this section? */ /* need more tests! -Stanley */ /* Without the section, the driver still works */#if 1 if ( urb->actual_length == urb->device_request.wLength ) {#ifdef EP0_DEBUG printk(KERN_INFO"pxa_ep0recv under test: UDC ep0 receive all data.\n");#endif usbd_recv_setup(ep0_urb); endpoint->state = WAIT_FOR_SETUP; }#endif UDCCS0 |= UDCCS0_OPR; // to allow to enter a premature STATUS IN stage UDCCS0 |= UDCCS0_IPR; } return;}#endif void pxa_ep0xmit(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){ int short_packet; int size; struct urb *urb = endpoint->tx_urb; PXA_REGS(udccs0, " --> xmit"); //printk(KERN_INFO"tx[%d:%d] CS0[%02x]\n", udc_interrupts, jifs(), UDCCS0); // check for premature status stage - host abandoned previous IN if ((udccs0 & UDCCS0_OPR) && !(UDCCS0 & UDCCS0_SA) ) { // clear tx fifo and opr UDCCS0 = UDCCS0_FTF | UDCCS0_OPR; endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; PXA_REGS(UDCCS0, " <-- xmit premature status"); return; } // check for stall if (udccs0 & UDCCS0_SST) { // clear stall and tx fifo UDCCS0 = UDCCS0_SST | UDCCS0_FTF; endpoint->state = WAIT_FOR_SETUP; endpoint->tx_urb = NULL; PXA_REGS(UDCCS0, " <-- xmit stall"); return; } /* How much are we sending this time? (May be zero!) (Note that later call of tx_complete() will add last to sent.) */ if (NULL == urb) { size = 0; } else { endpoint->last = size = MIN (urb->actual_length - endpoint->sent, endpoint->tx_packetSize); } /* Will this be a short packet? (It may be the last, but still be full size, in which case we will need a ZLP later.) */ short_packet = (size < endpoint->tx_packetSize); PXA_XMIT(size); if (size > 0 && urb->buffer) { // Stuff the FIFO unsigned char *cp = urb->buffer + endpoint->sent; while (size--) { UDDRN(0) = *cp++; } } // Is this the end of the data state? (We've sent all the data, plus any required ZLP.) if (!endpoint->tx_urb || (endpoint->last < endpoint->tx_packetSize)) { // Tell the UDC we are at the end of the packet. UDCCS0 = UDCCS0_IPR; endpoint->state = WAIT_FOR_OUT_STATUS; PXA_REGS(UDCCS0, " <-- xmit wait for status"); } else if ((endpoint->last == endpoint->tx_packetSize) && ((endpoint->last + endpoint->sent) == ep0_urb->actual_length) && ((ep0_urb->actual_length) < le16_to_cpu(ep0_urb->device_request.wLength)) ) { // Tell the UDC we are at the end of the packet. endpoint->state = DATA_STATE_NEED_ZLP; PXA_REGS(UDCCS0, " <-- xmit need zlp"); } else { PXA_REGS(UDCCS0, " <-- xmit not finished"); }}void __inline__ pxa_ep0setup(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){ if ((udccs0 & (UDCCS0_SA | UDCCS0_OPR | UDCCS0_RNE)) == (UDCCS0_SA | UDCCS0_OPR | UDCCS0_RNE)) { int len = 0; int max = 8; unsigned char *cp = (unsigned char *)&ep0_urb->device_request; PXA_REGS(udccs0, " --> setup"); //memset(cp, 0, max); while (max-- /*&& (UDCCS0 & UDCCS0_RNE)*/) { len++; *cp++ = UDDR0; } PXA_SETUP(&ep0_urb->device_request);#ifdef CONFIG_USBD_EP0_SUPPORT/* This section is added to give some supports for setup data IN mode. It is necessary * to call usbd_recv_setup * routine at end of receiving all data * - Stanley */#ifdef EP0_DEBUG printk( KERN_INFO"URB request:\n" ); printk( KERN_INFO"ep0.bmRequestType: 0x%x\n", ep0_urb->device_request.bmRequestType ); printk( KERN_INFO"ep0.bRequest: 0x%x\n", ep0_urb->device_request.bRequest ); printk( KERN_INFO"ep0.wlength: 0x%x\n", ep0_urb->device_request.wLength );#endif // Controll Write - Maybe we will receive more data from the host if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE && le16_to_cpu(ep0_urb->device_request.wLength)!=0 ) {#ifdef EP0_DEBUG printk("HOST2DEVICE\n");#endif endpoint->state = DATA_STATE_RECV; // allocate new memory for such a request; ep0_urb->buffer = kmalloc( ep0_urb->device_request.wLength, GFP_ATOMIC ); if ( !ep0_urb->buffer ) { panic("pxa_ep0setup: Out of memory!\n"); return; } ep0_urb->buffer_length = ep0_urb->device_request.wLength; ep0_urb->actual_length = 0; // the bugs endpoint->rcv_urb = ep0_urb; UDCCS0 = UDCCS0_SA | UDCCS0_OPR; PXA_REGS(UDCCS0," <-- setup recv"); return; }#endif // process setup packet if (usbd_recv_setup(ep0_urb)) { // setup processing failed UDCCS0 = UDCCS0_FST; endpoint->state = WAIT_FOR_SETUP; PXA_REGS(udccs0, " --> bad setup FST"); return; } // check direction if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { // Control Write - we are receiving more data from the host#ifdef EP0_DEBUG printk("HOST2DEVICE - zero length\n");#endif // should we setup to receive data // Skip this condition; - Stanley if (le16_to_cpu (ep0_urb->device_request.wLength)) { //printk(KERN_INFO"sl11_ep0: read data %d\n", // le16_to_cpu(ep0_urb->device_request.wLength)); endpoint->rcv_urb = ep0_urb; endpoint->rcv_urb->actual_length = 0; endpoint->state = DATA_STATE_RECV; // XXX this has not been tested // pxa_out_0 (0, endpoint); PXA_REGS(UDCCS0," <-- setup no response"); return; } // allow for premature IN (c.f. 12.5.3 #8) UDCCS0 = UDCCS0_IPR; PXA_REGS(UDCCS0," <-- setup nodata"); } else { // Control Read - we are sending data to the host#ifdef EP0_DEBUG printk("DEVICE2HOST\n");#endif // verify that we have non-zero request length if (!le16_to_cpu (ep0_urb->device_request.wLength)) { udc_stall_ep (0); PXA_REGS(UDCCS0," <-- setup stalling zero wLength"); return; } // verify that we have non-zero length response if (!ep0_urb->actual_length) { udc_stall_ep (0); PXA_REGS(UDCCS0," <-- setup stalling zero response"); return; } // start sending endpoint->tx_urb = ep0_urb; endpoint->sent = 0; endpoint->last = 0; endpoint->state = DATA_STATE_XMIT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -