linux/drivers/usb/host/ehci-q.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2001-2004 by David Brownell
 */

/* this file is part of ehci-hcd.c */

/*-------------------------------------------------------------------------*/

/*
 * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
 *
 * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
 * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
 * buffers needed for the larger number).  We use one QH per endpoint, queue
 * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
 *
 * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
 * interrupts) needs careful scheduling.  Performance improvements can be
 * an ongoing challenge.  That's in "ehci-sched.c".
 *
 * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
 * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
 * (b) special fields in qh entries or (c) split iso entries.  TTs will
 * buffer low/full speed data so the host collects it at high speed.
 */

/*-------------------------------------------------------------------------*/

/* fill a qtd, returning how much of the buffer we were able to queue up */

static unsigned int
qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
		  size_t len, int token, int maxpacket)
{}

/*-------------------------------------------------------------------------*/

static inline void
qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{}

/* if it weren't for a common silicon quirk (writing the dummy into the qh
 * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
 * recovery (including urb dequeue) would need software changes to a QH...
 */
static void
qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
{}

/*-------------------------------------------------------------------------*/

static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);

static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
		struct usb_host_endpoint *ep)
{}

static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
		struct urb *urb, u32 token)
{}

static int qtd_copy_status (
	struct ehci_hcd *ehci,
	struct urb *urb,
	size_t length,
	u32 token
)
{}

static void
ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
{}

static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);

/*
 * Process and free completed qtds for a qh, returning URBs to drivers.
 * Chases up to qh->hw_current.  Returns nonzero if the caller should
 * unlink qh.
 */
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{}

/*-------------------------------------------------------------------------*/

/*
 * 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
) {}

/*
 * 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
) {}

/*-------------------------------------------------------------------------*/

// 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
) {}

/*-------------------------------------------------------------------------*/

static void enable_async(struct ehci_hcd *ehci)
{}

static void disable_async(struct ehci_hcd *ehci)
{}

/* move qh (and its qtds) onto async queue; maybe enable queue.  */

static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{}

/*-------------------------------------------------------------------------*/

/*
 * For control/bulk/interrupt, return QH with these TDs appended.
 * Allocates and initializes the QH if necessary.
 * Returns null if it can't allocate a QH it needs to.
 * If the QH has TDs (urbs) already, that's great.
 */
static struct ehci_qh *qh_append_tds (
	struct ehci_hcd		*ehci,
	struct urb		*urb,
	struct list_head	*qtd_list,
	int			epnum,
	void			**ptr
)
{}

/*-------------------------------------------------------------------------*/

static int
submit_async (
	struct ehci_hcd		*ehci,
	struct urb		*urb,
	struct list_head	*qtd_list,
	gfp_t			mem_flags
) {}

/*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_HCD_TEST_MODE
/*
 * This function creates the qtds and submits them for the
 * SINGLE_STEP_SET_FEATURE Test.
 * This is done in two parts: first SETUP req for GetDesc is sent then
 * 15 seconds later, the IN stage for GetDesc starts to req data from dev
 *
 * is_setup : i/p argument decides which of the two stage needs to be
 * performed; TRUE - SETUP and FALSE - IN+STATUS
 * Returns 0 if success
 */
static int ehci_submit_single_step_set_feature(
	struct usb_hcd  *hcd,
	struct urb      *urb,
	int             is_setup
) {}
#endif /* CONFIG_USB_HCD_TEST_MODE */

/*-------------------------------------------------------------------------*/

static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{}

static void start_iaa_cycle(struct ehci_hcd *ehci)
{}

static void end_iaa_cycle(struct ehci_hcd *ehci)
{}

/* See if the async qh for the qtds being unlinked are now gone from the HC */

static void end_unlink_async(struct ehci_hcd *ehci)
{}

static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh);

static void unlink_empty_async(struct ehci_hcd *ehci)
{}

#ifdef	CONFIG_PM

/* The root hub is suspended; unlink all the async QHs */
static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
{}

#endif

/* makes sure the async qh will become idle */
/* caller must own ehci->lock */

static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{}

/*-------------------------------------------------------------------------*/

static void scan_async (struct ehci_hcd *ehci)
{}