?? sa1100.c
字號:
free_irq (SA1100_GPIO_TO_IRQ (CONFIG_SA1100_USBCABLE_GPIO), NULL);#endif}/** * udc_release_io - release UDC io region */void udc_release_io (){ sa1100_free_dma (usbd_rcv_dma); sa1100_free_dma (usbd_tx_dma);}/* ep0 dma engine functions ******************************************************************** *//* * EP0 State - See the Intel Application Note */#define EP0_STATE_IDLE 0#define EP0_STATE_IN_DATA_PHASE 1#define EP0_STATE_END_IN 2char *ep0_state_desc[] = { "idle", "in", "end"};static int ep0_state = EP0_STATE_IDLE;//struct urb ep0_urb;struct urb *ep0_urb;static unsigned char *buffer;static unsigned int buffer_cnt;/* * There are two scenarios: * * 1. Data to be sent is an exact multiple of the packetsize and less than * the requested size. An empty packet needs to be sent. * * 2. Everything else. The last packet will be recognized as the last * because it is less than the packetsize OR because we have sent exactly * the required amount of data. */static unsigned int send_zlp;struct usb_endpoint_instance *ep0_endpoint;char *send_zlp_description[] = { "exact", "forced"};int ep0_enable (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint){ ep0_endpoint = endpoint; dbg_ep0(0, "ep0_urb: %p", ep0_urb); if (!ep0_urb) { if (!(ep0_urb = usbd_alloc_urb (device, device->function_instance_array, 0, 512))) { dbg_ep0 (1, "ep0_enable: usbd_alloc_urb failed\n"); } } else { dbg_ep0 (1, "ep0_enable: ep0_urb already allocated\n"); } return 0;}void ep0_disable (void){ dbg_ep0(0, "ep0_urb: %p", ep0_urb); if (ep0_urb) { usbd_dealloc_urb (ep0_urb); ep0_urb = 0; } else { dbg_ep0 (1, "ep0_disable: ep0_urb already NULL\n"); }}int ep0_reset (void){ dbgENTER (dbgflg_usbdbi_ep0, 1); ep0_state = EP0_STATE_IDLE; udc_reset_ep (0); return 0;}/* * ep0_set_opr * * Set OPR and optionally DE. */static void ep0_set_opr (void){ int ok; IOIOIO(UDCCS0, UDCCS0_S0, *(UDCCS0) = UDCCS0_SO , (*(UDCCS0) & UDCCS0_OPR), ok); if (!ok) { dbg_ep0(0, "failed to reset OPR"); } dbg_ep0(1,"CS0: %02x ok: %d", *(UDCCS0), ok);}/* * ep0_set_opr_and_de * * Set OPR and optionally DE. */static void ep0_set_opr_and_de (void){ int ok; IOIOIO(UDCCS0, UDCCS0_S0, *(UDCCS0) = (UDCCS0_SO | UDCCS0_DE) , (*(UDCCS0) & UDCCS0_OPR), ok); if (!ok) { dbg_ep0(0, "failed to reset OPR"); } dbg_ep0(1,"CS0: %02x ok: %d", *(UDCCS0), ok);}/* * ep0_read_data * * Retreive setup data from FIFO. */__inline__ static int ep0_read_data (struct usb_device_request *request, int max){ int fifo_count; int bytes_read; int i; int reads; unsigned char *cp = (unsigned char *) request; int udcwc; int udccs0; udccs0 = *(UDCCS0); udcwc = fifo_count = udc(UDCWC) & 0xff; if (fifo_count != max) { dbg_ep0 (0, "ep0_read_data: have %d bytes; want max\n", fifo_count); } reads = 0; bytes_read = 0; for (reads = 0, bytes_read = 0; udcwc && fifo_count--;) { i = 0; do { *cp = (unsigned char) *(UDCD0); // XXX without this reads may be corrupt, typically the wLength field // will contain bad data, which in turn will cause get descriptor config // to return the full set of descriptors in response to limited first // get descriptor 9, which will BSOD windows udelay(10); reads++; i++; } while ((((udcwc = udc(UDCWC) & 0xff)) > fifo_count) && (i < 10)); if (i == 10) { dbg_ep0 (0, "failed: UDCWC: %2x %2x bytes: %d fifo: %d reads: %d no change\n", udcwc, *(UDCWC), bytes_read, fifo_count, reads); } if (udcwc < (fifo_count - 1)) { dbg_ep0 (0, "failed: UDCWC: %2x %2x bytes: %d fifo: %d reads: %d too low\n", udcwc, *(UDCWC), bytes_read, fifo_count, reads); } cp++; bytes_read++; if ((bytes_read >= max) && (fifo_count > 0)) { dbg_ep0 (0, "reading too much data\n"); break; } } dbg_ep0 ((bytes_read == max)?2:0, "ep0_read_data: reads: %d want: %d fifo_count: %d bytes_read: %d CS0: %02x:%02x CWC: %02x", reads, max, fifo_count, bytes_read, *(UDCCS0), udccs0, udcwc); return bytes_read;}/* * * ep0_read_request * * Called when in IDLE state to get a setup packet. */static void ep0_read_request (unsigned int udccs0, unsigned int udccr){ int i; int ok; if (!(udccr & UDCCR_UDA)) { dbg_ep0 (3, "warning, UDC not active"); } // reset SST if (udccs0 & UDCCS0_SST) { IOIOIO (UDCCS0, UDCCS0_SST, *(UDCCS0) = UDCCS0_SST, *(UDCCS0) & UDCCS0_SST, ok); if (!ok) { dbg_ep0 (0, "failed to reset SST CS0: %02x ok: %d", *(UDCCS0), ok); } } // check UDC Endpoint 0 Control/Status register for OUT Packet Ready (OPR) (c.f. 11.8.7.1) if (!(udccs0 & UDCCS0_OPR)) { // wait for another interrupt dbg_ep0 (3, "wait for another interrupt CS0: %02x", udccs0); return; } // read a device request ep0_urb->actual_length = 0; if ((i = ep0_read_data (&ep0_urb->device_request, 8)) < 8) { ep0_set_opr (); dbg_ep0 (2, "not enough data: %d", i); return; } //ep0_need_data = le16_to_cpu(ep0_urb->device_request.wLength); dbg_ep0 (3, "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x", ep0_urb->device_request.bmRequestType, ep0_urb->device_request.bRequest, le16_to_cpu (ep0_urb->device_request.wValue), le16_to_cpu (ep0_urb->device_request.wIndex), le16_to_cpu (ep0_urb->device_request.wLength)); { char *cp = (char *) &ep0_urb->device_request; dbg_ep0 (1, "%02x %02x %02x %02x %02x %02x %02x %02x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7] ); } // check if we have been initialized if (!ep0_urb->device) { ep0_set_opr_and_de (); udc_stall_ep (0); return; } // check direction of data transfer if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { // if this is a set address save it if ((ep0_urb->device_request.bmRequestType == 0) && (ep0_urb->device_request.bRequest == USB_REQ_SET_ADDRESS)) { usb_address = le16_to_cpu(ep0_urb->device_request.wValue) & 0xff; /* * very occasionally register write will fail, delay and redo twice * to ensure that it actually got through, cannot check as UDC * will not propagate until SO and DE are set. We also need a delay * after setting SO and DE, exiting too soon can also result in * problems if address has not propagated. */ *(UDCAR) = usb_address; udelay(2); *(UDCAR) = usb_address; udelay(2); *(UDCAR) = usb_address; ep0_set_opr_and_de(); udelay(40); if (usbd_recv_setup(ep0_urb)) { dbg_ep0(5, "usb_recv_setup failed, not stalling"); } } else { //ep0_set_opr_and_de(); // submit urb to ep0, stall if non-zero result if (usbd_recv_setup(ep0_urb)) { dbg_ep0(1, "usb_recv_setup failed, stalling"); udc_stall_ep(0); } ep0_set_opr_and_de(); // tbr getting better results with this. } return; } // submit urb to ep0, stall if non-zero result if (usbd_recv_setup (ep0_urb)) { dbg_ep0 (2, "usb_recv_setup failed, stalling"); ep0_set_opr_and_de (); udc_stall_ep (0); return; } // device reqeust has specified Device-to-Host, so we should be returning data // check request length, zero is not legal if (!le16_to_cpu (ep0_urb->device_request.wLength)) { dbg_ep0 (0, "wLength zero, stall"); ep0_set_opr_and_de (); udc_stall_ep (0); return; } // check that we have some data to send back, zero should not be possible if (!ep0_urb->actual_length) { dbg_ep0 (0, "no data, stall"); ep0_set_opr_and_de (); udc_stall_ep (0); return; } // everything looks sane, so set buffer pointers and setup for data transfer buffer = ep0_urb->buffer; buffer_cnt = ep0_urb->actual_length; /* * IFF we are sending a multiple of the packet size AND less than was * requested we will need to send an empty packet after all the data packets. */ if (!(buffer_cnt % 8) && (buffer_cnt < le16_to_cpu (ep0_urb->device_request.wLength))) { send_zlp = 1; dbg_ep0 (1, "DEVICE2HOST: SEND ZLP %x %x", ep0_urb->actual_length, le16_to_cpu (ep0_urb->device_request.wLength)); } else { send_zlp = 0; dbg_ep0 (2, "DEVICE2HOST: NO ZLP %x %x", ep0_urb->actual_length, le16_to_cpu (ep0_urb->device_request.wLength)); } ep0_state = EP0_STATE_IN_DATA_PHASE;}/* * ep0_in * * Send some data to host. */static void ep0_in (unsigned int udccs0){ int transfer_cnt = 0; unsigned int fifo_count; volatile int writes = 0; unsigned long start = jiffies; int ok; udccs0 = *(UDCCS0); dbg_ep0 (2, "CS0: %02x", udccs0); // check for non empty FIFO if (*(UDCWC)) { dbg_ep0 (0, "FIFO not empty"); return; } // process iff ep0 is not stalled, no premature end and IPR is clear if (udccs0 & (UDCCS0_SE | UDCCS0_SST)) { dbg_ep0 (1, "ep0_in: SE or SST set\n"); return; } // first check that IPR is not set, if it is then we wait for it to clear. if (udccs0 & UDCCS0_IPR) { for (ok = 0; (*(UDCCS0) & UDCCS0_IPR) && ok < 2000; ok++) { udelay (25); // XXX } if (ok == 2000) { dbg_ep0 (0, "IPR clear timed out"); } dbg_ep0 (0, "IPR was set count: %d", ok); } // get up to first 8 bytes of data transfer_cnt = MIN (8, buffer_cnt); buffer_cnt -= transfer_cnt; fifo_count = 0; do { int count = 0; int udcwc; do { *(UDCD0) = (unsigned long) buffer[fifo_count]; count++; writes++; } while (((udcwc = udc (UDCWC)) == fifo_count) && (count < 2000)); if (udcwc <= fifo_count) { dbg_ep0 (0, "sending STALL, failed writing FIFO transfer: %d fifo_count: %x CS0: %02x CWC: %02x", transfer_cnt, fifo_count, *(UDCCS0), udcwc); udc_stall_ep (0); ep0_state = EP0_STATE_IDLE; return; } fifo_count++; } while (fifo_count < transfer_cnt); dbg_ep0 (3, "elapsed: %lx writes: %d fifo_count: %d transfer_cnt: %d buffer_cnt: %d CS0: %02x CWC: %02x", jiffies - start, writes, fifo_count, transfer_cnt, buffer_cnt, *(UDCCS0), *(UDCWC)); buffer += transfer_cnt; // set data end, and start if (buffer_cnt == 0) { ep0_state = EP0_STATE_END_IN; } IOIOIO (UDCCS0, UDCCS0_IPR, *(UDCCS0) = (UDCCS0_IPR | ((((!buffer_cnt) && (send_zlp != 1)) ? UDCCS0_DE : 0))), !(*(UDCCS0) & UDCCS0_IPR), ok); if (!ok) { dbg_ep0 (0, "failed to set IPR CS0: %02x ok: %d", *(UDCCS0), ok); }}/* * ep0_end_in * * Handle end of IN, possibly with ZLP. */static void ep0_end_in (unsigned int udccs0){ int ok; dbg_ep0 (2, " status: %02x CS0: %02x", udccs0, *(UDCCS0)); // reset SST if necessary if (udccs0 & UDCCS0_SST) { IOIOIO (UDCCS0, UDCCS0_SST, *(UDCCS0) = UDCCS0_SST, *(UDCCS0) & UDCCS0_SST, ok); if (!ok) { dbg_ep0 (0, "failed to reset SST"); } } // reset SE if necessary if (udccs0 & UDCCS0_SE) { IOIOIO (UDCCS0, UDCCS0_SSE, *(UDCCS0) = UDCCS0_SSE, *(UDCCS0) & UDCCS0_SSE, ok); if (!ok) { dbg_ep0 (0, "failed to reset SE"); } } // ensure that IPR is not set and send zero length packet if necessary if (!(udc (UDCCS0) & UDCCS0_IPR) && (send_zlp == 1)) { IOIOIO (UDCCS0, UDCCS0_DE | UDCCS0_IPR, *(UDCCS0) = (UDCCS0_DE | UDCCS0_IPR), (*(UDCCS0) & (UDCCS0_DE | UDCCS0_IPR)) != (UDCCS0_DE | UDCCS0_IPR), ok); if (!ok) { dbg_ep0 (0, "failed to set DE and IPR CS0: %02x", *(UDCCS0)); } else { dbg_ep0 (1, "set DE and IPR, ZLP sent CS0: %02x", *(UDCCS0)); } } // set state to IDLE ep0_state = EP0_STATE_IDLE; send_zlp = 0;}/* * ep0_int_hndlr * * Handle ep0 interrupts. * * Generally follows the example in the Intel Application Note. * */void ep0_int_hndlr (unsigned int status){ unsigned int udccs0; unsigned int udccr; udccs0 = udc (UDCCS0); udccr = udc (UDCCR); ep0_interrupts++; dbg_ep0 (4, "------------>[%d:%s:%s CCR: %02x CS0: %02x CWC: %02x CAR: %02x]", ep0_interrupts, ep0_state_desc[ep0_state], send_zlp_description[send_zlp], udccr, udccs0, *(UDCWC), *(UDCAR)); if (udccs0 == UDCCS0_IPR) { dbg_ep0 (3, "IPR SET [%d:%02x]", ep0_state, udccs0); return; } if (udccs0 & UDCCS0_SST) { dbg_ep0 (3, "previously sent stall [%d:%02x]", ep0_state, udccs0); } // SE if (udccs0 & UDCCS0_SE) { int ok; dbg_ep0 (3, "unloading, found UDCCS0_SE: CS0: %02x", udccs0); // reset SE IOIOIO (UDCCS0, UDCCS0_SSE, *(UDCCS0) = UDCCS0_SSE, *(UDCCS0) & UDCCS0_SE, ok); if (!ok) { dbg_ep0 (0, "failed to reset SE CS0: %02x ok: %d", *(UDCCS0), ok); } // clear SE before unloading any setup packets if (udccs0 & UDCCS0_OPR) { // reset OPR *(UDCCS0) = UDCCS0_SO; } ep0_state = EP0_STATE_IDLE; if (send_zlp) { dbg_ep0 (0, "not sending ZLP CS0: %02x", *(UDCCS0)); } send_zlp = 0; } if ((ep0_state != EP0_STATE_IDLE) && (udccs0 & UDCCS0_OPR)) { dbg_ep0 (3, "Forcing EP0_STATE_IDLE CS0: %02x", udccs0); ep0_state = EP0_STATE_IDLE; } switch (ep0_state) { case EP0_STATE_IDLE: dbg_ep0 (4, "state: EP0_STATE_IDLE CS0: %02x", udccs0); ep0_read_request (udccs0, udccr); if (ep0_state != EP0_STATE_IN_DATA_PHASE) { break; } // fall through to data phase ep0_set_opr (); case EP0_STATE_IN_DATA_PHASE: dbg_ep0 (4, "state: EP0_STATE_IN_DATA_PHASE %x", udccs0); ep0_in (udccs0); break; case EP0_STATE_END_IN: dbg_ep0 (4, "state: EP0_STATE_END_IN %x", udccs0); ep0_end_in (udccs0); break; } dbg_ep0 (4, "<------------[%s:%s CCR: %02x CS0: %02x CWC: %02x]", ep0_state_desc[ep0_state], send_zlp_description[send_zlp], *(UDCCR), *(UDCCS0), *(UDCWC));}/* ep1 dma engine functions ******************************************************************** */static int dmachn_rx; // rx dma channelstatic int dma_enabled; // dma channel has been setupstatic int dma_is_active; // dma engine is runningstatic int dma_rx_active; // dma engine is runningstatic dma_addr_t dma_rx_curpos;struct usb_device_instance *ep1_device;struct usb_endpoint_instance *ep1_endpoint;/* * * ep1_stop_dma - stop the DMA engine * * Stop the DMA engine. */static void ep1_stop_dma (struct urb *urb){ if (urb && dma_enabled) { unsigned long flags; save_flags_cli (flags); if (!dma_is_active) { restore_flags (flags); dbg_rx (1, "dma OFF: %x %x %x", dmachn_rx, dma_enabled, dma_is_active); return; } dma_is_active = 0; restore_flags (flags); if (ep1_endpoint->rcv_packetSize > 20) { _sa1100_bi_dma_flush_all_irq(dmachn_rx); } }}/* * * ep1_start_dma - start the DMA engine running * * Start the DMA engine. This should allow incoming data to be stored * in the DMA receive buffer. * */static void ep1_start_dma (struct urb *urb){ if (urb && dma_enabled) { unsigned long flags; int ok; save_flags_cli (flags); if (dma_is_active) { restore_flags (flags); dbg_rx (1, "dma ON: %x %x %x", dmachn_rx, dma_enabled, dma_is_active); return; } dma_is_active = 1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -