1246145Shselasky/* $FreeBSD$ */
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;
141246145Shselasky
142246145Shselasky	if (cv->sleeping)
143246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
144246145Shselasky
145246145Shselasky	cv->sleeping = 1;
146246145Shselasky
147246145Shselasky	while (cv->sleeping) {
148246145Shselasky		if (timo >= 0) {
149246145Shselasky			delta = ticks - start;
150246145Shselasky			if (delta >= timo || delta < 0)
151246145Shselasky				break;
152246145Shselasky		}
153246145Shselasky		mtx_unlock(mtx);
154246145Shselasky
155246145Shselasky		usb_idle();
156246145Shselasky
157246145Shselasky		mtx_lock(mtx);
158246145Shselasky	}
159246145Shselasky
160246145Shselasky	if (cv->sleeping) {
161246145Shselasky		cv->sleeping = 0;
162246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
163246145Shselasky	}
164246145Shselasky	return (0);
165246145Shselasky}
166246145Shselasky
167246145Shselaskyvoid
168246145Shselaskycv_signal(struct cv *cv)
169246145Shselasky{
170246145Shselasky	cv->sleeping = 0;
171246145Shselasky}
172246145Shselasky
173246145Shselaskyvoid
174246145Shselaskycv_broadcast(struct cv *cv)
175246145Shselasky{
176246145Shselasky	cv->sleeping = 0;
177246145Shselasky}
178246145Shselasky
179246145Shselasky/*------------------------------------------------------------------------*
180246145Shselasky * Implementation of callout API
181246145Shselasky *------------------------------------------------------------------------*/
182246145Shselasky
183246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *);
184246145Shselasky
185246145Shselaskyvolatile int ticks = 0;
186246145Shselasky
187246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
188246145Shselasky
189246145Shselaskystatic struct mtx mtx_callout;
190246145Shselaskystatic struct usb_proc_msg callout_msg[2];
191246145Shselasky
192246145Shselaskystatic void
193246145Shselaskycallout_system_init(void *arg)
194246145Shselasky{
195246145Shselasky	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
196246145Shselasky
197246145Shselasky	callout_msg[0].pm_callback = &callout_proc_msg;
198246145Shselasky	callout_msg[1].pm_callback = &callout_proc_msg;
199246145Shselasky}
200246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
201246145Shselasky
202246145Shselaskystatic void
203246145Shselaskycallout_callback(struct callout *c)
204246145Shselasky{
205246145Shselasky	mtx_lock(c->mtx);
206246145Shselasky
207246145Shselasky	mtx_lock(&mtx_callout);
208246145Shselasky	if (c->entry.le_prev != NULL) {
209246145Shselasky		LIST_REMOVE(c, entry);
210246145Shselasky		c->entry.le_prev = NULL;
211246145Shselasky	}
212246145Shselasky	mtx_unlock(&mtx_callout);
213246145Shselasky
214246145Shselasky	if (c->func)
215246145Shselasky		(c->func) (c->arg);
216246145Shselasky
217246145Shselasky	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
218246145Shselasky		mtx_unlock(c->mtx);
219246145Shselasky}
220246145Shselasky
221246145Shselaskyvoid
222246145Shselaskycallout_process(int timeout)
223246145Shselasky{
224246145Shselasky	ticks += timeout;
225246145Shselasky	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
226246145Shselasky}
227246145Shselasky
228246145Shselaskystatic void
229246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg)
230246145Shselasky{
231246145Shselasky	struct callout *c;
232246145Shselasky	int delta;
233246145Shselasky
234246145Shselaskyrepeat:
235246145Shselasky	mtx_lock(&mtx_callout);
236246145Shselasky
237246145Shselasky	LIST_FOREACH(c, &head_callout, entry) {
238246145Shselasky
239246145Shselasky		delta = c->timeout - ticks;
240246145Shselasky		if (delta < 0) {
241246145Shselasky			mtx_unlock(&mtx_callout);
242246145Shselasky
243246145Shselasky			callout_callback(c);
244246145Shselasky
245246145Shselasky			goto repeat;
246246145Shselasky		}
247246145Shselasky	}
248246145Shselasky	mtx_unlock(&mtx_callout);
249246145Shselasky}
250246145Shselasky
251246145Shselaskyvoid
252246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
253246145Shselasky{
254246145Shselasky	memset(c, 0, sizeof(*c));
255246145Shselasky
256246145Shselasky	if (mtx == NULL)
257246145Shselasky		mtx = &Giant;
258246145Shselasky
259246145Shselasky	c->mtx = mtx;
260246145Shselasky	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
261246145Shselasky}
262246145Shselasky
263246145Shselaskyvoid
264246145Shselaskycallout_reset(struct callout *c, int to_ticks,
265246145Shselasky    void (*func) (void *), void *arg)
266246145Shselasky{
267246145Shselasky	callout_stop(c);
268246145Shselasky
269246145Shselasky	c->func = func;
270246145Shselasky	c->arg = arg;
271246145Shselasky	c->timeout = ticks + to_ticks;
272246145Shselasky
273246145Shselasky	mtx_lock(&mtx_callout);
274246145Shselasky	LIST_INSERT_HEAD(&head_callout, c, entry);
275246145Shselasky	mtx_unlock(&mtx_callout);
276246145Shselasky}
277246145Shselasky
278246145Shselaskyvoid
279246145Shselaskycallout_stop(struct callout *c)
280246145Shselasky{
281246145Shselasky	mtx_lock(&mtx_callout);
282246145Shselasky
283246145Shselasky	if (c->entry.le_prev != NULL) {
284246145Shselasky		LIST_REMOVE(c, entry);
285246145Shselasky		c->entry.le_prev = NULL;
286246145Shselasky	}
287246145Shselasky	mtx_unlock(&mtx_callout);
288246145Shselasky
289246145Shselasky	c->func = NULL;
290246145Shselasky	c->arg = NULL;
291246145Shselasky}
292246145Shselasky
293246145Shselaskyvoid
294246145Shselaskycallout_drain(struct callout *c)
295246145Shselasky{
296246145Shselasky	if (c->mtx == NULL)
297246145Shselasky		return;			/* not initialised */
298246145Shselasky
299246145Shselasky	mtx_lock(c->mtx);
300246145Shselasky	callout_stop(c);
301246145Shselasky	mtx_unlock(c->mtx);
302246145Shselasky}
303246145Shselasky
304246145Shselaskyint
305246145Shselaskycallout_pending(struct callout *c)
306246145Shselasky{
307246145Shselasky	int retval;
308246145Shselasky
309246145Shselasky	mtx_lock(&mtx_callout);
310246145Shselasky	retval = (c->entry.le_prev != NULL);
311246145Shselasky	mtx_unlock(&mtx_callout);
312246145Shselasky
313246145Shselasky	return (retval);
314246145Shselasky}
315246145Shselasky
316246145Shselasky/*------------------------------------------------------------------------*
317246145Shselasky * Implementation of device API
318246145Shselasky *------------------------------------------------------------------------*/
319246145Shselasky
320246145Shselaskystatic const char unknown_string[] = { "unknown" };
321246145Shselasky
322246145Shselaskystatic TAILQ_HEAD(, module_data) module_head =
323246145Shselasky    TAILQ_HEAD_INITIALIZER(module_head);
324246145Shselasky
325246145Shselaskystatic uint8_t
326246145Shselaskydevclass_equal(const char *a, const char *b)
327246145Shselasky{
328246145Shselasky	char ta, tb;
329246145Shselasky
330246145Shselasky	if (a == b)
331246145Shselasky		return (1);
332246145Shselasky
333246145Shselasky	while (1) {
334246145Shselasky		ta = *a;
335246145Shselasky		tb = *b;
336246145Shselasky		if (ta != tb)
337246145Shselasky			return (0);
338246145Shselasky		if (ta == 0)
339246145Shselasky			break;
340246145Shselasky		a++;
341246145Shselasky		b++;
342246145Shselasky	}
343246145Shselasky	return (1);
344246145Shselasky}
345246145Shselasky
346246145Shselaskyint
347246145Shselaskybus_generic_resume(device_t dev)
348246145Shselasky{
349246145Shselasky	return (0);
350246145Shselasky}
351246145Shselasky
352246145Shselaskyint
353246145Shselaskybus_generic_shutdown(device_t dev)
354246145Shselasky{
355246145Shselasky	return (0);
356246145Shselasky}
357246145Shselasky
358246145Shselaskyint
359246145Shselaskybus_generic_suspend(device_t dev)
360246145Shselasky{
361246145Shselasky	return (0);
362246145Shselasky}
363246145Shselasky
364246145Shselaskyint
365246145Shselaskybus_generic_print_child(device_t dev, device_t child)
366246145Shselasky{
367246145Shselasky	return (0);
368246145Shselasky}
369246145Shselasky
370246145Shselaskyvoid
371246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver)
372246145Shselasky{
373246145Shselasky	return;
374246145Shselasky}
375246145Shselasky
376246145Shselaskydevice_t
377246145Shselaskydevice_get_parent(device_t dev)
378246145Shselasky{
379246145Shselasky	return (dev ? dev->dev_parent : NULL);
380246145Shselasky}
381246145Shselasky
382246145Shselaskyvoid
383246145Shselaskydevice_set_interrupt(device_t dev, intr_fn_t *fn, void *arg)
384246145Shselasky{
385246145Shselasky	dev->dev_irq_fn = fn;
386246145Shselasky	dev->dev_irq_arg = arg;
387246145Shselasky}
388246145Shselasky
389246145Shselaskyvoid
390246145Shselaskydevice_run_interrupts(device_t parent)
391246145Shselasky{
392246145Shselasky	device_t child;
393246145Shselasky
394246145Shselasky	if (parent == NULL)
395246145Shselasky		return;
396246145Shselasky
397246145Shselasky	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
398246145Shselasky		if (child->dev_irq_fn != NULL)
399246145Shselasky			(child->dev_irq_fn) (child->dev_irq_arg);
400246145Shselasky	}
401246145Shselasky}
402246145Shselasky
403246145Shselaskyvoid
404246145Shselaskydevice_set_ivars(device_t dev, void *ivars)
405246145Shselasky{
406246145Shselasky	dev->dev_aux = ivars;
407246145Shselasky}
408246145Shselasky
409246145Shselaskyvoid   *
410246145Shselaskydevice_get_ivars(device_t dev)
411246145Shselasky{
412246145Shselasky	return (dev ? dev->dev_aux : NULL);
413246145Shselasky}
414246145Shselasky
415246145Shselaskyint
416246145Shselaskydevice_get_unit(device_t dev)
417246145Shselasky{
418246145Shselasky	return (dev ? dev->dev_unit : 0);
419246145Shselasky}
420246145Shselasky
421246145Shselaskyint
422246145Shselaskybus_generic_detach(device_t dev)
423246145Shselasky{
424246145Shselasky	device_t child;
425246145Shselasky	int error;
426246145Shselasky
427246145Shselasky	if (!dev->dev_attached)
428246145Shselasky		return (EBUSY);
429246145Shselasky
430246145Shselasky	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
431246145Shselasky		if ((error = device_detach(child)) != 0)
432246145Shselasky			return (error);
433246145Shselasky	}
434246145Shselasky	return (0);
435246145Shselasky}
436246145Shselasky
437246145Shselaskyconst char *
438246145Shselaskydevice_get_nameunit(device_t dev)
439246145Shselasky{
440246145Shselasky	if (dev && dev->dev_nameunit[0])
441246145Shselasky		return (dev->dev_nameunit);
442246145Shselasky
443246145Shselasky	return (unknown_string);
444246145Shselasky}
445246145Shselasky
446246145Shselaskystatic uint8_t
447246145Shselaskydevclass_create(devclass_t *dc_pp)
448246145Shselasky{
449246145Shselasky	if (dc_pp == NULL) {
450246145Shselasky		return (1);
451246145Shselasky	}
452246145Shselasky	if (dc_pp[0] == NULL) {
453246145Shselasky		dc_pp[0] = malloc(sizeof(**(dc_pp)),
454246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
455246145Shselasky
456246145Shselasky		if (dc_pp[0] == NULL) {
457246145Shselasky			return (1);
458246145Shselasky		}
459246145Shselasky	}
460246145Shselasky	return (0);
461246145Shselasky}
462246145Shselasky
463246145Shselaskystatic const struct module_data *
464246145Shselaskydevclass_find_create(const char *classname)
465246145Shselasky{
466246145Shselasky	const struct module_data *mod;
467246145Shselasky
468246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
469246145Shselasky		if (devclass_equal(mod->mod_name, classname)) {
470246145Shselasky			if (devclass_create(mod->devclass_pp)) {
471246145Shselasky				continue;
472246145Shselasky			}
473246145Shselasky			return (mod);
474246145Shselasky		}
475246145Shselasky	}
476246145Shselasky	return (NULL);
477246145Shselasky}
478246145Shselasky
479246145Shselaskystatic uint8_t
480246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev)
481246145Shselasky{
482246145Shselasky	device_t *pp_dev;
483246145Shselasky	device_t *end;
484246145Shselasky	uint8_t unit;
485246145Shselasky
486246145Shselasky	pp_dev = mod->devclass_pp[0]->dev_list;
487246145Shselasky	end = pp_dev + DEVCLASS_MAXUNIT;
488246145Shselasky	unit = 0;
489246145Shselasky
490246145Shselasky	while (pp_dev != end) {
491246145Shselasky		if (*pp_dev == NULL) {
492246145Shselasky			*pp_dev = dev;
493246145Shselasky			dev->dev_unit = unit;
494246145Shselasky			dev->dev_module = mod;
495246145Shselasky			snprintf(dev->dev_nameunit,
496246145Shselasky			    sizeof(dev->dev_nameunit),
497246145Shselasky			    "%s%d", device_get_name(dev), unit);
498246145Shselasky			return (0);
499246145Shselasky		}
500246145Shselasky		pp_dev++;
501246145Shselasky		unit++;
502246145Shselasky	}
503246145Shselasky	DPRINTF("Could not add device to devclass.\n");
504246145Shselasky	return (1);
505246145Shselasky}
506246145Shselasky
507246145Shselaskystatic void
508246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev)
509246145Shselasky{
510246145Shselasky	if (mod == NULL) {
511246145Shselasky		return;
512246145Shselasky	}
513246145Shselasky	mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL;
514246145Shselasky	dev->dev_module = NULL;
515246145Shselasky}
516246145Shselasky
517246145Shselaskystatic device_t
518246145Shselaskymake_device(device_t parent, const char *name)
519246145Shselasky{
520246145Shselasky	device_t dev = NULL;
521246145Shselasky	const struct module_data *mod = NULL;
522246145Shselasky
523246145Shselasky	if (name) {
524246145Shselasky
525246145Shselasky		mod = devclass_find_create(name);
526246145Shselasky
527246145Shselasky		if (!mod) {
528246145Shselasky
529246145Shselasky			DPRINTF("%s:%d:%s: can't find device "
530246145Shselasky			    "class %s\n", __FILE__, __LINE__,
531246145Shselasky			    __FUNCTION__, name);
532246145Shselasky
533246145Shselasky			goto done;
534246145Shselasky		}
535246145Shselasky	}
536246145Shselasky	dev = malloc(sizeof(*dev),
537246145Shselasky	    M_DEVBUF, M_WAITOK | M_ZERO);
538246145Shselasky
539246145Shselasky	if (dev == NULL)
540246145Shselasky		goto done;
541246145Shselasky
542246145Shselasky	dev->dev_parent = parent;
543246145Shselasky	TAILQ_INIT(&dev->dev_children);
544246145Shselasky
545246145Shselasky	if (name) {
546246145Shselasky		dev->dev_fixed_class = 1;
547246145Shselasky		if (devclass_add_device(mod, dev)) {
548246145Shselasky			goto error;
549246145Shselasky		}
550246145Shselasky	}
551246145Shselaskydone:
552246145Shselasky	return (dev);
553246145Shselasky
554246145Shselaskyerror:
555246145Shselasky	if (dev) {
556246145Shselasky		free(dev, M_DEVBUF);
557246145Shselasky	}
558246145Shselasky	return (NULL);
559246145Shselasky}
560246145Shselasky
561246145Shselaskydevice_t
562246145Shselaskydevice_add_child(device_t dev, const char *name, int unit)
563246145Shselasky{
564246145Shselasky	device_t child;
565246145Shselasky
566246145Shselasky	if (unit != -1) {
567246145Shselasky		device_printf(dev, "Unit is not -1\n");
568246145Shselasky	}
569246145Shselasky	child = make_device(dev, name);
570246145Shselasky	if (child == NULL) {
571246145Shselasky		device_printf(dev, "Could not add child '%s'\n", name);
572246145Shselasky		goto done;
573246145Shselasky	}
574246145Shselasky	if (dev == NULL) {
575246145Shselasky		/* no parent */
576246145Shselasky		goto done;
577246145Shselasky	}
578246145Shselasky	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
579246145Shselaskydone:
580246145Shselasky	return (child);
581246145Shselasky}
582246145Shselasky
583246145Shselaskyint
584246145Shselaskydevice_delete_child(device_t dev, device_t child)
585246145Shselasky{
586246145Shselasky	int error = 0;
587246145Shselasky	device_t grandchild;
588246145Shselasky
589246145Shselasky	/* remove children first */
590246145Shselasky
591246145Shselasky	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
592246145Shselasky		error = device_delete_child(child, grandchild);
593246145Shselasky		if (error) {
594246145Shselasky			device_printf(dev, "Error deleting child!\n");
595246145Shselasky			goto done;
596246145Shselasky		}
597246145Shselasky	}
598246145Shselasky
599246145Shselasky	error = device_detach(child);
600246145Shselasky
601246145Shselasky	if (error)
602246145Shselasky		goto done;
603246145Shselasky
604246145Shselasky	devclass_delete_device(child->dev_module, child);
605246145Shselasky
606246145Shselasky	if (dev != NULL) {
607246145Shselasky		/* remove child from parent */
608246145Shselasky		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
609246145Shselasky	}
610246145Shselasky	free(child, M_DEVBUF);
611246145Shselasky
612246145Shselaskydone:
613246145Shselasky	return (error);
614246145Shselasky}
615246145Shselasky
616246145Shselaskyint
617246145Shselaskydevice_delete_children(device_t dev)
618246145Shselasky{
619246145Shselasky	device_t child;
620246145Shselasky	int error = 0;
621246145Shselasky
622246145Shselasky	while ((child = TAILQ_FIRST(&dev->dev_children))) {
623246145Shselasky		error = device_delete_child(dev, child);
624246145Shselasky		if (error) {
625246145Shselasky			device_printf(dev, "Error deleting child!\n");
626246145Shselasky			break;
627246145Shselasky		}
628246145Shselasky	}
629246145Shselasky	return (error);
630246145Shselasky}
631246145Shselasky
632246145Shselaskyvoid
633246145Shselaskydevice_quiet(device_t dev)
634246145Shselasky{
635246145Shselasky	dev->dev_quiet = 1;
636246145Shselasky}
637246145Shselasky
638246145Shselaskyconst char *
639246145Shselaskydevice_get_desc(device_t dev)
640246145Shselasky{
641246145Shselasky	if (dev)
642246145Shselasky		return &(dev->dev_desc[0]);
643246145Shselasky	return (unknown_string);
644246145Shselasky}
645246145Shselasky
646246145Shselaskystatic int
647246145Shselaskydefault_method(void)
648246145Shselasky{
649246145Shselasky	/* do nothing */
650246145Shselasky	DPRINTF("Default method called\n");
651246145Shselasky	return (0);
652246145Shselasky}
653246145Shselasky
654246145Shselaskyvoid   *
655246145Shselaskydevice_get_method(device_t dev, const char *what)
656246145Shselasky{
657246145Shselasky	const struct device_method *mtod;
658246145Shselasky
659246145Shselasky	mtod = dev->dev_module->driver->methods;
660246145Shselasky	while (mtod->func != NULL) {
661246145Shselasky		if (devclass_equal(mtod->desc, what)) {
662246145Shselasky			return (mtod->func);
663246145Shselasky		}
664246145Shselasky		mtod++;
665246145Shselasky	}
666246145Shselasky	return ((void *)&default_method);
667246145Shselasky}
668246145Shselasky
669246145Shselaskyconst char *
670246145Shselaskydevice_get_name(device_t dev)
671246145Shselasky{
672246145Shselasky	if (dev == NULL)
673246145Shselasky		return (unknown_string);
674246145Shselasky
675246145Shselasky	return (dev->dev_module->driver->name);
676246145Shselasky}
677246145Shselasky
678246145Shselaskystatic int
679246145Shselaskydevice_allocate_softc(device_t dev)
680246145Shselasky{
681246145Shselasky	const struct module_data *mod;
682246145Shselasky
683246145Shselasky	mod = dev->dev_module;
684246145Shselasky
685246145Shselasky	if ((dev->dev_softc_alloc == 0) &&
686246145Shselasky	    (mod->driver->size != 0)) {
687246145Shselasky		dev->dev_sc = malloc(mod->driver->size,
688246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
689246145Shselasky
690246145Shselasky		if (dev->dev_sc == NULL)
691246145Shselasky			return (ENOMEM);
692246145Shselasky
693246145Shselasky		dev->dev_softc_alloc = 1;
694246145Shselasky	}
695246145Shselasky	return (0);
696246145Shselasky}
697246145Shselasky
698246145Shselaskyint
699246145Shselaskydevice_probe_and_attach(device_t dev)
700246145Shselasky{
701246145Shselasky	const struct module_data *mod;
702246145Shselasky	const char *bus_name_parent;
703246145Shselasky
704246145Shselasky	bus_name_parent = device_get_name(device_get_parent(dev));
705246145Shselasky
706246145Shselasky	if (dev->dev_attached)
707246145Shselasky		return (0);		/* fail-safe */
708246145Shselasky
709246145Shselasky	if (dev->dev_fixed_class) {
710246145Shselasky
711246145Shselasky		mod = dev->dev_module;
712246145Shselasky
713246145Shselasky		if (DEVICE_PROBE(dev) <= 0) {
714246145Shselasky
715246145Shselasky			if (device_allocate_softc(dev) == 0) {
716246145Shselasky
717246145Shselasky				if (DEVICE_ATTACH(dev) == 0) {
718246145Shselasky					/* success */
719246145Shselasky					dev->dev_attached = 1;
720246145Shselasky					return (0);
721246145Shselasky				}
722246145Shselasky			}
723246145Shselasky		}
724246145Shselasky		device_detach(dev);
725246145Shselasky
726246145Shselasky		goto error;
727246145Shselasky	}
728246145Shselasky	/*
729246145Shselasky         * Else find a module for our device, if any
730246145Shselasky         */
731246145Shselasky
732246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
733246145Shselasky		if (devclass_equal(mod->bus_name, bus_name_parent)) {
734246145Shselasky			if (devclass_create(mod->devclass_pp)) {
735246145Shselasky				continue;
736246145Shselasky			}
737246145Shselasky			if (devclass_add_device(mod, dev)) {
738246145Shselasky				continue;
739246145Shselasky			}
740246145Shselasky			if (DEVICE_PROBE(dev) <= 0) {
741246145Shselasky
742246145Shselasky				if (device_allocate_softc(dev) == 0) {
743246145Shselasky
744246145Shselasky					if (DEVICE_ATTACH(dev) == 0) {
745246145Shselasky						/* success */
746246145Shselasky						dev->dev_attached = 1;
747246145Shselasky						return (0);
748246145Shselasky					}
749246145Shselasky				}
750246145Shselasky			}
751246145Shselasky			/* else try next driver */
752246145Shselasky
753246145Shselasky			device_detach(dev);
754246145Shselasky		}
755246145Shselasky	}
756246145Shselasky
757246145Shselaskyerror:
758246145Shselasky	return (ENODEV);
759246145Shselasky}
760246145Shselasky
761246145Shselaskyint
762246145Shselaskydevice_detach(device_t dev)
763246145Shselasky{
764246145Shselasky	const struct module_data *mod = dev->dev_module;
765246145Shselasky	int error;
766246145Shselasky
767246145Shselasky	if (dev->dev_attached) {
768246145Shselasky
769246145Shselasky		error = DEVICE_DETACH(dev);
770246145Shselasky		if (error) {
771246145Shselasky			return error;
772246145Shselasky		}
773246145Shselasky		dev->dev_attached = 0;
774246145Shselasky	}
775246145Shselasky	device_set_softc(dev, NULL);
776246145Shselasky
777246145Shselasky	if (dev->dev_fixed_class == 0)
778246145Shselasky		devclass_delete_device(mod, dev);
779246145Shselasky
780246145Shselasky	return (0);
781246145Shselasky}
782246145Shselasky
783246145Shselaskyvoid
784246145Shselaskydevice_set_softc(device_t dev, void *softc)
785246145Shselasky{
786246145Shselasky	if (dev->dev_softc_alloc) {
787246145Shselasky		free(dev->dev_sc, M_DEVBUF);
788246145Shselasky		dev->dev_sc = NULL;
789246145Shselasky	}
790246145Shselasky	dev->dev_sc = softc;
791246145Shselasky	dev->dev_softc_alloc = 0;
792246145Shselasky}
793246145Shselasky
794246145Shselaskyvoid   *
795246145Shselaskydevice_get_softc(device_t dev)
796246145Shselasky{
797246145Shselasky	if (dev == NULL)
798246145Shselasky		return (NULL);
799246145Shselasky
800246145Shselasky	return (dev->dev_sc);
801246145Shselasky}
802246145Shselasky
803246145Shselaskyint
804246145Shselaskydevice_is_attached(device_t dev)
805246145Shselasky{
806246145Shselasky	return (dev->dev_attached);
807246145Shselasky}
808246145Shselasky
809246145Shselaskyvoid
810246145Shselaskydevice_set_desc(device_t dev, const char *desc)
811246145Shselasky{
812246145Shselasky	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
813246145Shselasky}
814246145Shselasky
815246145Shselaskyvoid
816246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc)
817246145Shselasky{
818246145Shselasky	device_set_desc(dev, desc);
819246145Shselasky}
820246145Shselasky
821246145Shselaskyvoid   *
822246145Shselaskydevclass_get_softc(devclass_t dc, int unit)
823246145Shselasky{
824246145Shselasky	return (device_get_softc(devclass_get_device(dc, unit)));
825246145Shselasky}
826246145Shselasky
827246145Shselaskyint
828246145Shselaskydevclass_get_maxunit(devclass_t dc)
829246145Shselasky{
830246145Shselasky	int max_unit = 0;
831246145Shselasky
832246145Shselasky	if (dc) {
833246145Shselasky		max_unit = DEVCLASS_MAXUNIT;
834246145Shselasky		while (max_unit--) {
835246145Shselasky			if (dc->dev_list[max_unit]) {
836246145Shselasky				break;
837246145Shselasky			}
838246145Shselasky		}
839246145Shselasky		max_unit++;
840246145Shselasky	}
841246145Shselasky	return (max_unit);
842246145Shselasky}
843246145Shselasky
844246145Shselaskydevice_t
845246145Shselaskydevclass_get_device(devclass_t dc, int unit)
846246145Shselasky{
847246145Shselasky	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
848246145Shselasky	    NULL : dc->dev_list[unit]);
849246145Shselasky}
850246145Shselasky
851246145Shselaskydevclass_t
852246145Shselaskydevclass_find(const char *classname)
853246145Shselasky{
854246145Shselasky	const struct module_data *mod;
855246145Shselasky
856246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
857246145Shselasky		if (devclass_equal(mod->mod_name, classname))
858246145Shselasky			return (mod->devclass_pp[0]);
859246145Shselasky	}
860246145Shselasky	return (NULL);
861246145Shselasky}
862246145Shselasky
863246145Shselaskyvoid
864246145Shselaskymodule_register(void *data)
865246145Shselasky{
866246145Shselasky	struct module_data *mdata = data;
867246145Shselasky
868246145Shselasky	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
869246145Shselasky}
870246145Shselasky
871246145Shselasky/*------------------------------------------------------------------------*
872246145Shselasky * System startup
873246145Shselasky *------------------------------------------------------------------------*/
874246145Shselasky
875246145Shselaskystatic void
876246145Shselaskysysinit_run(const void **ppdata)
877246145Shselasky{
878246145Shselasky	const struct sysinit *psys;
879246145Shselasky
880246145Shselasky	while ((psys = *ppdata) != NULL) {
881246145Shselasky		(psys->func) (psys->data);
882246145Shselasky		ppdata++;
883246145Shselasky	}
884246145Shselasky}
885246145Shselasky
886246145Shselasky/*------------------------------------------------------------------------*
887246145Shselasky * USB process API
888246145Shselasky *------------------------------------------------------------------------*/
889246145Shselasky
890246145Shselaskystatic int usb_do_process(struct usb_process *);
891246145Shselaskystatic int usb_proc_level = -1;
892246145Shselaskystatic struct mtx usb_proc_mtx;
893246145Shselasky
894246145Shselaskyvoid
895246145Shselaskyusb_idle(void)
896246145Shselasky{
897246145Shselasky	int old_level = usb_proc_level;
898246145Shselasky	int old_giant = Giant.owned;
899246145Shselasky	int worked;
900246145Shselasky
901246145Shselasky	device_run_interrupts(usb_pci_root);
902246145Shselasky
903246145Shselasky	do {
904246145Shselasky		worked = 0;
905246145Shselasky		Giant.owned = 0;
906246145Shselasky
907246145Shselasky		while (++usb_proc_level < USB_PROC_MAX)
908246145Shselasky			worked |= usb_do_process(usb_process + usb_proc_level);
909246145Shselasky
910246145Shselasky		usb_proc_level = old_level;
911246145Shselasky		Giant.owned = old_giant;
912246145Shselasky
913246145Shselasky	} while (worked);
914246145Shselasky}
915246145Shselasky
916246145Shselaskyvoid
917246145Shselaskyusb_init(void)
918246145Shselasky{
919246145Shselasky	sysinit_run(sysinit_data);
920246145Shselasky}
921246145Shselasky
922246145Shselaskyvoid
923246145Shselaskyusb_uninit(void)
924246145Shselasky{
925246145Shselasky	sysinit_run(sysuninit_data);
926246145Shselasky}
927246145Shselasky
928246145Shselaskystatic void
929246145Shselaskyusb_process_init_sub(struct usb_process *up)
930246145Shselasky{
931246145Shselasky	TAILQ_INIT(&up->up_qhead);
932246145Shselasky
933246145Shselasky	cv_init(&up->up_cv, "-");
934246145Shselasky	cv_init(&up->up_drain, "usbdrain");
935246145Shselasky
936246145Shselasky	up->up_mtx = &usb_proc_mtx;
937246145Shselasky}
938246145Shselasky
939246145Shselaskystatic void
940246145Shselaskyusb_process_init(void *arg)
941246145Shselasky{
942246145Shselasky	uint8_t x;
943246145Shselasky
944246145Shselasky	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
945246145Shselasky
946246145Shselasky	for (x = 0; x != USB_PROC_MAX; x++)
947246145Shselasky		usb_process_init_sub(&usb_process[x]);
948246145Shselasky
949246145Shselasky}
950246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
951246145Shselasky
952246145Shselaskystatic int
953246145Shselaskyusb_do_process(struct usb_process *up)
954246145Shselasky{
955246145Shselasky	struct usb_proc_msg *pm;
956246145Shselasky	int worked = 0;
957246145Shselasky
958246145Shselasky	mtx_lock(&usb_proc_mtx);
959246145Shselasky
960246145Shselaskyrepeat:
961246145Shselasky	pm = TAILQ_FIRST(&up->up_qhead);
962246145Shselasky
963246145Shselasky	if (pm != NULL) {
964246145Shselasky
965246145Shselasky		worked = 1;
966246145Shselasky
967246145Shselasky		(pm->pm_callback) (pm);
968246145Shselasky
969246145Shselasky		if (pm == TAILQ_FIRST(&up->up_qhead)) {
970246145Shselasky			/* nothing changed */
971246145Shselasky			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
972246145Shselasky			pm->pm_qentry.tqe_prev = NULL;
973246145Shselasky		}
974246145Shselasky		goto repeat;
975246145Shselasky	}
976246145Shselasky	mtx_unlock(&usb_proc_mtx);
977246145Shselasky
978246145Shselasky	return (worked);
979246145Shselasky}
980246145Shselasky
981246145Shselaskyvoid   *
982246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
983246145Shselasky{
984246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
985246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
986246145Shselasky	struct usb_proc_msg *pm2;
987246145Shselasky	usb_size_t d;
988246145Shselasky	uint8_t t;
989246145Shselasky
990246145Shselasky	t = 0;
991246145Shselasky
992246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
993246145Shselasky		t |= 1;
994246145Shselasky	}
995246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
996246145Shselasky		t |= 2;
997246145Shselasky	}
998246145Shselasky	if (t == 0) {
999246145Shselasky		/*
1000246145Shselasky		 * No entries are queued. Queue "pm0" and use the existing
1001246145Shselasky		 * message number.
1002246145Shselasky		 */
1003246145Shselasky		pm2 = pm0;
1004246145Shselasky	} else if (t == 1) {
1005246145Shselasky		/* Check if we need to increment the message number. */
1006246145Shselasky		if (pm0->pm_num == up->up_msg_num) {
1007246145Shselasky			up->up_msg_num++;
1008246145Shselasky		}
1009246145Shselasky		pm2 = pm1;
1010246145Shselasky	} else if (t == 2) {
1011246145Shselasky		/* Check if we need to increment the message number. */
1012246145Shselasky		if (pm1->pm_num == up->up_msg_num) {
1013246145Shselasky			up->up_msg_num++;
1014246145Shselasky		}
1015246145Shselasky		pm2 = pm0;
1016246145Shselasky	} else if (t == 3) {
1017246145Shselasky		/*
1018246145Shselasky		 * Both entries are queued. Re-queue the entry closest to
1019246145Shselasky		 * the end.
1020246145Shselasky		 */
1021246145Shselasky		d = (pm1->pm_num - pm0->pm_num);
1022246145Shselasky
1023246145Shselasky		/* Check sign after subtraction */
1024246145Shselasky		if (d & 0x80000000) {
1025246145Shselasky			pm2 = pm0;
1026246145Shselasky		} else {
1027246145Shselasky			pm2 = pm1;
1028246145Shselasky		}
1029246145Shselasky
1030246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1031246145Shselasky	} else {
1032246145Shselasky		pm2 = NULL;		/* panic - should not happen */
1033246145Shselasky	}
1034246145Shselasky
1035246145Shselasky	/* Put message last on queue */
1036246145Shselasky
1037246145Shselasky	pm2->pm_num = up->up_msg_num;
1038246145Shselasky	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1039246145Shselasky
1040246145Shselasky	return (pm2);
1041246145Shselasky}
1042246145Shselasky
1043246145Shselasky/*------------------------------------------------------------------------*
1044246145Shselasky *	usb_proc_is_gone
1045246145Shselasky *
1046246145Shselasky * Return values:
1047246145Shselasky *    0: USB process is running
1048246145Shselasky * Else: USB process is tearing down
1049246145Shselasky *------------------------------------------------------------------------*/
1050246145Shselaskyuint8_t
1051246145Shselaskyusb_proc_is_gone(struct usb_process *up)
1052246145Shselasky{
1053246145Shselasky	return (0);
1054246145Shselasky}
1055246145Shselasky
1056246145Shselasky/*------------------------------------------------------------------------*
1057246145Shselasky *	usb_proc_mwait
1058246145Shselasky *
1059246145Shselasky * This function will return when the USB process message pointed to
1060246145Shselasky * by "pm" is no longer on a queue. This function must be called
1061246145Shselasky * having "usb_proc_mtx" locked.
1062246145Shselasky *------------------------------------------------------------------------*/
1063246145Shselaskyvoid
1064246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1065246145Shselasky{
1066246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1067246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1068246145Shselasky
1069246145Shselasky	/* Just remove the messages from the queue. */
1070246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1071246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1072246145Shselasky		pm0->pm_qentry.tqe_prev = NULL;
1073246145Shselasky	}
1074246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1075246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1076246145Shselasky		pm1->pm_qentry.tqe_prev = NULL;
1077246145Shselasky	}
1078246145Shselasky}
1079246145Shselasky
1080246145Shselasky/*------------------------------------------------------------------------*
1081246145Shselasky * SYSTEM attach
1082246145Shselasky *------------------------------------------------------------------------*/
1083246145Shselasky
1084246145Shselaskystatic device_method_t pci_methods[] = {
1085246145Shselasky	DEVMETHOD_END
1086246145Shselasky};
1087246145Shselasky
1088246145Shselaskystatic driver_t pci_driver = {
1089246145Shselasky	.name = "pci",
1090246145Shselasky	.methods = pci_methods,
1091246145Shselasky};
1092246145Shselasky
1093246145Shselaskystatic devclass_t pci_devclass;
1094246145Shselasky
1095246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1096246145Shselasky
1097246145Shselaskystatic const char *usb_pci_devices[] = {
1098246145Shselasky#ifdef USB_PROBE_LIST
1099246145Shselasky	USB_PROBE_LIST
1100246145Shselasky#endif
1101246145Shselasky};
1102246145Shselasky
1103246145Shselasky#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1104246145Shselasky
1105246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX];
1106246145Shselasky
1107246145Shselaskystatic void
1108246145Shselaskyusb_pci_mod_load(void *arg)
1109246145Shselasky{
1110246145Shselasky	uint32_t x;
1111246145Shselasky
1112246145Shselasky	usb_pci_root = device_add_child(NULL, "pci", -1);
1113246145Shselasky	if (usb_pci_root == NULL)
1114246145Shselasky		return;
1115246145Shselasky
1116246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1117246145Shselasky		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1118246145Shselasky		if (usb_pci_dev[x] == NULL)
1119246145Shselasky			continue;
1120246145Shselasky		if (device_probe_and_attach(usb_pci_dev[x])) {
1121246145Shselasky			device_printf(usb_pci_dev[x],
1122246145Shselasky			    "WARNING: Probe and attach failed!\n");
1123246145Shselasky		}
1124246145Shselasky	}
1125246145Shselasky}
1126246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1127246145Shselasky
1128246145Shselaskystatic void
1129246145Shselaskyusb_pci_mod_unload(void *arg)
1130246145Shselasky{
1131246145Shselasky	uint32_t x;
1132246145Shselasky
1133246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1134246145Shselasky		if (usb_pci_dev[x]) {
1135246145Shselasky			device_detach(usb_pci_dev[x]);
1136246145Shselasky			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1137246145Shselasky		}
1138246145Shselasky	}
1139246145Shselasky	if (usb_pci_root)
1140246145Shselasky		device_delete_child(NULL, usb_pci_root);
1141246145Shselasky}
1142246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1143246145Shselasky
1144246145Shselasky/*------------------------------------------------------------------------*
1145246145Shselasky * MALLOC API
1146246145Shselasky *------------------------------------------------------------------------*/
1147246145Shselasky
1148246145Shselasky#define	USB_POOL_ALIGN 8
1149246145Shselasky
1150246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1151246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE;
1152246145Shselaskystatic uint32_t usb_pool_entries;
1153246145Shselasky
1154246145Shselaskystruct malloc_hdr {
1155246145Shselasky	TAILQ_ENTRY(malloc_hdr) entry;
1156246145Shselasky	uint32_t size;
1157246145Shselasky} __aligned(USB_POOL_ALIGN);
1158246145Shselasky
1159246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head =
1160246145Shselasky	TAILQ_HEAD_INITIALIZER(malloc_head);
1161246145Shselasky
1162246145Shselaskyvoid   *
1163246145Shselaskyusb_malloc(unsigned long size)
1164246145Shselasky{
1165246145Shselasky	struct malloc_hdr *hdr;
1166246145Shselasky
1167246145Shselasky	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1168246145Shselasky	size += sizeof(struct malloc_hdr);
1169246145Shselasky
1170246145Shselasky	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1171246145Shselasky		if (hdr->size == size)
1172246145Shselasky			break;
1173246145Shselasky	}
1174246145Shselasky
1175246145Shselasky	if (hdr) {
1176246145Shselasky		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1177246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1178246145Shselasky
1179246145Shselasky		TAILQ_REMOVE(&malloc_head, hdr, entry);
1180246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1181246145Shselasky		return (hdr + 1);
1182246145Shselasky	}
1183246145Shselasky	if (usb_pool_rem >= size) {
1184246145Shselasky		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1185246145Shselasky		hdr->size = size;
1186246145Shselasky
1187246145Shselasky		usb_pool_rem -= size;
1188246145Shselasky		usb_pool_entries++;
1189246145Shselasky
1190246145Shselasky		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1191246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1192246145Shselasky
1193246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1194246145Shselasky		return (hdr + 1);
1195246145Shselasky	}
1196246145Shselasky	return (NULL);
1197246145Shselasky}
1198246145Shselasky
1199246145Shselaskyvoid
1200246145Shselaskyusb_free(void *arg)
1201246145Shselasky{
1202246145Shselasky	struct malloc_hdr *hdr;
1203246145Shselasky
1204246145Shselasky	if (arg == NULL)
1205246145Shselasky		return;
1206246145Shselasky
1207246145Shselasky	hdr = arg;
1208246145Shselasky	hdr--;
1209246145Shselasky
1210246145Shselasky	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1211246145Shselasky}
1212246145Shselasky
1213246145Shselaskychar   *
1214246145Shselaskyusb_strdup(const char *str)
1215246145Shselasky{
1216246145Shselasky	char *tmp;
1217246145Shselasky	int len;
1218246145Shselasky
1219246145Shselasky	len = 1 + strlen(str);
1220246145Shselasky
1221246145Shselasky	tmp = usb_malloc(len);
1222246145Shselasky	if (tmp == NULL)
1223246145Shselasky		return (NULL);
1224246145Shselasky
1225246145Shselasky	memcpy(tmp, str, len);
1226246145Shselasky	return (tmp);
1227246145Shselasky}
1228