bsd_kernel.c revision 291403
1246145Shselasky/* $FreeBSD: head/sys/boot/kshim/bsd_kernel.c 291403 2015-11-27 18:19:11Z zbb $ */
2246145Shselasky/*-
3246145Shselasky * Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
4246145Shselasky *
5246145Shselasky * Redistribution and use in source and binary forms, with or without
6246145Shselasky * modification, are permitted provided that the following conditions
7246145Shselasky * are met:
8246145Shselasky * 1. Redistributions of source code must retain the above copyright
9246145Shselasky *    notice, this list of conditions and the following disclaimer.
10246145Shselasky * 2. Redistributions in binary form must reproduce the above copyright
11246145Shselasky *    notice, this list of conditions and the following disclaimer in the
12246145Shselasky *    documentation and/or other materials provided with the distribution.
13246145Shselasky *
14246145Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15246145Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16246145Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17246145Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18246145Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19246145Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20246145Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21246145Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22246145Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23246145Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24246145Shselasky * SUCH DAMAGE.
25246145Shselasky */
26246145Shselasky
27246145Shselasky#include <bsd_global.h>
28246145Shselasky
29246363Shselaskystruct usb_process usb_process[USB_PROC_MAX];
30246363Shselasky
31246145Shselaskystatic device_t usb_pci_root;
32246145Shselasky
33246145Shselasky/*------------------------------------------------------------------------*
34246145Shselasky * Implementation of mutex API
35246145Shselasky *------------------------------------------------------------------------*/
36246145Shselasky
37246145Shselaskystruct mtx Giant;
38246145Shselasky
39246145Shselaskystatic void
40246145Shselaskymtx_system_init(void *arg)
41246145Shselasky{
42246145Shselasky	mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE);
43246145Shselasky}
44246145ShselaskySYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL);
45246145Shselasky
46246145Shselaskyvoid
47246145Shselaskymtx_init(struct mtx *mtx, const char *name, const char *type, int opt)
48246145Shselasky{
49246145Shselasky	mtx->owned = 0;
50246145Shselasky	mtx->parent = mtx;
51246145Shselasky}
52246145Shselasky
53246145Shselaskyvoid
54246145Shselaskymtx_lock(struct mtx *mtx)
55246145Shselasky{
56246145Shselasky	mtx = mtx->parent;
57246145Shselasky	mtx->owned++;
58246145Shselasky}
59246145Shselasky
60246145Shselaskyvoid
61246145Shselaskymtx_unlock(struct mtx *mtx)
62246145Shselasky{
63246145Shselasky	mtx = mtx->parent;
64246145Shselasky	mtx->owned--;
65246145Shselasky}
66246145Shselasky
67246145Shselaskyint
68246145Shselaskymtx_owned(struct mtx *mtx)
69246145Shselasky{
70246145Shselasky	mtx = mtx->parent;
71246145Shselasky	return (mtx->owned != 0);
72246145Shselasky}
73246145Shselasky
74246145Shselaskyvoid
75246145Shselaskymtx_destroy(struct mtx *mtx)
76246145Shselasky{
77246145Shselasky	/* NOP */
78246145Shselasky}
79246145Shselasky
80246145Shselasky/*------------------------------------------------------------------------*
81246145Shselasky * Implementation of shared/exclusive mutex API
82246145Shselasky *------------------------------------------------------------------------*/
83246145Shselasky
84246145Shselaskyvoid
85246145Shselaskysx_init_flags(struct sx *sx, const char *name, int flags)
86246145Shselasky{
87246145Shselasky	sx->owned = 0;
88246145Shselasky}
89246145Shselasky
90246145Shselaskyvoid
91246145Shselaskysx_destroy(struct sx *sx)
92246145Shselasky{
93246145Shselasky	/* NOP */
94246145Shselasky}
95246145Shselasky
96246145Shselaskyvoid
97246145Shselaskysx_xlock(struct sx *sx)
98246145Shselasky{
99246145Shselasky	sx->owned++;
100246145Shselasky}
101246145Shselasky
102246145Shselaskyvoid
103246145Shselaskysx_xunlock(struct sx *sx)
104246145Shselasky{
105246145Shselasky	sx->owned--;
106246145Shselasky}
107246145Shselasky
108246145Shselaskyint
109246145Shselaskysx_xlocked(struct sx *sx)
110246145Shselasky{
111246145Shselasky	return (sx->owned != 0);
112246145Shselasky}
113246145Shselasky
114246145Shselasky/*------------------------------------------------------------------------*
115246145Shselasky * Implementaiton of condition variable API
116246145Shselasky *------------------------------------------------------------------------*/
117246145Shselasky
118246145Shselaskyvoid
119246145Shselaskycv_init(struct cv *cv, const char *desc)
120246145Shselasky{
121246145Shselasky	cv->sleeping = 0;
122246145Shselasky}
123246145Shselasky
124246145Shselaskyvoid
125246145Shselaskycv_destroy(struct cv *cv)
126246145Shselasky{
127246145Shselasky	/* NOP */
128246145Shselasky}
129246145Shselasky
130246145Shselaskyvoid
131246145Shselaskycv_wait(struct cv *cv, struct mtx *mtx)
132246145Shselasky{
133246145Shselasky	cv_timedwait(cv, mtx, -1);
134246145Shselasky}
135246145Shselasky
136246145Shselaskyint
137246145Shselaskycv_timedwait(struct cv *cv, struct mtx *mtx, int timo)
138246145Shselasky{
139246145Shselasky	int start = ticks;
140246145Shselasky	int delta;
141291403Szbb	int time = 0;
142246145Shselasky
143246145Shselasky	if (cv->sleeping)
144246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
145246145Shselasky
146246145Shselasky	cv->sleeping = 1;
147246145Shselasky
148246145Shselasky	while (cv->sleeping) {
149246145Shselasky		if (timo >= 0) {
150246145Shselasky			delta = ticks - start;
151246145Shselasky			if (delta >= timo || delta < 0)
152246145Shselasky				break;
153246145Shselasky		}
154246145Shselasky		mtx_unlock(mtx);
155246145Shselasky
156246145Shselasky		usb_idle();
157246145Shselasky
158291403Szbb		if (++time >= (1000000 / hz)) {
159291403Szbb			time = 0;
160291403Szbb			callout_process(1);
161291403Szbb		}
162291403Szbb
163291403Szbb		/* Sleep for 1 us */
164291403Szbb		delay(1);
165291403Szbb
166246145Shselasky		mtx_lock(mtx);
167246145Shselasky	}
168246145Shselasky
169246145Shselasky	if (cv->sleeping) {
170246145Shselasky		cv->sleeping = 0;
171246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
172246145Shselasky	}
173246145Shselasky	return (0);
174246145Shselasky}
175246145Shselasky
176246145Shselaskyvoid
177246145Shselaskycv_signal(struct cv *cv)
178246145Shselasky{
179246145Shselasky	cv->sleeping = 0;
180246145Shselasky}
181246145Shselasky
182246145Shselaskyvoid
183246145Shselaskycv_broadcast(struct cv *cv)
184246145Shselasky{
185246145Shselasky	cv->sleeping = 0;
186246145Shselasky}
187246145Shselasky
188246145Shselasky/*------------------------------------------------------------------------*
189246145Shselasky * Implementation of callout API
190246145Shselasky *------------------------------------------------------------------------*/
191246145Shselasky
192246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *);
193246145Shselasky
194246145Shselaskyvolatile int ticks = 0;
195246145Shselasky
196246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
197246145Shselasky
198246145Shselaskystatic struct mtx mtx_callout;
199246145Shselaskystatic struct usb_proc_msg callout_msg[2];
200246145Shselasky
201246145Shselaskystatic void
202246145Shselaskycallout_system_init(void *arg)
203246145Shselasky{
204246145Shselasky	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
205246145Shselasky
206246145Shselasky	callout_msg[0].pm_callback = &callout_proc_msg;
207246145Shselasky	callout_msg[1].pm_callback = &callout_proc_msg;
208246145Shselasky}
209246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
210246145Shselasky
211246145Shselaskystatic void
212246145Shselaskycallout_callback(struct callout *c)
213246145Shselasky{
214246145Shselasky	mtx_lock(c->mtx);
215246145Shselasky
216246145Shselasky	mtx_lock(&mtx_callout);
217246145Shselasky	if (c->entry.le_prev != NULL) {
218246145Shselasky		LIST_REMOVE(c, entry);
219246145Shselasky		c->entry.le_prev = NULL;
220246145Shselasky	}
221246145Shselasky	mtx_unlock(&mtx_callout);
222246145Shselasky
223246145Shselasky	if (c->func)
224246145Shselasky		(c->func) (c->arg);
225246145Shselasky
226246145Shselasky	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
227246145Shselasky		mtx_unlock(c->mtx);
228246145Shselasky}
229246145Shselasky
230246145Shselaskyvoid
231246145Shselaskycallout_process(int timeout)
232246145Shselasky{
233246145Shselasky	ticks += timeout;
234246145Shselasky	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
235246145Shselasky}
236246145Shselasky
237246145Shselaskystatic void
238246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg)
239246145Shselasky{
240246145Shselasky	struct callout *c;
241246145Shselasky	int delta;
242246145Shselasky
243246145Shselaskyrepeat:
244246145Shselasky	mtx_lock(&mtx_callout);
245246145Shselasky
246246145Shselasky	LIST_FOREACH(c, &head_callout, entry) {
247246145Shselasky
248246145Shselasky		delta = c->timeout - ticks;
249246145Shselasky		if (delta < 0) {
250246145Shselasky			mtx_unlock(&mtx_callout);
251246145Shselasky
252246145Shselasky			callout_callback(c);
253246145Shselasky
254246145Shselasky			goto repeat;
255246145Shselasky		}
256246145Shselasky	}
257246145Shselasky	mtx_unlock(&mtx_callout);
258246145Shselasky}
259246145Shselasky
260246145Shselaskyvoid
261246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
262246145Shselasky{
263246145Shselasky	memset(c, 0, sizeof(*c));
264246145Shselasky
265246145Shselasky	if (mtx == NULL)
266246145Shselasky		mtx = &Giant;
267246145Shselasky
268246145Shselasky	c->mtx = mtx;
269246145Shselasky	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
270246145Shselasky}
271246145Shselasky
272246145Shselaskyvoid
273246145Shselaskycallout_reset(struct callout *c, int to_ticks,
274246145Shselasky    void (*func) (void *), void *arg)
275246145Shselasky{
276246145Shselasky	callout_stop(c);
277246145Shselasky
278246145Shselasky	c->func = func;
279246145Shselasky	c->arg = arg;
280246145Shselasky	c->timeout = ticks + to_ticks;
281246145Shselasky
282246145Shselasky	mtx_lock(&mtx_callout);
283246145Shselasky	LIST_INSERT_HEAD(&head_callout, c, entry);
284246145Shselasky	mtx_unlock(&mtx_callout);
285246145Shselasky}
286246145Shselasky
287246145Shselaskyvoid
288246145Shselaskycallout_stop(struct callout *c)
289246145Shselasky{
290246145Shselasky	mtx_lock(&mtx_callout);
291246145Shselasky
292246145Shselasky	if (c->entry.le_prev != NULL) {
293246145Shselasky		LIST_REMOVE(c, entry);
294246145Shselasky		c->entry.le_prev = NULL;
295246145Shselasky	}
296246145Shselasky	mtx_unlock(&mtx_callout);
297246145Shselasky
298246145Shselasky	c->func = NULL;
299246145Shselasky	c->arg = NULL;
300246145Shselasky}
301246145Shselasky
302246145Shselaskyvoid
303246145Shselaskycallout_drain(struct callout *c)
304246145Shselasky{
305246145Shselasky	if (c->mtx == NULL)
306246145Shselasky		return;			/* not initialised */
307246145Shselasky
308246145Shselasky	mtx_lock(c->mtx);
309246145Shselasky	callout_stop(c);
310246145Shselasky	mtx_unlock(c->mtx);
311246145Shselasky}
312246145Shselasky
313246145Shselaskyint
314246145Shselaskycallout_pending(struct callout *c)
315246145Shselasky{
316246145Shselasky	int retval;
317246145Shselasky
318246145Shselasky	mtx_lock(&mtx_callout);
319246145Shselasky	retval = (c->entry.le_prev != NULL);
320246145Shselasky	mtx_unlock(&mtx_callout);
321246145Shselasky
322246145Shselasky	return (retval);
323246145Shselasky}
324246145Shselasky
325246145Shselasky/*------------------------------------------------------------------------*
326246145Shselasky * Implementation of device API
327246145Shselasky *------------------------------------------------------------------------*/
328246145Shselasky
329246145Shselaskystatic const char unknown_string[] = { "unknown" };
330246145Shselasky
331246145Shselaskystatic TAILQ_HEAD(, module_data) module_head =
332246145Shselasky    TAILQ_HEAD_INITIALIZER(module_head);
333246145Shselasky
334246145Shselaskystatic uint8_t
335246145Shselaskydevclass_equal(const char *a, const char *b)
336246145Shselasky{
337246145Shselasky	char ta, tb;
338246145Shselasky
339246145Shselasky	if (a == b)
340246145Shselasky		return (1);
341246145Shselasky
342246145Shselasky	while (1) {
343246145Shselasky		ta = *a;
344246145Shselasky		tb = *b;
345246145Shselasky		if (ta != tb)
346246145Shselasky			return (0);
347246145Shselasky		if (ta == 0)
348246145Shselasky			break;
349246145Shselasky		a++;
350246145Shselasky		b++;
351246145Shselasky	}
352246145Shselasky	return (1);
353246145Shselasky}
354246145Shselasky
355246145Shselaskyint
356246145Shselaskybus_generic_resume(device_t dev)
357246145Shselasky{
358246145Shselasky	return (0);
359246145Shselasky}
360246145Shselasky
361246145Shselaskyint
362246145Shselaskybus_generic_shutdown(device_t dev)
363246145Shselasky{
364246145Shselasky	return (0);
365246145Shselasky}
366246145Shselasky
367246145Shselaskyint
368246145Shselaskybus_generic_suspend(device_t dev)
369246145Shselasky{
370246145Shselasky	return (0);
371246145Shselasky}
372246145Shselasky
373246145Shselaskyint
374246145Shselaskybus_generic_print_child(device_t dev, device_t child)
375246145Shselasky{
376246145Shselasky	return (0);
377246145Shselasky}
378246145Shselasky
379246145Shselaskyvoid
380246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver)
381246145Shselasky{
382246145Shselasky	return;
383246145Shselasky}
384246145Shselasky
385246145Shselaskydevice_t
386246145Shselaskydevice_get_parent(device_t dev)
387246145Shselasky{
388246145Shselasky	return (dev ? dev->dev_parent : NULL);
389246145Shselasky}
390246145Shselasky
391246145Shselaskyvoid
392266396Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter,
393266396Shselasky    driver_intr_t *fn, void *arg)
394246145Shselasky{
395266396Shselasky	dev->dev_irq_filter = filter;
396246145Shselasky	dev->dev_irq_fn = fn;
397246145Shselasky	dev->dev_irq_arg = arg;
398246145Shselasky}
399246145Shselasky
400246145Shselaskyvoid
401246145Shselaskydevice_run_interrupts(device_t parent)
402246145Shselasky{
403246145Shselasky	device_t child;
404246145Shselasky
405246145Shselasky	if (parent == NULL)
406246145Shselasky		return;
407246145Shselasky
408246145Shselasky	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
409266396Shselasky		int status;
410266396Shselasky		if (child->dev_irq_filter != NULL)
411266396Shselasky			status = child->dev_irq_filter(child->dev_irq_arg);
412266396Shselasky		else
413266396Shselasky			status = FILTER_SCHEDULE_THREAD;
414266396Shselasky
415266396Shselasky		if (status == FILTER_SCHEDULE_THREAD) {
416266396Shselasky			if (child->dev_irq_fn != NULL)
417266396Shselasky				(child->dev_irq_fn) (child->dev_irq_arg);
418266396Shselasky		}
419246145Shselasky	}
420246145Shselasky}
421246145Shselasky
422246145Shselaskyvoid
423246145Shselaskydevice_set_ivars(device_t dev, void *ivars)
424246145Shselasky{
425246145Shselasky	dev->dev_aux = ivars;
426246145Shselasky}
427246145Shselasky
428246145Shselaskyvoid   *
429246145Shselaskydevice_get_ivars(device_t dev)
430246145Shselasky{
431246145Shselasky	return (dev ? dev->dev_aux : NULL);
432246145Shselasky}
433246145Shselasky
434246145Shselaskyint
435246145Shselaskydevice_get_unit(device_t dev)
436246145Shselasky{
437246145Shselasky	return (dev ? dev->dev_unit : 0);
438246145Shselasky}
439246145Shselasky
440246145Shselaskyint
441246145Shselaskybus_generic_detach(device_t dev)
442246145Shselasky{
443246145Shselasky	device_t child;
444246145Shselasky	int error;
445246145Shselasky
446246145Shselasky	if (!dev->dev_attached)
447246145Shselasky		return (EBUSY);
448246145Shselasky
449246145Shselasky	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
450246145Shselasky		if ((error = device_detach(child)) != 0)
451246145Shselasky			return (error);
452246145Shselasky	}
453246145Shselasky	return (0);
454246145Shselasky}
455246145Shselasky
456246145Shselaskyconst char *
457246145Shselaskydevice_get_nameunit(device_t dev)
458246145Shselasky{
459246145Shselasky	if (dev && dev->dev_nameunit[0])
460246145Shselasky		return (dev->dev_nameunit);
461246145Shselasky
462246145Shselasky	return (unknown_string);
463246145Shselasky}
464246145Shselasky
465246145Shselaskystatic uint8_t
466246145Shselaskydevclass_create(devclass_t *dc_pp)
467246145Shselasky{
468246145Shselasky	if (dc_pp == NULL) {
469246145Shselasky		return (1);
470246145Shselasky	}
471246145Shselasky	if (dc_pp[0] == NULL) {
472246145Shselasky		dc_pp[0] = malloc(sizeof(**(dc_pp)),
473246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
474246145Shselasky
475246145Shselasky		if (dc_pp[0] == NULL) {
476246145Shselasky			return (1);
477246145Shselasky		}
478246145Shselasky	}
479246145Shselasky	return (0);
480246145Shselasky}
481246145Shselasky
482246145Shselaskystatic const struct module_data *
483246145Shselaskydevclass_find_create(const char *classname)
484246145Shselasky{
485246145Shselasky	const struct module_data *mod;
486246145Shselasky
487246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
488246145Shselasky		if (devclass_equal(mod->mod_name, classname)) {
489246145Shselasky			if (devclass_create(mod->devclass_pp)) {
490246145Shselasky				continue;
491246145Shselasky			}
492246145Shselasky			return (mod);
493246145Shselasky		}
494246145Shselasky	}
495246145Shselasky	return (NULL);
496246145Shselasky}
497246145Shselasky
498246145Shselaskystatic uint8_t
499246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev)
500246145Shselasky{
501246145Shselasky	device_t *pp_dev;
502246145Shselasky	device_t *end;
503246145Shselasky	uint8_t unit;
504246145Shselasky
505246145Shselasky	pp_dev = mod->devclass_pp[0]->dev_list;
506246145Shselasky	end = pp_dev + DEVCLASS_MAXUNIT;
507246145Shselasky	unit = 0;
508246145Shselasky
509246145Shselasky	while (pp_dev != end) {
510246145Shselasky		if (*pp_dev == NULL) {
511246145Shselasky			*pp_dev = dev;
512246145Shselasky			dev->dev_unit = unit;
513246145Shselasky			dev->dev_module = mod;
514246145Shselasky			snprintf(dev->dev_nameunit,
515246145Shselasky			    sizeof(dev->dev_nameunit),
516246145Shselasky			    "%s%d", device_get_name(dev), unit);
517246145Shselasky			return (0);
518246145Shselasky		}
519246145Shselasky		pp_dev++;
520246145Shselasky		unit++;
521246145Shselasky	}
522246145Shselasky	DPRINTF("Could not add device to devclass.\n");
523246145Shselasky	return (1);
524246145Shselasky}
525246145Shselasky
526246145Shselaskystatic void
527246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev)
528246145Shselasky{
529246145Shselasky	if (mod == NULL) {
530246145Shselasky		return;
531246145Shselasky	}
532246145Shselasky	mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL;
533246145Shselasky	dev->dev_module = NULL;
534246145Shselasky}
535246145Shselasky
536246145Shselaskystatic device_t
537246145Shselaskymake_device(device_t parent, const char *name)
538246145Shselasky{
539246145Shselasky	device_t dev = NULL;
540246145Shselasky	const struct module_data *mod = NULL;
541246145Shselasky
542246145Shselasky	if (name) {
543246145Shselasky
544246145Shselasky		mod = devclass_find_create(name);
545246145Shselasky
546246145Shselasky		if (!mod) {
547246145Shselasky
548246145Shselasky			DPRINTF("%s:%d:%s: can't find device "
549246145Shselasky			    "class %s\n", __FILE__, __LINE__,
550246145Shselasky			    __FUNCTION__, name);
551246145Shselasky
552246145Shselasky			goto done;
553246145Shselasky		}
554246145Shselasky	}
555246145Shselasky	dev = malloc(sizeof(*dev),
556246145Shselasky	    M_DEVBUF, M_WAITOK | M_ZERO);
557246145Shselasky
558246145Shselasky	if (dev == NULL)
559246145Shselasky		goto done;
560246145Shselasky
561246145Shselasky	dev->dev_parent = parent;
562246145Shselasky	TAILQ_INIT(&dev->dev_children);
563246145Shselasky
564246145Shselasky	if (name) {
565246145Shselasky		dev->dev_fixed_class = 1;
566246145Shselasky		if (devclass_add_device(mod, dev)) {
567246145Shselasky			goto error;
568246145Shselasky		}
569246145Shselasky	}
570246145Shselaskydone:
571246145Shselasky	return (dev);
572246145Shselasky
573246145Shselaskyerror:
574246145Shselasky	if (dev) {
575246145Shselasky		free(dev, M_DEVBUF);
576246145Shselasky	}
577246145Shselasky	return (NULL);
578246145Shselasky}
579246145Shselasky
580246145Shselaskydevice_t
581246145Shselaskydevice_add_child(device_t dev, const char *name, int unit)
582246145Shselasky{
583246145Shselasky	device_t child;
584246145Shselasky
585246145Shselasky	if (unit != -1) {
586246145Shselasky		device_printf(dev, "Unit is not -1\n");
587246145Shselasky	}
588246145Shselasky	child = make_device(dev, name);
589246145Shselasky	if (child == NULL) {
590246145Shselasky		device_printf(dev, "Could not add child '%s'\n", name);
591246145Shselasky		goto done;
592246145Shselasky	}
593246145Shselasky	if (dev == NULL) {
594246145Shselasky		/* no parent */
595246145Shselasky		goto done;
596246145Shselasky	}
597246145Shselasky	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
598246145Shselaskydone:
599246145Shselasky	return (child);
600246145Shselasky}
601246145Shselasky
602246145Shselaskyint
603246145Shselaskydevice_delete_child(device_t dev, device_t child)
604246145Shselasky{
605246145Shselasky	int error = 0;
606246145Shselasky	device_t grandchild;
607246145Shselasky
608246145Shselasky	/* remove children first */
609246145Shselasky
610246145Shselasky	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
611246145Shselasky		error = device_delete_child(child, grandchild);
612246145Shselasky		if (error) {
613246145Shselasky			device_printf(dev, "Error deleting child!\n");
614246145Shselasky			goto done;
615246145Shselasky		}
616246145Shselasky	}
617246145Shselasky
618246145Shselasky	error = device_detach(child);
619246145Shselasky
620246145Shselasky	if (error)
621246145Shselasky		goto done;
622246145Shselasky
623246145Shselasky	devclass_delete_device(child->dev_module, child);
624246145Shselasky
625246145Shselasky	if (dev != NULL) {
626246145Shselasky		/* remove child from parent */
627246145Shselasky		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
628246145Shselasky	}
629246145Shselasky	free(child, M_DEVBUF);
630246145Shselasky
631246145Shselaskydone:
632246145Shselasky	return (error);
633246145Shselasky}
634246145Shselasky
635246145Shselaskyint
636246145Shselaskydevice_delete_children(device_t dev)
637246145Shselasky{
638246145Shselasky	device_t child;
639246145Shselasky	int error = 0;
640246145Shselasky
641246145Shselasky	while ((child = TAILQ_FIRST(&dev->dev_children))) {
642246145Shselasky		error = device_delete_child(dev, child);
643246145Shselasky		if (error) {
644246145Shselasky			device_printf(dev, "Error deleting child!\n");
645246145Shselasky			break;
646246145Shselasky		}
647246145Shselasky	}
648246145Shselasky	return (error);
649246145Shselasky}
650246145Shselasky
651246145Shselaskyvoid
652246145Shselaskydevice_quiet(device_t dev)
653246145Shselasky{
654246145Shselasky	dev->dev_quiet = 1;
655246145Shselasky}
656246145Shselasky
657246145Shselaskyconst char *
658246145Shselaskydevice_get_desc(device_t dev)
659246145Shselasky{
660246145Shselasky	if (dev)
661246145Shselasky		return &(dev->dev_desc[0]);
662246145Shselasky	return (unknown_string);
663246145Shselasky}
664246145Shselasky
665246145Shselaskystatic int
666246145Shselaskydefault_method(void)
667246145Shselasky{
668246145Shselasky	/* do nothing */
669246145Shselasky	DPRINTF("Default method called\n");
670246145Shselasky	return (0);
671246145Shselasky}
672246145Shselasky
673246145Shselaskyvoid   *
674246145Shselaskydevice_get_method(device_t dev, const char *what)
675246145Shselasky{
676246145Shselasky	const struct device_method *mtod;
677246145Shselasky
678246145Shselasky	mtod = dev->dev_module->driver->methods;
679246145Shselasky	while (mtod->func != NULL) {
680246145Shselasky		if (devclass_equal(mtod->desc, what)) {
681246145Shselasky			return (mtod->func);
682246145Shselasky		}
683246145Shselasky		mtod++;
684246145Shselasky	}
685246145Shselasky	return ((void *)&default_method);
686246145Shselasky}
687246145Shselasky
688246145Shselaskyconst char *
689246145Shselaskydevice_get_name(device_t dev)
690246145Shselasky{
691246145Shselasky	if (dev == NULL)
692246145Shselasky		return (unknown_string);
693246145Shselasky
694246145Shselasky	return (dev->dev_module->driver->name);
695246145Shselasky}
696246145Shselasky
697246145Shselaskystatic int
698246145Shselaskydevice_allocate_softc(device_t dev)
699246145Shselasky{
700246145Shselasky	const struct module_data *mod;
701246145Shselasky
702246145Shselasky	mod = dev->dev_module;
703246145Shselasky
704246145Shselasky	if ((dev->dev_softc_alloc == 0) &&
705246145Shselasky	    (mod->driver->size != 0)) {
706246145Shselasky		dev->dev_sc = malloc(mod->driver->size,
707246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
708246145Shselasky
709246145Shselasky		if (dev->dev_sc == NULL)
710246145Shselasky			return (ENOMEM);
711246145Shselasky
712246145Shselasky		dev->dev_softc_alloc = 1;
713246145Shselasky	}
714246145Shselasky	return (0);
715246145Shselasky}
716246145Shselasky
717246145Shselaskyint
718246145Shselaskydevice_probe_and_attach(device_t dev)
719246145Shselasky{
720246145Shselasky	const struct module_data *mod;
721246145Shselasky	const char *bus_name_parent;
722246145Shselasky
723246145Shselasky	bus_name_parent = device_get_name(device_get_parent(dev));
724246145Shselasky
725246145Shselasky	if (dev->dev_attached)
726246145Shselasky		return (0);		/* fail-safe */
727246145Shselasky
728246145Shselasky	if (dev->dev_fixed_class) {
729246145Shselasky
730246145Shselasky		mod = dev->dev_module;
731246145Shselasky
732246145Shselasky		if (DEVICE_PROBE(dev) <= 0) {
733246145Shselasky
734246145Shselasky			if (device_allocate_softc(dev) == 0) {
735246145Shselasky
736246145Shselasky				if (DEVICE_ATTACH(dev) == 0) {
737246145Shselasky					/* success */
738246145Shselasky					dev->dev_attached = 1;
739246145Shselasky					return (0);
740246145Shselasky				}
741246145Shselasky			}
742246145Shselasky		}
743246145Shselasky		device_detach(dev);
744246145Shselasky
745246145Shselasky		goto error;
746246145Shselasky	}
747246145Shselasky	/*
748246145Shselasky         * Else find a module for our device, if any
749246145Shselasky         */
750246145Shselasky
751246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
752246145Shselasky		if (devclass_equal(mod->bus_name, bus_name_parent)) {
753246145Shselasky			if (devclass_create(mod->devclass_pp)) {
754246145Shselasky				continue;
755246145Shselasky			}
756246145Shselasky			if (devclass_add_device(mod, dev)) {
757246145Shselasky				continue;
758246145Shselasky			}
759246145Shselasky			if (DEVICE_PROBE(dev) <= 0) {
760246145Shselasky
761246145Shselasky				if (device_allocate_softc(dev) == 0) {
762246145Shselasky
763246145Shselasky					if (DEVICE_ATTACH(dev) == 0) {
764246145Shselasky						/* success */
765246145Shselasky						dev->dev_attached = 1;
766246145Shselasky						return (0);
767246145Shselasky					}
768246145Shselasky				}
769246145Shselasky			}
770246145Shselasky			/* else try next driver */
771246145Shselasky
772246145Shselasky			device_detach(dev);
773246145Shselasky		}
774246145Shselasky	}
775246145Shselasky
776246145Shselaskyerror:
777246145Shselasky	return (ENODEV);
778246145Shselasky}
779246145Shselasky
780246145Shselaskyint
781246145Shselaskydevice_detach(device_t dev)
782246145Shselasky{
783246145Shselasky	const struct module_data *mod = dev->dev_module;
784246145Shselasky	int error;
785246145Shselasky
786246145Shselasky	if (dev->dev_attached) {
787246145Shselasky
788246145Shselasky		error = DEVICE_DETACH(dev);
789246145Shselasky		if (error) {
790246145Shselasky			return error;
791246145Shselasky		}
792246145Shselasky		dev->dev_attached = 0;
793246145Shselasky	}
794246145Shselasky	device_set_softc(dev, NULL);
795246145Shselasky
796246145Shselasky	if (dev->dev_fixed_class == 0)
797246145Shselasky		devclass_delete_device(mod, dev);
798246145Shselasky
799246145Shselasky	return (0);
800246145Shselasky}
801246145Shselasky
802246145Shselaskyvoid
803246145Shselaskydevice_set_softc(device_t dev, void *softc)
804246145Shselasky{
805246145Shselasky	if (dev->dev_softc_alloc) {
806246145Shselasky		free(dev->dev_sc, M_DEVBUF);
807246145Shselasky		dev->dev_sc = NULL;
808246145Shselasky	}
809246145Shselasky	dev->dev_sc = softc;
810246145Shselasky	dev->dev_softc_alloc = 0;
811246145Shselasky}
812246145Shselasky
813246145Shselaskyvoid   *
814246145Shselaskydevice_get_softc(device_t dev)
815246145Shselasky{
816246145Shselasky	if (dev == NULL)
817246145Shselasky		return (NULL);
818246145Shselasky
819246145Shselasky	return (dev->dev_sc);
820246145Shselasky}
821246145Shselasky
822246145Shselaskyint
823246145Shselaskydevice_is_attached(device_t dev)
824246145Shselasky{
825246145Shselasky	return (dev->dev_attached);
826246145Shselasky}
827246145Shselasky
828246145Shselaskyvoid
829246145Shselaskydevice_set_desc(device_t dev, const char *desc)
830246145Shselasky{
831246145Shselasky	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
832246145Shselasky}
833246145Shselasky
834246145Shselaskyvoid
835246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc)
836246145Shselasky{
837246145Shselasky	device_set_desc(dev, desc);
838246145Shselasky}
839246145Shselasky
840246145Shselaskyvoid   *
841246145Shselaskydevclass_get_softc(devclass_t dc, int unit)
842246145Shselasky{
843246145Shselasky	return (device_get_softc(devclass_get_device(dc, unit)));
844246145Shselasky}
845246145Shselasky
846246145Shselaskyint
847246145Shselaskydevclass_get_maxunit(devclass_t dc)
848246145Shselasky{
849246145Shselasky	int max_unit = 0;
850246145Shselasky
851246145Shselasky	if (dc) {
852246145Shselasky		max_unit = DEVCLASS_MAXUNIT;
853246145Shselasky		while (max_unit--) {
854246145Shselasky			if (dc->dev_list[max_unit]) {
855246145Shselasky				break;
856246145Shselasky			}
857246145Shselasky		}
858246145Shselasky		max_unit++;
859246145Shselasky	}
860246145Shselasky	return (max_unit);
861246145Shselasky}
862246145Shselasky
863246145Shselaskydevice_t
864246145Shselaskydevclass_get_device(devclass_t dc, int unit)
865246145Shselasky{
866246145Shselasky	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
867246145Shselasky	    NULL : dc->dev_list[unit]);
868246145Shselasky}
869246145Shselasky
870246145Shselaskydevclass_t
871246145Shselaskydevclass_find(const char *classname)
872246145Shselasky{
873246145Shselasky	const struct module_data *mod;
874246145Shselasky
875246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
876246145Shselasky		if (devclass_equal(mod->mod_name, classname))
877246145Shselasky			return (mod->devclass_pp[0]);
878246145Shselasky	}
879246145Shselasky	return (NULL);
880246145Shselasky}
881246145Shselasky
882246145Shselaskyvoid
883246145Shselaskymodule_register(void *data)
884246145Shselasky{
885246145Shselasky	struct module_data *mdata = data;
886246145Shselasky
887246145Shselasky	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
888246145Shselasky}
889246145Shselasky
890246145Shselasky/*------------------------------------------------------------------------*
891246145Shselasky * System startup
892246145Shselasky *------------------------------------------------------------------------*/
893246145Shselasky
894246145Shselaskystatic void
895246145Shselaskysysinit_run(const void **ppdata)
896246145Shselasky{
897246145Shselasky	const struct sysinit *psys;
898246145Shselasky
899246145Shselasky	while ((psys = *ppdata) != NULL) {
900246145Shselasky		(psys->func) (psys->data);
901246145Shselasky		ppdata++;
902246145Shselasky	}
903246145Shselasky}
904246145Shselasky
905246145Shselasky/*------------------------------------------------------------------------*
906246145Shselasky * USB process API
907246145Shselasky *------------------------------------------------------------------------*/
908246145Shselasky
909246145Shselaskystatic int usb_do_process(struct usb_process *);
910246145Shselaskystatic int usb_proc_level = -1;
911246145Shselaskystatic struct mtx usb_proc_mtx;
912246145Shselasky
913246145Shselaskyvoid
914246145Shselaskyusb_idle(void)
915246145Shselasky{
916246145Shselasky	int old_level = usb_proc_level;
917246145Shselasky	int old_giant = Giant.owned;
918246145Shselasky	int worked;
919246145Shselasky
920246145Shselasky	device_run_interrupts(usb_pci_root);
921246145Shselasky
922246145Shselasky	do {
923246145Shselasky		worked = 0;
924246145Shselasky		Giant.owned = 0;
925246145Shselasky
926246145Shselasky		while (++usb_proc_level < USB_PROC_MAX)
927246145Shselasky			worked |= usb_do_process(usb_process + usb_proc_level);
928246145Shselasky
929246145Shselasky		usb_proc_level = old_level;
930246145Shselasky		Giant.owned = old_giant;
931246145Shselasky
932246145Shselasky	} while (worked);
933246145Shselasky}
934246145Shselasky
935246145Shselaskyvoid
936246145Shselaskyusb_init(void)
937246145Shselasky{
938246145Shselasky	sysinit_run(sysinit_data);
939246145Shselasky}
940246145Shselasky
941246145Shselaskyvoid
942246145Shselaskyusb_uninit(void)
943246145Shselasky{
944246145Shselasky	sysinit_run(sysuninit_data);
945246145Shselasky}
946246145Shselasky
947246145Shselaskystatic void
948246145Shselaskyusb_process_init_sub(struct usb_process *up)
949246145Shselasky{
950246145Shselasky	TAILQ_INIT(&up->up_qhead);
951246145Shselasky
952246145Shselasky	cv_init(&up->up_cv, "-");
953246145Shselasky	cv_init(&up->up_drain, "usbdrain");
954246145Shselasky
955246145Shselasky	up->up_mtx = &usb_proc_mtx;
956246145Shselasky}
957246145Shselasky
958246145Shselaskystatic void
959246145Shselaskyusb_process_init(void *arg)
960246145Shselasky{
961246145Shselasky	uint8_t x;
962246145Shselasky
963246145Shselasky	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
964246145Shselasky
965246145Shselasky	for (x = 0; x != USB_PROC_MAX; x++)
966246145Shselasky		usb_process_init_sub(&usb_process[x]);
967246145Shselasky
968246145Shselasky}
969246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
970246145Shselasky
971246145Shselaskystatic int
972246145Shselaskyusb_do_process(struct usb_process *up)
973246145Shselasky{
974246145Shselasky	struct usb_proc_msg *pm;
975246145Shselasky	int worked = 0;
976246145Shselasky
977246145Shselasky	mtx_lock(&usb_proc_mtx);
978246145Shselasky
979246145Shselaskyrepeat:
980246145Shselasky	pm = TAILQ_FIRST(&up->up_qhead);
981246145Shselasky
982246145Shselasky	if (pm != NULL) {
983246145Shselasky
984246145Shselasky		worked = 1;
985246145Shselasky
986246145Shselasky		(pm->pm_callback) (pm);
987246145Shselasky
988246145Shselasky		if (pm == TAILQ_FIRST(&up->up_qhead)) {
989246145Shselasky			/* nothing changed */
990246145Shselasky			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
991246145Shselasky			pm->pm_qentry.tqe_prev = NULL;
992246145Shselasky		}
993246145Shselasky		goto repeat;
994246145Shselasky	}
995246145Shselasky	mtx_unlock(&usb_proc_mtx);
996246145Shselasky
997246145Shselasky	return (worked);
998246145Shselasky}
999246145Shselasky
1000246145Shselaskyvoid   *
1001246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
1002246145Shselasky{
1003246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1004246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1005246145Shselasky	struct usb_proc_msg *pm2;
1006246145Shselasky	usb_size_t d;
1007246145Shselasky	uint8_t t;
1008246145Shselasky
1009246145Shselasky	t = 0;
1010246145Shselasky
1011246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1012246145Shselasky		t |= 1;
1013246145Shselasky	}
1014246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1015246145Shselasky		t |= 2;
1016246145Shselasky	}
1017246145Shselasky	if (t == 0) {
1018246145Shselasky		/*
1019246145Shselasky		 * No entries are queued. Queue "pm0" and use the existing
1020246145Shselasky		 * message number.
1021246145Shselasky		 */
1022246145Shselasky		pm2 = pm0;
1023246145Shselasky	} else if (t == 1) {
1024246145Shselasky		/* Check if we need to increment the message number. */
1025246145Shselasky		if (pm0->pm_num == up->up_msg_num) {
1026246145Shselasky			up->up_msg_num++;
1027246145Shselasky		}
1028246145Shselasky		pm2 = pm1;
1029246145Shselasky	} else if (t == 2) {
1030246145Shselasky		/* Check if we need to increment the message number. */
1031246145Shselasky		if (pm1->pm_num == up->up_msg_num) {
1032246145Shselasky			up->up_msg_num++;
1033246145Shselasky		}
1034246145Shselasky		pm2 = pm0;
1035246145Shselasky	} else if (t == 3) {
1036246145Shselasky		/*
1037246145Shselasky		 * Both entries are queued. Re-queue the entry closest to
1038246145Shselasky		 * the end.
1039246145Shselasky		 */
1040246145Shselasky		d = (pm1->pm_num - pm0->pm_num);
1041246145Shselasky
1042246145Shselasky		/* Check sign after subtraction */
1043246145Shselasky		if (d & 0x80000000) {
1044246145Shselasky			pm2 = pm0;
1045246145Shselasky		} else {
1046246145Shselasky			pm2 = pm1;
1047246145Shselasky		}
1048246145Shselasky
1049246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1050246145Shselasky	} else {
1051246145Shselasky		pm2 = NULL;		/* panic - should not happen */
1052246145Shselasky	}
1053246145Shselasky
1054246145Shselasky	/* Put message last on queue */
1055246145Shselasky
1056246145Shselasky	pm2->pm_num = up->up_msg_num;
1057246145Shselasky	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1058246145Shselasky
1059246145Shselasky	return (pm2);
1060246145Shselasky}
1061246145Shselasky
1062246145Shselasky/*------------------------------------------------------------------------*
1063246145Shselasky *	usb_proc_is_gone
1064246145Shselasky *
1065246145Shselasky * Return values:
1066246145Shselasky *    0: USB process is running
1067246145Shselasky * Else: USB process is tearing down
1068246145Shselasky *------------------------------------------------------------------------*/
1069246145Shselaskyuint8_t
1070246145Shselaskyusb_proc_is_gone(struct usb_process *up)
1071246145Shselasky{
1072246145Shselasky	return (0);
1073246145Shselasky}
1074246145Shselasky
1075246145Shselasky/*------------------------------------------------------------------------*
1076246145Shselasky *	usb_proc_mwait
1077246145Shselasky *
1078246145Shselasky * This function will return when the USB process message pointed to
1079246145Shselasky * by "pm" is no longer on a queue. This function must be called
1080246145Shselasky * having "usb_proc_mtx" locked.
1081246145Shselasky *------------------------------------------------------------------------*/
1082246145Shselaskyvoid
1083246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1084246145Shselasky{
1085246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1086246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1087246145Shselasky
1088246145Shselasky	/* Just remove the messages from the queue. */
1089246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1090246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1091246145Shselasky		pm0->pm_qentry.tqe_prev = NULL;
1092246145Shselasky	}
1093246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1094246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1095246145Shselasky		pm1->pm_qentry.tqe_prev = NULL;
1096246145Shselasky	}
1097246145Shselasky}
1098246145Shselasky
1099246145Shselasky/*------------------------------------------------------------------------*
1100246145Shselasky * SYSTEM attach
1101246145Shselasky *------------------------------------------------------------------------*/
1102246145Shselasky
1103266882Shselasky#ifdef USB_PCI_PROBE_LIST
1104246145Shselaskystatic device_method_t pci_methods[] = {
1105246145Shselasky	DEVMETHOD_END
1106246145Shselasky};
1107246145Shselasky
1108246145Shselaskystatic driver_t pci_driver = {
1109246145Shselasky	.name = "pci",
1110246145Shselasky	.methods = pci_methods,
1111246145Shselasky};
1112246145Shselasky
1113246145Shselaskystatic devclass_t pci_devclass;
1114246145Shselasky
1115246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1116246145Shselasky
1117246145Shselaskystatic const char *usb_pci_devices[] = {
1118266882Shselasky	USB_PCI_PROBE_LIST
1119246145Shselasky};
1120246145Shselasky
1121246145Shselasky#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1122246145Shselasky
1123246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX];
1124246145Shselasky
1125246145Shselaskystatic void
1126246145Shselaskyusb_pci_mod_load(void *arg)
1127246145Shselasky{
1128246145Shselasky	uint32_t x;
1129246145Shselasky
1130246145Shselasky	usb_pci_root = device_add_child(NULL, "pci", -1);
1131246145Shselasky	if (usb_pci_root == NULL)
1132246145Shselasky		return;
1133246145Shselasky
1134246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1135246145Shselasky		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1136246145Shselasky		if (usb_pci_dev[x] == NULL)
1137246145Shselasky			continue;
1138246145Shselasky		if (device_probe_and_attach(usb_pci_dev[x])) {
1139246145Shselasky			device_printf(usb_pci_dev[x],
1140246145Shselasky			    "WARNING: Probe and attach failed!\n");
1141246145Shselasky		}
1142246145Shselasky	}
1143246145Shselasky}
1144246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1145246145Shselasky
1146246145Shselaskystatic void
1147246145Shselaskyusb_pci_mod_unload(void *arg)
1148246145Shselasky{
1149246145Shselasky	uint32_t x;
1150246145Shselasky
1151246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1152246145Shselasky		if (usb_pci_dev[x]) {
1153246145Shselasky			device_detach(usb_pci_dev[x]);
1154246145Shselasky			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1155246145Shselasky		}
1156246145Shselasky	}
1157246145Shselasky	if (usb_pci_root)
1158246145Shselasky		device_delete_child(NULL, usb_pci_root);
1159246145Shselasky}
1160246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1161266882Shselasky#endif
1162246145Shselasky
1163246145Shselasky/*------------------------------------------------------------------------*
1164246145Shselasky * MALLOC API
1165246145Shselasky *------------------------------------------------------------------------*/
1166246145Shselasky
1167266882Shselasky#ifndef HAVE_MALLOC
1168246145Shselasky#define	USB_POOL_ALIGN 8
1169246145Shselasky
1170246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1171246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE;
1172246145Shselaskystatic uint32_t usb_pool_entries;
1173246145Shselasky
1174246145Shselaskystruct malloc_hdr {
1175246145Shselasky	TAILQ_ENTRY(malloc_hdr) entry;
1176246145Shselasky	uint32_t size;
1177246145Shselasky} __aligned(USB_POOL_ALIGN);
1178246145Shselasky
1179246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head =
1180246145Shselasky	TAILQ_HEAD_INITIALIZER(malloc_head);
1181246145Shselasky
1182246145Shselaskyvoid   *
1183246145Shselaskyusb_malloc(unsigned long size)
1184246145Shselasky{
1185246145Shselasky	struct malloc_hdr *hdr;
1186246145Shselasky
1187246145Shselasky	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1188246145Shselasky	size += sizeof(struct malloc_hdr);
1189246145Shselasky
1190246145Shselasky	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1191246145Shselasky		if (hdr->size == size)
1192246145Shselasky			break;
1193246145Shselasky	}
1194246145Shselasky
1195246145Shselasky	if (hdr) {
1196266882Shselasky		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1197246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1198246145Shselasky
1199246145Shselasky		TAILQ_REMOVE(&malloc_head, hdr, entry);
1200246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1201246145Shselasky		return (hdr + 1);
1202246145Shselasky	}
1203246145Shselasky	if (usb_pool_rem >= size) {
1204246145Shselasky		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1205246145Shselasky		hdr->size = size;
1206246145Shselasky
1207246145Shselasky		usb_pool_rem -= size;
1208246145Shselasky		usb_pool_entries++;
1209246145Shselasky
1210266882Shselasky		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1211246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1212246145Shselasky
1213246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1214246145Shselasky		return (hdr + 1);
1215246145Shselasky	}
1216246145Shselasky	return (NULL);
1217246145Shselasky}
1218246145Shselasky
1219246145Shselaskyvoid
1220246145Shselaskyusb_free(void *arg)
1221246145Shselasky{
1222246145Shselasky	struct malloc_hdr *hdr;
1223246145Shselasky
1224246145Shselasky	if (arg == NULL)
1225246145Shselasky		return;
1226246145Shselasky
1227246145Shselasky	hdr = arg;
1228246145Shselasky	hdr--;
1229246145Shselasky
1230246145Shselasky	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1231246145Shselasky}
1232266882Shselasky#endif
1233246145Shselasky
1234246145Shselaskychar   *
1235246145Shselaskyusb_strdup(const char *str)
1236246145Shselasky{
1237246145Shselasky	char *tmp;
1238246145Shselasky	int len;
1239246145Shselasky
1240246145Shselasky	len = 1 + strlen(str);
1241246145Shselasky
1242266882Shselasky	tmp = malloc(len,XXX,XXX);
1243246145Shselasky	if (tmp == NULL)
1244246145Shselasky		return (NULL);
1245246145Shselasky
1246246145Shselasky	memcpy(tmp, str, len);
1247246145Shselasky	return (tmp);
1248246145Shselasky}
1249