1f9f848faSopenharmony_ci/*-
2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
3f9f848faSopenharmony_ci *
4f9f848faSopenharmony_ci * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
5f9f848faSopenharmony_ci *
6f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without
7f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions
8f9f848faSopenharmony_ci * are met:
9f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright
10f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer.
11f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
12f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
13f9f848faSopenharmony_ci *    documentation and/or other materials provided with the distribution.
14f9f848faSopenharmony_ci *
15f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f9f848faSopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25f9f848faSopenharmony_ci * SUCH DAMAGE.
26f9f848faSopenharmony_ci */
27f9f848faSopenharmony_ci
28f9f848faSopenharmony_ci#include "implementation/global_implementation.h"
29f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY
30f9f848faSopenharmony_ci#include "implementation/usb_btree.h"
31f9f848faSopenharmony_ci#endif
32f9f848faSopenharmony_ci
33f9f848faSopenharmony_ci/* function prototypes  */
34f9f848faSopenharmony_ci
35f9f848faSopenharmony_cistatic device_probe_t usb_probe;
36f9f848faSopenharmony_cistatic device_attach_t usb_attach;
37f9f848faSopenharmony_cistatic device_detach_t usb_detach;
38f9f848faSopenharmony_cistatic device_suspend_t usb_suspend;
39f9f848faSopenharmony_cistatic device_resume_t usb_resume;
40f9f848faSopenharmony_cistatic device_shutdown_t usb_shutdown;
41f9f848faSopenharmony_ci
42f9f848faSopenharmony_cistatic void	usb_attach_sub(device_t, struct usb_bus *);
43f9f848faSopenharmony_ci
44f9f848faSopenharmony_ci#undef	USB_DEBUG_VAR
45f9f848faSopenharmony_ci#define	USB_DEBUG_VAR   usb_ctrl_debug
46f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
47f9f848faSopenharmony_cistatic int usb_ctrl_debug = 0;
48f9f848faSopenharmony_civoid
49f9f848faSopenharmony_ciusb_controller_debug_func(int level)
50f9f848faSopenharmony_ci{
51f9f848faSopenharmony_ci	usb_ctrl_debug = level;
52f9f848faSopenharmony_ci	PRINTK("The level of usb controller debug is %d\n", level);
53f9f848faSopenharmony_ci}
54f9f848faSopenharmony_ciDEBUG_MODULE(controller, usb_controller_debug_func);
55f9f848faSopenharmony_ci#endif
56f9f848faSopenharmony_ci
57f9f848faSopenharmony_cistatic int usb_no_suspend_wait = 0;
58f9f848faSopenharmony_cistatic int usb_no_resume_wait = 0;
59f9f848faSopenharmony_cistatic int usb_no_shutdown_wait = 0;
60f9f848faSopenharmony_cistatic devclass_t usb_devclass;
61f9f848faSopenharmony_ci
62f9f848faSopenharmony_cistatic device_method_t usb_methods[] = {
63f9f848faSopenharmony_ci	DEVMETHOD(device_probe, usb_probe),
64f9f848faSopenharmony_ci	DEVMETHOD(device_attach, usb_attach),
65f9f848faSopenharmony_ci	DEVMETHOD(device_detach, usb_detach),
66f9f848faSopenharmony_ci	DEVMETHOD(device_suspend, usb_suspend),
67f9f848faSopenharmony_ci	DEVMETHOD(device_resume, usb_resume),
68f9f848faSopenharmony_ci	DEVMETHOD(device_shutdown, usb_shutdown),
69f9f848faSopenharmony_ci
70f9f848faSopenharmony_ci	DEVMETHOD_END
71f9f848faSopenharmony_ci};
72f9f848faSopenharmony_ci
73f9f848faSopenharmony_cistatic driver_t usb_driver = {
74f9f848faSopenharmony_ci	.name = "usbus",
75f9f848faSopenharmony_ci	.methods = usb_methods,
76f9f848faSopenharmony_ci	.size = 0,
77f9f848faSopenharmony_ci};
78f9f848faSopenharmony_ci
79f9f848faSopenharmony_ci/* Host Only Drivers */
80f9f848faSopenharmony_ciDRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0);
81f9f848faSopenharmony_ciDRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0);
82f9f848faSopenharmony_ci
83f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
84f9f848faSopenharmony_ci *	usb_probe
85f9f848faSopenharmony_ci *
86f9f848faSopenharmony_ci * This function is called from "{ehci,ohci,uhci}_pci_attach()".
87f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
88f9f848faSopenharmony_cistatic int
89f9f848faSopenharmony_ciusb_probe(device_t dev)
90f9f848faSopenharmony_ci{
91f9f848faSopenharmony_ci	DPRINTF("\n");
92f9f848faSopenharmony_ci	return (0);
93f9f848faSopenharmony_ci}
94f9f848faSopenharmony_ci
95f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
96f9f848faSopenharmony_cistatic void
97f9f848faSopenharmony_ciusb_root_mount_rel(struct usb_bus *bus)
98f9f848faSopenharmony_ci{
99f9f848faSopenharmony_ci	if (bus->bus_roothold != NULL) {
100f9f848faSopenharmony_ci		DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold);
101f9f848faSopenharmony_ci		root_mount_rel(bus->bus_roothold);
102f9f848faSopenharmony_ci		bus->bus_roothold = NULL;
103f9f848faSopenharmony_ci	}
104f9f848faSopenharmony_ci}
105f9f848faSopenharmony_ci#endif
106f9f848faSopenharmony_ci
107f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY
108f9f848faSopenharmony_ciusbd_bt_tree hub_tree;
109f9f848faSopenharmony_ci#endif
110f9f848faSopenharmony_ci
111f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
112f9f848faSopenharmony_ci *	usb_attach
113f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
114f9f848faSopenharmony_cistatic int
115f9f848faSopenharmony_ciusb_attach(device_t dev)
116f9f848faSopenharmony_ci{
117f9f848faSopenharmony_ci	struct usb_bus *bus = (struct usb_bus *)device_get_ivars(dev);
118f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY
119f9f848faSopenharmony_ci	struct node_info info;
120f9f848faSopenharmony_ci#endif
121f9f848faSopenharmony_ci	DPRINTF("\n");
122f9f848faSopenharmony_ci
123f9f848faSopenharmony_ci	if (bus == NULL) {
124f9f848faSopenharmony_ci		device_printf(dev, "USB device has no ivars\n");
125f9f848faSopenharmony_ci		return (ENXIO);
126f9f848faSopenharmony_ci	}
127f9f848faSopenharmony_ci
128f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
129f9f848faSopenharmony_ci	if (usb_no_boot_wait == 0) {
130f9f848faSopenharmony_ci		/* delay vfs_mountroot until the bus is explored */
131f9f848faSopenharmony_ci		bus->bus_roothold = root_mount_hold(device_get_nameunit(dev));
132f9f848faSopenharmony_ci	}
133f9f848faSopenharmony_ci#endif
134f9f848faSopenharmony_ci
135f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY
136f9f848faSopenharmony_ci	info.port_no = 0;
137f9f848faSopenharmony_ci	info.nameunit = device_get_nameunit(dev);
138f9f848faSopenharmony_ci	hub_tree = usbd_create_bt_node(&info);
139f9f848faSopenharmony_ci	if (hub_tree == NULL) {
140f9f848faSopenharmony_ci		PRINT_ERR("Root node create failed!\n");
141f9f848faSopenharmony_ci	}
142f9f848faSopenharmony_ci#endif
143f9f848faSopenharmony_ci	usb_attach_sub(dev, bus);
144f9f848faSopenharmony_ci	return (0);			/* return success */
145f9f848faSopenharmony_ci}
146f9f848faSopenharmony_ci
147f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
148f9f848faSopenharmony_ci *	usb_detach
149f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
150f9f848faSopenharmony_cistatic int
151f9f848faSopenharmony_ciusb_detach(device_t dev)
152f9f848faSopenharmony_ci{
153f9f848faSopenharmony_ci	struct usb_bus *bus = (struct usb_bus *)device_get_softc(dev);
154f9f848faSopenharmony_ci
155f9f848faSopenharmony_ci	DPRINTF("\n");
156f9f848faSopenharmony_ci
157f9f848faSopenharmony_ci	if (bus == NULL) {
158f9f848faSopenharmony_ci		/* was never setup properly */
159f9f848faSopenharmony_ci		return (0);
160f9f848faSopenharmony_ci	}
161f9f848faSopenharmony_ci	/* Stop power watchdog */
162f9f848faSopenharmony_ci	usb_callout_drain(&bus->power_wdog);
163f9f848faSopenharmony_ci
164f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
165f9f848faSopenharmony_ci	/* Let the USB explore process detach all devices. */
166f9f848faSopenharmony_ci	usb_root_mount_rel(bus);
167f9f848faSopenharmony_ci#endif
168f9f848faSopenharmony_ci
169f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
170f9f848faSopenharmony_ci
171f9f848faSopenharmony_ci	/* Queue detach job */
172f9f848faSopenharmony_ci	(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
173f9f848faSopenharmony_ci	    &bus->detach_msg[0], &bus->detach_msg[1]);
174f9f848faSopenharmony_ci
175f9f848faSopenharmony_ci	/* Wait for detach to complete */
176f9f848faSopenharmony_ci	usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus),
177f9f848faSopenharmony_ci	    &bus->detach_msg[0], &bus->detach_msg[1]);
178f9f848faSopenharmony_ci
179f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
180f9f848faSopenharmony_ci
181f9f848faSopenharmony_ci#if USB_HAVE_PER_BUS_PROCESS
182f9f848faSopenharmony_ci	/* Get rid of USB callback processes */
183f9f848faSopenharmony_ci
184f9f848faSopenharmony_ci	usb_proc_free(USB_BUS_GIANT_PROC(bus));
185f9f848faSopenharmony_ci	usb_proc_free(USB_BUS_NON_GIANT_ISOC_PROC(bus));
186f9f848faSopenharmony_ci	usb_proc_free(USB_BUS_NON_GIANT_BULK_PROC(bus));
187f9f848faSopenharmony_ci
188f9f848faSopenharmony_ci	/* Get rid of USB explore process */
189f9f848faSopenharmony_ci
190f9f848faSopenharmony_ci	usb_proc_free(USB_BUS_EXPLORE_PROC(bus));
191f9f848faSopenharmony_ci
192f9f848faSopenharmony_ci	/* Get rid of control transfer process */
193f9f848faSopenharmony_ci
194f9f848faSopenharmony_ci	usb_proc_free(USB_BUS_CONTROL_XFER_PROC(bus));
195f9f848faSopenharmony_ci#endif
196f9f848faSopenharmony_ci
197f9f848faSopenharmony_ci#if USB_HAVE_PF
198f9f848faSopenharmony_ci	usbpf_detach(bus);
199f9f848faSopenharmony_ci#endif
200f9f848faSopenharmony_ci
201f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY
202f9f848faSopenharmony_ci	usbd_free_bt_node(hub_tree);
203f9f848faSopenharmony_ci	hub_tree = NULL;
204f9f848faSopenharmony_ci#endif
205f9f848faSopenharmony_ci
206f9f848faSopenharmony_ci	return (0);
207f9f848faSopenharmony_ci}
208f9f848faSopenharmony_ci
209f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
210f9f848faSopenharmony_ci *	usb_suspend
211f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
212f9f848faSopenharmony_cistatic int
213f9f848faSopenharmony_ciusb_suspend(device_t dev)
214f9f848faSopenharmony_ci{
215f9f848faSopenharmony_ci	struct usb_bus *bus = (struct usb_bus *)device_get_softc(dev);
216f9f848faSopenharmony_ci
217f9f848faSopenharmony_ci	DPRINTF("\n");
218f9f848faSopenharmony_ci
219f9f848faSopenharmony_ci	if (bus == NULL) {
220f9f848faSopenharmony_ci		/* was never setup properly */
221f9f848faSopenharmony_ci		return (0);
222f9f848faSopenharmony_ci	}
223f9f848faSopenharmony_ci
224f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
225f9f848faSopenharmony_ci	(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
226f9f848faSopenharmony_ci	    &bus->suspend_msg[0], &bus->suspend_msg[1]);
227f9f848faSopenharmony_ci	if (usb_no_suspend_wait == 0) {
228f9f848faSopenharmony_ci		/* wait for suspend callback to be executed */
229f9f848faSopenharmony_ci		usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus),
230f9f848faSopenharmony_ci		    &bus->suspend_msg[0], &bus->suspend_msg[1]);
231f9f848faSopenharmony_ci	}
232f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
233f9f848faSopenharmony_ci
234f9f848faSopenharmony_ci	return (0);
235f9f848faSopenharmony_ci}
236f9f848faSopenharmony_ci
237f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
238f9f848faSopenharmony_ci *	usb_resume
239f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
240f9f848faSopenharmony_cistatic int
241f9f848faSopenharmony_ciusb_resume(device_t dev)
242f9f848faSopenharmony_ci{
243f9f848faSopenharmony_ci	struct usb_bus *bus = (struct usb_bus *)device_get_softc(dev);
244f9f848faSopenharmony_ci
245f9f848faSopenharmony_ci	DPRINTF("\n");
246f9f848faSopenharmony_ci
247f9f848faSopenharmony_ci	if (bus == NULL) {
248f9f848faSopenharmony_ci		/* was never setup properly */
249f9f848faSopenharmony_ci		return (0);
250f9f848faSopenharmony_ci	}
251f9f848faSopenharmony_ci
252f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
253f9f848faSopenharmony_ci	(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
254f9f848faSopenharmony_ci	    &bus->resume_msg[0], &bus->resume_msg[1]);
255f9f848faSopenharmony_ci	if (usb_no_resume_wait == 0) {
256f9f848faSopenharmony_ci		/* wait for resume callback to be executed */
257f9f848faSopenharmony_ci		usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus),
258f9f848faSopenharmony_ci		    &bus->resume_msg[0], &bus->resume_msg[1]);
259f9f848faSopenharmony_ci	}
260f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
261f9f848faSopenharmony_ci
262f9f848faSopenharmony_ci	return (0);
263f9f848faSopenharmony_ci}
264f9f848faSopenharmony_ci
265f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
266f9f848faSopenharmony_ci *	usb_bus_reset_async_locked
267f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
268f9f848faSopenharmony_civoid
269f9f848faSopenharmony_ciusb_bus_reset_async_locked(struct usb_bus *bus)
270f9f848faSopenharmony_ci{
271f9f848faSopenharmony_ci	USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
272f9f848faSopenharmony_ci
273f9f848faSopenharmony_ci	DPRINTF("\n");
274f9f848faSopenharmony_ci
275f9f848faSopenharmony_ci	if ((bus->reset_msg[0].hdr.pm_qentry.tqe_prev != NULL) ||
276f9f848faSopenharmony_ci	    (bus->reset_msg[1].hdr.pm_qentry.tqe_prev != NULL)) {
277f9f848faSopenharmony_ci		DPRINTF("Reset already pending\n");
278f9f848faSopenharmony_ci		return;
279f9f848faSopenharmony_ci	}
280f9f848faSopenharmony_ci
281f9f848faSopenharmony_ci	device_printf(bus->parent, "Resetting controller\n");
282f9f848faSopenharmony_ci
283f9f848faSopenharmony_ci	(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
284f9f848faSopenharmony_ci	    &bus->reset_msg[0], &bus->reset_msg[1]);
285f9f848faSopenharmony_ci}
286f9f848faSopenharmony_ci
287f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
288f9f848faSopenharmony_ci *	usb_shutdown
289f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
290f9f848faSopenharmony_cistatic int
291f9f848faSopenharmony_ciusb_shutdown(device_t dev)
292f9f848faSopenharmony_ci{
293f9f848faSopenharmony_ci	struct usb_bus *bus = device_get_softc(dev);
294f9f848faSopenharmony_ci
295f9f848faSopenharmony_ci	DPRINTF("\n");
296f9f848faSopenharmony_ci
297f9f848faSopenharmony_ci	if (bus == NULL) {
298f9f848faSopenharmony_ci		/* was never setup properly */
299f9f848faSopenharmony_ci		return (0);
300f9f848faSopenharmony_ci	}
301f9f848faSopenharmony_ci
302f9f848faSopenharmony_ci	DPRINTF("%s: Controller shutdown\n", device_get_nameunit(bus->bdev));
303f9f848faSopenharmony_ci
304f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
305f9f848faSopenharmony_ci	(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
306f9f848faSopenharmony_ci	    &bus->shutdown_msg[0], &bus->shutdown_msg[1]);
307f9f848faSopenharmony_ci	if (usb_no_shutdown_wait == 0) {
308f9f848faSopenharmony_ci		/* wait for shutdown callback to be executed */
309f9f848faSopenharmony_ci		usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus),
310f9f848faSopenharmony_ci		    &bus->shutdown_msg[0], &bus->shutdown_msg[1]);
311f9f848faSopenharmony_ci	}
312f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
313f9f848faSopenharmony_ci
314f9f848faSopenharmony_ci	DPRINTF("%s: Controller shutdown complete\n",
315f9f848faSopenharmony_ci	    device_get_nameunit(bus->bdev));
316f9f848faSopenharmony_ci
317f9f848faSopenharmony_ci	return (0);
318f9f848faSopenharmony_ci}
319f9f848faSopenharmony_ci
320f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
321f9f848faSopenharmony_ci *	usb_bus_explore
322f9f848faSopenharmony_ci *
323f9f848faSopenharmony_ci * This function is used to explore the device tree from the root.
324f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
325f9f848faSopenharmony_cistatic void
326f9f848faSopenharmony_ciusb_bus_explore(struct usb_proc_msg *pm)
327f9f848faSopenharmony_ci{
328f9f848faSopenharmony_ci	struct usb_bus *bus;
329f9f848faSopenharmony_ci	struct usb_device *udev;
330f9f848faSopenharmony_ci
331f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
332f9f848faSopenharmony_ci	udev = bus->devices[USB_ROOT_HUB_ADDR];
333f9f848faSopenharmony_ci
334f9f848faSopenharmony_ci	if (bus->no_explore != 0)
335f9f848faSopenharmony_ci		return;
336f9f848faSopenharmony_ci
337f9f848faSopenharmony_ci	if (udev != NULL) {
338f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
339f9f848faSopenharmony_ci		uhub_explore_handle_re_enumerate(udev);
340f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
341f9f848faSopenharmony_ci	}
342f9f848faSopenharmony_ci
343f9f848faSopenharmony_ci	if ((udev != NULL) && (udev->hub != NULL)) {
344f9f848faSopenharmony_ci		if (bus->do_probe) {
345f9f848faSopenharmony_ci			bus->do_probe = 0;
346f9f848faSopenharmony_ci			bus->driver_added_refcount++;
347f9f848faSopenharmony_ci		}
348f9f848faSopenharmony_ci		if (bus->driver_added_refcount == 0) {
349f9f848faSopenharmony_ci			/* avoid zero, hence that is memory default */
350f9f848faSopenharmony_ci			bus->driver_added_refcount = 1;
351f9f848faSopenharmony_ci		}
352f9f848faSopenharmony_ci
353f9f848faSopenharmony_ci#ifdef DDB
354f9f848faSopenharmony_ci		/*
355f9f848faSopenharmony_ci		 * The following three lines of code are only here to
356f9f848faSopenharmony_ci		 * recover from DDB:
357f9f848faSopenharmony_ci		 */
358f9f848faSopenharmony_ci		usb_proc_rewakeup(USB_BUS_CONTROL_XFER_PROC(bus));
359f9f848faSopenharmony_ci		usb_proc_rewakeup(USB_BUS_GIANT_PROC(bus));
360f9f848faSopenharmony_ci		usb_proc_rewakeup(USB_BUS_NON_GIANT_ISOC_PROC(bus));
361f9f848faSopenharmony_ci		usb_proc_rewakeup(USB_BUS_NON_GIANT_BULK_PROC(bus));
362f9f848faSopenharmony_ci#endif
363f9f848faSopenharmony_ci
364f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
365f9f848faSopenharmony_ci
366f9f848faSopenharmony_ci#if USB_HAVE_POWERD
367f9f848faSopenharmony_ci		/*
368f9f848faSopenharmony_ci		 * First update the USB power state!
369f9f848faSopenharmony_ci		 */
370f9f848faSopenharmony_ci		usb_bus_powerd(bus);
371f9f848faSopenharmony_ci#endif
372f9f848faSopenharmony_ci		 /* Explore the Root USB HUB. */
373f9f848faSopenharmony_ci		(void)(udev->hub->explore) (udev);
374f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
375f9f848faSopenharmony_ci	}
376f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
377f9f848faSopenharmony_ci	usb_root_mount_rel(bus);
378f9f848faSopenharmony_ci#endif
379f9f848faSopenharmony_ci}
380f9f848faSopenharmony_ci
381f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
382f9f848faSopenharmony_ci *	usb_bus_detach
383f9f848faSopenharmony_ci *
384f9f848faSopenharmony_ci * This function is used to detach the device tree from the root.
385f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
386f9f848faSopenharmony_cistatic void
387f9f848faSopenharmony_ciusb_bus_detach(struct usb_proc_msg *pm)
388f9f848faSopenharmony_ci{
389f9f848faSopenharmony_ci	struct usb_bus *bus;
390f9f848faSopenharmony_ci	struct usb_device *udev;
391f9f848faSopenharmony_ci	device_t dev;
392f9f848faSopenharmony_ci
393f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
394f9f848faSopenharmony_ci	udev = bus->devices[USB_ROOT_HUB_ADDR];
395f9f848faSopenharmony_ci	dev = bus->bdev;
396f9f848faSopenharmony_ci	/* clear the softc */
397f9f848faSopenharmony_ci	device_set_softc(dev, NULL);
398f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
399f9f848faSopenharmony_ci
400f9f848faSopenharmony_ci	/* detach children first */
401f9f848faSopenharmony_ci	mtx_lock(&Giant);
402f9f848faSopenharmony_ci	(void)bus_generic_detach(dev);
403f9f848faSopenharmony_ci	mtx_unlock(&Giant);
404f9f848faSopenharmony_ci
405f9f848faSopenharmony_ci	/*
406f9f848faSopenharmony_ci	 * Free USB device and all subdevices, if any.
407f9f848faSopenharmony_ci	 */
408f9f848faSopenharmony_ci	usb_free_device(udev, 0);
409f9f848faSopenharmony_ci
410f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
411f9f848faSopenharmony_ci	/* clear bdev variable last */
412f9f848faSopenharmony_ci	bus->bdev = NULL;
413f9f848faSopenharmony_ci}
414f9f848faSopenharmony_ci
415f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
416f9f848faSopenharmony_ci *	usb_bus_suspend
417f9f848faSopenharmony_ci *
418f9f848faSopenharmony_ci * This function is used to suspend the USB controller.
419f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
420f9f848faSopenharmony_cistatic void
421f9f848faSopenharmony_ciusb_bus_suspend(struct usb_proc_msg *pm)
422f9f848faSopenharmony_ci{
423f9f848faSopenharmony_ci	struct usb_bus *bus;
424f9f848faSopenharmony_ci	struct usb_device *udev;
425f9f848faSopenharmony_ci	usb_error_t err;
426f9f848faSopenharmony_ci	uint8_t do_unlock;
427f9f848faSopenharmony_ci
428f9f848faSopenharmony_ci	DPRINTF("\n");
429f9f848faSopenharmony_ci
430f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
431f9f848faSopenharmony_ci	udev = bus->devices[USB_ROOT_HUB_ADDR];
432f9f848faSopenharmony_ci
433f9f848faSopenharmony_ci	if ((udev == NULL) || (bus->bdev == NULL))
434f9f848faSopenharmony_ci		return;
435f9f848faSopenharmony_ci
436f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
437f9f848faSopenharmony_ci
438f9f848faSopenharmony_ci	/*
439f9f848faSopenharmony_ci	 * We use the shutdown event here because the suspend and
440f9f848faSopenharmony_ci	 * resume events are reserved for the USB port suspend and
441f9f848faSopenharmony_ci	 * resume. The USB system suspend is implemented like full
442f9f848faSopenharmony_ci	 * shutdown and all connected USB devices will be disconnected
443f9f848faSopenharmony_ci	 * subsequently. At resume all USB devices will be
444f9f848faSopenharmony_ci	 * re-connected again.
445f9f848faSopenharmony_ci	 */
446f9f848faSopenharmony_ci
447f9f848faSopenharmony_ci	(void)bus_generic_shutdown(bus->bdev);
448f9f848faSopenharmony_ci
449f9f848faSopenharmony_ci	do_unlock = usbd_enum_lock(udev);
450f9f848faSopenharmony_ci
451f9f848faSopenharmony_ci	err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
452f9f848faSopenharmony_ci	if (err)
453f9f848faSopenharmony_ci		device_printf(bus->bdev, "Could not unconfigure root HUB\n");
454f9f848faSopenharmony_ci
455f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
456f9f848faSopenharmony_ci	bus->hw_power_state = 0;
457f9f848faSopenharmony_ci	bus->no_explore = 1;
458f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
459f9f848faSopenharmony_ci
460f9f848faSopenharmony_ci	if (bus->methods->set_hw_power != NULL)
461f9f848faSopenharmony_ci		(bus->methods->set_hw_power) (bus);
462f9f848faSopenharmony_ci
463f9f848faSopenharmony_ci	if (bus->methods->set_hw_power_sleep != NULL)
464f9f848faSopenharmony_ci		(bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND);
465f9f848faSopenharmony_ci
466f9f848faSopenharmony_ci	if (do_unlock)
467f9f848faSopenharmony_ci		usbd_enum_unlock(udev);
468f9f848faSopenharmony_ci
469f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
470f9f848faSopenharmony_ci}
471f9f848faSopenharmony_ci
472f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
473f9f848faSopenharmony_ci *	usb_bus_resume
474f9f848faSopenharmony_ci *
475f9f848faSopenharmony_ci * This function is used to resume the USB controller.
476f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
477f9f848faSopenharmony_cistatic void
478f9f848faSopenharmony_ciusb_bus_resume(struct usb_proc_msg *pm)
479f9f848faSopenharmony_ci{
480f9f848faSopenharmony_ci	struct usb_bus *bus;
481f9f848faSopenharmony_ci	struct usb_device *udev;
482f9f848faSopenharmony_ci	usb_error_t err;
483f9f848faSopenharmony_ci	uint8_t do_unlock;
484f9f848faSopenharmony_ci
485f9f848faSopenharmony_ci	DPRINTF("\n");
486f9f848faSopenharmony_ci
487f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
488f9f848faSopenharmony_ci	udev = bus->devices[USB_ROOT_HUB_ADDR];
489f9f848faSopenharmony_ci
490f9f848faSopenharmony_ci	if ((udev == NULL) || (bus->bdev == NULL))
491f9f848faSopenharmony_ci		return;
492f9f848faSopenharmony_ci
493f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
494f9f848faSopenharmony_ci
495f9f848faSopenharmony_ci	do_unlock = usbd_enum_lock(udev);
496f9f848faSopenharmony_ci
497f9f848faSopenharmony_ci	USB_TAKE_CONTROLLER(device_get_parent(bus->bdev));
498f9f848faSopenharmony_ci
499f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
500f9f848faSopenharmony_ci 	bus->hw_power_state =
501f9f848faSopenharmony_ci	  USB_HW_POWER_CONTROL |
502f9f848faSopenharmony_ci	  USB_HW_POWER_BULK |
503f9f848faSopenharmony_ci	  USB_HW_POWER_INTERRUPT |
504f9f848faSopenharmony_ci	  USB_HW_POWER_ISOC |
505f9f848faSopenharmony_ci	  USB_HW_POWER_NON_ROOT_HUB;
506f9f848faSopenharmony_ci	bus->no_explore = 0;
507f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
508f9f848faSopenharmony_ci
509f9f848faSopenharmony_ci	if (bus->methods->set_hw_power_sleep != NULL)
510f9f848faSopenharmony_ci		(bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME);
511f9f848faSopenharmony_ci
512f9f848faSopenharmony_ci	if (bus->methods->set_hw_power != NULL)
513f9f848faSopenharmony_ci		(bus->methods->set_hw_power) (bus);
514f9f848faSopenharmony_ci
515f9f848faSopenharmony_ci	/* restore USB configuration to index 0 */
516f9f848faSopenharmony_ci	err = usbd_set_config_index(udev, 0);
517f9f848faSopenharmony_ci	if (err)
518f9f848faSopenharmony_ci		device_printf(bus->bdev, "Could not configure root HUB\n");
519f9f848faSopenharmony_ci
520f9f848faSopenharmony_ci	/* probe and attach */
521f9f848faSopenharmony_ci	err = usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY);
522f9f848faSopenharmony_ci	if (err) {
523f9f848faSopenharmony_ci		device_printf(bus->bdev, "Could not probe and "
524f9f848faSopenharmony_ci		    "attach root HUB\n");
525f9f848faSopenharmony_ci	}
526f9f848faSopenharmony_ci
527f9f848faSopenharmony_ci	if (do_unlock)
528f9f848faSopenharmony_ci		usbd_enum_unlock(udev);
529f9f848faSopenharmony_ci
530f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
531f9f848faSopenharmony_ci}
532f9f848faSopenharmony_ci
533f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
534f9f848faSopenharmony_ci *	usb_bus_reset
535f9f848faSopenharmony_ci *
536f9f848faSopenharmony_ci * This function is used to reset the USB controller.
537f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
538f9f848faSopenharmony_cistatic void
539f9f848faSopenharmony_ciusb_bus_reset(struct usb_proc_msg *pm)
540f9f848faSopenharmony_ci{
541f9f848faSopenharmony_ci	struct usb_bus *bus;
542f9f848faSopenharmony_ci
543f9f848faSopenharmony_ci	DPRINTF("\n");
544f9f848faSopenharmony_ci
545f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
546f9f848faSopenharmony_ci
547f9f848faSopenharmony_ci	if ((bus->bdev == NULL) || (bus->no_explore != 0))
548f9f848faSopenharmony_ci		return;
549f9f848faSopenharmony_ci
550f9f848faSopenharmony_ci	/* a suspend and resume will reset the USB controller */
551f9f848faSopenharmony_ci	usb_bus_suspend(pm);
552f9f848faSopenharmony_ci	usb_bus_resume(pm);
553f9f848faSopenharmony_ci}
554f9f848faSopenharmony_ci
555f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
556f9f848faSopenharmony_ci *	usb_bus_shutdown
557f9f848faSopenharmony_ci *
558f9f848faSopenharmony_ci * This function is used to shutdown the USB controller.
559f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
560f9f848faSopenharmony_cistatic void
561f9f848faSopenharmony_ciusb_bus_shutdown(struct usb_proc_msg *pm)
562f9f848faSopenharmony_ci{
563f9f848faSopenharmony_ci	struct usb_bus *bus;
564f9f848faSopenharmony_ci	struct usb_device *udev;
565f9f848faSopenharmony_ci	usb_error_t err;
566f9f848faSopenharmony_ci	uint8_t do_unlock;
567f9f848faSopenharmony_ci
568f9f848faSopenharmony_ci	DPRINTF("\n");
569f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
570f9f848faSopenharmony_ci	udev = bus->devices[USB_ROOT_HUB_ADDR];
571f9f848faSopenharmony_ci
572f9f848faSopenharmony_ci	if ((udev == NULL) || (bus->bdev == NULL))
573f9f848faSopenharmony_ci		return;
574f9f848faSopenharmony_ci
575f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
576f9f848faSopenharmony_ci
577f9f848faSopenharmony_ci	(void)bus_generic_shutdown(bus->bdev);
578f9f848faSopenharmony_ci
579f9f848faSopenharmony_ci	do_unlock = usbd_enum_lock(udev);
580f9f848faSopenharmony_ci
581f9f848faSopenharmony_ci	err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
582f9f848faSopenharmony_ci	if (err)
583f9f848faSopenharmony_ci		device_printf(bus->bdev, "Could not unconfigure root HUB\n");
584f9f848faSopenharmony_ci
585f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
586f9f848faSopenharmony_ci	bus->hw_power_state = 0;
587f9f848faSopenharmony_ci	bus->no_explore = 1;
588f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
589f9f848faSopenharmony_ci
590f9f848faSopenharmony_ci	if (bus->methods->set_hw_power != NULL)
591f9f848faSopenharmony_ci		(bus->methods->set_hw_power) (bus);
592f9f848faSopenharmony_ci
593f9f848faSopenharmony_ci	if (bus->methods->set_hw_power_sleep != NULL)
594f9f848faSopenharmony_ci		(bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN);
595f9f848faSopenharmony_ci
596f9f848faSopenharmony_ci	if (do_unlock)
597f9f848faSopenharmony_ci		usbd_enum_unlock(udev);
598f9f848faSopenharmony_ci
599f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
600f9f848faSopenharmony_ci}
601f9f848faSopenharmony_ci
602f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
603f9f848faSopenharmony_ci *	usb_bus_attach
604f9f848faSopenharmony_ci *
605f9f848faSopenharmony_ci * This function attaches USB in context of the explore thread.
606f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
607f9f848faSopenharmony_cistatic void
608f9f848faSopenharmony_ciusb_bus_attach(struct usb_proc_msg *pm)
609f9f848faSopenharmony_ci{
610f9f848faSopenharmony_ci	struct usb_bus *bus;
611f9f848faSopenharmony_ci	struct usb_device *child;
612f9f848faSopenharmony_ci	device_t dev;
613f9f848faSopenharmony_ci	usb_error_t err;
614f9f848faSopenharmony_ci	enum usb_dev_speed speed;
615f9f848faSopenharmony_ci
616f9f848faSopenharmony_ci	bus = ((struct usb_bus_msg *)pm)->bus;
617f9f848faSopenharmony_ci	dev = bus->bdev;
618f9f848faSopenharmony_ci
619f9f848faSopenharmony_ci	DPRINTF("\n");
620f9f848faSopenharmony_ci
621f9f848faSopenharmony_ci	switch (bus->usbrev) {
622f9f848faSopenharmony_ci	case USB_REV_1_0:
623f9f848faSopenharmony_ci		speed = USB_SPEED_FULL;
624f9f848faSopenharmony_ci		device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n");
625f9f848faSopenharmony_ci		break;
626f9f848faSopenharmony_ci
627f9f848faSopenharmony_ci	case USB_REV_1_1:
628f9f848faSopenharmony_ci		speed = USB_SPEED_FULL;
629f9f848faSopenharmony_ci		device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n");
630f9f848faSopenharmony_ci		break;
631f9f848faSopenharmony_ci
632f9f848faSopenharmony_ci	case USB_REV_2_0:
633f9f848faSopenharmony_ci		speed = USB_SPEED_HIGH;
634f9f848faSopenharmony_ci		device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n");
635f9f848faSopenharmony_ci		break;
636f9f848faSopenharmony_ci
637f9f848faSopenharmony_ci	case USB_REV_2_5:
638f9f848faSopenharmony_ci		speed = USB_SPEED_VARIABLE;
639f9f848faSopenharmony_ci		device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n");
640f9f848faSopenharmony_ci		break;
641f9f848faSopenharmony_ci
642f9f848faSopenharmony_ci	case USB_REV_3_0:
643f9f848faSopenharmony_ci		speed = USB_SPEED_SUPER;
644f9f848faSopenharmony_ci		device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n");
645f9f848faSopenharmony_ci		break;
646f9f848faSopenharmony_ci
647f9f848faSopenharmony_ci	default:
648f9f848faSopenharmony_ci		device_printf(bus->bdev, "Unsupported USB revision\n");
649f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
650f9f848faSopenharmony_ci		usb_root_mount_rel(bus);
651f9f848faSopenharmony_ci#endif
652f9f848faSopenharmony_ci		return;
653f9f848faSopenharmony_ci	}
654f9f848faSopenharmony_ci
655f9f848faSopenharmony_ci	/* default power_mask value */
656f9f848faSopenharmony_ci	bus->hw_power_state =
657f9f848faSopenharmony_ci	  USB_HW_POWER_CONTROL |
658f9f848faSopenharmony_ci	  USB_HW_POWER_BULK |
659f9f848faSopenharmony_ci	  USB_HW_POWER_INTERRUPT |
660f9f848faSopenharmony_ci	  USB_HW_POWER_ISOC |
661f9f848faSopenharmony_ci	  USB_HW_POWER_NON_ROOT_HUB;
662f9f848faSopenharmony_ci
663f9f848faSopenharmony_ci	USB_BUS_UNLOCK(bus);
664f9f848faSopenharmony_ci
665f9f848faSopenharmony_ci	/* make sure power is set at least once */
666f9f848faSopenharmony_ci
667f9f848faSopenharmony_ci	if (bus->methods->set_hw_power != NULL) {
668f9f848faSopenharmony_ci		(bus->methods->set_hw_power) (bus);
669f9f848faSopenharmony_ci	}
670f9f848faSopenharmony_ci
671f9f848faSopenharmony_ci	/* allocate the Root USB device */
672f9f848faSopenharmony_ci
673f9f848faSopenharmony_ci	child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1,
674f9f848faSopenharmony_ci	    speed, USB_MODE_HOST);
675f9f848faSopenharmony_ci	if (child) {
676f9f848faSopenharmony_ci		err = usb_probe_and_attach(child,
677f9f848faSopenharmony_ci		    USB_IFACE_INDEX_ANY);
678f9f848faSopenharmony_ci		if (!err) {
679f9f848faSopenharmony_ci			if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) ||
680f9f848faSopenharmony_ci			    (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) {
681f9f848faSopenharmony_ci				err = USB_ERR_NO_ROOT_HUB;
682f9f848faSopenharmony_ci			}
683f9f848faSopenharmony_ci		}
684f9f848faSopenharmony_ci	} else {
685f9f848faSopenharmony_ci		err = USB_ERR_NOMEM;
686f9f848faSopenharmony_ci	}
687f9f848faSopenharmony_ci
688f9f848faSopenharmony_ci	USB_BUS_LOCK(bus);
689f9f848faSopenharmony_ci
690f9f848faSopenharmony_ci	if (err) {
691f9f848faSopenharmony_ci		device_printf(bus->bdev, "Root HUB problem, error=%s\n",
692f9f848faSopenharmony_ci		    usbd_errstr(err));
693f9f848faSopenharmony_ci#if USB_HAVE_ROOT_MOUNT_HOLD
694f9f848faSopenharmony_ci		usb_root_mount_rel(bus);
695f9f848faSopenharmony_ci#endif
696f9f848faSopenharmony_ci	}
697f9f848faSopenharmony_ci
698f9f848faSopenharmony_ci	/* set softc - we are ready */
699f9f848faSopenharmony_ci	device_set_softc(dev, bus);
700f9f848faSopenharmony_ci}
701f9f848faSopenharmony_ci
702f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
703f9f848faSopenharmony_ci *	usb_attach_sub
704f9f848faSopenharmony_ci *
705f9f848faSopenharmony_ci * This function creates a thread which runs the USB attach code.
706f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
707f9f848faSopenharmony_ci
708f9f848faSopenharmony_cistatic void
709f9f848faSopenharmony_ciusb_attach_sub(device_t dev, struct usb_bus *bus)
710f9f848faSopenharmony_ci{
711f9f848faSopenharmony_ci	mtx_lock(&Giant);
712f9f848faSopenharmony_ci	if (usb_devclass_ptr == NULL)
713f9f848faSopenharmony_ci		usb_devclass_ptr = devclass_find("usbus");
714f9f848faSopenharmony_ci	mtx_unlock(&Giant);
715f9f848faSopenharmony_ci
716f9f848faSopenharmony_ci#if USB_HAVE_PF
717f9f848faSopenharmony_ci	usbpf_attach(bus);
718f9f848faSopenharmony_ci#endif
719f9f848faSopenharmony_ci	/* Initialise USB process messages */
720f9f848faSopenharmony_ci	bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore;
721f9f848faSopenharmony_ci	bus->explore_msg[0].bus = bus;
722f9f848faSopenharmony_ci	bus->explore_msg[1].hdr.pm_callback = &usb_bus_explore;
723f9f848faSopenharmony_ci	bus->explore_msg[1].bus = bus;
724f9f848faSopenharmony_ci
725f9f848faSopenharmony_ci	bus->detach_msg[0].hdr.pm_callback = &usb_bus_detach;
726f9f848faSopenharmony_ci	bus->detach_msg[0].bus = bus;
727f9f848faSopenharmony_ci	bus->detach_msg[1].hdr.pm_callback = &usb_bus_detach;
728f9f848faSopenharmony_ci	bus->detach_msg[1].bus = bus;
729f9f848faSopenharmony_ci
730f9f848faSopenharmony_ci	bus->attach_msg[0].hdr.pm_callback = &usb_bus_attach;
731f9f848faSopenharmony_ci	bus->attach_msg[0].bus = bus;
732f9f848faSopenharmony_ci	bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach;
733f9f848faSopenharmony_ci	bus->attach_msg[1].bus = bus;
734f9f848faSopenharmony_ci
735f9f848faSopenharmony_ci	bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend;
736f9f848faSopenharmony_ci	bus->suspend_msg[0].bus = bus;
737f9f848faSopenharmony_ci	bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend;
738f9f848faSopenharmony_ci	bus->suspend_msg[1].bus = bus;
739f9f848faSopenharmony_ci
740f9f848faSopenharmony_ci	bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume;
741f9f848faSopenharmony_ci	bus->resume_msg[0].bus = bus;
742f9f848faSopenharmony_ci	bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume;
743f9f848faSopenharmony_ci	bus->resume_msg[1].bus = bus;
744f9f848faSopenharmony_ci
745f9f848faSopenharmony_ci	bus->reset_msg[0].hdr.pm_callback = &usb_bus_reset;
746f9f848faSopenharmony_ci	bus->reset_msg[0].bus = bus;
747f9f848faSopenharmony_ci	bus->reset_msg[1].hdr.pm_callback = &usb_bus_reset;
748f9f848faSopenharmony_ci	bus->reset_msg[1].bus = bus;
749f9f848faSopenharmony_ci
750f9f848faSopenharmony_ci	bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown;
751f9f848faSopenharmony_ci	bus->shutdown_msg[0].bus = bus;
752f9f848faSopenharmony_ci	bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown;
753f9f848faSopenharmony_ci	bus->shutdown_msg[1].bus = bus;
754f9f848faSopenharmony_ci
755f9f848faSopenharmony_ci#if USB_HAVE_PER_BUS_PROCESS
756f9f848faSopenharmony_ci	/* Create USB explore and callback processes */
757f9f848faSopenharmony_ci	if (usb_proc_create(USB_BUS_GIANT_PROC(bus),
758f9f848faSopenharmony_ci	    &bus->bus_mtx, "USB_GIANT_Task", USB_PRI_MED)) {
759f9f848faSopenharmony_ci		device_printf(dev, "WARNING: Creation of USB Giant "
760f9f848faSopenharmony_ci		    "callback process failed.\n");
761f9f848faSopenharmony_ci	} else if (usb_proc_create(USB_BUS_NON_GIANT_ISOC_PROC(bus),
762f9f848faSopenharmony_ci	    &bus->bus_mtx, "USB_NGIAN_ISOC_Task", USB_PRI_HIGHEST)) {
763f9f848faSopenharmony_ci		device_printf(dev, "WARNING: Creation of USB non-Giant ISOC"
764f9f848faSopenharmony_ci		    "callback process failed.\n");
765f9f848faSopenharmony_ci	} else if (usb_proc_create(USB_BUS_NON_GIANT_BULK_PROC(bus),
766f9f848faSopenharmony_ci	    &bus->bus_mtx, "USB_NGIAN_BULK_Task", USB_PRI_HIGH)) {
767f9f848faSopenharmony_ci		device_printf(dev, "WARNING: Creation of USB non-Giant BULK"
768f9f848faSopenharmony_ci		    "callback process failed.\n");
769f9f848faSopenharmony_ci	} else if (usb_proc_create(USB_BUS_EXPLORE_PROC(bus),
770f9f848faSopenharmony_ci	    &bus->bus_mtx, "USB_EXPLR_Task", USB_PRI_MED)) {
771f9f848faSopenharmony_ci		device_printf(dev, "WARNING: Creation of USB explore "
772f9f848faSopenharmony_ci		    "process failed.\n");
773f9f848faSopenharmony_ci	} else if (usb_proc_create(USB_BUS_CONTROL_XFER_PROC(bus),
774f9f848faSopenharmony_ci	    &bus->bus_mtx, "USB_CXFER_Task", USB_PRI_MED)) {
775f9f848faSopenharmony_ci		device_printf(dev, "WARNING: Creation of USB control transfer "
776f9f848faSopenharmony_ci		    "process failed.\n");
777f9f848faSopenharmony_ci	} else
778f9f848faSopenharmony_ci#endif
779f9f848faSopenharmony_ci	{
780f9f848faSopenharmony_ci		/* Get final attach going */
781f9f848faSopenharmony_ci		USB_BUS_LOCK(bus);
782f9f848faSopenharmony_ci		(void)usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
783f9f848faSopenharmony_ci		    &bus->attach_msg[0], &bus->attach_msg[1]);
784f9f848faSopenharmony_ci		USB_BUS_UNLOCK(bus);
785f9f848faSopenharmony_ci
786f9f848faSopenharmony_ci		/* Do initial explore */
787f9f848faSopenharmony_ci		if (usb_port_status_get()) {
788f9f848faSopenharmony_ci			usb_needs_explore(bus, 1);
789f9f848faSopenharmony_ci		}
790f9f848faSopenharmony_ci	}
791f9f848faSopenharmony_ci}
792f9f848faSopenharmony_ci
793f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
794f9f848faSopenharmony_ci *	usb_bus_mem_flush_all_cb
795f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
796f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
797f9f848faSopenharmony_cistatic void
798f9f848faSopenharmony_ciusb_bus_mem_flush_all_cb(struct usb_bus *bus, struct usb_page_cache *pc,
799f9f848faSopenharmony_ci    struct usb_page *pg, usb_size_t nsize, usb_size_t align)
800f9f848faSopenharmony_ci{
801f9f848faSopenharmony_ci	usb_pc_cpu_flush(pc);
802f9f848faSopenharmony_ci}
803f9f848faSopenharmony_ci#endif
804f9f848faSopenharmony_ci
805f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
806f9f848faSopenharmony_ci *	usb_bus_mem_flush_all - factored out code
807f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
808f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
809f9f848faSopenharmony_civoid
810f9f848faSopenharmony_ciusb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb)
811f9f848faSopenharmony_ci{
812f9f848faSopenharmony_ci	if (cb) {
813f9f848faSopenharmony_ci		cb(bus, &usb_bus_mem_flush_all_cb);
814f9f848faSopenharmony_ci	}
815f9f848faSopenharmony_ci}
816f9f848faSopenharmony_ci#endif
817f9f848faSopenharmony_ci
818f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
819f9f848faSopenharmony_ci *	usb_bus_mem_alloc_all_cb
820f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
821f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
822f9f848faSopenharmony_cistatic void
823f9f848faSopenharmony_ciusb_bus_mem_alloc_all_cb(struct usb_bus *bus, struct usb_page_cache *pc,
824f9f848faSopenharmony_ci    struct usb_page *pg, usb_size_t nsize, usb_size_t align)
825f9f848faSopenharmony_ci{
826f9f848faSopenharmony_ci	/* need to initialize the page cache */
827f9f848faSopenharmony_ci	pc->tag_parent = bus->dma_parent_tag;
828f9f848faSopenharmony_ci
829f9f848faSopenharmony_ci	if (usb_pc_alloc_mem(pc, pg, nsize, align)) {
830f9f848faSopenharmony_ci		bus->alloc_failed = 1;
831f9f848faSopenharmony_ci	}
832f9f848faSopenharmony_ci}
833f9f848faSopenharmony_ci#endif
834f9f848faSopenharmony_ci
835f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
836f9f848faSopenharmony_ci *	usb_bus_mem_alloc_all - factored out code
837f9f848faSopenharmony_ci *
838f9f848faSopenharmony_ci * Returns:
839f9f848faSopenharmony_ci *    0: Success
840f9f848faSopenharmony_ci * Else: Failure
841f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
842f9f848faSopenharmony_ciuint8_t
843f9f848faSopenharmony_ciusb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat,
844f9f848faSopenharmony_ci    usb_bus_mem_cb_t *cb)
845f9f848faSopenharmony_ci{
846f9f848faSopenharmony_ci	bus->alloc_failed = 0;
847f9f848faSopenharmony_ci
848f9f848faSopenharmony_ci	mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent),
849f9f848faSopenharmony_ci	    "usb_def_mtx", MTX_DEF | MTX_RECURSE);
850f9f848faSopenharmony_ci
851f9f848faSopenharmony_ci	mtx_init(&bus->bus_spin_lock, device_get_nameunit(bus->parent),
852f9f848faSopenharmony_ci	    "usb_spin_mtx", MTX_SPIN | MTX_RECURSE);
853f9f848faSopenharmony_ci
854f9f848faSopenharmony_ci	usb_callout_init_mtx(&bus->power_wdog,
855f9f848faSopenharmony_ci	    &bus->bus_mtx, 0);
856f9f848faSopenharmony_ci
857f9f848faSopenharmony_ci	TAILQ_INIT(&bus->intr_q.head);
858f9f848faSopenharmony_ci
859f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
860f9f848faSopenharmony_ci	usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags,
861f9f848faSopenharmony_ci	    dmat, &bus->bus_mtx, NULL, bus->dma_bits, USB_BUS_DMA_TAG_MAX);
862f9f848faSopenharmony_ci#endif
863f9f848faSopenharmony_ci	if ((bus->devices_max > USB_MAX_DEVICES) ||
864f9f848faSopenharmony_ci	    (bus->devices_max < USB_MIN_DEVICES) ||
865f9f848faSopenharmony_ci	    (bus->devices == NULL)) {
866f9f848faSopenharmony_ci		DPRINTFN(0, "Devices field has not been "
867f9f848faSopenharmony_ci		    "initialised properly\n");
868f9f848faSopenharmony_ci		bus->alloc_failed = 1;		/* failure */
869f9f848faSopenharmony_ci	}
870f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
871f9f848faSopenharmony_ci	if (cb) {
872f9f848faSopenharmony_ci		cb(bus, &usb_bus_mem_alloc_all_cb);
873f9f848faSopenharmony_ci	}
874f9f848faSopenharmony_ci#endif
875f9f848faSopenharmony_ci	if (bus->alloc_failed) {
876f9f848faSopenharmony_ci		usb_bus_mem_free_all(bus, cb);
877f9f848faSopenharmony_ci	}
878f9f848faSopenharmony_ci	return (bus->alloc_failed);
879f9f848faSopenharmony_ci}
880f9f848faSopenharmony_ci
881f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
882f9f848faSopenharmony_ci *	usb_bus_mem_free_all_cb
883f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
884f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
885f9f848faSopenharmony_cistatic void
886f9f848faSopenharmony_ciusb_bus_mem_free_all_cb(struct usb_bus *bus, struct usb_page_cache *pc,
887f9f848faSopenharmony_ci    struct usb_page *pg, usb_size_t nsize, usb_size_t align)
888f9f848faSopenharmony_ci{
889f9f848faSopenharmony_ci	usb_pc_free_mem(pc);
890f9f848faSopenharmony_ci}
891f9f848faSopenharmony_ci#endif
892f9f848faSopenharmony_ci
893f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
894f9f848faSopenharmony_ci *	usb_bus_mem_free_all - factored out code
895f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
896f9f848faSopenharmony_civoid
897f9f848faSopenharmony_ciusb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb)
898f9f848faSopenharmony_ci{
899f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA
900f9f848faSopenharmony_ci	if (cb) {
901f9f848faSopenharmony_ci		cb(bus, &usb_bus_mem_free_all_cb);
902f9f848faSopenharmony_ci	}
903f9f848faSopenharmony_ci	usb_dma_tag_unsetup(bus->dma_parent_tag);
904f9f848faSopenharmony_ci#endif
905f9f848faSopenharmony_ci
906f9f848faSopenharmony_ci	mtx_destroy(&bus->bus_mtx);
907f9f848faSopenharmony_ci	mtx_destroy(&bus->bus_spin_lock);
908f9f848faSopenharmony_ci}
909f9f848faSopenharmony_ci
910f9f848faSopenharmony_ci/* convenience wrappers */
911f9f848faSopenharmony_civoid
912f9f848faSopenharmony_ciusb_proc_explore_mwait(struct usb_device *udev, void *pm1, void *pm2)
913f9f848faSopenharmony_ci{
914f9f848faSopenharmony_ci	usb_proc_mwait(USB_BUS_EXPLORE_PROC(udev->bus), pm1, pm2);
915f9f848faSopenharmony_ci}
916f9f848faSopenharmony_ci
917f9f848faSopenharmony_civoid *
918f9f848faSopenharmony_ciusb_proc_explore_msignal(struct usb_device *udev, void *pm1, void *pm2)
919f9f848faSopenharmony_ci{
920f9f848faSopenharmony_ci	return (usb_proc_msignal(USB_BUS_EXPLORE_PROC(udev->bus), pm1, pm2));
921f9f848faSopenharmony_ci}
922f9f848faSopenharmony_ci
923f9f848faSopenharmony_civoid
924f9f848faSopenharmony_ciusb_proc_explore_lock(struct usb_device *udev)
925f9f848faSopenharmony_ci{
926f9f848faSopenharmony_ci	USB_BUS_LOCK(udev->bus);
927f9f848faSopenharmony_ci}
928f9f848faSopenharmony_ci
929f9f848faSopenharmony_civoid
930f9f848faSopenharmony_ciusb_proc_explore_unlock(struct usb_device *udev)
931f9f848faSopenharmony_ci{
932f9f848faSopenharmony_ci	USB_BUS_UNLOCK(udev->bus);
933f9f848faSopenharmony_ci}
934f9f848faSopenharmony_ci
935f9f848faSopenharmony_ci#undef	USB_DEBUG_VAR
936