📄 ohci-q.c
字号:
} break; // case PIPE_INTERRUPT: // case PIPE_ISOCHRONOUS: default: periodic_unlink (ohci, ed); break; }}/*-------------------------------------------------------------------------*//* get and maybe (re)init an endpoint. init _should_ be done only as part * of enumeration, usb_set_configuration() or usb_set_interface(). */static struct ed *ed_get ( struct ohci_hcd *ohci, struct usb_host_endpoint *ep, struct usb_device *udev, unsigned int pipe, int interval) { struct ed *ed; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); if (!(ed = ep->hcpriv)) { struct td *td; int is_out; u32 info; ed = ed_alloc (ohci, GFP_ATOMIC); if (!ed) { /* out of memory */ goto done; } /* dummy td; end of td list for ed */ td = td_alloc (ohci, GFP_ATOMIC); if (!td) { /* out of memory */ ed_free (ohci, ed); ed = NULL; goto done; } ed->dummy = td; ed->hwTailP = cpu_to_hc32 (ohci, td->td_dma); ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ ed->state = ED_IDLE; is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN); /* FIXME usbcore changes dev->devnum before SET_ADDRESS * suceeds ... otherwise we wouldn't need "pipe". */ info = usb_pipedevice (pipe); ed->type = usb_pipetype(pipe); info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7; info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16; if (udev->speed == USB_SPEED_LOW) info |= ED_LOWSPEED; /* only control transfers store pids in tds */ if (ed->type != PIPE_CONTROL) { info |= is_out ? ED_OUT : ED_IN; if (ed->type != PIPE_BULK) { /* periodic transfers... */ if (ed->type == PIPE_ISOCHRONOUS) info |= ED_ISO; else if (interval > 32) /* iso can be bigger */ interval = 32; ed->interval = interval; ed->load = usb_calc_bus_time ( udev->speed, !is_out, ed->type == PIPE_ISOCHRONOUS, le16_to_cpu(ep->desc.wMaxPacketSize)) / 1000; } } ed->hwINFO = cpu_to_hc32(ohci, info); ep->hcpriv = ed; }done: spin_unlock_irqrestore (&ohci->lock, flags); return ed; }/*-------------------------------------------------------------------------*//* request unlinking of an endpoint from an operational HC. * put the ep on the rm_list * real work is done at the next start frame (SF) hardware interrupt * caller guarantees HCD is running, so hardware access is safe, * and that ed->state is ED_OPER */static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed){ ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE); ed_deschedule (ohci, ed); /* rm_list is just singly linked, for simplicity */ ed->ed_next = ohci->ed_rm_list; ed->ed_prev = NULL; ohci->ed_rm_list = ed; /* enable SOF interrupt */ ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); // flush those writes, and get latest HCCA contents (void) ohci_readl (ohci, &ohci->regs->control); /* SF interrupt might get delayed; record the frame counter value that * indicates when the HC isn't looking at it, so concurrent unlinks * behave. frame_no wraps every 2^16 msec, and changes right before * SF is triggered. */ ed->tick = ohci_frame_no(ohci) + 1;}/*-------------------------------------------------------------------------* * TD handling functions *-------------------------------------------------------------------------*//* enqueue next TD for this URB (OHCI spec 5.2.8.2) */static voidtd_fill (struct ohci_hcd *ohci, u32 info, dma_addr_t data, int len, struct urb *urb, int index){ struct td *td, *td_pt; struct urb_priv *urb_priv = urb->hcpriv; int is_iso = info & TD_ISO; int hash; // ASSERT (index < urb_priv->length); /* aim for only one interrupt per urb. mostly applies to control * and iso; other urbs rarely need more than one TD per urb. * this way, only final tds (or ones with an error) cause IRQs. * at least immediately; use DI=6 in case any control request is * tempted to die part way through. (and to force the hc to flush * its donelist soonish, even on unlink paths.) * * NOTE: could delay interrupts even for the last TD, and get fewer * interrupts ... increasing per-urb latency by sharing interrupts. * Drivers that queue bulk urbs may request that behavior. */ if (index != (urb_priv->length - 1) || (urb->transfer_flags & URB_NO_INTERRUPT)) info |= TD_DI_SET (6); /* use this td as the next dummy */ td_pt = urb_priv->td [index]; /* fill the old dummy TD */ td = urb_priv->td [index] = urb_priv->ed->dummy; urb_priv->ed->dummy = td_pt; td->ed = urb_priv->ed; td->next_dl_td = NULL; td->index = index; td->urb = urb; td->data_dma = data; if (!len) data = 0; td->hwINFO = cpu_to_hc32 (ohci, info); if (is_iso) { td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000); td->ed->last_iso = info & 0xffff; } else { td->hwCBP = cpu_to_hc32 (ohci, data); } if (data) td->hwBE = cpu_to_hc32 (ohci, data + len - 1); else td->hwBE = 0; td->hwNextTD = cpu_to_hc32 (ohci, td_pt->td_dma); /* append to queue */ list_add_tail (&td->td_list, &td->ed->td_list); /* hash it for later reverse mapping */ hash = TD_HASH_FUNC (td->td_dma); td->td_hash = ohci->td_hash [hash]; ohci->td_hash [hash] = td; /* HC might read the TD (or cachelines) right away ... */ wmb (); td->ed->hwTailP = td->hwNextTD;}/*-------------------------------------------------------------------------*//* Prepare all TDs of a transfer, and queue them onto the ED. * Caller guarantees HC is active. * Usually the ED is already on the schedule, so TDs might be * processed as soon as they're queued. */static void td_submit_urb ( struct ohci_hcd *ohci, struct urb *urb) { struct urb_priv *urb_priv = urb->hcpriv; dma_addr_t data; int data_len = urb->transfer_buffer_length; int cnt = 0; u32 info = 0; int is_out = usb_pipeout (urb->pipe); int periodic = 0; /* OHCI handles the bulk/interrupt data toggles itself. We just * use the device toggle bits for resetting, and rely on the fact * that resetting toggle is meaningless if the endpoint is active. */ if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); } urb_priv->td_cnt = 0; list_add (&urb_priv->pending, &ohci->pending); if (data_len) data = urb->transfer_dma; else data = 0; /* NOTE: TD_CC is set so we can tell which TDs the HC processed by * using TD_CC_GET, as well as by seeing them on the done list. * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) */ switch (urb_priv->ed->type) { /* Bulk and interrupt are identical except for where in the schedule * their EDs live. */ case PIPE_INTERRUPT: /* ... and periodic urbs have extra accounting */ periodic = ohci_to_hcd(ohci)->self.bandwidth_int_reqs++ == 0 && ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0; /* FALLTHROUGH */ case PIPE_BULK: info = is_out ? TD_T_TOGGLE | TD_CC | TD_DP_OUT : TD_T_TOGGLE | TD_CC | TD_DP_IN; /* TDs _could_ transfer up to 8K each */ while (data_len > 4096) { td_fill (ohci, info, data, 4096, urb, cnt); data += 4096; data_len -= 4096; cnt++; } /* maybe avoid ED halt on final TD short read */ if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) info |= TD_R; td_fill (ohci, info, data, data_len, urb, cnt); cnt++; if ((urb->transfer_flags & URB_ZERO_PACKET) && cnt < urb_priv->length) { td_fill (ohci, info, 0, 0, urb, cnt); cnt++; } /* maybe kickstart bulk list */ if (urb_priv->ed->type == PIPE_BULK) { wmb (); ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus); } break; /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, * any DATA phase works normally, and the STATUS ack is special. */ case PIPE_CONTROL: info = TD_CC | TD_DP_SETUP | TD_T_DATA0; td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++); if (data_len > 0) { info = TD_CC | TD_R | TD_T_DATA1; info |= is_out ? TD_DP_OUT : TD_DP_IN; /* NOTE: mishandles transfers >8K, some >4K */ td_fill (ohci, info, data, data_len, urb, cnt++); } info = (is_out || data_len == 0) ? TD_CC | TD_DP_IN | TD_T_DATA1 : TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill (ohci, info, data, 0, urb, cnt++); /* maybe kickstart control list */ wmb (); ohci_writel (ohci, OHCI_CLF, &ohci->regs->cmdstatus); break; /* ISO has no retransmit, so no toggle; and it uses special TDs. * Each TD could handle multiple consecutive frames (interval 1); * we could often reduce the number of TDs here. */ case PIPE_ISOCHRONOUS: for (cnt = 0; cnt < urb->number_of_packets; cnt++) { int frame = urb->start_frame; // FIXME scheduling should handle frame counter // roll-around ... exotic case (and OHCI has // a 2^16 iso range, vs other HCs max of 2^10) frame += cnt * urb->interval; frame &= 0xffff; td_fill (ohci, TD_CC | TD_ISO | frame, data + urb->iso_frame_desc [cnt].offset, urb->iso_frame_desc [cnt].length, urb, cnt); } periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0 && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0; break; } /* start periodic dma if needed */ if (periodic) { wmb (); ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } // ASSERT (urb_priv->length == cnt);}/*-------------------------------------------------------------------------* * Done List handling functions *-------------------------------------------------------------------------*//* calculate transfer length/status and update the urb * PRECONDITION: irqsafe (only for urb->status locking) */static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td){ u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { u16 tdPSW = ohci_hwPSW (ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that * only the first of 0..MAXPSW psws is used. */ cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ return; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; else { /* short reads are always OK for ISO */ if (cc == TD_DATAUNDERRUN) cc = TD_CC_NOERROR; dlen = tdPSW & 0x3ff; } urb->actual_length += dlen; urb->iso_frame_desc [td->index].actual_length = dlen; urb->iso_frame_desc [td->index].status = cc_to_error [cc]; if (cc != TD_CC_NOERROR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -