// SPDX-License-Identifier: GPL-1.0+ /* * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber <[email protected]> * (C) Copyright 2000-2002 David Brownell <[email protected]> * * This file is licenced under the GPL. */ #include <linux/irq.h> #include <linux/slab.h> static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) { … } /*-------------------------------------------------------------------------*/ /* * URB goes back to driver, and isn't reissued. * It's completely gone from HC data structures. * PRECONDITION: ohci lock held, irqs blocked. */ static void finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { … } /*-------------------------------------------------------------------------* * ED handling functions *-------------------------------------------------------------------------*/ /* search for the right schedule branch to use for a periodic ed. * does some load balancing; returns the branch, or negative errno. */ static int balance (struct ohci_hcd *ohci, int interval, int load) { … } /*-------------------------------------------------------------------------*/ /* both iso and interrupt requests have periods; this routine puts them * into the schedule tree in the apppropriate place. most iso devices use * 1msec periods, but that's not required. */ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) { … } /* link an ed into one of the HC chains */ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) { … } /*-------------------------------------------------------------------------*/ /* scan the periodic table to find and unlink this ED */ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) { … } /* unlink an ed from one of the HC chains. * just the link to the ed is unlinked. * the link from the ed still points to another operational ed or 0 * so the HC can eventually finish the processing of the unlinked ed * (assuming it already started that, which needn't be true). * * ED_UNLINK is a transient state: the HC may still see this ED, but soon * it won't. ED_SKIP means the HC will finish its current transaction, * but won't start anything new. The TD queue may still grow; device * drivers don't know about this HCD-internal state. * * When the HC can't see the ED, something changes ED_UNLINK to one of: * * - ED_OPER: when there's any request queued, the ED gets rescheduled * immediately. HC should be working on them. * * - ED_IDLE: when there's no TD queue or the HC isn't running. * * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. */ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { … } /*-------------------------------------------------------------------------*/ /* 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 ) { … } /*-------------------------------------------------------------------------*/ /* 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) { … } /*-------------------------------------------------------------------------* * TD handling functions *-------------------------------------------------------------------------*/ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ static void td_fill (struct ohci_hcd *ohci, u32 info, dma_addr_t data, int len, struct urb *urb, int index) { … } /*-------------------------------------------------------------------------*/ /* 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 ) { … } /*-------------------------------------------------------------------------* * Done List handling functions *-------------------------------------------------------------------------*/ /* calculate transfer length/status and update the urb */ static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { … } /*-------------------------------------------------------------------------*/ static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { … } /* Add a TD to the done list */ static void add_to_done_list(struct ohci_hcd *ohci, struct td *td) { … } /* Get the entries on the hardware done queue and put them on our list */ static void update_done_list(struct ohci_hcd *ohci) { … } /*-------------------------------------------------------------------------*/ /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ static void finish_unlinks(struct ohci_hcd *ohci) { … } /*-------------------------------------------------------------------------*/ /* Take back a TD from the host controller */ static void takeback_td(struct ohci_hcd *ohci, struct td *td) { … } /* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, * instead of scanning the (re-reversed) donelist as this does. */ static void process_done_list(struct ohci_hcd *ohci) { … } /* * TD takeback and URB giveback must be single-threaded. * This routine takes care of it all. */ static void ohci_work(struct ohci_hcd *ohci) { … }