1f9f848faSopenharmony_ci/*-
2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
3f9f848faSopenharmony_ci *
4f9f848faSopenharmony_ci * Copyright (c) 2008-2021 Hans Petter Selasky. All rights reserved.
5f9f848faSopenharmony_ci *
6f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without
7f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions
8f9f848faSopenharmony_ci * are met:
9f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright
10f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer.
11f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
12f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
13f9f848faSopenharmony_ci *    documentation and/or other materials provided with the distribution.
14f9f848faSopenharmony_ci *
15f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f9f848faSopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25f9f848faSopenharmony_ci * SUCH DAMAGE.
26f9f848faSopenharmony_ci */
27f9f848faSopenharmony_ci
28f9f848faSopenharmony_ci#include "implementation/global_implementation.h"
29f9f848faSopenharmony_ci
30f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
31f9f848faSopenharmony_ci#define	USB_DEBUG_VAR usb_debug
32f9f848faSopenharmony_ci
33f9f848faSopenharmony_ciSPIN_LOCK_INIT(g_usb_wait_queue_spinlock);
34f9f848faSopenharmony_ci
35f9f848faSopenharmony_cistruct usb_std_packet_size {
36f9f848faSopenharmony_ci	struct {
37f9f848faSopenharmony_ci		uint16_t min;		/* inclusive */
38f9f848faSopenharmony_ci		uint16_t max;		/* inclusive */
39f9f848faSopenharmony_ci	}	range;
40f9f848faSopenharmony_ci
41f9f848faSopenharmony_ci	uint16_t fixed[4];
42f9f848faSopenharmony_ci};
43f9f848faSopenharmony_ci
44f9f848faSopenharmony_cistatic usb_callback_t usb_request_callback;
45f9f848faSopenharmony_ci
46f9f848faSopenharmony_cistatic const struct usb_config usb_control_ep_cfg[USB_CTRL_XFER_MAX] = {
47f9f848faSopenharmony_ci	/* This transfer is used for generic control endpoint transfers */
48f9f848faSopenharmony_ci
49f9f848faSopenharmony_ci	[0] = {
50f9f848faSopenharmony_ci		.type = UE_CONTROL,
51f9f848faSopenharmony_ci		.endpoint = 0x00,	/* Control endpoint */
52f9f848faSopenharmony_ci		.direction = UE_DIR_ANY,
53f9f848faSopenharmony_ci		.bufsize = USB_EP0_BUFSIZE,	/* bytes */
54f9f848faSopenharmony_ci		.flags = {.proxy_buffer = 1,},
55f9f848faSopenharmony_ci		.callback = &usb_request_callback,
56f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
57f9f848faSopenharmony_ci	},
58f9f848faSopenharmony_ci
59f9f848faSopenharmony_ci	/* This transfer is used for generic clear stall only */
60f9f848faSopenharmony_ci
61f9f848faSopenharmony_ci	[1] = {
62f9f848faSopenharmony_ci		.type = UE_CONTROL,
63f9f848faSopenharmony_ci		.endpoint = 0x00,	/* Control pipe */
64f9f848faSopenharmony_ci		.direction = UE_DIR_ANY,
65f9f848faSopenharmony_ci		.bufsize = sizeof(struct usb_device_request),
66f9f848faSopenharmony_ci		.callback = &usb_do_clear_stall_callback,
67f9f848faSopenharmony_ci		.timeout = 1000,	/* 1 second */
68f9f848faSopenharmony_ci		.interval = 50,	/* 50ms */
69f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
70f9f848faSopenharmony_ci	},
71f9f848faSopenharmony_ci};
72f9f848faSopenharmony_ci
73f9f848faSopenharmony_cistatic const struct usb_config usb_control_ep_quirk_cfg[USB_CTRL_XFER_MAX] = {
74f9f848faSopenharmony_ci	/* This transfer is used for generic control endpoint transfers */
75f9f848faSopenharmony_ci
76f9f848faSopenharmony_ci	[0] = {
77f9f848faSopenharmony_ci		.type = UE_CONTROL,
78f9f848faSopenharmony_ci		.endpoint = 0x00,	/* Control endpoint */
79f9f848faSopenharmony_ci		.direction = UE_DIR_ANY,
80f9f848faSopenharmony_ci		.bufsize = 65535,	/* bytes */
81f9f848faSopenharmony_ci		.callback = &usb_request_callback,
82f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
83f9f848faSopenharmony_ci	},
84f9f848faSopenharmony_ci
85f9f848faSopenharmony_ci	/* This transfer is used for generic clear stall only */
86f9f848faSopenharmony_ci
87f9f848faSopenharmony_ci	[1] = {
88f9f848faSopenharmony_ci		.type = UE_CONTROL,
89f9f848faSopenharmony_ci		.endpoint = 0x00,	/* Control pipe */
90f9f848faSopenharmony_ci		.direction = UE_DIR_ANY,
91f9f848faSopenharmony_ci		.bufsize = sizeof(struct usb_device_request),
92f9f848faSopenharmony_ci		.callback = &usb_do_clear_stall_callback,
93f9f848faSopenharmony_ci		.timeout = 1000,	/* 1 second */
94f9f848faSopenharmony_ci		.interval = 50,	/* 50ms */
95f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
96f9f848faSopenharmony_ci	},
97f9f848faSopenharmony_ci};
98f9f848faSopenharmony_ci
99f9f848faSopenharmony_ci/* function prototypes */
100f9f848faSopenharmony_ci
101f9f848faSopenharmony_cistatic void	usbd_update_max_frame_size(struct usb_xfer *);
102f9f848faSopenharmony_cistatic void	usbd_transfer_unsetup_sub(struct usb_xfer_root *, uint8_t);
103f9f848faSopenharmony_cistatic void	usbd_control_transfer_init(struct usb_xfer *);
104f9f848faSopenharmony_cistatic int	usbd_setup_ctrl_transfer(struct usb_xfer *);
105f9f848faSopenharmony_cistatic void	usb_callback_proc(struct usb_proc_msg *);
106f9f848faSopenharmony_cistatic void	usbd_callback_ss_done_defer(struct usb_xfer *);
107f9f848faSopenharmony_cistatic void	usbd_callback_wrapper(struct usb_xfer_queue *);
108f9f848faSopenharmony_cistatic void	usbd_transfer_start_cb(void *);
109f9f848faSopenharmony_cistatic uint8_t	usbd_callback_wrapper_sub(struct usb_xfer *);
110f9f848faSopenharmony_cistatic void	usbd_get_std_packet_size(struct usb_std_packet_size *ptr,
111f9f848faSopenharmony_ci		    uint8_t type, enum usb_dev_speed speed);
112f9f848faSopenharmony_ci
113f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
114f9f848faSopenharmony_ci *	usb_request_callback
115f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
116f9f848faSopenharmony_cistatic void
117f9f848faSopenharmony_ciusb_request_callback(struct usb_xfer *xfer, usb_error_t error)
118f9f848faSopenharmony_ci{
119f9f848faSopenharmony_ci	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE)
120f9f848faSopenharmony_ci		usb_handle_request_callback(xfer, error);
121f9f848faSopenharmony_ci	else
122f9f848faSopenharmony_ci		usbd_do_request_callback(xfer, error);
123f9f848faSopenharmony_ci}
124f9f848faSopenharmony_ci
125f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
126f9f848faSopenharmony_ci *	usbd_update_max_frame_size
127f9f848faSopenharmony_ci *
128f9f848faSopenharmony_ci * This function updates the maximum frame size, hence high speed USB
129f9f848faSopenharmony_ci * can transfer multiple consecutive packets.
130f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
131f9f848faSopenharmony_cistatic void
132f9f848faSopenharmony_ciusbd_update_max_frame_size(struct usb_xfer *xfer)
133f9f848faSopenharmony_ci{
134f9f848faSopenharmony_ci	/* compute maximum frame size */
135f9f848faSopenharmony_ci	/* this computation should not overflow 16-bit */
136f9f848faSopenharmony_ci	/* max = 15 * 1024 */
137f9f848faSopenharmony_ci
138f9f848faSopenharmony_ci	xfer->max_frame_size = xfer->max_packet_size * xfer->max_packet_count;
139f9f848faSopenharmony_ci}
140f9f848faSopenharmony_ci
141f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
142f9f848faSopenharmony_ci *	usbd_get_dma_delay
143f9f848faSopenharmony_ci *
144f9f848faSopenharmony_ci * The following function is called when we need to
145f9f848faSopenharmony_ci * synchronize with DMA hardware.
146f9f848faSopenharmony_ci *
147f9f848faSopenharmony_ci * Returns:
148f9f848faSopenharmony_ci *    0: no DMA delay required
149f9f848faSopenharmony_ci * Else: milliseconds of DMA delay
150f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
151f9f848faSopenharmony_ciusb_timeout_t
152f9f848faSopenharmony_ciusbd_get_dma_delay(struct usb_device *udev)
153f9f848faSopenharmony_ci{
154f9f848faSopenharmony_ci	const struct usb_bus_methods *mtod;
155f9f848faSopenharmony_ci	uint32_t temp;
156f9f848faSopenharmony_ci
157f9f848faSopenharmony_ci	mtod = udev->bus->methods;
158f9f848faSopenharmony_ci	temp = 0;
159f9f848faSopenharmony_ci
160f9f848faSopenharmony_ci	if (mtod->get_dma_delay) {
161f9f848faSopenharmony_ci		(mtod->get_dma_delay) (udev, &temp);
162f9f848faSopenharmony_ci		/*
163f9f848faSopenharmony_ci		 * Round up and convert to milliseconds. Note that we use
164f9f848faSopenharmony_ci		 * 1024 milliseconds per second. to save a division.
165f9f848faSopenharmony_ci		 */
166f9f848faSopenharmony_ci		temp += 0x3FF;
167f9f848faSopenharmony_ci		temp /= 0x400;
168f9f848faSopenharmony_ci	}
169f9f848faSopenharmony_ci	return (temp);
170f9f848faSopenharmony_ci}
171f9f848faSopenharmony_ci
172f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
173f9f848faSopenharmony_ci *	usbd_transfer_setup_sub_malloc
174f9f848faSopenharmony_ci *
175f9f848faSopenharmony_ci * This function will allocate one or more DMA'able memory chunks
176f9f848faSopenharmony_ci * according to "size", "align" and "count" arguments. "ppc" is
177f9f848faSopenharmony_ci * pointed to a linear array of USB page caches afterwards.
178f9f848faSopenharmony_ci *
179f9f848faSopenharmony_ci * If the "align" argument is equal to "1" a non-contiguous allocation
180f9f848faSopenharmony_ci * can happen. Else if the "align" argument is greater than "1", the
181f9f848faSopenharmony_ci * allocation will always be contiguous in memory.
182f9f848faSopenharmony_ci *
183f9f848faSopenharmony_ci * Returns:
184f9f848faSopenharmony_ci *    0: Success
185f9f848faSopenharmony_ci * Else: Failure
186f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
187f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
188f9f848faSopenharmony_ciuint8_t
189f9f848faSopenharmony_ciusbd_transfer_setup_sub_malloc(struct usb_setup_params *parm,
190f9f848faSopenharmony_ci    struct usb_page_cache **ppc, usb_size_t size, usb_size_t align,
191f9f848faSopenharmony_ci    usb_size_t count)
192f9f848faSopenharmony_ci{
193f9f848faSopenharmony_ci	struct usb_page_cache *pc;
194f9f848faSopenharmony_ci	struct usb_page *pg;
195f9f848faSopenharmony_ci	void *buf;
196f9f848faSopenharmony_ci	usb_size_t n_dma_pc;
197f9f848faSopenharmony_ci	usb_size_t n_dma_pg;
198f9f848faSopenharmony_ci	usb_size_t n_obj;
199f9f848faSopenharmony_ci	usb_size_t x;
200f9f848faSopenharmony_ci	usb_size_t y;
201f9f848faSopenharmony_ci	usb_size_t r;
202f9f848faSopenharmony_ci	usb_size_t z;
203f9f848faSopenharmony_ci
204f9f848faSopenharmony_ci	USB_ASSERT(align > 0, ("Invalid alignment, 0x%08x\n",
205f9f848faSopenharmony_ci	    align));
206f9f848faSopenharmony_ci	USB_ASSERT(size > 0, ("Invalid size = 0\n"));
207f9f848faSopenharmony_ci
208f9f848faSopenharmony_ci	if (count == 0) {
209f9f848faSopenharmony_ci		return (0);		/* nothing to allocate */
210f9f848faSopenharmony_ci	}
211f9f848faSopenharmony_ci	/*
212f9f848faSopenharmony_ci	 * Make sure that the size is aligned properly.
213f9f848faSopenharmony_ci	 */
214f9f848faSopenharmony_ci	size = -((-size) & (-align));
215f9f848faSopenharmony_ci
216f9f848faSopenharmony_ci	/*
217f9f848faSopenharmony_ci	 * Try multi-allocation chunks to reduce the number of DMA
218f9f848faSopenharmony_ci	 * allocations, hence DMA allocations are slow.
219f9f848faSopenharmony_ci	 */
220f9f848faSopenharmony_ci	if (align == 1) {
221f9f848faSopenharmony_ci		/* special case - non-cached multi page DMA memory */
222f9f848faSopenharmony_ci		n_dma_pc = count;
223f9f848faSopenharmony_ci		n_dma_pg = (2 + (size / USB_PAGE_SIZE));
224f9f848faSopenharmony_ci		n_obj = 1;
225f9f848faSopenharmony_ci	} else if (size >= USB_PAGE_SIZE) {
226f9f848faSopenharmony_ci		n_dma_pc = count;
227f9f848faSopenharmony_ci		n_dma_pg = 1;
228f9f848faSopenharmony_ci		n_obj = 1;
229f9f848faSopenharmony_ci	} else {
230f9f848faSopenharmony_ci		/* compute number of objects per page */
231f9f848faSopenharmony_ci		n_obj = (USB_PAGE_SIZE / size);
232f9f848faSopenharmony_ci		/*
233f9f848faSopenharmony_ci		 * Compute number of DMA chunks, rounded up
234f9f848faSopenharmony_ci		 * to nearest one:
235f9f848faSopenharmony_ci		 */
236f9f848faSopenharmony_ci		n_dma_pc = ((count + n_obj - 1) / n_obj);
237f9f848faSopenharmony_ci		n_dma_pg = 1;
238f9f848faSopenharmony_ci	}
239f9f848faSopenharmony_ci
240f9f848faSopenharmony_ci	/*
241f9f848faSopenharmony_ci	 * DMA memory is allocated once, but mapped twice. That's why
242f9f848faSopenharmony_ci	 * there is one list for auto-free and another list for
243f9f848faSopenharmony_ci	 * non-auto-free which only holds the mapping and not the
244f9f848faSopenharmony_ci	 * allocation.
245f9f848faSopenharmony_ci	 */
246f9f848faSopenharmony_ci	if (parm->buf == NULL) {
247f9f848faSopenharmony_ci		/* reserve memory (auto-free) */
248f9f848faSopenharmony_ci		parm->dma_page_ptr += n_dma_pc * n_dma_pg;
249f9f848faSopenharmony_ci		parm->dma_page_cache_ptr += n_dma_pc;
250f9f848faSopenharmony_ci
251f9f848faSopenharmony_ci		/* reserve memory (no-auto-free) */
252f9f848faSopenharmony_ci		parm->dma_page_ptr += count * n_dma_pg;
253f9f848faSopenharmony_ci		parm->xfer_page_cache_ptr += count;
254f9f848faSopenharmony_ci		return (0);
255f9f848faSopenharmony_ci	}
256f9f848faSopenharmony_ci	for (x = 0; x != n_dma_pc; x++) {
257f9f848faSopenharmony_ci		/* need to initialize the page cache */
258f9f848faSopenharmony_ci		parm->dma_page_cache_ptr[x].tag_parent =
259f9f848faSopenharmony_ci		    &parm->curr_xfer->xroot->dma_parent_tag;
260f9f848faSopenharmony_ci	}
261f9f848faSopenharmony_ci	for (x = 0; x != count; x++) {
262f9f848faSopenharmony_ci		/* need to initialize the page cache */
263f9f848faSopenharmony_ci		parm->xfer_page_cache_ptr[x].tag_parent =
264f9f848faSopenharmony_ci		    &parm->curr_xfer->xroot->dma_parent_tag;
265f9f848faSopenharmony_ci	}
266f9f848faSopenharmony_ci
267f9f848faSopenharmony_ci	if (ppc != NULL) {
268f9f848faSopenharmony_ci		*ppc = parm->xfer_page_cache_ptr;
269f9f848faSopenharmony_ci	}
270f9f848faSopenharmony_ci	r = count;			/* set remainder count */
271f9f848faSopenharmony_ci	z = n_obj * size;		/* set allocation size */
272f9f848faSopenharmony_ci	pc = parm->xfer_page_cache_ptr;
273f9f848faSopenharmony_ci	pg = parm->dma_page_ptr;
274f9f848faSopenharmony_ci
275f9f848faSopenharmony_ci	for (x = 0; x != n_dma_pc; x++) {
276f9f848faSopenharmony_ci		if (r < n_obj) {
277f9f848faSopenharmony_ci			/* compute last remainder */
278f9f848faSopenharmony_ci			z = r * size;
279f9f848faSopenharmony_ci			n_obj = r;
280f9f848faSopenharmony_ci		}
281f9f848faSopenharmony_ci		if (usb_pc_alloc_mem(parm->dma_page_cache_ptr,
282f9f848faSopenharmony_ci		    pg, z, align)) {
283f9f848faSopenharmony_ci			return (1);	/* failure */
284f9f848faSopenharmony_ci		}
285f9f848faSopenharmony_ci		/* Set beginning of current buffer */
286f9f848faSopenharmony_ci		buf = parm->dma_page_cache_ptr->buffer;
287f9f848faSopenharmony_ci		/* Make room for one DMA page cache and one page */
288f9f848faSopenharmony_ci		parm->dma_page_cache_ptr++;
289f9f848faSopenharmony_ci		pg += n_dma_pg;
290f9f848faSopenharmony_ci
291f9f848faSopenharmony_ci		for (y = 0; (y != n_obj); y++, r--, pc++, pg += n_dma_pg) {
292f9f848faSopenharmony_ci			/* Load sub-chunk into DMA */
293f9f848faSopenharmony_ci			if (usb_pc_dmamap_create(pc, size)) {
294f9f848faSopenharmony_ci				return (1);	/* failure */
295f9f848faSopenharmony_ci			}
296f9f848faSopenharmony_ci			pc->buffer = USB_ADD_BYTES(buf, y * size);
297f9f848faSopenharmony_ci			pc->page_start = pg;
298f9f848faSopenharmony_ci
299f9f848faSopenharmony_ci			USB_MTX_LOCK(pc->tag_parent->mtx);
300f9f848faSopenharmony_ci			if (usb_pc_load_mem(pc, size, 1 /* synchronous */ )) {
301f9f848faSopenharmony_ci				USB_MTX_UNLOCK(pc->tag_parent->mtx);
302f9f848faSopenharmony_ci				return (1);	/* failure */
303f9f848faSopenharmony_ci			}
304f9f848faSopenharmony_ci			USB_MTX_UNLOCK(pc->tag_parent->mtx);
305f9f848faSopenharmony_ci		}
306f9f848faSopenharmony_ci	}
307f9f848faSopenharmony_ci
308f9f848faSopenharmony_ci	parm->xfer_page_cache_ptr = pc;
309f9f848faSopenharmony_ci	parm->dma_page_ptr = pg;
310f9f848faSopenharmony_ci	return (0);
311f9f848faSopenharmony_ci}
312f9f848faSopenharmony_ci#endif
313f9f848faSopenharmony_ci
314f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
315f9f848faSopenharmony_ci *	usbd_transfer_setup_sub - transfer setup subroutine
316f9f848faSopenharmony_ci *
317f9f848faSopenharmony_ci * This function must be called from the "xfer_setup" callback of the
318f9f848faSopenharmony_ci * USB Host or Device controller driver when setting up an USB
319f9f848faSopenharmony_ci * transfer. This function will setup correct packet sizes, buffer
320f9f848faSopenharmony_ci * sizes, flags and more, that are stored in the "usb_xfer"
321f9f848faSopenharmony_ci * structure.
322f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
323f9f848faSopenharmony_civoid
324f9f848faSopenharmony_ciusbd_transfer_setup_sub(struct usb_setup_params *parm)
325f9f848faSopenharmony_ci{
326f9f848faSopenharmony_ci	enum {
327f9f848faSopenharmony_ci		REQ_SIZE = 8,
328f9f848faSopenharmony_ci		MIN_PKT = 8,
329f9f848faSopenharmony_ci	};
330f9f848faSopenharmony_ci	struct usb_xfer *xfer = parm->curr_xfer;
331f9f848faSopenharmony_ci	const struct usb_config *setup = parm->curr_setup;
332f9f848faSopenharmony_ci	struct usb_endpoint_ss_comp_descriptor *ecomp;
333f9f848faSopenharmony_ci	struct usb_endpoint_descriptor *edesc;
334f9f848faSopenharmony_ci	struct usb_std_packet_size std_size;
335f9f848faSopenharmony_ci	usb_frcount_t n_frlengths;
336f9f848faSopenharmony_ci	usb_frcount_t n_frbuffers;
337f9f848faSopenharmony_ci	usb_frcount_t x;
338f9f848faSopenharmony_ci	uint16_t maxp_old;
339f9f848faSopenharmony_ci	uint8_t type;
340f9f848faSopenharmony_ci	uint8_t zmps;
341f9f848faSopenharmony_ci
342f9f848faSopenharmony_ci	/*
343f9f848faSopenharmony_ci	 * Sanity check. The following parameters must be initialized before
344f9f848faSopenharmony_ci	 * calling this function.
345f9f848faSopenharmony_ci	 */
346f9f848faSopenharmony_ci	if ((parm->hc_max_packet_size == 0) ||
347f9f848faSopenharmony_ci	    (parm->hc_max_packet_count == 0) ||
348f9f848faSopenharmony_ci	    (parm->hc_max_frame_size == 0)) {
349f9f848faSopenharmony_ci		parm->err = USB_ERR_INVAL;
350f9f848faSopenharmony_ci		goto done;
351f9f848faSopenharmony_ci	}
352f9f848faSopenharmony_ci	edesc = xfer->endpoint->edesc;
353f9f848faSopenharmony_ci	ecomp = xfer->endpoint->ecomp;
354f9f848faSopenharmony_ci
355f9f848faSopenharmony_ci	type = (edesc->bmAttributes & UE_XFERTYPE);
356f9f848faSopenharmony_ci
357f9f848faSopenharmony_ci	xfer->flags = setup->flags;
358f9f848faSopenharmony_ci	xfer->nframes = setup->frames;
359f9f848faSopenharmony_ci	xfer->timeout = setup->timeout;
360f9f848faSopenharmony_ci	xfer->callback = setup->callback;
361f9f848faSopenharmony_ci	xfer->interval = setup->interval;
362f9f848faSopenharmony_ci	xfer->endpointno = edesc->bEndpointAddress;
363f9f848faSopenharmony_ci	xfer->max_packet_size = UGETW(edesc->wMaxPacketSize);
364f9f848faSopenharmony_ci	xfer->max_packet_count = 1;
365f9f848faSopenharmony_ci	/* make a shadow copy: */
366f9f848faSopenharmony_ci	xfer->flags_int.usb_mode = parm->udev->flags.usb_mode;
367f9f848faSopenharmony_ci
368f9f848faSopenharmony_ci	parm->bufsize = setup->bufsize;
369f9f848faSopenharmony_ci
370f9f848faSopenharmony_ci	switch (parm->speed) {
371f9f848faSopenharmony_ci	case USB_SPEED_HIGH:
372f9f848faSopenharmony_ci		switch (type) {
373f9f848faSopenharmony_ci		case UE_ISOCHRONOUS:
374f9f848faSopenharmony_ci		case UE_INTERRUPT:
375f9f848faSopenharmony_ci			xfer->max_packet_count +=
376f9f848faSopenharmony_ci			    (xfer->max_packet_size >> 11) & 3;
377f9f848faSopenharmony_ci
378f9f848faSopenharmony_ci			/* check for invalid max packet count */
379f9f848faSopenharmony_ci			if (xfer->max_packet_count > 3)
380f9f848faSopenharmony_ci				xfer->max_packet_count = 3;
381f9f848faSopenharmony_ci			break;
382f9f848faSopenharmony_ci		default:
383f9f848faSopenharmony_ci			break;
384f9f848faSopenharmony_ci		}
385f9f848faSopenharmony_ci		xfer->max_packet_size &= 0x7FF;
386f9f848faSopenharmony_ci		break;
387f9f848faSopenharmony_ci	case USB_SPEED_SUPER:
388f9f848faSopenharmony_ci		xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3;
389f9f848faSopenharmony_ci
390f9f848faSopenharmony_ci		if (ecomp != NULL)
391f9f848faSopenharmony_ci			xfer->max_packet_count += ecomp->bMaxBurst;
392f9f848faSopenharmony_ci
393f9f848faSopenharmony_ci		if ((xfer->max_packet_count == 0) ||
394f9f848faSopenharmony_ci		    (xfer->max_packet_count > 16))
395f9f848faSopenharmony_ci			xfer->max_packet_count = 16;
396f9f848faSopenharmony_ci
397f9f848faSopenharmony_ci		switch (type) {
398f9f848faSopenharmony_ci		case UE_CONTROL:
399f9f848faSopenharmony_ci			xfer->max_packet_count = 1;
400f9f848faSopenharmony_ci			break;
401f9f848faSopenharmony_ci		case UE_ISOCHRONOUS:
402f9f848faSopenharmony_ci			if (ecomp != NULL) {
403f9f848faSopenharmony_ci				uint8_t mult;
404f9f848faSopenharmony_ci
405f9f848faSopenharmony_ci				mult = UE_GET_SS_ISO_MULT(
406f9f848faSopenharmony_ci				    ecomp->bmAttributes) + 1;
407f9f848faSopenharmony_ci				if (mult > 3)
408f9f848faSopenharmony_ci					mult = 3;
409f9f848faSopenharmony_ci
410f9f848faSopenharmony_ci				xfer->max_packet_count *= mult;
411f9f848faSopenharmony_ci			}
412f9f848faSopenharmony_ci			break;
413f9f848faSopenharmony_ci		default:
414f9f848faSopenharmony_ci			break;
415f9f848faSopenharmony_ci		}
416f9f848faSopenharmony_ci		xfer->max_packet_size &= 0x7FF;
417f9f848faSopenharmony_ci		break;
418f9f848faSopenharmony_ci	default:
419f9f848faSopenharmony_ci		break;
420f9f848faSopenharmony_ci	}
421f9f848faSopenharmony_ci	/* range check "max_packet_count" */
422f9f848faSopenharmony_ci
423f9f848faSopenharmony_ci	if (xfer->max_packet_count > parm->hc_max_packet_count) {
424f9f848faSopenharmony_ci		xfer->max_packet_count = parm->hc_max_packet_count;
425f9f848faSopenharmony_ci	}
426f9f848faSopenharmony_ci
427f9f848faSopenharmony_ci	/* store max packet size value before filtering */
428f9f848faSopenharmony_ci
429f9f848faSopenharmony_ci	maxp_old = xfer->max_packet_size;
430f9f848faSopenharmony_ci
431f9f848faSopenharmony_ci	/* filter "wMaxPacketSize" according to HC capabilities */
432f9f848faSopenharmony_ci
433f9f848faSopenharmony_ci	if ((xfer->max_packet_size > parm->hc_max_packet_size) ||
434f9f848faSopenharmony_ci	    (xfer->max_packet_size == 0)) {
435f9f848faSopenharmony_ci		xfer->max_packet_size = parm->hc_max_packet_size;
436f9f848faSopenharmony_ci	}
437f9f848faSopenharmony_ci	/* filter "wMaxPacketSize" according to standard sizes */
438f9f848faSopenharmony_ci
439f9f848faSopenharmony_ci	usbd_get_std_packet_size(&std_size, type, parm->speed);
440f9f848faSopenharmony_ci
441f9f848faSopenharmony_ci	if (std_size.range.min || std_size.range.max) {
442f9f848faSopenharmony_ci		if (xfer->max_packet_size < std_size.range.min) {
443f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.range.min;
444f9f848faSopenharmony_ci		}
445f9f848faSopenharmony_ci		if (xfer->max_packet_size > std_size.range.max) {
446f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.range.max;
447f9f848faSopenharmony_ci		}
448f9f848faSopenharmony_ci	} else {
449f9f848faSopenharmony_ci		if (xfer->max_packet_size >= std_size.fixed[3]) {
450f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.fixed[3];
451f9f848faSopenharmony_ci		} else if (xfer->max_packet_size >= std_size.fixed[2]) {
452f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.fixed[2];
453f9f848faSopenharmony_ci		} else if (xfer->max_packet_size >= std_size.fixed[1]) {
454f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.fixed[1];
455f9f848faSopenharmony_ci		} else {
456f9f848faSopenharmony_ci			/* only one possibility left */
457f9f848faSopenharmony_ci			xfer->max_packet_size = std_size.fixed[0];
458f9f848faSopenharmony_ci		}
459f9f848faSopenharmony_ci	}
460f9f848faSopenharmony_ci
461f9f848faSopenharmony_ci	/*
462f9f848faSopenharmony_ci	 * Check if the max packet size was outside its allowed range
463f9f848faSopenharmony_ci	 * and clamped to a valid value:
464f9f848faSopenharmony_ci	 */
465f9f848faSopenharmony_ci	if (maxp_old != xfer->max_packet_size)
466f9f848faSopenharmony_ci		xfer->flags_int.maxp_was_clamped = 1;
467f9f848faSopenharmony_ci
468f9f848faSopenharmony_ci	/* compute "max_frame_size" */
469f9f848faSopenharmony_ci
470f9f848faSopenharmony_ci	usbd_update_max_frame_size(xfer);
471f9f848faSopenharmony_ci
472f9f848faSopenharmony_ci	/* check interrupt interval and transfer pre-delay */
473f9f848faSopenharmony_ci
474f9f848faSopenharmony_ci	if (type == UE_ISOCHRONOUS) {
475f9f848faSopenharmony_ci		uint16_t frame_limit;
476f9f848faSopenharmony_ci
477f9f848faSopenharmony_ci		xfer->interval = 0;	/* not used, must be zero */
478f9f848faSopenharmony_ci		xfer->flags_int.isochronous_xfr = 1;	/* set flag */
479f9f848faSopenharmony_ci
480f9f848faSopenharmony_ci		if (xfer->timeout == 0) {
481f9f848faSopenharmony_ci			/*
482f9f848faSopenharmony_ci			 * set a default timeout in
483f9f848faSopenharmony_ci			 * case something goes wrong!
484f9f848faSopenharmony_ci			 */
485f9f848faSopenharmony_ci			xfer->timeout = 1000 / 4;
486f9f848faSopenharmony_ci		}
487f9f848faSopenharmony_ci		switch (parm->speed) {
488f9f848faSopenharmony_ci		case USB_SPEED_LOW:
489f9f848faSopenharmony_ci		case USB_SPEED_FULL:
490f9f848faSopenharmony_ci			frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER;
491f9f848faSopenharmony_ci			xfer->fps_shift = 0;
492f9f848faSopenharmony_ci			break;
493f9f848faSopenharmony_ci		default:
494f9f848faSopenharmony_ci			frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER;
495f9f848faSopenharmony_ci			xfer->fps_shift = edesc->bInterval;
496f9f848faSopenharmony_ci			if (xfer->fps_shift > 0)
497f9f848faSopenharmony_ci				xfer->fps_shift--;
498f9f848faSopenharmony_ci			if (xfer->fps_shift > 3)
499f9f848faSopenharmony_ci				xfer->fps_shift = 3;
500f9f848faSopenharmony_ci			if (xfer->flags.pre_scale_frames != 0)
501f9f848faSopenharmony_ci				xfer->nframes <<= (3 - xfer->fps_shift);
502f9f848faSopenharmony_ci			break;
503f9f848faSopenharmony_ci		}
504f9f848faSopenharmony_ci
505f9f848faSopenharmony_ci		if (xfer->nframes > frame_limit) {
506f9f848faSopenharmony_ci			/*
507f9f848faSopenharmony_ci			 * this is not going to work
508f9f848faSopenharmony_ci			 * cross hardware
509f9f848faSopenharmony_ci			 */
510f9f848faSopenharmony_ci			parm->err = USB_ERR_INVAL;
511f9f848faSopenharmony_ci			goto done;
512f9f848faSopenharmony_ci		}
513f9f848faSopenharmony_ci		if (xfer->nframes == 0) {
514f9f848faSopenharmony_ci			/*
515f9f848faSopenharmony_ci			 * this is not a valid value
516f9f848faSopenharmony_ci			 */
517f9f848faSopenharmony_ci			parm->err = USB_ERR_ZERO_NFRAMES;
518f9f848faSopenharmony_ci			goto done;
519f9f848faSopenharmony_ci		}
520f9f848faSopenharmony_ci	} else {
521f9f848faSopenharmony_ci		/*
522f9f848faSopenharmony_ci		 * If a value is specified use that else check the
523f9f848faSopenharmony_ci		 * endpoint descriptor!
524f9f848faSopenharmony_ci		 */
525f9f848faSopenharmony_ci		if (type == UE_INTERRUPT) {
526f9f848faSopenharmony_ci			uint32_t temp;
527f9f848faSopenharmony_ci
528f9f848faSopenharmony_ci			if (xfer->interval == 0) {
529f9f848faSopenharmony_ci				xfer->interval = edesc->bInterval;
530f9f848faSopenharmony_ci
531f9f848faSopenharmony_ci				switch (parm->speed) {
532f9f848faSopenharmony_ci				case USB_SPEED_LOW:
533f9f848faSopenharmony_ci				case USB_SPEED_FULL:
534f9f848faSopenharmony_ci					break;
535f9f848faSopenharmony_ci				default:
536f9f848faSopenharmony_ci					/* 125us -> 1ms */
537f9f848faSopenharmony_ci					if (xfer->interval < 4)
538f9f848faSopenharmony_ci						xfer->interval = 1;
539f9f848faSopenharmony_ci					else if (xfer->interval > 16)
540f9f848faSopenharmony_ci						xfer->interval = (1 << (16 - 4));
541f9f848faSopenharmony_ci					else
542f9f848faSopenharmony_ci						xfer->interval =
543f9f848faSopenharmony_ci						    (1 << (xfer->interval - 4));
544f9f848faSopenharmony_ci					break;
545f9f848faSopenharmony_ci				}
546f9f848faSopenharmony_ci			}
547f9f848faSopenharmony_ci
548f9f848faSopenharmony_ci			if (xfer->interval == 0) {
549f9f848faSopenharmony_ci				/*
550f9f848faSopenharmony_ci				 * One millisecond is the smallest
551f9f848faSopenharmony_ci				 * interval we support:
552f9f848faSopenharmony_ci				 */
553f9f848faSopenharmony_ci				xfer->interval = 1;
554f9f848faSopenharmony_ci			}
555f9f848faSopenharmony_ci
556f9f848faSopenharmony_ci			xfer->fps_shift = 0;
557f9f848faSopenharmony_ci			temp = 1;
558f9f848faSopenharmony_ci
559f9f848faSopenharmony_ci			while ((temp != 0) && (temp < xfer->interval)) {
560f9f848faSopenharmony_ci				xfer->fps_shift++;
561f9f848faSopenharmony_ci				temp *= 2;
562f9f848faSopenharmony_ci			}
563f9f848faSopenharmony_ci
564f9f848faSopenharmony_ci			switch (parm->speed) {
565f9f848faSopenharmony_ci			case USB_SPEED_LOW:
566f9f848faSopenharmony_ci			case USB_SPEED_FULL:
567f9f848faSopenharmony_ci				break;
568f9f848faSopenharmony_ci			default:
569f9f848faSopenharmony_ci				xfer->fps_shift += 3;
570f9f848faSopenharmony_ci				break;
571f9f848faSopenharmony_ci			}
572f9f848faSopenharmony_ci		}
573f9f848faSopenharmony_ci	}
574f9f848faSopenharmony_ci
575f9f848faSopenharmony_ci	/*
576f9f848faSopenharmony_ci	 * NOTE: we do not allow "max_packet_size" or "max_frame_size"
577f9f848faSopenharmony_ci	 * to be equal to zero when setting up USB transfers, hence
578f9f848faSopenharmony_ci	 * this leads to alot of extra code in the USB kernel.
579f9f848faSopenharmony_ci	 */
580f9f848faSopenharmony_ci
581f9f848faSopenharmony_ci	if ((xfer->max_frame_size == 0) ||
582f9f848faSopenharmony_ci	    (xfer->max_packet_size == 0)) {
583f9f848faSopenharmony_ci		zmps = 1;
584f9f848faSopenharmony_ci
585f9f848faSopenharmony_ci		if ((parm->bufsize <= MIN_PKT) &&
586f9f848faSopenharmony_ci		    (type != UE_CONTROL) &&
587f9f848faSopenharmony_ci		    (type != UE_BULK)) {
588f9f848faSopenharmony_ci			/* workaround */
589f9f848faSopenharmony_ci			xfer->max_packet_size = MIN_PKT;
590f9f848faSopenharmony_ci			xfer->max_packet_count = 1;
591f9f848faSopenharmony_ci			parm->bufsize = 0;	/* automatic setup length */
592f9f848faSopenharmony_ci			usbd_update_max_frame_size(xfer);
593f9f848faSopenharmony_ci
594f9f848faSopenharmony_ci		} else {
595f9f848faSopenharmony_ci			parm->err = USB_ERR_ZERO_MAXP;
596f9f848faSopenharmony_ci			goto done;
597f9f848faSopenharmony_ci		}
598f9f848faSopenharmony_ci
599f9f848faSopenharmony_ci	} else {
600f9f848faSopenharmony_ci		zmps = 0;
601f9f848faSopenharmony_ci	}
602f9f848faSopenharmony_ci
603f9f848faSopenharmony_ci	/*
604f9f848faSopenharmony_ci	 * check if we should setup a default
605f9f848faSopenharmony_ci	 * length:
606f9f848faSopenharmony_ci	 */
607f9f848faSopenharmony_ci
608f9f848faSopenharmony_ci	if (parm->bufsize == 0) {
609f9f848faSopenharmony_ci		parm->bufsize = xfer->max_frame_size;
610f9f848faSopenharmony_ci
611f9f848faSopenharmony_ci		if (type == UE_ISOCHRONOUS) {
612f9f848faSopenharmony_ci			parm->bufsize *= xfer->nframes;
613f9f848faSopenharmony_ci		}
614f9f848faSopenharmony_ci	}
615f9f848faSopenharmony_ci	/*
616f9f848faSopenharmony_ci	 * check if we are about to setup a proxy
617f9f848faSopenharmony_ci	 * type of buffer:
618f9f848faSopenharmony_ci	 */
619f9f848faSopenharmony_ci
620f9f848faSopenharmony_ci	if (xfer->flags.proxy_buffer) {
621f9f848faSopenharmony_ci		/* round bufsize up */
622f9f848faSopenharmony_ci
623f9f848faSopenharmony_ci		parm->bufsize += (xfer->max_frame_size - 1);
624f9f848faSopenharmony_ci
625f9f848faSopenharmony_ci		if (parm->bufsize < xfer->max_frame_size) {
626f9f848faSopenharmony_ci			/* length wrapped around */
627f9f848faSopenharmony_ci			parm->err = USB_ERR_INVAL;
628f9f848faSopenharmony_ci			goto done;
629f9f848faSopenharmony_ci		}
630f9f848faSopenharmony_ci		/* subtract remainder */
631f9f848faSopenharmony_ci
632f9f848faSopenharmony_ci		parm->bufsize -= (parm->bufsize % xfer->max_frame_size);
633f9f848faSopenharmony_ci
634f9f848faSopenharmony_ci		/* add length of USB device request structure, if any */
635f9f848faSopenharmony_ci
636f9f848faSopenharmony_ci		if (type == UE_CONTROL) {
637f9f848faSopenharmony_ci			parm->bufsize += REQ_SIZE;	/* SETUP message */
638f9f848faSopenharmony_ci		}
639f9f848faSopenharmony_ci	}
640f9f848faSopenharmony_ci	xfer->max_data_length = parm->bufsize;
641f9f848faSopenharmony_ci
642f9f848faSopenharmony_ci	/* Setup "n_frlengths" and "n_frbuffers" */
643f9f848faSopenharmony_ci
644f9f848faSopenharmony_ci	if (type == UE_ISOCHRONOUS) {
645f9f848faSopenharmony_ci		n_frlengths = xfer->nframes;
646f9f848faSopenharmony_ci		n_frbuffers = 1;
647f9f848faSopenharmony_ci	} else {
648f9f848faSopenharmony_ci		if (type == UE_CONTROL) {
649f9f848faSopenharmony_ci			xfer->flags_int.control_xfr = 1;
650f9f848faSopenharmony_ci			if (xfer->nframes == 0) {
651f9f848faSopenharmony_ci				if (parm->bufsize <= REQ_SIZE) {
652f9f848faSopenharmony_ci					/*
653f9f848faSopenharmony_ci					 * there will never be any data
654f9f848faSopenharmony_ci					 * stage
655f9f848faSopenharmony_ci					 */
656f9f848faSopenharmony_ci					xfer->nframes = 1;
657f9f848faSopenharmony_ci				} else {
658f9f848faSopenharmony_ci					xfer->nframes = 2;
659f9f848faSopenharmony_ci				}
660f9f848faSopenharmony_ci			}
661f9f848faSopenharmony_ci		} else {
662f9f848faSopenharmony_ci			if (xfer->nframes == 0) {
663f9f848faSopenharmony_ci				xfer->nframes = 1;
664f9f848faSopenharmony_ci			}
665f9f848faSopenharmony_ci		}
666f9f848faSopenharmony_ci
667f9f848faSopenharmony_ci		n_frlengths = xfer->nframes;
668f9f848faSopenharmony_ci		n_frbuffers = xfer->nframes;
669f9f848faSopenharmony_ci	}
670f9f848faSopenharmony_ci
671f9f848faSopenharmony_ci	/*
672f9f848faSopenharmony_ci	 * check if we have room for the
673f9f848faSopenharmony_ci	 * USB device request structure:
674f9f848faSopenharmony_ci	 */
675f9f848faSopenharmony_ci
676f9f848faSopenharmony_ci	if (type == UE_CONTROL) {
677f9f848faSopenharmony_ci		if (xfer->max_data_length < REQ_SIZE) {
678f9f848faSopenharmony_ci			/* length wrapped around or too small bufsize */
679f9f848faSopenharmony_ci			parm->err = USB_ERR_INVAL;
680f9f848faSopenharmony_ci			goto done;
681f9f848faSopenharmony_ci		}
682f9f848faSopenharmony_ci		xfer->max_data_length -= REQ_SIZE;
683f9f848faSopenharmony_ci	}
684f9f848faSopenharmony_ci	/*
685f9f848faSopenharmony_ci	 * Setup "frlengths" and shadow "frlengths" for keeping the
686f9f848faSopenharmony_ci	 * initial frame lengths when a USB transfer is complete. This
687f9f848faSopenharmony_ci	 * information is useful when computing isochronous offsets.
688f9f848faSopenharmony_ci	 */
689f9f848faSopenharmony_ci	xfer->frlengths = parm->xfer_length_ptr;
690f9f848faSopenharmony_ci	parm->xfer_length_ptr += 2 * n_frlengths;
691f9f848faSopenharmony_ci
692f9f848faSopenharmony_ci	/* setup "frbuffers" */
693f9f848faSopenharmony_ci	xfer->frbuffers = parm->xfer_page_cache_ptr;
694f9f848faSopenharmony_ci	parm->xfer_page_cache_ptr += n_frbuffers;
695f9f848faSopenharmony_ci
696f9f848faSopenharmony_ci	/* initialize max frame count */
697f9f848faSopenharmony_ci	xfer->max_frame_count = xfer->nframes;
698f9f848faSopenharmony_ci
699f9f848faSopenharmony_ci	/*
700f9f848faSopenharmony_ci	 * check if we need to setup
701f9f848faSopenharmony_ci	 * a local buffer:
702f9f848faSopenharmony_ci	 */
703f9f848faSopenharmony_ci
704f9f848faSopenharmony_ci	if (!xfer->flags.ext_buffer) {
705f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
706f9f848faSopenharmony_ci		struct usb_page_search page_info;
707f9f848faSopenharmony_ci		struct usb_page_cache *pc;
708f9f848faSopenharmony_ci
709f9f848faSopenharmony_ci		if (usbd_transfer_setup_sub_malloc(parm,
710f9f848faSopenharmony_ci		    &pc, parm->bufsize, 1, 1)) {
711f9f848faSopenharmony_ci			parm->err = USB_ERR_NOMEM;
712f9f848faSopenharmony_ci		} else if (parm->buf != NULL) {
713f9f848faSopenharmony_ci			usbd_get_page(pc, 0, &page_info);
714f9f848faSopenharmony_ci
715f9f848faSopenharmony_ci			xfer->local_buffer = page_info.buffer;
716f9f848faSopenharmony_ci
717f9f848faSopenharmony_ci			usbd_xfer_set_frame_offset(xfer, 0, 0);
718f9f848faSopenharmony_ci
719f9f848faSopenharmony_ci			if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
720f9f848faSopenharmony_ci				usbd_xfer_set_frame_offset(xfer, REQ_SIZE, 1);
721f9f848faSopenharmony_ci			}
722f9f848faSopenharmony_ci		}
723f9f848faSopenharmony_ci#else
724f9f848faSopenharmony_ci		/* align data */
725f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
726f9f848faSopenharmony_ci
727f9f848faSopenharmony_ci		if (parm->buf != NULL) {
728f9f848faSopenharmony_ci			xfer->local_buffer =
729f9f848faSopenharmony_ci			    USB_ADD_BYTES(parm->buf, parm->size[0]);
730f9f848faSopenharmony_ci
731f9f848faSopenharmony_ci			usbd_xfer_set_frame_offset(xfer, 0, 0);
732f9f848faSopenharmony_ci
733f9f848faSopenharmony_ci			if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
734f9f848faSopenharmony_ci				usbd_xfer_set_frame_offset(xfer, REQ_SIZE, 1);
735f9f848faSopenharmony_ci			}
736f9f848faSopenharmony_ci		}
737f9f848faSopenharmony_ci		parm->size[0] += parm->bufsize;
738f9f848faSopenharmony_ci
739f9f848faSopenharmony_ci		/* align data again */
740f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
741f9f848faSopenharmony_ci#endif
742f9f848faSopenharmony_ci	}
743f9f848faSopenharmony_ci	/*
744f9f848faSopenharmony_ci	 * Compute maximum buffer size
745f9f848faSopenharmony_ci	 */
746f9f848faSopenharmony_ci
747f9f848faSopenharmony_ci	if (parm->bufsize_max < parm->bufsize) {
748f9f848faSopenharmony_ci		parm->bufsize_max = parm->bufsize;
749f9f848faSopenharmony_ci	}
750f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
751f9f848faSopenharmony_ci	if (xfer->flags_int.bdma_enable) {
752f9f848faSopenharmony_ci		/*
753f9f848faSopenharmony_ci		 * Setup "dma_page_ptr".
754f9f848faSopenharmony_ci		 *
755f9f848faSopenharmony_ci		 * Proof for formula below:
756f9f848faSopenharmony_ci		 *
757f9f848faSopenharmony_ci		 * Assume there are three USB frames having length "a", "b" and
758f9f848faSopenharmony_ci		 * "c". These USB frames will at maximum need "z"
759f9f848faSopenharmony_ci		 * "usb_page" structures. "z" is given by:
760f9f848faSopenharmony_ci		 *
761f9f848faSopenharmony_ci		 * z = ((a / USB_PAGE_SIZE) + 2) + ((b / USB_PAGE_SIZE) + 2) +
762f9f848faSopenharmony_ci		 * ((c / USB_PAGE_SIZE) + 2);
763f9f848faSopenharmony_ci		 *
764f9f848faSopenharmony_ci		 * Constraining "a", "b" and "c" like this:
765f9f848faSopenharmony_ci		 *
766f9f848faSopenharmony_ci		 * (a + b + c) <= parm->bufsize
767f9f848faSopenharmony_ci		 *
768f9f848faSopenharmony_ci		 * We know that:
769f9f848faSopenharmony_ci		 *
770f9f848faSopenharmony_ci		 * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
771f9f848faSopenharmony_ci		 *
772f9f848faSopenharmony_ci		 * Here is the general formula:
773f9f848faSopenharmony_ci		 */
774f9f848faSopenharmony_ci		xfer->dma_page_ptr = parm->dma_page_ptr;
775f9f848faSopenharmony_ci		parm->dma_page_ptr += (2 * n_frbuffers);
776f9f848faSopenharmony_ci		parm->dma_page_ptr += (parm->bufsize / USB_PAGE_SIZE);
777f9f848faSopenharmony_ci	}
778f9f848faSopenharmony_ci#endif
779f9f848faSopenharmony_ci	if (zmps) {
780f9f848faSopenharmony_ci		/* correct maximum data length */
781f9f848faSopenharmony_ci		xfer->max_data_length = 0;
782f9f848faSopenharmony_ci	}
783f9f848faSopenharmony_ci	/* subtract USB frame remainder from "hc_max_frame_size" */
784f9f848faSopenharmony_ci
785f9f848faSopenharmony_ci	xfer->max_hc_frame_size =
786f9f848faSopenharmony_ci	    (parm->hc_max_frame_size -
787f9f848faSopenharmony_ci	    (parm->hc_max_frame_size % xfer->max_frame_size));
788f9f848faSopenharmony_ci
789f9f848faSopenharmony_ci	if (xfer->max_hc_frame_size == 0) {
790f9f848faSopenharmony_ci		parm->err = USB_ERR_INVAL;
791f9f848faSopenharmony_ci		goto done;
792f9f848faSopenharmony_ci	}
793f9f848faSopenharmony_ci
794f9f848faSopenharmony_ci	/* initialize frame buffers */
795f9f848faSopenharmony_ci
796f9f848faSopenharmony_ci	if (parm->buf) {
797f9f848faSopenharmony_ci		for (x = 0; x != n_frbuffers; x++) {
798f9f848faSopenharmony_ci			xfer->frbuffers[x].tag_parent =
799f9f848faSopenharmony_ci			    &xfer->xroot->dma_parent_tag;
800f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
801f9f848faSopenharmony_ci			if (xfer->flags_int.bdma_enable &&
802f9f848faSopenharmony_ci			    (parm->bufsize_max > 0)) {
803f9f848faSopenharmony_ci				if (usb_pc_dmamap_create(
804f9f848faSopenharmony_ci				    xfer->frbuffers + x,
805f9f848faSopenharmony_ci				    parm->bufsize_max)) {
806f9f848faSopenharmony_ci					parm->err = USB_ERR_NOMEM;
807f9f848faSopenharmony_ci					goto done;
808f9f848faSopenharmony_ci				}
809f9f848faSopenharmony_ci			}
810f9f848faSopenharmony_ci#endif
811f9f848faSopenharmony_ci		}
812f9f848faSopenharmony_ci	}
813f9f848faSopenharmony_cidone:
814f9f848faSopenharmony_ci	if (parm->err) {
815f9f848faSopenharmony_ci		/*
816f9f848faSopenharmony_ci		 * Set some dummy values so that we avoid division by zero:
817f9f848faSopenharmony_ci		 */
818f9f848faSopenharmony_ci		xfer->max_hc_frame_size = 1;
819f9f848faSopenharmony_ci		xfer->max_frame_size = 1;
820f9f848faSopenharmony_ci		xfer->max_packet_size = 1;
821f9f848faSopenharmony_ci		xfer->max_data_length = 0;
822f9f848faSopenharmony_ci		xfer->nframes = 0;
823f9f848faSopenharmony_ci		xfer->max_frame_count = 0;
824f9f848faSopenharmony_ci	}
825f9f848faSopenharmony_ci}
826f9f848faSopenharmony_ci
827f9f848faSopenharmony_cistatic uint8_t
828f9f848faSopenharmony_ciusbd_transfer_setup_has_bulk(const struct usb_config *setup_start,
829f9f848faSopenharmony_ci    uint16_t n_setup)
830f9f848faSopenharmony_ci{
831f9f848faSopenharmony_ci	uint8_t type;
832f9f848faSopenharmony_ci
833f9f848faSopenharmony_ci	while (n_setup--) {
834f9f848faSopenharmony_ci		type = setup_start[n_setup].type;
835f9f848faSopenharmony_ci		if ((type == UE_BULK) || (type == UE_BULK_INTR) ||
836f9f848faSopenharmony_ci		    (type == UE_TYPE_ANY))
837f9f848faSopenharmony_ci			return (1);
838f9f848faSopenharmony_ci	}
839f9f848faSopenharmony_ci	return (0);
840f9f848faSopenharmony_ci}
841f9f848faSopenharmony_ci
842f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
843f9f848faSopenharmony_ci *	usbd_transfer_setup - setup an array of USB transfers
844f9f848faSopenharmony_ci *
845f9f848faSopenharmony_ci * NOTE: You must always call "usbd_transfer_unsetup" after calling
846f9f848faSopenharmony_ci * "usbd_transfer_setup" if success was returned.
847f9f848faSopenharmony_ci *
848f9f848faSopenharmony_ci * The idea is that the USB device driver should pre-allocate all its
849f9f848faSopenharmony_ci * transfers by one call to this function.
850f9f848faSopenharmony_ci *
851f9f848faSopenharmony_ci * Return values:
852f9f848faSopenharmony_ci *    0: Success
853f9f848faSopenharmony_ci * Else: Failure
854f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
855f9f848faSopenharmony_ciusb_error_t
856f9f848faSopenharmony_ciusbd_transfer_setup(struct usb_device *udev,
857f9f848faSopenharmony_ci    const uint8_t *ifaces, struct usb_xfer **ppxfer,
858f9f848faSopenharmony_ci    const struct usb_config *setup_start, uint16_t n_setup,
859f9f848faSopenharmony_ci    void *priv_sc, struct mtx *xfer_mtx)
860f9f848faSopenharmony_ci{
861f9f848faSopenharmony_ci	const struct usb_config *setup_end = setup_start + n_setup;
862f9f848faSopenharmony_ci	const struct usb_config *setup;
863f9f848faSopenharmony_ci	struct usb_setup_params *parm;
864f9f848faSopenharmony_ci	struct usb_endpoint *ep;
865f9f848faSopenharmony_ci	struct usb_xfer_root *info;
866f9f848faSopenharmony_ci	struct usb_xfer *xfer;
867f9f848faSopenharmony_ci	void *buf = NULL;
868f9f848faSopenharmony_ci	usb_error_t error = USB_ERR_NORMAL_COMPLETION;
869f9f848faSopenharmony_ci	uint16_t n;
870f9f848faSopenharmony_ci	uint16_t refcount;
871f9f848faSopenharmony_ci	uint8_t do_unlock;
872f9f848faSopenharmony_ci
873f9f848faSopenharmony_ci	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
874f9f848faSopenharmony_ci	    "usbd_transfer_setup can sleep!");
875f9f848faSopenharmony_ci
876f9f848faSopenharmony_ci	/* do some checking first */
877f9f848faSopenharmony_ci
878f9f848faSopenharmony_ci	if (n_setup == 0) {
879f9f848faSopenharmony_ci		DPRINTFN(5, "setup array has zero length!\n");
880f9f848faSopenharmony_ci		return (USB_ERR_INVAL);
881f9f848faSopenharmony_ci	}
882f9f848faSopenharmony_ci	if (ifaces == 0) {
883f9f848faSopenharmony_ci		DPRINTFN(5, "ifaces array is NULL!\n");
884f9f848faSopenharmony_ci		return (USB_ERR_INVAL);
885f9f848faSopenharmony_ci	}
886f9f848faSopenharmony_ci	if (xfer_mtx == NULL) {
887f9f848faSopenharmony_ci		DPRINTFN(5, "using global lock\n");
888f9f848faSopenharmony_ci		xfer_mtx = &Giant;
889f9f848faSopenharmony_ci	}
890f9f848faSopenharmony_ci
891f9f848faSopenharmony_ci	/* more sanity checks */
892f9f848faSopenharmony_ci
893f9f848faSopenharmony_ci	for (setup = setup_start, n = 0;
894f9f848faSopenharmony_ci	    setup != setup_end; setup++, n++) {
895f9f848faSopenharmony_ci		if (setup->bufsize == (usb_frlength_t)-1) {
896f9f848faSopenharmony_ci			error = USB_ERR_BAD_BUFSIZE;
897f9f848faSopenharmony_ci			DPRINTF("invalid bufsize\n");
898f9f848faSopenharmony_ci		}
899f9f848faSopenharmony_ci		if (setup->callback == NULL) {
900f9f848faSopenharmony_ci			error = USB_ERR_NO_CALLBACK;
901f9f848faSopenharmony_ci			DPRINTF("no callback\n");
902f9f848faSopenharmony_ci		}
903f9f848faSopenharmony_ci		ppxfer[n] = NULL;
904f9f848faSopenharmony_ci	}
905f9f848faSopenharmony_ci
906f9f848faSopenharmony_ci	if (error)
907f9f848faSopenharmony_ci		return (error);
908f9f848faSopenharmony_ci
909f9f848faSopenharmony_ci	/* Protect scratch area */
910f9f848faSopenharmony_ci	do_unlock = usbd_ctrl_lock(udev);
911f9f848faSopenharmony_ci
912f9f848faSopenharmony_ci	refcount = 0;
913f9f848faSopenharmony_ci	info = NULL;
914f9f848faSopenharmony_ci
915f9f848faSopenharmony_ci	parm = &udev->scratch.xfer_setup[0].parm;
916f9f848faSopenharmony_ci	(void)memset_s(parm, sizeof(*parm), 0, sizeof(*parm));
917f9f848faSopenharmony_ci
918f9f848faSopenharmony_ci	parm->udev = udev;
919f9f848faSopenharmony_ci	parm->speed = usbd_get_speed(udev);
920f9f848faSopenharmony_ci	parm->hc_max_packet_count = 1;
921f9f848faSopenharmony_ci
922f9f848faSopenharmony_ci	if (parm->speed >= USB_SPEED_MAX) {
923f9f848faSopenharmony_ci		parm->err = USB_ERR_INVAL;
924f9f848faSopenharmony_ci		goto done;
925f9f848faSopenharmony_ci	}
926f9f848faSopenharmony_ci	/* setup all transfers */
927f9f848faSopenharmony_ci
928f9f848faSopenharmony_ci	while (1) {
929f9f848faSopenharmony_ci		if (buf) {
930f9f848faSopenharmony_ci			/*
931f9f848faSopenharmony_ci			 * Initialize the "usb_xfer_root" structure,
932f9f848faSopenharmony_ci			 * which is common for all our USB transfers.
933f9f848faSopenharmony_ci			 */
934f9f848faSopenharmony_ci			info = USB_ADD_BYTES(buf, 0);
935f9f848faSopenharmony_ci
936f9f848faSopenharmony_ci			info->memory_base = buf;
937f9f848faSopenharmony_ci			info->memory_size = parm->size[0];
938f9f848faSopenharmony_ci
939f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
940f9f848faSopenharmony_ci			info->dma_page_cache_start = USB_ADD_BYTES(buf, parm->size[4]);
941f9f848faSopenharmony_ci			info->dma_page_cache_end = USB_ADD_BYTES(buf, parm->size[5]);
942f9f848faSopenharmony_ci#endif
943f9f848faSopenharmony_ci			info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm->size[5]);
944f9f848faSopenharmony_ci			info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm->size[2]);
945f9f848faSopenharmony_ci
946f9f848faSopenharmony_ci			cv_init(&info->cv_drain, "WDRAIN");
947f9f848faSopenharmony_ci
948f9f848faSopenharmony_ci			info->xfer_mtx = xfer_mtx;
949f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
950f9f848faSopenharmony_ci			usb_dma_tag_setup(&info->dma_parent_tag,
951f9f848faSopenharmony_ci			    parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
952f9f848faSopenharmony_ci			    xfer_mtx, &usb_bdma_done_event, udev->bus->dma_bits, parm->dma_tag_max);
953f9f848faSopenharmony_ci#endif
954f9f848faSopenharmony_ci
955f9f848faSopenharmony_ci			info->bus = udev->bus;
956f9f848faSopenharmony_ci			info->udev = udev;
957f9f848faSopenharmony_ci
958f9f848faSopenharmony_ci			TAILQ_INIT(&info->done_q.head);
959f9f848faSopenharmony_ci			info->done_q.command = &usbd_callback_wrapper;
960f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
961f9f848faSopenharmony_ci			TAILQ_INIT(&info->dma_q.head);
962f9f848faSopenharmony_ci			info->dma_q.command = &usb_bdma_work_loop;
963f9f848faSopenharmony_ci#endif
964f9f848faSopenharmony_ci			info->done_m[0].hdr.pm_callback = &usb_callback_proc;
965f9f848faSopenharmony_ci			info->done_m[0].xroot = info;
966f9f848faSopenharmony_ci			info->done_m[1].hdr.pm_callback = &usb_callback_proc;
967f9f848faSopenharmony_ci			info->done_m[1].xroot = info;
968f9f848faSopenharmony_ci
969f9f848faSopenharmony_ci			/*
970f9f848faSopenharmony_ci			 * In device side mode control endpoint
971f9f848faSopenharmony_ci			 * requests need to run from a separate
972f9f848faSopenharmony_ci			 * context, else there is a chance of
973f9f848faSopenharmony_ci			 * deadlock!
974f9f848faSopenharmony_ci			 */
975f9f848faSopenharmony_ci			if (setup_start == usb_control_ep_cfg ||
976f9f848faSopenharmony_ci			    setup_start == usb_control_ep_quirk_cfg)
977f9f848faSopenharmony_ci				info->done_p =
978f9f848faSopenharmony_ci				    USB_BUS_CONTROL_XFER_PROC(udev->bus);
979f9f848faSopenharmony_ci			else if (xfer_mtx == &Giant)
980f9f848faSopenharmony_ci				info->done_p =
981f9f848faSopenharmony_ci				    USB_BUS_GIANT_PROC(udev->bus);
982f9f848faSopenharmony_ci			else if (usbd_transfer_setup_has_bulk(setup_start, n_setup))
983f9f848faSopenharmony_ci				info->done_p =
984f9f848faSopenharmony_ci				    USB_BUS_NON_GIANT_BULK_PROC(udev->bus);
985f9f848faSopenharmony_ci			else
986f9f848faSopenharmony_ci				info->done_p =
987f9f848faSopenharmony_ci				    USB_BUS_NON_GIANT_ISOC_PROC(udev->bus);
988f9f848faSopenharmony_ci		}
989f9f848faSopenharmony_ci		/* reset sizes */
990f9f848faSopenharmony_ci
991f9f848faSopenharmony_ci		parm->size[0] = 0;
992f9f848faSopenharmony_ci		parm->buf = buf;
993f9f848faSopenharmony_ci		parm->size[0] += sizeof(info[0]);
994f9f848faSopenharmony_ci
995f9f848faSopenharmony_ci		for (setup = setup_start, n = 0;
996f9f848faSopenharmony_ci		    setup != setup_end; setup++, n++) {
997f9f848faSopenharmony_ci			/* skip USB transfers without callbacks: */
998f9f848faSopenharmony_ci			if (setup->callback == NULL) {
999f9f848faSopenharmony_ci				continue;
1000f9f848faSopenharmony_ci			}
1001f9f848faSopenharmony_ci			/* see if there is a matching endpoint */
1002f9f848faSopenharmony_ci			ep = usbd_get_endpoint(udev,
1003f9f848faSopenharmony_ci			    ifaces[setup->if_index], setup);
1004f9f848faSopenharmony_ci
1005f9f848faSopenharmony_ci			/*
1006f9f848faSopenharmony_ci			 * Check that the USB PIPE is valid and that
1007f9f848faSopenharmony_ci			 * the endpoint mode is proper.
1008f9f848faSopenharmony_ci			 *
1009f9f848faSopenharmony_ci			 * Make sure we don't allocate a streams
1010f9f848faSopenharmony_ci			 * transfer when such a combination is not
1011f9f848faSopenharmony_ci			 * valid.
1012f9f848faSopenharmony_ci			 */
1013f9f848faSopenharmony_ci			if ((ep == NULL) || (ep->methods == NULL) ||
1014f9f848faSopenharmony_ci			    ((ep->ep_mode != USB_EP_MODE_STREAMS) &&
1015f9f848faSopenharmony_ci			    (ep->ep_mode != USB_EP_MODE_DEFAULT)) ||
1016f9f848faSopenharmony_ci			    ((setup->stream_id != 0) &&
1017f9f848faSopenharmony_ci			    ((setup->stream_id >= USB_MAX_EP_STREAMS) ||
1018f9f848faSopenharmony_ci			    (ep->ep_mode != USB_EP_MODE_STREAMS)))) {
1019f9f848faSopenharmony_ci				if (setup->flags.no_pipe_ok)
1020f9f848faSopenharmony_ci					continue;
1021f9f848faSopenharmony_ci				if ((setup->usb_mode != USB_MODE_DUAL) &&
1022f9f848faSopenharmony_ci				    (setup->usb_mode != udev->flags.usb_mode))
1023f9f848faSopenharmony_ci					continue;
1024f9f848faSopenharmony_ci				parm->err = USB_ERR_NO_PIPE;
1025f9f848faSopenharmony_ci				goto done;
1026f9f848faSopenharmony_ci			}
1027f9f848faSopenharmony_ci
1028f9f848faSopenharmony_ci			/* align data properly */
1029f9f848faSopenharmony_ci			parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1030f9f848faSopenharmony_ci
1031f9f848faSopenharmony_ci			/* store current setup pointer */
1032f9f848faSopenharmony_ci			parm->curr_setup = setup;
1033f9f848faSopenharmony_ci
1034f9f848faSopenharmony_ci			if (buf) {
1035f9f848faSopenharmony_ci				/*
1036f9f848faSopenharmony_ci				 * Common initialization of the
1037f9f848faSopenharmony_ci				 * "usb_xfer" structure.
1038f9f848faSopenharmony_ci				 */
1039f9f848faSopenharmony_ci				xfer = USB_ADD_BYTES(buf, parm->size[0]);
1040f9f848faSopenharmony_ci				xfer->address = udev->address;
1041f9f848faSopenharmony_ci				xfer->priv_sc = priv_sc;
1042f9f848faSopenharmony_ci				xfer->xroot = info;
1043f9f848faSopenharmony_ci
1044f9f848faSopenharmony_ci				usb_callout_init_mtx(&xfer->timeout_handle,
1045f9f848faSopenharmony_ci				    &udev->bus->bus_mtx, 0);
1046f9f848faSopenharmony_ci			} else {
1047f9f848faSopenharmony_ci				/*
1048f9f848faSopenharmony_ci				 * Setup a dummy xfer, hence we are
1049f9f848faSopenharmony_ci				 * writing to the "usb_xfer"
1050f9f848faSopenharmony_ci				 * structure pointed to by "xfer"
1051f9f848faSopenharmony_ci				 * before we have allocated any
1052f9f848faSopenharmony_ci				 * memory:
1053f9f848faSopenharmony_ci				 */
1054f9f848faSopenharmony_ci				xfer = &udev->scratch.xfer_setup[0].dummy;
1055f9f848faSopenharmony_ci				(void)memset_s(xfer, sizeof(*xfer), 0, sizeof(*xfer));
1056f9f848faSopenharmony_ci				refcount++;
1057f9f848faSopenharmony_ci			}
1058f9f848faSopenharmony_ci
1059f9f848faSopenharmony_ci			/* set transfer endpoint pointer */
1060f9f848faSopenharmony_ci			xfer->endpoint = ep;
1061f9f848faSopenharmony_ci
1062f9f848faSopenharmony_ci			/* set transfer stream ID */
1063f9f848faSopenharmony_ci			xfer->stream_id = setup->stream_id;
1064f9f848faSopenharmony_ci
1065f9f848faSopenharmony_ci			parm->size[0] += sizeof(xfer[0]);
1066f9f848faSopenharmony_ci			parm->methods = xfer->endpoint->methods;
1067f9f848faSopenharmony_ci			parm->curr_xfer = xfer;
1068f9f848faSopenharmony_ci
1069f9f848faSopenharmony_ci			/*
1070f9f848faSopenharmony_ci			 * Call the Host or Device controller transfer
1071f9f848faSopenharmony_ci			 * setup routine:
1072f9f848faSopenharmony_ci			 */
1073f9f848faSopenharmony_ci			(udev->bus->methods->xfer_setup) (parm);
1074f9f848faSopenharmony_ci
1075f9f848faSopenharmony_ci			/* check for error */
1076f9f848faSopenharmony_ci			if (parm->err)
1077f9f848faSopenharmony_ci				goto done;
1078f9f848faSopenharmony_ci
1079f9f848faSopenharmony_ci			if (buf) {
1080f9f848faSopenharmony_ci				/*
1081f9f848faSopenharmony_ci				 * Increment the endpoint refcount. This
1082f9f848faSopenharmony_ci				 * basically prevents setting a new
1083f9f848faSopenharmony_ci				 * configuration and alternate setting
1084f9f848faSopenharmony_ci				 * when USB transfers are in use on
1085f9f848faSopenharmony_ci				 * the given interface. Search the USB
1086f9f848faSopenharmony_ci				 * code for "endpoint->refcount_alloc" if you
1087f9f848faSopenharmony_ci				 * want more information.
1088f9f848faSopenharmony_ci				 */
1089f9f848faSopenharmony_ci				USB_BUS_LOCK(info->bus);
1090f9f848faSopenharmony_ci				if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
1091f9f848faSopenharmony_ci					parm->err = USB_ERR_INVAL;
1092f9f848faSopenharmony_ci
1093f9f848faSopenharmony_ci				xfer->endpoint->refcount_alloc++;
1094f9f848faSopenharmony_ci
1095f9f848faSopenharmony_ci				if (xfer->endpoint->refcount_alloc == 0)
1096f9f848faSopenharmony_ci					panic("usbd_transfer_setup(): Refcount wrapped to zero\n");
1097f9f848faSopenharmony_ci				USB_BUS_UNLOCK(info->bus);
1098f9f848faSopenharmony_ci
1099f9f848faSopenharmony_ci				/*
1100f9f848faSopenharmony_ci				 * Whenever we set ppxfer[] then we
1101f9f848faSopenharmony_ci				 * also need to increment the
1102f9f848faSopenharmony_ci				 * "setup_refcount":
1103f9f848faSopenharmony_ci				 */
1104f9f848faSopenharmony_ci				info->setup_refcount++;
1105f9f848faSopenharmony_ci
1106f9f848faSopenharmony_ci				/*
1107f9f848faSopenharmony_ci				 * Transfer is successfully setup and
1108f9f848faSopenharmony_ci				 * can be used:
1109f9f848faSopenharmony_ci				 */
1110f9f848faSopenharmony_ci				ppxfer[n] = xfer;
1111f9f848faSopenharmony_ci			}
1112f9f848faSopenharmony_ci
1113f9f848faSopenharmony_ci			/* check for error */
1114f9f848faSopenharmony_ci			if (parm->err)
1115f9f848faSopenharmony_ci				goto done;
1116f9f848faSopenharmony_ci		}
1117f9f848faSopenharmony_ci
1118f9f848faSopenharmony_ci		if ((buf != NULL) || (parm->err != 0))
1119f9f848faSopenharmony_ci			goto done;
1120f9f848faSopenharmony_ci
1121f9f848faSopenharmony_ci		/* if no transfers, nothing to do */
1122f9f848faSopenharmony_ci		if (refcount == 0)
1123f9f848faSopenharmony_ci			goto done;
1124f9f848faSopenharmony_ci
1125f9f848faSopenharmony_ci		/* align data properly */
1126f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1127f9f848faSopenharmony_ci
1128f9f848faSopenharmony_ci		/* store offset temporarily */
1129f9f848faSopenharmony_ci		parm->size[1] = parm->size[0];
1130f9f848faSopenharmony_ci
1131f9f848faSopenharmony_ci		/*
1132f9f848faSopenharmony_ci		 * The number of DMA tags required depends on
1133f9f848faSopenharmony_ci		 * the number of endpoints. The current estimate
1134f9f848faSopenharmony_ci		 * for maximum number of DMA tags per endpoint
1135f9f848faSopenharmony_ci		 * is three:
1136f9f848faSopenharmony_ci		 * 1) for loading memory
1137f9f848faSopenharmony_ci		 * 2) for allocating memory
1138f9f848faSopenharmony_ci		 * 3) for fixing memory [UHCI]
1139f9f848faSopenharmony_ci		 */
1140f9f848faSopenharmony_ci		parm->dma_tag_max += 3 * MIN(n_setup, USB_EP_MAX);
1141f9f848faSopenharmony_ci
1142f9f848faSopenharmony_ci		/*
1143f9f848faSopenharmony_ci		 * DMA tags for QH, TD, Data and more.
1144f9f848faSopenharmony_ci		 */
1145f9f848faSopenharmony_ci		parm->dma_tag_max += 8;
1146f9f848faSopenharmony_ci
1147f9f848faSopenharmony_ci		parm->dma_tag_p += parm->dma_tag_max;
1148f9f848faSopenharmony_ci
1149f9f848faSopenharmony_ci		parm->size[0] += ((uint8_t *)parm->dma_tag_p) -
1150f9f848faSopenharmony_ci		    ((uint8_t *)0);
1151f9f848faSopenharmony_ci
1152f9f848faSopenharmony_ci		/* align data properly */
1153f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1154f9f848faSopenharmony_ci
1155f9f848faSopenharmony_ci		/* store offset temporarily */
1156f9f848faSopenharmony_ci		parm->size[3] = parm->size[0];
1157f9f848faSopenharmony_ci
1158f9f848faSopenharmony_ci		parm->size[0] += ((uint8_t *)parm->dma_page_ptr) -
1159f9f848faSopenharmony_ci		    ((uint8_t *)0);
1160f9f848faSopenharmony_ci
1161f9f848faSopenharmony_ci		/* align data properly */
1162f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1163f9f848faSopenharmony_ci
1164f9f848faSopenharmony_ci		/* store offset temporarily */
1165f9f848faSopenharmony_ci		parm->size[4] = parm->size[0];
1166f9f848faSopenharmony_ci
1167f9f848faSopenharmony_ci		parm->size[0] += ((uint8_t *)parm->dma_page_cache_ptr) -
1168f9f848faSopenharmony_ci		    ((uint8_t *)0);
1169f9f848faSopenharmony_ci
1170f9f848faSopenharmony_ci		/* store end offset temporarily */
1171f9f848faSopenharmony_ci		parm->size[5] = parm->size[0];
1172f9f848faSopenharmony_ci
1173f9f848faSopenharmony_ci		parm->size[0] += ((uint8_t *)parm->xfer_page_cache_ptr) -
1174f9f848faSopenharmony_ci		    ((uint8_t *)0);
1175f9f848faSopenharmony_ci
1176f9f848faSopenharmony_ci		/* store end offset temporarily */
1177f9f848faSopenharmony_ci
1178f9f848faSopenharmony_ci		parm->size[2] = parm->size[0];
1179f9f848faSopenharmony_ci
1180f9f848faSopenharmony_ci		/* align data properly */
1181f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1182f9f848faSopenharmony_ci
1183f9f848faSopenharmony_ci		parm->size[6] = parm->size[0];
1184f9f848faSopenharmony_ci
1185f9f848faSopenharmony_ci		parm->size[0] += ((uint8_t *)parm->xfer_length_ptr) -
1186f9f848faSopenharmony_ci		    ((uint8_t *)0);
1187f9f848faSopenharmony_ci
1188f9f848faSopenharmony_ci		/* align data properly */
1189f9f848faSopenharmony_ci		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
1190f9f848faSopenharmony_ci
1191f9f848faSopenharmony_ci		/* allocate zeroed memory */
1192f9f848faSopenharmony_ci		buf = bsd_malloc(parm->size[0], M_USB, M_WAITOK | M_ZERO);
1193f9f848faSopenharmony_ci
1194f9f848faSopenharmony_ci		if (buf == NULL) {
1195f9f848faSopenharmony_ci			parm->err = USB_ERR_NOMEM;
1196f9f848faSopenharmony_ci			DPRINTFN(0, "cannot allocate memory block for "
1197f9f848faSopenharmony_ci			    "configuration (%d bytes)\n",
1198f9f848faSopenharmony_ci			    parm->size[0]);
1199f9f848faSopenharmony_ci			goto done;
1200f9f848faSopenharmony_ci		}
1201f9f848faSopenharmony_ci		parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]);
1202f9f848faSopenharmony_ci		parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]);
1203f9f848faSopenharmony_ci		parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]);
1204f9f848faSopenharmony_ci		parm->xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[5]);
1205f9f848faSopenharmony_ci		parm->xfer_length_ptr = USB_ADD_BYTES(buf, parm->size[6]);
1206f9f848faSopenharmony_ci	}
1207f9f848faSopenharmony_ci
1208f9f848faSopenharmony_cidone:
1209f9f848faSopenharmony_ci	if (buf) {
1210f9f848faSopenharmony_ci		if (info->setup_refcount == 0) {
1211f9f848faSopenharmony_ci			/*
1212f9f848faSopenharmony_ci			 * "usbd_transfer_unsetup_sub" will unlock
1213f9f848faSopenharmony_ci			 * the bus mutex before returning !
1214f9f848faSopenharmony_ci			 */
1215f9f848faSopenharmony_ci			USB_BUS_LOCK(info->bus);
1216f9f848faSopenharmony_ci
1217f9f848faSopenharmony_ci			/* something went wrong */
1218f9f848faSopenharmony_ci			usbd_transfer_unsetup_sub(info, 0);
1219f9f848faSopenharmony_ci		}
1220f9f848faSopenharmony_ci	}
1221f9f848faSopenharmony_ci
1222f9f848faSopenharmony_ci	/* check if any errors happened */
1223f9f848faSopenharmony_ci	if (parm->err)
1224f9f848faSopenharmony_ci		usbd_transfer_unsetup(ppxfer, n_setup);
1225f9f848faSopenharmony_ci
1226f9f848faSopenharmony_ci	error = parm->err;
1227f9f848faSopenharmony_ci
1228f9f848faSopenharmony_ci	if (do_unlock)
1229f9f848faSopenharmony_ci		usbd_ctrl_unlock(udev);
1230f9f848faSopenharmony_ci
1231f9f848faSopenharmony_ci	return (error);
1232f9f848faSopenharmony_ci}
1233f9f848faSopenharmony_ci
1234f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1235f9f848faSopenharmony_ci *	usbd_transfer_unsetup_sub - factored out code
1236f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1237f9f848faSopenharmony_cistatic void
1238f9f848faSopenharmony_ciusbd_transfer_unsetup_sub(struct usb_xfer_root *info, uint8_t needs_delay)
1239f9f848faSopenharmony_ci{
1240f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
1241f9f848faSopenharmony_ci	struct usb_page_cache *pc;
1242f9f848faSopenharmony_ci#endif
1243f9f848faSopenharmony_ci
1244f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED);
1245f9f848faSopenharmony_ci
1246f9f848faSopenharmony_ci	/* wait for any outstanding DMA operations */
1247f9f848faSopenharmony_ci
1248f9f848faSopenharmony_ci	if (needs_delay) {
1249f9f848faSopenharmony_ci		usb_timeout_t temp;
1250f9f848faSopenharmony_ci		temp = usbd_get_dma_delay(info->udev);
1251f9f848faSopenharmony_ci		if (temp != 0) {
1252f9f848faSopenharmony_ci			usb_pause_mtx(&info->bus->bus_mtx,
1253f9f848faSopenharmony_ci			    USB_MS_TO_TICKS(temp));
1254f9f848faSopenharmony_ci		}
1255f9f848faSopenharmony_ci	}
1256f9f848faSopenharmony_ci
1257f9f848faSopenharmony_ci	/* make sure that our done messages are not queued anywhere */
1258f9f848faSopenharmony_ci	usb_proc_mwait(info->done_p, &info->done_m[0], &info->done_m[1]);
1259f9f848faSopenharmony_ci
1260f9f848faSopenharmony_ci	USB_BUS_UNLOCK(info->bus);
1261f9f848faSopenharmony_ci
1262f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
1263f9f848faSopenharmony_ci	/* free DMA'able memory, if any */
1264f9f848faSopenharmony_ci	pc = info->dma_page_cache_start;
1265f9f848faSopenharmony_ci	while (pc != info->dma_page_cache_end) {
1266f9f848faSopenharmony_ci		usb_pc_free_mem(pc);
1267f9f848faSopenharmony_ci		pc++;
1268f9f848faSopenharmony_ci	}
1269f9f848faSopenharmony_ci
1270f9f848faSopenharmony_ci	/* free DMA maps in all "xfer->frbuffers" */
1271f9f848faSopenharmony_ci	pc = info->xfer_page_cache_start;
1272f9f848faSopenharmony_ci	while (pc != info->xfer_page_cache_end) {
1273f9f848faSopenharmony_ci		usb_pc_dmamap_destroy(pc);
1274f9f848faSopenharmony_ci		pc++;
1275f9f848faSopenharmony_ci	}
1276f9f848faSopenharmony_ci
1277f9f848faSopenharmony_ci	/* free all DMA tags */
1278f9f848faSopenharmony_ci	usb_dma_tag_unsetup(&info->dma_parent_tag);
1279f9f848faSopenharmony_ci#endif
1280f9f848faSopenharmony_ci
1281f9f848faSopenharmony_ci	cv_destroy(&info->cv_drain);
1282f9f848faSopenharmony_ci
1283f9f848faSopenharmony_ci	/*
1284f9f848faSopenharmony_ci	 * free the "memory_base" last, hence the "info" structure is
1285f9f848faSopenharmony_ci	 * contained within the "memory_base"!
1286f9f848faSopenharmony_ci	 */
1287f9f848faSopenharmony_ci	bsd_free(info->memory_base, M_USB);
1288f9f848faSopenharmony_ci	info->memory_base = NULL;
1289f9f848faSopenharmony_ci}
1290f9f848faSopenharmony_ci
1291f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1292f9f848faSopenharmony_ci *	usbd_transfer_unsetup - unsetup/free an array of USB transfers
1293f9f848faSopenharmony_ci *
1294f9f848faSopenharmony_ci * NOTE: All USB transfers in progress will get called back passing
1295f9f848faSopenharmony_ci * the error code "USB_ERR_CANCELLED" before this function
1296f9f848faSopenharmony_ci * returns.
1297f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1298f9f848faSopenharmony_civoid
1299f9f848faSopenharmony_ciusbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
1300f9f848faSopenharmony_ci{
1301f9f848faSopenharmony_ci	struct usb_xfer *xfer;
1302f9f848faSopenharmony_ci	struct usb_xfer_root *info;
1303f9f848faSopenharmony_ci	uint8_t needs_delay = 0;
1304f9f848faSopenharmony_ci
1305f9f848faSopenharmony_ci	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1306f9f848faSopenharmony_ci	    "usbd_transfer_unsetup can sleep!");
1307f9f848faSopenharmony_ci
1308f9f848faSopenharmony_ci	while (n_setup--) {
1309f9f848faSopenharmony_ci		xfer = pxfer[n_setup];
1310f9f848faSopenharmony_ci
1311f9f848faSopenharmony_ci		if (xfer == NULL)
1312f9f848faSopenharmony_ci			continue;
1313f9f848faSopenharmony_ci
1314f9f848faSopenharmony_ci		info = xfer->xroot;
1315f9f848faSopenharmony_ci
1316f9f848faSopenharmony_ci		USB_XFER_LOCK(xfer);
1317f9f848faSopenharmony_ci		USB_BUS_LOCK(info->bus);
1318f9f848faSopenharmony_ci
1319f9f848faSopenharmony_ci		/*
1320f9f848faSopenharmony_ci		 * HINT: when you start/stop a transfer, it might be a
1321f9f848faSopenharmony_ci		 * good idea to directly use the "pxfer[]" structure:
1322f9f848faSopenharmony_ci		 *
1323f9f848faSopenharmony_ci		 * usbd_transfer_start(sc->pxfer[0]);
1324f9f848faSopenharmony_ci		 * usbd_transfer_stop(sc->pxfer[0]);
1325f9f848faSopenharmony_ci		 *
1326f9f848faSopenharmony_ci		 * That way, if your code has many parts that will not
1327f9f848faSopenharmony_ci		 * stop running under the same lock, in other words
1328f9f848faSopenharmony_ci		 * "xfer_mtx", the usbd_transfer_start and
1329f9f848faSopenharmony_ci		 * usbd_transfer_stop functions will simply return
1330f9f848faSopenharmony_ci		 * when they detect a NULL pointer argument.
1331f9f848faSopenharmony_ci		 *
1332f9f848faSopenharmony_ci		 * To avoid any races we clear the "pxfer[]" pointer
1333f9f848faSopenharmony_ci		 * while holding the private mutex of the driver:
1334f9f848faSopenharmony_ci		 */
1335f9f848faSopenharmony_ci		pxfer[n_setup] = NULL;
1336f9f848faSopenharmony_ci
1337f9f848faSopenharmony_ci		USB_BUS_UNLOCK(info->bus);
1338f9f848faSopenharmony_ci		USB_XFER_UNLOCK(xfer);
1339f9f848faSopenharmony_ci
1340f9f848faSopenharmony_ci		usbd_transfer_drain(xfer);
1341f9f848faSopenharmony_ci
1342f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
1343f9f848faSopenharmony_ci		if (xfer->flags_int.bdma_enable)
1344f9f848faSopenharmony_ci			needs_delay = 1;
1345f9f848faSopenharmony_ci#endif
1346f9f848faSopenharmony_ci		/*
1347f9f848faSopenharmony_ci		 * NOTE: default endpoint does not have an
1348f9f848faSopenharmony_ci		 * interface, even if endpoint->iface_index == 0
1349f9f848faSopenharmony_ci		 */
1350f9f848faSopenharmony_ci		USB_BUS_LOCK(info->bus);
1351f9f848faSopenharmony_ci		xfer->endpoint->refcount_alloc--;
1352f9f848faSopenharmony_ci		USB_BUS_UNLOCK(info->bus);
1353f9f848faSopenharmony_ci
1354f9f848faSopenharmony_ci		usb_callout_drain(&xfer->timeout_handle);
1355f9f848faSopenharmony_ci
1356f9f848faSopenharmony_ci		USB_BUS_LOCK(info->bus);
1357f9f848faSopenharmony_ci
1358f9f848faSopenharmony_ci		USB_ASSERT(info->setup_refcount != 0, ("Invalid setup "
1359f9f848faSopenharmony_ci		    "reference count\n"));
1360f9f848faSopenharmony_ci
1361f9f848faSopenharmony_ci		info->setup_refcount--;
1362f9f848faSopenharmony_ci
1363f9f848faSopenharmony_ci		if (info->setup_refcount == 0) {
1364f9f848faSopenharmony_ci			usbd_transfer_unsetup_sub(info,
1365f9f848faSopenharmony_ci			    needs_delay);
1366f9f848faSopenharmony_ci		} else {
1367f9f848faSopenharmony_ci			USB_BUS_UNLOCK(info->bus);
1368f9f848faSopenharmony_ci		}
1369f9f848faSopenharmony_ci	}
1370f9f848faSopenharmony_ci}
1371f9f848faSopenharmony_ci
1372f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1373f9f848faSopenharmony_ci *	usbd_control_transfer_init - factored out code
1374f9f848faSopenharmony_ci *
1375f9f848faSopenharmony_ci * In USB Device Mode we have to wait for the SETUP packet which
1376f9f848faSopenharmony_ci * containst the "struct usb_device_request" structure, before we can
1377f9f848faSopenharmony_ci * transfer any data. In USB Host Mode we already have the SETUP
1378f9f848faSopenharmony_ci * packet at the moment the USB transfer is started. This leads us to
1379f9f848faSopenharmony_ci * having to setup the USB transfer at two different places in
1380f9f848faSopenharmony_ci * time. This function just contains factored out control transfer
1381f9f848faSopenharmony_ci * initialisation code, so that we don't duplicate the code.
1382f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1383f9f848faSopenharmony_cistatic void
1384f9f848faSopenharmony_ciusbd_control_transfer_init(struct usb_xfer *xfer)
1385f9f848faSopenharmony_ci{
1386f9f848faSopenharmony_ci	struct usb_device_request req;
1387f9f848faSopenharmony_ci
1388f9f848faSopenharmony_ci	/* copy out the USB request header */
1389f9f848faSopenharmony_ci
1390f9f848faSopenharmony_ci	usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
1391f9f848faSopenharmony_ci
1392f9f848faSopenharmony_ci	/* setup remainder */
1393f9f848faSopenharmony_ci
1394f9f848faSopenharmony_ci	xfer->flags_int.control_rem = UGETW(req.wLength);
1395f9f848faSopenharmony_ci
1396f9f848faSopenharmony_ci	/* copy direction to endpoint variable */
1397f9f848faSopenharmony_ci
1398f9f848faSopenharmony_ci	xfer->endpointno &= ~(UE_DIR_IN | UE_DIR_OUT);
1399f9f848faSopenharmony_ci	xfer->endpointno |=
1400f9f848faSopenharmony_ci	    (req.bmRequestType & UT_READ) ? UE_DIR_IN : UE_DIR_OUT;
1401f9f848faSopenharmony_ci}
1402f9f848faSopenharmony_ci
1403f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1404f9f848faSopenharmony_ci *	usbd_control_transfer_did_data
1405f9f848faSopenharmony_ci *
1406f9f848faSopenharmony_ci * This function returns non-zero if a control endpoint has
1407f9f848faSopenharmony_ci * transferred the first DATA packet after the SETUP packet.
1408f9f848faSopenharmony_ci * Else it returns zero.
1409f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1410f9f848faSopenharmony_cistatic uint8_t
1411f9f848faSopenharmony_ciusbd_control_transfer_did_data(struct usb_xfer *xfer)
1412f9f848faSopenharmony_ci{
1413f9f848faSopenharmony_ci	struct usb_device_request req;
1414f9f848faSopenharmony_ci
1415f9f848faSopenharmony_ci	/* SETUP packet is not yet sent */
1416f9f848faSopenharmony_ci	if (xfer->flags_int.control_hdr != 0)
1417f9f848faSopenharmony_ci		return (0);
1418f9f848faSopenharmony_ci
1419f9f848faSopenharmony_ci	/* copy out the USB request header */
1420f9f848faSopenharmony_ci	usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
1421f9f848faSopenharmony_ci
1422f9f848faSopenharmony_ci	/* compare remainder to the initial value */
1423f9f848faSopenharmony_ci	return (xfer->flags_int.control_rem != UGETW(req.wLength));
1424f9f848faSopenharmony_ci}
1425f9f848faSopenharmony_ci
1426f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1427f9f848faSopenharmony_ci *	usbd_setup_ctrl_transfer
1428f9f848faSopenharmony_ci *
1429f9f848faSopenharmony_ci * This function handles initialisation of control transfers. Control
1430f9f848faSopenharmony_ci * transfers are special in that regard that they can both transmit
1431f9f848faSopenharmony_ci * and receive data.
1432f9f848faSopenharmony_ci *
1433f9f848faSopenharmony_ci * Return values:
1434f9f848faSopenharmony_ci *    0: Success
1435f9f848faSopenharmony_ci * Else: Failure
1436f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1437f9f848faSopenharmony_cistatic int
1438f9f848faSopenharmony_ciusbd_setup_ctrl_transfer(struct usb_xfer *xfer)
1439f9f848faSopenharmony_ci{
1440f9f848faSopenharmony_ci	usb_frlength_t len;
1441f9f848faSopenharmony_ci
1442f9f848faSopenharmony_ci	/* Check for control endpoint stall */
1443f9f848faSopenharmony_ci	if (xfer->flags.stall_pipe && xfer->flags_int.control_act) {
1444f9f848faSopenharmony_ci		/* the control transfer is no longer active */
1445f9f848faSopenharmony_ci		xfer->flags_int.control_stall = 1;
1446f9f848faSopenharmony_ci		xfer->flags_int.control_act = 0;
1447f9f848faSopenharmony_ci	} else {
1448f9f848faSopenharmony_ci		/* don't stall control transfer by default */
1449f9f848faSopenharmony_ci		xfer->flags_int.control_stall = 0;
1450f9f848faSopenharmony_ci	}
1451f9f848faSopenharmony_ci
1452f9f848faSopenharmony_ci	/* Check for invalid number of frames */
1453f9f848faSopenharmony_ci	if (xfer->nframes > 2) {
1454f9f848faSopenharmony_ci		/*
1455f9f848faSopenharmony_ci		 * If you need to split a control transfer, you
1456f9f848faSopenharmony_ci		 * have to do one part at a time. Only with
1457f9f848faSopenharmony_ci		 * non-control transfers you can do multiple
1458f9f848faSopenharmony_ci		 * parts a time.
1459f9f848faSopenharmony_ci		 */
1460f9f848faSopenharmony_ci		DPRINTFN(0, "Too many frames: %u\n",
1461f9f848faSopenharmony_ci		    (unsigned int)xfer->nframes);
1462f9f848faSopenharmony_ci		goto error;
1463f9f848faSopenharmony_ci	}
1464f9f848faSopenharmony_ci
1465f9f848faSopenharmony_ci	/*
1466f9f848faSopenharmony_ci         * Check if there is a control
1467f9f848faSopenharmony_ci         * transfer in progress:
1468f9f848faSopenharmony_ci         */
1469f9f848faSopenharmony_ci	if (xfer->flags_int.control_act) {
1470f9f848faSopenharmony_ci		if (xfer->flags_int.control_hdr) {
1471f9f848faSopenharmony_ci			/* clear send header flag */
1472f9f848faSopenharmony_ci
1473f9f848faSopenharmony_ci			xfer->flags_int.control_hdr = 0;
1474f9f848faSopenharmony_ci
1475f9f848faSopenharmony_ci			/* setup control transfer */
1476f9f848faSopenharmony_ci			if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1477f9f848faSopenharmony_ci				usbd_control_transfer_init(xfer);
1478f9f848faSopenharmony_ci			}
1479f9f848faSopenharmony_ci		}
1480f9f848faSopenharmony_ci		/* get data length */
1481f9f848faSopenharmony_ci
1482f9f848faSopenharmony_ci		len = xfer->sumlen;
1483f9f848faSopenharmony_ci
1484f9f848faSopenharmony_ci	} else {
1485f9f848faSopenharmony_ci		/* the size of the SETUP structure is hardcoded ! */
1486f9f848faSopenharmony_ci
1487f9f848faSopenharmony_ci		if (xfer->frlengths[0] != sizeof(struct usb_device_request)) {
1488f9f848faSopenharmony_ci			DPRINTFN(0, "Wrong framelength %u != %zu\n",
1489f9f848faSopenharmony_ci			    xfer->frlengths[0], sizeof(struct
1490f9f848faSopenharmony_ci			    usb_device_request));
1491f9f848faSopenharmony_ci			goto error;
1492f9f848faSopenharmony_ci		}
1493f9f848faSopenharmony_ci		/* check USB mode */
1494f9f848faSopenharmony_ci		if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1495f9f848faSopenharmony_ci			/* check number of frames */
1496f9f848faSopenharmony_ci			if (xfer->nframes != 1) {
1497f9f848faSopenharmony_ci				/*
1498f9f848faSopenharmony_ci			         * We need to receive the setup
1499f9f848faSopenharmony_ci			         * message first so that we know the
1500f9f848faSopenharmony_ci			         * data direction!
1501f9f848faSopenharmony_ci			         */
1502f9f848faSopenharmony_ci				DPRINTF("Misconfigured transfer\n");
1503f9f848faSopenharmony_ci				goto error;
1504f9f848faSopenharmony_ci			}
1505f9f848faSopenharmony_ci			/*
1506f9f848faSopenharmony_ci			 * Set a dummy "control_rem" value.  This
1507f9f848faSopenharmony_ci			 * variable will be overwritten later by a
1508f9f848faSopenharmony_ci			 * call to "usbd_control_transfer_init()" !
1509f9f848faSopenharmony_ci			 */
1510f9f848faSopenharmony_ci			xfer->flags_int.control_rem = 0xFFFF;
1511f9f848faSopenharmony_ci		} else {
1512f9f848faSopenharmony_ci			/* setup "endpoint" and "control_rem" */
1513f9f848faSopenharmony_ci
1514f9f848faSopenharmony_ci			usbd_control_transfer_init(xfer);
1515f9f848faSopenharmony_ci		}
1516f9f848faSopenharmony_ci
1517f9f848faSopenharmony_ci		/* set transfer-header flag */
1518f9f848faSopenharmony_ci
1519f9f848faSopenharmony_ci		xfer->flags_int.control_hdr = 1;
1520f9f848faSopenharmony_ci
1521f9f848faSopenharmony_ci		/* get data length */
1522f9f848faSopenharmony_ci
1523f9f848faSopenharmony_ci		len = (xfer->sumlen - sizeof(struct usb_device_request));
1524f9f848faSopenharmony_ci	}
1525f9f848faSopenharmony_ci
1526f9f848faSopenharmony_ci	/* update did data flag */
1527f9f848faSopenharmony_ci
1528f9f848faSopenharmony_ci	xfer->flags_int.control_did_data =
1529f9f848faSopenharmony_ci	    usbd_control_transfer_did_data(xfer);
1530f9f848faSopenharmony_ci
1531f9f848faSopenharmony_ci	/* check if there is a length mismatch */
1532f9f848faSopenharmony_ci
1533f9f848faSopenharmony_ci	if (len > xfer->flags_int.control_rem) {
1534f9f848faSopenharmony_ci		DPRINTFN(0, "Length (%d) greater than "
1535f9f848faSopenharmony_ci		    "remaining length (%d)\n", len,
1536f9f848faSopenharmony_ci		    xfer->flags_int.control_rem);
1537f9f848faSopenharmony_ci		goto error;
1538f9f848faSopenharmony_ci	}
1539f9f848faSopenharmony_ci	/* check if we are doing a short transfer */
1540f9f848faSopenharmony_ci
1541f9f848faSopenharmony_ci	if (xfer->flags.force_short_xfer) {
1542f9f848faSopenharmony_ci		xfer->flags_int.control_rem = 0;
1543f9f848faSopenharmony_ci	} else {
1544f9f848faSopenharmony_ci		if ((len != xfer->max_data_length) &&
1545f9f848faSopenharmony_ci		    (len != xfer->flags_int.control_rem) &&
1546f9f848faSopenharmony_ci		    (xfer->nframes != 1)) {
1547f9f848faSopenharmony_ci			DPRINTFN(0, "Short control transfer without "
1548f9f848faSopenharmony_ci			    "force_short_xfer set\n");
1549f9f848faSopenharmony_ci			goto error;
1550f9f848faSopenharmony_ci		}
1551f9f848faSopenharmony_ci		xfer->flags_int.control_rem -= len;
1552f9f848faSopenharmony_ci	}
1553f9f848faSopenharmony_ci
1554f9f848faSopenharmony_ci	/* the status part is executed when "control_act" is 0 */
1555f9f848faSopenharmony_ci
1556f9f848faSopenharmony_ci	if ((xfer->flags_int.control_rem > 0) ||
1557f9f848faSopenharmony_ci	    (xfer->flags.manual_status)) {
1558f9f848faSopenharmony_ci		/* don't execute the STATUS stage yet */
1559f9f848faSopenharmony_ci		xfer->flags_int.control_act = 1;
1560f9f848faSopenharmony_ci
1561f9f848faSopenharmony_ci		/* sanity check */
1562f9f848faSopenharmony_ci		if ((!xfer->flags_int.control_hdr) &&
1563f9f848faSopenharmony_ci		    (xfer->nframes == 1)) {
1564f9f848faSopenharmony_ci			/*
1565f9f848faSopenharmony_ci		         * This is not a valid operation!
1566f9f848faSopenharmony_ci		         */
1567f9f848faSopenharmony_ci			DPRINTFN(0, "Invalid parameter "
1568f9f848faSopenharmony_ci			    "combination\n");
1569f9f848faSopenharmony_ci			goto error;
1570f9f848faSopenharmony_ci		}
1571f9f848faSopenharmony_ci	} else {
1572f9f848faSopenharmony_ci		/* time to execute the STATUS stage */
1573f9f848faSopenharmony_ci		xfer->flags_int.control_act = 0;
1574f9f848faSopenharmony_ci	}
1575f9f848faSopenharmony_ci	return (0);			/* success */
1576f9f848faSopenharmony_ci
1577f9f848faSopenharmony_cierror:
1578f9f848faSopenharmony_ci	return (1);			/* failure */
1579f9f848faSopenharmony_ci}
1580f9f848faSopenharmony_ci
1581f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1582f9f848faSopenharmony_ci *	usbd_transfer_submit - start USB hardware for the given transfer
1583f9f848faSopenharmony_ci *
1584f9f848faSopenharmony_ci * This function should only be called from the USB callback.
1585f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1586f9f848faSopenharmony_civoid
1587f9f848faSopenharmony_ciusbd_transfer_submit(struct usb_xfer *xfer)
1588f9f848faSopenharmony_ci{
1589f9f848faSopenharmony_ci	struct usb_xfer_root *info;
1590f9f848faSopenharmony_ci	struct usb_bus *bus;
1591f9f848faSopenharmony_ci	usb_frcount_t x;
1592f9f848faSopenharmony_ci
1593f9f848faSopenharmony_ci	info = xfer->xroot;
1594f9f848faSopenharmony_ci	bus = info->bus;
1595f9f848faSopenharmony_ci
1596f9f848faSopenharmony_ci	DPRINTF("xfer=%p, endpoint=%p, nframes=%d, dir=%s\n",
1597f9f848faSopenharmony_ci	    xfer, xfer->endpoint, xfer->nframes, USB_GET_DATA_ISREAD(xfer) ?
1598f9f848faSopenharmony_ci	    "read" : "write");
1599f9f848faSopenharmony_ci
1600f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
1601f9f848faSopenharmony_ci	if (USB_DEBUG_VAR > 0) {
1602f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
1603f9f848faSopenharmony_ci
1604f9f848faSopenharmony_ci		usb_dump_endpoint(xfer->endpoint);
1605f9f848faSopenharmony_ci
1606f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
1607f9f848faSopenharmony_ci	}
1608f9f848faSopenharmony_ci#endif
1609f9f848faSopenharmony_ci
1610f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
1611f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(bus, MA_NOTOWNED);
1612f9f848faSopenharmony_ci
1613f9f848faSopenharmony_ci	/* Only open the USB transfer once! */
1614f9f848faSopenharmony_ci	if (!xfer->flags_int.open) {
1615f9f848faSopenharmony_ci		xfer->flags_int.open = 1;
1616f9f848faSopenharmony_ci
1617f9f848faSopenharmony_ci		DPRINTF("open\n");
1618f9f848faSopenharmony_ci
1619f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
1620f9f848faSopenharmony_ci		(xfer->endpoint->methods->open) (xfer);
1621f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
1622f9f848faSopenharmony_ci	}
1623f9f848faSopenharmony_ci	/* set "transferring" flag */
1624f9f848faSopenharmony_ci	xfer->flags_int.transferring = 1;
1625f9f848faSopenharmony_ci
1626f9f848faSopenharmony_ci#if USB_HAVE_POWERD
1627f9f848faSopenharmony_ci	/* increment power reference */
1628f9f848faSopenharmony_ci	usbd_transfer_power_ref(xfer, 1);
1629f9f848faSopenharmony_ci#endif
1630f9f848faSopenharmony_ci	/*
1631f9f848faSopenharmony_ci	 * Check if the transfer is waiting on a queue, most
1632f9f848faSopenharmony_ci	 * frequently the "done_q":
1633f9f848faSopenharmony_ci	 */
1634f9f848faSopenharmony_ci	if (xfer->wait_queue) {
1635f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
1636f9f848faSopenharmony_ci		usbd_transfer_dequeue(xfer);
1637f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
1638f9f848faSopenharmony_ci	}
1639f9f848faSopenharmony_ci	/* clear "did_dma_delay" flag */
1640f9f848faSopenharmony_ci	xfer->flags_int.did_dma_delay = 0;
1641f9f848faSopenharmony_ci
1642f9f848faSopenharmony_ci	/* clear "did_close" flag */
1643f9f848faSopenharmony_ci	xfer->flags_int.did_close = 0;
1644f9f848faSopenharmony_ci
1645f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
1646f9f848faSopenharmony_ci	/* clear "bdma_setup" flag */
1647f9f848faSopenharmony_ci	xfer->flags_int.bdma_setup = 0;
1648f9f848faSopenharmony_ci#endif
1649f9f848faSopenharmony_ci	/* by default we cannot cancel any USB transfer immediately */
1650f9f848faSopenharmony_ci	xfer->flags_int.can_cancel_immed = 0;
1651f9f848faSopenharmony_ci
1652f9f848faSopenharmony_ci	/* clear lengths and frame counts by default */
1653f9f848faSopenharmony_ci	xfer->sumlen = 0;
1654f9f848faSopenharmony_ci	xfer->actlen = 0;
1655f9f848faSopenharmony_ci	xfer->aframes = 0;
1656f9f848faSopenharmony_ci
1657f9f848faSopenharmony_ci	/* clear any previous errors */
1658f9f848faSopenharmony_ci	xfer->error = USB_ERR_NORMAL_COMPLETION;
1659f9f848faSopenharmony_ci
1660f9f848faSopenharmony_ci	/* Check if the device is still alive */
1661f9f848faSopenharmony_ci	if (info->udev->state < USB_STATE_POWERED) {
1662f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
1663f9f848faSopenharmony_ci		/*
1664f9f848faSopenharmony_ci		 * Must return cancelled error code else
1665f9f848faSopenharmony_ci		 * device drivers can hang.
1666f9f848faSopenharmony_ci		 */
1667f9f848faSopenharmony_ci		usbd_transfer_done(xfer, USB_ERR_CANCELLED);
1668f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
1669f9f848faSopenharmony_ci		return;
1670f9f848faSopenharmony_ci	}
1671f9f848faSopenharmony_ci
1672f9f848faSopenharmony_ci	/* sanity check */
1673f9f848faSopenharmony_ci	if (xfer->nframes == 0) {
1674f9f848faSopenharmony_ci		if (xfer->flags.stall_pipe) {
1675f9f848faSopenharmony_ci			/*
1676f9f848faSopenharmony_ci			 * Special case - want to stall without transferring
1677f9f848faSopenharmony_ci			 * any data:
1678f9f848faSopenharmony_ci			 */
1679f9f848faSopenharmony_ci			DPRINTF("xfer=%p nframes=0: stall "
1680f9f848faSopenharmony_ci			    "or clear stall!\n", xfer);
1681f9f848faSopenharmony_ci			USB_BUS_LOCK(bus);
1682f9f848faSopenharmony_ci			xfer->flags_int.can_cancel_immed = 1;
1683f9f848faSopenharmony_ci			/* start the transfer */
1684f9f848faSopenharmony_ci			usb_command_wrapper(&xfer->endpoint->
1685f9f848faSopenharmony_ci			    endpoint_q[xfer->stream_id], xfer);
1686f9f848faSopenharmony_ci			USB_BUS_UNLOCK(bus);
1687f9f848faSopenharmony_ci			return;
1688f9f848faSopenharmony_ci		}
1689f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
1690f9f848faSopenharmony_ci		usbd_transfer_done(xfer, USB_ERR_INVAL);
1691f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
1692f9f848faSopenharmony_ci		return;
1693f9f848faSopenharmony_ci	}
1694f9f848faSopenharmony_ci	/* compute some variables */
1695f9f848faSopenharmony_ci
1696f9f848faSopenharmony_ci	for (x = 0; x != xfer->nframes; x++) {
1697f9f848faSopenharmony_ci		/* make a copy of the frlenghts[] */
1698f9f848faSopenharmony_ci		xfer->frlengths[x + xfer->max_frame_count] = xfer->frlengths[x];
1699f9f848faSopenharmony_ci		/* compute total transfer length */
1700f9f848faSopenharmony_ci		xfer->sumlen += xfer->frlengths[x];
1701f9f848faSopenharmony_ci		if (xfer->sumlen < xfer->frlengths[x]) {
1702f9f848faSopenharmony_ci			/* length wrapped around */
1703f9f848faSopenharmony_ci			USB_BUS_LOCK(bus);
1704f9f848faSopenharmony_ci			usbd_transfer_done(xfer, USB_ERR_INVAL);
1705f9f848faSopenharmony_ci			USB_BUS_UNLOCK(bus);
1706f9f848faSopenharmony_ci			return;
1707f9f848faSopenharmony_ci		}
1708f9f848faSopenharmony_ci	}
1709f9f848faSopenharmony_ci
1710f9f848faSopenharmony_ci	/* clear some internal flags */
1711f9f848faSopenharmony_ci
1712f9f848faSopenharmony_ci	xfer->flags_int.short_xfer_ok = 0;
1713f9f848faSopenharmony_ci	xfer->flags_int.short_frames_ok = 0;
1714f9f848faSopenharmony_ci
1715f9f848faSopenharmony_ci	/* check if this is a control transfer */
1716f9f848faSopenharmony_ci
1717f9f848faSopenharmony_ci	if (xfer->flags_int.control_xfr) {
1718f9f848faSopenharmony_ci		if (usbd_setup_ctrl_transfer(xfer)) {
1719f9f848faSopenharmony_ci			USB_BUS_LOCK(bus);
1720f9f848faSopenharmony_ci			usbd_transfer_done(xfer, USB_ERR_STALLED);
1721f9f848faSopenharmony_ci			USB_BUS_UNLOCK(bus);
1722f9f848faSopenharmony_ci			return;
1723f9f848faSopenharmony_ci		}
1724f9f848faSopenharmony_ci	}
1725f9f848faSopenharmony_ci	/*
1726f9f848faSopenharmony_ci	 * Setup filtered version of some transfer flags,
1727f9f848faSopenharmony_ci	 * in case of data read direction
1728f9f848faSopenharmony_ci	 */
1729f9f848faSopenharmony_ci	if (USB_GET_DATA_ISREAD(xfer)) {
1730f9f848faSopenharmony_ci		if (xfer->flags.short_frames_ok) {
1731f9f848faSopenharmony_ci			xfer->flags_int.short_xfer_ok = 1;
1732f9f848faSopenharmony_ci			xfer->flags_int.short_frames_ok = 1;
1733f9f848faSopenharmony_ci		} else if (xfer->flags.short_xfer_ok) {
1734f9f848faSopenharmony_ci			xfer->flags_int.short_xfer_ok = 1;
1735f9f848faSopenharmony_ci
1736f9f848faSopenharmony_ci			/* check for control transfer */
1737f9f848faSopenharmony_ci			if (xfer->flags_int.control_xfr) {
1738f9f848faSopenharmony_ci				/*
1739f9f848faSopenharmony_ci				 * 1) Control transfers do not support
1740f9f848faSopenharmony_ci				 * reception of multiple short USB
1741f9f848faSopenharmony_ci				 * frames in host mode and device side
1742f9f848faSopenharmony_ci				 * mode, with exception of:
1743f9f848faSopenharmony_ci				 *
1744f9f848faSopenharmony_ci				 * 2) Due to sometimes buggy device
1745f9f848faSopenharmony_ci				 * side firmware we need to do a
1746f9f848faSopenharmony_ci				 * STATUS stage in case of short
1747f9f848faSopenharmony_ci				 * control transfers in USB host mode.
1748f9f848faSopenharmony_ci				 * The STATUS stage then becomes the
1749f9f848faSopenharmony_ci				 * "alt_next" to the DATA stage.
1750f9f848faSopenharmony_ci				 */
1751f9f848faSopenharmony_ci				xfer->flags_int.short_frames_ok = 1;
1752f9f848faSopenharmony_ci			}
1753f9f848faSopenharmony_ci		}
1754f9f848faSopenharmony_ci	}
1755f9f848faSopenharmony_ci	/*
1756f9f848faSopenharmony_ci	 * Check if BUS-DMA support is enabled and try to load virtual
1757f9f848faSopenharmony_ci	 * buffers into DMA, if any:
1758f9f848faSopenharmony_ci	 */
1759f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
1760f9f848faSopenharmony_ci	if (xfer->flags_int.bdma_enable) {
1761f9f848faSopenharmony_ci		/* insert the USB transfer last in the BUS-DMA queue */
1762f9f848faSopenharmony_ci		usb_command_wrapper(&xfer->xroot->dma_q, xfer);
1763f9f848faSopenharmony_ci		return;
1764f9f848faSopenharmony_ci	}
1765f9f848faSopenharmony_ci#endif
1766f9f848faSopenharmony_ci	/*
1767f9f848faSopenharmony_ci	 * Enter the USB transfer into the Host Controller or
1768f9f848faSopenharmony_ci	 * Device Controller schedule:
1769f9f848faSopenharmony_ci	 */
1770f9f848faSopenharmony_ci	usbd_pipe_enter(xfer);
1771f9f848faSopenharmony_ci}
1772f9f848faSopenharmony_ci
1773f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1774f9f848faSopenharmony_ci *	usbd_pipe_enter - factored out code
1775f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1776f9f848faSopenharmony_civoid
1777f9f848faSopenharmony_ciusbd_pipe_enter(struct usb_xfer *xfer)
1778f9f848faSopenharmony_ci{
1779f9f848faSopenharmony_ci	struct usb_endpoint *ep;
1780f9f848faSopenharmony_ci
1781f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
1782f9f848faSopenharmony_ci
1783f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
1784f9f848faSopenharmony_ci
1785f9f848faSopenharmony_ci	ep = xfer->endpoint;
1786f9f848faSopenharmony_ci
1787f9f848faSopenharmony_ci	DPRINTF("enter\n");
1788f9f848faSopenharmony_ci
1789f9f848faSopenharmony_ci	/* the transfer can now be cancelled */
1790f9f848faSopenharmony_ci	xfer->flags_int.can_cancel_immed = 1;
1791f9f848faSopenharmony_ci
1792f9f848faSopenharmony_ci	/* enter the transfer */
1793f9f848faSopenharmony_ci	(ep->methods->enter) (xfer);
1794f9f848faSopenharmony_ci
1795f9f848faSopenharmony_ci	/* check for transfer error */
1796f9f848faSopenharmony_ci	if (xfer->error) {
1797f9f848faSopenharmony_ci		/* some error has happened */
1798f9f848faSopenharmony_ci		usbd_transfer_done(xfer, (usb_error_t)0);
1799f9f848faSopenharmony_ci		USB_BUS_UNLOCK(xfer->xroot->bus);
1800f9f848faSopenharmony_ci		return;
1801f9f848faSopenharmony_ci	}
1802f9f848faSopenharmony_ci
1803f9f848faSopenharmony_ci	/* start the transfer */
1804f9f848faSopenharmony_ci	usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], xfer);
1805f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
1806f9f848faSopenharmony_ci}
1807f9f848faSopenharmony_ci
1808f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1809f9f848faSopenharmony_ci *	usbd_transfer_start - start an USB transfer
1810f9f848faSopenharmony_ci *
1811f9f848faSopenharmony_ci * NOTE: Calling this function more than one time will only
1812f9f848faSopenharmony_ci *       result in a single transfer start, until the USB transfer
1813f9f848faSopenharmony_ci *       completes.
1814f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1815f9f848faSopenharmony_civoid
1816f9f848faSopenharmony_ciusbd_transfer_start(struct usb_xfer *xfer)
1817f9f848faSopenharmony_ci{
1818f9f848faSopenharmony_ci	if (xfer == NULL) {
1819f9f848faSopenharmony_ci		/* transfer is gone */
1820f9f848faSopenharmony_ci		return;
1821f9f848faSopenharmony_ci	}
1822f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
1823f9f848faSopenharmony_ci
1824f9f848faSopenharmony_ci	/* mark the USB transfer started */
1825f9f848faSopenharmony_ci
1826f9f848faSopenharmony_ci	if (!xfer->flags_int.started) {
1827f9f848faSopenharmony_ci		/* lock the BUS lock to avoid races updating flags_int */
1828f9f848faSopenharmony_ci		USB_BUS_LOCK(xfer->xroot->bus);
1829f9f848faSopenharmony_ci		xfer->flags_int.started = 1;
1830f9f848faSopenharmony_ci		USB_BUS_UNLOCK(xfer->xroot->bus);
1831f9f848faSopenharmony_ci	}
1832f9f848faSopenharmony_ci	/* check if the USB transfer callback is already transferring */
1833f9f848faSopenharmony_ci
1834f9f848faSopenharmony_ci	if (xfer->flags_int.transferring) {
1835f9f848faSopenharmony_ci		return;
1836f9f848faSopenharmony_ci	}
1837f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
1838f9f848faSopenharmony_ci	/* call the USB transfer callback */
1839f9f848faSopenharmony_ci	usbd_callback_ss_done_defer(xfer);
1840f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
1841f9f848faSopenharmony_ci}
1842f9f848faSopenharmony_ci
1843f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1844f9f848faSopenharmony_ci *	usbd_transfer_stop - stop an USB transfer
1845f9f848faSopenharmony_ci *
1846f9f848faSopenharmony_ci * NOTE: Calling this function more than one time will only
1847f9f848faSopenharmony_ci *       result in a single transfer stop.
1848f9f848faSopenharmony_ci * NOTE: When this function returns it is not safe to free nor
1849f9f848faSopenharmony_ci *       reuse any DMA buffers. See "usbd_transfer_drain()".
1850f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1851f9f848faSopenharmony_civoid
1852f9f848faSopenharmony_ciusbd_transfer_stop(struct usb_xfer *xfer)
1853f9f848faSopenharmony_ci{
1854f9f848faSopenharmony_ci	struct usb_endpoint *ep;
1855f9f848faSopenharmony_ci
1856f9f848faSopenharmony_ci	if (xfer == NULL) {
1857f9f848faSopenharmony_ci		/* transfer is gone */
1858f9f848faSopenharmony_ci		return;
1859f9f848faSopenharmony_ci	}
1860f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
1861f9f848faSopenharmony_ci
1862f9f848faSopenharmony_ci	/* check if the USB transfer was ever opened */
1863f9f848faSopenharmony_ci
1864f9f848faSopenharmony_ci	if (!xfer->flags_int.open) {
1865f9f848faSopenharmony_ci		if (xfer->flags_int.started) {
1866f9f848faSopenharmony_ci			/* nothing to do except clearing the "started" flag */
1867f9f848faSopenharmony_ci			/* lock the BUS lock to avoid races updating flags_int */
1868f9f848faSopenharmony_ci			USB_BUS_LOCK(xfer->xroot->bus);
1869f9f848faSopenharmony_ci			xfer->flags_int.started = 0;
1870f9f848faSopenharmony_ci			USB_BUS_UNLOCK(xfer->xroot->bus);
1871f9f848faSopenharmony_ci		}
1872f9f848faSopenharmony_ci		return;
1873f9f848faSopenharmony_ci	}
1874f9f848faSopenharmony_ci	/* try to stop the current USB transfer */
1875f9f848faSopenharmony_ci
1876f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
1877f9f848faSopenharmony_ci	/* override any previous error */
1878f9f848faSopenharmony_ci	xfer->error = USB_ERR_CANCELLED;
1879f9f848faSopenharmony_ci
1880f9f848faSopenharmony_ci	/*
1881f9f848faSopenharmony_ci	 * Clear "open" and "started" when both private and USB lock
1882f9f848faSopenharmony_ci	 * is locked so that we don't get a race updating "flags_int"
1883f9f848faSopenharmony_ci	 */
1884f9f848faSopenharmony_ci	xfer->flags_int.open = 0;
1885f9f848faSopenharmony_ci	xfer->flags_int.started = 0;
1886f9f848faSopenharmony_ci
1887f9f848faSopenharmony_ci	/*
1888f9f848faSopenharmony_ci	 * Check if we can cancel the USB transfer immediately.
1889f9f848faSopenharmony_ci	 */
1890f9f848faSopenharmony_ci	if (xfer->flags_int.transferring) {
1891f9f848faSopenharmony_ci		if (xfer->flags_int.can_cancel_immed &&
1892f9f848faSopenharmony_ci		    (!xfer->flags_int.did_close)) {
1893f9f848faSopenharmony_ci			DPRINTF("close\n");
1894f9f848faSopenharmony_ci			/*
1895f9f848faSopenharmony_ci			 * The following will lead to an USB_ERR_CANCELLED
1896f9f848faSopenharmony_ci			 * error code being passed to the USB callback.
1897f9f848faSopenharmony_ci			 */
1898f9f848faSopenharmony_ci			(xfer->endpoint->methods->close) (xfer);
1899f9f848faSopenharmony_ci			/* only close once */
1900f9f848faSopenharmony_ci			xfer->flags_int.did_close = 1;
1901f9f848faSopenharmony_ci		} else {
1902f9f848faSopenharmony_ci			/* need to wait for the next done callback */
1903f9f848faSopenharmony_ci		}
1904f9f848faSopenharmony_ci	} else {
1905f9f848faSopenharmony_ci		DPRINTF("close\n");
1906f9f848faSopenharmony_ci
1907f9f848faSopenharmony_ci		/* close here and now */
1908f9f848faSopenharmony_ci		(xfer->endpoint->methods->close) (xfer);
1909f9f848faSopenharmony_ci
1910f9f848faSopenharmony_ci		/*
1911f9f848faSopenharmony_ci		 * Any additional DMA delay is done by
1912f9f848faSopenharmony_ci		 * "usbd_transfer_unsetup()".
1913f9f848faSopenharmony_ci		 */
1914f9f848faSopenharmony_ci
1915f9f848faSopenharmony_ci		/*
1916f9f848faSopenharmony_ci		 * Special case. Check if we need to restart a blocked
1917f9f848faSopenharmony_ci		 * endpoint.
1918f9f848faSopenharmony_ci		 */
1919f9f848faSopenharmony_ci		ep = xfer->endpoint;
1920f9f848faSopenharmony_ci
1921f9f848faSopenharmony_ci		/*
1922f9f848faSopenharmony_ci		 * If the current USB transfer is completing we need
1923f9f848faSopenharmony_ci		 * to start the next one:
1924f9f848faSopenharmony_ci		 */
1925f9f848faSopenharmony_ci		if (ep->endpoint_q[xfer->stream_id].curr == xfer) {
1926f9f848faSopenharmony_ci			usb_command_wrapper(
1927f9f848faSopenharmony_ci			    &ep->endpoint_q[xfer->stream_id], NULL);
1928f9f848faSopenharmony_ci		}
1929f9f848faSopenharmony_ci	}
1930f9f848faSopenharmony_ci
1931f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
1932f9f848faSopenharmony_ci}
1933f9f848faSopenharmony_ci
1934f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1935f9f848faSopenharmony_ci *	usbd_transfer_pending
1936f9f848faSopenharmony_ci *
1937f9f848faSopenharmony_ci * This function will check if an USB transfer is pending which is a
1938f9f848faSopenharmony_ci * little bit complicated!
1939f9f848faSopenharmony_ci * Return values:
1940f9f848faSopenharmony_ci * 0: Not pending
1941f9f848faSopenharmony_ci * 1: Pending: The USB transfer will receive a callback in the future.
1942f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1943f9f848faSopenharmony_ciuint8_t
1944f9f848faSopenharmony_ciusbd_transfer_pending(struct usb_xfer *xfer)
1945f9f848faSopenharmony_ci{
1946f9f848faSopenharmony_ci	struct usb_xfer_root *info;
1947f9f848faSopenharmony_ci	struct usb_xfer_queue *pq;
1948f9f848faSopenharmony_ci
1949f9f848faSopenharmony_ci	if (xfer == NULL) {
1950f9f848faSopenharmony_ci		/* transfer is gone */
1951f9f848faSopenharmony_ci		return (0);
1952f9f848faSopenharmony_ci	}
1953f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
1954f9f848faSopenharmony_ci
1955f9f848faSopenharmony_ci	if (xfer->flags_int.transferring) {
1956f9f848faSopenharmony_ci		/* trivial case */
1957f9f848faSopenharmony_ci		return (1);
1958f9f848faSopenharmony_ci	}
1959f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
1960f9f848faSopenharmony_ci	if (xfer->wait_queue) {
1961f9f848faSopenharmony_ci		/* we are waiting on a queue somewhere */
1962f9f848faSopenharmony_ci		USB_BUS_UNLOCK(xfer->xroot->bus);
1963f9f848faSopenharmony_ci		return (1);
1964f9f848faSopenharmony_ci	}
1965f9f848faSopenharmony_ci	info = xfer->xroot;
1966f9f848faSopenharmony_ci	pq = &info->done_q;
1967f9f848faSopenharmony_ci
1968f9f848faSopenharmony_ci	if (pq->curr == xfer) {
1969f9f848faSopenharmony_ci		/* we are currently scheduled for callback */
1970f9f848faSopenharmony_ci		USB_BUS_UNLOCK(xfer->xroot->bus);
1971f9f848faSopenharmony_ci		return (1);
1972f9f848faSopenharmony_ci	}
1973f9f848faSopenharmony_ci	/* we are not pending */
1974f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
1975f9f848faSopenharmony_ci	return (0);
1976f9f848faSopenharmony_ci}
1977f9f848faSopenharmony_ci
1978f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
1979f9f848faSopenharmony_ci *	usbd_transfer_drain
1980f9f848faSopenharmony_ci *
1981f9f848faSopenharmony_ci * This function will stop the USB transfer and wait for any
1982f9f848faSopenharmony_ci * additional BUS-DMA and HW-DMA operations to complete. Buffers that
1983f9f848faSopenharmony_ci * are loaded into DMA can safely be freed or reused after that this
1984f9f848faSopenharmony_ci * function has returned.
1985f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
1986f9f848faSopenharmony_civoid
1987f9f848faSopenharmony_ciusbd_transfer_drain(struct usb_xfer *xfer)
1988f9f848faSopenharmony_ci{
1989f9f848faSopenharmony_ci	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1990f9f848faSopenharmony_ci	    "usbd_transfer_drain can sleep!");
1991f9f848faSopenharmony_ci
1992f9f848faSopenharmony_ci	if (xfer == NULL) {
1993f9f848faSopenharmony_ci		/* transfer is gone */
1994f9f848faSopenharmony_ci		return;
1995f9f848faSopenharmony_ci	}
1996f9f848faSopenharmony_ci	if (xfer->xroot->xfer_mtx != &Giant) {
1997f9f848faSopenharmony_ci		USB_XFER_LOCK_ASSERT(xfer, MA_NOTOWNED);
1998f9f848faSopenharmony_ci	}
1999f9f848faSopenharmony_ci	USB_XFER_LOCK(xfer);
2000f9f848faSopenharmony_ci
2001f9f848faSopenharmony_ci	usbd_transfer_stop(xfer);
2002f9f848faSopenharmony_ci
2003f9f848faSopenharmony_ci	while (usbd_transfer_pending(xfer) ||
2004f9f848faSopenharmony_ci	    xfer->flags_int.doing_callback) {
2005f9f848faSopenharmony_ci		/*
2006f9f848faSopenharmony_ci		 * It is allowed that the callback can drop its
2007f9f848faSopenharmony_ci		 * transfer mutex. In that case checking only
2008f9f848faSopenharmony_ci		 * "usbd_transfer_pending()" is not enough to tell if
2009f9f848faSopenharmony_ci		 * the USB transfer is fully drained. We also need to
2010f9f848faSopenharmony_ci		 * check the internal "doing_callback" flag.
2011f9f848faSopenharmony_ci		 */
2012f9f848faSopenharmony_ci		xfer->flags_int.draining = 1;
2013f9f848faSopenharmony_ci
2014f9f848faSopenharmony_ci		/*
2015f9f848faSopenharmony_ci		 * Wait until the current outstanding USB
2016f9f848faSopenharmony_ci		 * transfer is complete !
2017f9f848faSopenharmony_ci		 */
2018f9f848faSopenharmony_ci		(void)cv_wait(&xfer->xroot->cv_drain, xfer->xroot->xfer_mtx);
2019f9f848faSopenharmony_ci	}
2020f9f848faSopenharmony_ci	USB_XFER_UNLOCK(xfer);
2021f9f848faSopenharmony_ci}
2022f9f848faSopenharmony_ci
2023f9f848faSopenharmony_cistruct usb_page_cache *
2024f9f848faSopenharmony_ciusbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
2025f9f848faSopenharmony_ci{
2026f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2027f9f848faSopenharmony_ci
2028f9f848faSopenharmony_ci	return (&xfer->frbuffers[frindex]);
2029f9f848faSopenharmony_ci}
2030f9f848faSopenharmony_ci
2031f9f848faSopenharmony_civoid *
2032f9f848faSopenharmony_ciusbd_xfer_get_frame_buffer(struct usb_xfer *xfer, usb_frcount_t frindex)
2033f9f848faSopenharmony_ci{
2034f9f848faSopenharmony_ci	struct usb_page_search page_info;
2035f9f848faSopenharmony_ci
2036f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2037f9f848faSopenharmony_ci
2038f9f848faSopenharmony_ci	usbd_get_page(&xfer->frbuffers[frindex], 0, &page_info);
2039f9f848faSopenharmony_ci	return (page_info.buffer);
2040f9f848faSopenharmony_ci}
2041f9f848faSopenharmony_ci
2042f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2043f9f848faSopenharmony_ci *	usbd_xfer_get_fps_shift
2044f9f848faSopenharmony_ci *
2045f9f848faSopenharmony_ci * The following function is only useful for isochronous transfers. It
2046f9f848faSopenharmony_ci * returns how many times the frame execution rate has been shifted
2047f9f848faSopenharmony_ci * down.
2048f9f848faSopenharmony_ci *
2049f9f848faSopenharmony_ci * Return value:
2050f9f848faSopenharmony_ci * Success: 0..3
2051f9f848faSopenharmony_ci * Failure: 0
2052f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2053f9f848faSopenharmony_ciuint8_t
2054f9f848faSopenharmony_ciusbd_xfer_get_fps_shift(struct usb_xfer *xfer)
2055f9f848faSopenharmony_ci{
2056f9f848faSopenharmony_ci	return (xfer->fps_shift);
2057f9f848faSopenharmony_ci}
2058f9f848faSopenharmony_ci
2059f9f848faSopenharmony_ciusb_frlength_t
2060f9f848faSopenharmony_ciusbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex)
2061f9f848faSopenharmony_ci{
2062f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2063f9f848faSopenharmony_ci
2064f9f848faSopenharmony_ci	return (xfer->frlengths[frindex]);
2065f9f848faSopenharmony_ci}
2066f9f848faSopenharmony_ci
2067f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2068f9f848faSopenharmony_ci *	usbd_xfer_set_frame_data
2069f9f848faSopenharmony_ci *
2070f9f848faSopenharmony_ci * This function sets the pointer of the buffer that should
2071f9f848faSopenharmony_ci * loaded directly into DMA for the given USB frame. Passing "ptr"
2072f9f848faSopenharmony_ci * equal to NULL while the corresponding "frlength" is greater
2073f9f848faSopenharmony_ci * than zero gives undefined results!
2074f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2075f9f848faSopenharmony_civoid
2076f9f848faSopenharmony_ciusbd_xfer_set_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
2077f9f848faSopenharmony_ci    void *ptr, usb_frlength_t len)
2078f9f848faSopenharmony_ci{
2079f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2080f9f848faSopenharmony_ci
2081f9f848faSopenharmony_ci	/* set virtual address to load and length */
2082f9f848faSopenharmony_ci	xfer->frbuffers[frindex].buffer = ptr;
2083f9f848faSopenharmony_ci	usbd_xfer_set_frame_len(xfer, frindex, len);
2084f9f848faSopenharmony_ci}
2085f9f848faSopenharmony_ci
2086f9f848faSopenharmony_civoid
2087f9f848faSopenharmony_ciusbd_xfer_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
2088f9f848faSopenharmony_ci    void **ptr, int *len)
2089f9f848faSopenharmony_ci{
2090f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2091f9f848faSopenharmony_ci
2092f9f848faSopenharmony_ci	if (ptr != NULL)
2093f9f848faSopenharmony_ci		*ptr = xfer->frbuffers[frindex].buffer;
2094f9f848faSopenharmony_ci	if (len != NULL)
2095f9f848faSopenharmony_ci		*len = xfer->frlengths[frindex];
2096f9f848faSopenharmony_ci}
2097f9f848faSopenharmony_ci
2098f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2099f9f848faSopenharmony_ci *	usbd_xfer_old_frame_length
2100f9f848faSopenharmony_ci *
2101f9f848faSopenharmony_ci * This function returns the framelength of the given frame at the
2102f9f848faSopenharmony_ci * time the transfer was submitted. This function can be used to
2103f9f848faSopenharmony_ci * compute the starting data pointer of the next isochronous frame
2104f9f848faSopenharmony_ci * when an isochronous transfer has completed.
2105f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2106f9f848faSopenharmony_ciusb_frlength_t
2107f9f848faSopenharmony_ciusbd_xfer_old_frame_length(struct usb_xfer *xfer, usb_frcount_t frindex)
2108f9f848faSopenharmony_ci{
2109f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2110f9f848faSopenharmony_ci
2111f9f848faSopenharmony_ci	return (xfer->frlengths[frindex + xfer->max_frame_count]);
2112f9f848faSopenharmony_ci}
2113f9f848faSopenharmony_ci
2114f9f848faSopenharmony_civoid
2115f9f848faSopenharmony_ciusbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes,
2116f9f848faSopenharmony_ci    int *nframes)
2117f9f848faSopenharmony_ci{
2118f9f848faSopenharmony_ci	if (actlen != NULL)
2119f9f848faSopenharmony_ci		*actlen = xfer->actlen;
2120f9f848faSopenharmony_ci	if (sumlen != NULL)
2121f9f848faSopenharmony_ci		*sumlen = xfer->sumlen;
2122f9f848faSopenharmony_ci	if (aframes != NULL)
2123f9f848faSopenharmony_ci		*aframes = xfer->aframes;
2124f9f848faSopenharmony_ci	if (nframes != NULL)
2125f9f848faSopenharmony_ci		*nframes = xfer->nframes;
2126f9f848faSopenharmony_ci}
2127f9f848faSopenharmony_ci
2128f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2129f9f848faSopenharmony_ci *	usbd_xfer_set_frame_offset
2130f9f848faSopenharmony_ci *
2131f9f848faSopenharmony_ci * This function sets the frame data buffer offset relative to the beginning
2132f9f848faSopenharmony_ci * of the USB DMA buffer allocated for this USB transfer.
2133f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2134f9f848faSopenharmony_civoid
2135f9f848faSopenharmony_ciusbd_xfer_set_frame_offset(struct usb_xfer *xfer, usb_frlength_t offset,
2136f9f848faSopenharmony_ci    usb_frcount_t frindex)
2137f9f848faSopenharmony_ci{
2138f9f848faSopenharmony_ci	KASSERT(!xfer->flags.ext_buffer, ("Cannot offset data frame "
2139f9f848faSopenharmony_ci	    "when the USB buffer is external\n"));
2140f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2141f9f848faSopenharmony_ci
2142f9f848faSopenharmony_ci	/* set virtual address to load */
2143f9f848faSopenharmony_ci	xfer->frbuffers[frindex].buffer =
2144f9f848faSopenharmony_ci	    USB_ADD_BYTES(xfer->local_buffer, offset);
2145f9f848faSopenharmony_ci}
2146f9f848faSopenharmony_ci
2147f9f848faSopenharmony_civoid
2148f9f848faSopenharmony_ciusbd_xfer_set_interval(struct usb_xfer *xfer, int i)
2149f9f848faSopenharmony_ci{
2150f9f848faSopenharmony_ci	xfer->interval = i;
2151f9f848faSopenharmony_ci}
2152f9f848faSopenharmony_ci
2153f9f848faSopenharmony_civoid
2154f9f848faSopenharmony_ciusbd_xfer_set_timeout(struct usb_xfer *xfer, int t)
2155f9f848faSopenharmony_ci{
2156f9f848faSopenharmony_ci	xfer->timeout = t;
2157f9f848faSopenharmony_ci}
2158f9f848faSopenharmony_ci
2159f9f848faSopenharmony_civoid
2160f9f848faSopenharmony_ciusbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n)
2161f9f848faSopenharmony_ci{
2162f9f848faSopenharmony_ci	xfer->nframes = n;
2163f9f848faSopenharmony_ci}
2164f9f848faSopenharmony_ci
2165f9f848faSopenharmony_ciusb_frcount_t
2166f9f848faSopenharmony_ciusbd_xfer_max_frames(struct usb_xfer *xfer)
2167f9f848faSopenharmony_ci{
2168f9f848faSopenharmony_ci	return (xfer->max_frame_count);
2169f9f848faSopenharmony_ci}
2170f9f848faSopenharmony_ci
2171f9f848faSopenharmony_ciusb_frlength_t
2172f9f848faSopenharmony_ciusbd_xfer_max_len(struct usb_xfer *xfer)
2173f9f848faSopenharmony_ci{
2174f9f848faSopenharmony_ci	return (xfer->max_data_length);
2175f9f848faSopenharmony_ci}
2176f9f848faSopenharmony_ci
2177f9f848faSopenharmony_ciusb_frlength_t
2178f9f848faSopenharmony_ciusbd_xfer_max_framelen(struct usb_xfer *xfer)
2179f9f848faSopenharmony_ci{
2180f9f848faSopenharmony_ci	return (xfer->max_frame_size);
2181f9f848faSopenharmony_ci}
2182f9f848faSopenharmony_ci
2183f9f848faSopenharmony_civoid
2184f9f848faSopenharmony_ciusbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex,
2185f9f848faSopenharmony_ci    usb_frlength_t len)
2186f9f848faSopenharmony_ci{
2187f9f848faSopenharmony_ci	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
2188f9f848faSopenharmony_ci
2189f9f848faSopenharmony_ci	xfer->frlengths[frindex] = len;
2190f9f848faSopenharmony_ci}
2191f9f848faSopenharmony_ci
2192f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2193f9f848faSopenharmony_ci *	usb_callback_proc - factored out code
2194f9f848faSopenharmony_ci *
2195f9f848faSopenharmony_ci * This function performs USB callbacks.
2196f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2197f9f848faSopenharmony_cistatic void
2198f9f848faSopenharmony_ciusb_callback_proc(struct usb_proc_msg *_pm)
2199f9f848faSopenharmony_ci{
2200f9f848faSopenharmony_ci	struct usb_done_msg *pm = (void *)_pm;
2201f9f848faSopenharmony_ci	struct usb_xfer_root *info = pm->xroot;
2202f9f848faSopenharmony_ci
2203f9f848faSopenharmony_ci	/* Change locking order */
2204f9f848faSopenharmony_ci	USB_BUS_UNLOCK(info->bus);
2205f9f848faSopenharmony_ci
2206f9f848faSopenharmony_ci	/*
2207f9f848faSopenharmony_ci	 * We exploit the fact that the mutex is the same for all
2208f9f848faSopenharmony_ci	 * callbacks that will be called from this thread:
2209f9f848faSopenharmony_ci	 */
2210f9f848faSopenharmony_ci	USB_MTX_LOCK(info->xfer_mtx);
2211f9f848faSopenharmony_ci	USB_BUS_LOCK(info->bus);
2212f9f848faSopenharmony_ci
2213f9f848faSopenharmony_ci	/* Continue where we lost track */
2214f9f848faSopenharmony_ci	usb_command_wrapper(&info->done_q,
2215f9f848faSopenharmony_ci	    info->done_q.curr);
2216f9f848faSopenharmony_ci
2217f9f848faSopenharmony_ci	USB_MTX_UNLOCK(info->xfer_mtx);
2218f9f848faSopenharmony_ci}
2219f9f848faSopenharmony_ci
2220f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2221f9f848faSopenharmony_ci *	usbd_callback_ss_done_defer
2222f9f848faSopenharmony_ci *
2223f9f848faSopenharmony_ci * This function will defer the start, stop and done callback to the
2224f9f848faSopenharmony_ci * correct thread.
2225f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2226f9f848faSopenharmony_cistatic void
2227f9f848faSopenharmony_ciusbd_callback_ss_done_defer(struct usb_xfer *xfer)
2228f9f848faSopenharmony_ci{
2229f9f848faSopenharmony_ci	struct usb_xfer_root *info = xfer->xroot;
2230f9f848faSopenharmony_ci	struct usb_xfer_queue *pq = &info->done_q;
2231f9f848faSopenharmony_ci
2232f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
2233f9f848faSopenharmony_ci
2234f9f848faSopenharmony_ci	if (pq->curr != xfer) {
2235f9f848faSopenharmony_ci		usbd_transfer_enqueue(pq, xfer);
2236f9f848faSopenharmony_ci	}
2237f9f848faSopenharmony_ci	if (!pq->recurse_1) {
2238f9f848faSopenharmony_ci		/*
2239f9f848faSopenharmony_ci	         * We have to postpone the callback due to the fact we
2240f9f848faSopenharmony_ci	         * will have a Lock Order Reversal, LOR, if we try to
2241f9f848faSopenharmony_ci	         * proceed !
2242f9f848faSopenharmony_ci	         */
2243f9f848faSopenharmony_ci		if (usb_proc_msignal(info->done_p,
2244f9f848faSopenharmony_ci		    &info->done_m[0], &info->done_m[1])) {
2245f9f848faSopenharmony_ci			/* ignore */
2246f9f848faSopenharmony_ci		}
2247f9f848faSopenharmony_ci	} else {
2248f9f848faSopenharmony_ci		/* clear second recurse flag */
2249f9f848faSopenharmony_ci		pq->recurse_2 = 0;
2250f9f848faSopenharmony_ci	}
2251f9f848faSopenharmony_ci	return;
2252f9f848faSopenharmony_ci
2253f9f848faSopenharmony_ci}
2254f9f848faSopenharmony_ci
2255f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2256f9f848faSopenharmony_ci *	usbd_callback_wrapper
2257f9f848faSopenharmony_ci *
2258f9f848faSopenharmony_ci * This is a wrapper for USB callbacks. This wrapper does some
2259f9f848faSopenharmony_ci * auto-magic things like figuring out if we can call the callback
2260f9f848faSopenharmony_ci * directly from the current context or if we need to wakeup the
2261f9f848faSopenharmony_ci * interrupt process.
2262f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2263f9f848faSopenharmony_cistatic void
2264f9f848faSopenharmony_ciusbd_callback_wrapper(struct usb_xfer_queue *pq)
2265f9f848faSopenharmony_ci{
2266f9f848faSopenharmony_ci	struct usb_xfer *xfer = pq->curr;
2267f9f848faSopenharmony_ci	struct usb_xfer_root *info = xfer->xroot;
2268f9f848faSopenharmony_ci
2269f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED);
2270f9f848faSopenharmony_ci	if (!mtx_owned(info->xfer_mtx) && !SCHEDULER_STOPPED()) {
2271f9f848faSopenharmony_ci		/*
2272f9f848faSopenharmony_ci		 * Cases that end up here:
2273f9f848faSopenharmony_ci		 *
2274f9f848faSopenharmony_ci		 * 5) HW interrupt done callback or other source.
2275f9f848faSopenharmony_ci		 */
2276f9f848faSopenharmony_ci		DPRINTFN(3, "case 5\n");
2277f9f848faSopenharmony_ci
2278f9f848faSopenharmony_ci		/*
2279f9f848faSopenharmony_ci		 * We have to postpone the callback due to the fact we
2280f9f848faSopenharmony_ci		 * will have a Lock Order Reversal, LOR, if we try to
2281f9f848faSopenharmony_ci		 * proceed!
2282f9f848faSopenharmony_ci		 */
2283f9f848faSopenharmony_ci		if (usb_proc_msignal(info->done_p,
2284f9f848faSopenharmony_ci		    &info->done_m[0], &info->done_m[1])) {
2285f9f848faSopenharmony_ci			/* ignore */
2286f9f848faSopenharmony_ci		}
2287f9f848faSopenharmony_ci		return;
2288f9f848faSopenharmony_ci	}
2289f9f848faSopenharmony_ci	/*
2290f9f848faSopenharmony_ci	 * Cases that end up here:
2291f9f848faSopenharmony_ci	 *
2292f9f848faSopenharmony_ci	 * 1) We are starting a transfer
2293f9f848faSopenharmony_ci	 * 2) We are prematurely calling back a transfer
2294f9f848faSopenharmony_ci	 * 3) We are stopping a transfer
2295f9f848faSopenharmony_ci	 * 4) We are doing an ordinary callback
2296f9f848faSopenharmony_ci	 */
2297f9f848faSopenharmony_ci	DPRINTFN(3, "case 1-4\n");
2298f9f848faSopenharmony_ci	/* get next USB transfer in the queue */
2299f9f848faSopenharmony_ci	info->done_q.curr = NULL;
2300f9f848faSopenharmony_ci
2301f9f848faSopenharmony_ci	/* set flag in case of drain */
2302f9f848faSopenharmony_ci	xfer->flags_int.doing_callback = 1;
2303f9f848faSopenharmony_ci
2304f9f848faSopenharmony_ci	USB_BUS_UNLOCK(info->bus);
2305f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(info->bus, MA_NOTOWNED);
2306f9f848faSopenharmony_ci
2307f9f848faSopenharmony_ci	/* set correct USB state for callback */
2308f9f848faSopenharmony_ci	if (!xfer->flags_int.transferring) {
2309f9f848faSopenharmony_ci		xfer->usb_state = USB_ST_SETUP;
2310f9f848faSopenharmony_ci		if (!xfer->flags_int.started) {
2311f9f848faSopenharmony_ci			/* we got stopped before we even got started */
2312f9f848faSopenharmony_ci			USB_BUS_LOCK(info->bus);
2313f9f848faSopenharmony_ci			goto done;
2314f9f848faSopenharmony_ci		}
2315f9f848faSopenharmony_ci	} else {
2316f9f848faSopenharmony_ci		if (usbd_callback_wrapper_sub(xfer)) {
2317f9f848faSopenharmony_ci			/* the callback has been deferred */
2318f9f848faSopenharmony_ci			USB_BUS_LOCK(info->bus);
2319f9f848faSopenharmony_ci			goto done;
2320f9f848faSopenharmony_ci		}
2321f9f848faSopenharmony_ci#if USB_HAVE_POWERD
2322f9f848faSopenharmony_ci		/* decrement power reference */
2323f9f848faSopenharmony_ci		usbd_transfer_power_ref(xfer, -1);
2324f9f848faSopenharmony_ci#endif
2325f9f848faSopenharmony_ci		xfer->flags_int.transferring = 0;
2326f9f848faSopenharmony_ci
2327f9f848faSopenharmony_ci		if (xfer->error) {
2328f9f848faSopenharmony_ci			xfer->usb_state = USB_ST_ERROR;
2329f9f848faSopenharmony_ci		} else {
2330f9f848faSopenharmony_ci			/* set transferred state */
2331f9f848faSopenharmony_ci			xfer->usb_state = USB_ST_TRANSFERRED;
2332f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
2333f9f848faSopenharmony_ci			/* sync DMA memory, if any */
2334f9f848faSopenharmony_ci			if (xfer->flags_int.bdma_enable &&
2335f9f848faSopenharmony_ci			    (!xfer->flags_int.bdma_no_post_sync)) {
2336f9f848faSopenharmony_ci				usb_bdma_post_sync(xfer);
2337f9f848faSopenharmony_ci			}
2338f9f848faSopenharmony_ci#endif
2339f9f848faSopenharmony_ci		}
2340f9f848faSopenharmony_ci	}
2341f9f848faSopenharmony_ci
2342f9f848faSopenharmony_ci#if USB_HAVE_PF
2343f9f848faSopenharmony_ci	if (xfer->usb_state != USB_ST_SETUP) {
2344f9f848faSopenharmony_ci		USB_BUS_LOCK(info->bus);
2345f9f848faSopenharmony_ci		usbpf_xfertap(xfer, USBPF_XFERTAP_DONE);
2346f9f848faSopenharmony_ci		USB_BUS_UNLOCK(info->bus);
2347f9f848faSopenharmony_ci	}
2348f9f848faSopenharmony_ci#endif
2349f9f848faSopenharmony_ci	/* call processing routine */
2350f9f848faSopenharmony_ci	(xfer->callback) (xfer, xfer->error);
2351f9f848faSopenharmony_ci
2352f9f848faSopenharmony_ci	/* pickup the USB mutex again */
2353f9f848faSopenharmony_ci	USB_BUS_LOCK(info->bus);
2354f9f848faSopenharmony_ci
2355f9f848faSopenharmony_ci	/*
2356f9f848faSopenharmony_ci	 * Check if we got started after that we got cancelled, but
2357f9f848faSopenharmony_ci	 * before we managed to do the callback.
2358f9f848faSopenharmony_ci	 */
2359f9f848faSopenharmony_ci	if ((!xfer->flags_int.open) &&
2360f9f848faSopenharmony_ci	    (xfer->flags_int.started) &&
2361f9f848faSopenharmony_ci	    (xfer->usb_state == USB_ST_ERROR)) {
2362f9f848faSopenharmony_ci		/* clear flag in case of drain */
2363f9f848faSopenharmony_ci		xfer->flags_int.doing_callback = 0;
2364f9f848faSopenharmony_ci		/* try to loop, but not recursivly */
2365f9f848faSopenharmony_ci		usb_command_wrapper(&info->done_q, xfer);
2366f9f848faSopenharmony_ci		return;
2367f9f848faSopenharmony_ci	}
2368f9f848faSopenharmony_ci
2369f9f848faSopenharmony_cidone:
2370f9f848faSopenharmony_ci	/* clear flag in case of drain */
2371f9f848faSopenharmony_ci	xfer->flags_int.doing_callback = 0;
2372f9f848faSopenharmony_ci
2373f9f848faSopenharmony_ci	/*
2374f9f848faSopenharmony_ci	 * Check if we are draining.
2375f9f848faSopenharmony_ci	 */
2376f9f848faSopenharmony_ci	if (xfer->flags_int.draining &&
2377f9f848faSopenharmony_ci	    (!xfer->flags_int.transferring)) {
2378f9f848faSopenharmony_ci		/* "usbd_transfer_drain()" is waiting for end of transfer */
2379f9f848faSopenharmony_ci		xfer->flags_int.draining = 0;
2380f9f848faSopenharmony_ci		(void)cv_broadcast(&info->cv_drain);
2381f9f848faSopenharmony_ci	}
2382f9f848faSopenharmony_ci
2383f9f848faSopenharmony_ci	/* do the next callback, if any */
2384f9f848faSopenharmony_ci	usb_command_wrapper(&info->done_q,
2385f9f848faSopenharmony_ci	    info->done_q.curr);
2386f9f848faSopenharmony_ci}
2387f9f848faSopenharmony_ci
2388f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2389f9f848faSopenharmony_ci *	usb_dma_delay_done_cb
2390f9f848faSopenharmony_ci *
2391f9f848faSopenharmony_ci * This function is called when the DMA delay has been exectuded, and
2392f9f848faSopenharmony_ci * will make sure that the callback is called to complete the USB
2393f9f848faSopenharmony_ci * transfer. This code path is usually only used when there is an USB
2394f9f848faSopenharmony_ci * error like USB_ERR_CANCELLED.
2395f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2396f9f848faSopenharmony_civoid
2397f9f848faSopenharmony_ciusb_dma_delay_done_cb(struct usb_xfer *xfer)
2398f9f848faSopenharmony_ci{
2399f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
2400f9f848faSopenharmony_ci
2401f9f848faSopenharmony_ci	DPRINTFN(3, "Completed %p\n", xfer);
2402f9f848faSopenharmony_ci
2403f9f848faSopenharmony_ci	/* queue callback for execution, again */
2404f9f848faSopenharmony_ci	usbd_transfer_done(xfer, (usb_error_t)0);
2405f9f848faSopenharmony_ci}
2406f9f848faSopenharmony_ci
2407f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2408f9f848faSopenharmony_ci *	usbd_transfer_dequeue
2409f9f848faSopenharmony_ci *
2410f9f848faSopenharmony_ci *  - This function is used to remove an USB transfer from a USB
2411f9f848faSopenharmony_ci *  transfer queue.
2412f9f848faSopenharmony_ci *
2413f9f848faSopenharmony_ci *  - This function can be called multiple times in a row.
2414f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2415f9f848faSopenharmony_civoid
2416f9f848faSopenharmony_ciusbd_transfer_dequeue(struct usb_xfer *xfer)
2417f9f848faSopenharmony_ci{
2418f9f848faSopenharmony_ci	struct usb_xfer_queue *pq;
2419f9f848faSopenharmony_ci	uint32_t int_save;
2420f9f848faSopenharmony_ci
2421f9f848faSopenharmony_ci	LOS_SpinLockSave(&g_usb_wait_queue_spinlock, &int_save);
2422f9f848faSopenharmony_ci	pq = xfer->wait_queue;
2423f9f848faSopenharmony_ci	if (pq != NULL) {
2424f9f848faSopenharmony_ci		TAILQ_REMOVE(&pq->head, xfer, wait_entry);
2425f9f848faSopenharmony_ci		xfer->wait_queue = NULL;
2426f9f848faSopenharmony_ci	}
2427f9f848faSopenharmony_ci	LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
2428f9f848faSopenharmony_ci}
2429f9f848faSopenharmony_ci
2430f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2431f9f848faSopenharmony_ci *	usbd_transfer_enqueue
2432f9f848faSopenharmony_ci *
2433f9f848faSopenharmony_ci *  - This function is used to insert an USB transfer into a USB *
2434f9f848faSopenharmony_ci *  transfer queue.
2435f9f848faSopenharmony_ci *
2436f9f848faSopenharmony_ci *  - This function can be called multiple times in a row.
2437f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2438f9f848faSopenharmony_civoid
2439f9f848faSopenharmony_ciusbd_transfer_enqueue(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
2440f9f848faSopenharmony_ci{
2441f9f848faSopenharmony_ci	uint32_t int_save;
2442f9f848faSopenharmony_ci	/*
2443f9f848faSopenharmony_ci	 * Insert the USB transfer into the queue, if it is not
2444f9f848faSopenharmony_ci	 * already on a USB transfer queue:
2445f9f848faSopenharmony_ci	 */
2446f9f848faSopenharmony_ci	LOS_SpinLockSave(&g_usb_wait_queue_spinlock, &int_save);
2447f9f848faSopenharmony_ci	if (xfer->wait_queue == NULL) {
2448f9f848faSopenharmony_ci		xfer->wait_queue = pq;
2449f9f848faSopenharmony_ci		TAILQ_INSERT_TAIL(&pq->head, xfer, wait_entry);
2450f9f848faSopenharmony_ci	}
2451f9f848faSopenharmony_ci	LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
2452f9f848faSopenharmony_ci}
2453f9f848faSopenharmony_ci
2454f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2455f9f848faSopenharmony_ci *	usbd_transfer_done
2456f9f848faSopenharmony_ci *
2457f9f848faSopenharmony_ci *  - This function is used to remove an USB transfer from the busdma,
2458f9f848faSopenharmony_ci *  pipe or interrupt queue.
2459f9f848faSopenharmony_ci *
2460f9f848faSopenharmony_ci *  - This function is used to queue the USB transfer on the done
2461f9f848faSopenharmony_ci *  queue.
2462f9f848faSopenharmony_ci *
2463f9f848faSopenharmony_ci *  - This function is used to stop any USB transfer timeouts.
2464f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2465f9f848faSopenharmony_civoid
2466f9f848faSopenharmony_ciusbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
2467f9f848faSopenharmony_ci{
2468f9f848faSopenharmony_ci	struct usb_xfer_root *info = xfer->xroot;
2469f9f848faSopenharmony_ci
2470f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED);
2471f9f848faSopenharmony_ci
2472f9f848faSopenharmony_ci	DPRINTF("err=%s\n", usbd_errstr(error));
2473f9f848faSopenharmony_ci
2474f9f848faSopenharmony_ci	/*
2475f9f848faSopenharmony_ci	 * If we are not transferring then just return.
2476f9f848faSopenharmony_ci	 * This can happen during transfer cancel.
2477f9f848faSopenharmony_ci	 */
2478f9f848faSopenharmony_ci	if (!xfer->flags_int.transferring) {
2479f9f848faSopenharmony_ci		DPRINTF("not transferring\n");
2480f9f848faSopenharmony_ci		/* end of control transfer, if any */
2481f9f848faSopenharmony_ci		xfer->flags_int.control_act = 0;
2482f9f848faSopenharmony_ci		return;
2483f9f848faSopenharmony_ci	}
2484f9f848faSopenharmony_ci	/* only set transfer error, if not already set */
2485f9f848faSopenharmony_ci	if (xfer->error == USB_ERR_NORMAL_COMPLETION)
2486f9f848faSopenharmony_ci		xfer->error = error;
2487f9f848faSopenharmony_ci
2488f9f848faSopenharmony_ci	/* stop any callouts */
2489f9f848faSopenharmony_ci	usb_callout_stop(&xfer->timeout_handle);
2490f9f848faSopenharmony_ci
2491f9f848faSopenharmony_ci	/*
2492f9f848faSopenharmony_ci	 * If we are waiting on a queue, just remove the USB transfer
2493f9f848faSopenharmony_ci	 * from the queue, if any. We should have the required locks
2494f9f848faSopenharmony_ci	 * locked to do the remove when this function is called.
2495f9f848faSopenharmony_ci	 */
2496f9f848faSopenharmony_ci	usbd_transfer_dequeue(xfer);
2497f9f848faSopenharmony_ci
2498f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
2499f9f848faSopenharmony_ci	if (mtx_owned(info->xfer_mtx)) {
2500f9f848faSopenharmony_ci		struct usb_xfer_queue *pq;
2501f9f848faSopenharmony_ci
2502f9f848faSopenharmony_ci		/*
2503f9f848faSopenharmony_ci		 * If the private USB lock is not locked, then we assume
2504f9f848faSopenharmony_ci		 * that the BUS-DMA load stage has been passed:
2505f9f848faSopenharmony_ci		 */
2506f9f848faSopenharmony_ci		pq = &info->dma_q;
2507f9f848faSopenharmony_ci
2508f9f848faSopenharmony_ci		if (pq->curr == xfer) {
2509f9f848faSopenharmony_ci			/* start the next BUS-DMA load, if any */
2510f9f848faSopenharmony_ci			usb_command_wrapper(pq, NULL);
2511f9f848faSopenharmony_ci		}
2512f9f848faSopenharmony_ci	}
2513f9f848faSopenharmony_ci#endif
2514f9f848faSopenharmony_ci	/* keep some statistics */
2515f9f848faSopenharmony_ci	if (xfer->error == USB_ERR_CANCELLED) {
2516f9f848faSopenharmony_ci		info->udev->stats_cancelled.uds_requests
2517f9f848faSopenharmony_ci		    [xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
2518f9f848faSopenharmony_ci	} else if (xfer->error != USB_ERR_NORMAL_COMPLETION) {
2519f9f848faSopenharmony_ci		info->udev->stats_err.uds_requests
2520f9f848faSopenharmony_ci		    [xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
2521f9f848faSopenharmony_ci	} else {
2522f9f848faSopenharmony_ci		info->udev->stats_ok.uds_requests
2523f9f848faSopenharmony_ci		    [xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
2524f9f848faSopenharmony_ci	}
2525f9f848faSopenharmony_ci
2526f9f848faSopenharmony_ci	/* call the USB transfer callback */
2527f9f848faSopenharmony_ci	usbd_callback_ss_done_defer(xfer);
2528f9f848faSopenharmony_ci}
2529f9f848faSopenharmony_ci
2530f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2531f9f848faSopenharmony_ci *	usbd_transfer_start_cb
2532f9f848faSopenharmony_ci *
2533f9f848faSopenharmony_ci * This function is called to start the USB transfer when
2534f9f848faSopenharmony_ci * "xfer->interval" is greater than zero, and and the endpoint type is
2535f9f848faSopenharmony_ci * BULK or CONTROL.
2536f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2537f9f848faSopenharmony_cistatic void
2538f9f848faSopenharmony_ciusbd_transfer_start_cb(void *arg)
2539f9f848faSopenharmony_ci{
2540f9f848faSopenharmony_ci	struct usb_xfer *xfer = arg;
2541f9f848faSopenharmony_ci	struct usb_endpoint *ep = xfer->endpoint;
2542f9f848faSopenharmony_ci
2543f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
2544f9f848faSopenharmony_ci
2545f9f848faSopenharmony_ci	DPRINTF("start\n");
2546f9f848faSopenharmony_ci
2547f9f848faSopenharmony_ci#if USB_HAVE_PF
2548f9f848faSopenharmony_ci	usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
2549f9f848faSopenharmony_ci#endif
2550f9f848faSopenharmony_ci
2551f9f848faSopenharmony_ci	/* the transfer can now be cancelled */
2552f9f848faSopenharmony_ci	xfer->flags_int.can_cancel_immed = 1;
2553f9f848faSopenharmony_ci
2554f9f848faSopenharmony_ci	/* start USB transfer, if no error */
2555f9f848faSopenharmony_ci	if (xfer->error == 0)
2556f9f848faSopenharmony_ci		(ep->methods->start) (xfer);
2557f9f848faSopenharmony_ci
2558f9f848faSopenharmony_ci	/* check for transfer error */
2559f9f848faSopenharmony_ci	if (xfer->error) {
2560f9f848faSopenharmony_ci		/* some error has happened */
2561f9f848faSopenharmony_ci		usbd_transfer_done(xfer, (usb_error_t)0);
2562f9f848faSopenharmony_ci	}
2563f9f848faSopenharmony_ci}
2564f9f848faSopenharmony_ci
2565f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2566f9f848faSopenharmony_ci *	usbd_xfer_set_stall
2567f9f848faSopenharmony_ci *
2568f9f848faSopenharmony_ci * This function is used to set the stall flag outside the
2569f9f848faSopenharmony_ci * callback. This function is NULL safe.
2570f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2571f9f848faSopenharmony_civoid
2572f9f848faSopenharmony_ciusbd_xfer_set_stall(struct usb_xfer *xfer)
2573f9f848faSopenharmony_ci{
2574f9f848faSopenharmony_ci	if (xfer == NULL) {
2575f9f848faSopenharmony_ci		/* tearing down */
2576f9f848faSopenharmony_ci		return;
2577f9f848faSopenharmony_ci	}
2578f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
2579f9f848faSopenharmony_ci
2580f9f848faSopenharmony_ci	/* avoid any races by locking the USB mutex */
2581f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
2582f9f848faSopenharmony_ci	xfer->flags.stall_pipe = 1;
2583f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
2584f9f848faSopenharmony_ci}
2585f9f848faSopenharmony_ci
2586f9f848faSopenharmony_ciint
2587f9f848faSopenharmony_ciusbd_xfer_is_stalled(struct usb_xfer *xfer)
2588f9f848faSopenharmony_ci{
2589f9f848faSopenharmony_ci	return (xfer->endpoint->is_stalled);
2590f9f848faSopenharmony_ci}
2591f9f848faSopenharmony_ci
2592f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2593f9f848faSopenharmony_ci *	usbd_transfer_clear_stall
2594f9f848faSopenharmony_ci *
2595f9f848faSopenharmony_ci * This function is used to clear the stall flag outside the
2596f9f848faSopenharmony_ci * callback. This function is NULL safe.
2597f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2598f9f848faSopenharmony_civoid
2599f9f848faSopenharmony_ciusbd_transfer_clear_stall(struct usb_xfer *xfer)
2600f9f848faSopenharmony_ci{
2601f9f848faSopenharmony_ci	if (xfer == NULL) {
2602f9f848faSopenharmony_ci		/* tearing down */
2603f9f848faSopenharmony_ci		return;
2604f9f848faSopenharmony_ci	}
2605f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
2606f9f848faSopenharmony_ci
2607f9f848faSopenharmony_ci	/* avoid any races by locking the USB mutex */
2608f9f848faSopenharmony_ci	USB_BUS_LOCK(xfer->xroot->bus);
2609f9f848faSopenharmony_ci
2610f9f848faSopenharmony_ci	xfer->flags.stall_pipe = 0;
2611f9f848faSopenharmony_ci
2612f9f848faSopenharmony_ci	USB_BUS_UNLOCK(xfer->xroot->bus);
2613f9f848faSopenharmony_ci}
2614f9f848faSopenharmony_ci
2615f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2616f9f848faSopenharmony_ci *	usbd_pipe_start
2617f9f848faSopenharmony_ci *
2618f9f848faSopenharmony_ci * This function is used to add an USB transfer to the pipe transfer list.
2619f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2620f9f848faSopenharmony_civoid
2621f9f848faSopenharmony_ciusbd_pipe_start(struct usb_xfer_queue *pq)
2622f9f848faSopenharmony_ci{
2623f9f848faSopenharmony_ci	struct usb_endpoint *ep;
2624f9f848faSopenharmony_ci	struct usb_xfer *xfer;
2625f9f848faSopenharmony_ci	uint8_t type;
2626f9f848faSopenharmony_ci
2627f9f848faSopenharmony_ci	xfer = pq->curr;
2628f9f848faSopenharmony_ci	ep = xfer->endpoint;
2629f9f848faSopenharmony_ci
2630f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
2631f9f848faSopenharmony_ci
2632f9f848faSopenharmony_ci	/*
2633f9f848faSopenharmony_ci	 * If the endpoint is already stalled we do nothing !
2634f9f848faSopenharmony_ci	 */
2635f9f848faSopenharmony_ci	if (ep->is_stalled) {
2636f9f848faSopenharmony_ci		DPRINTFN(1, "is_stalled\n");
2637f9f848faSopenharmony_ci		return;
2638f9f848faSopenharmony_ci	}
2639f9f848faSopenharmony_ci	/*
2640f9f848faSopenharmony_ci	 * Check if we are supposed to stall the endpoint:
2641f9f848faSopenharmony_ci	 */
2642f9f848faSopenharmony_ci	if (xfer->flags.stall_pipe) {
2643f9f848faSopenharmony_ci		struct usb_device *udev;
2644f9f848faSopenharmony_ci		struct usb_xfer_root *info;
2645f9f848faSopenharmony_ci
2646f9f848faSopenharmony_ci		/* clear stall command */
2647f9f848faSopenharmony_ci		xfer->flags.stall_pipe = 0;
2648f9f848faSopenharmony_ci
2649f9f848faSopenharmony_ci		/* get pointer to USB device */
2650f9f848faSopenharmony_ci		info = xfer->xroot;
2651f9f848faSopenharmony_ci		udev = info->udev;
2652f9f848faSopenharmony_ci
2653f9f848faSopenharmony_ci		/*
2654f9f848faSopenharmony_ci		 * Only stall BULK and INTERRUPT endpoints.
2655f9f848faSopenharmony_ci		 */
2656f9f848faSopenharmony_ci		type = (ep->edesc->bmAttributes & UE_XFERTYPE);
2657f9f848faSopenharmony_ci		if ((type == UE_BULK) ||
2658f9f848faSopenharmony_ci		    (type == UE_INTERRUPT)) {
2659f9f848faSopenharmony_ci			uint8_t did_stall;
2660f9f848faSopenharmony_ci
2661f9f848faSopenharmony_ci			did_stall = 1;
2662f9f848faSopenharmony_ci
2663f9f848faSopenharmony_ci			if (udev->flags.usb_mode == USB_MODE_DEVICE) {
2664f9f848faSopenharmony_ci				(udev->bus->methods->set_stall) (
2665f9f848faSopenharmony_ci				    udev, ep, &did_stall);
2666f9f848faSopenharmony_ci			} else if (udev->ctrl_xfer[1]) {
2667f9f848faSopenharmony_ci				info = udev->ctrl_xfer[1]->xroot;
2668f9f848faSopenharmony_ci				(void)usb_proc_msignal(
2669f9f848faSopenharmony_ci				    USB_BUS_CS_PROC(info->bus),
2670f9f848faSopenharmony_ci				    &udev->cs_msg[0], &udev->cs_msg[1]);
2671f9f848faSopenharmony_ci			} else {
2672f9f848faSopenharmony_ci				/* should not happen */
2673f9f848faSopenharmony_ci				DPRINTFN(0, "No stall handler\n");
2674f9f848faSopenharmony_ci			}
2675f9f848faSopenharmony_ci			/*
2676f9f848faSopenharmony_ci			 * Check if we should stall. Some USB hardware
2677f9f848faSopenharmony_ci			 * handles set- and clear-stall in hardware.
2678f9f848faSopenharmony_ci			 */
2679f9f848faSopenharmony_ci			if (did_stall) {
2680f9f848faSopenharmony_ci				/*
2681f9f848faSopenharmony_ci				 * The transfer will be continued when
2682f9f848faSopenharmony_ci				 * the clear-stall control endpoint
2683f9f848faSopenharmony_ci				 * message is received.
2684f9f848faSopenharmony_ci				 */
2685f9f848faSopenharmony_ci				ep->is_stalled = 1;
2686f9f848faSopenharmony_ci				DPRINTFN(1, "did_stall\n");
2687f9f848faSopenharmony_ci				return;
2688f9f848faSopenharmony_ci			}
2689f9f848faSopenharmony_ci		} else if (type == UE_ISOCHRONOUS) {
2690f9f848faSopenharmony_ci			/*
2691f9f848faSopenharmony_ci			 * Make sure any FIFO overflow or other FIFO
2692f9f848faSopenharmony_ci			 * error conditions go away by resetting the
2693f9f848faSopenharmony_ci			 * endpoint FIFO through the clear stall
2694f9f848faSopenharmony_ci			 * method.
2695f9f848faSopenharmony_ci			 */
2696f9f848faSopenharmony_ci			if (udev->flags.usb_mode == USB_MODE_DEVICE) {
2697f9f848faSopenharmony_ci				(udev->bus->methods->clear_stall) (udev, ep);
2698f9f848faSopenharmony_ci			}
2699f9f848faSopenharmony_ci		}
2700f9f848faSopenharmony_ci	}
2701f9f848faSopenharmony_ci	/* Set or clear stall complete - special case */
2702f9f848faSopenharmony_ci	if (xfer->nframes == 0) {
2703f9f848faSopenharmony_ci		/* we are complete */
2704f9f848faSopenharmony_ci		xfer->aframes = 0;
2705f9f848faSopenharmony_ci		usbd_transfer_done(xfer, (usb_error_t)0);
2706f9f848faSopenharmony_ci		DPRINTFN(1, "nframes == 0\n");
2707f9f848faSopenharmony_ci		return;
2708f9f848faSopenharmony_ci	}
2709f9f848faSopenharmony_ci	/*
2710f9f848faSopenharmony_ci	 * Handled cases:
2711f9f848faSopenharmony_ci	 *
2712f9f848faSopenharmony_ci	 * 1) Start the first transfer queued.
2713f9f848faSopenharmony_ci	 *
2714f9f848faSopenharmony_ci	 * 2) Re-start the current USB transfer.
2715f9f848faSopenharmony_ci	 */
2716f9f848faSopenharmony_ci	/*
2717f9f848faSopenharmony_ci	 * Check if there should be any
2718f9f848faSopenharmony_ci	 * pre transfer start delay:
2719f9f848faSopenharmony_ci	 */
2720f9f848faSopenharmony_ci	if (xfer->interval > 0) {
2721f9f848faSopenharmony_ci		type = (ep->edesc->bmAttributes & UE_XFERTYPE);
2722f9f848faSopenharmony_ci		if ((type == UE_BULK) ||
2723f9f848faSopenharmony_ci		    (type == UE_CONTROL)) {
2724f9f848faSopenharmony_ci			usbd_transfer_timeout_ms(xfer,
2725f9f848faSopenharmony_ci			    &usbd_transfer_start_cb,
2726f9f848faSopenharmony_ci			    xfer->interval);
2727f9f848faSopenharmony_ci			DPRINTFN(1, "usbd_transfer_timeout_ms \n");
2728f9f848faSopenharmony_ci			return;
2729f9f848faSopenharmony_ci		}
2730f9f848faSopenharmony_ci	}
2731f9f848faSopenharmony_ci
2732f9f848faSopenharmony_ci	usbd_transfer_start_cb((void *)xfer);
2733f9f848faSopenharmony_ci}
2734f9f848faSopenharmony_ci
2735f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2736f9f848faSopenharmony_ci *	usbd_transfer_timeout_ms
2737f9f848faSopenharmony_ci *
2738f9f848faSopenharmony_ci * This function is used to setup a timeout on the given USB
2739f9f848faSopenharmony_ci * transfer. If the timeout has been deferred the callback given by
2740f9f848faSopenharmony_ci * "cb" will get called after "ms" milliseconds.
2741f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2742f9f848faSopenharmony_civoid
2743f9f848faSopenharmony_ciusbd_transfer_timeout_ms(struct usb_xfer *xfer,
2744f9f848faSopenharmony_ci    void (*cb) (void *arg), usb_timeout_t ms)
2745f9f848faSopenharmony_ci{
2746f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
2747f9f848faSopenharmony_ci
2748f9f848faSopenharmony_ci	/* defer delay */
2749f9f848faSopenharmony_ci	usb_callout_reset(&xfer->timeout_handle,
2750f9f848faSopenharmony_ci	    USB_MS_TO_TICKS(ms) + USB_CALLOUT_ZERO_TICKS, cb, xfer);
2751f9f848faSopenharmony_ci}
2752f9f848faSopenharmony_ci
2753f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2754f9f848faSopenharmony_ci *	usbd_callback_wrapper_sub
2755f9f848faSopenharmony_ci *
2756f9f848faSopenharmony_ci *  - This function will update variables in an USB transfer after
2757f9f848faSopenharmony_ci *  that the USB transfer is complete.
2758f9f848faSopenharmony_ci *
2759f9f848faSopenharmony_ci *  - This function is used to start the next USB transfer on the
2760f9f848faSopenharmony_ci *  ep transfer queue, if any.
2761f9f848faSopenharmony_ci *
2762f9f848faSopenharmony_ci * NOTE: In some special cases the USB transfer will not be removed from
2763f9f848faSopenharmony_ci * the pipe queue, but remain first. To enforce USB transfer removal call
2764f9f848faSopenharmony_ci * this function passing the error code "USB_ERR_CANCELLED".
2765f9f848faSopenharmony_ci *
2766f9f848faSopenharmony_ci * Return values:
2767f9f848faSopenharmony_ci * 0: Success.
2768f9f848faSopenharmony_ci * Else: The callback has been deferred.
2769f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2770f9f848faSopenharmony_cistatic uint8_t
2771f9f848faSopenharmony_ciusbd_callback_wrapper_sub(struct usb_xfer *xfer)
2772f9f848faSopenharmony_ci{
2773f9f848faSopenharmony_ci	struct usb_endpoint *ep;
2774f9f848faSopenharmony_ci	struct usb_bus *bus;
2775f9f848faSopenharmony_ci	usb_frcount_t x;
2776f9f848faSopenharmony_ci
2777f9f848faSopenharmony_ci	bus = xfer->xroot->bus;
2778f9f848faSopenharmony_ci
2779f9f848faSopenharmony_ci	if ((!xfer->flags_int.open) &&
2780f9f848faSopenharmony_ci	    (!xfer->flags_int.did_close)) {
2781f9f848faSopenharmony_ci		DPRINTF("close\n");
2782f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
2783f9f848faSopenharmony_ci		(xfer->endpoint->methods->close) (xfer);
2784f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
2785f9f848faSopenharmony_ci		/* only close once */
2786f9f848faSopenharmony_ci		xfer->flags_int.did_close = 1;
2787f9f848faSopenharmony_ci		return (1);		/* wait for new callback */
2788f9f848faSopenharmony_ci	}
2789f9f848faSopenharmony_ci	/*
2790f9f848faSopenharmony_ci	 * If we have a non-hardware induced error we
2791f9f848faSopenharmony_ci	 * need to do the DMA delay!
2792f9f848faSopenharmony_ci	 */
2793f9f848faSopenharmony_ci	if ((xfer->error != 0) && (!xfer->flags_int.did_dma_delay) &&
2794f9f848faSopenharmony_ci	    ((xfer->error == USB_ERR_CANCELLED) ||
2795f9f848faSopenharmony_ci	    (xfer->error == USB_ERR_TIMEOUT) ||
2796f9f848faSopenharmony_ci	    (bus->methods->start_dma_delay != NULL))) {
2797f9f848faSopenharmony_ci		usb_timeout_t temp;
2798f9f848faSopenharmony_ci
2799f9f848faSopenharmony_ci		/* only delay once */
2800f9f848faSopenharmony_ci		xfer->flags_int.did_dma_delay = 1;
2801f9f848faSopenharmony_ci
2802f9f848faSopenharmony_ci		/* we can not cancel this delay */
2803f9f848faSopenharmony_ci		xfer->flags_int.can_cancel_immed = 0;
2804f9f848faSopenharmony_ci
2805f9f848faSopenharmony_ci		temp = usbd_get_dma_delay(xfer->xroot->udev);
2806f9f848faSopenharmony_ci
2807f9f848faSopenharmony_ci		DPRINTFN(3, "DMA delay, %u ms, "
2808f9f848faSopenharmony_ci		    "on %p\n", temp, xfer);
2809f9f848faSopenharmony_ci
2810f9f848faSopenharmony_ci		if (temp != 0) {
2811f9f848faSopenharmony_ci			USB_BUS_LOCK(bus);
2812f9f848faSopenharmony_ci			/*
2813f9f848faSopenharmony_ci			 * Some hardware solutions have dedicated
2814f9f848faSopenharmony_ci			 * events when it is safe to free DMA'ed
2815f9f848faSopenharmony_ci			 * memory. For the other hardware platforms we
2816f9f848faSopenharmony_ci			 * use a static delay.
2817f9f848faSopenharmony_ci			 */
2818f9f848faSopenharmony_ci			if (bus->methods->start_dma_delay != NULL) {
2819f9f848faSopenharmony_ci				(bus->methods->start_dma_delay) (xfer);
2820f9f848faSopenharmony_ci			} else {
2821f9f848faSopenharmony_ci				usbd_transfer_timeout_ms(xfer,
2822f9f848faSopenharmony_ci				    (void (*)(void *))&usb_dma_delay_done_cb,
2823f9f848faSopenharmony_ci				    temp);
2824f9f848faSopenharmony_ci			}
2825f9f848faSopenharmony_ci			USB_BUS_UNLOCK(bus);
2826f9f848faSopenharmony_ci			return (1);	/* wait for new callback */
2827f9f848faSopenharmony_ci		}
2828f9f848faSopenharmony_ci	}
2829f9f848faSopenharmony_ci	/* check actual number of frames */
2830f9f848faSopenharmony_ci	if (xfer->aframes > xfer->nframes) {
2831f9f848faSopenharmony_ci		if (xfer->error == 0) {
2832f9f848faSopenharmony_ci			panic("%s: actual number of frames, %d, is "
2833f9f848faSopenharmony_ci			    "greater than initial number of frames, %d\n",
2834f9f848faSopenharmony_ci			    __FUNCTION__, xfer->aframes, xfer->nframes);
2835f9f848faSopenharmony_ci		} else {
2836f9f848faSopenharmony_ci			/* just set some valid value */
2837f9f848faSopenharmony_ci			xfer->aframes = xfer->nframes;
2838f9f848faSopenharmony_ci		}
2839f9f848faSopenharmony_ci	}
2840f9f848faSopenharmony_ci	/* compute actual length */
2841f9f848faSopenharmony_ci	xfer->actlen = 0;
2842f9f848faSopenharmony_ci
2843f9f848faSopenharmony_ci	for (x = 0; x != xfer->aframes; x++) {
2844f9f848faSopenharmony_ci		xfer->actlen += xfer->frlengths[x];
2845f9f848faSopenharmony_ci	}
2846f9f848faSopenharmony_ci
2847f9f848faSopenharmony_ci	/*
2848f9f848faSopenharmony_ci	 * Frames that were not transferred get zero actual length in
2849f9f848faSopenharmony_ci	 * case the USB device driver does not check the actual number
2850f9f848faSopenharmony_ci	 * of frames transferred, "xfer->aframes":
2851f9f848faSopenharmony_ci	 */
2852f9f848faSopenharmony_ci	for (; x < xfer->nframes; x++) {
2853f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, x, 0);
2854f9f848faSopenharmony_ci	}
2855f9f848faSopenharmony_ci
2856f9f848faSopenharmony_ci	/* check actual length */
2857f9f848faSopenharmony_ci	if (xfer->actlen > xfer->sumlen) {
2858f9f848faSopenharmony_ci		if (xfer->error == 0) {
2859f9f848faSopenharmony_ci			panic("%s: actual length, %d, is greater than "
2860f9f848faSopenharmony_ci			    "initial length, %d\n",
2861f9f848faSopenharmony_ci			    __FUNCTION__, xfer->actlen, xfer->sumlen);
2862f9f848faSopenharmony_ci		} else {
2863f9f848faSopenharmony_ci			/* just set some valid value */
2864f9f848faSopenharmony_ci			xfer->actlen = xfer->sumlen;
2865f9f848faSopenharmony_ci		}
2866f9f848faSopenharmony_ci	}
2867f9f848faSopenharmony_ci	DPRINTFN(1, "xfer=%p endpoint=%p sts=%d alen=%d, slen=%d, afrm=%d, nfrm=%d\n",
2868f9f848faSopenharmony_ci	    xfer, xfer->endpoint, xfer->error, xfer->actlen, xfer->sumlen,
2869f9f848faSopenharmony_ci	    xfer->aframes, xfer->nframes);
2870f9f848faSopenharmony_ci
2871f9f848faSopenharmony_ci	if (xfer->error) {
2872f9f848faSopenharmony_ci		/* end of control transfer, if any */
2873f9f848faSopenharmony_ci		xfer->flags_int.control_act = 0;
2874f9f848faSopenharmony_ci
2875f9f848faSopenharmony_ci#if USB_HAVE_TT_SUPPORT
2876f9f848faSopenharmony_ci		switch (xfer->error) {
2877f9f848faSopenharmony_ci		case USB_ERR_NORMAL_COMPLETION:
2878f9f848faSopenharmony_ci		case USB_ERR_SHORT_XFER:
2879f9f848faSopenharmony_ci		case USB_ERR_STALLED:
2880f9f848faSopenharmony_ci		case USB_ERR_CANCELLED:
2881f9f848faSopenharmony_ci			/* nothing to do */
2882f9f848faSopenharmony_ci			break;
2883f9f848faSopenharmony_ci		default:
2884f9f848faSopenharmony_ci			/* try to reset the TT, if any */
2885f9f848faSopenharmony_ci			USB_BUS_LOCK(bus);
2886f9f848faSopenharmony_ci			uhub_tt_buffer_reset_async_locked(xfer->xroot->udev, xfer->endpoint);
2887f9f848faSopenharmony_ci			USB_BUS_UNLOCK(bus);
2888f9f848faSopenharmony_ci			break;
2889f9f848faSopenharmony_ci		}
2890f9f848faSopenharmony_ci#endif
2891f9f848faSopenharmony_ci		/* check if we should block the execution queue */
2892f9f848faSopenharmony_ci		if ((xfer->error != USB_ERR_CANCELLED) &&
2893f9f848faSopenharmony_ci		    (xfer->flags.pipe_bof)) {
2894f9f848faSopenharmony_ci			DPRINTFN(2, "xfer=%p: Block On Failure "
2895f9f848faSopenharmony_ci			    "on endpoint=%p\n", xfer, xfer->endpoint);
2896f9f848faSopenharmony_ci			goto done;
2897f9f848faSopenharmony_ci		}
2898f9f848faSopenharmony_ci	} else {
2899f9f848faSopenharmony_ci		/* check for short transfers */
2900f9f848faSopenharmony_ci		if (xfer->actlen < xfer->sumlen) {
2901f9f848faSopenharmony_ci			/* end of control transfer, if any */
2902f9f848faSopenharmony_ci			xfer->flags_int.control_act = 0;
2903f9f848faSopenharmony_ci
2904f9f848faSopenharmony_ci			if (!xfer->flags_int.short_xfer_ok) {
2905f9f848faSopenharmony_ci				xfer->error = USB_ERR_SHORT_XFER;
2906f9f848faSopenharmony_ci				if (xfer->flags.pipe_bof) {
2907f9f848faSopenharmony_ci					DPRINTFN(2, "xfer=%p: Block On Failure on "
2908f9f848faSopenharmony_ci					    "Short Transfer on endpoint %p.\n",
2909f9f848faSopenharmony_ci					    xfer, xfer->endpoint);
2910f9f848faSopenharmony_ci					goto done;
2911f9f848faSopenharmony_ci				}
2912f9f848faSopenharmony_ci			}
2913f9f848faSopenharmony_ci		} else {
2914f9f848faSopenharmony_ci			/*
2915f9f848faSopenharmony_ci			 * Check if we are in the middle of a
2916f9f848faSopenharmony_ci			 * control transfer:
2917f9f848faSopenharmony_ci			 */
2918f9f848faSopenharmony_ci			if (xfer->flags_int.control_act) {
2919f9f848faSopenharmony_ci				DPRINTFN(5, "xfer=%p: Control transfer "
2920f9f848faSopenharmony_ci				    "active on endpoint=%p\n", xfer, xfer->endpoint);
2921f9f848faSopenharmony_ci				goto done;
2922f9f848faSopenharmony_ci			}
2923f9f848faSopenharmony_ci		}
2924f9f848faSopenharmony_ci	}
2925f9f848faSopenharmony_ci
2926f9f848faSopenharmony_ci	ep = xfer->endpoint;
2927f9f848faSopenharmony_ci
2928f9f848faSopenharmony_ci	/*
2929f9f848faSopenharmony_ci	 * If the current USB transfer is completing we need to start the
2930f9f848faSopenharmony_ci	 * next one:
2931f9f848faSopenharmony_ci	 */
2932f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
2933f9f848faSopenharmony_ci	if (ep->endpoint_q[xfer->stream_id].curr == xfer) {
2934f9f848faSopenharmony_ci		usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], NULL);
2935f9f848faSopenharmony_ci
2936f9f848faSopenharmony_ci		if ((ep->endpoint_q[xfer->stream_id].curr != NULL) ||
2937f9f848faSopenharmony_ci		    (TAILQ_FIRST(&ep->endpoint_q[xfer->stream_id].head) != NULL)) {
2938f9f848faSopenharmony_ci			/* there is another USB transfer waiting */
2939f9f848faSopenharmony_ci		} else {
2940f9f848faSopenharmony_ci			/* this is the last USB transfer */
2941f9f848faSopenharmony_ci			/* clear isochronous sync flag */
2942f9f848faSopenharmony_ci			xfer->endpoint->is_synced = 0;
2943f9f848faSopenharmony_ci		}
2944f9f848faSopenharmony_ci	}
2945f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
2946f9f848faSopenharmony_cidone:
2947f9f848faSopenharmony_ci	return (0);
2948f9f848faSopenharmony_ci}
2949f9f848faSopenharmony_ci
2950f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
2951f9f848faSopenharmony_ci *	usb_command_wrapper
2952f9f848faSopenharmony_ci *
2953f9f848faSopenharmony_ci * This function is used to execute commands non-recursivly on an USB
2954f9f848faSopenharmony_ci * transfer.
2955f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
2956f9f848faSopenharmony_civoid
2957f9f848faSopenharmony_ciusb_command_wrapper(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
2958f9f848faSopenharmony_ci{
2959f9f848faSopenharmony_ci	uint32_t int_save;
2960f9f848faSopenharmony_ci
2961f9f848faSopenharmony_ci	if (xfer) {
2962f9f848faSopenharmony_ci		/*
2963f9f848faSopenharmony_ci		 * If the transfer is not already processing,
2964f9f848faSopenharmony_ci		 * queue it!
2965f9f848faSopenharmony_ci		 */
2966f9f848faSopenharmony_ci		if (pq->curr != xfer) {
2967f9f848faSopenharmony_ci			usbd_transfer_enqueue(pq, xfer);
2968f9f848faSopenharmony_ci			if (pq->curr != NULL) {
2969f9f848faSopenharmony_ci				/* something is already processing */
2970f9f848faSopenharmony_ci				DPRINTFN(6, "busy %p\n", pq->curr);
2971f9f848faSopenharmony_ci				return;
2972f9f848faSopenharmony_ci			}
2973f9f848faSopenharmony_ci		}
2974f9f848faSopenharmony_ci	} else {
2975f9f848faSopenharmony_ci		/* Get next element in queue */
2976f9f848faSopenharmony_ci		pq->curr = NULL;
2977f9f848faSopenharmony_ci	}
2978f9f848faSopenharmony_ci
2979f9f848faSopenharmony_ci	if (!pq->recurse_1) {
2980f9f848faSopenharmony_ci		do {
2981f9f848faSopenharmony_ci
2982f9f848faSopenharmony_ci			LOS_SpinLockSave(&g_usb_wait_queue_spinlock, &int_save);
2983f9f848faSopenharmony_ci			/* set both recurse flags */
2984f9f848faSopenharmony_ci			pq->recurse_1 = 1;
2985f9f848faSopenharmony_ci			pq->recurse_2 = 1;
2986f9f848faSopenharmony_ci
2987f9f848faSopenharmony_ci			if (pq->curr == NULL) {
2988f9f848faSopenharmony_ci				xfer = TAILQ_FIRST(&pq->head);
2989f9f848faSopenharmony_ci				if (xfer) {
2990f9f848faSopenharmony_ci					TAILQ_REMOVE(&pq->head, xfer,
2991f9f848faSopenharmony_ci					    wait_entry);
2992f9f848faSopenharmony_ci					xfer->wait_queue = NULL;
2993f9f848faSopenharmony_ci					pq->curr = xfer;
2994f9f848faSopenharmony_ci				} else {
2995f9f848faSopenharmony_ci					/* clear first recurse flag */
2996f9f848faSopenharmony_ci					pq->recurse_1 = 0;
2997f9f848faSopenharmony_ci					LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
2998f9f848faSopenharmony_ci					break;
2999f9f848faSopenharmony_ci				}
3000f9f848faSopenharmony_ci			}
3001f9f848faSopenharmony_ci			LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
3002f9f848faSopenharmony_ci
3003f9f848faSopenharmony_ci			DPRINTFN(6, "cb %p (enter)\n", pq->curr);
3004f9f848faSopenharmony_ci			(pq->command) (pq);
3005f9f848faSopenharmony_ci			DPRINTFN(6, "cb %p (leave)\n", pq->curr);
3006f9f848faSopenharmony_ci
3007f9f848faSopenharmony_ci			LOS_SpinLockSave(&g_usb_wait_queue_spinlock, &int_save);
3008f9f848faSopenharmony_ci			if (pq->recurse_2) {
3009f9f848faSopenharmony_ci				/* clear first recurse flag */
3010f9f848faSopenharmony_ci				pq->recurse_1 = 0;
3011f9f848faSopenharmony_ci				LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
3012f9f848faSopenharmony_ci				break;
3013f9f848faSopenharmony_ci			}
3014f9f848faSopenharmony_ci			LOS_SpinUnlockRestore(&g_usb_wait_queue_spinlock, int_save);
3015f9f848faSopenharmony_ci		} while (1);
3016f9f848faSopenharmony_ci
3017f9f848faSopenharmony_ci	} else {
3018f9f848faSopenharmony_ci		/* clear second recurse flag */
3019f9f848faSopenharmony_ci		pq->recurse_2 = 0;
3020f9f848faSopenharmony_ci	}
3021f9f848faSopenharmony_ci}
3022f9f848faSopenharmony_ci
3023f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
3024f9f848faSopenharmony_ci *	usbd_ctrl_transfer_setup
3025f9f848faSopenharmony_ci *
3026f9f848faSopenharmony_ci * This function is used to setup the default USB control endpoint
3027f9f848faSopenharmony_ci * transfer.
3028f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
3029f9f848faSopenharmony_civoid
3030f9f848faSopenharmony_ciusbd_ctrl_transfer_setup(struct usb_device *udev)
3031f9f848faSopenharmony_ci{
3032f9f848faSopenharmony_ci	struct usb_xfer *xfer;
3033f9f848faSopenharmony_ci	uint8_t no_resetup;
3034f9f848faSopenharmony_ci	uint8_t iface_index;
3035f9f848faSopenharmony_ci
3036f9f848faSopenharmony_ci	/* check for root HUB */
3037f9f848faSopenharmony_ci	if (udev->parent_hub == NULL)
3038f9f848faSopenharmony_ci		return;
3039f9f848faSopenharmony_cirepeat:
3040f9f848faSopenharmony_ci
3041f9f848faSopenharmony_ci	xfer = udev->ctrl_xfer[0];
3042f9f848faSopenharmony_ci	if (xfer) {
3043f9f848faSopenharmony_ci		USB_XFER_LOCK(xfer);
3044f9f848faSopenharmony_ci		no_resetup =
3045f9f848faSopenharmony_ci		    ((xfer->address == udev->address) &&
3046f9f848faSopenharmony_ci		    (udev->ctrl_ep_desc.wMaxPacketSize[0] ==
3047f9f848faSopenharmony_ci		    udev->ddesc.bMaxPacketSize));
3048f9f848faSopenharmony_ci		if (udev->flags.usb_mode == USB_MODE_DEVICE) {
3049f9f848faSopenharmony_ci			if (no_resetup) {
3050f9f848faSopenharmony_ci				/*
3051f9f848faSopenharmony_ci				 * NOTE: checking "xfer->address" and
3052f9f848faSopenharmony_ci				 * starting the USB transfer must be
3053f9f848faSopenharmony_ci				 * atomic!
3054f9f848faSopenharmony_ci				 */
3055f9f848faSopenharmony_ci				usbd_transfer_start(xfer);
3056f9f848faSopenharmony_ci			}
3057f9f848faSopenharmony_ci		}
3058f9f848faSopenharmony_ci		USB_XFER_UNLOCK(xfer);
3059f9f848faSopenharmony_ci	} else {
3060f9f848faSopenharmony_ci		no_resetup = 0;
3061f9f848faSopenharmony_ci	}
3062f9f848faSopenharmony_ci
3063f9f848faSopenharmony_ci	if (no_resetup) {
3064f9f848faSopenharmony_ci		/*
3065f9f848faSopenharmony_ci		 * All parameters are exactly the same like before.
3066f9f848faSopenharmony_ci		 * Just return.
3067f9f848faSopenharmony_ci		 */
3068f9f848faSopenharmony_ci		return;
3069f9f848faSopenharmony_ci	}
3070f9f848faSopenharmony_ci	/*
3071f9f848faSopenharmony_ci	 * Update wMaxPacketSize for the default control endpoint:
3072f9f848faSopenharmony_ci	 */
3073f9f848faSopenharmony_ci	udev->ctrl_ep_desc.wMaxPacketSize[0] =
3074f9f848faSopenharmony_ci	    udev->ddesc.bMaxPacketSize;
3075f9f848faSopenharmony_ci
3076f9f848faSopenharmony_ci	/*
3077f9f848faSopenharmony_ci	 * Unsetup any existing USB transfer:
3078f9f848faSopenharmony_ci	 */
3079f9f848faSopenharmony_ci	usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX);
3080f9f848faSopenharmony_ci
3081f9f848faSopenharmony_ci	/*
3082f9f848faSopenharmony_ci	 * Reset clear stall error counter.
3083f9f848faSopenharmony_ci	 */
3084f9f848faSopenharmony_ci	udev->clear_stall_errors = 0;
3085f9f848faSopenharmony_ci
3086f9f848faSopenharmony_ci	/*
3087f9f848faSopenharmony_ci	 * Try to setup a new USB transfer for the
3088f9f848faSopenharmony_ci	 * default control endpoint:
3089f9f848faSopenharmony_ci	 */
3090f9f848faSopenharmony_ci	iface_index = 0;
3091f9f848faSopenharmony_ci	if (usbd_transfer_setup(udev, &iface_index,
3092f9f848faSopenharmony_ci	    udev->ctrl_xfer, udev->bus->control_ep_quirk ?
3093f9f848faSopenharmony_ci	    usb_control_ep_quirk_cfg : usb_control_ep_cfg, USB_CTRL_XFER_MAX, NULL,
3094f9f848faSopenharmony_ci	    &udev->device_mtx)) {
3095f9f848faSopenharmony_ci		DPRINTFN(0, "could not setup default "
3096f9f848faSopenharmony_ci		    "USB transfer\n");
3097f9f848faSopenharmony_ci	} else {
3098f9f848faSopenharmony_ci		goto repeat;
3099f9f848faSopenharmony_ci	}
3100f9f848faSopenharmony_ci}
3101f9f848faSopenharmony_ci
3102f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
3103f9f848faSopenharmony_ci *	usbd_clear_data_toggle - factored out code
3104f9f848faSopenharmony_ci *
3105f9f848faSopenharmony_ci * NOTE: the intention of this function is not to reset the hardware
3106f9f848faSopenharmony_ci * data toggle.
3107f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
3108f9f848faSopenharmony_civoid
3109f9f848faSopenharmony_ciusbd_clear_stall_locked(struct usb_device *udev, struct usb_endpoint *ep)
3110f9f848faSopenharmony_ci{
3111f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
3112f9f848faSopenharmony_ci
3113f9f848faSopenharmony_ci	/* check that we have a valid case */
3114f9f848faSopenharmony_ci	if ((udev->flags.usb_mode == USB_MODE_HOST) &&
3115f9f848faSopenharmony_ci	    (udev->parent_hub != NULL) &&
3116f9f848faSopenharmony_ci	    (udev->bus->methods->clear_stall != NULL) &&
3117f9f848faSopenharmony_ci	    (ep->methods != NULL)) {
3118f9f848faSopenharmony_ci		(udev->bus->methods->clear_stall) (udev, ep);
3119f9f848faSopenharmony_ci	}
3120f9f848faSopenharmony_ci}
3121f9f848faSopenharmony_ci
3122f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
3123f9f848faSopenharmony_ci *	usbd_clear_data_toggle - factored out code
3124f9f848faSopenharmony_ci *
3125f9f848faSopenharmony_ci * NOTE: the intention of this function is not to reset the hardware
3126f9f848faSopenharmony_ci * data toggle on the USB device side.
3127f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
3128f9f848faSopenharmony_civoid
3129f9f848faSopenharmony_ciusbd_clear_data_toggle(struct usb_device *udev, struct usb_endpoint *ep)
3130f9f848faSopenharmony_ci{
3131f9f848faSopenharmony_ci	DPRINTFN(5, "udev=%p endpoint=%p\n", udev, ep);
3132f9f848faSopenharmony_ci
3133f9f848faSopenharmony_ci	USB_BUS_LOCK(udev->bus);
3134f9f848faSopenharmony_ci	ep->toggle_next = 0;
3135f9f848faSopenharmony_ci	/* some hardware needs a callback to clear the data toggle */
3136f9f848faSopenharmony_ci	usbd_clear_stall_locked(udev, ep);
3137f9f848faSopenharmony_ci	USB_BUS_UNLOCK(udev->bus);
3138f9f848faSopenharmony_ci}
3139f9f848faSopenharmony_ci
3140f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
3141f9f848faSopenharmony_ci *	usbd_clear_stall_callback - factored out clear stall callback
3142f9f848faSopenharmony_ci *
3143f9f848faSopenharmony_ci * Input parameters:
3144f9f848faSopenharmony_ci *  xfer1: Clear Stall Control Transfer
3145f9f848faSopenharmony_ci *  xfer2: Stalled USB Transfer
3146f9f848faSopenharmony_ci *
3147f9f848faSopenharmony_ci * This function is NULL safe.
3148f9f848faSopenharmony_ci *
3149f9f848faSopenharmony_ci * Return values:
3150f9f848faSopenharmony_ci *   0: In progress
3151f9f848faSopenharmony_ci *   Else: Finished
3152f9f848faSopenharmony_ci *
3153f9f848faSopenharmony_ci * Clear stall config example:
3154f9f848faSopenharmony_ci *
3155f9f848faSopenharmony_ci * static const struct usb_config my_clearstall =  {
3156f9f848faSopenharmony_ci *	.type = UE_CONTROL,
3157f9f848faSopenharmony_ci *	.endpoint = 0,
3158f9f848faSopenharmony_ci *	.direction = UE_DIR_ANY,
3159f9f848faSopenharmony_ci *	.interval = 50, //50 milliseconds
3160f9f848faSopenharmony_ci *	.bufsize = sizeof(struct usb_device_request),
3161f9f848faSopenharmony_ci *	.timeout = 1000, //1.000 seconds
3162f9f848faSopenharmony_ci *	.callback = &my_clear_stall_callback, // **
3163f9f848faSopenharmony_ci *	.usb_mode = USB_MODE_HOST,
3164f9f848faSopenharmony_ci * };
3165f9f848faSopenharmony_ci *
3166f9f848faSopenharmony_ci * ** "my_clear_stall_callback" calls "usbd_clear_stall_callback"
3167f9f848faSopenharmony_ci * passing the correct parameters.
3168f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
3169f9f848faSopenharmony_ciuint8_t
3170f9f848faSopenharmony_ciusbd_clear_stall_callback(struct usb_xfer *xfer1,
3171f9f848faSopenharmony_ci    struct usb_xfer *xfer2)
3172f9f848faSopenharmony_ci{
3173f9f848faSopenharmony_ci	struct usb_device_request req;
3174f9f848faSopenharmony_ci
3175f9f848faSopenharmony_ci	if (xfer2 == NULL) {
3176f9f848faSopenharmony_ci		/* looks like we are tearing down */
3177f9f848faSopenharmony_ci		DPRINTF("NULL input parameter\n");
3178f9f848faSopenharmony_ci		return (0);
3179f9f848faSopenharmony_ci	}
3180f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer1, MA_OWNED);
3181f9f848faSopenharmony_ci	USB_XFER_LOCK_ASSERT(xfer2, MA_OWNED);
3182f9f848faSopenharmony_ci
3183f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer1)) {
3184f9f848faSopenharmony_ci	case USB_ST_SETUP:
3185f9f848faSopenharmony_ci
3186f9f848faSopenharmony_ci		/*
3187f9f848faSopenharmony_ci		 * pre-clear the data toggle to DATA0 ("umass.c" and
3188f9f848faSopenharmony_ci		 * "ata-usb.c" depends on this)
3189f9f848faSopenharmony_ci		 */
3190f9f848faSopenharmony_ci
3191f9f848faSopenharmony_ci		usbd_clear_data_toggle(xfer2->xroot->udev, xfer2->endpoint);
3192f9f848faSopenharmony_ci
3193f9f848faSopenharmony_ci		/* setup a clear-stall packet */
3194f9f848faSopenharmony_ci
3195f9f848faSopenharmony_ci		req.bmRequestType = UT_WRITE_ENDPOINT;
3196f9f848faSopenharmony_ci		req.bRequest = UR_CLEAR_FEATURE;
3197f9f848faSopenharmony_ci		USETW(req.wValue, UF_ENDPOINT_HALT);
3198f9f848faSopenharmony_ci		req.wIndex[0] = xfer2->endpoint->edesc->bEndpointAddress;
3199f9f848faSopenharmony_ci		req.wIndex[1] = 0;
3200f9f848faSopenharmony_ci		USETW(req.wLength, 0);
3201f9f848faSopenharmony_ci
3202f9f848faSopenharmony_ci		/*
3203f9f848faSopenharmony_ci		 * "usbd_transfer_setup_sub()" will ensure that
3204f9f848faSopenharmony_ci		 * we have sufficient room in the buffer for
3205f9f848faSopenharmony_ci		 * the request structure!
3206f9f848faSopenharmony_ci		 */
3207f9f848faSopenharmony_ci
3208f9f848faSopenharmony_ci		/* copy in the transfer */
3209f9f848faSopenharmony_ci
3210f9f848faSopenharmony_ci		usbd_copy_in(xfer1->frbuffers, 0, &req, sizeof(req));
3211f9f848faSopenharmony_ci
3212f9f848faSopenharmony_ci		/* set length */
3213f9f848faSopenharmony_ci		xfer1->frlengths[0] = sizeof(req);
3214f9f848faSopenharmony_ci		xfer1->nframes = 1;
3215f9f848faSopenharmony_ci
3216f9f848faSopenharmony_ci		usbd_transfer_submit(xfer1);
3217f9f848faSopenharmony_ci		return (0);
3218f9f848faSopenharmony_ci
3219f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
3220f9f848faSopenharmony_ci		break;
3221f9f848faSopenharmony_ci
3222f9f848faSopenharmony_ci	default:			/* Error */
3223f9f848faSopenharmony_ci		if (xfer1->error == USB_ERR_CANCELLED) {
3224f9f848faSopenharmony_ci			return (0);
3225f9f848faSopenharmony_ci		}
3226f9f848faSopenharmony_ci		break;
3227f9f848faSopenharmony_ci	}
3228f9f848faSopenharmony_ci	return (1);			/* Clear Stall Finished */
3229f9f848faSopenharmony_ci}
3230f9f848faSopenharmony_ci
3231f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
3232f9f848faSopenharmony_ci *	usbd_transfer_poll
3233f9f848faSopenharmony_ci *
3234f9f848faSopenharmony_ci * The following function gets called from the USB keyboard driver and
3235f9f848faSopenharmony_ci * UMASS when the system has paniced.
3236f9f848faSopenharmony_ci *
3237f9f848faSopenharmony_ci * NOTE: It is currently not possible to resume normal operation on
3238f9f848faSopenharmony_ci * the USB controller which has been polled, due to clearing of the
3239f9f848faSopenharmony_ci * "up_dsleep" and "up_msleep" flags.
3240f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
3241f9f848faSopenharmony_civoid
3242f9f848faSopenharmony_ciusbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max)
3243f9f848faSopenharmony_ci{
3244f9f848faSopenharmony_ci	struct usb_xfer *xfer;
3245f9f848faSopenharmony_ci	struct usb_xfer_root *xroot;
3246f9f848faSopenharmony_ci	struct usb_device *udev;
3247f9f848faSopenharmony_ci	struct usb_proc_msg *pm;
3248f9f848faSopenharmony_ci	uint16_t n;
3249f9f848faSopenharmony_ci	uint16_t drop_bus;
3250f9f848faSopenharmony_ci	uint16_t drop_xfer;
3251f9f848faSopenharmony_ci
3252f9f848faSopenharmony_ci	for (n = 0; n != max; n++) {
3253f9f848faSopenharmony_ci		/* Extra checks to avoid panic */
3254f9f848faSopenharmony_ci		xfer = ppxfer[n];
3255f9f848faSopenharmony_ci		if (xfer == NULL)
3256f9f848faSopenharmony_ci			continue;	/* no USB transfer */
3257f9f848faSopenharmony_ci		xroot = xfer->xroot;
3258f9f848faSopenharmony_ci		if (xroot == NULL)
3259f9f848faSopenharmony_ci			continue;	/* no USB root */
3260f9f848faSopenharmony_ci		udev = xroot->udev;
3261f9f848faSopenharmony_ci		if (udev == NULL)
3262f9f848faSopenharmony_ci			continue;	/* no USB device */
3263f9f848faSopenharmony_ci		if (udev->bus == NULL)
3264f9f848faSopenharmony_ci			continue;	/* no BUS structure */
3265f9f848faSopenharmony_ci		if (udev->bus->methods == NULL)
3266f9f848faSopenharmony_ci			continue;	/* no BUS methods */
3267f9f848faSopenharmony_ci		if (udev->bus->methods->xfer_poll == NULL)
3268f9f848faSopenharmony_ci			continue;	/* no poll method */
3269f9f848faSopenharmony_ci
3270f9f848faSopenharmony_ci		/* make sure that the BUS mutex is not locked */
3271f9f848faSopenharmony_ci		drop_bus = 0;
3272f9f848faSopenharmony_ci		while (mtx_owned(&xroot->udev->bus->bus_mtx) && !SCHEDULER_STOPPED()) {
3273f9f848faSopenharmony_ci			mtx_unlock(&xroot->udev->bus->bus_mtx);
3274f9f848faSopenharmony_ci			drop_bus++;
3275f9f848faSopenharmony_ci		}
3276f9f848faSopenharmony_ci
3277f9f848faSopenharmony_ci		/* make sure that the transfer mutex is not locked */
3278f9f848faSopenharmony_ci		drop_xfer = 0;
3279f9f848faSopenharmony_ci		while (mtx_owned(xroot->xfer_mtx) && !SCHEDULER_STOPPED()) {
3280f9f848faSopenharmony_ci			mtx_unlock(xroot->xfer_mtx);
3281f9f848faSopenharmony_ci			drop_xfer++;
3282f9f848faSopenharmony_ci		}
3283f9f848faSopenharmony_ci
3284f9f848faSopenharmony_ci		/* Make sure cv_signal() and cv_broadcast() is not called */
3285f9f848faSopenharmony_ci		USB_BUS_CONTROL_XFER_PROC(udev->bus)->up_msleep = 0;
3286f9f848faSopenharmony_ci		USB_BUS_EXPLORE_PROC(udev->bus)->up_msleep = 0;
3287f9f848faSopenharmony_ci		USB_BUS_GIANT_PROC(udev->bus)->up_msleep = 0;
3288f9f848faSopenharmony_ci		USB_BUS_NON_GIANT_ISOC_PROC(udev->bus)->up_msleep = 0;
3289f9f848faSopenharmony_ci		USB_BUS_NON_GIANT_BULK_PROC(udev->bus)->up_msleep = 0;
3290f9f848faSopenharmony_ci
3291f9f848faSopenharmony_ci		/* poll USB hardware */
3292f9f848faSopenharmony_ci		(udev->bus->methods->xfer_poll) (udev->bus);
3293f9f848faSopenharmony_ci
3294f9f848faSopenharmony_ci		USB_BUS_LOCK(xroot->bus);
3295f9f848faSopenharmony_ci
3296f9f848faSopenharmony_ci		/* check for clear stall */
3297f9f848faSopenharmony_ci		if (udev->ctrl_xfer[1] != NULL) {
3298f9f848faSopenharmony_ci			/* poll clear stall start */
3299f9f848faSopenharmony_ci			pm = &udev->cs_msg[0].hdr;
3300f9f848faSopenharmony_ci			(pm->pm_callback) (pm);
3301f9f848faSopenharmony_ci			/* poll clear stall done thread */
3302f9f848faSopenharmony_ci			pm = &udev->ctrl_xfer[1]->
3303f9f848faSopenharmony_ci			    xroot->done_m[0].hdr;
3304f9f848faSopenharmony_ci			(pm->pm_callback) (pm);
3305f9f848faSopenharmony_ci		}
3306f9f848faSopenharmony_ci
3307f9f848faSopenharmony_ci		/* poll done thread */
3308f9f848faSopenharmony_ci		pm = &xroot->done_m[0].hdr;
3309f9f848faSopenharmony_ci		(pm->pm_callback) (pm);
3310f9f848faSopenharmony_ci
3311f9f848faSopenharmony_ci		USB_BUS_UNLOCK(xroot->bus);
3312f9f848faSopenharmony_ci
3313f9f848faSopenharmony_ci		/* restore transfer mutex */
3314f9f848faSopenharmony_ci		while (drop_xfer--)
3315f9f848faSopenharmony_ci			mtx_lock(xroot->xfer_mtx);
3316f9f848faSopenharmony_ci
3317f9f848faSopenharmony_ci		/* restore BUS mutex */
3318f9f848faSopenharmony_ci		while (drop_bus--)
3319f9f848faSopenharmony_ci			mtx_lock(&xroot->udev->bus->bus_mtx);
3320f9f848faSopenharmony_ci	}
3321f9f848faSopenharmony_ci}
3322f9f848faSopenharmony_ci
3323f9f848faSopenharmony_cistatic void
3324f9f848faSopenharmony_ciusbd_get_std_packet_size(struct usb_std_packet_size *ptr,
3325f9f848faSopenharmony_ci    uint8_t type, enum usb_dev_speed speed)
3326f9f848faSopenharmony_ci{
3327f9f848faSopenharmony_ci	static const uint16_t intr_range_max[USB_SPEED_MAX] = {
3328f9f848faSopenharmony_ci		[USB_SPEED_LOW] = 8,
3329f9f848faSopenharmony_ci		[USB_SPEED_FULL] = 64,
3330f9f848faSopenharmony_ci		[USB_SPEED_HIGH] = 1024,
3331f9f848faSopenharmony_ci		[USB_SPEED_VARIABLE] = 1024,
3332f9f848faSopenharmony_ci		[USB_SPEED_SUPER] = 1024,
3333f9f848faSopenharmony_ci	};
3334f9f848faSopenharmony_ci
3335f9f848faSopenharmony_ci	static const uint16_t isoc_range_max[USB_SPEED_MAX] = {
3336f9f848faSopenharmony_ci		[USB_SPEED_LOW] = 0,	/* invalid */
3337f9f848faSopenharmony_ci		[USB_SPEED_FULL] = 1023,
3338f9f848faSopenharmony_ci		[USB_SPEED_HIGH] = 1024,
3339f9f848faSopenharmony_ci		[USB_SPEED_VARIABLE] = 3584,
3340f9f848faSopenharmony_ci		[USB_SPEED_SUPER] = 1024,
3341f9f848faSopenharmony_ci	};
3342f9f848faSopenharmony_ci
3343f9f848faSopenharmony_ci	static const uint16_t control_min[USB_SPEED_MAX] = {
3344f9f848faSopenharmony_ci		[USB_SPEED_LOW] = 8,
3345f9f848faSopenharmony_ci		[USB_SPEED_FULL] = 8,
3346f9f848faSopenharmony_ci		[USB_SPEED_HIGH] = 64,
3347f9f848faSopenharmony_ci		[USB_SPEED_VARIABLE] = 512,
3348f9f848faSopenharmony_ci		[USB_SPEED_SUPER] = 512,
3349f9f848faSopenharmony_ci	};
3350f9f848faSopenharmony_ci
3351f9f848faSopenharmony_ci	static const uint16_t bulk_min[USB_SPEED_MAX] = {
3352f9f848faSopenharmony_ci		[USB_SPEED_LOW] = 8,
3353f9f848faSopenharmony_ci		[USB_SPEED_FULL] = 8,
3354f9f848faSopenharmony_ci		[USB_SPEED_HIGH] = 512,
3355f9f848faSopenharmony_ci		[USB_SPEED_VARIABLE] = 512,
3356f9f848faSopenharmony_ci		[USB_SPEED_SUPER] = 1024,
3357f9f848faSopenharmony_ci	};
3358f9f848faSopenharmony_ci
3359f9f848faSopenharmony_ci	uint16_t temp;
3360f9f848faSopenharmony_ci
3361f9f848faSopenharmony_ci	(void)memset_s(ptr, sizeof(*ptr), 0, sizeof(*ptr));
3362f9f848faSopenharmony_ci
3363f9f848faSopenharmony_ci	switch (type) {
3364f9f848faSopenharmony_ci	case UE_INTERRUPT:
3365f9f848faSopenharmony_ci		ptr->range.max = intr_range_max[speed];
3366f9f848faSopenharmony_ci		break;
3367f9f848faSopenharmony_ci	case UE_ISOCHRONOUS:
3368f9f848faSopenharmony_ci		ptr->range.max = isoc_range_max[speed];
3369f9f848faSopenharmony_ci		break;
3370f9f848faSopenharmony_ci	default:
3371f9f848faSopenharmony_ci		if (type == UE_BULK)
3372f9f848faSopenharmony_ci			temp = bulk_min[speed];
3373f9f848faSopenharmony_ci		else /* UE_CONTROL */
3374f9f848faSopenharmony_ci			temp = control_min[speed];
3375f9f848faSopenharmony_ci
3376f9f848faSopenharmony_ci		/* default is fixed */
3377f9f848faSopenharmony_ci		ptr->fixed[0] = temp;
3378f9f848faSopenharmony_ci		ptr->fixed[1] = temp;
3379f9f848faSopenharmony_ci		ptr->fixed[2] = temp;
3380f9f848faSopenharmony_ci		ptr->fixed[3] = temp;
3381f9f848faSopenharmony_ci
3382f9f848faSopenharmony_ci		if (speed == USB_SPEED_FULL) {
3383f9f848faSopenharmony_ci			/* multiple sizes */
3384f9f848faSopenharmony_ci			ptr->fixed[1] = 16;
3385f9f848faSopenharmony_ci			ptr->fixed[2] = 32;
3386f9f848faSopenharmony_ci			ptr->fixed[3] = 64;
3387f9f848faSopenharmony_ci		}
3388f9f848faSopenharmony_ci		if ((speed == USB_SPEED_VARIABLE) &&
3389f9f848faSopenharmony_ci		    (type == UE_BULK)) {
3390f9f848faSopenharmony_ci			/* multiple sizes */
3391f9f848faSopenharmony_ci			ptr->fixed[2] = 1024;
3392f9f848faSopenharmony_ci			ptr->fixed[3] = 1536;
3393f9f848faSopenharmony_ci		}
3394f9f848faSopenharmony_ci		break;
3395f9f848faSopenharmony_ci	}
3396f9f848faSopenharmony_ci}
3397f9f848faSopenharmony_ci
3398f9f848faSopenharmony_civoid	*
3399f9f848faSopenharmony_ciusbd_xfer_softc(struct usb_xfer *xfer)
3400f9f848faSopenharmony_ci{
3401f9f848faSopenharmony_ci	return (xfer->priv_sc);
3402f9f848faSopenharmony_ci}
3403f9f848faSopenharmony_ci
3404f9f848faSopenharmony_civoid *
3405f9f848faSopenharmony_ciusbd_xfer_get_priv(struct usb_xfer *xfer)
3406f9f848faSopenharmony_ci{
3407f9f848faSopenharmony_ci	return (xfer->priv_fifo);
3408f9f848faSopenharmony_ci}
3409f9f848faSopenharmony_ci
3410f9f848faSopenharmony_civoid
3411f9f848faSopenharmony_ciusbd_xfer_set_priv(struct usb_xfer *xfer, void *ptr)
3412f9f848faSopenharmony_ci{
3413f9f848faSopenharmony_ci	xfer->priv_fifo = ptr;
3414f9f848faSopenharmony_ci}
3415f9f848faSopenharmony_ci
3416f9f848faSopenharmony_ciuint8_t
3417f9f848faSopenharmony_ciusbd_xfer_state(struct usb_xfer *xfer)
3418f9f848faSopenharmony_ci{
3419f9f848faSopenharmony_ci	return (xfer->usb_state);
3420f9f848faSopenharmony_ci}
3421f9f848faSopenharmony_ci
3422f9f848faSopenharmony_civoid
3423f9f848faSopenharmony_ciusbd_xfer_set_flag(struct usb_xfer *xfer, int flag)
3424f9f848faSopenharmony_ci{
3425f9f848faSopenharmony_ci	switch (flag) {
3426f9f848faSopenharmony_ci		case USB_FORCE_SHORT_XFER:
3427f9f848faSopenharmony_ci			xfer->flags.force_short_xfer = 1;
3428f9f848faSopenharmony_ci			break;
3429f9f848faSopenharmony_ci		case USB_SHORT_XFER_OK:
3430f9f848faSopenharmony_ci			xfer->flags.short_xfer_ok = 1;
3431f9f848faSopenharmony_ci			break;
3432f9f848faSopenharmony_ci		case USB_MULTI_SHORT_OK:
3433f9f848faSopenharmony_ci			xfer->flags.short_frames_ok = 1;
3434f9f848faSopenharmony_ci			break;
3435f9f848faSopenharmony_ci		case USB_MANUAL_STATUS:
3436f9f848faSopenharmony_ci			xfer->flags.manual_status = 1;
3437f9f848faSopenharmony_ci			break;
3438f9f848faSopenharmony_ci	}
3439f9f848faSopenharmony_ci}
3440f9f848faSopenharmony_ci
3441f9f848faSopenharmony_civoid
3442f9f848faSopenharmony_ciusbd_xfer_clr_flag(struct usb_xfer *xfer, int flag)
3443f9f848faSopenharmony_ci{
3444f9f848faSopenharmony_ci	switch (flag) {
3445f9f848faSopenharmony_ci		case USB_FORCE_SHORT_XFER:
3446f9f848faSopenharmony_ci			xfer->flags.force_short_xfer = 0;
3447f9f848faSopenharmony_ci			break;
3448f9f848faSopenharmony_ci		case USB_SHORT_XFER_OK:
3449f9f848faSopenharmony_ci			xfer->flags.short_xfer_ok = 0;
3450f9f848faSopenharmony_ci			break;
3451f9f848faSopenharmony_ci		case USB_MULTI_SHORT_OK:
3452f9f848faSopenharmony_ci			xfer->flags.short_frames_ok = 0;
3453f9f848faSopenharmony_ci			break;
3454f9f848faSopenharmony_ci		case USB_MANUAL_STATUS:
3455f9f848faSopenharmony_ci			xfer->flags.manual_status = 0;
3456f9f848faSopenharmony_ci			break;
3457f9f848faSopenharmony_ci	}
3458f9f848faSopenharmony_ci}
3459f9f848faSopenharmony_ci
3460f9f848faSopenharmony_ci/*
3461f9f848faSopenharmony_ci * The following function returns in milliseconds when the isochronous
3462f9f848faSopenharmony_ci * transfer was completed by the hardware. The returned value wraps
3463f9f848faSopenharmony_ci * around 65536 milliseconds.
3464f9f848faSopenharmony_ci */
3465f9f848faSopenharmony_ciuint16_t
3466f9f848faSopenharmony_ciusbd_xfer_get_timestamp(struct usb_xfer *xfer)
3467f9f848faSopenharmony_ci{
3468f9f848faSopenharmony_ci	return (xfer->isoc_time_complete);
3469f9f848faSopenharmony_ci}
3470f9f848faSopenharmony_ci
3471f9f848faSopenharmony_ci/*
3472f9f848faSopenharmony_ci * The following function returns non-zero if the max packet size
3473f9f848faSopenharmony_ci * field was clamped to a valid value. Else it returns zero.
3474f9f848faSopenharmony_ci */
3475f9f848faSopenharmony_ciuint8_t
3476f9f848faSopenharmony_ciusbd_xfer_maxp_was_clamped(struct usb_xfer *xfer)
3477f9f848faSopenharmony_ci{
3478f9f848faSopenharmony_ci	return (xfer->flags_int.maxp_was_clamped);
3479f9f848faSopenharmony_ci}
3480f9f848faSopenharmony_ci
3481f9f848faSopenharmony_ci/*
3482f9f848faSopenharmony_ci * The following function computes the next isochronous frame number
3483f9f848faSopenharmony_ci * where the first isochronous packet should be queued.
3484f9f848faSopenharmony_ci *
3485f9f848faSopenharmony_ci * The function returns non-zero if there was a discontinuity.
3486f9f848faSopenharmony_ci * Else zero is returned for normal operation.
3487f9f848faSopenharmony_ci */
3488f9f848faSopenharmony_ciuint8_t
3489f9f848faSopenharmony_ciusbd_xfer_get_isochronous_start_frame(struct usb_xfer *xfer, uint32_t frame_curr,
3490f9f848faSopenharmony_ci    uint32_t frame_min, uint32_t frame_ms, uint32_t frame_mask, uint32_t *p_frame_start)
3491f9f848faSopenharmony_ci{
3492f9f848faSopenharmony_ci	uint32_t duration;
3493f9f848faSopenharmony_ci	uint32_t delta;
3494f9f848faSopenharmony_ci	uint8_t retval;
3495f9f848faSopenharmony_ci	uint8_t shift;
3496f9f848faSopenharmony_ci
3497f9f848faSopenharmony_ci	/* Compute time ahead of current schedule. */
3498f9f848faSopenharmony_ci	delta = (xfer->endpoint->isoc_next - frame_curr) & frame_mask;
3499f9f848faSopenharmony_ci
3500f9f848faSopenharmony_ci	/*
3501f9f848faSopenharmony_ci	 * Check if it is the first transfer or if the future frame
3502f9f848faSopenharmony_ci	 * delta is less than one millisecond or if the frame delta is
3503f9f848faSopenharmony_ci	 * negative:
3504f9f848faSopenharmony_ci	 */
3505f9f848faSopenharmony_ci	if (xfer->endpoint->is_synced == 0 ||
3506f9f848faSopenharmony_ci	    delta < (frame_ms + frame_min) ||
3507f9f848faSopenharmony_ci	    delta > (frame_mask / 2)) {
3508f9f848faSopenharmony_ci		/* Schedule transfer 2 milliseconds into the future. */
3509f9f848faSopenharmony_ci		xfer->endpoint->isoc_next = (frame_curr + 2 * frame_ms + frame_min) & frame_mask;
3510f9f848faSopenharmony_ci		xfer->endpoint->is_synced = 1;
3511f9f848faSopenharmony_ci
3512f9f848faSopenharmony_ci		retval = 1;
3513f9f848faSopenharmony_ci	} else {
3514f9f848faSopenharmony_ci		retval = 0;
3515f9f848faSopenharmony_ci	}
3516f9f848faSopenharmony_ci
3517f9f848faSopenharmony_ci	/* Store start time, if any. */
3518f9f848faSopenharmony_ci	if (p_frame_start != NULL)
3519f9f848faSopenharmony_ci		*p_frame_start = xfer->endpoint->isoc_next & frame_mask;
3520f9f848faSopenharmony_ci
3521f9f848faSopenharmony_ci	/* Get relative completion time, in milliseconds. */
3522f9f848faSopenharmony_ci	delta = xfer->endpoint->isoc_next - frame_curr + (frame_curr % frame_ms);
3523f9f848faSopenharmony_ci	delta &= frame_mask;
3524f9f848faSopenharmony_ci	delta /= frame_ms;
3525f9f848faSopenharmony_ci
3526f9f848faSopenharmony_ci	switch (usbd_get_speed(xfer->xroot->udev)) {
3527f9f848faSopenharmony_ci	case USB_SPEED_FULL:
3528f9f848faSopenharmony_ci		shift = 3;
3529f9f848faSopenharmony_ci		break;
3530f9f848faSopenharmony_ci	default:
3531f9f848faSopenharmony_ci		shift = usbd_xfer_get_fps_shift(xfer);
3532f9f848faSopenharmony_ci		break;
3533f9f848faSopenharmony_ci	}
3534f9f848faSopenharmony_ci
3535f9f848faSopenharmony_ci	/* Get duration in milliseconds, rounded up. */
3536f9f848faSopenharmony_ci	duration = ((xfer->nframes << shift) + 7) / 8;
3537f9f848faSopenharmony_ci
3538f9f848faSopenharmony_ci	/* Compute full 32-bit completion time, in milliseconds. */
3539f9f848faSopenharmony_ci	xfer->isoc_time_complete =
3540f9f848faSopenharmony_ci	    usb_isoc_time_expand(xfer->xroot->bus, frame_curr / frame_ms) +
3541f9f848faSopenharmony_ci	    delta + duration;
3542f9f848faSopenharmony_ci
3543f9f848faSopenharmony_ci	/* Compute next isochronous frame. */
3544f9f848faSopenharmony_ci	xfer->endpoint->isoc_next += duration * frame_ms;
3545f9f848faSopenharmony_ci	xfer->endpoint->isoc_next &= frame_mask;
3546f9f848faSopenharmony_ci
3547f9f848faSopenharmony_ci	return (retval);
3548f9f848faSopenharmony_ci}
3549f9f848faSopenharmony_ci
3550f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
3551