?? hc_crisv10.c
字號(hào):
{ usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data; struct urb *urb; int epid; int epid_done; etrax_urb_priv_t *urb_priv; DBFENTER; dbg_isoc("dma8_sub3_descr (ISOC) bottom half."); for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) { unsigned long flags; save_flags(flags); cli(); epid_done = 0; /* The descriptor interrupt handler has marked all transmitted isoch. out URBs with TRANSFER_DONE. Now we traverse all epids and for all that have isoch. out traffic traverse its URB list and complete the transmitted URB. */ while (!epid_done) { /* Get the first urb (if any). */ urb = urb_list_first(epid); if (urb == 0) { epid_done = 1; continue; } if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) { epid_done = 1; continue; } if (!usb_pipeout(urb->pipe)) { /* descr interrupts are generated only for out pipes. */ epid_done = 1; continue; } dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub); urb_priv = (etrax_urb_priv_t *)urb->hcpriv; assert(urb_priv); if (urb_priv->urb_state == TRANSFER_DONE) { int i; struct usb_iso_packet_descriptor *packet; /* This urb has been sent. */ dbg_isoc("Completing isoc out URB 0x%p", urb); for (i = 0; i < urb->number_of_packets; i++) { packet = &urb->iso_frame_desc[i]; packet->status = 0; packet->actual_length = packet->length; } etrax_usb_complete_isoc_urb(urb, 0); if (urb_list_empty(epid)) { etrax_usb_free_epid(epid); epid_done = 1; } } else { epid_done = 1; } } restore_flags(flags); } kmem_cache_free(isoc_compl_cache, comp_data); DBFEXIT;}static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc){ struct urb *urb; etrax_urb_priv_t *urb_priv; int epid = 0; unsigned long flags; /* Isoc diagnostics. */ static int curr_fm = 0; static int prev_fm = 0; DBFENTER; /* Clear this interrupt. */ *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); /* Note that this while loop assumes that all packets span only one rx descriptor. */ /* The reason we cli here is that we call the driver's callback functions. */ save_flags(flags); cli(); while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); urb = urb_list_first(epid); //printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb); if (!urb) { err("No urb for epid %d in rx interrupt", epid); __dump_ept_data(epid); goto skip_out; } /* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since ctrl pipes are not. */ if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { __u32 r_usb_ept_data; int no_error = 0; assert(test_bit(epid, (void *)&epid_usage_bitmask)); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { r_usb_ept_data = *R_USB_EPT_DATA_ISO; if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) && (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) && (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) { /* Not an error, just a failure to receive an expected iso in packet in this frame. This is not documented in the designers reference. */ no_error++; } else { warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data); } } else { r_usb_ept_data = *R_USB_EPT_DATA; warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data); } if (!no_error){ warn("error in rx desc->status, epid %d, first urb = 0x%lx", epid, (unsigned long)urb); __dump_in_desc(myNextRxDesc); warn("R_USB_STATUS = 0x%x", *R_USB_STATUS); /* Check that ept was disabled when error occurred. */ switch (usb_pipetype(urb->pipe)) { case PIPE_BULK: assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))); break; case PIPE_CONTROL: assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))); break; case PIPE_INTERRUPT: assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable))); break; case PIPE_ISOCHRONOUS: assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))); break; default: warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p", usb_pipetype(urb->pipe), urb); } etrax_usb_complete_urb(urb, -EPROTO); goto skip_out; } } urb_priv = (etrax_urb_priv_t *)urb->hcpriv; assert(urb_priv); if ((usb_pipetype(urb->pipe) == PIPE_BULK) || (usb_pipetype(urb->pipe) == PIPE_CONTROL) || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { /* We get nodata for empty data transactions, and the rx descriptor's hw_len field is not valid in that case. No data to copy in other words. */ } else { /* Make sure the data fits in the buffer. */ assert(urb_priv->rx_offset + myNextRxDesc->hw_len <= urb->transfer_buffer_length); memcpy(urb->transfer_buffer + urb_priv->rx_offset, phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); urb_priv->rx_offset += myNextRxDesc->hw_len; } if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) && ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) == IO_STATE(USB_EP_command, enable, yes))) { /* The EP is still enabled, so the OUT packet used to ack the in data is probably not processed yet. If the EP sub pointer has not moved beyond urb_priv->last_sb mark it for a descriptor interrupt and complete the urb in the descriptor interrupt handler. */ USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0; while ((sub != NULL) && (sub != urb_priv->last_sb)) { sub = sub->next ? phys_to_virt(sub->next) : 0; } if (sub != NULL) { /* The urb has not been fully processed. */ urb_priv->urb_state = WAITING_FOR_DESCR_INTR; } else { warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub); etrax_usb_complete_urb(urb, 0); } } else { etrax_usb_complete_urb(urb, 0); } } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { struct usb_iso_packet_descriptor *packet; if (urb_priv->urb_state == UNLINK) { info("Ignoring rx data for urb being unlinked."); goto skip_out; } else if (urb_priv->urb_state == NOT_STARTED) { info("What? Got rx data for urb that isn't started?"); goto skip_out; } packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter]; packet->status = 0; if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { /* We get nodata for empty data transactions, and the rx descriptor's hw_len field is not valid in that case. We copy 0 bytes however to stay in synch. */ packet->actual_length = 0; } else { packet->actual_length = myNextRxDesc->hw_len; /* Make sure the data fits in the buffer. */ assert(packet->actual_length <= packet->length); memcpy(urb->transfer_buffer + packet->offset, phys_to_virt(myNextRxDesc->buf), packet->actual_length); } /* Increment the packet counter. */ urb_priv->isoc_packet_counter++; /* Note that we don't care about the eot field in the rx descriptor's status. It will always be set for isoc traffic. */ if (urb->number_of_packets == urb_priv->isoc_packet_counter) { /* Out-of-synch diagnostics. */ curr_fm = (*R_USB_FM_NUMBER & 0x7ff); if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) { /* This test is wrong, if there is more than one isoc in endpoint active it will always calculate wrong since prev_fm is shared by all endpoints. FIXME Make this check per URB using urb->start_frame. */ dbg_isoc("Out of synch? Previous frame = %d, current frame = %d", prev_fm, curr_fm); } prev_fm = curr_fm; /* Complete the urb with status OK. */ etrax_usb_complete_isoc_urb(urb, 0); } } skip_out: /* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr has the same layout as USB_IN_Desc for the relevant fields.) */ prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc); myPrevRxDesc = myNextRxDesc; myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); myLastRxDesc = myPrevRxDesc; myNextRxDesc->status = 0; myNextRxDesc = phys_to_virt(myNextRxDesc->next); } restore_flags(flags); DBFEXIT; return IRQ_HANDLED;}/* This function will unlink the SB descriptors associated with this urb. */static int etrax_remove_from_sb_list(struct urb *urb){ USB_SB_Desc_t *next_sb, *first_sb, *last_sb; etrax_urb_priv_t *urb_priv; int i = 0; DBFENTER; urb_priv = (etrax_urb_priv_t *)urb->hcpriv; assert(urb_priv); /* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor doesn't really need to be disabled, it's just that we expect it to be. */ if (usb_pipetype(urb->pipe) == PIPE_BULK) { assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable))); } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable))); } first_sb = urb_priv->first_sb; last_sb = urb_priv->last_sb; assert(first_sb); assert(last_sb); while (first_sb != last_sb) { next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next); kmem_cache_free(usb_desc_cache, first_sb); first_sb = next_sb; i++; } kmem_cache_free(usb_desc_cache, last_sb); i++; dbg_sb("%d SB descriptors freed", i); /* Compare i with urb->number_of_packets for Isoc traffic. Should be same when calling unlink_urb */ DBFEXIT; return i;}static int etrax_usb_submit_bulk_urb(struct urb *urb){ int epid; int empty; unsigned long flags; etrax_urb_priv_t *urb_priv; DBFENTER; /* Epid allocation, empty check and list add must be protected. Read about this in etrax_usb_submit_ctrl_urb. */ spin_lock_irqsave(&urb_list_lock, flags); epid = etrax_usb_setup_epid(urb); if (epid == -1) { DBFEXIT; spin_unlock_irqrestore(&urb_list_lock, flags); return -ENOMEM; } empty = urb_list_empty(epid); urb_list_add(urb, epid); spin_unlock_irqrestore(&urb_list_lock, flags); dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d", usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid); /* Mark the urb as being in progress. */ urb->status = -EINPROGRESS; /* Setup the hcpriv data. */ urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); assert(urb_priv != NULL); /* This sets rx_offset to 0. */ urb_priv->urb_state = NOT_STARTED; urb->hcpriv = urb_priv; if (empty) { etrax_usb_add_to_bulk_sb_list(urb, epid); } DBFEXIT; return 0;}static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid){ USB_SB_Desc_t *sb_desc; etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; unsigned long flags; char maxlen; DBFENTER; dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); sb_desc = kmem_cache_zalloc(usb_desc_cache, SLAB_FLAG); assert(sb_desc != NULL); if (usb_pipeout(urb->pipe)) { dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid); /* This is probably a sanity check of the bulk transaction length not being larger than 64 kB. */ if (urb->transfer_buffer_length > 0xffff) { panic("urb->transfer_buffer_length > 0xffff"); } sb_desc->sw_len = urb->transfer_buffer_length; /* The rem field is don't care if it's not a full-length transfer, so setting it shouldn't hurt. Also, rem isn't used for OUT traffic. */ sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, out) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes)); /* The full field is set to yes, even if we don't actually check that this is a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0). Setting full prevents the USB controller from sending an empty packet in that case. However, if URB_ZERO_PACKET was set we want that. */ if (!(urb
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -