xref: /dragonfly/sys/bus/u4b/usb_transfer.c (revision 2b3f93ea)
106cb2463SMarkus Pfeiffer /* $FreeBSD: head/sys/dev/usb/usb_transfer.c 276717 2015-01-05 20:22:18Z hselasky $ */
212bd3c8bSSascha Wildner /*-
312bd3c8bSSascha Wildner  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
412bd3c8bSSascha Wildner  *
512bd3c8bSSascha Wildner  * Redistribution and use in source and binary forms, with or without
612bd3c8bSSascha Wildner  * modification, are permitted provided that the following conditions
712bd3c8bSSascha Wildner  * are met:
812bd3c8bSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
912bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1012bd3c8bSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1112bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
1212bd3c8bSSascha Wildner  *    documentation and/or other materials provided with the distribution.
1312bd3c8bSSascha Wildner  *
1412bd3c8bSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1512bd3c8bSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1612bd3c8bSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1712bd3c8bSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1812bd3c8bSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1912bd3c8bSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2012bd3c8bSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2112bd3c8bSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2212bd3c8bSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2312bd3c8bSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2412bd3c8bSSascha Wildner  * SUCH DAMAGE.
2512bd3c8bSSascha Wildner  */
2612bd3c8bSSascha Wildner 
2712bd3c8bSSascha Wildner #include <sys/stdint.h>
2812bd3c8bSSascha Wildner #include <sys/param.h>
2912bd3c8bSSascha Wildner #include <sys/queue.h>
3012bd3c8bSSascha Wildner #include <sys/types.h>
3112bd3c8bSSascha Wildner #include <sys/systm.h>
3212bd3c8bSSascha Wildner #include <sys/kernel.h>
3312bd3c8bSSascha Wildner #include <sys/bus.h>
34ccb00b06SMatthew Dillon #include <sys/thread.h>
3512bd3c8bSSascha Wildner #include <sys/module.h>
3612bd3c8bSSascha Wildner #include <sys/lock.h>
3712bd3c8bSSascha Wildner #include <sys/condvar.h>
3812bd3c8bSSascha Wildner #include <sys/sysctl.h>
3912bd3c8bSSascha Wildner #include <sys/unistd.h>
4012bd3c8bSSascha Wildner #include <sys/callout.h>
4112bd3c8bSSascha Wildner #include <sys/malloc.h>
42*2b3f93eaSMatthew Dillon #include <sys/caps.h>
4312bd3c8bSSascha Wildner #include <sys/proc.h>
4412bd3c8bSSascha Wildner 
45ccb00b06SMatthew Dillon #include <sys/thread2.h>
46ccb00b06SMatthew Dillon 
47722d05c3SSascha Wildner #include <bus/u4b/usb.h>
48722d05c3SSascha Wildner #include <bus/u4b/usbdi.h>
49722d05c3SSascha Wildner #include <bus/u4b/usbdi_util.h>
5012bd3c8bSSascha Wildner 
5112bd3c8bSSascha Wildner #define	USB_DEBUG_VAR usb_debug
5212bd3c8bSSascha Wildner 
53722d05c3SSascha Wildner #include <bus/u4b/usb_core.h>
54722d05c3SSascha Wildner #include <bus/u4b/usb_busdma.h>
55722d05c3SSascha Wildner #include <bus/u4b/usb_process.h>
56722d05c3SSascha Wildner #include <bus/u4b/usb_transfer.h>
57722d05c3SSascha Wildner #include <bus/u4b/usb_device.h>
58722d05c3SSascha Wildner #include <bus/u4b/usb_debug.h>
59722d05c3SSascha Wildner #include <bus/u4b/usb_util.h>
6012bd3c8bSSascha Wildner 
61722d05c3SSascha Wildner #include <bus/u4b/usb_controller.h>
62722d05c3SSascha Wildner #include <bus/u4b/usb_bus.h>
63722d05c3SSascha Wildner #include <bus/u4b/usb_pf.h>
6412bd3c8bSSascha Wildner 
6512bd3c8bSSascha Wildner struct usb_std_packet_size {
6612bd3c8bSSascha Wildner 	struct {
6712bd3c8bSSascha Wildner 		uint16_t min;		/* inclusive */
6812bd3c8bSSascha Wildner 		uint16_t max;		/* inclusive */
6912bd3c8bSSascha Wildner 	}	range;
7012bd3c8bSSascha Wildner 
7112bd3c8bSSascha Wildner 	uint16_t fixed[4];
7212bd3c8bSSascha Wildner };
7312bd3c8bSSascha Wildner 
7412bd3c8bSSascha Wildner static usb_callback_t usb_request_callback;
7512bd3c8bSSascha Wildner 
7612bd3c8bSSascha Wildner static const struct usb_config usb_control_ep_cfg[USB_CTRL_XFER_MAX] = {
7712bd3c8bSSascha Wildner 
7812bd3c8bSSascha Wildner 	/* This transfer is used for generic control endpoint transfers */
7912bd3c8bSSascha Wildner 
8012bd3c8bSSascha Wildner 	[0] = {
8112bd3c8bSSascha Wildner 		.type = UE_CONTROL,
8212bd3c8bSSascha Wildner 		.endpoint = 0x00,	/* Control endpoint */
8312bd3c8bSSascha Wildner 		.direction = UE_DIR_ANY,
8412bd3c8bSSascha Wildner 		.bufsize = USB_EP0_BUFSIZE,	/* bytes */
8512bd3c8bSSascha Wildner 		.flags = {.proxy_buffer = 1,},
8612bd3c8bSSascha Wildner 		.callback = &usb_request_callback,
8712bd3c8bSSascha Wildner 		.usb_mode = USB_MODE_DUAL,	/* both modes */
8812bd3c8bSSascha Wildner 	},
8912bd3c8bSSascha Wildner 
9012bd3c8bSSascha Wildner 	/* This transfer is used for generic clear stall only */
9112bd3c8bSSascha Wildner 
9212bd3c8bSSascha Wildner 	[1] = {
9312bd3c8bSSascha Wildner 		.type = UE_CONTROL,
9412bd3c8bSSascha Wildner 		.endpoint = 0x00,	/* Control pipe */
9512bd3c8bSSascha Wildner 		.direction = UE_DIR_ANY,
9612bd3c8bSSascha Wildner 		.bufsize = sizeof(struct usb_device_request),
9712bd3c8bSSascha Wildner 		.callback = &usb_do_clear_stall_callback,
9812bd3c8bSSascha Wildner 		.timeout = 1000,	/* 1 second */
9912bd3c8bSSascha Wildner 		.interval = 50,	/* 50ms */
10012bd3c8bSSascha Wildner 		.usb_mode = USB_MODE_HOST,
10112bd3c8bSSascha Wildner 	},
10212bd3c8bSSascha Wildner };
10312bd3c8bSSascha Wildner 
10412bd3c8bSSascha Wildner /* function prototypes */
10512bd3c8bSSascha Wildner 
10612bd3c8bSSascha Wildner static void	usbd_update_max_frame_size(struct usb_xfer *);
10712bd3c8bSSascha Wildner static void	usbd_transfer_unsetup_sub(struct usb_xfer_root *, uint8_t);
108ccb00b06SMatthew Dillon static void	usbd_delayed_free(void *data, struct malloc_type *mtype);
10912bd3c8bSSascha Wildner static void	usbd_control_transfer_init(struct usb_xfer *);
11012bd3c8bSSascha Wildner static int	usbd_setup_ctrl_transfer(struct usb_xfer *);
11112bd3c8bSSascha Wildner static void	usb_callback_proc(struct usb_proc_msg *);
11212bd3c8bSSascha Wildner static void	usbd_callback_ss_done_defer(struct usb_xfer *);
11312bd3c8bSSascha Wildner static void	usbd_callback_wrapper(struct usb_xfer_queue *);
11412bd3c8bSSascha Wildner static void	usbd_transfer_start_cb(void *);
11512bd3c8bSSascha Wildner static uint8_t	usbd_callback_wrapper_sub(struct usb_xfer *);
11612bd3c8bSSascha Wildner static void	usbd_get_std_packet_size(struct usb_std_packet_size *ptr,
11712bd3c8bSSascha Wildner 		    uint8_t type, enum usb_dev_speed speed);
11812bd3c8bSSascha Wildner 
11912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
12012bd3c8bSSascha Wildner  *	usb_request_callback
12112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
12212bd3c8bSSascha Wildner static void
usb_request_callback(struct usb_xfer * xfer,usb_error_t error)12312bd3c8bSSascha Wildner usb_request_callback(struct usb_xfer *xfer, usb_error_t error)
12412bd3c8bSSascha Wildner {
12512bd3c8bSSascha Wildner 	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE)
12612bd3c8bSSascha Wildner 		usb_handle_request_callback(xfer, error);
12712bd3c8bSSascha Wildner 	else
12812bd3c8bSSascha Wildner 		usbd_do_request_callback(xfer, error);
12912bd3c8bSSascha Wildner }
13012bd3c8bSSascha Wildner 
13112bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
13212bd3c8bSSascha Wildner  *	usbd_update_max_frame_size
13312bd3c8bSSascha Wildner  *
13412bd3c8bSSascha Wildner  * This function updates the maximum frame size, hence high speed USB
13512bd3c8bSSascha Wildner  * can transfer multiple consecutive packets.
13612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
13712bd3c8bSSascha Wildner static void
usbd_update_max_frame_size(struct usb_xfer * xfer)13812bd3c8bSSascha Wildner usbd_update_max_frame_size(struct usb_xfer *xfer)
13912bd3c8bSSascha Wildner {
14012bd3c8bSSascha Wildner 	/* compute maximum frame size */
14112bd3c8bSSascha Wildner 	/* this computation should not overflow 16-bit */
14212bd3c8bSSascha Wildner 	/* max = 15 * 1024 */
14312bd3c8bSSascha Wildner 
14412bd3c8bSSascha Wildner 	xfer->max_frame_size = xfer->max_packet_size * xfer->max_packet_count;
14512bd3c8bSSascha Wildner }
14612bd3c8bSSascha Wildner 
14712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
14812bd3c8bSSascha Wildner  *	usbd_get_dma_delay
14912bd3c8bSSascha Wildner  *
15012bd3c8bSSascha Wildner  * The following function is called when we need to
15112bd3c8bSSascha Wildner  * synchronize with DMA hardware.
15212bd3c8bSSascha Wildner  *
15312bd3c8bSSascha Wildner  * Returns:
15412bd3c8bSSascha Wildner  *    0: no DMA delay required
15512bd3c8bSSascha Wildner  * Else: milliseconds of DMA delay
15612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
15712bd3c8bSSascha Wildner usb_timeout_t
usbd_get_dma_delay(struct usb_device * udev)15812bd3c8bSSascha Wildner usbd_get_dma_delay(struct usb_device *udev)
15912bd3c8bSSascha Wildner {
1608922de18SMarkus Pfeiffer 	const struct usb_bus_methods *mtod;
16112bd3c8bSSascha Wildner 	uint32_t temp;
16212bd3c8bSSascha Wildner 
16312bd3c8bSSascha Wildner 	mtod = udev->bus->methods;
16412bd3c8bSSascha Wildner 	temp = 0;
16512bd3c8bSSascha Wildner 
16612bd3c8bSSascha Wildner 	if (mtod->get_dma_delay) {
16712bd3c8bSSascha Wildner 		(mtod->get_dma_delay) (udev, &temp);
16812bd3c8bSSascha Wildner 		/*
16912bd3c8bSSascha Wildner 		 * Round up and convert to milliseconds. Note that we use
17012bd3c8bSSascha Wildner 		 * 1024 milliseconds per second. to save a division.
17112bd3c8bSSascha Wildner 		 */
17212bd3c8bSSascha Wildner 		temp += 0x3FF;
17312bd3c8bSSascha Wildner 		temp /= 0x400;
17412bd3c8bSSascha Wildner 	}
17512bd3c8bSSascha Wildner 	return (temp);
17612bd3c8bSSascha Wildner }
17712bd3c8bSSascha Wildner 
17812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
17912bd3c8bSSascha Wildner  *	usbd_transfer_setup_sub_malloc
18012bd3c8bSSascha Wildner  *
18112bd3c8bSSascha Wildner  * This function will allocate one or more DMA'able memory chunks
18212bd3c8bSSascha Wildner  * according to "size", "align" and "count" arguments. "ppc" is
18312bd3c8bSSascha Wildner  * pointed to a linear array of USB page caches afterwards.
18412bd3c8bSSascha Wildner  *
18557bed822SMarkus Pfeiffer  * If the "align" argument is equal to "1" a non-contiguous allocation
18657bed822SMarkus Pfeiffer  * can happen. Else if the "align" argument is greater than "1", the
18757bed822SMarkus Pfeiffer  * allocation will always be contiguous in memory.
18857bed822SMarkus Pfeiffer  *
18912bd3c8bSSascha Wildner  * Returns:
19012bd3c8bSSascha Wildner  *    0: Success
19112bd3c8bSSascha Wildner  * Else: Failure
19212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
19312bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
19412bd3c8bSSascha Wildner uint8_t
usbd_transfer_setup_sub_malloc(struct usb_setup_params * parm,struct usb_page_cache ** ppc,usb_size_t size,usb_size_t align,usb_size_t count)19512bd3c8bSSascha Wildner usbd_transfer_setup_sub_malloc(struct usb_setup_params *parm,
19612bd3c8bSSascha Wildner     struct usb_page_cache **ppc, usb_size_t size, usb_size_t align,
19712bd3c8bSSascha Wildner     usb_size_t count)
19812bd3c8bSSascha Wildner {
19912bd3c8bSSascha Wildner 	struct usb_page_cache *pc;
20012bd3c8bSSascha Wildner 	struct usb_page *pg;
20112bd3c8bSSascha Wildner 	void *buf;
20212bd3c8bSSascha Wildner 	usb_size_t n_dma_pc;
20357bed822SMarkus Pfeiffer 	usb_size_t n_dma_pg;
20412bd3c8bSSascha Wildner 	usb_size_t n_obj;
20512bd3c8bSSascha Wildner 	usb_size_t x;
20612bd3c8bSSascha Wildner 	usb_size_t y;
20712bd3c8bSSascha Wildner 	usb_size_t r;
20812bd3c8bSSascha Wildner 	usb_size_t z;
20912bd3c8bSSascha Wildner 
21057bed822SMarkus Pfeiffer 	USB_ASSERT(align > 0, ("Invalid alignment, 0x%08x\n",
21112bd3c8bSSascha Wildner 	    align));
21212bd3c8bSSascha Wildner 	USB_ASSERT(size > 0, ("Invalid size = 0\n"));
21363da4a34SSascha Wildner 
21412bd3c8bSSascha Wildner 	if (count == 0) {
21512bd3c8bSSascha Wildner 		return (0);		/* nothing to allocate */
21612bd3c8bSSascha Wildner 	}
21712bd3c8bSSascha Wildner 	/*
21812bd3c8bSSascha Wildner 	 * Make sure that the size is aligned properly.
21912bd3c8bSSascha Wildner 	 */
22012bd3c8bSSascha Wildner 	size = -((-size) & (-align));
22112bd3c8bSSascha Wildner 
22212bd3c8bSSascha Wildner 	/*
22312bd3c8bSSascha Wildner 	 * Try multi-allocation chunks to reduce the number of DMA
22412bd3c8bSSascha Wildner 	 * allocations, hence DMA allocations are slow.
22512bd3c8bSSascha Wildner 	 */
22657bed822SMarkus Pfeiffer 	if (align == 1) {
22757bed822SMarkus Pfeiffer 		/* special case - non-cached multi page DMA memory */
22812bd3c8bSSascha Wildner 		n_dma_pc = count;
22957bed822SMarkus Pfeiffer 		n_dma_pg = (2 + (size / USB_PAGE_SIZE));
23057bed822SMarkus Pfeiffer 		n_obj = 1;
23157bed822SMarkus Pfeiffer 	} else if (size >= USB_PAGE_SIZE) {
23257bed822SMarkus Pfeiffer 		n_dma_pc = count;
23357bed822SMarkus Pfeiffer 		n_dma_pg = 1;
23412bd3c8bSSascha Wildner 		n_obj = 1;
23512bd3c8bSSascha Wildner 	} else {
23612bd3c8bSSascha Wildner 		/* compute number of objects per page */
237dd681da6SMatthew Dillon #ifdef USB_DMA_SINGLE_ALLOC
238dd681da6SMatthew Dillon 		n_obj = 1;
239dd681da6SMatthew Dillon #else
2405e41ab93SMarkus Pfeiffer 		n_obj = (USB_PAGE_SIZE / size);
241dd681da6SMatthew Dillon #endif
24212bd3c8bSSascha Wildner 		/*
24312bd3c8bSSascha Wildner 		 * Compute number of DMA chunks, rounded up
24412bd3c8bSSascha Wildner 		 * to nearest one:
24512bd3c8bSSascha Wildner 		 */
24612bd3c8bSSascha Wildner 		n_dma_pc = ((count + n_obj - 1) / n_obj);
24757bed822SMarkus Pfeiffer 		n_dma_pg = 1;
24812bd3c8bSSascha Wildner 	}
24912bd3c8bSSascha Wildner 
25057bed822SMarkus Pfeiffer 	/*
25157bed822SMarkus Pfeiffer 	 * DMA memory is allocated once, but mapped twice. That's why
25257bed822SMarkus Pfeiffer 	 * there is one list for auto-free and another list for
25357bed822SMarkus Pfeiffer 	 * non-auto-free which only holds the mapping and not the
25457bed822SMarkus Pfeiffer 	 * allocation.
25557bed822SMarkus Pfeiffer 	 */
25612bd3c8bSSascha Wildner 	if (parm->buf == NULL) {
25757bed822SMarkus Pfeiffer 		/* reserve memory (auto-free) */
25857bed822SMarkus Pfeiffer 		parm->dma_page_ptr += n_dma_pc * n_dma_pg;
25912bd3c8bSSascha Wildner 		parm->dma_page_cache_ptr += n_dma_pc;
26057bed822SMarkus Pfeiffer 
26157bed822SMarkus Pfeiffer 		/* reserve memory (no-auto-free) */
26257bed822SMarkus Pfeiffer 		parm->dma_page_ptr += count * n_dma_pg;
26312bd3c8bSSascha Wildner 		parm->xfer_page_cache_ptr += count;
26412bd3c8bSSascha Wildner 		return (0);
26512bd3c8bSSascha Wildner 	}
26612bd3c8bSSascha Wildner 	for (x = 0; x != n_dma_pc; x++) {
26712bd3c8bSSascha Wildner 		/* need to initialize the page cache */
26812bd3c8bSSascha Wildner 		parm->dma_page_cache_ptr[x].tag_parent =
26912bd3c8bSSascha Wildner 		    &parm->curr_xfer->xroot->dma_parent_tag;
27012bd3c8bSSascha Wildner 	}
27112bd3c8bSSascha Wildner 	for (x = 0; x != count; x++) {
27212bd3c8bSSascha Wildner 		/* need to initialize the page cache */
27312bd3c8bSSascha Wildner 		parm->xfer_page_cache_ptr[x].tag_parent =
27412bd3c8bSSascha Wildner 		    &parm->curr_xfer->xroot->dma_parent_tag;
27512bd3c8bSSascha Wildner 	}
27612bd3c8bSSascha Wildner 
277dd681da6SMatthew Dillon 	if (ppc != NULL) {
278dd681da6SMatthew Dillon 		if (n_obj != 1)
27912bd3c8bSSascha Wildner 			*ppc = parm->xfer_page_cache_ptr;
280dd681da6SMatthew Dillon 		else
281dd681da6SMatthew Dillon 			*ppc = parm->dma_page_cache_ptr;
28212bd3c8bSSascha Wildner 	}
28312bd3c8bSSascha Wildner 	r = count;			/* set remainder count */
28412bd3c8bSSascha Wildner 	z = n_obj * size;		/* set allocation size */
28512bd3c8bSSascha Wildner 	pc = parm->xfer_page_cache_ptr;
28612bd3c8bSSascha Wildner 	pg = parm->dma_page_ptr;
28712bd3c8bSSascha Wildner 
288dd681da6SMatthew Dillon 	if (n_obj == 1) {
289dd681da6SMatthew Dillon 	    /*
290dd681da6SMatthew Dillon 	     * Avoid mapping memory twice if only a single object
291dd681da6SMatthew Dillon 	     * should be allocated per page cache:
292dd681da6SMatthew Dillon 	     */
293dd681da6SMatthew Dillon 	    for (x = 0; x != n_dma_pc; x++) {
294dd681da6SMatthew Dillon 		if (usb_pc_alloc_mem(parm->dma_page_cache_ptr,
295dd681da6SMatthew Dillon 		    pg, z, align)) {
296dd681da6SMatthew Dillon 			return (1);	/* failure */
297dd681da6SMatthew Dillon 		}
298dd681da6SMatthew Dillon 		/* Make room for one DMA page cache and "n_dma_pg" pages */
299dd681da6SMatthew Dillon 		parm->dma_page_cache_ptr++;
300dd681da6SMatthew Dillon 		pg += n_dma_pg;
301dd681da6SMatthew Dillon 	    }
302dd681da6SMatthew Dillon 	} else {
30312bd3c8bSSascha Wildner 	    for (x = 0; x != n_dma_pc; x++) {
30412bd3c8bSSascha Wildner 
30512bd3c8bSSascha Wildner 		if (r < n_obj) {
30612bd3c8bSSascha Wildner 			/* compute last remainder */
30712bd3c8bSSascha Wildner 			z = r * size;
30812bd3c8bSSascha Wildner 			n_obj = r;
30912bd3c8bSSascha Wildner 		}
31012bd3c8bSSascha Wildner 		if (usb_pc_alloc_mem(parm->dma_page_cache_ptr,
31112bd3c8bSSascha Wildner 		    pg, z, align)) {
31212bd3c8bSSascha Wildner 			return (1);	/* failure */
31312bd3c8bSSascha Wildner 		}
31412bd3c8bSSascha Wildner 		/* Set beginning of current buffer */
31512bd3c8bSSascha Wildner 		buf = parm->dma_page_cache_ptr->buffer;
316dd681da6SMatthew Dillon 		/* Make room for one DMA page cache and "n_dma_pg" pages */
31712bd3c8bSSascha Wildner 		parm->dma_page_cache_ptr++;
31857bed822SMarkus Pfeiffer 		pg += n_dma_pg;
31912bd3c8bSSascha Wildner 
32057bed822SMarkus Pfeiffer 		for (y = 0; (y != n_obj); y++, r--, pc++, pg += n_dma_pg) {
32112bd3c8bSSascha Wildner 
32212bd3c8bSSascha Wildner 			/* Load sub-chunk into DMA */
32312bd3c8bSSascha Wildner 			if (usb_pc_dmamap_create(pc, size)) {
32412bd3c8bSSascha Wildner 				return (1);	/* failure */
32512bd3c8bSSascha Wildner 			}
32612bd3c8bSSascha Wildner 			pc->buffer = USB_ADD_BYTES(buf, y * size);
32712bd3c8bSSascha Wildner 			pc->page_start = pg;
32812bd3c8bSSascha Wildner 
329722d05c3SSascha Wildner 			lockmgr(pc->tag_parent->lock, LK_EXCLUSIVE);
33012bd3c8bSSascha Wildner 			if (usb_pc_load_mem(pc, size, 1 /* synchronous */ )) {
331722d05c3SSascha Wildner 				lockmgr(pc->tag_parent->lock, LK_RELEASE);
33212bd3c8bSSascha Wildner 				return (1);	/* failure */
33312bd3c8bSSascha Wildner 			}
334722d05c3SSascha Wildner 			lockmgr(pc->tag_parent->lock, LK_RELEASE);
33512bd3c8bSSascha Wildner 		}
33612bd3c8bSSascha Wildner 	    }
337dd681da6SMatthew Dillon 	}
33812bd3c8bSSascha Wildner 
33912bd3c8bSSascha Wildner 	parm->xfer_page_cache_ptr = pc;
34012bd3c8bSSascha Wildner 	parm->dma_page_ptr = pg;
34112bd3c8bSSascha Wildner 	return (0);
34212bd3c8bSSascha Wildner }
34312bd3c8bSSascha Wildner #endif
34412bd3c8bSSascha Wildner 
34512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
34612bd3c8bSSascha Wildner  *	usbd_transfer_setup_sub - transfer setup subroutine
34712bd3c8bSSascha Wildner  *
34812bd3c8bSSascha Wildner  * This function must be called from the "xfer_setup" callback of the
34912bd3c8bSSascha Wildner  * USB Host or Device controller driver when setting up an USB
35012bd3c8bSSascha Wildner  * transfer. This function will setup correct packet sizes, buffer
35112bd3c8bSSascha Wildner  * sizes, flags and more, that are stored in the "usb_xfer"
35212bd3c8bSSascha Wildner  * structure.
35312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
35412bd3c8bSSascha Wildner void
usbd_transfer_setup_sub(struct usb_setup_params * parm)35512bd3c8bSSascha Wildner usbd_transfer_setup_sub(struct usb_setup_params *parm)
35612bd3c8bSSascha Wildner {
35712bd3c8bSSascha Wildner 	enum {
35812bd3c8bSSascha Wildner 		REQ_SIZE = 8,
35912bd3c8bSSascha Wildner 		MIN_PKT = 8,
36012bd3c8bSSascha Wildner 	};
36112bd3c8bSSascha Wildner 	struct usb_xfer *xfer = parm->curr_xfer;
36212bd3c8bSSascha Wildner 	const struct usb_config *setup = parm->curr_setup;
36312bd3c8bSSascha Wildner 	struct usb_endpoint_ss_comp_descriptor *ecomp;
36412bd3c8bSSascha Wildner 	struct usb_endpoint_descriptor *edesc;
36512bd3c8bSSascha Wildner 	struct usb_std_packet_size std_size;
36612bd3c8bSSascha Wildner 	usb_frcount_t n_frlengths;
36712bd3c8bSSascha Wildner 	usb_frcount_t n_frbuffers;
36812bd3c8bSSascha Wildner 	usb_frcount_t x;
36906cb2463SMarkus Pfeiffer 	uint16_t maxp_old;
37012bd3c8bSSascha Wildner 	uint8_t type;
37112bd3c8bSSascha Wildner 	uint8_t zmps;
37212bd3c8bSSascha Wildner 
37312bd3c8bSSascha Wildner 	/*
37412bd3c8bSSascha Wildner 	 * Sanity check. The following parameters must be initialized before
37512bd3c8bSSascha Wildner 	 * calling this function.
37612bd3c8bSSascha Wildner 	 */
37712bd3c8bSSascha Wildner 	if ((parm->hc_max_packet_size == 0) ||
37812bd3c8bSSascha Wildner 	    (parm->hc_max_packet_count == 0) ||
37912bd3c8bSSascha Wildner 	    (parm->hc_max_frame_size == 0)) {
38012bd3c8bSSascha Wildner 		parm->err = USB_ERR_INVAL;
38112bd3c8bSSascha Wildner 		goto done;
38212bd3c8bSSascha Wildner 	}
38312bd3c8bSSascha Wildner 	edesc = xfer->endpoint->edesc;
38412bd3c8bSSascha Wildner 	ecomp = xfer->endpoint->ecomp;
38512bd3c8bSSascha Wildner 
38612bd3c8bSSascha Wildner 	type = (edesc->bmAttributes & UE_XFERTYPE);
38712bd3c8bSSascha Wildner 
38812bd3c8bSSascha Wildner 	xfer->flags = setup->flags;
38912bd3c8bSSascha Wildner 	xfer->nframes = setup->frames;
39012bd3c8bSSascha Wildner 	xfer->timeout = setup->timeout;
39112bd3c8bSSascha Wildner 	xfer->callback = setup->callback;
39212bd3c8bSSascha Wildner 	xfer->interval = setup->interval;
39312bd3c8bSSascha Wildner 	xfer->endpointno = edesc->bEndpointAddress;
39412bd3c8bSSascha Wildner 	xfer->max_packet_size = UGETW(edesc->wMaxPacketSize);
39512bd3c8bSSascha Wildner 	xfer->max_packet_count = 1;
39612bd3c8bSSascha Wildner 	/* make a shadow copy: */
39712bd3c8bSSascha Wildner 	xfer->flags_int.usb_mode = parm->udev->flags.usb_mode;
39812bd3c8bSSascha Wildner 
39912bd3c8bSSascha Wildner 	parm->bufsize = setup->bufsize;
40012bd3c8bSSascha Wildner 
40112bd3c8bSSascha Wildner 	switch (parm->speed) {
40212bd3c8bSSascha Wildner 	case USB_SPEED_HIGH:
40312bd3c8bSSascha Wildner 		switch (type) {
40412bd3c8bSSascha Wildner 		case UE_ISOCHRONOUS:
40512bd3c8bSSascha Wildner 		case UE_INTERRUPT:
40657bed822SMarkus Pfeiffer 			xfer->max_packet_count +=
40757bed822SMarkus Pfeiffer 			    (xfer->max_packet_size >> 11) & 3;
40812bd3c8bSSascha Wildner 
40912bd3c8bSSascha Wildner 			/* check for invalid max packet count */
41012bd3c8bSSascha Wildner 			if (xfer->max_packet_count > 3)
41112bd3c8bSSascha Wildner 				xfer->max_packet_count = 3;
41212bd3c8bSSascha Wildner 			break;
41312bd3c8bSSascha Wildner 		default:
41412bd3c8bSSascha Wildner 			break;
41512bd3c8bSSascha Wildner 		}
41612bd3c8bSSascha Wildner 		xfer->max_packet_size &= 0x7FF;
41712bd3c8bSSascha Wildner 		break;
41812bd3c8bSSascha Wildner 	case USB_SPEED_SUPER:
41912bd3c8bSSascha Wildner 		xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3;
42012bd3c8bSSascha Wildner 
42112bd3c8bSSascha Wildner 		if (ecomp != NULL)
42212bd3c8bSSascha Wildner 			xfer->max_packet_count += ecomp->bMaxBurst;
42312bd3c8bSSascha Wildner 
42412bd3c8bSSascha Wildner 		if ((xfer->max_packet_count == 0) ||
42512bd3c8bSSascha Wildner 		    (xfer->max_packet_count > 16))
42612bd3c8bSSascha Wildner 			xfer->max_packet_count = 16;
42712bd3c8bSSascha Wildner 
42812bd3c8bSSascha Wildner 		switch (type) {
42912bd3c8bSSascha Wildner 		case UE_CONTROL:
43012bd3c8bSSascha Wildner 			xfer->max_packet_count = 1;
43112bd3c8bSSascha Wildner 			break;
43212bd3c8bSSascha Wildner 		case UE_ISOCHRONOUS:
43312bd3c8bSSascha Wildner 			if (ecomp != NULL) {
43412bd3c8bSSascha Wildner 				uint8_t mult;
43512bd3c8bSSascha Wildner 
4365e41ab93SMarkus Pfeiffer 				mult = UE_GET_SS_ISO_MULT(
43757bed822SMarkus Pfeiffer 				    ecomp->bmAttributes) + 1;
43812bd3c8bSSascha Wildner 				if (mult > 3)
43912bd3c8bSSascha Wildner 					mult = 3;
44012bd3c8bSSascha Wildner 
44112bd3c8bSSascha Wildner 				xfer->max_packet_count *= mult;
44212bd3c8bSSascha Wildner 			}
44312bd3c8bSSascha Wildner 			break;
44412bd3c8bSSascha Wildner 		default:
44512bd3c8bSSascha Wildner 			break;
44612bd3c8bSSascha Wildner 		}
44712bd3c8bSSascha Wildner 		xfer->max_packet_size &= 0x7FF;
44812bd3c8bSSascha Wildner 		break;
44912bd3c8bSSascha Wildner 	default:
45012bd3c8bSSascha Wildner 		break;
45112bd3c8bSSascha Wildner 	}
45212bd3c8bSSascha Wildner 	/* range check "max_packet_count" */
45312bd3c8bSSascha Wildner 
45412bd3c8bSSascha Wildner 	if (xfer->max_packet_count > parm->hc_max_packet_count) {
45512bd3c8bSSascha Wildner 		xfer->max_packet_count = parm->hc_max_packet_count;
45612bd3c8bSSascha Wildner 	}
45706cb2463SMarkus Pfeiffer 
45806cb2463SMarkus Pfeiffer 	/* store max packet size value before filtering */
45906cb2463SMarkus Pfeiffer 
46006cb2463SMarkus Pfeiffer 	maxp_old = xfer->max_packet_size;
46106cb2463SMarkus Pfeiffer 
46212bd3c8bSSascha Wildner 	/* filter "wMaxPacketSize" according to HC capabilities */
46312bd3c8bSSascha Wildner 
46412bd3c8bSSascha Wildner 	if ((xfer->max_packet_size > parm->hc_max_packet_size) ||
46512bd3c8bSSascha Wildner 	    (xfer->max_packet_size == 0)) {
46612bd3c8bSSascha Wildner 		xfer->max_packet_size = parm->hc_max_packet_size;
46712bd3c8bSSascha Wildner 	}
46812bd3c8bSSascha Wildner 	/* filter "wMaxPacketSize" according to standard sizes */
46912bd3c8bSSascha Wildner 
47012bd3c8bSSascha Wildner 	usbd_get_std_packet_size(&std_size, type, parm->speed);
47112bd3c8bSSascha Wildner 
47212bd3c8bSSascha Wildner 	if (std_size.range.min || std_size.range.max) {
47312bd3c8bSSascha Wildner 
47412bd3c8bSSascha Wildner 		if (xfer->max_packet_size < std_size.range.min) {
47512bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.range.min;
47612bd3c8bSSascha Wildner 		}
47712bd3c8bSSascha Wildner 		if (xfer->max_packet_size > std_size.range.max) {
47812bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.range.max;
47912bd3c8bSSascha Wildner 		}
48012bd3c8bSSascha Wildner 	} else {
48112bd3c8bSSascha Wildner 
48212bd3c8bSSascha Wildner 		if (xfer->max_packet_size >= std_size.fixed[3]) {
48312bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.fixed[3];
48412bd3c8bSSascha Wildner 		} else if (xfer->max_packet_size >= std_size.fixed[2]) {
48512bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.fixed[2];
48612bd3c8bSSascha Wildner 		} else if (xfer->max_packet_size >= std_size.fixed[1]) {
48712bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.fixed[1];
48812bd3c8bSSascha Wildner 		} else {
48912bd3c8bSSascha Wildner 			/* only one possibility left */
49012bd3c8bSSascha Wildner 			xfer->max_packet_size = std_size.fixed[0];
49112bd3c8bSSascha Wildner 		}
49212bd3c8bSSascha Wildner 	}
49312bd3c8bSSascha Wildner 
49406cb2463SMarkus Pfeiffer 	/*
49506cb2463SMarkus Pfeiffer 	 * Check if the max packet size was outside its allowed range
49606cb2463SMarkus Pfeiffer 	 * and clamped to a valid value:
49706cb2463SMarkus Pfeiffer 	 */
49806cb2463SMarkus Pfeiffer 	if (maxp_old != xfer->max_packet_size)
49906cb2463SMarkus Pfeiffer 		xfer->flags_int.maxp_was_clamped = 1;
50006cb2463SMarkus Pfeiffer 
50112bd3c8bSSascha Wildner 	/* compute "max_frame_size" */
50212bd3c8bSSascha Wildner 
50312bd3c8bSSascha Wildner 	usbd_update_max_frame_size(xfer);
50412bd3c8bSSascha Wildner 
50512bd3c8bSSascha Wildner 	/* check interrupt interval and transfer pre-delay */
50612bd3c8bSSascha Wildner 
50712bd3c8bSSascha Wildner 	if (type == UE_ISOCHRONOUS) {
50812bd3c8bSSascha Wildner 
50912bd3c8bSSascha Wildner 		uint16_t frame_limit;
51012bd3c8bSSascha Wildner 
51112bd3c8bSSascha Wildner 		xfer->interval = 0;	/* not used, must be zero */
51212bd3c8bSSascha Wildner 		xfer->flags_int.isochronous_xfr = 1;	/* set flag */
51312bd3c8bSSascha Wildner 
51412bd3c8bSSascha Wildner 		if (xfer->timeout == 0) {
51512bd3c8bSSascha Wildner 			/*
51612bd3c8bSSascha Wildner 			 * set a default timeout in
51712bd3c8bSSascha Wildner 			 * case something goes wrong!
51812bd3c8bSSascha Wildner 			 */
51912bd3c8bSSascha Wildner 			xfer->timeout = 1000 / 4;
52012bd3c8bSSascha Wildner 		}
52112bd3c8bSSascha Wildner 		switch (parm->speed) {
52212bd3c8bSSascha Wildner 		case USB_SPEED_LOW:
52312bd3c8bSSascha Wildner 		case USB_SPEED_FULL:
52412bd3c8bSSascha Wildner 			frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER;
52512bd3c8bSSascha Wildner 			xfer->fps_shift = 0;
52612bd3c8bSSascha Wildner 			break;
52712bd3c8bSSascha Wildner 		default:
52812bd3c8bSSascha Wildner 			frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER;
52912bd3c8bSSascha Wildner 			xfer->fps_shift = edesc->bInterval;
53012bd3c8bSSascha Wildner 			if (xfer->fps_shift > 0)
53112bd3c8bSSascha Wildner 				xfer->fps_shift--;
53212bd3c8bSSascha Wildner 			if (xfer->fps_shift > 3)
53312bd3c8bSSascha Wildner 				xfer->fps_shift = 3;
53412bd3c8bSSascha Wildner 			if (xfer->flags.pre_scale_frames != 0)
53512bd3c8bSSascha Wildner 				xfer->nframes <<= (3 - xfer->fps_shift);
53612bd3c8bSSascha Wildner 			break;
53712bd3c8bSSascha Wildner 		}
53812bd3c8bSSascha Wildner 
53912bd3c8bSSascha Wildner 		if (xfer->nframes > frame_limit) {
54012bd3c8bSSascha Wildner 			/*
54112bd3c8bSSascha Wildner 			 * this is not going to work
54212bd3c8bSSascha Wildner 			 * cross hardware
54312bd3c8bSSascha Wildner 			 */
54412bd3c8bSSascha Wildner 			parm->err = USB_ERR_INVAL;
54512bd3c8bSSascha Wildner 			goto done;
54612bd3c8bSSascha Wildner 		}
54712bd3c8bSSascha Wildner 		if (xfer->nframes == 0) {
54812bd3c8bSSascha Wildner 			/*
54912bd3c8bSSascha Wildner 			 * this is not a valid value
55012bd3c8bSSascha Wildner 			 */
55112bd3c8bSSascha Wildner 			parm->err = USB_ERR_ZERO_NFRAMES;
55212bd3c8bSSascha Wildner 			goto done;
55312bd3c8bSSascha Wildner 		}
55412bd3c8bSSascha Wildner 	} else {
55512bd3c8bSSascha Wildner 
55612bd3c8bSSascha Wildner 		/*
55712bd3c8bSSascha Wildner 		 * If a value is specified use that else check the
55812bd3c8bSSascha Wildner 		 * endpoint descriptor!
55912bd3c8bSSascha Wildner 		 */
56012bd3c8bSSascha Wildner 		if (type == UE_INTERRUPT) {
56112bd3c8bSSascha Wildner 
56212bd3c8bSSascha Wildner 			uint32_t temp;
56312bd3c8bSSascha Wildner 
56412bd3c8bSSascha Wildner 			if (xfer->interval == 0) {
56512bd3c8bSSascha Wildner 
56612bd3c8bSSascha Wildner 				xfer->interval = edesc->bInterval;
56712bd3c8bSSascha Wildner 
56812bd3c8bSSascha Wildner 				switch (parm->speed) {
56912bd3c8bSSascha Wildner 				case USB_SPEED_LOW:
57012bd3c8bSSascha Wildner 				case USB_SPEED_FULL:
57112bd3c8bSSascha Wildner 					break;
57212bd3c8bSSascha Wildner 				default:
57312bd3c8bSSascha Wildner 					/* 125us -> 1ms */
57412bd3c8bSSascha Wildner 					if (xfer->interval < 4)
57512bd3c8bSSascha Wildner 						xfer->interval = 1;
57612bd3c8bSSascha Wildner 					else if (xfer->interval > 16)
57712bd3c8bSSascha Wildner 						xfer->interval = (1 << (16 - 4));
57812bd3c8bSSascha Wildner 					else
57912bd3c8bSSascha Wildner 						xfer->interval =
58012bd3c8bSSascha Wildner 						    (1 << (xfer->interval - 4));
58112bd3c8bSSascha Wildner 					break;
58212bd3c8bSSascha Wildner 				}
58312bd3c8bSSascha Wildner 			}
58412bd3c8bSSascha Wildner 
58512bd3c8bSSascha Wildner 			if (xfer->interval == 0) {
58612bd3c8bSSascha Wildner 				/*
58712bd3c8bSSascha Wildner 				 * One millisecond is the smallest
58812bd3c8bSSascha Wildner 				 * interval we support:
58912bd3c8bSSascha Wildner 				 */
59012bd3c8bSSascha Wildner 				xfer->interval = 1;
59112bd3c8bSSascha Wildner 			}
59212bd3c8bSSascha Wildner 
59312bd3c8bSSascha Wildner 			xfer->fps_shift = 0;
59412bd3c8bSSascha Wildner 			temp = 1;
59512bd3c8bSSascha Wildner 
59612bd3c8bSSascha Wildner 			while ((temp != 0) && (temp < xfer->interval)) {
59712bd3c8bSSascha Wildner 				xfer->fps_shift++;
59812bd3c8bSSascha Wildner 				temp *= 2;
59912bd3c8bSSascha Wildner 			}
60012bd3c8bSSascha Wildner 
60112bd3c8bSSascha Wildner 			switch (parm->speed) {
60212bd3c8bSSascha Wildner 			case USB_SPEED_LOW:
60312bd3c8bSSascha Wildner 			case USB_SPEED_FULL:
60412bd3c8bSSascha Wildner 				break;
60512bd3c8bSSascha Wildner 			default:
60612bd3c8bSSascha Wildner 				xfer->fps_shift += 3;
60712bd3c8bSSascha Wildner 				break;
60812bd3c8bSSascha Wildner 			}
60912bd3c8bSSascha Wildner 		}
61012bd3c8bSSascha Wildner 	}
61112bd3c8bSSascha Wildner 
61212bd3c8bSSascha Wildner 	/*
61312bd3c8bSSascha Wildner 	 * NOTE: we do not allow "max_packet_size" or "max_frame_size"
61412bd3c8bSSascha Wildner 	 * to be equal to zero when setting up USB transfers, hence
61512bd3c8bSSascha Wildner 	 * this leads to alot of extra code in the USB kernel.
61612bd3c8bSSascha Wildner 	 */
61712bd3c8bSSascha Wildner 
61812bd3c8bSSascha Wildner 	if ((xfer->max_frame_size == 0) ||
61912bd3c8bSSascha Wildner 	    (xfer->max_packet_size == 0)) {
62012bd3c8bSSascha Wildner 
62112bd3c8bSSascha Wildner 		zmps = 1;
62212bd3c8bSSascha Wildner 
62312bd3c8bSSascha Wildner 		if ((parm->bufsize <= MIN_PKT) &&
62412bd3c8bSSascha Wildner 		    (type != UE_CONTROL) &&
62512bd3c8bSSascha Wildner 		    (type != UE_BULK)) {
62612bd3c8bSSascha Wildner 
62712bd3c8bSSascha Wildner 			/* workaround */
62812bd3c8bSSascha Wildner 			xfer->max_packet_size = MIN_PKT;
62912bd3c8bSSascha Wildner 			xfer->max_packet_count = 1;
63012bd3c8bSSascha Wildner 			parm->bufsize = 0;	/* automatic setup length */
63112bd3c8bSSascha Wildner 			usbd_update_max_frame_size(xfer);
63212bd3c8bSSascha Wildner 
63312bd3c8bSSascha Wildner 		} else {
63412bd3c8bSSascha Wildner 			parm->err = USB_ERR_ZERO_MAXP;
63512bd3c8bSSascha Wildner 			goto done;
63612bd3c8bSSascha Wildner 		}
63712bd3c8bSSascha Wildner 
63812bd3c8bSSascha Wildner 	} else {
63912bd3c8bSSascha Wildner 		zmps = 0;
64012bd3c8bSSascha Wildner 	}
64112bd3c8bSSascha Wildner 
64212bd3c8bSSascha Wildner 	/*
64312bd3c8bSSascha Wildner 	 * check if we should setup a default
64412bd3c8bSSascha Wildner 	 * length:
64512bd3c8bSSascha Wildner 	 */
64612bd3c8bSSascha Wildner 
64712bd3c8bSSascha Wildner 	if (parm->bufsize == 0) {
64812bd3c8bSSascha Wildner 
64912bd3c8bSSascha Wildner 		parm->bufsize = xfer->max_frame_size;
65012bd3c8bSSascha Wildner 
65112bd3c8bSSascha Wildner 		if (type == UE_ISOCHRONOUS) {
65212bd3c8bSSascha Wildner 			parm->bufsize *= xfer->nframes;
65312bd3c8bSSascha Wildner 		}
65412bd3c8bSSascha Wildner 	}
65512bd3c8bSSascha Wildner 	/*
65612bd3c8bSSascha Wildner 	 * check if we are about to setup a proxy
65712bd3c8bSSascha Wildner 	 * type of buffer:
65812bd3c8bSSascha Wildner 	 */
65912bd3c8bSSascha Wildner 
66012bd3c8bSSascha Wildner 	if (xfer->flags.proxy_buffer) {
66112bd3c8bSSascha Wildner 
66212bd3c8bSSascha Wildner 		/* round bufsize up */
66312bd3c8bSSascha Wildner 
66412bd3c8bSSascha Wildner 		parm->bufsize += (xfer->max_frame_size - 1);
66512bd3c8bSSascha Wildner 
66612bd3c8bSSascha Wildner 		if (parm->bufsize < xfer->max_frame_size) {
66712bd3c8bSSascha Wildner 			/* length wrapped around */
66812bd3c8bSSascha Wildner 			parm->err = USB_ERR_INVAL;
66912bd3c8bSSascha Wildner 			goto done;
67012bd3c8bSSascha Wildner 		}
67112bd3c8bSSascha Wildner 		/* subtract remainder */
67212bd3c8bSSascha Wildner 
67312bd3c8bSSascha Wildner 		parm->bufsize -= (parm->bufsize % xfer->max_frame_size);
67412bd3c8bSSascha Wildner 
67512bd3c8bSSascha Wildner 		/* add length of USB device request structure, if any */
67612bd3c8bSSascha Wildner 
67712bd3c8bSSascha Wildner 		if (type == UE_CONTROL) {
67812bd3c8bSSascha Wildner 			parm->bufsize += REQ_SIZE;	/* SETUP message */
67912bd3c8bSSascha Wildner 		}
68012bd3c8bSSascha Wildner 	}
68112bd3c8bSSascha Wildner 	xfer->max_data_length = parm->bufsize;
68212bd3c8bSSascha Wildner 
68312bd3c8bSSascha Wildner 	/* Setup "n_frlengths" and "n_frbuffers" */
68412bd3c8bSSascha Wildner 
68512bd3c8bSSascha Wildner 	if (type == UE_ISOCHRONOUS) {
68612bd3c8bSSascha Wildner 		n_frlengths = xfer->nframes;
68712bd3c8bSSascha Wildner 		n_frbuffers = 1;
68812bd3c8bSSascha Wildner 	} else {
68912bd3c8bSSascha Wildner 
69012bd3c8bSSascha Wildner 		if (type == UE_CONTROL) {
69112bd3c8bSSascha Wildner 			xfer->flags_int.control_xfr = 1;
69212bd3c8bSSascha Wildner 			if (xfer->nframes == 0) {
69312bd3c8bSSascha Wildner 				if (parm->bufsize <= REQ_SIZE) {
69412bd3c8bSSascha Wildner 					/*
69512bd3c8bSSascha Wildner 					 * there will never be any data
69612bd3c8bSSascha Wildner 					 * stage
69712bd3c8bSSascha Wildner 					 */
69812bd3c8bSSascha Wildner 					xfer->nframes = 1;
69912bd3c8bSSascha Wildner 				} else {
70012bd3c8bSSascha Wildner 					xfer->nframes = 2;
70112bd3c8bSSascha Wildner 				}
70212bd3c8bSSascha Wildner 			}
70312bd3c8bSSascha Wildner 		} else {
70412bd3c8bSSascha Wildner 			if (xfer->nframes == 0) {
70512bd3c8bSSascha Wildner 				xfer->nframes = 1;
70612bd3c8bSSascha Wildner 			}
70712bd3c8bSSascha Wildner 		}
70812bd3c8bSSascha Wildner 
70912bd3c8bSSascha Wildner 		n_frlengths = xfer->nframes;
71012bd3c8bSSascha Wildner 		n_frbuffers = xfer->nframes;
71112bd3c8bSSascha Wildner 	}
71212bd3c8bSSascha Wildner 
71312bd3c8bSSascha Wildner 	/*
71412bd3c8bSSascha Wildner 	 * check if we have room for the
71512bd3c8bSSascha Wildner 	 * USB device request structure:
71612bd3c8bSSascha Wildner 	 */
71712bd3c8bSSascha Wildner 
71812bd3c8bSSascha Wildner 	if (type == UE_CONTROL) {
71912bd3c8bSSascha Wildner 
72012bd3c8bSSascha Wildner 		if (xfer->max_data_length < REQ_SIZE) {
72112bd3c8bSSascha Wildner 			/* length wrapped around or too small bufsize */
72212bd3c8bSSascha Wildner 			parm->err = USB_ERR_INVAL;
72312bd3c8bSSascha Wildner 			goto done;
72412bd3c8bSSascha Wildner 		}
72512bd3c8bSSascha Wildner 		xfer->max_data_length -= REQ_SIZE;
72612bd3c8bSSascha Wildner 	}
72712bd3c8bSSascha Wildner 	/*
72812bd3c8bSSascha Wildner 	 * Setup "frlengths" and shadow "frlengths" for keeping the
72912bd3c8bSSascha Wildner 	 * initial frame lengths when a USB transfer is complete. This
73012bd3c8bSSascha Wildner 	 * information is useful when computing isochronous offsets.
73112bd3c8bSSascha Wildner 	 */
73212bd3c8bSSascha Wildner 	xfer->frlengths = parm->xfer_length_ptr;
73312bd3c8bSSascha Wildner 	parm->xfer_length_ptr += 2 * n_frlengths;
73412bd3c8bSSascha Wildner 
73512bd3c8bSSascha Wildner 	/* setup "frbuffers" */
73612bd3c8bSSascha Wildner 	xfer->frbuffers = parm->xfer_page_cache_ptr;
73712bd3c8bSSascha Wildner 	parm->xfer_page_cache_ptr += n_frbuffers;
73812bd3c8bSSascha Wildner 
73912bd3c8bSSascha Wildner 	/* initialize max frame count */
74012bd3c8bSSascha Wildner 	xfer->max_frame_count = xfer->nframes;
74112bd3c8bSSascha Wildner 
74212bd3c8bSSascha Wildner 	/*
74312bd3c8bSSascha Wildner 	 * check if we need to setup
74412bd3c8bSSascha Wildner 	 * a local buffer:
74512bd3c8bSSascha Wildner 	 */
74612bd3c8bSSascha Wildner 
74712bd3c8bSSascha Wildner 	if (!xfer->flags.ext_buffer) {
74857bed822SMarkus Pfeiffer #if USB_HAVE_BUSDMA
74957bed822SMarkus Pfeiffer 		struct usb_page_search page_info;
75057bed822SMarkus Pfeiffer 		struct usb_page_cache *pc;
75112bd3c8bSSascha Wildner 
75257bed822SMarkus Pfeiffer 		if (usbd_transfer_setup_sub_malloc(parm,
75357bed822SMarkus Pfeiffer 		    &pc, parm->bufsize, 1, 1)) {
75457bed822SMarkus Pfeiffer 			parm->err = USB_ERR_NOMEM;
75557bed822SMarkus Pfeiffer 		} else if (parm->buf != NULL) {
75657bed822SMarkus Pfeiffer 
75757bed822SMarkus Pfeiffer 			usbd_get_page(pc, 0, &page_info);
75857bed822SMarkus Pfeiffer 
75957bed822SMarkus Pfeiffer 			xfer->local_buffer = page_info.buffer;
76057bed822SMarkus Pfeiffer 
76157bed822SMarkus Pfeiffer 			usbd_xfer_set_frame_offset(xfer, 0, 0);
76257bed822SMarkus Pfeiffer 
76357bed822SMarkus Pfeiffer 			if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
76457bed822SMarkus Pfeiffer 				usbd_xfer_set_frame_offset(xfer, REQ_SIZE, 1);
76557bed822SMarkus Pfeiffer 			}
76657bed822SMarkus Pfeiffer 		}
76757bed822SMarkus Pfeiffer #else
76812bd3c8bSSascha Wildner 		/* align data */
76912bd3c8bSSascha Wildner 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
77012bd3c8bSSascha Wildner 
77157bed822SMarkus Pfeiffer 		if (parm->buf != NULL) {
77212bd3c8bSSascha Wildner 			xfer->local_buffer =
77312bd3c8bSSascha Wildner 			    USB_ADD_BYTES(parm->buf, parm->size[0]);
77412bd3c8bSSascha Wildner 
77512bd3c8bSSascha Wildner 			usbd_xfer_set_frame_offset(xfer, 0, 0);
77612bd3c8bSSascha Wildner 
77712bd3c8bSSascha Wildner 			if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
77812bd3c8bSSascha Wildner 				usbd_xfer_set_frame_offset(xfer, REQ_SIZE, 1);
77912bd3c8bSSascha Wildner 			}
78012bd3c8bSSascha Wildner 		}
78112bd3c8bSSascha Wildner 		parm->size[0] += parm->bufsize;
78212bd3c8bSSascha Wildner 
78312bd3c8bSSascha Wildner 		/* align data again */
78412bd3c8bSSascha Wildner 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
78557bed822SMarkus Pfeiffer #endif
78612bd3c8bSSascha Wildner 	}
78712bd3c8bSSascha Wildner 	/*
78812bd3c8bSSascha Wildner 	 * Compute maximum buffer size
78912bd3c8bSSascha Wildner 	 */
79012bd3c8bSSascha Wildner 
79112bd3c8bSSascha Wildner 	if (parm->bufsize_max < parm->bufsize) {
79212bd3c8bSSascha Wildner 		parm->bufsize_max = parm->bufsize;
79312bd3c8bSSascha Wildner 	}
79412bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
79512bd3c8bSSascha Wildner 	if (xfer->flags_int.bdma_enable) {
79612bd3c8bSSascha Wildner 		/*
79712bd3c8bSSascha Wildner 		 * Setup "dma_page_ptr".
79812bd3c8bSSascha Wildner 		 *
79912bd3c8bSSascha Wildner 		 * Proof for formula below:
80012bd3c8bSSascha Wildner 		 *
80112bd3c8bSSascha Wildner 		 * Assume there are three USB frames having length "a", "b" and
80212bd3c8bSSascha Wildner 		 * "c". These USB frames will at maximum need "z"
80312bd3c8bSSascha Wildner 		 * "usb_page" structures. "z" is given by:
80412bd3c8bSSascha Wildner 		 *
80512bd3c8bSSascha Wildner 		 * z = ((a / USB_PAGE_SIZE) + 2) + ((b / USB_PAGE_SIZE) + 2) +
80612bd3c8bSSascha Wildner 		 * ((c / USB_PAGE_SIZE) + 2);
80712bd3c8bSSascha Wildner 		 *
80812bd3c8bSSascha Wildner 		 * Constraining "a", "b" and "c" like this:
80912bd3c8bSSascha Wildner 		 *
81012bd3c8bSSascha Wildner 		 * (a + b + c) <= parm->bufsize
81112bd3c8bSSascha Wildner 		 *
81212bd3c8bSSascha Wildner 		 * We know that:
81312bd3c8bSSascha Wildner 		 *
81412bd3c8bSSascha Wildner 		 * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
81512bd3c8bSSascha Wildner 		 *
81612bd3c8bSSascha Wildner 		 * Here is the general formula:
81712bd3c8bSSascha Wildner 		 */
81812bd3c8bSSascha Wildner 		xfer->dma_page_ptr = parm->dma_page_ptr;
81912bd3c8bSSascha Wildner 		parm->dma_page_ptr += (2 * n_frbuffers);
82012bd3c8bSSascha Wildner 		parm->dma_page_ptr += (parm->bufsize / USB_PAGE_SIZE);
82112bd3c8bSSascha Wildner 	}
82212bd3c8bSSascha Wildner #endif
82312bd3c8bSSascha Wildner 	if (zmps) {
82412bd3c8bSSascha Wildner 		/* correct maximum data length */
82512bd3c8bSSascha Wildner 		xfer->max_data_length = 0;
82612bd3c8bSSascha Wildner 	}
82712bd3c8bSSascha Wildner 	/* subtract USB frame remainder from "hc_max_frame_size" */
82812bd3c8bSSascha Wildner 
82912bd3c8bSSascha Wildner 	xfer->max_hc_frame_size =
83012bd3c8bSSascha Wildner 	    (parm->hc_max_frame_size -
83112bd3c8bSSascha Wildner 	    (parm->hc_max_frame_size % xfer->max_frame_size));
83212bd3c8bSSascha Wildner 
83312bd3c8bSSascha Wildner 	if (xfer->max_hc_frame_size == 0) {
83412bd3c8bSSascha Wildner 		parm->err = USB_ERR_INVAL;
83512bd3c8bSSascha Wildner 		goto done;
83612bd3c8bSSascha Wildner 	}
83712bd3c8bSSascha Wildner 
83812bd3c8bSSascha Wildner 	/* initialize frame buffers */
83912bd3c8bSSascha Wildner 
84012bd3c8bSSascha Wildner 	if (parm->buf) {
84112bd3c8bSSascha Wildner 		for (x = 0; x != n_frbuffers; x++) {
84212bd3c8bSSascha Wildner 			xfer->frbuffers[x].tag_parent =
84312bd3c8bSSascha Wildner 			    &xfer->xroot->dma_parent_tag;
84412bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
84512bd3c8bSSascha Wildner 			if (xfer->flags_int.bdma_enable &&
84612bd3c8bSSascha Wildner 			    (parm->bufsize_max > 0)) {
84712bd3c8bSSascha Wildner 
84812bd3c8bSSascha Wildner 				if (usb_pc_dmamap_create(
84912bd3c8bSSascha Wildner 				    xfer->frbuffers + x,
85012bd3c8bSSascha Wildner 				    parm->bufsize_max)) {
85112bd3c8bSSascha Wildner 					parm->err = USB_ERR_NOMEM;
85212bd3c8bSSascha Wildner 					goto done;
85312bd3c8bSSascha Wildner 				}
85412bd3c8bSSascha Wildner 			}
85512bd3c8bSSascha Wildner #endif
85612bd3c8bSSascha Wildner 		}
85712bd3c8bSSascha Wildner 	}
85812bd3c8bSSascha Wildner done:
85912bd3c8bSSascha Wildner 	if (parm->err) {
86012bd3c8bSSascha Wildner 		/*
86112bd3c8bSSascha Wildner 		 * Set some dummy values so that we avoid division by zero:
86212bd3c8bSSascha Wildner 		 */
86312bd3c8bSSascha Wildner 		xfer->max_hc_frame_size = 1;
86412bd3c8bSSascha Wildner 		xfer->max_frame_size = 1;
86512bd3c8bSSascha Wildner 		xfer->max_packet_size = 1;
86612bd3c8bSSascha Wildner 		xfer->max_data_length = 0;
86712bd3c8bSSascha Wildner 		xfer->nframes = 0;
86812bd3c8bSSascha Wildner 		xfer->max_frame_count = 0;
86912bd3c8bSSascha Wildner 	}
87012bd3c8bSSascha Wildner }
87112bd3c8bSSascha Wildner 
87212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
87312bd3c8bSSascha Wildner  *	usbd_transfer_setup - setup an array of USB transfers
87412bd3c8bSSascha Wildner  *
87512bd3c8bSSascha Wildner  * NOTE: You must always call "usbd_transfer_unsetup" after calling
87612bd3c8bSSascha Wildner  * "usbd_transfer_setup" if success was returned.
87712bd3c8bSSascha Wildner  *
87812bd3c8bSSascha Wildner  * The idea is that the USB device driver should pre-allocate all its
87912bd3c8bSSascha Wildner  * transfers by one call to this function.
88012bd3c8bSSascha Wildner  *
88112bd3c8bSSascha Wildner  * Return values:
88212bd3c8bSSascha Wildner  *    0: Success
88312bd3c8bSSascha Wildner  * Else: Failure
88412bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
88512bd3c8bSSascha Wildner usb_error_t
usbd_transfer_setup(struct usb_device * udev,const uint8_t * ifaces,struct usb_xfer ** ppxfer,const struct usb_config * setup_start,uint16_t n_setup,void * priv_sc,struct lock * xfer_lock)88612bd3c8bSSascha Wildner usbd_transfer_setup(struct usb_device *udev,
88712bd3c8bSSascha Wildner     const uint8_t *ifaces, struct usb_xfer **ppxfer,
88812bd3c8bSSascha Wildner     const struct usb_config *setup_start, uint16_t n_setup,
889722d05c3SSascha Wildner     void *priv_sc, struct lock *xfer_lock)
89012bd3c8bSSascha Wildner {
89112bd3c8bSSascha Wildner 	const struct usb_config *setup_end = setup_start + n_setup;
89212bd3c8bSSascha Wildner 	const struct usb_config *setup;
89357bed822SMarkus Pfeiffer 	struct usb_setup_params *parm;
89412bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
89512bd3c8bSSascha Wildner 	struct usb_xfer_root *info;
89612bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
89712bd3c8bSSascha Wildner 	void *buf = NULL;
89857bed822SMarkus Pfeiffer 	usb_error_t error = 0;
89912bd3c8bSSascha Wildner 	uint16_t n;
90012bd3c8bSSascha Wildner 	uint16_t refcount;
90157bed822SMarkus Pfeiffer 	uint8_t do_unlock;
90212bd3c8bSSascha Wildner 
90363da4a34SSascha Wildner #if 0
90412bd3c8bSSascha Wildner 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
90512bd3c8bSSascha Wildner 	    "usbd_transfer_setup can sleep!");
90663da4a34SSascha Wildner #endif
90763da4a34SSascha Wildner 
90812bd3c8bSSascha Wildner 	/* do some checking first */
90912bd3c8bSSascha Wildner 
91012bd3c8bSSascha Wildner 	if (n_setup == 0) {
91112bd3c8bSSascha Wildner 		DPRINTFN(6, "setup array has zero length!\n");
91212bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
91312bd3c8bSSascha Wildner 	}
914681e352eSSascha Wildner 	if (ifaces == NULL) {
91512bd3c8bSSascha Wildner 		DPRINTFN(6, "ifaces array is NULL!\n");
91612bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
91712bd3c8bSSascha Wildner 	}
918722d05c3SSascha Wildner 	if (xfer_lock == NULL) {
9193a76bbe8SSascha Wildner 		panic("xfer without lock!\n");
92012bd3c8bSSascha Wildner 		DPRINTFN(6, "using global lock\n");
92112bd3c8bSSascha Wildner 	}
92257bed822SMarkus Pfeiffer 
92357bed822SMarkus Pfeiffer 	/* more sanity checks */
92457bed822SMarkus Pfeiffer 
92512bd3c8bSSascha Wildner 	for (setup = setup_start, n = 0;
92612bd3c8bSSascha Wildner 	    setup != setup_end; setup++, n++) {
92712bd3c8bSSascha Wildner 		if (setup->bufsize == (usb_frlength_t)-1) {
92857bed822SMarkus Pfeiffer 			error = USB_ERR_BAD_BUFSIZE;
92912bd3c8bSSascha Wildner 			DPRINTF("invalid bufsize\n");
93012bd3c8bSSascha Wildner 		}
93112bd3c8bSSascha Wildner 		if (setup->callback == NULL) {
93257bed822SMarkus Pfeiffer 			error = USB_ERR_NO_CALLBACK;
93312bd3c8bSSascha Wildner 			DPRINTF("no callback\n");
93412bd3c8bSSascha Wildner 		}
93512bd3c8bSSascha Wildner 		ppxfer[n] = NULL;
93612bd3c8bSSascha Wildner 	}
93712bd3c8bSSascha Wildner 
93857bed822SMarkus Pfeiffer 	if (error)
93957bed822SMarkus Pfeiffer 		return (error);
94012bd3c8bSSascha Wildner 
94157bed822SMarkus Pfeiffer 	/* Protect scratch area */
94257bed822SMarkus Pfeiffer 	do_unlock = usbd_enum_lock(udev);
94312bd3c8bSSascha Wildner 
94457bed822SMarkus Pfeiffer 	refcount = 0;
94557bed822SMarkus Pfeiffer 	info = NULL;
94657bed822SMarkus Pfeiffer 
94757bed822SMarkus Pfeiffer 	parm = &udev->scratch.xfer_setup[0].parm;
94857bed822SMarkus Pfeiffer 	memset(parm, 0, sizeof(*parm));
94957bed822SMarkus Pfeiffer 
95057bed822SMarkus Pfeiffer 	parm->udev = udev;
95157bed822SMarkus Pfeiffer 	parm->speed = usbd_get_speed(udev);
95257bed822SMarkus Pfeiffer 	parm->hc_max_packet_count = 1;
95357bed822SMarkus Pfeiffer 
95457bed822SMarkus Pfeiffer 	if (parm->speed >= USB_SPEED_MAX) {
95557bed822SMarkus Pfeiffer 		parm->err = USB_ERR_INVAL;
95612bd3c8bSSascha Wildner 		goto done;
95712bd3c8bSSascha Wildner 	}
95812bd3c8bSSascha Wildner 	/* setup all transfers */
95912bd3c8bSSascha Wildner 
96012bd3c8bSSascha Wildner 	while (1) {
96112bd3c8bSSascha Wildner 
96212bd3c8bSSascha Wildner 		if (buf) {
96312bd3c8bSSascha Wildner 			/*
96412bd3c8bSSascha Wildner 			 * Initialize the "usb_xfer_root" structure,
96512bd3c8bSSascha Wildner 			 * which is common for all our USB transfers.
96612bd3c8bSSascha Wildner 			 */
96712bd3c8bSSascha Wildner 			info = USB_ADD_BYTES(buf, 0);
96812bd3c8bSSascha Wildner 
96912bd3c8bSSascha Wildner 			info->memory_base = buf;
97057bed822SMarkus Pfeiffer 			info->memory_size = parm->size[0];
97112bd3c8bSSascha Wildner 
97212bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
97357bed822SMarkus Pfeiffer 			info->dma_page_cache_start = USB_ADD_BYTES(buf, parm->size[4]);
97457bed822SMarkus Pfeiffer 			info->dma_page_cache_end = USB_ADD_BYTES(buf, parm->size[5]);
97512bd3c8bSSascha Wildner #endif
97657bed822SMarkus Pfeiffer 			info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm->size[5]);
97757bed822SMarkus Pfeiffer 			info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm->size[2]);
97812bd3c8bSSascha Wildner 
97912bd3c8bSSascha Wildner 			cv_init(&info->cv_drain, "WDRAIN");
98012bd3c8bSSascha Wildner 
981722d05c3SSascha Wildner 			info->xfer_lock = xfer_lock;
98212bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
98312bd3c8bSSascha Wildner 			usb_dma_tag_setup(&info->dma_parent_tag,
98457bed822SMarkus Pfeiffer 			    parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
985dd681da6SMatthew Dillon 			    xfer_lock, &usb_bdma_done_event,
986dd681da6SMatthew Dillon 			    udev->bus->dma_bits, parm->dma_tag_max);
98712bd3c8bSSascha Wildner #endif
98812bd3c8bSSascha Wildner 
98912bd3c8bSSascha Wildner 			info->bus = udev->bus;
99012bd3c8bSSascha Wildner 			info->udev = udev;
99112bd3c8bSSascha Wildner 
99212bd3c8bSSascha Wildner 			TAILQ_INIT(&info->done_q.head);
99312bd3c8bSSascha Wildner 			info->done_q.command = &usbd_callback_wrapper;
99412bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
99512bd3c8bSSascha Wildner 			TAILQ_INIT(&info->dma_q.head);
99612bd3c8bSSascha Wildner 			info->dma_q.command = &usb_bdma_work_loop;
99712bd3c8bSSascha Wildner #endif
99812bd3c8bSSascha Wildner 			info->done_m[0].hdr.pm_callback = &usb_callback_proc;
99912bd3c8bSSascha Wildner 			info->done_m[0].xroot = info;
100012bd3c8bSSascha Wildner 			info->done_m[1].hdr.pm_callback = &usb_callback_proc;
100112bd3c8bSSascha Wildner 			info->done_m[1].xroot = info;
100212bd3c8bSSascha Wildner 
100312bd3c8bSSascha Wildner 			/*
100412bd3c8bSSascha Wildner 			 * In device side mode control endpoint
100512bd3c8bSSascha Wildner 			 * requests need to run from a separate
100612bd3c8bSSascha Wildner 			 * context, else there is a chance of
100712bd3c8bSSascha Wildner 			 * deadlock!
100812bd3c8bSSascha Wildner 			 */
100912bd3c8bSSascha Wildner 			if (setup_start == usb_control_ep_cfg)
101012bd3c8bSSascha Wildner 				info->done_p =
101157bed822SMarkus Pfeiffer 				    USB_BUS_CONTROL_XFER_PROC(udev->bus);
101212bd3c8bSSascha Wildner 			else
101312bd3c8bSSascha Wildner 				info->done_p =
101457bed822SMarkus Pfeiffer 				    USB_BUS_NON_GIANT_PROC(udev->bus);
101512bd3c8bSSascha Wildner 		}
101612bd3c8bSSascha Wildner 		/* reset sizes */
101712bd3c8bSSascha Wildner 
101857bed822SMarkus Pfeiffer 		parm->size[0] = 0;
101957bed822SMarkus Pfeiffer 		parm->buf = buf;
102057bed822SMarkus Pfeiffer 		parm->size[0] += sizeof(info[0]);
102112bd3c8bSSascha Wildner 
102212bd3c8bSSascha Wildner 		for (setup = setup_start, n = 0;
102312bd3c8bSSascha Wildner 		    setup != setup_end; setup++, n++) {
102412bd3c8bSSascha Wildner 
102512bd3c8bSSascha Wildner 			/* skip USB transfers without callbacks: */
102612bd3c8bSSascha Wildner 			if (setup->callback == NULL) {
102712bd3c8bSSascha Wildner 				continue;
102812bd3c8bSSascha Wildner 			}
102912bd3c8bSSascha Wildner 			/* see if there is a matching endpoint */
103012bd3c8bSSascha Wildner 			ep = usbd_get_endpoint(udev,
103112bd3c8bSSascha Wildner 			    ifaces[setup->if_index], setup);
103257bed822SMarkus Pfeiffer 
10335e41ab93SMarkus Pfeiffer 			/*
10345e41ab93SMarkus Pfeiffer 			 * Check that the USB PIPE is valid and that
10355e41ab93SMarkus Pfeiffer 			 * the endpoint mode is proper.
10365e41ab93SMarkus Pfeiffer 			 *
10375e41ab93SMarkus Pfeiffer 			 * Make sure we don't allocate a streams
10385e41ab93SMarkus Pfeiffer 			 * transfer when such a combination is not
10395e41ab93SMarkus Pfeiffer 			 * valid.
10405e41ab93SMarkus Pfeiffer 			 */
10415e41ab93SMarkus Pfeiffer 			if ((ep == NULL) || (ep->methods == NULL) ||
10425e41ab93SMarkus Pfeiffer 			    ((ep->ep_mode != USB_EP_MODE_STREAMS) &&
10435e41ab93SMarkus Pfeiffer 			    (ep->ep_mode != USB_EP_MODE_DEFAULT)) ||
10445e41ab93SMarkus Pfeiffer 			    (setup->stream_id != 0 &&
10455e41ab93SMarkus Pfeiffer 			    (setup->stream_id >= USB_MAX_EP_STREAMS ||
10465e41ab93SMarkus Pfeiffer 			    (ep->ep_mode != USB_EP_MODE_STREAMS)))) {
104712bd3c8bSSascha Wildner 				if (setup->flags.no_pipe_ok)
104812bd3c8bSSascha Wildner 					continue;
104912bd3c8bSSascha Wildner 				if ((setup->usb_mode != USB_MODE_DUAL) &&
105012bd3c8bSSascha Wildner 				    (setup->usb_mode != udev->flags.usb_mode))
105112bd3c8bSSascha Wildner 					continue;
105257bed822SMarkus Pfeiffer 				parm->err = USB_ERR_NO_PIPE;
105312bd3c8bSSascha Wildner 				goto done;
105412bd3c8bSSascha Wildner 			}
105512bd3c8bSSascha Wildner 
105612bd3c8bSSascha Wildner 			/* align data properly */
105757bed822SMarkus Pfeiffer 			parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
105812bd3c8bSSascha Wildner 
105912bd3c8bSSascha Wildner 			/* store current setup pointer */
106057bed822SMarkus Pfeiffer 			parm->curr_setup = setup;
106112bd3c8bSSascha Wildner 
106212bd3c8bSSascha Wildner 			if (buf) {
106312bd3c8bSSascha Wildner 				/*
106412bd3c8bSSascha Wildner 				 * Common initialization of the
106512bd3c8bSSascha Wildner 				 * "usb_xfer" structure.
106612bd3c8bSSascha Wildner 				 */
106757bed822SMarkus Pfeiffer 				xfer = USB_ADD_BYTES(buf, parm->size[0]);
106812bd3c8bSSascha Wildner 				xfer->address = udev->address;
106912bd3c8bSSascha Wildner 				xfer->priv_sc = priv_sc;
107012bd3c8bSSascha Wildner 				xfer->xroot = info;
107112bd3c8bSSascha Wildner 
107212bd3c8bSSascha Wildner 				usb_callout_init_mtx(&xfer->timeout_handle,
1073722d05c3SSascha Wildner 				    &udev->bus->bus_lock, 0);
107412bd3c8bSSascha Wildner 			} else {
107512bd3c8bSSascha Wildner 				/*
107612bd3c8bSSascha Wildner 				 * Setup a dummy xfer, hence we are
107712bd3c8bSSascha Wildner 				 * writing to the "usb_xfer"
107812bd3c8bSSascha Wildner 				 * structure pointed to by "xfer"
107912bd3c8bSSascha Wildner 				 * before we have allocated any
108012bd3c8bSSascha Wildner 				 * memory:
108112bd3c8bSSascha Wildner 				 */
108257bed822SMarkus Pfeiffer 				xfer = &udev->scratch.xfer_setup[0].dummy;
108357bed822SMarkus Pfeiffer 				memset(xfer, 0, sizeof(*xfer));
108412bd3c8bSSascha Wildner 				refcount++;
108512bd3c8bSSascha Wildner 			}
108612bd3c8bSSascha Wildner 
108712bd3c8bSSascha Wildner 			/* set transfer endpoint pointer */
108812bd3c8bSSascha Wildner 			xfer->endpoint = ep;
108912bd3c8bSSascha Wildner 
10905e41ab93SMarkus Pfeiffer 			/* set transfer stream ID */
10915e41ab93SMarkus Pfeiffer 			xfer->stream_id = setup->stream_id;
10925e41ab93SMarkus Pfeiffer 
109357bed822SMarkus Pfeiffer 			parm->size[0] += sizeof(xfer[0]);
109457bed822SMarkus Pfeiffer 			parm->methods = xfer->endpoint->methods;
109557bed822SMarkus Pfeiffer 			parm->curr_xfer = xfer;
109612bd3c8bSSascha Wildner 
109712bd3c8bSSascha Wildner 			/*
109812bd3c8bSSascha Wildner 			 * Call the Host or Device controller transfer
109912bd3c8bSSascha Wildner 			 * setup routine:
110012bd3c8bSSascha Wildner 			 */
110157bed822SMarkus Pfeiffer 			(udev->bus->methods->xfer_setup) (parm);
110212bd3c8bSSascha Wildner 
110312bd3c8bSSascha Wildner 			/* check for error */
110457bed822SMarkus Pfeiffer 			if (parm->err)
110512bd3c8bSSascha Wildner 				goto done;
110612bd3c8bSSascha Wildner 
110712bd3c8bSSascha Wildner 			if (buf) {
110812bd3c8bSSascha Wildner 				/*
110912bd3c8bSSascha Wildner 				 * Increment the endpoint refcount. This
111012bd3c8bSSascha Wildner 				 * basically prevents setting a new
111112bd3c8bSSascha Wildner 				 * configuration and alternate setting
111212bd3c8bSSascha Wildner 				 * when USB transfers are in use on
111312bd3c8bSSascha Wildner 				 * the given interface. Search the USB
111412bd3c8bSSascha Wildner 				 * code for "endpoint->refcount_alloc" if you
111512bd3c8bSSascha Wildner 				 * want more information.
111612bd3c8bSSascha Wildner 				 */
111712bd3c8bSSascha Wildner 				USB_BUS_LOCK(info->bus);
111812bd3c8bSSascha Wildner 				if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
111957bed822SMarkus Pfeiffer 					parm->err = USB_ERR_INVAL;
112012bd3c8bSSascha Wildner 
112112bd3c8bSSascha Wildner 				xfer->endpoint->refcount_alloc++;
112212bd3c8bSSascha Wildner 
112312bd3c8bSSascha Wildner 				if (xfer->endpoint->refcount_alloc == 0)
112412bd3c8bSSascha Wildner 					panic("usbd_transfer_setup(): Refcount wrapped to zero\n");
112512bd3c8bSSascha Wildner 				USB_BUS_UNLOCK(info->bus);
112612bd3c8bSSascha Wildner 
112712bd3c8bSSascha Wildner 				/*
112812bd3c8bSSascha Wildner 				 * Whenever we set ppxfer[] then we
112912bd3c8bSSascha Wildner 				 * also need to increment the
113012bd3c8bSSascha Wildner 				 * "setup_refcount":
113112bd3c8bSSascha Wildner 				 */
113212bd3c8bSSascha Wildner 				info->setup_refcount++;
113312bd3c8bSSascha Wildner 
113412bd3c8bSSascha Wildner 				/*
113512bd3c8bSSascha Wildner 				 * Transfer is successfully setup and
113612bd3c8bSSascha Wildner 				 * can be used:
113712bd3c8bSSascha Wildner 				 */
113812bd3c8bSSascha Wildner 				ppxfer[n] = xfer;
113912bd3c8bSSascha Wildner 			}
114012bd3c8bSSascha Wildner 
114112bd3c8bSSascha Wildner 			/* check for error */
114257bed822SMarkus Pfeiffer 			if (parm->err)
114312bd3c8bSSascha Wildner 				goto done;
114412bd3c8bSSascha Wildner 		}
114512bd3c8bSSascha Wildner 
114657bed822SMarkus Pfeiffer 		if (buf != NULL || parm->err != 0)
114712bd3c8bSSascha Wildner 			goto done;
114857bed822SMarkus Pfeiffer 
114957bed822SMarkus Pfeiffer 		/* if no transfers, nothing to do */
115057bed822SMarkus Pfeiffer 		if (refcount == 0)
115112bd3c8bSSascha Wildner 			goto done;
115257bed822SMarkus Pfeiffer 
115312bd3c8bSSascha Wildner 		/* align data properly */
115457bed822SMarkus Pfeiffer 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
115512bd3c8bSSascha Wildner 
115612bd3c8bSSascha Wildner 		/* store offset temporarily */
115757bed822SMarkus Pfeiffer 		parm->size[1] = parm->size[0];
115812bd3c8bSSascha Wildner 
115912bd3c8bSSascha Wildner 		/*
116012bd3c8bSSascha Wildner 		 * The number of DMA tags required depends on
116112bd3c8bSSascha Wildner 		 * the number of endpoints. The current estimate
116212bd3c8bSSascha Wildner 		 * for maximum number of DMA tags per endpoint
116357bed822SMarkus Pfeiffer 		 * is three:
116457bed822SMarkus Pfeiffer 		 * 1) for loading memory
116557bed822SMarkus Pfeiffer 		 * 2) for allocating memory
116657bed822SMarkus Pfeiffer 		 * 3) for fixing memory [UHCI]
116712bd3c8bSSascha Wildner 		 */
116857bed822SMarkus Pfeiffer 		parm->dma_tag_max += 3 * MIN(n_setup, USB_EP_MAX);
116912bd3c8bSSascha Wildner 
117012bd3c8bSSascha Wildner 		/*
117112bd3c8bSSascha Wildner 		 * DMA tags for QH, TD, Data and more.
117212bd3c8bSSascha Wildner 		 */
117357bed822SMarkus Pfeiffer 		parm->dma_tag_max += 8;
117412bd3c8bSSascha Wildner 
117557bed822SMarkus Pfeiffer 		parm->dma_tag_p += parm->dma_tag_max;
117612bd3c8bSSascha Wildner 
117757bed822SMarkus Pfeiffer 		parm->size[0] += ((uint8_t *)parm->dma_tag_p) -
117812bd3c8bSSascha Wildner 		    ((uint8_t *)0);
117912bd3c8bSSascha Wildner 
118012bd3c8bSSascha Wildner 		/* align data properly */
118157bed822SMarkus Pfeiffer 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
118212bd3c8bSSascha Wildner 
118312bd3c8bSSascha Wildner 		/* store offset temporarily */
118457bed822SMarkus Pfeiffer 		parm->size[3] = parm->size[0];
118512bd3c8bSSascha Wildner 
118657bed822SMarkus Pfeiffer 		parm->size[0] += ((uint8_t *)parm->dma_page_ptr) -
118712bd3c8bSSascha Wildner 		    ((uint8_t *)0);
118812bd3c8bSSascha Wildner 
118912bd3c8bSSascha Wildner 		/* align data properly */
119057bed822SMarkus Pfeiffer 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
119112bd3c8bSSascha Wildner 
119212bd3c8bSSascha Wildner 		/* store offset temporarily */
119357bed822SMarkus Pfeiffer 		parm->size[4] = parm->size[0];
119412bd3c8bSSascha Wildner 
119557bed822SMarkus Pfeiffer 		parm->size[0] += ((uint8_t *)parm->dma_page_cache_ptr) -
119612bd3c8bSSascha Wildner 		    ((uint8_t *)0);
119712bd3c8bSSascha Wildner 
119812bd3c8bSSascha Wildner 		/* store end offset temporarily */
119957bed822SMarkus Pfeiffer 		parm->size[5] = parm->size[0];
120012bd3c8bSSascha Wildner 
120157bed822SMarkus Pfeiffer 		parm->size[0] += ((uint8_t *)parm->xfer_page_cache_ptr) -
120212bd3c8bSSascha Wildner 		    ((uint8_t *)0);
120312bd3c8bSSascha Wildner 
120412bd3c8bSSascha Wildner 		/* store end offset temporarily */
120512bd3c8bSSascha Wildner 
120657bed822SMarkus Pfeiffer 		parm->size[2] = parm->size[0];
120712bd3c8bSSascha Wildner 
120812bd3c8bSSascha Wildner 		/* align data properly */
120957bed822SMarkus Pfeiffer 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
121012bd3c8bSSascha Wildner 
121157bed822SMarkus Pfeiffer 		parm->size[6] = parm->size[0];
121212bd3c8bSSascha Wildner 
121357bed822SMarkus Pfeiffer 		parm->size[0] += ((uint8_t *)parm->xfer_length_ptr) -
121412bd3c8bSSascha Wildner 		    ((uint8_t *)0);
121512bd3c8bSSascha Wildner 
121612bd3c8bSSascha Wildner 		/* align data properly */
121757bed822SMarkus Pfeiffer 		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
121812bd3c8bSSascha Wildner 
121912bd3c8bSSascha Wildner 		/* allocate zeroed memory */
122057bed822SMarkus Pfeiffer 		buf = kmalloc(parm->size[0], M_USB, M_WAITOK | M_ZERO);
122112bd3c8bSSascha Wildner 
122257bed822SMarkus Pfeiffer 		if (buf == NULL) {
122357bed822SMarkus Pfeiffer 			parm->err = USB_ERR_NOMEM;
122457bed822SMarkus Pfeiffer 			DPRINTFN(0, "cannot allocate memory block for "
122557bed822SMarkus Pfeiffer 			    "configuration (%d bytes)\n",
122657bed822SMarkus Pfeiffer 			    parm->size[0]);
122757bed822SMarkus Pfeiffer 			goto done;
122857bed822SMarkus Pfeiffer 		}
122957bed822SMarkus Pfeiffer 		parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]);
123057bed822SMarkus Pfeiffer 		parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]);
123157bed822SMarkus Pfeiffer 		parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]);
123257bed822SMarkus Pfeiffer 		parm->xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[5]);
123357bed822SMarkus Pfeiffer 		parm->xfer_length_ptr = USB_ADD_BYTES(buf, parm->size[6]);
123412bd3c8bSSascha Wildner 	}
123512bd3c8bSSascha Wildner 
123612bd3c8bSSascha Wildner done:
123712bd3c8bSSascha Wildner 	if (buf) {
123812bd3c8bSSascha Wildner 		if (info->setup_refcount == 0) {
123912bd3c8bSSascha Wildner 			/*
124012bd3c8bSSascha Wildner 			 * "usbd_transfer_unsetup_sub" will unlock
124112bd3c8bSSascha Wildner 			 * the bus mutex before returning !
124212bd3c8bSSascha Wildner 			 */
124312bd3c8bSSascha Wildner 			USB_BUS_LOCK(info->bus);
124412bd3c8bSSascha Wildner 
124512bd3c8bSSascha Wildner 			/* something went wrong */
124612bd3c8bSSascha Wildner 			usbd_transfer_unsetup_sub(info, 0);
124712bd3c8bSSascha Wildner 		}
124812bd3c8bSSascha Wildner 	}
124957bed822SMarkus Pfeiffer 
125057bed822SMarkus Pfeiffer 	/* check if any errors happened */
125157bed822SMarkus Pfeiffer 	if (parm->err)
125212bd3c8bSSascha Wildner 		usbd_transfer_unsetup(ppxfer, n_setup);
125357bed822SMarkus Pfeiffer 
125457bed822SMarkus Pfeiffer 	error = parm->err;
125557bed822SMarkus Pfeiffer 
125657bed822SMarkus Pfeiffer 	if (do_unlock)
125757bed822SMarkus Pfeiffer 		usbd_enum_unlock(udev);
125857bed822SMarkus Pfeiffer 
125957bed822SMarkus Pfeiffer 	return (error);
126012bd3c8bSSascha Wildner }
126112bd3c8bSSascha Wildner 
126212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
126312bd3c8bSSascha Wildner  *	usbd_transfer_unsetup_sub - factored out code
126412bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
126512bd3c8bSSascha Wildner static void
usbd_transfer_unsetup_sub(struct usb_xfer_root * info,uint8_t needs_delay)126612bd3c8bSSascha Wildner usbd_transfer_unsetup_sub(struct usb_xfer_root *info, uint8_t needs_delay)
126712bd3c8bSSascha Wildner {
126812bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
126912bd3c8bSSascha Wildner 	struct usb_page_cache *pc;
127012bd3c8bSSascha Wildner #endif
127112bd3c8bSSascha Wildner 
1272722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(info->bus);
127312bd3c8bSSascha Wildner 
127412bd3c8bSSascha Wildner 	/* wait for any outstanding DMA operations */
1275e15d1b68SMatthew Dillon 	/* This is insane */
127612bd3c8bSSascha Wildner 	if (needs_delay) {
127712bd3c8bSSascha Wildner 		usb_timeout_t temp;
127812bd3c8bSSascha Wildner 		temp = usbd_get_dma_delay(info->udev);
127912bd3c8bSSascha Wildner 		if (temp != 0) {
1280722d05c3SSascha Wildner 			usb_pause_mtx(&info->bus->bus_lock,
128112bd3c8bSSascha Wildner 			    USB_MS_TO_TICKS(temp));
128212bd3c8bSSascha Wildner 		}
128312bd3c8bSSascha Wildner 	}
128412bd3c8bSSascha Wildner 
128512bd3c8bSSascha Wildner 	/* make sure that our done messages are not queued anywhere */
128612bd3c8bSSascha Wildner 	usb_proc_mwait(info->done_p, &info->done_m[0], &info->done_m[1]);
128712bd3c8bSSascha Wildner 
128812bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(info->bus);
128912bd3c8bSSascha Wildner 
129012bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
129112bd3c8bSSascha Wildner 	/* free DMA'able memory, if any */
129212bd3c8bSSascha Wildner 	pc = info->dma_page_cache_start;
129312bd3c8bSSascha Wildner 	while (pc != info->dma_page_cache_end) {
129412bd3c8bSSascha Wildner 		usb_pc_free_mem(pc);
129512bd3c8bSSascha Wildner 		pc++;
129612bd3c8bSSascha Wildner 	}
129712bd3c8bSSascha Wildner 
129812bd3c8bSSascha Wildner 	/* free DMA maps in all "xfer->frbuffers" */
129912bd3c8bSSascha Wildner 	pc = info->xfer_page_cache_start;
130012bd3c8bSSascha Wildner 	while (pc != info->xfer_page_cache_end) {
130112bd3c8bSSascha Wildner 		usb_pc_dmamap_destroy(pc);
130212bd3c8bSSascha Wildner 		pc++;
130312bd3c8bSSascha Wildner 	}
130412bd3c8bSSascha Wildner 
130512bd3c8bSSascha Wildner 	/* free all DMA tags */
130612bd3c8bSSascha Wildner 	usb_dma_tag_unsetup(&info->dma_parent_tag);
130712bd3c8bSSascha Wildner #endif
130812bd3c8bSSascha Wildner 
130912bd3c8bSSascha Wildner 	cv_destroy(&info->cv_drain);
131012bd3c8bSSascha Wildner 
131112bd3c8bSSascha Wildner 	/*
131212bd3c8bSSascha Wildner 	 * free the "memory_base" last, hence the "info" structure is
131312bd3c8bSSascha Wildner 	 * contained within the "memory_base"!
131412bd3c8bSSascha Wildner 	 */
1315ccb00b06SMatthew Dillon 	usbd_delayed_free(info->memory_base, M_USB);
1316ccb00b06SMatthew Dillon }
1317ccb00b06SMatthew Dillon 
1318ccb00b06SMatthew Dillon /*
1319ccb00b06SMatthew Dillon  * This is a horrible hack and workaround to a very bad decision by
1320ccb00b06SMatthew Dillon  * the original U4B coder to integrate the QH/TD structures into the
1321ccb00b06SMatthew Dillon  * xfer and then free the whole mess all at once.
1322ccb00b06SMatthew Dillon  *
1323ccb00b06SMatthew Dillon  * The problem is that the controller may still be accessing the QHs,
1324ccb00b06SMatthew Dillon  * because it might have gotten side-tracked onto the removed QHs
1325ccb00b06SMatthew Dillon  * chain link.  They have to remain intact long enough for the
1326ccb00b06SMatthew Dillon  * controller to get out.
1327ccb00b06SMatthew Dillon  *
1328ccb00b06SMatthew Dillon  * This horrible hack basically just delays freeing by 256 slots.
1329ccb00b06SMatthew Dillon  * It's not even time-based or door-bell based (which is the way
1330ccb00b06SMatthew Dillon  * the linux driver does it)... but to fix it properly requires rewriting
1331ccb00b06SMatthew Dillon  * too much of this driver.
1332ccb00b06SMatthew Dillon  */
1333ccb00b06SMatthew Dillon #define DFREE_SLOTS	256
1334ccb00b06SMatthew Dillon #define DFREE_MASK	(DFREE_SLOTS - 1)
1335ccb00b06SMatthew Dillon 
1336ccb00b06SMatthew Dillon static struct dfree_slot {
1337ccb00b06SMatthew Dillon 	void *data;
1338ccb00b06SMatthew Dillon 	struct malloc_type *mtype;
1339ccb00b06SMatthew Dillon } dfree_slots[DFREE_SLOTS];
1340ccb00b06SMatthew Dillon static int dfree_index;
1341ccb00b06SMatthew Dillon 
1342ccb00b06SMatthew Dillon static void
usbd_delayed_free(void * data,struct malloc_type * mtype)1343ccb00b06SMatthew Dillon usbd_delayed_free(void *data, struct malloc_type *mtype)
1344ccb00b06SMatthew Dillon {
1345ccb00b06SMatthew Dillon 	struct dfree_slot slot;
1346ccb00b06SMatthew Dillon 	int index;
1347ccb00b06SMatthew Dillon 
1348ccb00b06SMatthew Dillon 	crit_enter();
1349ccb00b06SMatthew Dillon 	index = atomic_fetchadd_int(&dfree_index, 1);
1350ccb00b06SMatthew Dillon 	index &= DFREE_MASK;
1351ccb00b06SMatthew Dillon 	slot = dfree_slots[index];
1352ccb00b06SMatthew Dillon 	dfree_slots[index].data = data;
1353ccb00b06SMatthew Dillon 	dfree_slots[index].mtype = mtype;
1354ccb00b06SMatthew Dillon 	crit_exit();
1355ccb00b06SMatthew Dillon 	if (slot.data)
1356ccb00b06SMatthew Dillon 		kfree(slot.data, slot.mtype);
135712bd3c8bSSascha Wildner }
135812bd3c8bSSascha Wildner 
135912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
136012bd3c8bSSascha Wildner  *	usbd_transfer_unsetup - unsetup/free an array of USB transfers
136112bd3c8bSSascha Wildner  *
136212bd3c8bSSascha Wildner  * NOTE: All USB transfers in progress will get called back passing
136312bd3c8bSSascha Wildner  * the error code "USB_ERR_CANCELLED" before this function
136412bd3c8bSSascha Wildner  * returns.
136512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
136612bd3c8bSSascha Wildner void
usbd_transfer_unsetup(struct usb_xfer ** pxfer,uint16_t n_setup)136712bd3c8bSSascha Wildner usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
136812bd3c8bSSascha Wildner {
136912bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
137012bd3c8bSSascha Wildner 	struct usb_xfer_root *info;
137112bd3c8bSSascha Wildner 	uint8_t needs_delay = 0;
137212bd3c8bSSascha Wildner 
137363da4a34SSascha Wildner #if 0
137412bd3c8bSSascha Wildner 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
137512bd3c8bSSascha Wildner 	    "usbd_transfer_unsetup can sleep!");
137663da4a34SSascha Wildner #endif
137712bd3c8bSSascha Wildner 
137812bd3c8bSSascha Wildner 	while (n_setup--) {
137912bd3c8bSSascha Wildner 		xfer = pxfer[n_setup];
138012bd3c8bSSascha Wildner 
138112bd3c8bSSascha Wildner 		if (xfer == NULL)
138212bd3c8bSSascha Wildner 			continue;
138312bd3c8bSSascha Wildner 
138412bd3c8bSSascha Wildner 		info = xfer->xroot;
138512bd3c8bSSascha Wildner 
138612bd3c8bSSascha Wildner 		USB_XFER_LOCK(xfer);
138712bd3c8bSSascha Wildner 		USB_BUS_LOCK(info->bus);
138812bd3c8bSSascha Wildner 
138912bd3c8bSSascha Wildner 		/*
139012bd3c8bSSascha Wildner 		 * HINT: when you start/stop a transfer, it might be a
139112bd3c8bSSascha Wildner 		 * good idea to directly use the "pxfer[]" structure:
139212bd3c8bSSascha Wildner 		 *
139312bd3c8bSSascha Wildner 		 * usbd_transfer_start(sc->pxfer[0]);
139412bd3c8bSSascha Wildner 		 * usbd_transfer_stop(sc->pxfer[0]);
139512bd3c8bSSascha Wildner 		 *
139612bd3c8bSSascha Wildner 		 * That way, if your code has many parts that will not
139712bd3c8bSSascha Wildner 		 * stop running under the same lock, in other words
139812bd3c8bSSascha Wildner 		 * "xfer_mtx", the usbd_transfer_start and
139912bd3c8bSSascha Wildner 		 * usbd_transfer_stop functions will simply return
140012bd3c8bSSascha Wildner 		 * when they detect a NULL pointer argument.
140112bd3c8bSSascha Wildner 		 *
140212bd3c8bSSascha Wildner 		 * To avoid any races we clear the "pxfer[]" pointer
140312bd3c8bSSascha Wildner 		 * while holding the private mutex of the driver:
140412bd3c8bSSascha Wildner 		 */
140512bd3c8bSSascha Wildner 		pxfer[n_setup] = NULL;
140612bd3c8bSSascha Wildner 
140712bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(info->bus);
140812bd3c8bSSascha Wildner 		USB_XFER_UNLOCK(xfer);
140912bd3c8bSSascha Wildner 
141012bd3c8bSSascha Wildner 		usbd_transfer_drain(xfer);
141112bd3c8bSSascha Wildner 
141212bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
141312bd3c8bSSascha Wildner 		if (xfer->flags_int.bdma_enable)
141412bd3c8bSSascha Wildner 			needs_delay = 1;
141512bd3c8bSSascha Wildner #endif
141612bd3c8bSSascha Wildner 		/*
141712bd3c8bSSascha Wildner 		 * NOTE: default endpoint does not have an
141812bd3c8bSSascha Wildner 		 * interface, even if endpoint->iface_index == 0
141912bd3c8bSSascha Wildner 		 */
142012bd3c8bSSascha Wildner 		USB_BUS_LOCK(info->bus);
142112bd3c8bSSascha Wildner 		xfer->endpoint->refcount_alloc--;
142212bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(info->bus);
142312bd3c8bSSascha Wildner 
142412bd3c8bSSascha Wildner 		usb_callout_drain(&xfer->timeout_handle);
142512bd3c8bSSascha Wildner 
142612bd3c8bSSascha Wildner 		USB_BUS_LOCK(info->bus);
142763da4a34SSascha Wildner 
142812bd3c8bSSascha Wildner 		USB_ASSERT(info->setup_refcount != 0, ("Invalid setup "
142912bd3c8bSSascha Wildner 		    "reference count\n"));
143063da4a34SSascha Wildner 
143112bd3c8bSSascha Wildner 		info->setup_refcount--;
143212bd3c8bSSascha Wildner 
143312bd3c8bSSascha Wildner 		if (info->setup_refcount == 0) {
143412bd3c8bSSascha Wildner 			usbd_transfer_unsetup_sub(info,
143512bd3c8bSSascha Wildner 			    needs_delay);
143612bd3c8bSSascha Wildner 		} else {
143712bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(info->bus);
143812bd3c8bSSascha Wildner 		}
143912bd3c8bSSascha Wildner 	}
144012bd3c8bSSascha Wildner }
144112bd3c8bSSascha Wildner 
144212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
144312bd3c8bSSascha Wildner  *	usbd_control_transfer_init - factored out code
144412bd3c8bSSascha Wildner  *
144512bd3c8bSSascha Wildner  * In USB Device Mode we have to wait for the SETUP packet which
144612bd3c8bSSascha Wildner  * containst the "struct usb_device_request" structure, before we can
144712bd3c8bSSascha Wildner  * transfer any data. In USB Host Mode we already have the SETUP
144812bd3c8bSSascha Wildner  * packet at the moment the USB transfer is started. This leads us to
144912bd3c8bSSascha Wildner  * having to setup the USB transfer at two different places in
145012bd3c8bSSascha Wildner  * time. This function just contains factored out control transfer
145112bd3c8bSSascha Wildner  * initialisation code, so that we don't duplicate the code.
145212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
145312bd3c8bSSascha Wildner static void
usbd_control_transfer_init(struct usb_xfer * xfer)145412bd3c8bSSascha Wildner usbd_control_transfer_init(struct usb_xfer *xfer)
145512bd3c8bSSascha Wildner {
145612bd3c8bSSascha Wildner 	struct usb_device_request req;
145712bd3c8bSSascha Wildner 
145812bd3c8bSSascha Wildner 	/* copy out the USB request header */
145912bd3c8bSSascha Wildner 
146012bd3c8bSSascha Wildner 	usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
146112bd3c8bSSascha Wildner 
146212bd3c8bSSascha Wildner 	/* setup remainder */
146312bd3c8bSSascha Wildner 
146412bd3c8bSSascha Wildner 	xfer->flags_int.control_rem = UGETW(req.wLength);
146512bd3c8bSSascha Wildner 
146612bd3c8bSSascha Wildner 	/* copy direction to endpoint variable */
146712bd3c8bSSascha Wildner 
146812bd3c8bSSascha Wildner 	xfer->endpointno &= ~(UE_DIR_IN | UE_DIR_OUT);
146912bd3c8bSSascha Wildner 	xfer->endpointno |=
147012bd3c8bSSascha Wildner 	    (req.bmRequestType & UT_READ) ? UE_DIR_IN : UE_DIR_OUT;
147112bd3c8bSSascha Wildner }
147212bd3c8bSSascha Wildner 
147312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
1474dd681da6SMatthew Dillon  *	usbd_control_transfer_did_data
1475dd681da6SMatthew Dillon  *
1476dd681da6SMatthew Dillon  * This function returns non-zero if a control endpoint has
1477dd681da6SMatthew Dillon  * transferred the first DATA packet after the SETUP packet.
1478dd681da6SMatthew Dillon  * Else it returns zero.
1479dd681da6SMatthew Dillon  *------------------------------------------------------------------------*/
1480dd681da6SMatthew Dillon static uint8_t
usbd_control_transfer_did_data(struct usb_xfer * xfer)1481dd681da6SMatthew Dillon usbd_control_transfer_did_data(struct usb_xfer *xfer)
1482dd681da6SMatthew Dillon {
1483dd681da6SMatthew Dillon 	struct usb_device_request req;
1484dd681da6SMatthew Dillon 
1485dd681da6SMatthew Dillon 	/* SETUP packet is not yet sent */
1486dd681da6SMatthew Dillon 	if (xfer->flags_int.control_hdr != 0)
1487dd681da6SMatthew Dillon 		return (0);
1488dd681da6SMatthew Dillon 
1489dd681da6SMatthew Dillon 	/* copy out the USB request header */
1490dd681da6SMatthew Dillon 	usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
1491dd681da6SMatthew Dillon 
1492dd681da6SMatthew Dillon 	/* compare remainder to the initial value */
1493dd681da6SMatthew Dillon 	return (xfer->flags_int.control_rem != UGETW(req.wLength));
1494dd681da6SMatthew Dillon }
1495dd681da6SMatthew Dillon 
1496dd681da6SMatthew Dillon /*------------------------------------------------------------------------*
149712bd3c8bSSascha Wildner  *	usbd_setup_ctrl_transfer
149812bd3c8bSSascha Wildner  *
149912bd3c8bSSascha Wildner  * This function handles initialisation of control transfers. Control
150012bd3c8bSSascha Wildner  * transfers are special in that regard that they can both transmit
150112bd3c8bSSascha Wildner  * and receive data.
150212bd3c8bSSascha Wildner  *
150312bd3c8bSSascha Wildner  * Return values:
150412bd3c8bSSascha Wildner  *    0: Success
150512bd3c8bSSascha Wildner  * Else: Failure
150612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
150712bd3c8bSSascha Wildner static int
usbd_setup_ctrl_transfer(struct usb_xfer * xfer)150812bd3c8bSSascha Wildner usbd_setup_ctrl_transfer(struct usb_xfer *xfer)
150912bd3c8bSSascha Wildner {
151012bd3c8bSSascha Wildner 	usb_frlength_t len;
151112bd3c8bSSascha Wildner 
151212bd3c8bSSascha Wildner 	/* Check for control endpoint stall */
151312bd3c8bSSascha Wildner 	if (xfer->flags.stall_pipe && xfer->flags_int.control_act) {
151412bd3c8bSSascha Wildner 		/* the control transfer is no longer active */
151512bd3c8bSSascha Wildner 		xfer->flags_int.control_stall = 1;
151612bd3c8bSSascha Wildner 		xfer->flags_int.control_act = 0;
151712bd3c8bSSascha Wildner 	} else {
151812bd3c8bSSascha Wildner 		/* don't stall control transfer by default */
151912bd3c8bSSascha Wildner 		xfer->flags_int.control_stall = 0;
152012bd3c8bSSascha Wildner 	}
152112bd3c8bSSascha Wildner 
152212bd3c8bSSascha Wildner 	/* Check for invalid number of frames */
152312bd3c8bSSascha Wildner 	if (xfer->nframes > 2) {
152412bd3c8bSSascha Wildner 		/*
152512bd3c8bSSascha Wildner 		 * If you need to split a control transfer, you
152612bd3c8bSSascha Wildner 		 * have to do one part at a time. Only with
152712bd3c8bSSascha Wildner 		 * non-control transfers you can do multiple
152812bd3c8bSSascha Wildner 		 * parts a time.
152912bd3c8bSSascha Wildner 		 */
153012bd3c8bSSascha Wildner 		DPRINTFN(0, "Too many frames: %u\n",
153112bd3c8bSSascha Wildner 		    (unsigned int)xfer->nframes);
153212bd3c8bSSascha Wildner 		goto error;
153312bd3c8bSSascha Wildner 	}
153412bd3c8bSSascha Wildner 
153512bd3c8bSSascha Wildner 	/*
153612bd3c8bSSascha Wildner          * Check if there is a control
153712bd3c8bSSascha Wildner          * transfer in progress:
153812bd3c8bSSascha Wildner          */
153912bd3c8bSSascha Wildner 	if (xfer->flags_int.control_act) {
154012bd3c8bSSascha Wildner 
154112bd3c8bSSascha Wildner 		if (xfer->flags_int.control_hdr) {
154212bd3c8bSSascha Wildner 
154312bd3c8bSSascha Wildner 			/* clear send header flag */
154412bd3c8bSSascha Wildner 
154512bd3c8bSSascha Wildner 			xfer->flags_int.control_hdr = 0;
154612bd3c8bSSascha Wildner 
154712bd3c8bSSascha Wildner 			/* setup control transfer */
154812bd3c8bSSascha Wildner 			if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
154912bd3c8bSSascha Wildner 				usbd_control_transfer_init(xfer);
155012bd3c8bSSascha Wildner 			}
155112bd3c8bSSascha Wildner 		}
155212bd3c8bSSascha Wildner 		/* get data length */
155312bd3c8bSSascha Wildner 
155412bd3c8bSSascha Wildner 		len = xfer->sumlen;
155512bd3c8bSSascha Wildner 
155612bd3c8bSSascha Wildner 	} else {
155712bd3c8bSSascha Wildner 
155812bd3c8bSSascha Wildner 		/* the size of the SETUP structure is hardcoded ! */
155912bd3c8bSSascha Wildner 
156012bd3c8bSSascha Wildner 		if (xfer->frlengths[0] != sizeof(struct usb_device_request)) {
156112bd3c8bSSascha Wildner 			DPRINTFN(0, "Wrong framelength %u != %zu\n",
156212bd3c8bSSascha Wildner 			    xfer->frlengths[0], sizeof(struct
156312bd3c8bSSascha Wildner 			    usb_device_request));
156412bd3c8bSSascha Wildner 			goto error;
156512bd3c8bSSascha Wildner 		}
156612bd3c8bSSascha Wildner 		/* check USB mode */
156712bd3c8bSSascha Wildner 		if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
156812bd3c8bSSascha Wildner 
156912bd3c8bSSascha Wildner 			/* check number of frames */
157012bd3c8bSSascha Wildner 			if (xfer->nframes != 1) {
157112bd3c8bSSascha Wildner 				/*
157212bd3c8bSSascha Wildner 			         * We need to receive the setup
157312bd3c8bSSascha Wildner 			         * message first so that we know the
157412bd3c8bSSascha Wildner 			         * data direction!
157512bd3c8bSSascha Wildner 			         */
157612bd3c8bSSascha Wildner 				DPRINTF("Misconfigured transfer\n");
157712bd3c8bSSascha Wildner 				goto error;
157812bd3c8bSSascha Wildner 			}
157912bd3c8bSSascha Wildner 			/*
158012bd3c8bSSascha Wildner 			 * Set a dummy "control_rem" value.  This
158112bd3c8bSSascha Wildner 			 * variable will be overwritten later by a
158212bd3c8bSSascha Wildner 			 * call to "usbd_control_transfer_init()" !
158312bd3c8bSSascha Wildner 			 */
158412bd3c8bSSascha Wildner 			xfer->flags_int.control_rem = 0xFFFF;
158512bd3c8bSSascha Wildner 		} else {
158612bd3c8bSSascha Wildner 
158712bd3c8bSSascha Wildner 			/* setup "endpoint" and "control_rem" */
158812bd3c8bSSascha Wildner 
158912bd3c8bSSascha Wildner 			usbd_control_transfer_init(xfer);
159012bd3c8bSSascha Wildner 		}
159112bd3c8bSSascha Wildner 
159212bd3c8bSSascha Wildner 		/* set transfer-header flag */
159312bd3c8bSSascha Wildner 
159412bd3c8bSSascha Wildner 		xfer->flags_int.control_hdr = 1;
159512bd3c8bSSascha Wildner 
159612bd3c8bSSascha Wildner 		/* get data length */
159712bd3c8bSSascha Wildner 
159812bd3c8bSSascha Wildner 		len = (xfer->sumlen - sizeof(struct usb_device_request));
159912bd3c8bSSascha Wildner 	}
160012bd3c8bSSascha Wildner 
1601dd681da6SMatthew Dillon 	/* update did data flag */
1602dd681da6SMatthew Dillon 
1603dd681da6SMatthew Dillon 	xfer->flags_int.control_did_data =
1604dd681da6SMatthew Dillon 	    usbd_control_transfer_did_data(xfer);
1605dd681da6SMatthew Dillon 
160612bd3c8bSSascha Wildner 	/* check if there is a length mismatch */
160712bd3c8bSSascha Wildner 
160812bd3c8bSSascha Wildner 	if (len > xfer->flags_int.control_rem) {
160912bd3c8bSSascha Wildner 		DPRINTFN(0, "Length (%d) greater than "
161012bd3c8bSSascha Wildner 		    "remaining length (%d)\n", len,
161112bd3c8bSSascha Wildner 		    xfer->flags_int.control_rem);
161212bd3c8bSSascha Wildner 		goto error;
161312bd3c8bSSascha Wildner 	}
161412bd3c8bSSascha Wildner 	/* check if we are doing a short transfer */
161512bd3c8bSSascha Wildner 
161612bd3c8bSSascha Wildner 	if (xfer->flags.force_short_xfer) {
161712bd3c8bSSascha Wildner 		xfer->flags_int.control_rem = 0;
161812bd3c8bSSascha Wildner 	} else {
161912bd3c8bSSascha Wildner 		if ((len != xfer->max_data_length) &&
162012bd3c8bSSascha Wildner 		    (len != xfer->flags_int.control_rem) &&
162112bd3c8bSSascha Wildner 		    (xfer->nframes != 1)) {
162212bd3c8bSSascha Wildner 			DPRINTFN(0, "Short control transfer without "
162312bd3c8bSSascha Wildner 			    "force_short_xfer set\n");
162412bd3c8bSSascha Wildner 			goto error;
162512bd3c8bSSascha Wildner 		}
162612bd3c8bSSascha Wildner 		xfer->flags_int.control_rem -= len;
162712bd3c8bSSascha Wildner 	}
162812bd3c8bSSascha Wildner 
162912bd3c8bSSascha Wildner 	/* the status part is executed when "control_act" is 0 */
163012bd3c8bSSascha Wildner 
163112bd3c8bSSascha Wildner 	if ((xfer->flags_int.control_rem > 0) ||
163212bd3c8bSSascha Wildner 	    (xfer->flags.manual_status)) {
163312bd3c8bSSascha Wildner 		/* don't execute the STATUS stage yet */
163412bd3c8bSSascha Wildner 		xfer->flags_int.control_act = 1;
163512bd3c8bSSascha Wildner 
163612bd3c8bSSascha Wildner 		/* sanity check */
163712bd3c8bSSascha Wildner 		if ((!xfer->flags_int.control_hdr) &&
163812bd3c8bSSascha Wildner 		    (xfer->nframes == 1)) {
163912bd3c8bSSascha Wildner 			/*
164012bd3c8bSSascha Wildner 		         * This is not a valid operation!
164112bd3c8bSSascha Wildner 		         */
164212bd3c8bSSascha Wildner 			DPRINTFN(0, "Invalid parameter "
164312bd3c8bSSascha Wildner 			    "combination\n");
164412bd3c8bSSascha Wildner 			goto error;
164512bd3c8bSSascha Wildner 		}
164612bd3c8bSSascha Wildner 	} else {
164712bd3c8bSSascha Wildner 		/* time to execute the STATUS stage */
164812bd3c8bSSascha Wildner 		xfer->flags_int.control_act = 0;
164912bd3c8bSSascha Wildner 	}
165012bd3c8bSSascha Wildner 	return (0);			/* success */
165112bd3c8bSSascha Wildner 
165212bd3c8bSSascha Wildner error:
165312bd3c8bSSascha Wildner 	return (1);			/* failure */
165412bd3c8bSSascha Wildner }
165512bd3c8bSSascha Wildner 
165612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
165712bd3c8bSSascha Wildner  *	usbd_transfer_submit - start USB hardware for the given transfer
165812bd3c8bSSascha Wildner  *
165912bd3c8bSSascha Wildner  * This function should only be called from the USB callback.
166012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
166112bd3c8bSSascha Wildner void
usbd_transfer_submit(struct usb_xfer * xfer)166212bd3c8bSSascha Wildner usbd_transfer_submit(struct usb_xfer *xfer)
166312bd3c8bSSascha Wildner {
166412bd3c8bSSascha Wildner 	struct usb_xfer_root *info;
166512bd3c8bSSascha Wildner 	struct usb_bus *bus;
166612bd3c8bSSascha Wildner 	usb_frcount_t x;
166712bd3c8bSSascha Wildner 
166812bd3c8bSSascha Wildner 	info = xfer->xroot;
166912bd3c8bSSascha Wildner 	bus = info->bus;
167012bd3c8bSSascha Wildner 
167112bd3c8bSSascha Wildner 	DPRINTF("xfer=%p, endpoint=%p, nframes=%d, dir=%s\n",
167212bd3c8bSSascha Wildner 	    xfer, xfer->endpoint, xfer->nframes, USB_GET_DATA_ISREAD(xfer) ?
167312bd3c8bSSascha Wildner 	    "read" : "write");
167412bd3c8bSSascha Wildner 
167512bd3c8bSSascha Wildner #ifdef USB_DEBUG
167612bd3c8bSSascha Wildner 	if (USB_DEBUG_VAR > 0) {
167712bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
167812bd3c8bSSascha Wildner 
167912bd3c8bSSascha Wildner 		usb_dump_endpoint(xfer->endpoint);
168012bd3c8bSSascha Wildner 
168112bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
168212bd3c8bSSascha Wildner 	}
168312bd3c8bSSascha Wildner #endif
168412bd3c8bSSascha Wildner 
1685722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer);
1686722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT_NOTOWNED(bus);
168712bd3c8bSSascha Wildner 
168812bd3c8bSSascha Wildner 	/* Only open the USB transfer once! */
168912bd3c8bSSascha Wildner 	if (!xfer->flags_int.open) {
169012bd3c8bSSascha Wildner 		xfer->flags_int.open = 1;
169112bd3c8bSSascha Wildner 
169212bd3c8bSSascha Wildner 		DPRINTF("open\n");
169312bd3c8bSSascha Wildner 
169412bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
169512bd3c8bSSascha Wildner 		(xfer->endpoint->methods->open) (xfer);
169612bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
169712bd3c8bSSascha Wildner 	}
169812bd3c8bSSascha Wildner 	/* set "transferring" flag */
169912bd3c8bSSascha Wildner 	xfer->flags_int.transferring = 1;
170012bd3c8bSSascha Wildner 
170112bd3c8bSSascha Wildner #if USB_HAVE_POWERD
170212bd3c8bSSascha Wildner 	/* increment power reference */
170312bd3c8bSSascha Wildner 	usbd_transfer_power_ref(xfer, 1);
170412bd3c8bSSascha Wildner #endif
170512bd3c8bSSascha Wildner 	/*
170612bd3c8bSSascha Wildner 	 * Check if the transfer is waiting on a queue, most
170712bd3c8bSSascha Wildner 	 * frequently the "done_q":
170812bd3c8bSSascha Wildner 	 */
170912bd3c8bSSascha Wildner 	if (xfer->wait_queue) {
171012bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
171112bd3c8bSSascha Wildner 		usbd_transfer_dequeue(xfer);
171212bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
171312bd3c8bSSascha Wildner 	}
171412bd3c8bSSascha Wildner 	/* clear "did_dma_delay" flag */
171512bd3c8bSSascha Wildner 	xfer->flags_int.did_dma_delay = 0;
171612bd3c8bSSascha Wildner 
171712bd3c8bSSascha Wildner 	/* clear "did_close" flag */
171812bd3c8bSSascha Wildner 	xfer->flags_int.did_close = 0;
171912bd3c8bSSascha Wildner 
172012bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
172112bd3c8bSSascha Wildner 	/* clear "bdma_setup" flag */
172212bd3c8bSSascha Wildner 	xfer->flags_int.bdma_setup = 0;
172312bd3c8bSSascha Wildner #endif
172412bd3c8bSSascha Wildner 	/* by default we cannot cancel any USB transfer immediately */
172512bd3c8bSSascha Wildner 	xfer->flags_int.can_cancel_immed = 0;
172612bd3c8bSSascha Wildner 
172712bd3c8bSSascha Wildner 	/* clear lengths and frame counts by default */
172812bd3c8bSSascha Wildner 	xfer->sumlen = 0;
172912bd3c8bSSascha Wildner 	xfer->actlen = 0;
173012bd3c8bSSascha Wildner 	xfer->aframes = 0;
173112bd3c8bSSascha Wildner 
173212bd3c8bSSascha Wildner 	/* clear any previous errors */
173312bd3c8bSSascha Wildner 	xfer->error = 0;
173412bd3c8bSSascha Wildner 
173512bd3c8bSSascha Wildner 	/* Check if the device is still alive */
173612bd3c8bSSascha Wildner 	if (info->udev->state < USB_STATE_POWERED) {
173712bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
173812bd3c8bSSascha Wildner 		/*
173912bd3c8bSSascha Wildner 		 * Must return cancelled error code else
174012bd3c8bSSascha Wildner 		 * device drivers can hang.
174112bd3c8bSSascha Wildner 		 */
174212bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, USB_ERR_CANCELLED);
174312bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
174412bd3c8bSSascha Wildner 		return;
174512bd3c8bSSascha Wildner 	}
174612bd3c8bSSascha Wildner 
174712bd3c8bSSascha Wildner 	/* sanity check */
174812bd3c8bSSascha Wildner 	if (xfer->nframes == 0) {
174912bd3c8bSSascha Wildner 		if (xfer->flags.stall_pipe) {
175012bd3c8bSSascha Wildner 			/*
175112bd3c8bSSascha Wildner 			 * Special case - want to stall without transferring
175212bd3c8bSSascha Wildner 			 * any data:
175312bd3c8bSSascha Wildner 			 */
175412bd3c8bSSascha Wildner 			DPRINTF("xfer=%p nframes=0: stall "
175512bd3c8bSSascha Wildner 			    "or clear stall!\n", xfer);
175612bd3c8bSSascha Wildner 			USB_BUS_LOCK(bus);
175712bd3c8bSSascha Wildner 			xfer->flags_int.can_cancel_immed = 1;
175812bd3c8bSSascha Wildner 			/* start the transfer */
17595e41ab93SMarkus Pfeiffer 			usb_command_wrapper(&xfer->endpoint->
17605e41ab93SMarkus Pfeiffer 			    endpoint_q[xfer->stream_id], xfer);
176112bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(bus);
176212bd3c8bSSascha Wildner 			return;
176312bd3c8bSSascha Wildner 		}
176412bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
176512bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, USB_ERR_INVAL);
176612bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
176712bd3c8bSSascha Wildner 		return;
176812bd3c8bSSascha Wildner 	}
176912bd3c8bSSascha Wildner 	/* compute some variables */
177012bd3c8bSSascha Wildner 
177112bd3c8bSSascha Wildner 	for (x = 0; x != xfer->nframes; x++) {
177212bd3c8bSSascha Wildner 		/* make a copy of the frlenghts[] */
177312bd3c8bSSascha Wildner 		xfer->frlengths[x + xfer->max_frame_count] = xfer->frlengths[x];
177412bd3c8bSSascha Wildner 		/* compute total transfer length */
177512bd3c8bSSascha Wildner 		xfer->sumlen += xfer->frlengths[x];
177612bd3c8bSSascha Wildner 		if (xfer->sumlen < xfer->frlengths[x]) {
177712bd3c8bSSascha Wildner 			/* length wrapped around */
177812bd3c8bSSascha Wildner 			USB_BUS_LOCK(bus);
177912bd3c8bSSascha Wildner 			usbd_transfer_done(xfer, USB_ERR_INVAL);
178012bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(bus);
178112bd3c8bSSascha Wildner 			return;
178212bd3c8bSSascha Wildner 		}
178312bd3c8bSSascha Wildner 	}
178412bd3c8bSSascha Wildner 
178512bd3c8bSSascha Wildner 	/* clear some internal flags */
178612bd3c8bSSascha Wildner 
178712bd3c8bSSascha Wildner 	xfer->flags_int.short_xfer_ok = 0;
178812bd3c8bSSascha Wildner 	xfer->flags_int.short_frames_ok = 0;
178912bd3c8bSSascha Wildner 
179012bd3c8bSSascha Wildner 	/* check if this is a control transfer */
179112bd3c8bSSascha Wildner 
179212bd3c8bSSascha Wildner 	if (xfer->flags_int.control_xfr) {
179312bd3c8bSSascha Wildner 
179412bd3c8bSSascha Wildner 		if (usbd_setup_ctrl_transfer(xfer)) {
179512bd3c8bSSascha Wildner 			USB_BUS_LOCK(bus);
179612bd3c8bSSascha Wildner 			usbd_transfer_done(xfer, USB_ERR_STALLED);
179712bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(bus);
179812bd3c8bSSascha Wildner 			return;
179912bd3c8bSSascha Wildner 		}
180012bd3c8bSSascha Wildner 	}
180112bd3c8bSSascha Wildner 	/*
180212bd3c8bSSascha Wildner 	 * Setup filtered version of some transfer flags,
180312bd3c8bSSascha Wildner 	 * in case of data read direction
180412bd3c8bSSascha Wildner 	 */
180512bd3c8bSSascha Wildner 	if (USB_GET_DATA_ISREAD(xfer)) {
180612bd3c8bSSascha Wildner 
180712bd3c8bSSascha Wildner 		if (xfer->flags.short_frames_ok) {
180812bd3c8bSSascha Wildner 			xfer->flags_int.short_xfer_ok = 1;
180912bd3c8bSSascha Wildner 			xfer->flags_int.short_frames_ok = 1;
181012bd3c8bSSascha Wildner 		} else if (xfer->flags.short_xfer_ok) {
181112bd3c8bSSascha Wildner 			xfer->flags_int.short_xfer_ok = 1;
181212bd3c8bSSascha Wildner 
181312bd3c8bSSascha Wildner 			/* check for control transfer */
181412bd3c8bSSascha Wildner 			if (xfer->flags_int.control_xfr) {
181512bd3c8bSSascha Wildner 				/*
181612bd3c8bSSascha Wildner 				 * 1) Control transfers do not support
181712bd3c8bSSascha Wildner 				 * reception of multiple short USB
181812bd3c8bSSascha Wildner 				 * frames in host mode and device side
181912bd3c8bSSascha Wildner 				 * mode, with exception of:
182012bd3c8bSSascha Wildner 				 *
182112bd3c8bSSascha Wildner 				 * 2) Due to sometimes buggy device
182212bd3c8bSSascha Wildner 				 * side firmware we need to do a
182312bd3c8bSSascha Wildner 				 * STATUS stage in case of short
182412bd3c8bSSascha Wildner 				 * control transfers in USB host mode.
182512bd3c8bSSascha Wildner 				 * The STATUS stage then becomes the
182612bd3c8bSSascha Wildner 				 * "alt_next" to the DATA stage.
182712bd3c8bSSascha Wildner 				 */
182812bd3c8bSSascha Wildner 				xfer->flags_int.short_frames_ok = 1;
182912bd3c8bSSascha Wildner 			}
183012bd3c8bSSascha Wildner 		}
183112bd3c8bSSascha Wildner 	}
183212bd3c8bSSascha Wildner 	/*
183312bd3c8bSSascha Wildner 	 * Check if BUS-DMA support is enabled and try to load virtual
183412bd3c8bSSascha Wildner 	 * buffers into DMA, if any:
183512bd3c8bSSascha Wildner 	 */
183612bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
183712bd3c8bSSascha Wildner 	if (xfer->flags_int.bdma_enable) {
183812bd3c8bSSascha Wildner 		/* insert the USB transfer last in the BUS-DMA queue */
183912bd3c8bSSascha Wildner 		usb_command_wrapper(&xfer->xroot->dma_q, xfer);
184012bd3c8bSSascha Wildner 		return;
184112bd3c8bSSascha Wildner 	}
184212bd3c8bSSascha Wildner #endif
184312bd3c8bSSascha Wildner 	/*
184412bd3c8bSSascha Wildner 	 * Enter the USB transfer into the Host Controller or
184512bd3c8bSSascha Wildner 	 * Device Controller schedule:
184612bd3c8bSSascha Wildner 	 */
184712bd3c8bSSascha Wildner 	usbd_pipe_enter(xfer);
184812bd3c8bSSascha Wildner }
184912bd3c8bSSascha Wildner 
185012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
185112bd3c8bSSascha Wildner  *	usbd_pipe_enter - factored out code
185212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
185312bd3c8bSSascha Wildner void
usbd_pipe_enter(struct usb_xfer * xfer)185412bd3c8bSSascha Wildner usbd_pipe_enter(struct usb_xfer *xfer)
185512bd3c8bSSascha Wildner {
185612bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
185712bd3c8bSSascha Wildner 
18583a76bbe8SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer);
185963da4a34SSascha Wildner 
186012bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
186112bd3c8bSSascha Wildner 
186212bd3c8bSSascha Wildner 	ep = xfer->endpoint;
186312bd3c8bSSascha Wildner 
186412bd3c8bSSascha Wildner 	DPRINTF("enter\n");
186512bd3c8bSSascha Wildner 
18665e41ab93SMarkus Pfeiffer 	/* the transfer can now be cancelled */
186712bd3c8bSSascha Wildner 	xfer->flags_int.can_cancel_immed = 1;
186812bd3c8bSSascha Wildner 
186957bed822SMarkus Pfeiffer 	/* enter the transfer */
187057bed822SMarkus Pfeiffer 	(ep->methods->enter) (xfer);
187157bed822SMarkus Pfeiffer 
187212bd3c8bSSascha Wildner 	/* check for transfer error */
187312bd3c8bSSascha Wildner 	if (xfer->error) {
187412bd3c8bSSascha Wildner 		/* some error has happened */
187512bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, 0);
187612bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(xfer->xroot->bus);
187712bd3c8bSSascha Wildner 		return;
187812bd3c8bSSascha Wildner 	}
187912bd3c8bSSascha Wildner 
188012bd3c8bSSascha Wildner 	/* start the transfer */
18815e41ab93SMarkus Pfeiffer 	usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], xfer);
188212bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
188312bd3c8bSSascha Wildner }
188412bd3c8bSSascha Wildner 
188512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
188612bd3c8bSSascha Wildner  *	usbd_transfer_start - start an USB transfer
188712bd3c8bSSascha Wildner  *
188812bd3c8bSSascha Wildner  * NOTE: Calling this function more than one time will only
188912bd3c8bSSascha Wildner  *       result in a single transfer start, until the USB transfer
189012bd3c8bSSascha Wildner  *       completes.
189112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
189212bd3c8bSSascha Wildner void
usbd_transfer_start(struct usb_xfer * xfer)189312bd3c8bSSascha Wildner usbd_transfer_start(struct usb_xfer *xfer)
189412bd3c8bSSascha Wildner {
189512bd3c8bSSascha Wildner 	if (xfer == NULL) {
189612bd3c8bSSascha Wildner 		/* transfer is gone */
189712bd3c8bSSascha Wildner 		return;
189812bd3c8bSSascha Wildner 	}
18993a76bbe8SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer);
190063da4a34SSascha Wildner 
190112bd3c8bSSascha Wildner 	/* mark the USB transfer started */
190212bd3c8bSSascha Wildner 
190312bd3c8bSSascha Wildner 	if (!xfer->flags_int.started) {
190412bd3c8bSSascha Wildner 		/* lock the BUS lock to avoid races updating flags_int */
190512bd3c8bSSascha Wildner 		USB_BUS_LOCK(xfer->xroot->bus);
190612bd3c8bSSascha Wildner 		xfer->flags_int.started = 1;
190712bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(xfer->xroot->bus);
190812bd3c8bSSascha Wildner 	}
190912bd3c8bSSascha Wildner 	/* check if the USB transfer callback is already transferring */
191012bd3c8bSSascha Wildner 
191112bd3c8bSSascha Wildner 	if (xfer->flags_int.transferring) {
191212bd3c8bSSascha Wildner 		return;
191312bd3c8bSSascha Wildner 	}
191412bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
191512bd3c8bSSascha Wildner 	/* call the USB transfer callback */
191612bd3c8bSSascha Wildner 	usbd_callback_ss_done_defer(xfer);
191712bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
191812bd3c8bSSascha Wildner }
191912bd3c8bSSascha Wildner 
192012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
192112bd3c8bSSascha Wildner  *	usbd_transfer_stop - stop an USB transfer
192212bd3c8bSSascha Wildner  *
192312bd3c8bSSascha Wildner  * NOTE: Calling this function more than one time will only
192412bd3c8bSSascha Wildner  *       result in a single transfer stop.
192512bd3c8bSSascha Wildner  * NOTE: When this function returns it is not safe to free nor
192612bd3c8bSSascha Wildner  *       reuse any DMA buffers. See "usbd_transfer_drain()".
192712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
192812bd3c8bSSascha Wildner void
usbd_transfer_stop(struct usb_xfer * xfer)192912bd3c8bSSascha Wildner usbd_transfer_stop(struct usb_xfer *xfer)
193012bd3c8bSSascha Wildner {
193112bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
193212bd3c8bSSascha Wildner 
193312bd3c8bSSascha Wildner 	if (xfer == NULL) {
193412bd3c8bSSascha Wildner 		/* transfer is gone */
193512bd3c8bSSascha Wildner 		return;
193612bd3c8bSSascha Wildner 	}
193763da4a34SSascha Wildner #if 0
193812bd3c8bSSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
193963da4a34SSascha Wildner #endif
194063da4a34SSascha Wildner 
194112bd3c8bSSascha Wildner 	/* check if the USB transfer was ever opened */
194212bd3c8bSSascha Wildner 
194312bd3c8bSSascha Wildner 	if (!xfer->flags_int.open) {
194412bd3c8bSSascha Wildner 		if (xfer->flags_int.started) {
194512bd3c8bSSascha Wildner 			/* nothing to do except clearing the "started" flag */
194612bd3c8bSSascha Wildner 			/* lock the BUS lock to avoid races updating flags_int */
194712bd3c8bSSascha Wildner 			USB_BUS_LOCK(xfer->xroot->bus);
194812bd3c8bSSascha Wildner 			xfer->flags_int.started = 0;
194912bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(xfer->xroot->bus);
195012bd3c8bSSascha Wildner 		}
195112bd3c8bSSascha Wildner 		return;
195212bd3c8bSSascha Wildner 	}
195312bd3c8bSSascha Wildner 	/* try to stop the current USB transfer */
195412bd3c8bSSascha Wildner 
195512bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
195612bd3c8bSSascha Wildner 	/* override any previous error */
195712bd3c8bSSascha Wildner 	xfer->error = USB_ERR_CANCELLED;
195812bd3c8bSSascha Wildner 
195912bd3c8bSSascha Wildner 	/*
196012bd3c8bSSascha Wildner 	 * Clear "open" and "started" when both private and USB lock
196112bd3c8bSSascha Wildner 	 * is locked so that we don't get a race updating "flags_int"
196212bd3c8bSSascha Wildner 	 */
196312bd3c8bSSascha Wildner 	xfer->flags_int.open = 0;
196412bd3c8bSSascha Wildner 	xfer->flags_int.started = 0;
196512bd3c8bSSascha Wildner 
196612bd3c8bSSascha Wildner 	/*
196712bd3c8bSSascha Wildner 	 * Check if we can cancel the USB transfer immediately.
196812bd3c8bSSascha Wildner 	 */
196912bd3c8bSSascha Wildner 	if (xfer->flags_int.transferring) {
197012bd3c8bSSascha Wildner 		if (xfer->flags_int.can_cancel_immed &&
197112bd3c8bSSascha Wildner 		    (!xfer->flags_int.did_close)) {
197212bd3c8bSSascha Wildner 			DPRINTF("close\n");
197312bd3c8bSSascha Wildner 			/*
197412bd3c8bSSascha Wildner 			 * The following will lead to an USB_ERR_CANCELLED
197512bd3c8bSSascha Wildner 			 * error code being passed to the USB callback.
197612bd3c8bSSascha Wildner 			 */
197712bd3c8bSSascha Wildner 			(xfer->endpoint->methods->close) (xfer);
197812bd3c8bSSascha Wildner 			/* only close once */
197912bd3c8bSSascha Wildner 			xfer->flags_int.did_close = 1;
198012bd3c8bSSascha Wildner 		} else {
198112bd3c8bSSascha Wildner 			/* need to wait for the next done callback */
198212bd3c8bSSascha Wildner 		}
198312bd3c8bSSascha Wildner 	} else {
198412bd3c8bSSascha Wildner 		DPRINTF("close\n");
198512bd3c8bSSascha Wildner 
198612bd3c8bSSascha Wildner 		/* close here and now */
198712bd3c8bSSascha Wildner 		(xfer->endpoint->methods->close) (xfer);
198812bd3c8bSSascha Wildner 
198912bd3c8bSSascha Wildner 		/*
199012bd3c8bSSascha Wildner 		 * Any additional DMA delay is done by
199112bd3c8bSSascha Wildner 		 * "usbd_transfer_unsetup()".
199212bd3c8bSSascha Wildner 		 */
199312bd3c8bSSascha Wildner 
199412bd3c8bSSascha Wildner 		/*
199512bd3c8bSSascha Wildner 		 * Special case. Check if we need to restart a blocked
199612bd3c8bSSascha Wildner 		 * endpoint.
199712bd3c8bSSascha Wildner 		 */
199812bd3c8bSSascha Wildner 		ep = xfer->endpoint;
199912bd3c8bSSascha Wildner 
200012bd3c8bSSascha Wildner 		/*
200112bd3c8bSSascha Wildner 		 * If the current USB transfer is completing we need
200212bd3c8bSSascha Wildner 		 * to start the next one:
200312bd3c8bSSascha Wildner 		 */
20045e41ab93SMarkus Pfeiffer 		if (ep->endpoint_q[xfer->stream_id].curr == xfer) {
20055e41ab93SMarkus Pfeiffer 			usb_command_wrapper(
20065e41ab93SMarkus Pfeiffer 			    &ep->endpoint_q[xfer->stream_id], NULL);
200712bd3c8bSSascha Wildner 		}
200812bd3c8bSSascha Wildner 	}
200912bd3c8bSSascha Wildner 
201012bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
201112bd3c8bSSascha Wildner }
201212bd3c8bSSascha Wildner 
201312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
201412bd3c8bSSascha Wildner  *	usbd_transfer_pending
201512bd3c8bSSascha Wildner  *
201612bd3c8bSSascha Wildner  * This function will check if an USB transfer is pending which is a
201712bd3c8bSSascha Wildner  * little bit complicated!
201812bd3c8bSSascha Wildner  * Return values:
201912bd3c8bSSascha Wildner  * 0: Not pending
202012bd3c8bSSascha Wildner  * 1: Pending: The USB transfer will receive a callback in the future.
202112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
202212bd3c8bSSascha Wildner uint8_t
usbd_transfer_pending(struct usb_xfer * xfer)202312bd3c8bSSascha Wildner usbd_transfer_pending(struct usb_xfer *xfer)
202412bd3c8bSSascha Wildner {
202512bd3c8bSSascha Wildner 	struct usb_xfer_root *info;
202612bd3c8bSSascha Wildner 	struct usb_xfer_queue *pq;
202712bd3c8bSSascha Wildner 
202812bd3c8bSSascha Wildner 	if (xfer == NULL) {
202912bd3c8bSSascha Wildner 		/* transfer is gone */
203012bd3c8bSSascha Wildner 		return (0);
203112bd3c8bSSascha Wildner 	}
203263da4a34SSascha Wildner #if 0
203312bd3c8bSSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
203463da4a34SSascha Wildner #endif
203563da4a34SSascha Wildner 
203612bd3c8bSSascha Wildner 	if (xfer->flags_int.transferring) {
203712bd3c8bSSascha Wildner 		/* trivial case */
203812bd3c8bSSascha Wildner 		return (1);
203912bd3c8bSSascha Wildner 	}
204012bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
204112bd3c8bSSascha Wildner 	if (xfer->wait_queue) {
204212bd3c8bSSascha Wildner 		/* we are waiting on a queue somewhere */
204312bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(xfer->xroot->bus);
204412bd3c8bSSascha Wildner 		return (1);
204512bd3c8bSSascha Wildner 	}
204612bd3c8bSSascha Wildner 	info = xfer->xroot;
204712bd3c8bSSascha Wildner 	pq = &info->done_q;
204812bd3c8bSSascha Wildner 
204912bd3c8bSSascha Wildner 	if (pq->curr == xfer) {
205012bd3c8bSSascha Wildner 		/* we are currently scheduled for callback */
205112bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(xfer->xroot->bus);
205212bd3c8bSSascha Wildner 		return (1);
205312bd3c8bSSascha Wildner 	}
205412bd3c8bSSascha Wildner 	/* we are not pending */
205512bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
205612bd3c8bSSascha Wildner 	return (0);
205712bd3c8bSSascha Wildner }
205812bd3c8bSSascha Wildner 
205912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
206012bd3c8bSSascha Wildner  *	usbd_transfer_drain
206112bd3c8bSSascha Wildner  *
206212bd3c8bSSascha Wildner  * This function will stop the USB transfer and wait for any
206312bd3c8bSSascha Wildner  * additional BUS-DMA and HW-DMA operations to complete. Buffers that
206412bd3c8bSSascha Wildner  * are loaded into DMA can safely be freed or reused after that this
206512bd3c8bSSascha Wildner  * function has returned.
206612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
206712bd3c8bSSascha Wildner void
usbd_transfer_drain(struct usb_xfer * xfer)206812bd3c8bSSascha Wildner usbd_transfer_drain(struct usb_xfer *xfer)
206912bd3c8bSSascha Wildner {
207063da4a34SSascha Wildner #if 0
207112bd3c8bSSascha Wildner 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
207212bd3c8bSSascha Wildner 	    "usbd_transfer_drain can sleep!");
207363da4a34SSascha Wildner #endif
207463da4a34SSascha Wildner 
207512bd3c8bSSascha Wildner 	if (xfer == NULL) {
207612bd3c8bSSascha Wildner 		/* transfer is gone */
207712bd3c8bSSascha Wildner 		return;
207812bd3c8bSSascha Wildner 	}
2079722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT_NOTOWNED(xfer);
208012bd3c8bSSascha Wildner 	USB_XFER_LOCK(xfer);
208112bd3c8bSSascha Wildner 
208212bd3c8bSSascha Wildner 	usbd_transfer_stop(xfer);
208312bd3c8bSSascha Wildner 
208412bd3c8bSSascha Wildner 	/*
208512bd3c8bSSascha Wildner 	 * It is allowed that the callback can drop its
208612bd3c8bSSascha Wildner 	 * transfer mutex. In that case checking only
208712bd3c8bSSascha Wildner 	 * "usbd_transfer_pending()" is not enough to tell if
208812bd3c8bSSascha Wildner 	 * the USB transfer is fully drained. We also need to
208912bd3c8bSSascha Wildner 	 * check the internal "doing_callback" flag.
209012bd3c8bSSascha Wildner 	 */
209112bd3c8bSSascha Wildner 	xfer->flags_int.draining = 1;
209212bd3c8bSSascha Wildner 
209312bd3c8bSSascha Wildner 	/*
2094ccb00b06SMatthew Dillon 	 * XXX hack, the wakeup of xfer can race conditions which
2095ccb00b06SMatthew Dillon 	 *     clear the pending status of the xfer.
2096ccb00b06SMatthew Dillon 	 */
2097ccb00b06SMatthew Dillon 	while (usbd_transfer_pending(xfer) ||
2098ccb00b06SMatthew Dillon 	    xfer->flags_int.doing_callback) {
2099ccb00b06SMatthew Dillon 
2100ccb00b06SMatthew Dillon 		/*
210112bd3c8bSSascha Wildner 		 * Wait until the current outstanding USB
210212bd3c8bSSascha Wildner 		 * transfer is complete !
210312bd3c8bSSascha Wildner 		 */
2104ccb00b06SMatthew Dillon 		/* cv_wait(&xfer->xroot->cv_drain, xfer->xroot->xfer_lock); */
2105ccb00b06SMatthew Dillon 		lksleep(xfer, xfer->xroot->xfer_lock, 0, "DRAIN", hz);
210612bd3c8bSSascha Wildner 	}
2107ccb00b06SMatthew Dillon 	xfer->flags_int.draining = 0;
210812bd3c8bSSascha Wildner 	USB_XFER_UNLOCK(xfer);
210912bd3c8bSSascha Wildner }
211012bd3c8bSSascha Wildner 
211112bd3c8bSSascha Wildner struct usb_page_cache *
usbd_xfer_get_frame(struct usb_xfer * xfer,usb_frcount_t frindex)211212bd3c8bSSascha Wildner usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
211312bd3c8bSSascha Wildner {
211412bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
211512bd3c8bSSascha Wildner 
211612bd3c8bSSascha Wildner 	return (&xfer->frbuffers[frindex]);
211712bd3c8bSSascha Wildner }
211812bd3c8bSSascha Wildner 
211957bed822SMarkus Pfeiffer void *
usbd_xfer_get_frame_buffer(struct usb_xfer * xfer,usb_frcount_t frindex)212057bed822SMarkus Pfeiffer usbd_xfer_get_frame_buffer(struct usb_xfer *xfer, usb_frcount_t frindex)
212157bed822SMarkus Pfeiffer {
212257bed822SMarkus Pfeiffer 	struct usb_page_search page_info;
212357bed822SMarkus Pfeiffer 
212457bed822SMarkus Pfeiffer 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
212557bed822SMarkus Pfeiffer 
212657bed822SMarkus Pfeiffer 	usbd_get_page(&xfer->frbuffers[frindex], 0, &page_info);
212757bed822SMarkus Pfeiffer 	return (page_info.buffer);
212857bed822SMarkus Pfeiffer }
212957bed822SMarkus Pfeiffer 
213012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
213112bd3c8bSSascha Wildner  *	usbd_xfer_get_fps_shift
213212bd3c8bSSascha Wildner  *
213312bd3c8bSSascha Wildner  * The following function is only useful for isochronous transfers. It
213412bd3c8bSSascha Wildner  * returns how many times the frame execution rate has been shifted
213512bd3c8bSSascha Wildner  * down.
213612bd3c8bSSascha Wildner  *
213712bd3c8bSSascha Wildner  * Return value:
213812bd3c8bSSascha Wildner  * Success: 0..3
213912bd3c8bSSascha Wildner  * Failure: 0
214012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
214112bd3c8bSSascha Wildner uint8_t
usbd_xfer_get_fps_shift(struct usb_xfer * xfer)214212bd3c8bSSascha Wildner usbd_xfer_get_fps_shift(struct usb_xfer *xfer)
214312bd3c8bSSascha Wildner {
214412bd3c8bSSascha Wildner 	return (xfer->fps_shift);
214512bd3c8bSSascha Wildner }
214612bd3c8bSSascha Wildner 
214712bd3c8bSSascha Wildner usb_frlength_t
usbd_xfer_frame_len(struct usb_xfer * xfer,usb_frcount_t frindex)214812bd3c8bSSascha Wildner usbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex)
214912bd3c8bSSascha Wildner {
215012bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
215112bd3c8bSSascha Wildner 
215212bd3c8bSSascha Wildner 	return (xfer->frlengths[frindex]);
215312bd3c8bSSascha Wildner }
215412bd3c8bSSascha Wildner 
215512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
215612bd3c8bSSascha Wildner  *	usbd_xfer_set_frame_data
215712bd3c8bSSascha Wildner  *
215812bd3c8bSSascha Wildner  * This function sets the pointer of the buffer that should
215912bd3c8bSSascha Wildner  * loaded directly into DMA for the given USB frame. Passing "ptr"
216012bd3c8bSSascha Wildner  * equal to NULL while the corresponding "frlength" is greater
216112bd3c8bSSascha Wildner  * than zero gives undefined results!
216212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
216312bd3c8bSSascha Wildner void
usbd_xfer_set_frame_data(struct usb_xfer * xfer,usb_frcount_t frindex,void * ptr,usb_frlength_t len)216412bd3c8bSSascha Wildner usbd_xfer_set_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
216512bd3c8bSSascha Wildner     void *ptr, usb_frlength_t len)
216612bd3c8bSSascha Wildner {
216712bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
216812bd3c8bSSascha Wildner 
216912bd3c8bSSascha Wildner 	/* set virtual address to load and length */
217012bd3c8bSSascha Wildner 	xfer->frbuffers[frindex].buffer = ptr;
217112bd3c8bSSascha Wildner 	usbd_xfer_set_frame_len(xfer, frindex, len);
217212bd3c8bSSascha Wildner }
217312bd3c8bSSascha Wildner 
217412bd3c8bSSascha Wildner void
usbd_xfer_frame_data(struct usb_xfer * xfer,usb_frcount_t frindex,void ** ptr,int * len)217512bd3c8bSSascha Wildner usbd_xfer_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
217612bd3c8bSSascha Wildner     void **ptr, int *len)
217712bd3c8bSSascha Wildner {
217812bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
217912bd3c8bSSascha Wildner 
218012bd3c8bSSascha Wildner 	if (ptr != NULL)
218112bd3c8bSSascha Wildner 		*ptr = xfer->frbuffers[frindex].buffer;
218212bd3c8bSSascha Wildner 	if (len != NULL)
218312bd3c8bSSascha Wildner 		*len = xfer->frlengths[frindex];
218412bd3c8bSSascha Wildner }
218512bd3c8bSSascha Wildner 
218612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
218712bd3c8bSSascha Wildner  *	usbd_xfer_old_frame_length
218812bd3c8bSSascha Wildner  *
218912bd3c8bSSascha Wildner  * This function returns the framelength of the given frame at the
219012bd3c8bSSascha Wildner  * time the transfer was submitted. This function can be used to
219112bd3c8bSSascha Wildner  * compute the starting data pointer of the next isochronous frame
219212bd3c8bSSascha Wildner  * when an isochronous transfer has completed.
219312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
219412bd3c8bSSascha Wildner usb_frlength_t
usbd_xfer_old_frame_length(struct usb_xfer * xfer,usb_frcount_t frindex)219512bd3c8bSSascha Wildner usbd_xfer_old_frame_length(struct usb_xfer *xfer, usb_frcount_t frindex)
219612bd3c8bSSascha Wildner {
219712bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
219812bd3c8bSSascha Wildner 
219912bd3c8bSSascha Wildner 	return (xfer->frlengths[frindex + xfer->max_frame_count]);
220012bd3c8bSSascha Wildner }
220112bd3c8bSSascha Wildner 
220212bd3c8bSSascha Wildner void
usbd_xfer_status(struct usb_xfer * xfer,int * actlen,int * sumlen,int * aframes,int * nframes)220312bd3c8bSSascha Wildner usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes,
220412bd3c8bSSascha Wildner     int *nframes)
220512bd3c8bSSascha Wildner {
220612bd3c8bSSascha Wildner 	if (actlen != NULL)
220712bd3c8bSSascha Wildner 		*actlen = xfer->actlen;
220812bd3c8bSSascha Wildner 	if (sumlen != NULL)
220912bd3c8bSSascha Wildner 		*sumlen = xfer->sumlen;
221012bd3c8bSSascha Wildner 	if (aframes != NULL)
221112bd3c8bSSascha Wildner 		*aframes = xfer->aframes;
221212bd3c8bSSascha Wildner 	if (nframes != NULL)
221312bd3c8bSSascha Wildner 		*nframes = xfer->nframes;
221412bd3c8bSSascha Wildner }
221512bd3c8bSSascha Wildner 
221612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
221712bd3c8bSSascha Wildner  *	usbd_xfer_set_frame_offset
221812bd3c8bSSascha Wildner  *
221912bd3c8bSSascha Wildner  * This function sets the frame data buffer offset relative to the beginning
222012bd3c8bSSascha Wildner  * of the USB DMA buffer allocated for this USB transfer.
222112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
222212bd3c8bSSascha Wildner void
usbd_xfer_set_frame_offset(struct usb_xfer * xfer,usb_frlength_t offset,usb_frcount_t frindex)222312bd3c8bSSascha Wildner usbd_xfer_set_frame_offset(struct usb_xfer *xfer, usb_frlength_t offset,
222412bd3c8bSSascha Wildner     usb_frcount_t frindex)
222512bd3c8bSSascha Wildner {
222612bd3c8bSSascha Wildner 	KASSERT(!xfer->flags.ext_buffer, ("Cannot offset data frame "
222712bd3c8bSSascha Wildner 	    "when the USB buffer is external\n"));
222812bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
222912bd3c8bSSascha Wildner 
223012bd3c8bSSascha Wildner 	/* set virtual address to load */
223112bd3c8bSSascha Wildner 	xfer->frbuffers[frindex].buffer =
223212bd3c8bSSascha Wildner 	    USB_ADD_BYTES(xfer->local_buffer, offset);
223312bd3c8bSSascha Wildner }
223412bd3c8bSSascha Wildner 
223512bd3c8bSSascha Wildner void
usbd_xfer_set_interval(struct usb_xfer * xfer,int i)223612bd3c8bSSascha Wildner usbd_xfer_set_interval(struct usb_xfer *xfer, int i)
223712bd3c8bSSascha Wildner {
223812bd3c8bSSascha Wildner 	xfer->interval = i;
223912bd3c8bSSascha Wildner }
224012bd3c8bSSascha Wildner 
224112bd3c8bSSascha Wildner void
usbd_xfer_set_timeout(struct usb_xfer * xfer,int t)224212bd3c8bSSascha Wildner usbd_xfer_set_timeout(struct usb_xfer *xfer, int t)
224312bd3c8bSSascha Wildner {
224412bd3c8bSSascha Wildner 	xfer->timeout = t;
224512bd3c8bSSascha Wildner }
224612bd3c8bSSascha Wildner 
224712bd3c8bSSascha Wildner void
usbd_xfer_set_frames(struct usb_xfer * xfer,usb_frcount_t n)224812bd3c8bSSascha Wildner usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n)
224912bd3c8bSSascha Wildner {
225012bd3c8bSSascha Wildner 	xfer->nframes = n;
225112bd3c8bSSascha Wildner }
225212bd3c8bSSascha Wildner 
225312bd3c8bSSascha Wildner usb_frcount_t
usbd_xfer_max_frames(struct usb_xfer * xfer)225412bd3c8bSSascha Wildner usbd_xfer_max_frames(struct usb_xfer *xfer)
225512bd3c8bSSascha Wildner {
225612bd3c8bSSascha Wildner 	return (xfer->max_frame_count);
225712bd3c8bSSascha Wildner }
225812bd3c8bSSascha Wildner 
225912bd3c8bSSascha Wildner usb_frlength_t
usbd_xfer_max_len(struct usb_xfer * xfer)226012bd3c8bSSascha Wildner usbd_xfer_max_len(struct usb_xfer *xfer)
226112bd3c8bSSascha Wildner {
226212bd3c8bSSascha Wildner 	return (xfer->max_data_length);
226312bd3c8bSSascha Wildner }
226412bd3c8bSSascha Wildner 
226512bd3c8bSSascha Wildner usb_frlength_t
usbd_xfer_max_framelen(struct usb_xfer * xfer)226612bd3c8bSSascha Wildner usbd_xfer_max_framelen(struct usb_xfer *xfer)
226712bd3c8bSSascha Wildner {
226812bd3c8bSSascha Wildner 	return (xfer->max_frame_size);
226912bd3c8bSSascha Wildner }
227012bd3c8bSSascha Wildner 
227112bd3c8bSSascha Wildner void
usbd_xfer_set_frame_len(struct usb_xfer * xfer,usb_frcount_t frindex,usb_frlength_t len)227212bd3c8bSSascha Wildner usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex,
227312bd3c8bSSascha Wildner     usb_frlength_t len)
227412bd3c8bSSascha Wildner {
227512bd3c8bSSascha Wildner 	KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
227612bd3c8bSSascha Wildner 
227712bd3c8bSSascha Wildner 	xfer->frlengths[frindex] = len;
227812bd3c8bSSascha Wildner }
227912bd3c8bSSascha Wildner 
228012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
228112bd3c8bSSascha Wildner  *	usb_callback_proc - factored out code
228212bd3c8bSSascha Wildner  *
228312bd3c8bSSascha Wildner  * This function performs USB callbacks.
228412bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
228512bd3c8bSSascha Wildner static void
usb_callback_proc(struct usb_proc_msg * _pm)228612bd3c8bSSascha Wildner usb_callback_proc(struct usb_proc_msg *_pm)
228712bd3c8bSSascha Wildner {
228812bd3c8bSSascha Wildner 	struct usb_done_msg *pm = (void *)_pm;
228912bd3c8bSSascha Wildner 	struct usb_xfer_root *info = pm->xroot;
229012bd3c8bSSascha Wildner 
229112bd3c8bSSascha Wildner 	/* Change locking order */
229212bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(info->bus);
229312bd3c8bSSascha Wildner 
229412bd3c8bSSascha Wildner 	/*
229512bd3c8bSSascha Wildner 	 * We exploit the fact that the mutex is the same for all
229612bd3c8bSSascha Wildner 	 * callbacks that will be called from this thread:
229712bd3c8bSSascha Wildner 	 */
2298722d05c3SSascha Wildner 	lockmgr(info->xfer_lock, LK_EXCLUSIVE);
229912bd3c8bSSascha Wildner 	USB_BUS_LOCK(info->bus);
230012bd3c8bSSascha Wildner 
230112bd3c8bSSascha Wildner 	/* Continue where we lost track */
230212bd3c8bSSascha Wildner 	usb_command_wrapper(&info->done_q,
230312bd3c8bSSascha Wildner 	    info->done_q.curr);
230412bd3c8bSSascha Wildner 
2305722d05c3SSascha Wildner 	lockmgr(info->xfer_lock, LK_RELEASE);
230612bd3c8bSSascha Wildner }
230712bd3c8bSSascha Wildner 
230812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
230912bd3c8bSSascha Wildner  *	usbd_callback_ss_done_defer
231012bd3c8bSSascha Wildner  *
231112bd3c8bSSascha Wildner  * This function will defer the start, stop and done callback to the
231212bd3c8bSSascha Wildner  * correct thread.
231312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
231412bd3c8bSSascha Wildner static void
usbd_callback_ss_done_defer(struct usb_xfer * xfer)231512bd3c8bSSascha Wildner usbd_callback_ss_done_defer(struct usb_xfer *xfer)
231612bd3c8bSSascha Wildner {
231712bd3c8bSSascha Wildner 	struct usb_xfer_root *info = xfer->xroot;
231812bd3c8bSSascha Wildner 	struct usb_xfer_queue *pq = &info->done_q;
231912bd3c8bSSascha Wildner 
2320722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus);
232112bd3c8bSSascha Wildner 
232212bd3c8bSSascha Wildner 	if (pq->curr != xfer) {
232312bd3c8bSSascha Wildner 		usbd_transfer_enqueue(pq, xfer);
232412bd3c8bSSascha Wildner 	}
232512bd3c8bSSascha Wildner 	if (!pq->recurse_1) {
232612bd3c8bSSascha Wildner 
232712bd3c8bSSascha Wildner 		/*
232812bd3c8bSSascha Wildner 	         * We have to postpone the callback due to the fact we
232912bd3c8bSSascha Wildner 	         * will have a Lock Order Reversal, LOR, if we try to
233012bd3c8bSSascha Wildner 	         * proceed !
233112bd3c8bSSascha Wildner 	         */
233212bd3c8bSSascha Wildner 		if (usb_proc_msignal(info->done_p,
233312bd3c8bSSascha Wildner 		    &info->done_m[0], &info->done_m[1])) {
233412bd3c8bSSascha Wildner 			/* ignore */
233512bd3c8bSSascha Wildner 		}
233612bd3c8bSSascha Wildner 	} else {
233712bd3c8bSSascha Wildner 		/* clear second recurse flag */
233812bd3c8bSSascha Wildner 		pq->recurse_2 = 0;
233912bd3c8bSSascha Wildner 	}
234012bd3c8bSSascha Wildner 	return;
234112bd3c8bSSascha Wildner 
234212bd3c8bSSascha Wildner }
234312bd3c8bSSascha Wildner 
234412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
234512bd3c8bSSascha Wildner  *	usbd_callback_wrapper
234612bd3c8bSSascha Wildner  *
234712bd3c8bSSascha Wildner  * This is a wrapper for USB callbacks. This wrapper does some
234812bd3c8bSSascha Wildner  * auto-magic things like figuring out if we can call the callback
234912bd3c8bSSascha Wildner  * directly from the current context or if we need to wakeup the
235012bd3c8bSSascha Wildner  * interrupt process.
235112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
235212bd3c8bSSascha Wildner static void
usbd_callback_wrapper(struct usb_xfer_queue * pq)235312bd3c8bSSascha Wildner usbd_callback_wrapper(struct usb_xfer_queue *pq)
235412bd3c8bSSascha Wildner {
235512bd3c8bSSascha Wildner 	struct usb_xfer *xfer = pq->curr;
235612bd3c8bSSascha Wildner 	struct usb_xfer_root *info = xfer->xroot;
235712bd3c8bSSascha Wildner 
2358722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(info->bus);
23593a76bbe8SSascha Wildner 	if (!lockowned(info->xfer_lock)) {
236012bd3c8bSSascha Wildner 		/*
236112bd3c8bSSascha Wildner 		 * Cases that end up here:
236212bd3c8bSSascha Wildner 		 *
236312bd3c8bSSascha Wildner 		 * 5) HW interrupt done callback or other source.
236412bd3c8bSSascha Wildner 		 */
236512bd3c8bSSascha Wildner 		DPRINTFN(3, "case 5\n");
236612bd3c8bSSascha Wildner 
236712bd3c8bSSascha Wildner 		/*
236812bd3c8bSSascha Wildner 	         * We have to postpone the callback due to the fact we
236912bd3c8bSSascha Wildner 	         * will have a Lock Order Reversal, LOR, if we try to
237012bd3c8bSSascha Wildner 	         * proceed !
237112bd3c8bSSascha Wildner 	         */
237212bd3c8bSSascha Wildner 		if (usb_proc_msignal(info->done_p,
237312bd3c8bSSascha Wildner 		    &info->done_m[0], &info->done_m[1])) {
237412bd3c8bSSascha Wildner 			/* ignore */
237512bd3c8bSSascha Wildner 		}
237612bd3c8bSSascha Wildner 		return;
237712bd3c8bSSascha Wildner 	}
237812bd3c8bSSascha Wildner 	/*
237912bd3c8bSSascha Wildner 	 * Cases that end up here:
238012bd3c8bSSascha Wildner 	 *
238112bd3c8bSSascha Wildner 	 * 1) We are starting a transfer
238212bd3c8bSSascha Wildner 	 * 2) We are prematurely calling back a transfer
238312bd3c8bSSascha Wildner 	 * 3) We are stopping a transfer
238412bd3c8bSSascha Wildner 	 * 4) We are doing an ordinary callback
238512bd3c8bSSascha Wildner 	 */
238612bd3c8bSSascha Wildner 	DPRINTFN(3, "case 1-4\n");
238712bd3c8bSSascha Wildner 	/* get next USB transfer in the queue */
238812bd3c8bSSascha Wildner 	info->done_q.curr = NULL;
238912bd3c8bSSascha Wildner 
239012bd3c8bSSascha Wildner 	/* set flag in case of drain */
239112bd3c8bSSascha Wildner 	xfer->flags_int.doing_callback = 1;
239212bd3c8bSSascha Wildner 
239312bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(info->bus);
2394722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT_NOTOWNED(info->bus);
239512bd3c8bSSascha Wildner 
239612bd3c8bSSascha Wildner 	/* set correct USB state for callback */
239712bd3c8bSSascha Wildner 	if (!xfer->flags_int.transferring) {
239812bd3c8bSSascha Wildner 		xfer->usb_state = USB_ST_SETUP;
239912bd3c8bSSascha Wildner 		if (!xfer->flags_int.started) {
240012bd3c8bSSascha Wildner 			/* we got stopped before we even got started */
240112bd3c8bSSascha Wildner 			USB_BUS_LOCK(info->bus);
240212bd3c8bSSascha Wildner 			goto done;
240312bd3c8bSSascha Wildner 		}
240412bd3c8bSSascha Wildner 	} else {
240512bd3c8bSSascha Wildner 
240612bd3c8bSSascha Wildner 		if (usbd_callback_wrapper_sub(xfer)) {
240712bd3c8bSSascha Wildner 			/* the callback has been deferred */
240812bd3c8bSSascha Wildner 			USB_BUS_LOCK(info->bus);
240912bd3c8bSSascha Wildner 			goto done;
241012bd3c8bSSascha Wildner 		}
241112bd3c8bSSascha Wildner #if USB_HAVE_POWERD
241212bd3c8bSSascha Wildner 		/* decrement power reference */
241312bd3c8bSSascha Wildner 		usbd_transfer_power_ref(xfer, -1);
241412bd3c8bSSascha Wildner #endif
241512bd3c8bSSascha Wildner 		xfer->flags_int.transferring = 0;
241612bd3c8bSSascha Wildner 
241712bd3c8bSSascha Wildner 		if (xfer->error) {
241812bd3c8bSSascha Wildner 			xfer->usb_state = USB_ST_ERROR;
241912bd3c8bSSascha Wildner 		} else {
242012bd3c8bSSascha Wildner 			/* set transferred state */
242112bd3c8bSSascha Wildner 			xfer->usb_state = USB_ST_TRANSFERRED;
242212bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
242312bd3c8bSSascha Wildner 			/* sync DMA memory, if any */
242412bd3c8bSSascha Wildner 			if (xfer->flags_int.bdma_enable &&
242512bd3c8bSSascha Wildner 			    (!xfer->flags_int.bdma_no_post_sync)) {
242612bd3c8bSSascha Wildner 				usb_bdma_post_sync(xfer);
242712bd3c8bSSascha Wildner 			}
242812bd3c8bSSascha Wildner #endif
242912bd3c8bSSascha Wildner 		}
243012bd3c8bSSascha Wildner 	}
243112bd3c8bSSascha Wildner 
243212bd3c8bSSascha Wildner #if USB_HAVE_PF
243312bd3c8bSSascha Wildner 	if (xfer->usb_state != USB_ST_SETUP)
243412bd3c8bSSascha Wildner 		usbpf_xfertap(xfer, USBPF_XFERTAP_DONE);
243512bd3c8bSSascha Wildner #endif
243612bd3c8bSSascha Wildner 	/* call processing routine */
243712bd3c8bSSascha Wildner 	(xfer->callback) (xfer, xfer->error);
243812bd3c8bSSascha Wildner 
243912bd3c8bSSascha Wildner 	/* pickup the USB mutex again */
244012bd3c8bSSascha Wildner 	USB_BUS_LOCK(info->bus);
244112bd3c8bSSascha Wildner 
244212bd3c8bSSascha Wildner 	/*
244312bd3c8bSSascha Wildner 	 * Check if we got started after that we got cancelled, but
244412bd3c8bSSascha Wildner 	 * before we managed to do the callback.
244512bd3c8bSSascha Wildner 	 */
244612bd3c8bSSascha Wildner 	if ((!xfer->flags_int.open) &&
244712bd3c8bSSascha Wildner 	    (xfer->flags_int.started) &&
244812bd3c8bSSascha Wildner 	    (xfer->usb_state == USB_ST_ERROR)) {
244912bd3c8bSSascha Wildner 		/* clear flag in case of drain */
245012bd3c8bSSascha Wildner 		xfer->flags_int.doing_callback = 0;
245112bd3c8bSSascha Wildner 		/* try to loop, but not recursivly */
245212bd3c8bSSascha Wildner 		usb_command_wrapper(&info->done_q, xfer);
245312bd3c8bSSascha Wildner 		return;
245412bd3c8bSSascha Wildner 	}
245512bd3c8bSSascha Wildner 
245612bd3c8bSSascha Wildner done:
245712bd3c8bSSascha Wildner 	/* clear flag in case of drain */
245812bd3c8bSSascha Wildner 	xfer->flags_int.doing_callback = 0;
245912bd3c8bSSascha Wildner 
246012bd3c8bSSascha Wildner 	/*
246112bd3c8bSSascha Wildner 	 * Check if we are draining.
246212bd3c8bSSascha Wildner 	 */
246312bd3c8bSSascha Wildner 	if (xfer->flags_int.draining &&
246412bd3c8bSSascha Wildner 	    (!xfer->flags_int.transferring)) {
246512bd3c8bSSascha Wildner 		/* "usbd_transfer_drain()" is waiting for end of transfer */
246612bd3c8bSSascha Wildner 		xfer->flags_int.draining = 0;
2467ccb00b06SMatthew Dillon 		/* cv_broadcast(&info->cv_drain); */
2468ccb00b06SMatthew Dillon 		wakeup(xfer);
246912bd3c8bSSascha Wildner 	}
247012bd3c8bSSascha Wildner 
247112bd3c8bSSascha Wildner 	/* do the next callback, if any */
247212bd3c8bSSascha Wildner 	usb_command_wrapper(&info->done_q,
247312bd3c8bSSascha Wildner 	    info->done_q.curr);
247412bd3c8bSSascha Wildner }
247512bd3c8bSSascha Wildner 
247612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
247712bd3c8bSSascha Wildner  *	usb_dma_delay_done_cb
247812bd3c8bSSascha Wildner  *
247912bd3c8bSSascha Wildner  * This function is called when the DMA delay has been exectuded, and
248012bd3c8bSSascha Wildner  * will make sure that the callback is called to complete the USB
248112bd3c8bSSascha Wildner  * transfer. This code path is ususally only used when there is an USB
248212bd3c8bSSascha Wildner  * error like USB_ERR_CANCELLED.
248312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
248412bd3c8bSSascha Wildner void
usb_dma_delay_done_cb(struct usb_xfer * xfer)248512bd3c8bSSascha Wildner usb_dma_delay_done_cb(struct usb_xfer *xfer)
248612bd3c8bSSascha Wildner {
2487722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus);
248812bd3c8bSSascha Wildner 
248912bd3c8bSSascha Wildner 	DPRINTFN(3, "Completed %p\n", xfer);
249012bd3c8bSSascha Wildner 
249112bd3c8bSSascha Wildner 	/* queue callback for execution, again */
249212bd3c8bSSascha Wildner 	usbd_transfer_done(xfer, 0);
249312bd3c8bSSascha Wildner }
249412bd3c8bSSascha Wildner 
249512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
249612bd3c8bSSascha Wildner  *	usbd_transfer_dequeue
249712bd3c8bSSascha Wildner  *
249812bd3c8bSSascha Wildner  *  - This function is used to remove an USB transfer from a USB
249912bd3c8bSSascha Wildner  *  transfer queue.
250012bd3c8bSSascha Wildner  *
250112bd3c8bSSascha Wildner  *  - This function can be called multiple times in a row.
250212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
250312bd3c8bSSascha Wildner void
usbd_transfer_dequeue(struct usb_xfer * xfer)250412bd3c8bSSascha Wildner usbd_transfer_dequeue(struct usb_xfer *xfer)
250512bd3c8bSSascha Wildner {
250612bd3c8bSSascha Wildner 	struct usb_xfer_queue *pq;
250712bd3c8bSSascha Wildner 
250812bd3c8bSSascha Wildner 	pq = xfer->wait_queue;
250912bd3c8bSSascha Wildner 	if (pq) {
251012bd3c8bSSascha Wildner 		TAILQ_REMOVE(&pq->head, xfer, wait_entry);
251112bd3c8bSSascha Wildner 		xfer->wait_queue = NULL;
251212bd3c8bSSascha Wildner 	}
251312bd3c8bSSascha Wildner }
251412bd3c8bSSascha Wildner 
251512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
251612bd3c8bSSascha Wildner  *	usbd_transfer_enqueue
251712bd3c8bSSascha Wildner  *
251812bd3c8bSSascha Wildner  *  - This function is used to insert an USB transfer into a USB *
251912bd3c8bSSascha Wildner  *  transfer queue.
252012bd3c8bSSascha Wildner  *
252112bd3c8bSSascha Wildner  *  - This function can be called multiple times in a row.
252212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
252312bd3c8bSSascha Wildner void
usbd_transfer_enqueue(struct usb_xfer_queue * pq,struct usb_xfer * xfer)252412bd3c8bSSascha Wildner usbd_transfer_enqueue(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
252512bd3c8bSSascha Wildner {
252612bd3c8bSSascha Wildner 	/*
252712bd3c8bSSascha Wildner 	 * Insert the USB transfer into the queue, if it is not
252812bd3c8bSSascha Wildner 	 * already on a USB transfer queue:
252912bd3c8bSSascha Wildner 	 */
2530a72f2492SMarkus Pfeiffer 	/* mpf ?
2531ccb00b06SMatthew Dillon 	KKASSERT(xfer->wait_queue == NULL);
2532a72f2492SMarkus Pfeiffer 	*/
253312bd3c8bSSascha Wildner 	if (xfer->wait_queue == NULL) {
253412bd3c8bSSascha Wildner 		xfer->wait_queue = pq;
253512bd3c8bSSascha Wildner 		TAILQ_INSERT_TAIL(&pq->head, xfer, wait_entry);
253612bd3c8bSSascha Wildner 	}
253712bd3c8bSSascha Wildner }
253812bd3c8bSSascha Wildner 
253912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
254012bd3c8bSSascha Wildner  *	usbd_transfer_done
254112bd3c8bSSascha Wildner  *
254212bd3c8bSSascha Wildner  *  - This function is used to remove an USB transfer from the busdma,
254312bd3c8bSSascha Wildner  *  pipe or interrupt queue.
254412bd3c8bSSascha Wildner  *
254512bd3c8bSSascha Wildner  *  - This function is used to queue the USB transfer on the done
254612bd3c8bSSascha Wildner  *  queue.
254712bd3c8bSSascha Wildner  *
254812bd3c8bSSascha Wildner  *  - This function is used to stop any USB transfer timeouts.
254912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
255012bd3c8bSSascha Wildner void
usbd_transfer_done(struct usb_xfer * xfer,usb_error_t error)255112bd3c8bSSascha Wildner usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
255212bd3c8bSSascha Wildner {
255306cb2463SMarkus Pfeiffer 	struct usb_xfer_root *info = xfer->xroot;
255406cb2463SMarkus Pfeiffer 
255506cb2463SMarkus Pfeiffer 	USB_BUS_LOCK_ASSERT(info->bus);
255612bd3c8bSSascha Wildner 
255712bd3c8bSSascha Wildner 	DPRINTF("err=%s\n", usbd_errstr(error));
255812bd3c8bSSascha Wildner 
255912bd3c8bSSascha Wildner 	/*
256012bd3c8bSSascha Wildner 	 * If we are not transferring then just return.
256112bd3c8bSSascha Wildner 	 * This can happen during transfer cancel.
256212bd3c8bSSascha Wildner 	 */
256312bd3c8bSSascha Wildner 	if (!xfer->flags_int.transferring) {
256412bd3c8bSSascha Wildner 		DPRINTF("not transferring\n");
256512bd3c8bSSascha Wildner 		/* end of control transfer, if any */
256612bd3c8bSSascha Wildner 		xfer->flags_int.control_act = 0;
256712bd3c8bSSascha Wildner 		return;
256812bd3c8bSSascha Wildner 	}
256906cb2463SMarkus Pfeiffer 	/* only set transfer error, if not already set */
257006cb2463SMarkus Pfeiffer 	if (xfer->error == USB_ERR_NORMAL_COMPLETION)
257112bd3c8bSSascha Wildner 		xfer->error = error;
257206cb2463SMarkus Pfeiffer 
257312bd3c8bSSascha Wildner 	/* stop any callouts */
257412bd3c8bSSascha Wildner 	usb_callout_stop(&xfer->timeout_handle);
257512bd3c8bSSascha Wildner 
257612bd3c8bSSascha Wildner 	/*
257712bd3c8bSSascha Wildner 	 * If we are waiting on a queue, just remove the USB transfer
257812bd3c8bSSascha Wildner 	 * from the queue, if any. We should have the required locks
257912bd3c8bSSascha Wildner 	 * locked to do the remove when this function is called.
258012bd3c8bSSascha Wildner 	 */
258112bd3c8bSSascha Wildner 	usbd_transfer_dequeue(xfer);
258212bd3c8bSSascha Wildner 
258312bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA
25843a76bbe8SSascha Wildner 	if (lockowned(xfer->xroot->xfer_lock)) {
258512bd3c8bSSascha Wildner 		struct usb_xfer_queue *pq;
258612bd3c8bSSascha Wildner 
258712bd3c8bSSascha Wildner 		/*
258812bd3c8bSSascha Wildner 		 * If the private USB lock is not locked, then we assume
258912bd3c8bSSascha Wildner 		 * that the BUS-DMA load stage has been passed:
259012bd3c8bSSascha Wildner 		 */
259106cb2463SMarkus Pfeiffer 		pq = &info->dma_q;
259212bd3c8bSSascha Wildner 
259312bd3c8bSSascha Wildner 		if (pq->curr == xfer) {
259412bd3c8bSSascha Wildner 			/* start the next BUS-DMA load, if any */
259512bd3c8bSSascha Wildner 			usb_command_wrapper(pq, NULL);
259612bd3c8bSSascha Wildner 		}
259712bd3c8bSSascha Wildner 	}
259812bd3c8bSSascha Wildner #endif
259912bd3c8bSSascha Wildner 	/* keep some statistics */
260012bd3c8bSSascha Wildner 	if (xfer->error) {
260106cb2463SMarkus Pfeiffer 		info->bus->stats_err.uds_requests
260212bd3c8bSSascha Wildner 		    [xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
260312bd3c8bSSascha Wildner 	} else {
260406cb2463SMarkus Pfeiffer 		info->bus->stats_ok.uds_requests
260512bd3c8bSSascha Wildner 		    [xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
260612bd3c8bSSascha Wildner 	}
260712bd3c8bSSascha Wildner 
260812bd3c8bSSascha Wildner 	/* call the USB transfer callback */
260912bd3c8bSSascha Wildner 	usbd_callback_ss_done_defer(xfer);
261012bd3c8bSSascha Wildner }
261112bd3c8bSSascha Wildner 
261212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
261312bd3c8bSSascha Wildner  *	usbd_transfer_start_cb
261412bd3c8bSSascha Wildner  *
261512bd3c8bSSascha Wildner  * This function is called to start the USB transfer when
261612bd3c8bSSascha Wildner  * "xfer->interval" is greater than zero, and and the endpoint type is
261712bd3c8bSSascha Wildner  * BULK or CONTROL.
261812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
261912bd3c8bSSascha Wildner static void
usbd_transfer_start_cb(void * arg)262012bd3c8bSSascha Wildner usbd_transfer_start_cb(void *arg)
262112bd3c8bSSascha Wildner {
262212bd3c8bSSascha Wildner 	struct usb_xfer *xfer = arg;
262312bd3c8bSSascha Wildner 	struct usb_endpoint *ep = xfer->endpoint;
262412bd3c8bSSascha Wildner 
2625722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus);
262612bd3c8bSSascha Wildner 
262712bd3c8bSSascha Wildner 	DPRINTF("start\n");
262812bd3c8bSSascha Wildner 
262912bd3c8bSSascha Wildner #if USB_HAVE_PF
263012bd3c8bSSascha Wildner 	usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
263112bd3c8bSSascha Wildner #endif
263212bd3c8bSSascha Wildner 
26335e41ab93SMarkus Pfeiffer 	/* the transfer can now be cancelled */
263412bd3c8bSSascha Wildner 	xfer->flags_int.can_cancel_immed = 1;
263512bd3c8bSSascha Wildner 
263657bed822SMarkus Pfeiffer 	/* start USB transfer, if no error */
263757bed822SMarkus Pfeiffer 	if (xfer->error == 0)
263857bed822SMarkus Pfeiffer 		(ep->methods->start) (xfer);
263957bed822SMarkus Pfeiffer 
264057bed822SMarkus Pfeiffer 	/* check for transfer error */
264112bd3c8bSSascha Wildner 	if (xfer->error) {
264212bd3c8bSSascha Wildner 		/* some error has happened */
264312bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, 0);
264412bd3c8bSSascha Wildner 	}
264512bd3c8bSSascha Wildner }
264612bd3c8bSSascha Wildner 
264712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
264812bd3c8bSSascha Wildner  *	usbd_xfer_set_stall
264912bd3c8bSSascha Wildner  *
265012bd3c8bSSascha Wildner  * This function is used to set the stall flag outside the
265112bd3c8bSSascha Wildner  * callback. This function is NULL safe.
265212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
265312bd3c8bSSascha Wildner void
usbd_xfer_set_stall(struct usb_xfer * xfer)265412bd3c8bSSascha Wildner usbd_xfer_set_stall(struct usb_xfer *xfer)
265512bd3c8bSSascha Wildner {
265612bd3c8bSSascha Wildner 	if (xfer == NULL) {
265712bd3c8bSSascha Wildner 		/* tearing down */
265812bd3c8bSSascha Wildner 		return;
265912bd3c8bSSascha Wildner 	}
2660722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer);
266112bd3c8bSSascha Wildner 
266212bd3c8bSSascha Wildner 	/* avoid any races by locking the USB mutex */
266312bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
266412bd3c8bSSascha Wildner 	xfer->flags.stall_pipe = 1;
266512bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
266612bd3c8bSSascha Wildner }
266712bd3c8bSSascha Wildner 
266812bd3c8bSSascha Wildner int
usbd_xfer_is_stalled(struct usb_xfer * xfer)266912bd3c8bSSascha Wildner usbd_xfer_is_stalled(struct usb_xfer *xfer)
267012bd3c8bSSascha Wildner {
267112bd3c8bSSascha Wildner 	return (xfer->endpoint->is_stalled);
267212bd3c8bSSascha Wildner }
267312bd3c8bSSascha Wildner 
267412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
267512bd3c8bSSascha Wildner  *	usbd_transfer_clear_stall
267612bd3c8bSSascha Wildner  *
267712bd3c8bSSascha Wildner  * This function is used to clear the stall flag outside the
267812bd3c8bSSascha Wildner  * callback. This function is NULL safe.
267912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
268012bd3c8bSSascha Wildner void
usbd_transfer_clear_stall(struct usb_xfer * xfer)268112bd3c8bSSascha Wildner usbd_transfer_clear_stall(struct usb_xfer *xfer)
268212bd3c8bSSascha Wildner {
268312bd3c8bSSascha Wildner 	if (xfer == NULL) {
268412bd3c8bSSascha Wildner 		/* tearing down */
268512bd3c8bSSascha Wildner 		return;
268612bd3c8bSSascha Wildner 	}
2687722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer);
268812bd3c8bSSascha Wildner 
268912bd3c8bSSascha Wildner 	/* avoid any races by locking the USB mutex */
269012bd3c8bSSascha Wildner 	USB_BUS_LOCK(xfer->xroot->bus);
269112bd3c8bSSascha Wildner 
269212bd3c8bSSascha Wildner 	xfer->flags.stall_pipe = 0;
269312bd3c8bSSascha Wildner 
269412bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(xfer->xroot->bus);
269512bd3c8bSSascha Wildner }
269612bd3c8bSSascha Wildner 
269712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
269812bd3c8bSSascha Wildner  *	usbd_pipe_start
269912bd3c8bSSascha Wildner  *
270012bd3c8bSSascha Wildner  * This function is used to add an USB transfer to the pipe transfer list.
270112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
270212bd3c8bSSascha Wildner void
usbd_pipe_start(struct usb_xfer_queue * pq)270312bd3c8bSSascha Wildner usbd_pipe_start(struct usb_xfer_queue *pq)
270412bd3c8bSSascha Wildner {
270512bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
270612bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
270712bd3c8bSSascha Wildner 	uint8_t type;
270812bd3c8bSSascha Wildner 
270912bd3c8bSSascha Wildner 	xfer = pq->curr;
271012bd3c8bSSascha Wildner 	ep = xfer->endpoint;
271112bd3c8bSSascha Wildner 
2712722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus);
271312bd3c8bSSascha Wildner 
271412bd3c8bSSascha Wildner 	/*
271512bd3c8bSSascha Wildner 	 * If the endpoint is already stalled we do nothing !
271612bd3c8bSSascha Wildner 	 */
271712bd3c8bSSascha Wildner 	if (ep->is_stalled) {
271812bd3c8bSSascha Wildner 		return;
271912bd3c8bSSascha Wildner 	}
272012bd3c8bSSascha Wildner 	/*
272112bd3c8bSSascha Wildner 	 * Check if we are supposed to stall the endpoint:
272212bd3c8bSSascha Wildner 	 */
272312bd3c8bSSascha Wildner 	if (xfer->flags.stall_pipe) {
272412bd3c8bSSascha Wildner 		struct usb_device *udev;
272512bd3c8bSSascha Wildner 		struct usb_xfer_root *info;
272612bd3c8bSSascha Wildner 
272712bd3c8bSSascha Wildner 		/* clear stall command */
272812bd3c8bSSascha Wildner 		xfer->flags.stall_pipe = 0;
272912bd3c8bSSascha Wildner 
273012bd3c8bSSascha Wildner 		/* get pointer to USB device */
273112bd3c8bSSascha Wildner 		info = xfer->xroot;
273212bd3c8bSSascha Wildner 		udev = info->udev;
273312bd3c8bSSascha Wildner 
273412bd3c8bSSascha Wildner 		/*
273512bd3c8bSSascha Wildner 		 * Only stall BULK and INTERRUPT endpoints.
273612bd3c8bSSascha Wildner 		 */
273712bd3c8bSSascha Wildner 		type = (ep->edesc->bmAttributes & UE_XFERTYPE);
273812bd3c8bSSascha Wildner 		if ((type == UE_BULK) ||
273912bd3c8bSSascha Wildner 		    (type == UE_INTERRUPT)) {
274012bd3c8bSSascha Wildner 			uint8_t did_stall;
274112bd3c8bSSascha Wildner 
274212bd3c8bSSascha Wildner 			did_stall = 1;
274312bd3c8bSSascha Wildner 
274412bd3c8bSSascha Wildner 			if (udev->flags.usb_mode == USB_MODE_DEVICE) {
274512bd3c8bSSascha Wildner 				(udev->bus->methods->set_stall) (
27465e41ab93SMarkus Pfeiffer 				    udev, ep, &did_stall);
274712bd3c8bSSascha Wildner 			} else if (udev->ctrl_xfer[1]) {
274812bd3c8bSSascha Wildner 				info = udev->ctrl_xfer[1]->xroot;
274912bd3c8bSSascha Wildner 				usb_proc_msignal(
275057bed822SMarkus Pfeiffer 				    USB_BUS_NON_GIANT_PROC(info->bus),
275112bd3c8bSSascha Wildner 				    &udev->cs_msg[0], &udev->cs_msg[1]);
275212bd3c8bSSascha Wildner 			} else {
275312bd3c8bSSascha Wildner 				/* should not happen */
275412bd3c8bSSascha Wildner 				DPRINTFN(0, "No stall handler\n");
275512bd3c8bSSascha Wildner 			}
275612bd3c8bSSascha Wildner 			/*
275712bd3c8bSSascha Wildner 			 * Check if we should stall. Some USB hardware
275812bd3c8bSSascha Wildner 			 * handles set- and clear-stall in hardware.
275912bd3c8bSSascha Wildner 			 */
276012bd3c8bSSascha Wildner 			if (did_stall) {
276112bd3c8bSSascha Wildner 				/*
276212bd3c8bSSascha Wildner 				 * The transfer will be continued when
276312bd3c8bSSascha Wildner 				 * the clear-stall control endpoint
276412bd3c8bSSascha Wildner 				 * message is received.
276512bd3c8bSSascha Wildner 				 */
276612bd3c8bSSascha Wildner 				ep->is_stalled = 1;
276712bd3c8bSSascha Wildner 				return;
276812bd3c8bSSascha Wildner 			}
276912bd3c8bSSascha Wildner 		} else if (type == UE_ISOCHRONOUS) {
277012bd3c8bSSascha Wildner 
277112bd3c8bSSascha Wildner 			/*
277212bd3c8bSSascha Wildner 			 * Make sure any FIFO overflow or other FIFO
277312bd3c8bSSascha Wildner 			 * error conditions go away by resetting the
277412bd3c8bSSascha Wildner 			 * endpoint FIFO through the clear stall
277512bd3c8bSSascha Wildner 			 * method.
277612bd3c8bSSascha Wildner 			 */
277712bd3c8bSSascha Wildner 			if (udev->flags.usb_mode == USB_MODE_DEVICE) {
277812bd3c8bSSascha Wildner 				(udev->bus->methods->clear_stall) (udev, ep);
277912bd3c8bSSascha Wildner 			}
278012bd3c8bSSascha Wildner 		}
278112bd3c8bSSascha Wildner 	}
278212bd3c8bSSascha Wildner 	/* Set or clear stall complete - special case */
278312bd3c8bSSascha Wildner 	if (xfer->nframes == 0) {
278412bd3c8bSSascha Wildner 		/* we are complete */
278512bd3c8bSSascha Wildner 		xfer->aframes = 0;
278612bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, 0);
278712bd3c8bSSascha Wildner 		return;
278812bd3c8bSSascha Wildner 	}
278912bd3c8bSSascha Wildner 	/*
279012bd3c8bSSascha Wildner 	 * Handled cases:
279112bd3c8bSSascha Wildner 	 *
279212bd3c8bSSascha Wildner 	 * 1) Start the first transfer queued.
279312bd3c8bSSascha Wildner 	 *
279412bd3c8bSSascha Wildner 	 * 2) Re-start the current USB transfer.
279512bd3c8bSSascha Wildner 	 */
279612bd3c8bSSascha Wildner 	/*
279712bd3c8bSSascha Wildner 	 * Check if there should be any
279812bd3c8bSSascha Wildner 	 * pre transfer start delay:
279912bd3c8bSSascha Wildner 	 */
280012bd3c8bSSascha Wildner 	if (xfer->interval > 0) {
280112bd3c8bSSascha Wildner 		type = (ep->edesc->bmAttributes & UE_XFERTYPE);
280212bd3c8bSSascha Wildner 		if ((type == UE_BULK) ||
280312bd3c8bSSascha Wildner 		    (type == UE_CONTROL)) {
280412bd3c8bSSascha Wildner 			usbd_transfer_timeout_ms(xfer,
280512bd3c8bSSascha Wildner 			    &usbd_transfer_start_cb,
280612bd3c8bSSascha Wildner 			    xfer->interval);
280712bd3c8bSSascha Wildner 			return;
280812bd3c8bSSascha Wildner 		}
280912bd3c8bSSascha Wildner 	}
281012bd3c8bSSascha Wildner 	DPRINTF("start\n");
281112bd3c8bSSascha Wildner 
281212bd3c8bSSascha Wildner #if USB_HAVE_PF
281312bd3c8bSSascha Wildner 	usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
281412bd3c8bSSascha Wildner #endif
281557bed822SMarkus Pfeiffer 	/* the transfer can now be cancelled */
281657bed822SMarkus Pfeiffer 	xfer->flags_int.can_cancel_immed = 1;
281757bed822SMarkus Pfeiffer 
281812bd3c8bSSascha Wildner 	/* start USB transfer, if no error */
281912bd3c8bSSascha Wildner 	if (xfer->error == 0)
282012bd3c8bSSascha Wildner 		(ep->methods->start) (xfer);
282112bd3c8bSSascha Wildner 
282257bed822SMarkus Pfeiffer 	/* check for transfer error */
282312bd3c8bSSascha Wildner 	if (xfer->error) {
282412bd3c8bSSascha Wildner 		/* some error has happened */
282512bd3c8bSSascha Wildner 		usbd_transfer_done(xfer, 0);
282612bd3c8bSSascha Wildner 	}
282712bd3c8bSSascha Wildner }
282812bd3c8bSSascha Wildner 
282912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
283012bd3c8bSSascha Wildner  *	usbd_transfer_timeout_ms
283112bd3c8bSSascha Wildner  *
283212bd3c8bSSascha Wildner  * This function is used to setup a timeout on the given USB
283312bd3c8bSSascha Wildner  * transfer. If the timeout has been deferred the callback given by
283412bd3c8bSSascha Wildner  * "cb" will get called after "ms" milliseconds.
283512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
283612bd3c8bSSascha Wildner void
usbd_transfer_timeout_ms(struct usb_xfer * xfer,void (* cb)(void * arg),usb_timeout_t ms)283712bd3c8bSSascha Wildner usbd_transfer_timeout_ms(struct usb_xfer *xfer,
283812bd3c8bSSascha Wildner     void (*cb) (void *arg), usb_timeout_t ms)
283912bd3c8bSSascha Wildner {
2840722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(xfer->xroot->bus);
284163da4a34SSascha Wildner 
284212bd3c8bSSascha Wildner 	/* defer delay */
284312bd3c8bSSascha Wildner 	usb_callout_reset(&xfer->timeout_handle,
284406cb2463SMarkus Pfeiffer 	    USB_MS_TO_TICKS(ms) + USB_CALLOUT_ZERO_TICKS, cb, xfer);
284512bd3c8bSSascha Wildner }
284612bd3c8bSSascha Wildner 
284712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
284812bd3c8bSSascha Wildner  *	usbd_callback_wrapper_sub
284912bd3c8bSSascha Wildner  *
285012bd3c8bSSascha Wildner  *  - This function will update variables in an USB transfer after
285112bd3c8bSSascha Wildner  *  that the USB transfer is complete.
285212bd3c8bSSascha Wildner  *
285312bd3c8bSSascha Wildner  *  - This function is used to start the next USB transfer on the
285412bd3c8bSSascha Wildner  *  ep transfer queue, if any.
285512bd3c8bSSascha Wildner  *
285612bd3c8bSSascha Wildner  * NOTE: In some special cases the USB transfer will not be removed from
285712bd3c8bSSascha Wildner  * the pipe queue, but remain first. To enforce USB transfer removal call
285812bd3c8bSSascha Wildner  * this function passing the error code "USB_ERR_CANCELLED".
285912bd3c8bSSascha Wildner  *
286012bd3c8bSSascha Wildner  * Return values:
286112bd3c8bSSascha Wildner  * 0: Success.
286212bd3c8bSSascha Wildner  * Else: The callback has been deferred.
286312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
286412bd3c8bSSascha Wildner static uint8_t
usbd_callback_wrapper_sub(struct usb_xfer * xfer)286512bd3c8bSSascha Wildner usbd_callback_wrapper_sub(struct usb_xfer *xfer)
286612bd3c8bSSascha Wildner {
286712bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
286812bd3c8bSSascha Wildner 	struct usb_bus *bus;
286912bd3c8bSSascha Wildner 	usb_frcount_t x;
287012bd3c8bSSascha Wildner 
287112bd3c8bSSascha Wildner 	bus = xfer->xroot->bus;
287212bd3c8bSSascha Wildner 
287312bd3c8bSSascha Wildner 	if ((!xfer->flags_int.open) &&
287412bd3c8bSSascha Wildner 	    (!xfer->flags_int.did_close)) {
287512bd3c8bSSascha Wildner 		DPRINTF("close\n");
287612bd3c8bSSascha Wildner 		USB_BUS_LOCK(bus);
287712bd3c8bSSascha Wildner 		(xfer->endpoint->methods->close) (xfer);
287812bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(bus);
287912bd3c8bSSascha Wildner 		/* only close once */
288012bd3c8bSSascha Wildner 		xfer->flags_int.did_close = 1;
288112bd3c8bSSascha Wildner 		return (1);		/* wait for new callback */
288212bd3c8bSSascha Wildner 	}
288312bd3c8bSSascha Wildner 	/*
288412bd3c8bSSascha Wildner 	 * If we have a non-hardware induced error we
288512bd3c8bSSascha Wildner 	 * need to do the DMA delay!
288612bd3c8bSSascha Wildner 	 */
288712bd3c8bSSascha Wildner 	if (xfer->error != 0 && !xfer->flags_int.did_dma_delay &&
288812bd3c8bSSascha Wildner 	    (xfer->error == USB_ERR_CANCELLED ||
288912bd3c8bSSascha Wildner 	    xfer->error == USB_ERR_TIMEOUT ||
289012bd3c8bSSascha Wildner 	    bus->methods->start_dma_delay != NULL)) {
289112bd3c8bSSascha Wildner 
289212bd3c8bSSascha Wildner 		usb_timeout_t temp;
289312bd3c8bSSascha Wildner 
289412bd3c8bSSascha Wildner 		/* only delay once */
289512bd3c8bSSascha Wildner 		xfer->flags_int.did_dma_delay = 1;
289612bd3c8bSSascha Wildner 
289712bd3c8bSSascha Wildner 		/* we can not cancel this delay */
289812bd3c8bSSascha Wildner 		xfer->flags_int.can_cancel_immed = 0;
289912bd3c8bSSascha Wildner 
290012bd3c8bSSascha Wildner 		temp = usbd_get_dma_delay(xfer->xroot->udev);
290112bd3c8bSSascha Wildner 
290212bd3c8bSSascha Wildner 		DPRINTFN(3, "DMA delay, %u ms, "
290312bd3c8bSSascha Wildner 		    "on %p\n", temp, xfer);
290412bd3c8bSSascha Wildner 
290512bd3c8bSSascha Wildner 		if (temp != 0) {
290612bd3c8bSSascha Wildner 			USB_BUS_LOCK(bus);
290712bd3c8bSSascha Wildner 			/*
290812bd3c8bSSascha Wildner 			 * Some hardware solutions have dedicated
290912bd3c8bSSascha Wildner 			 * events when it is safe to free DMA'ed
291012bd3c8bSSascha Wildner 			 * memory. For the other hardware platforms we
291112bd3c8bSSascha Wildner 			 * use a static delay.
291212bd3c8bSSascha Wildner 			 */
291312bd3c8bSSascha Wildner 			if (bus->methods->start_dma_delay != NULL) {
291412bd3c8bSSascha Wildner 				(bus->methods->start_dma_delay) (xfer);
291512bd3c8bSSascha Wildner 			} else {
291612bd3c8bSSascha Wildner 				usbd_transfer_timeout_ms(xfer,
29175e41ab93SMarkus Pfeiffer 				    (void (*)(void *))&usb_dma_delay_done_cb,
29185e41ab93SMarkus Pfeiffer 				    temp);
291912bd3c8bSSascha Wildner 			}
292012bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(bus);
292112bd3c8bSSascha Wildner 			return (1);	/* wait for new callback */
292212bd3c8bSSascha Wildner 		}
292312bd3c8bSSascha Wildner 	}
292412bd3c8bSSascha Wildner 	/* check actual number of frames */
292512bd3c8bSSascha Wildner 	if (xfer->aframes > xfer->nframes) {
292612bd3c8bSSascha Wildner 		if (xfer->error == 0) {
292712bd3c8bSSascha Wildner 			panic("%s: actual number of frames, %d, is "
292812bd3c8bSSascha Wildner 			    "greater than initial number of frames, %d\n",
29297fd4e1a1SSascha Wildner 			    __func__, xfer->aframes, xfer->nframes);
293012bd3c8bSSascha Wildner 		} else {
293112bd3c8bSSascha Wildner 			/* just set some valid value */
293212bd3c8bSSascha Wildner 			xfer->aframes = xfer->nframes;
293312bd3c8bSSascha Wildner 		}
293412bd3c8bSSascha Wildner 	}
293512bd3c8bSSascha Wildner 	/* compute actual length */
293612bd3c8bSSascha Wildner 	xfer->actlen = 0;
293712bd3c8bSSascha Wildner 
293812bd3c8bSSascha Wildner 	for (x = 0; x != xfer->aframes; x++) {
293912bd3c8bSSascha Wildner 		xfer->actlen += xfer->frlengths[x];
294012bd3c8bSSascha Wildner 	}
294112bd3c8bSSascha Wildner 
294212bd3c8bSSascha Wildner 	/*
294312bd3c8bSSascha Wildner 	 * Frames that were not transferred get zero actual length in
294412bd3c8bSSascha Wildner 	 * case the USB device driver does not check the actual number
294512bd3c8bSSascha Wildner 	 * of frames transferred, "xfer->aframes":
294612bd3c8bSSascha Wildner 	 */
294712bd3c8bSSascha Wildner 	for (; x < xfer->nframes; x++) {
294812bd3c8bSSascha Wildner 		usbd_xfer_set_frame_len(xfer, x, 0);
294912bd3c8bSSascha Wildner 	}
295012bd3c8bSSascha Wildner 
295112bd3c8bSSascha Wildner 	/* check actual length */
295212bd3c8bSSascha Wildner 	if (xfer->actlen > xfer->sumlen) {
295312bd3c8bSSascha Wildner 		if (xfer->error == 0) {
295412bd3c8bSSascha Wildner 			panic("%s: actual length, %d, is greater than "
295512bd3c8bSSascha Wildner 			    "initial length, %d\n",
29567fd4e1a1SSascha Wildner 			    __func__, xfer->actlen, xfer->sumlen);
295712bd3c8bSSascha Wildner 		} else {
295812bd3c8bSSascha Wildner 			/* just set some valid value */
295912bd3c8bSSascha Wildner 			xfer->actlen = xfer->sumlen;
296012bd3c8bSSascha Wildner 		}
296112bd3c8bSSascha Wildner 	}
296212bd3c8bSSascha Wildner 	DPRINTFN(1, "xfer=%p endpoint=%p sts=%d alen=%d, slen=%d, afrm=%d, nfrm=%d\n",
296312bd3c8bSSascha Wildner 	    xfer, xfer->endpoint, xfer->error, xfer->actlen, xfer->sumlen,
296412bd3c8bSSascha Wildner 	    xfer->aframes, xfer->nframes);
296512bd3c8bSSascha Wildner 
296612bd3c8bSSascha Wildner 	if (xfer->error) {
296712bd3c8bSSascha Wildner 		/* end of control transfer, if any */
296812bd3c8bSSascha Wildner 		xfer->flags_int.control_act = 0;
296912bd3c8bSSascha Wildner 
297012bd3c8bSSascha Wildner 		/* check if we should block the execution queue */
297112bd3c8bSSascha Wildner 		if ((xfer->error != USB_ERR_CANCELLED) &&
297212bd3c8bSSascha Wildner 		    (xfer->flags.pipe_bof)) {
297312bd3c8bSSascha Wildner 			DPRINTFN(2, "xfer=%p: Block On Failure "
297412bd3c8bSSascha Wildner 			    "on endpoint=%p\n", xfer, xfer->endpoint);
297512bd3c8bSSascha Wildner 			goto done;
297612bd3c8bSSascha Wildner 		}
297712bd3c8bSSascha Wildner 	} else {
297812bd3c8bSSascha Wildner 		/* check for short transfers */
297912bd3c8bSSascha Wildner 		if (xfer->actlen < xfer->sumlen) {
298012bd3c8bSSascha Wildner 
298112bd3c8bSSascha Wildner 			/* end of control transfer, if any */
298212bd3c8bSSascha Wildner 			xfer->flags_int.control_act = 0;
298312bd3c8bSSascha Wildner 
298412bd3c8bSSascha Wildner 			if (!xfer->flags_int.short_xfer_ok) {
298512bd3c8bSSascha Wildner 				xfer->error = USB_ERR_SHORT_XFER;
298612bd3c8bSSascha Wildner 				if (xfer->flags.pipe_bof) {
298712bd3c8bSSascha Wildner 					DPRINTFN(2, "xfer=%p: Block On Failure on "
298812bd3c8bSSascha Wildner 					    "Short Transfer on endpoint %p.\n",
298912bd3c8bSSascha Wildner 					    xfer, xfer->endpoint);
299012bd3c8bSSascha Wildner 					goto done;
299112bd3c8bSSascha Wildner 				}
299212bd3c8bSSascha Wildner 			}
299312bd3c8bSSascha Wildner 		} else {
299412bd3c8bSSascha Wildner 			/*
299512bd3c8bSSascha Wildner 			 * Check if we are in the middle of a
299612bd3c8bSSascha Wildner 			 * control transfer:
299712bd3c8bSSascha Wildner 			 */
299812bd3c8bSSascha Wildner 			if (xfer->flags_int.control_act) {
299912bd3c8bSSascha Wildner 				DPRINTFN(5, "xfer=%p: Control transfer "
300012bd3c8bSSascha Wildner 				    "active on endpoint=%p\n", xfer, xfer->endpoint);
300112bd3c8bSSascha Wildner 				goto done;
300212bd3c8bSSascha Wildner 			}
300312bd3c8bSSascha Wildner 		}
300412bd3c8bSSascha Wildner 	}
300512bd3c8bSSascha Wildner 
300612bd3c8bSSascha Wildner 	ep = xfer->endpoint;
300712bd3c8bSSascha Wildner 
300812bd3c8bSSascha Wildner 	/*
300912bd3c8bSSascha Wildner 	 * If the current USB transfer is completing we need to start the
301012bd3c8bSSascha Wildner 	 * next one:
301112bd3c8bSSascha Wildner 	 */
301212bd3c8bSSascha Wildner 	USB_BUS_LOCK(bus);
30135e41ab93SMarkus Pfeiffer 	if (ep->endpoint_q[xfer->stream_id].curr == xfer) {
30145e41ab93SMarkus Pfeiffer 		usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], NULL);
301512bd3c8bSSascha Wildner 
301657bed822SMarkus Pfeiffer 		if (ep->endpoint_q[xfer->stream_id].curr != NULL ||
30175e41ab93SMarkus Pfeiffer 		    TAILQ_FIRST(&ep->endpoint_q[xfer->stream_id].head) != NULL) {
301812bd3c8bSSascha Wildner 			/* there is another USB transfer waiting */
301912bd3c8bSSascha Wildner 		} else {
302012bd3c8bSSascha Wildner 			/* this is the last USB transfer */
302112bd3c8bSSascha Wildner 			/* clear isochronous sync flag */
302212bd3c8bSSascha Wildner 			xfer->endpoint->is_synced = 0;
302312bd3c8bSSascha Wildner 		}
302412bd3c8bSSascha Wildner 	}
302512bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(bus);
302612bd3c8bSSascha Wildner done:
302712bd3c8bSSascha Wildner 	return (0);
302812bd3c8bSSascha Wildner }
302912bd3c8bSSascha Wildner 
303012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
303112bd3c8bSSascha Wildner  *	usb_command_wrapper
303212bd3c8bSSascha Wildner  *
303312bd3c8bSSascha Wildner  * This function is used to execute commands non-recursivly on an USB
303412bd3c8bSSascha Wildner  * transfer.
303512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
303612bd3c8bSSascha Wildner void
usb_command_wrapper(struct usb_xfer_queue * pq,struct usb_xfer * xfer)303712bd3c8bSSascha Wildner usb_command_wrapper(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
303812bd3c8bSSascha Wildner {
303912bd3c8bSSascha Wildner 	if (xfer) {
304012bd3c8bSSascha Wildner 		/*
304112bd3c8bSSascha Wildner 		 * If the transfer is not already processing,
304212bd3c8bSSascha Wildner 		 * queue it!
304312bd3c8bSSascha Wildner 		 */
304412bd3c8bSSascha Wildner 		if (pq->curr != xfer) {
304512bd3c8bSSascha Wildner 			usbd_transfer_enqueue(pq, xfer);
304612bd3c8bSSascha Wildner 			if (pq->curr != NULL) {
304712bd3c8bSSascha Wildner 				/* something is already processing */
304812bd3c8bSSascha Wildner 				DPRINTFN(6, "busy %p\n", pq->curr);
304912bd3c8bSSascha Wildner 				return;
305012bd3c8bSSascha Wildner 			}
305112bd3c8bSSascha Wildner 		}
305212bd3c8bSSascha Wildner 	} else {
305312bd3c8bSSascha Wildner 		/* Get next element in queue */
305412bd3c8bSSascha Wildner 		pq->curr = NULL;
305512bd3c8bSSascha Wildner 	}
305612bd3c8bSSascha Wildner 
305712bd3c8bSSascha Wildner 	if (!pq->recurse_1) {
305812bd3c8bSSascha Wildner 
305912bd3c8bSSascha Wildner 		do {
306012bd3c8bSSascha Wildner 
306112bd3c8bSSascha Wildner 			/* set both recurse flags */
306212bd3c8bSSascha Wildner 			pq->recurse_1 = 1;
306312bd3c8bSSascha Wildner 			pq->recurse_2 = 1;
306412bd3c8bSSascha Wildner 
306512bd3c8bSSascha Wildner 			if (pq->curr == NULL) {
306612bd3c8bSSascha Wildner 				xfer = TAILQ_FIRST(&pq->head);
306712bd3c8bSSascha Wildner 				if (xfer) {
306812bd3c8bSSascha Wildner 					TAILQ_REMOVE(&pq->head, xfer,
306912bd3c8bSSascha Wildner 					    wait_entry);
307012bd3c8bSSascha Wildner 					xfer->wait_queue = NULL;
307112bd3c8bSSascha Wildner 					pq->curr = xfer;
307212bd3c8bSSascha Wildner 				} else {
307312bd3c8bSSascha Wildner 					break;
307412bd3c8bSSascha Wildner 				}
307512bd3c8bSSascha Wildner 			}
307612bd3c8bSSascha Wildner 			DPRINTFN(6, "cb %p (enter)\n", pq->curr);
307712bd3c8bSSascha Wildner 			(pq->command) (pq);
307812bd3c8bSSascha Wildner 			DPRINTFN(6, "cb %p (leave)\n", pq->curr);
307912bd3c8bSSascha Wildner 
308012bd3c8bSSascha Wildner 		} while (!pq->recurse_2);
308112bd3c8bSSascha Wildner 
308212bd3c8bSSascha Wildner 		/* clear first recurse flag */
308312bd3c8bSSascha Wildner 		pq->recurse_1 = 0;
308412bd3c8bSSascha Wildner 
308512bd3c8bSSascha Wildner 	} else {
308612bd3c8bSSascha Wildner 		/* clear second recurse flag */
308712bd3c8bSSascha Wildner 		pq->recurse_2 = 0;
308812bd3c8bSSascha Wildner 	}
308912bd3c8bSSascha Wildner }
309012bd3c8bSSascha Wildner 
309112bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
309212bd3c8bSSascha Wildner  *	usbd_ctrl_transfer_setup
309312bd3c8bSSascha Wildner  *
309412bd3c8bSSascha Wildner  * This function is used to setup the default USB control endpoint
309512bd3c8bSSascha Wildner  * transfer.
309612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
309712bd3c8bSSascha Wildner void
usbd_ctrl_transfer_setup(struct usb_device * udev)309812bd3c8bSSascha Wildner usbd_ctrl_transfer_setup(struct usb_device *udev)
309912bd3c8bSSascha Wildner {
310012bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
310112bd3c8bSSascha Wildner 	uint8_t no_resetup;
310212bd3c8bSSascha Wildner 	uint8_t iface_index;
310312bd3c8bSSascha Wildner 
310412bd3c8bSSascha Wildner 	/* check for root HUB */
310512bd3c8bSSascha Wildner 	if (udev->parent_hub == NULL)
310612bd3c8bSSascha Wildner 		return;
310712bd3c8bSSascha Wildner repeat:
310812bd3c8bSSascha Wildner 
310912bd3c8bSSascha Wildner 	xfer = udev->ctrl_xfer[0];
311012bd3c8bSSascha Wildner 	if (xfer) {
311112bd3c8bSSascha Wildner 		USB_XFER_LOCK(xfer);
311212bd3c8bSSascha Wildner 		no_resetup =
311312bd3c8bSSascha Wildner 		    ((xfer->address == udev->address) &&
311412bd3c8bSSascha Wildner 		    (udev->ctrl_ep_desc.wMaxPacketSize[0] ==
311512bd3c8bSSascha Wildner 		    udev->ddesc.bMaxPacketSize));
311612bd3c8bSSascha Wildner 		if (udev->flags.usb_mode == USB_MODE_DEVICE) {
311712bd3c8bSSascha Wildner 			if (no_resetup) {
311812bd3c8bSSascha Wildner 				/*
311912bd3c8bSSascha Wildner 				 * NOTE: checking "xfer->address" and
312012bd3c8bSSascha Wildner 				 * starting the USB transfer must be
312112bd3c8bSSascha Wildner 				 * atomic!
312212bd3c8bSSascha Wildner 				 */
312312bd3c8bSSascha Wildner 				usbd_transfer_start(xfer);
312412bd3c8bSSascha Wildner 			}
312512bd3c8bSSascha Wildner 		}
312612bd3c8bSSascha Wildner 		USB_XFER_UNLOCK(xfer);
312712bd3c8bSSascha Wildner 	} else {
312812bd3c8bSSascha Wildner 		no_resetup = 0;
312912bd3c8bSSascha Wildner 	}
313012bd3c8bSSascha Wildner 
313112bd3c8bSSascha Wildner 	if (no_resetup) {
313212bd3c8bSSascha Wildner 		/*
313312bd3c8bSSascha Wildner 	         * All parameters are exactly the same like before.
313412bd3c8bSSascha Wildner 	         * Just return.
313512bd3c8bSSascha Wildner 	         */
313612bd3c8bSSascha Wildner 		return;
313712bd3c8bSSascha Wildner 	}
313812bd3c8bSSascha Wildner 	/*
313912bd3c8bSSascha Wildner 	 * Update wMaxPacketSize for the default control endpoint:
314012bd3c8bSSascha Wildner 	 */
314112bd3c8bSSascha Wildner 	udev->ctrl_ep_desc.wMaxPacketSize[0] =
314212bd3c8bSSascha Wildner 	    udev->ddesc.bMaxPacketSize;
314312bd3c8bSSascha Wildner 
314412bd3c8bSSascha Wildner 	/*
314512bd3c8bSSascha Wildner 	 * Unsetup any existing USB transfer:
314612bd3c8bSSascha Wildner 	 */
314712bd3c8bSSascha Wildner 	usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX);
314812bd3c8bSSascha Wildner 
314912bd3c8bSSascha Wildner 	/*
315012bd3c8bSSascha Wildner 	 * Reset clear stall error counter.
315112bd3c8bSSascha Wildner 	 */
315212bd3c8bSSascha Wildner 	udev->clear_stall_errors = 0;
315312bd3c8bSSascha Wildner 
315412bd3c8bSSascha Wildner 	/*
315512bd3c8bSSascha Wildner 	 * Try to setup a new USB transfer for the
315612bd3c8bSSascha Wildner 	 * default control endpoint:
315712bd3c8bSSascha Wildner 	 */
315812bd3c8bSSascha Wildner 	iface_index = 0;
315912bd3c8bSSascha Wildner 	if (usbd_transfer_setup(udev, &iface_index,
316012bd3c8bSSascha Wildner 	    udev->ctrl_xfer, usb_control_ep_cfg, USB_CTRL_XFER_MAX, NULL,
3161722d05c3SSascha Wildner 	    &udev->device_lock)) {
316212bd3c8bSSascha Wildner 		DPRINTFN(0, "could not setup default "
316312bd3c8bSSascha Wildner 		    "USB transfer\n");
316412bd3c8bSSascha Wildner 	} else {
316512bd3c8bSSascha Wildner 		goto repeat;
316612bd3c8bSSascha Wildner 	}
316712bd3c8bSSascha Wildner }
316812bd3c8bSSascha Wildner 
316912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
317012bd3c8bSSascha Wildner  *	usbd_clear_data_toggle - factored out code
317112bd3c8bSSascha Wildner  *
317212bd3c8bSSascha Wildner  * NOTE: the intention of this function is not to reset the hardware
317312bd3c8bSSascha Wildner  * data toggle.
317412bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
317512bd3c8bSSascha Wildner void
usbd_clear_stall_locked(struct usb_device * udev,struct usb_endpoint * ep)317612bd3c8bSSascha Wildner usbd_clear_stall_locked(struct usb_device *udev, struct usb_endpoint *ep)
317712bd3c8bSSascha Wildner {
3178722d05c3SSascha Wildner 	USB_BUS_LOCK_ASSERT(udev->bus);
317912bd3c8bSSascha Wildner 
318012bd3c8bSSascha Wildner 	/* check that we have a valid case */
318112bd3c8bSSascha Wildner 	if (udev->flags.usb_mode == USB_MODE_HOST &&
318212bd3c8bSSascha Wildner 	    udev->parent_hub != NULL &&
318312bd3c8bSSascha Wildner 	    udev->bus->methods->clear_stall != NULL &&
318412bd3c8bSSascha Wildner 	    ep->methods != NULL) {
318512bd3c8bSSascha Wildner 		(udev->bus->methods->clear_stall) (udev, ep);
318612bd3c8bSSascha Wildner 	}
318712bd3c8bSSascha Wildner }
318812bd3c8bSSascha Wildner 
318912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
319012bd3c8bSSascha Wildner  *	usbd_clear_data_toggle - factored out code
319112bd3c8bSSascha Wildner  *
319212bd3c8bSSascha Wildner  * NOTE: the intention of this function is not to reset the hardware
319312bd3c8bSSascha Wildner  * data toggle on the USB device side.
319412bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
319512bd3c8bSSascha Wildner void
usbd_clear_data_toggle(struct usb_device * udev,struct usb_endpoint * ep)319612bd3c8bSSascha Wildner usbd_clear_data_toggle(struct usb_device *udev, struct usb_endpoint *ep)
319712bd3c8bSSascha Wildner {
319812bd3c8bSSascha Wildner 	DPRINTFN(5, "udev=%p endpoint=%p\n", udev, ep);
319912bd3c8bSSascha Wildner 
320012bd3c8bSSascha Wildner 	USB_BUS_LOCK(udev->bus);
320112bd3c8bSSascha Wildner 	ep->toggle_next = 0;
320212bd3c8bSSascha Wildner 	/* some hardware needs a callback to clear the data toggle */
320312bd3c8bSSascha Wildner 	usbd_clear_stall_locked(udev, ep);
320412bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(udev->bus);
320512bd3c8bSSascha Wildner }
320612bd3c8bSSascha Wildner 
320712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
320812bd3c8bSSascha Wildner  *	usbd_clear_stall_callback - factored out clear stall callback
320912bd3c8bSSascha Wildner  *
321012bd3c8bSSascha Wildner  * Input parameters:
321112bd3c8bSSascha Wildner  *  xfer1: Clear Stall Control Transfer
321212bd3c8bSSascha Wildner  *  xfer2: Stalled USB Transfer
321312bd3c8bSSascha Wildner  *
321412bd3c8bSSascha Wildner  * This function is NULL safe.
321512bd3c8bSSascha Wildner  *
321612bd3c8bSSascha Wildner  * Return values:
321712bd3c8bSSascha Wildner  *   0: In progress
321812bd3c8bSSascha Wildner  *   Else: Finished
321912bd3c8bSSascha Wildner  *
322012bd3c8bSSascha Wildner  * Clear stall config example:
322112bd3c8bSSascha Wildner  *
322212bd3c8bSSascha Wildner  * static const struct usb_config my_clearstall =  {
322312bd3c8bSSascha Wildner  *	.type = UE_CONTROL,
322412bd3c8bSSascha Wildner  *	.endpoint = 0,
322512bd3c8bSSascha Wildner  *	.direction = UE_DIR_ANY,
322612bd3c8bSSascha Wildner  *	.interval = 50, //50 milliseconds
322712bd3c8bSSascha Wildner  *	.bufsize = sizeof(struct usb_device_request),
322812bd3c8bSSascha Wildner  *	.timeout = 1000, //1.000 seconds
322912bd3c8bSSascha Wildner  *	.callback = &my_clear_stall_callback, // **
323012bd3c8bSSascha Wildner  *	.usb_mode = USB_MODE_HOST,
323112bd3c8bSSascha Wildner  * };
323212bd3c8bSSascha Wildner  *
323312bd3c8bSSascha Wildner  * ** "my_clear_stall_callback" calls "usbd_clear_stall_callback"
323412bd3c8bSSascha Wildner  * passing the correct parameters.
323512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
323612bd3c8bSSascha Wildner uint8_t
usbd_clear_stall_callback(struct usb_xfer * xfer1,struct usb_xfer * xfer2)323712bd3c8bSSascha Wildner usbd_clear_stall_callback(struct usb_xfer *xfer1,
323812bd3c8bSSascha Wildner     struct usb_xfer *xfer2)
323912bd3c8bSSascha Wildner {
324012bd3c8bSSascha Wildner 	struct usb_device_request req;
324112bd3c8bSSascha Wildner 
324212bd3c8bSSascha Wildner 	if (xfer2 == NULL) {
324312bd3c8bSSascha Wildner 		/* looks like we are tearing down */
324412bd3c8bSSascha Wildner 		DPRINTF("NULL input parameter\n");
324512bd3c8bSSascha Wildner 		return (0);
324612bd3c8bSSascha Wildner 	}
3247722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer1);
3248722d05c3SSascha Wildner 	USB_XFER_LOCK_ASSERT(xfer2);
324912bd3c8bSSascha Wildner 
325012bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer1)) {
325112bd3c8bSSascha Wildner 	case USB_ST_SETUP:
325212bd3c8bSSascha Wildner 
325312bd3c8bSSascha Wildner 		/*
325412bd3c8bSSascha Wildner 		 * pre-clear the data toggle to DATA0 ("umass.c" and
325512bd3c8bSSascha Wildner 		 * "ata-usb.c" depends on this)
325612bd3c8bSSascha Wildner 		 */
325712bd3c8bSSascha Wildner 
325812bd3c8bSSascha Wildner 		usbd_clear_data_toggle(xfer2->xroot->udev, xfer2->endpoint);
325912bd3c8bSSascha Wildner 
326012bd3c8bSSascha Wildner 		/* setup a clear-stall packet */
326112bd3c8bSSascha Wildner 
326212bd3c8bSSascha Wildner 		req.bmRequestType = UT_WRITE_ENDPOINT;
326312bd3c8bSSascha Wildner 		req.bRequest = UR_CLEAR_FEATURE;
326412bd3c8bSSascha Wildner 		USETW(req.wValue, UF_ENDPOINT_HALT);
326512bd3c8bSSascha Wildner 		req.wIndex[0] = xfer2->endpoint->edesc->bEndpointAddress;
326612bd3c8bSSascha Wildner 		req.wIndex[1] = 0;
326712bd3c8bSSascha Wildner 		USETW(req.wLength, 0);
326812bd3c8bSSascha Wildner 
326912bd3c8bSSascha Wildner 		/*
327012bd3c8bSSascha Wildner 		 * "usbd_transfer_setup_sub()" will ensure that
327112bd3c8bSSascha Wildner 		 * we have sufficient room in the buffer for
327212bd3c8bSSascha Wildner 		 * the request structure!
327312bd3c8bSSascha Wildner 		 */
327412bd3c8bSSascha Wildner 
327512bd3c8bSSascha Wildner 		/* copy in the transfer */
327612bd3c8bSSascha Wildner 
327712bd3c8bSSascha Wildner 		usbd_copy_in(xfer1->frbuffers, 0, &req, sizeof(req));
327812bd3c8bSSascha Wildner 
327912bd3c8bSSascha Wildner 		/* set length */
328012bd3c8bSSascha Wildner 		xfer1->frlengths[0] = sizeof(req);
328112bd3c8bSSascha Wildner 		xfer1->nframes = 1;
328212bd3c8bSSascha Wildner 
328312bd3c8bSSascha Wildner 		usbd_transfer_submit(xfer1);
328412bd3c8bSSascha Wildner 		return (0);
328512bd3c8bSSascha Wildner 
328612bd3c8bSSascha Wildner 	case USB_ST_TRANSFERRED:
328712bd3c8bSSascha Wildner 		break;
328812bd3c8bSSascha Wildner 
328912bd3c8bSSascha Wildner 	default:			/* Error */
329012bd3c8bSSascha Wildner 		if (xfer1->error == USB_ERR_CANCELLED) {
329112bd3c8bSSascha Wildner 			return (0);
329212bd3c8bSSascha Wildner 		}
329312bd3c8bSSascha Wildner 		break;
329412bd3c8bSSascha Wildner 	}
329512bd3c8bSSascha Wildner 	return (1);			/* Clear Stall Finished */
329612bd3c8bSSascha Wildner }
329712bd3c8bSSascha Wildner 
329812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
329912bd3c8bSSascha Wildner  *	usbd_transfer_poll
330012bd3c8bSSascha Wildner  *
330112bd3c8bSSascha Wildner  * The following function gets called from the USB keyboard driver and
330212bd3c8bSSascha Wildner  * UMASS when the system has paniced.
330312bd3c8bSSascha Wildner  *
330412bd3c8bSSascha Wildner  * NOTE: It is currently not possible to resume normal operation on
330512bd3c8bSSascha Wildner  * the USB controller which has been polled, due to clearing of the
330612bd3c8bSSascha Wildner  * "up_dsleep" and "up_msleep" flags.
330712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
330812bd3c8bSSascha Wildner void
usbd_transfer_poll(struct usb_xfer ** ppxfer,uint16_t max)330912bd3c8bSSascha Wildner usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max)
331012bd3c8bSSascha Wildner {
331112bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
331212bd3c8bSSascha Wildner 	struct usb_xfer_root *xroot;
331312bd3c8bSSascha Wildner 	struct usb_device *udev;
331412bd3c8bSSascha Wildner 	struct usb_proc_msg *pm;
331512bd3c8bSSascha Wildner 	uint16_t n;
331612bd3c8bSSascha Wildner 	uint16_t drop_bus;
331712bd3c8bSSascha Wildner 	uint16_t drop_xfer;
331812bd3c8bSSascha Wildner 
331912bd3c8bSSascha Wildner 	for (n = 0; n != max; n++) {
332012bd3c8bSSascha Wildner 		/* Extra checks to avoid panic */
332112bd3c8bSSascha Wildner 		xfer = ppxfer[n];
332212bd3c8bSSascha Wildner 		if (xfer == NULL)
332312bd3c8bSSascha Wildner 			continue;	/* no USB transfer */
332412bd3c8bSSascha Wildner 		xroot = xfer->xroot;
332512bd3c8bSSascha Wildner 		if (xroot == NULL)
332612bd3c8bSSascha Wildner 			continue;	/* no USB root */
332712bd3c8bSSascha Wildner 		udev = xroot->udev;
332812bd3c8bSSascha Wildner 		if (udev == NULL)
332912bd3c8bSSascha Wildner 			continue;	/* no USB device */
333012bd3c8bSSascha Wildner 		if (udev->bus == NULL)
333112bd3c8bSSascha Wildner 			continue;	/* no BUS structure */
333212bd3c8bSSascha Wildner 		if (udev->bus->methods == NULL)
333312bd3c8bSSascha Wildner 			continue;	/* no BUS methods */
333412bd3c8bSSascha Wildner 		if (udev->bus->methods->xfer_poll == NULL)
333512bd3c8bSSascha Wildner 			continue;	/* no poll method */
333612bd3c8bSSascha Wildner 
333712bd3c8bSSascha Wildner 		/* make sure that the BUS mutex is not locked */
333812bd3c8bSSascha Wildner 		drop_bus = 0;
33393a76bbe8SSascha Wildner 		while (lockowned(&xroot->udev->bus->bus_lock)) {
3340722d05c3SSascha Wildner 			lockmgr(&xroot->udev->bus->bus_lock, LK_RELEASE);
334112bd3c8bSSascha Wildner 			drop_bus++;
334212bd3c8bSSascha Wildner 		}
334312bd3c8bSSascha Wildner 
334412bd3c8bSSascha Wildner 		/* make sure that the transfer mutex is not locked */
334512bd3c8bSSascha Wildner 		drop_xfer = 0;
33463a76bbe8SSascha Wildner 		while (lockowned(xroot->xfer_lock)) {
3347722d05c3SSascha Wildner 			lockmgr(xroot->xfer_lock, LK_RELEASE);
334812bd3c8bSSascha Wildner 			drop_xfer++;
334912bd3c8bSSascha Wildner 		}
335012bd3c8bSSascha Wildner 
335112bd3c8bSSascha Wildner 		/* Make sure cv_signal() and cv_broadcast() is not called */
335257bed822SMarkus Pfeiffer 		USB_BUS_CONTROL_XFER_PROC(udev->bus)->up_msleep = 0;
335357bed822SMarkus Pfeiffer 		USB_BUS_EXPLORE_PROC(udev->bus)->up_msleep = 0;
335457bed822SMarkus Pfeiffer 		USB_BUS_GIANT_PROC(udev->bus)->up_msleep = 0;
335557bed822SMarkus Pfeiffer 		USB_BUS_NON_GIANT_PROC(udev->bus)->up_msleep = 0;
335612bd3c8bSSascha Wildner 
335712bd3c8bSSascha Wildner 		/* poll USB hardware */
335812bd3c8bSSascha Wildner 		(udev->bus->methods->xfer_poll) (udev->bus);
335912bd3c8bSSascha Wildner 
336012bd3c8bSSascha Wildner 		USB_BUS_LOCK(xroot->bus);
336112bd3c8bSSascha Wildner 
336212bd3c8bSSascha Wildner 		/* check for clear stall */
336312bd3c8bSSascha Wildner 		if (udev->ctrl_xfer[1] != NULL) {
336412bd3c8bSSascha Wildner 
336512bd3c8bSSascha Wildner 			/* poll clear stall start */
336612bd3c8bSSascha Wildner 			pm = &udev->cs_msg[0].hdr;
336712bd3c8bSSascha Wildner 			(pm->pm_callback) (pm);
336812bd3c8bSSascha Wildner 			/* poll clear stall done thread */
336912bd3c8bSSascha Wildner 			pm = &udev->ctrl_xfer[1]->
337012bd3c8bSSascha Wildner 			    xroot->done_m[0].hdr;
337112bd3c8bSSascha Wildner 			(pm->pm_callback) (pm);
337212bd3c8bSSascha Wildner 		}
337312bd3c8bSSascha Wildner 
337412bd3c8bSSascha Wildner 		/* poll done thread */
337512bd3c8bSSascha Wildner 		pm = &xroot->done_m[0].hdr;
337612bd3c8bSSascha Wildner 		(pm->pm_callback) (pm);
337712bd3c8bSSascha Wildner 
337812bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(xroot->bus);
337912bd3c8bSSascha Wildner 
338012bd3c8bSSascha Wildner 		/* restore transfer mutex */
338112bd3c8bSSascha Wildner 		while (drop_xfer--)
3382722d05c3SSascha Wildner 			lockmgr(xroot->xfer_lock, LK_EXCLUSIVE);
338312bd3c8bSSascha Wildner 
338412bd3c8bSSascha Wildner 		/* restore BUS mutex */
338512bd3c8bSSascha Wildner 		while (drop_bus--)
3386722d05c3SSascha Wildner 			lockmgr(&xroot->udev->bus->bus_lock, LK_EXCLUSIVE);
338712bd3c8bSSascha Wildner 	}
338812bd3c8bSSascha Wildner }
338912bd3c8bSSascha Wildner 
339012bd3c8bSSascha Wildner static void
usbd_get_std_packet_size(struct usb_std_packet_size * ptr,uint8_t type,enum usb_dev_speed speed)339112bd3c8bSSascha Wildner usbd_get_std_packet_size(struct usb_std_packet_size *ptr,
339212bd3c8bSSascha Wildner     uint8_t type, enum usb_dev_speed speed)
339312bd3c8bSSascha Wildner {
339412bd3c8bSSascha Wildner 	static const uint16_t intr_range_max[USB_SPEED_MAX] = {
339512bd3c8bSSascha Wildner 		[USB_SPEED_LOW] = 8,
339612bd3c8bSSascha Wildner 		[USB_SPEED_FULL] = 64,
339712bd3c8bSSascha Wildner 		[USB_SPEED_HIGH] = 1024,
339812bd3c8bSSascha Wildner 		[USB_SPEED_VARIABLE] = 1024,
339912bd3c8bSSascha Wildner 		[USB_SPEED_SUPER] = 1024,
340012bd3c8bSSascha Wildner 	};
340112bd3c8bSSascha Wildner 
340212bd3c8bSSascha Wildner 	static const uint16_t isoc_range_max[USB_SPEED_MAX] = {
340312bd3c8bSSascha Wildner 		[USB_SPEED_LOW] = 0,	/* invalid */
340412bd3c8bSSascha Wildner 		[USB_SPEED_FULL] = 1023,
340512bd3c8bSSascha Wildner 		[USB_SPEED_HIGH] = 1024,
340612bd3c8bSSascha Wildner 		[USB_SPEED_VARIABLE] = 3584,
340712bd3c8bSSascha Wildner 		[USB_SPEED_SUPER] = 1024,
340812bd3c8bSSascha Wildner 	};
340912bd3c8bSSascha Wildner 
341012bd3c8bSSascha Wildner 	static const uint16_t control_min[USB_SPEED_MAX] = {
341112bd3c8bSSascha Wildner 		[USB_SPEED_LOW] = 8,
341212bd3c8bSSascha Wildner 		[USB_SPEED_FULL] = 8,
341312bd3c8bSSascha Wildner 		[USB_SPEED_HIGH] = 64,
341412bd3c8bSSascha Wildner 		[USB_SPEED_VARIABLE] = 512,
341512bd3c8bSSascha Wildner 		[USB_SPEED_SUPER] = 512,
341612bd3c8bSSascha Wildner 	};
341712bd3c8bSSascha Wildner 
341812bd3c8bSSascha Wildner 	static const uint16_t bulk_min[USB_SPEED_MAX] = {
341912bd3c8bSSascha Wildner 		[USB_SPEED_LOW] = 8,
342012bd3c8bSSascha Wildner 		[USB_SPEED_FULL] = 8,
342112bd3c8bSSascha Wildner 		[USB_SPEED_HIGH] = 512,
342212bd3c8bSSascha Wildner 		[USB_SPEED_VARIABLE] = 512,
342312bd3c8bSSascha Wildner 		[USB_SPEED_SUPER] = 1024,
342412bd3c8bSSascha Wildner 	};
342512bd3c8bSSascha Wildner 
342612bd3c8bSSascha Wildner 	uint16_t temp;
342712bd3c8bSSascha Wildner 
342812bd3c8bSSascha Wildner 	memset(ptr, 0, sizeof(*ptr));
342912bd3c8bSSascha Wildner 
343012bd3c8bSSascha Wildner 	switch (type) {
343112bd3c8bSSascha Wildner 	case UE_INTERRUPT:
343212bd3c8bSSascha Wildner 		ptr->range.max = intr_range_max[speed];
343312bd3c8bSSascha Wildner 		break;
343412bd3c8bSSascha Wildner 	case UE_ISOCHRONOUS:
343512bd3c8bSSascha Wildner 		ptr->range.max = isoc_range_max[speed];
343612bd3c8bSSascha Wildner 		break;
343712bd3c8bSSascha Wildner 	default:
343812bd3c8bSSascha Wildner 		if (type == UE_BULK)
343912bd3c8bSSascha Wildner 			temp = bulk_min[speed];
344012bd3c8bSSascha Wildner 		else /* UE_CONTROL */
344112bd3c8bSSascha Wildner 			temp = control_min[speed];
344212bd3c8bSSascha Wildner 
344312bd3c8bSSascha Wildner 		/* default is fixed */
344412bd3c8bSSascha Wildner 		ptr->fixed[0] = temp;
344512bd3c8bSSascha Wildner 		ptr->fixed[1] = temp;
344612bd3c8bSSascha Wildner 		ptr->fixed[2] = temp;
344712bd3c8bSSascha Wildner 		ptr->fixed[3] = temp;
344812bd3c8bSSascha Wildner 
344912bd3c8bSSascha Wildner 		if (speed == USB_SPEED_FULL) {
345012bd3c8bSSascha Wildner 			/* multiple sizes */
345112bd3c8bSSascha Wildner 			ptr->fixed[1] = 16;
345212bd3c8bSSascha Wildner 			ptr->fixed[2] = 32;
345312bd3c8bSSascha Wildner 			ptr->fixed[3] = 64;
345412bd3c8bSSascha Wildner 		}
345512bd3c8bSSascha Wildner 		if ((speed == USB_SPEED_VARIABLE) &&
345612bd3c8bSSascha Wildner 		    (type == UE_BULK)) {
345712bd3c8bSSascha Wildner 			/* multiple sizes */
345812bd3c8bSSascha Wildner 			ptr->fixed[2] = 1024;
345912bd3c8bSSascha Wildner 			ptr->fixed[3] = 1536;
346012bd3c8bSSascha Wildner 		}
346112bd3c8bSSascha Wildner 		break;
346212bd3c8bSSascha Wildner 	}
346312bd3c8bSSascha Wildner }
346412bd3c8bSSascha Wildner 
346512bd3c8bSSascha Wildner void	*
usbd_xfer_softc(struct usb_xfer * xfer)346612bd3c8bSSascha Wildner usbd_xfer_softc(struct usb_xfer *xfer)
346712bd3c8bSSascha Wildner {
346812bd3c8bSSascha Wildner 	return (xfer->priv_sc);
346912bd3c8bSSascha Wildner }
347012bd3c8bSSascha Wildner 
347112bd3c8bSSascha Wildner void *
usbd_xfer_get_priv(struct usb_xfer * xfer)347212bd3c8bSSascha Wildner usbd_xfer_get_priv(struct usb_xfer *xfer)
347312bd3c8bSSascha Wildner {
347412bd3c8bSSascha Wildner 	return (xfer->priv_fifo);
347512bd3c8bSSascha Wildner }
347612bd3c8bSSascha Wildner 
347712bd3c8bSSascha Wildner void
usbd_xfer_set_priv(struct usb_xfer * xfer,void * ptr)347812bd3c8bSSascha Wildner usbd_xfer_set_priv(struct usb_xfer *xfer, void *ptr)
347912bd3c8bSSascha Wildner {
348012bd3c8bSSascha Wildner 	xfer->priv_fifo = ptr;
348112bd3c8bSSascha Wildner }
348212bd3c8bSSascha Wildner 
348312bd3c8bSSascha Wildner uint8_t
usbd_xfer_state(struct usb_xfer * xfer)348412bd3c8bSSascha Wildner usbd_xfer_state(struct usb_xfer *xfer)
348512bd3c8bSSascha Wildner {
348612bd3c8bSSascha Wildner 	return (xfer->usb_state);
348712bd3c8bSSascha Wildner }
348812bd3c8bSSascha Wildner 
348912bd3c8bSSascha Wildner void
usbd_xfer_set_flag(struct usb_xfer * xfer,int flag)349012bd3c8bSSascha Wildner usbd_xfer_set_flag(struct usb_xfer *xfer, int flag)
349112bd3c8bSSascha Wildner {
349212bd3c8bSSascha Wildner 	switch (flag) {
349312bd3c8bSSascha Wildner 		case USB_FORCE_SHORT_XFER:
349412bd3c8bSSascha Wildner 			xfer->flags.force_short_xfer = 1;
349512bd3c8bSSascha Wildner 			break;
349612bd3c8bSSascha Wildner 		case USB_SHORT_XFER_OK:
349712bd3c8bSSascha Wildner 			xfer->flags.short_xfer_ok = 1;
349812bd3c8bSSascha Wildner 			break;
349912bd3c8bSSascha Wildner 		case USB_MULTI_SHORT_OK:
350012bd3c8bSSascha Wildner 			xfer->flags.short_frames_ok = 1;
350112bd3c8bSSascha Wildner 			break;
350212bd3c8bSSascha Wildner 		case USB_MANUAL_STATUS:
350312bd3c8bSSascha Wildner 			xfer->flags.manual_status = 1;
350412bd3c8bSSascha Wildner 			break;
350512bd3c8bSSascha Wildner 	}
350612bd3c8bSSascha Wildner }
350712bd3c8bSSascha Wildner 
350812bd3c8bSSascha Wildner void
usbd_xfer_clr_flag(struct usb_xfer * xfer,int flag)350912bd3c8bSSascha Wildner usbd_xfer_clr_flag(struct usb_xfer *xfer, int flag)
351012bd3c8bSSascha Wildner {
351112bd3c8bSSascha Wildner 	switch (flag) {
351212bd3c8bSSascha Wildner 		case USB_FORCE_SHORT_XFER:
351312bd3c8bSSascha Wildner 			xfer->flags.force_short_xfer = 0;
351412bd3c8bSSascha Wildner 			break;
351512bd3c8bSSascha Wildner 		case USB_SHORT_XFER_OK:
351612bd3c8bSSascha Wildner 			xfer->flags.short_xfer_ok = 0;
351712bd3c8bSSascha Wildner 			break;
351812bd3c8bSSascha Wildner 		case USB_MULTI_SHORT_OK:
351912bd3c8bSSascha Wildner 			xfer->flags.short_frames_ok = 0;
352012bd3c8bSSascha Wildner 			break;
352112bd3c8bSSascha Wildner 		case USB_MANUAL_STATUS:
352212bd3c8bSSascha Wildner 			xfer->flags.manual_status = 0;
352312bd3c8bSSascha Wildner 			break;
352412bd3c8bSSascha Wildner 	}
352512bd3c8bSSascha Wildner }
352612bd3c8bSSascha Wildner 
352712bd3c8bSSascha Wildner /*
352812bd3c8bSSascha Wildner  * The following function returns in milliseconds when the isochronous
352912bd3c8bSSascha Wildner  * transfer was completed by the hardware. The returned value wraps
353012bd3c8bSSascha Wildner  * around 65536 milliseconds.
353112bd3c8bSSascha Wildner  */
353212bd3c8bSSascha Wildner uint16_t
usbd_xfer_get_timestamp(struct usb_xfer * xfer)353312bd3c8bSSascha Wildner usbd_xfer_get_timestamp(struct usb_xfer *xfer)
353412bd3c8bSSascha Wildner {
353512bd3c8bSSascha Wildner 	return (xfer->isoc_time_complete);
353612bd3c8bSSascha Wildner }
353706cb2463SMarkus Pfeiffer 
353806cb2463SMarkus Pfeiffer /*
353906cb2463SMarkus Pfeiffer  * The following function returns non-zero if the max packet size
354006cb2463SMarkus Pfeiffer  * field was clamped to a valid value. Else it returns zero.
354106cb2463SMarkus Pfeiffer  */
354206cb2463SMarkus Pfeiffer uint8_t
usbd_xfer_maxp_was_clamped(struct usb_xfer * xfer)354306cb2463SMarkus Pfeiffer usbd_xfer_maxp_was_clamped(struct usb_xfer *xfer)
354406cb2463SMarkus Pfeiffer {
354506cb2463SMarkus Pfeiffer 	return (xfer->flags_int.maxp_was_clamped);
354606cb2463SMarkus Pfeiffer }
3547