?? ehci-q.c
字號:
/* token in overlay may be most current */ if (state == QH_STATE_IDLE && cpu_to_le32 (qtd->qtd_dma) == qh->hw_current) token = le32_to_cpu (qh->hw_token); /* force halt for unlinked or blocked qh, so we'll * patch the qh later and so that completions can't * activate it while we "know" it's stopped. */ if ((HALT_BIT & qh->hw_token) == 0) {halt: qh->hw_token |= HALT_BIT; wmb (); } } /* remove it from the queue */ spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); do_status = (urb->status == -EREMOTEIO) && usb_pipecontrol (urb->pipe); spin_unlock (&urb->lock); if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, struct ehci_qtd, qtd_list); last->hw_next = qtd->hw_next; } list_del (&qtd->qtd_list); last = qtd; } /* last urb's completion might still need calling */ if (likely (last != NULL)) { ehci_urb_done (ehci, last->urb); count++; ehci_qtd_free (ehci, last); } /* restore original state; caller must unlink or relink */ qh->qh_state = state; /* be sure the hardware's done with the qh before refreshing * it after fault cleanup, or recovering from silicon wrongly * overlaying the dummy qtd (which reduces DMA chatter). */ if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) { switch (state) { case QH_STATE_IDLE: qh_refresh(ehci, qh); break; case QH_STATE_LINKED: /* should be rare for periodic transfers, * except maybe high bandwidth ... */ if ((__constant_cpu_to_le32 (QH_SMASK) & qh->hw_info2) != 0) { intr_deschedule (ehci, qh); (void) qh_schedule (ehci, qh); } else unlink_async (ehci, qh); break; /* otherwise, unlink already started */ } } return count;}/*-------------------------------------------------------------------------*/// high bandwidth multiplier, as encoded in highspeed endpoint descriptors#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))// ... and packet size, for any kind of endpoint descriptor#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)/* * reverse of qh_urb_transaction: free a list of TDs. * used for cleanup after errors, before HC sees an URB's TDs. */static void qtd_list_free ( struct ehci_hcd *ehci, struct urb *urb, struct list_head *qtd_list) { struct list_head *entry, *temp; list_for_each_safe (entry, temp, qtd_list) { struct ehci_qtd *qtd; qtd = list_entry (entry, struct ehci_qtd, qtd_list); list_del (&qtd->qtd_list); ehci_qtd_free (ehci, qtd); }}/* * create a list of filled qtds for this URB; won't link into qh. */static struct list_head *qh_urb_transaction ( struct ehci_hcd *ehci, struct urb *urb, struct list_head *head, gfp_t flags) { struct ehci_qtd *qtd, *qtd_prev; dma_addr_t buf; int len, maxpacket; int is_input; u32 token; /* * URBs map to sequences of QTDs: one logical transaction */ qtd = ehci_qtd_alloc (ehci, flags); if (unlikely (!qtd)) return NULL; list_add_tail (&qtd->qtd_list, head); qtd->urb = urb; token = QTD_STS_ACTIVE; token |= (EHCI_TUNE_CERR << 10); /* for split transactions, SplitXState initialized to zero */ len = urb->transfer_buffer_length; is_input = usb_pipein (urb->pipe); if (usb_pipecontrol (urb->pipe)) { /* SETUP pid */ qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest), token | (2 /* "setup" */ << 8), 8); /* ... and always at least one more pid */ token ^= QTD_TOGGLE; qtd_prev = qtd; qtd = ehci_qtd_alloc (ehci, flags); if (unlikely (!qtd)) goto cleanup; qtd->urb = urb; qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); list_add_tail (&qtd->qtd_list, head); /* for zero length DATA stages, STATUS is always IN */ if (len == 0) token |= (1 /* "in" */ << 8); } /* * data transfer stage: buffer setup */ buf = urb->transfer_dma; if (is_input) token |= (1 /* "in" */ << 8); /* else it's already initted to "out" pid (0 << 8) */ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); /* * buffer gets wrapped in one or more qtds; * last one may be "short" (including zero len) * and may serve as a control status ack */ for (;;) { int this_qtd_len; this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket); len -= this_qtd_len; buf += this_qtd_len; if (is_input) qtd->hw_alt_next = ehci->async->hw_alt_next; /* qh makes control packets use qtd toggle; maybe switch it */ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) token ^= QTD_TOGGLE; if (likely (len <= 0)) break; qtd_prev = qtd; qtd = ehci_qtd_alloc (ehci, flags); if (unlikely (!qtd)) goto cleanup; qtd->urb = urb; qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); list_add_tail (&qtd->qtd_list, head); } /* unless the bulk/interrupt caller wants a chance to clean * up after short reads, hc should advance qh past this urb */ if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 || usb_pipecontrol (urb->pipe))) qtd->hw_alt_next = EHCI_LIST_END; /* * control requests may need a terminating data "status" ack; * bulk ones may need a terminating short packet (zero length). */ if (likely (urb->transfer_buffer_length != 0)) { int one_more = 0; if (usb_pipecontrol (urb->pipe)) { one_more = 1; token ^= 0x0100; /* "in" <--> "out" */ token |= QTD_TOGGLE; /* force DATA1 */ } else if (usb_pipebulk (urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) && !(urb->transfer_buffer_length % maxpacket)) { one_more = 1; } if (one_more) { qtd_prev = qtd; qtd = ehci_qtd_alloc (ehci, flags); if (unlikely (!qtd)) goto cleanup; qtd->urb = urb; qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); list_add_tail (&qtd->qtd_list, head); /* never any data in such packets */ qtd_fill (qtd, 0, 0, token, 0); } } /* by default, enable interrupt on urb completion */ if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); return head;cleanup: qtd_list_free (ehci, urb, head); return NULL;}/*-------------------------------------------------------------------------*/// Would be best to create all qh's from config descriptors,// when each interface/altsetting is established. Unlink// any previous qh and cancel its urbs first; endpoints are// implicitly reset then (data toggle too).// That'd mean updating how usbcore talks to HCDs. (2.7?)/* * Each QH holds a qtd list; a QH is used for everything except iso. * * For interrupt urbs, the scheduler must set the microframe scheduling * mask(s) each time the QH gets scheduled. For highspeed, that's * just one microframe in the s-mask. For split interrupt transactions * there are additional complications: c-mask, maybe FSTNs. */static struct ehci_qh *qh_make ( struct ehci_hcd *ehci, struct urb *urb, gfp_t flags) { struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); u32 info1 = 0, info2 = 0; int is_input, type; int maxp = 0; if (!qh) return qh; /* * init endpoint/device data for this QH */ info1 |= usb_pipeendpoint (urb->pipe) << 8; info1 |= usb_pipedevice (urb->pipe) << 0; is_input = usb_pipein (urb->pipe); type = usb_pipetype (urb->pipe); maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input); /* Compute interrupt scheduling parameters just once, and save. * - allowing for high bandwidth, how many nsec/uframe are used? * - split transactions need a second CSPLIT uframe; same question * - splits also need a schedule gap (for full/low speed I/O) * - qh has a polling interval * * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0, hb_mult (maxp) * max_packet (maxp))); qh->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { qh->c_usecs = 0; qh->gap_uf = 0; qh->period = urb->interval >> 3; if (qh->period == 0 && urb->interval != 1) { /* NOTE interval 2 or 4 uframes could work. * But interval 1 scheduling is simpler, and * includes high bandwidth. */ dbg ("intr period %d uframes, NYET!", urb->interval); goto done; } } else { struct usb_tt *tt = urb->dev->tt; int think_time; /* gap is f(FS/LS transfer times) */ qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, is_input, 0, maxp) / (125 * 1000); /* FIXME this just approximates SPLIT/CSPLIT times */ if (is_input) { // SPLIT, gap, CSPLIT+DATA qh->c_usecs = qh->usecs + HS_USECS (0); qh->usecs = HS_USECS (1); } else { // SPLIT+DATA, gap, CSPLIT qh->usecs += HS_USECS (1); qh->c_usecs = HS_USECS (0); } think_time = tt ? tt->think_time : 0; qh->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); qh->period = urb->interval; } } /* support for tt scheduling, and access to toggles */ qh->dev = urb->dev; /* using TT? */ switch (urb->dev->speed) { case USB_SPEED_LOW: info1 |= (1 << 12); /* EPS "low" */ /* FALL THROUGH */ case USB_SPEED_FULL: /* EPS 0 means "full" */ if (type != PIPE_INTERRUPT) info1 |= (EHCI_TUNE_RL_TT << 28); if (type == PIPE_CONTROL) { info1 |= (1 << 27); /* for TT */ info1 |= 1 << 14; /* toggle from qtd */ } info1 |= maxp << 16; info2 |= (EHCI_TUNE_MULT_TT << 30); /* Some Freescale processors have an erratum in which the * port number in the queue head was 0..N-1 instead of 1..N. */ if (ehci_has_fsl_portno_bug(ehci)) info2 |= (urb->dev->ttport-1) << 23; else info2 |= urb->dev->ttport << 23; /* set the address of the TT; for TDI's integrated * root hub tt, leave it zeroed. */ if (!ehci_is_TDI(ehci) || urb->dev->tt->hub != ehci_to_hcd(ehci)->self.root_hub) info2 |= urb->dev->tt->hub->devnum << 16; /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ break; case USB_SPEED_HIGH: /* no TT involved */ info1 |= (2 << 12); /* EPS "high" */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -