1139804Simp/* $FreeBSD$ */
2126324Sjhb/*-
3126324Sjhb * Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
4126324Sjhb *
5126324Sjhb * Redistribution and use in source and binary forms, with or without
6126324Sjhb * modification, are permitted provided that the following conditions
7126324Sjhb * are met:
8126324Sjhb * 1. Redistributions of source code must retain the above copyright
9126324Sjhb *    notice, this list of conditions and the following disclaimer.
10126324Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11126324Sjhb *    notice, this list of conditions and the following disclaimer in the
12126324Sjhb *    documentation and/or other materials provided with the distribution.
13126324Sjhb *
14126324Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15126324Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16126324Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17126324Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18126324Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19126324Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20126324Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21126324Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22126324Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23126324Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24126324Sjhb * SUCH DAMAGE.
25126324Sjhb */
26126324Sjhb
27126324Sjhb#include <bsd_global.h>
28126324Sjhb
29126324Sjhbstruct usb_process usb_process[USB_PROC_MAX];
30126324Sjhb
31126324Sjhbstatic device_t usb_pci_root;
32126324Sjhb
33126324Sjhb/*------------------------------------------------------------------------*
34126324Sjhb * Implementation of mutex API
35126324Sjhb *------------------------------------------------------------------------*/
36126324Sjhb
37126324Sjhbstruct mtx Giant;
38126324Sjhb
39126324Sjhbstatic void
40126324Sjhbmtx_system_init(void *arg)
41126324Sjhb{
42126324Sjhb	mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE);
43126324Sjhb}
44126324SjhbSYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL);
45126324Sjhb
46126324Sjhbvoid
47126324Sjhbmtx_init(struct mtx *mtx, const char *name, const char *type, int opt)
48126324Sjhb{
49126324Sjhb	mtx->owned = 0;
50126324Sjhb	mtx->parent = mtx;
51126324Sjhb}
52126324Sjhb
53126324Sjhbvoid
54126324Sjhbmtx_lock(struct mtx *mtx)
55126324Sjhb{
56126324Sjhb	mtx = mtx->parent;
57126324Sjhb	mtx->owned++;
58126324Sjhb}
59126324Sjhb
60126324Sjhbvoid
61126324Sjhbmtx_unlock(struct mtx *mtx)
62126324Sjhb{
63126324Sjhb	mtx = mtx->parent;
64126324Sjhb	mtx->owned--;
65154936Sjhb}
66154936Sjhb
67170640Sjeffint
68154936Sjhbmtx_owned(struct mtx *mtx)
69126324Sjhb{
70126324Sjhb	mtx = mtx->parent;
71126324Sjhb	return (mtx->owned != 0);
72126324Sjhb}
73126324Sjhb
74126324Sjhbvoid
75126324Sjhbmtx_destroy(struct mtx *mtx)
76177372Sjeff{
77126324Sjhb	/* NOP */
78126324Sjhb}
79126324Sjhb
80131259Sjhb/*------------------------------------------------------------------------*
81126324Sjhb * Implementation of shared/exclusive mutex API
82169666Sjeff *------------------------------------------------------------------------*/
83169666Sjeff
84154936Sjhbvoid
85154936Sjhbsx_init_flags(struct sx *sx, const char *name, int flags)
86154936Sjhb{
87154936Sjhb	sx->owned = 0;
88126324Sjhb}
89126324Sjhb
90126324Sjhbvoid
91126324Sjhbsx_destroy(struct sx *sx)
92126324Sjhb{
93126324Sjhb	/* NOP */
94126324Sjhb}
95126324Sjhb
96126324Sjhbvoid
97126324Sjhbsx_xlock(struct sx *sx)
98126324Sjhb{
99126324Sjhb	sx->owned++;
100165272Skmacy}
101126324Sjhb
102126324Sjhbvoid
103126324Sjhbsx_xunlock(struct sx *sx)
104126324Sjhb{
105126324Sjhb	sx->owned--;
106126324Sjhb}
107126324Sjhb
108126324Sjhbint
109126324Sjhbsx_xlocked(struct sx *sx)
110126324Sjhb{
111126324Sjhb	return (sx->owned != 0);
112126324Sjhb}
113126324Sjhb
114126324Sjhb/*------------------------------------------------------------------------*
115126324Sjhb * Implementaiton of condition variable API
116126324Sjhb *------------------------------------------------------------------------*/
117126324Sjhb
118126324Sjhbvoid
119126324Sjhbcv_init(struct cv *cv, const char *desc)
120165272Skmacy{
121126324Sjhb	cv->sleeping = 0;
122126324Sjhb}
123126324Sjhb
124136445Sjhbvoid
125134013Sjhbcv_destroy(struct cv *cv)
126164325Spjd{
127126324Sjhb	/* NOP */
128126324Sjhb}
129126324Sjhb
130126324Sjhbvoid
131126324Sjhbcv_wait(struct cv *cv, struct mtx *mtx)
132126324Sjhb{
133131259Sjhb	cv_timedwait(cv, mtx, -1);
134131259Sjhb}
135131259Sjhb
136131259Sjhbint
137126324Sjhbcv_timedwait(struct cv *cv, struct mtx *mtx, int timo)
138126324Sjhb{
139131259Sjhb	int start = ticks;
140131259Sjhb	int delta;
141131259Sjhb
142131259Sjhb	if (cv->sleeping)
143131259Sjhb		return (EWOULDBLOCK);	/* not allowed */
144131259Sjhb
145131259Sjhb	cv->sleeping = 1;
146177372Sjeff
147177372Sjeff	while (cv->sleeping) {
148177372Sjeff		if (timo >= 0) {
149131259Sjhb			delta = ticks - start;
150126324Sjhb			if (delta >= timo || delta < 0)
151169666Sjeff				break;
152126324Sjhb		}
153126324Sjhb		mtx_unlock(mtx);
154126324Sjhb
155126324Sjhb		usb_idle();
156177085Sjeff
157165272Skmacy		mtx_lock(mtx);
158126324Sjhb	}
159169666Sjeff
160169666Sjeff	if (cv->sleeping) {
161169666Sjeff		cv->sleeping = 0;
162169666Sjeff		return (EWOULDBLOCK);	/* not allowed */
163181334Sjhb	}
164169666Sjeff	return (0);
165177085Sjeff}
166126324Sjhb
167126324Sjhbvoid
168126324Sjhbcv_signal(struct cv *cv)
169126324Sjhb{
170126324Sjhb	cv->sleeping = 0;
171126324Sjhb}
172126324Sjhb
173126324Sjhbvoid
174126324Sjhbcv_broadcast(struct cv *cv)
175131259Sjhb{
176131259Sjhb	cv->sleeping = 0;
177131259Sjhb}
178131259Sjhb
179126324Sjhb/*------------------------------------------------------------------------*
180126324Sjhb * Implementation of callout API
181126324Sjhb *------------------------------------------------------------------------*/
182126324Sjhb
183126324Sjhbstatic void callout_proc_msg(struct usb_proc_msg *);
184176258Sjhb
185131259Sjhbvolatile int ticks = 0;
186131259Sjhb
187131259Sjhbstatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
188131259Sjhb
189131259Sjhbstatic struct mtx mtx_callout;
190131259Sjhbstatic struct usb_proc_msg callout_msg[2];
191131259Sjhb
192131259Sjhbstatic void
193131259Sjhbcallout_system_init(void *arg)
194131259Sjhb{
195131259Sjhb	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
196126324Sjhb
197169666Sjeff	callout_msg[0].pm_callback = &callout_proc_msg;
198169666Sjeff	callout_msg[1].pm_callback = &callout_proc_msg;
199169666Sjeff}
200169666SjeffSYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
201169666Sjeff
202169666Sjeffstatic void
203169666Sjeffcallout_callback(struct callout *c)
204126324Sjhb{
205126324Sjhb	mtx_lock(c->mtx);
206126324Sjhb
207126324Sjhb	mtx_lock(&mtx_callout);
208169666Sjeff	if (c->entry.le_prev != NULL) {
209126324Sjhb		LIST_REMOVE(c, entry);
210126324Sjhb		c->entry.le_prev = NULL;
211126324Sjhb	}
212126324Sjhb	mtx_unlock(&mtx_callout);
213126324Sjhb
214169666Sjeff	if (c->func)
215126324Sjhb		(c->func) (c->arg);
216126324Sjhb
217126324Sjhb	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
218126324Sjhb		mtx_unlock(c->mtx);
219126324Sjhb}
220126324Sjhb
221126324Sjhbvoid
222126324Sjhbcallout_process(int timeout)
223126324Sjhb{
224169666Sjeff	ticks += timeout;
225126324Sjhb	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
226126324Sjhb}
227126324Sjhb
228136445Sjhbstatic void
229136445Sjhbcallout_proc_msg(struct usb_proc_msg *pmsg)
230136445Sjhb{
231136445Sjhb	struct callout *c;
232136445Sjhb	int delta;
233136445Sjhb
234136445Sjhbrepeat:
235136445Sjhb	mtx_lock(&mtx_callout);
236136445Sjhb
237136445Sjhb	LIST_FOREACH(c, &head_callout, entry) {
238136445Sjhb
239136445Sjhb		delta = c->timeout - ticks;
240126324Sjhb		if (delta < 0) {
241136445Sjhb			mtx_unlock(&mtx_callout);
242136445Sjhb
243126324Sjhb			callout_callback(c);
244126324Sjhb
245126324Sjhb			goto repeat;
246126324Sjhb		}
247126324Sjhb	}
248126324Sjhb	mtx_unlock(&mtx_callout);
249126324Sjhb}
250126324Sjhb
251126324Sjhbvoid
252136445Sjhbcallout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
253126324Sjhb{
254126324Sjhb	memset(c, 0, sizeof(*c));
255126324Sjhb
256126324Sjhb	if (mtx == NULL)
257126324Sjhb		mtx = &Giant;
258126324Sjhb
259126324Sjhb	c->mtx = mtx;
260126324Sjhb	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
261126324Sjhb}
262126324Sjhb
263126324Sjhbvoid
264126324Sjhbcallout_reset(struct callout *c, int to_ticks,
265126324Sjhb    void (*func) (void *), void *arg)
266126324Sjhb{
267126324Sjhb	callout_stop(c);
268126324Sjhb
269126324Sjhb	c->func = func;
270126324Sjhb	c->arg = arg;
271126324Sjhb	c->timeout = ticks + to_ticks;
272137277Sjhb
273126324Sjhb	mtx_lock(&mtx_callout);
274126324Sjhb	LIST_INSERT_HEAD(&head_callout, c, entry);
275126324Sjhb	mtx_unlock(&mtx_callout);
276126324Sjhb}
277126324Sjhb
278165272Skmacyvoid
279165272Skmacycallout_stop(struct callout *c)
280126324Sjhb{
281126324Sjhb	mtx_lock(&mtx_callout);
282136445Sjhb
283137277Sjhb	if (c->entry.le_prev != NULL) {
284126324Sjhb		LIST_REMOVE(c, entry);
285126324Sjhb		c->entry.le_prev = NULL;
286126324Sjhb	}
287126324Sjhb	mtx_unlock(&mtx_callout);
288126324Sjhb
289126324Sjhb	c->func = NULL;
290165272Skmacy	c->arg = NULL;
291126324Sjhb}
292150177Sjhb
293150177Sjhbvoid
294152221Simpcallout_drain(struct callout *c)
295150177Sjhb{
296136445Sjhb	if (c->mtx == NULL)
297136445Sjhb		return;			/* not initialised */
298136445Sjhb
299136445Sjhb	mtx_lock(c->mtx);
300136445Sjhb	callout_stop(c);
301136445Sjhb	mtx_unlock(c->mtx);
302136445Sjhb}
303136445Sjhb
304126324Sjhbint
305165272Skmacycallout_pending(struct callout *c)
306165292Skmacy{
307165291Sache	int retval;
308165292Skmacy
309165292Skmacy	mtx_lock(&mtx_callout);
310165292Skmacy	retval = (c->entry.le_prev != NULL);
311165272Skmacy	mtx_unlock(&mtx_callout);
312165272Skmacy
313165272Skmacy	return (retval);
314165272Skmacy}
315165292Skmacy
316165292Skmacy/*------------------------------------------------------------------------*
317165272Skmacy * Implementation of device API
318131259Sjhb *------------------------------------------------------------------------*/
319131259Sjhb
320131259Sjhbstatic const char unknown_string[] = { "unknown" };
321131259Sjhb
322131259Sjhbstatic TAILQ_HEAD(, module_data) module_head =
323131259Sjhb    TAILQ_HEAD_INITIALIZER(module_head);
324131259Sjhb
325131259Sjhbstatic uint8_t
326165292Skmacydevclass_equal(const char *a, const char *b)
327126324Sjhb{
328126324Sjhb	char ta, tb;
329126324Sjhb
330126324Sjhb	if (a == b)
331126488Sjhb		return (1);
332136445Sjhb
333126324Sjhb	while (1) {
334126324Sjhb		ta = *a;
335172155Sattilio		tb = *b;
336165272Skmacy		if (ta != tb)
337126324Sjhb			return (0);
338165272Skmacy		if (ta == 0)
339126324Sjhb			break;
340126324Sjhb		a++;
341155741Sdavidxu		b++;
342134013Sjhb	}
343155741Sdavidxu	return (1);
344155741Sdavidxu}
345172155Sattilio
346126324Sjhbint
347126324Sjhbbus_generic_resume(device_t dev)
348126324Sjhb{
349126324Sjhb	return (0);
350126324Sjhb}
351126324Sjhb
352126324Sjhbint
353126885Sjhbbus_generic_shutdown(device_t dev)
354126324Sjhb{
355126324Sjhb	return (0);
356126324Sjhb}
357126324Sjhb
358126324Sjhbint
359126324Sjhbbus_generic_suspend(device_t dev)
360126324Sjhb{
361126324Sjhb	return (0);
362126324Sjhb}
363126324Sjhb
364177860Sjeffint
365126324Sjhbbus_generic_print_child(device_t dev, device_t child)
366126324Sjhb{
367126324Sjhb	return (0);
368126324Sjhb}
369126324Sjhb
370170294Sjeffvoid
371170294Sjeffbus_generic_driver_added(device_t dev, driver_t *driver)
372126324Sjhb{
373155741Sdavidxu	return;
374177085Sjeff}
375126324Sjhb
376126324Sjhbdevice_t
377126324Sjhbdevice_get_parent(device_t dev)
378126324Sjhb{
379126324Sjhb	return (dev ? dev->dev_parent : NULL);
380155741Sdavidxu}
381155741Sdavidxu
382126324Sjhbvoid
383126324Sjhbdevice_set_interrupt(device_t dev, driver_filter_t *filter,
384155741Sdavidxu    driver_intr_t *fn, void *arg)
385126324Sjhb{
386126324Sjhb	dev->dev_irq_filter = filter;
387126324Sjhb	dev->dev_irq_fn = fn;
388177375Sjeff	dev->dev_irq_arg = arg;
389177375Sjeff}
390177375Sjeff
391177375Sjeffvoid
392177375Sjeffdevice_run_interrupts(device_t parent)
393177375Sjeff{
394177471Sjeff	device_t child;
395177375Sjeff
396177375Sjeff	if (parent == NULL)
397177375Sjeff		return;
398177375Sjeff
399177375Sjeff	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
400129241Sbde		int status;
401173601Sjulian		if (child->dev_irq_filter != NULL)
402126324Sjhb			status = child->dev_irq_filter(child->dev_irq_arg);
403155741Sdavidxu		else
404155741Sdavidxu			status = FILTER_SCHEDULE_THREAD;
405126324Sjhb
406155741Sdavidxu		if (status == FILTER_SCHEDULE_THREAD) {
407155741Sdavidxu			if (child->dev_irq_fn != NULL)
408155741Sdavidxu				(child->dev_irq_fn) (child->dev_irq_arg);
409155741Sdavidxu		}
410155741Sdavidxu	}
411155741Sdavidxu}
412155741Sdavidxu
413155741Sdavidxuvoid
414155741Sdavidxudevice_set_ivars(device_t dev, void *ivars)
415155741Sdavidxu{
416155741Sdavidxu	dev->dev_aux = ivars;
417184667Sdavidxu}
418184667Sdavidxu
419184667Sdavidxuvoid   *
420184667Sdavidxudevice_get_ivars(device_t dev)
421184667Sdavidxu{
422184667Sdavidxu	return (dev ? dev->dev_aux : NULL);
423170294Sjeff}
424184667Sdavidxu
425170294Sjeffint
426184667Sdavidxudevice_get_unit(device_t dev)
427155936Sdavidxu{
428155936Sdavidxu	return (dev ? dev->dev_unit : 0);
429155936Sdavidxu}
430155936Sdavidxu
431170294Sjeffint
432170294Sjeffbus_generic_detach(device_t dev)
433181334Sjhb{
434181334Sjhb	device_t child;
435181334Sjhb	int error;
436181334Sjhb
437181334Sjhb	if (!dev->dev_attached)
438181334Sjhb		return (EBUSY);
439181334Sjhb
440181334Sjhb	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
441181334Sjhb		if ((error = device_detach(child)) != 0)
442170294Sjeff			return (error);
443170294Sjeff	}
444170294Sjeff	return (0);
445155741Sdavidxu}
446126324Sjhb
447126324Sjhbconst char *
448126324Sjhbdevice_get_nameunit(device_t dev)
449170294Sjeff{
450170294Sjeff	if (dev && dev->dev_nameunit[0])
451126324Sjhb		return (dev->dev_nameunit);
452126324Sjhb
453177085Sjeff	return (unknown_string);
454126324Sjhb}
455126324Sjhb
456175654Sjhbstatic uint8_t
457126324Sjhbdevclass_create(devclass_t *dc_pp)
458126324Sjhb{
459126324Sjhb	if (dc_pp == NULL) {
460126324Sjhb		return (1);
461126324Sjhb	}
462170294Sjeff	if (dc_pp[0] == NULL) {
463175654Sjhb		dc_pp[0] = malloc(sizeof(**(dc_pp)),
464175654Sjhb		    M_DEVBUF, M_WAITOK | M_ZERO);
465175654Sjhb
466175654Sjhb		if (dc_pp[0] == NULL) {
467175654Sjhb			return (1);
468126324Sjhb		}
469126324Sjhb	}
470126324Sjhb	return (0);
471126324Sjhb}
472175654Sjhb
473175654Sjhbstatic const struct module_data *
474175654Sjhbdevclass_find_create(const char *classname)
475175654Sjhb{
476175654Sjhb	const struct module_data *mod;
477175654Sjhb
478175654Sjhb	TAILQ_FOREACH(mod, &module_head, entry) {
479175654Sjhb		if (devclass_equal(mod->mod_name, classname)) {
480175654Sjhb			if (devclass_create(mod->devclass_pp)) {
481181334Sjhb				continue;
482181334Sjhb			}
483181334Sjhb			return (mod);
484181334Sjhb		}
485181334Sjhb	}
486181334Sjhb	return (NULL);
487181334Sjhb}
488181334Sjhb
489181334Sjhbstatic uint8_t
490175654Sjhbdevclass_add_device(const struct module_data *mod, device_t dev)
491175654Sjhb{
492175654Sjhb	device_t *pp_dev;
493177372Sjeff	device_t *end;
494177372Sjeff	uint8_t unit;
495177372Sjeff
496177372Sjeff	pp_dev = mod->devclass_pp[0]->dev_list;
497177085Sjeff	end = pp_dev + DEVCLASS_MAXUNIT;
498177085Sjeff	unit = 0;
499170294Sjeff
500126324Sjhb	while (pp_dev != end) {
501178272Sjeff		if (*pp_dev == NULL) {
502126324Sjhb			*pp_dev = dev;
503129241Sbde			dev->dev_unit = unit;
504173600Sjulian			dev->dev_module = mod;
505126324Sjhb			snprintf(dev->dev_nameunit,
506126324Sjhb			    sizeof(dev->dev_nameunit),
507126324Sjhb			    "%s%d", device_get_name(dev), unit);
508126324Sjhb			return (0);
509126324Sjhb		}
510126324Sjhb		pp_dev++;
511126324Sjhb		unit++;
512126324Sjhb	}
513126324Sjhb	DPRINTF("Could not add device to devclass.\n");
514126324Sjhb	return (1);
515126324Sjhb}
516170294Sjeff
517126324Sjhbstatic void
518126324Sjhbdevclass_delete_device(const struct module_data *mod, device_t dev)
519126324Sjhb{
520126324Sjhb	if (mod == NULL) {
521126324Sjhb		return;
522126324Sjhb	}
523126324Sjhb	mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL;
524126324Sjhb	dev->dev_module = NULL;
525126324Sjhb}
526126324Sjhb
527126324Sjhbstatic device_t
528126324Sjhbmake_device(device_t parent, const char *name)
529126324Sjhb{
530126324Sjhb	device_t dev = NULL;
531126324Sjhb	const struct module_data *mod = NULL;
532126324Sjhb
533126324Sjhb	if (name) {
534126324Sjhb
535126324Sjhb		mod = devclass_find_create(name);
536126324Sjhb
537126324Sjhb		if (!mod) {
538126324Sjhb
539126324Sjhb			DPRINTF("%s:%d:%s: can't find device "
540126324Sjhb			    "class %s\n", __FILE__, __LINE__,
541178272Sjeff			    __FUNCTION__, name);
542126324Sjhb
543126324Sjhb			goto done;
544126324Sjhb		}
545126324Sjhb	}
546126324Sjhb	dev = malloc(sizeof(*dev),
547126324Sjhb	    M_DEVBUF, M_WAITOK | M_ZERO);
548126324Sjhb
549126324Sjhb	if (dev == NULL)
550126324Sjhb		goto done;
551126324Sjhb
552126324Sjhb	dev->dev_parent = parent;
553126324Sjhb	TAILQ_INIT(&dev->dev_children);
554126324Sjhb
555170294Sjeff	if (name) {
556126324Sjhb		dev->dev_fixed_class = 1;
557126324Sjhb		if (devclass_add_device(mod, dev)) {
558155741Sdavidxu			goto error;
559155741Sdavidxu		}
560126324Sjhb	}
561155741Sdavidxudone:
562155741Sdavidxu	return (dev);
563155741Sdavidxu
564155741Sdavidxuerror:
565155741Sdavidxu	if (dev) {
566126324Sjhb		free(dev, M_DEVBUF);
567126324Sjhb	}
568126324Sjhb	return (NULL);
569126324Sjhb}
570126324Sjhb
571126324Sjhbdevice_t
572126324Sjhbdevice_add_child(device_t dev, const char *name, int unit)
573177085Sjeff{
574126324Sjhb	device_t child;
575170294Sjeff
576126324Sjhb	if (unit != -1) {
577170294Sjeff		device_printf(dev, "Unit is not -1\n");
578170294Sjeff	}
579170294Sjeff	child = make_device(dev, name);
580177085Sjeff	if (child == NULL) {
581170294Sjeff		device_printf(dev, "Could not add child '%s'\n", name);
582126324Sjhb		goto done;
583126324Sjhb	}
584126324Sjhb	if (dev == NULL) {
585126324Sjhb		/* no parent */
586126324Sjhb		goto done;
587126324Sjhb	}
588126324Sjhb	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
589177085Sjeffdone:
590126324Sjhb	return (child);
591155741Sdavidxu}
592126324Sjhb
593126324Sjhbint
594177085Sjeffdevice_delete_child(device_t dev, device_t child)
595126324Sjhb{
596170294Sjeff	int error = 0;
597155741Sdavidxu	device_t grandchild;
598155741Sdavidxu
599126324Sjhb	/* remove children first */
600126324Sjhb
601126324Sjhb	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
602126324Sjhb		error = device_delete_child(child, grandchild);
603126324Sjhb		if (error) {
604126324Sjhb			device_printf(dev, "Error deleting child!\n");
605126324Sjhb			goto done;
606126324Sjhb		}
607177085Sjeff	}
608126324Sjhb
609170294Sjeff	error = device_detach(child);
610126324Sjhb
611126324Sjhb	if (error)
612170294Sjeff		goto done;
613170294Sjeff
614170294Sjeff	devclass_delete_device(child->dev_module, child);
615177085Sjeff
616126324Sjhb	if (dev != NULL) {
617170294Sjeff		/* remove child from parent */
618170294Sjeff		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
619131249Sjhb	}
620126324Sjhb	free(child, M_DEVBUF);
621126324Sjhb
622126324Sjhbdone:
623126324Sjhb	return (error);
624126324Sjhb}
625126324Sjhb
626126324Sjhbint
627177085Sjeffdevice_delete_children(device_t dev)
628126324Sjhb{
629155741Sdavidxu	device_t child;
630126324Sjhb	int error = 0;
631177085Sjeff
632126324Sjhb	while ((child = TAILQ_FIRST(&dev->dev_children))) {
633126324Sjhb		error = device_delete_child(dev, child);
634170294Sjeff		if (error) {
635155741Sdavidxu			device_printf(dev, "Error deleting child!\n");
636155741Sdavidxu			break;
637155741Sdavidxu		}
638126324Sjhb	}
639155741Sdavidxu	return (error);
640126324Sjhb}
641126324Sjhb
642126324Sjhbvoid
643145056Sjhbdevice_quiet(device_t dev)
644145056Sjhb{
645126324Sjhb	dev->dev_quiet = 1;
646181334Sjhb}
647145056Sjhb
648126324Sjhbconst char *
649126324Sjhbdevice_get_desc(device_t dev)
650126324Sjhb{
651126324Sjhb	if (dev)
652126324Sjhb		return &(dev->dev_desc[0]);
653126324Sjhb	return (unknown_string);
654165272Skmacy}
655170294Sjeff
656126324Sjhbstatic int
657126324Sjhbdefault_method(void)
658126324Sjhb{
659126324Sjhb	/* do nothing */
660165272Skmacy	DPRINTF("Default method called\n");
661126324Sjhb	return (0);
662126324Sjhb}
663126324Sjhb
664126324Sjhbvoid   *
665126324Sjhbdevice_get_method(device_t dev, const char *what)
666126324Sjhb{
667126324Sjhb	const struct device_method *mtod;
668126324Sjhb
669126324Sjhb	mtod = dev->dev_module->driver->methods;
670126324Sjhb	while (mtod->func != NULL) {
671126324Sjhb		if (devclass_equal(mtod->desc, what)) {
672131259Sjhb			return (mtod->func);
673131259Sjhb		}
674131259Sjhb		mtod++;
675126324Sjhb	}
676126324Sjhb	return ((void *)&default_method);
677126324Sjhb}
678126324Sjhb
679129188Sjhbconst char *
680129188Sjhbdevice_get_name(device_t dev)
681157743Sdavidxu{
682129188Sjhb	if (dev == NULL)
683129241Sbde		return (unknown_string);
684173600Sjulian
685126324Sjhb	return (dev->dev_module->driver->name);
686126324Sjhb}
687177085Sjeff
688177085Sjeffstatic int
689136439Supsdevice_allocate_softc(device_t dev)
690184653Sjhb{
691184653Sjhb	const struct module_data *mod;
692184653Sjhb
693184653Sjhb	mod = dev->dev_module;
694184653Sjhb
695184653Sjhb	if ((dev->dev_softc_alloc == 0) &&
696184653Sjhb	    (mod->driver->size != 0)) {
697184653Sjhb		dev->dev_sc = malloc(mod->driver->size,
698184653Sjhb		    M_DEVBUF, M_WAITOK | M_ZERO);
699184653Sjhb
700184653Sjhb		if (dev->dev_sc == NULL)
701184653Sjhb			return (ENOMEM);
702126324Sjhb
703126324Sjhb		dev->dev_softc_alloc = 1;
704169666Sjeff	}
705126324Sjhb	return (0);
706169666Sjeff}
707169666Sjeff
708169666Sjeffint
709169666Sjeffdevice_probe_and_attach(device_t dev)
710169666Sjeff{
711169666Sjeff	const struct module_data *mod;
712169666Sjeff	const char *bus_name_parent;
713169666Sjeff
714169666Sjeff	bus_name_parent = device_get_name(device_get_parent(dev));
715169666Sjeff
716169666Sjeff	if (dev->dev_attached)
717169666Sjeff		return (0);		/* fail-safe */
718169666Sjeff
719169666Sjeff	if (dev->dev_fixed_class) {
720169666Sjeff
721169666Sjeff		mod = dev->dev_module;
722169666Sjeff
723169666Sjeff		if (DEVICE_PROBE(dev) <= 0) {
724169666Sjeff
725169666Sjeff			if (device_allocate_softc(dev) == 0) {
726169666Sjeff
727169666Sjeff				if (DEVICE_ATTACH(dev) == 0) {
728169666Sjeff					/* success */
729169666Sjeff					dev->dev_attached = 1;
730169666Sjeff					return (0);
731169666Sjeff				}
732169666Sjeff			}
733169666Sjeff		}
734169666Sjeff		device_detach(dev);
735169666Sjeff
736169666Sjeff		goto error;
737169666Sjeff	}
738126324Sjhb	/*
739126324Sjhb         * Else find a module for our device, if any
740181334Sjhb         */
741165272Skmacy
742126324Sjhb	TAILQ_FOREACH(mod, &module_head, entry) {
743126324Sjhb		if (devclass_equal(mod->bus_name, bus_name_parent)) {
744137277Sjhb			if (devclass_create(mod->devclass_pp)) {
745181334Sjhb				continue;
746126324Sjhb			}
747126324Sjhb			if (devclass_add_device(mod, dev)) {
748126324Sjhb				continue;
749165272Skmacy			}
750126324Sjhb			if (DEVICE_PROBE(dev) <= 0) {
751170294Sjeff
752181334Sjhb				if (device_allocate_softc(dev) == 0) {
753134013Sjhb
754126324Sjhb					if (DEVICE_ATTACH(dev) == 0) {
755129188Sjhb						/* success */
756137277Sjhb						dev->dev_attached = 1;
757137277Sjhb						return (0);
758137277Sjhb					}
759137277Sjhb				}
760137277Sjhb			}
761137277Sjhb			/* else try next driver */
762137277Sjhb
763165272Skmacy			device_detach(dev);
764137277Sjhb		}
765137277Sjhb	}
766137277Sjhb
767137277Sjhberror:
768170294Sjeff	return (ENODEV);
769181334Sjhb}
770170294Sjeff
771181334Sjhbint
772126324Sjhbdevice_detach(device_t dev)
773126324Sjhb{
774126324Sjhb	const struct module_data *mod = dev->dev_module;
775126324Sjhb	int error;
776126324Sjhb
777181334Sjhb	if (dev->dev_attached) {
778165272Skmacy
779126324Sjhb		error = DEVICE_DETACH(dev);
780126324Sjhb		if (error) {
781182875Sjhb			return error;
782181334Sjhb		}
783126324Sjhb		dev->dev_attached = 0;
784126324Sjhb	}
785126324Sjhb	device_set_softc(dev, NULL);
786165272Skmacy
787126324Sjhb	if (dev->dev_fixed_class == 0)
788177085Sjeff		devclass_delete_device(mod, dev);
789181334Sjhb
790134013Sjhb	return (0);
791126324Sjhb}
792129188Sjhb
793145056Sjhbvoid
794181334Sjhbdevice_set_softc(device_t dev, void *softc)
795182875Sjhb{
796170294Sjeff	if (dev->dev_softc_alloc) {
797181334Sjhb		free(dev->dev_sc, M_DEVBUF);
798181334Sjhb		dev->dev_sc = NULL;
799170294Sjeff	}
800170294Sjeff	dev->dev_sc = softc;
801181334Sjhb	dev->dev_softc_alloc = 0;
802126324Sjhb}
803126324Sjhb
804126324Sjhbvoid   *
805126324Sjhbdevice_get_softc(device_t dev)
806126324Sjhb{
807126324Sjhb	if (dev == NULL)
808126324Sjhb		return (NULL);
809126324Sjhb
810126324Sjhb	return (dev->dev_sc);
811170294Sjeff}
812126324Sjhb
813126324Sjhbint
814126324Sjhbdevice_is_attached(device_t dev)
815181334Sjhb{
816126324Sjhb	return (dev->dev_attached);
817129241Sbde}
818181334Sjhb
819129241Sbdevoid
820173600Sjuliandevice_set_desc(device_t dev, const char *desc)
821126324Sjhb{
822126324Sjhb	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
823126324Sjhb}
824126324Sjhb
825126324Sjhbvoid
826170294Sjeffdevice_set_desc_copy(device_t dev, const char *desc)
827170294Sjeff{
828126324Sjhb	device_set_desc(dev, desc);
829170294Sjeff}
830176078Sjeff
831126324Sjhbvoid   *
832170294Sjeffdevclass_get_softc(devclass_t dc, int unit)
833170294Sjeff{
834181334Sjhb	return (device_get_softc(devclass_get_device(dc, unit)));
835170294Sjeff}
836181334Sjhb
837181334Sjhbint
838170294Sjeffdevclass_get_maxunit(devclass_t dc)
839126324Sjhb{
840175654Sjhb	int max_unit = 0;
841126324Sjhb
842175654Sjhb	if (dc) {
843175654Sjhb		max_unit = DEVCLASS_MAXUNIT;
844175654Sjhb		while (max_unit--) {
845175654Sjhb			if (dc->dev_list[max_unit]) {
846126324Sjhb				break;
847126324Sjhb			}
848175664Sjhb		}
849170294Sjeff		max_unit++;
850126324Sjhb	}
851170294Sjeff	return (max_unit);
852126324Sjhb}
853126324Sjhb
854126324Sjhbdevice_t
855126324Sjhbdevclass_get_device(devclass_t dc, int unit)
856126324Sjhb{
857126324Sjhb	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
858126324Sjhb	    NULL : dc->dev_list[unit]);
859126324Sjhb}
860126324Sjhb
861126324Sjhbdevclass_t
862126324Sjhbdevclass_find(const char *classname)
863127085Sjhb{
864126324Sjhb	const struct module_data *mod;
865126324Sjhb
866181334Sjhb	TAILQ_FOREACH(mod, &module_head, entry) {
867126324Sjhb		if (devclass_equal(mod->mod_name, classname))
868126324Sjhb			return (mod->devclass_pp[0]);
869170294Sjeff	}
870181334Sjhb	return (NULL);
871181334Sjhb}
872126324Sjhb
873126324Sjhbvoid
874126324Sjhbmodule_register(void *data)
875126324Sjhb{
876126324Sjhb	struct module_data *mdata = data;
877126324Sjhb
878126324Sjhb	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
879126324Sjhb}
880126324Sjhb
881126324Sjhb/*------------------------------------------------------------------------*
882181334Sjhb * System startup
883126324Sjhb *------------------------------------------------------------------------*/
884126324Sjhb
885126324Sjhbstatic void
886126324Sjhbsysinit_run(const void **ppdata)
887126324Sjhb{
888126324Sjhb	const struct sysinit *psys;
889126324Sjhb
890136445Sjhb	while ((psys = *ppdata) != NULL) {
891126324Sjhb		(psys->func) (psys->data);
892170294Sjeff		ppdata++;
893170294Sjeff	}
894170294Sjeff}
895170294Sjeff
896170294Sjeff/*------------------------------------------------------------------------*
897170294Sjeff * USB process API
898126324Sjhb *------------------------------------------------------------------------*/
899126324Sjhb
900126324Sjhbstatic int usb_do_process(struct usb_process *);
901126324Sjhbstatic int usb_proc_level = -1;
902170294Sjeffstatic struct mtx usb_proc_mtx;
903170294Sjeff
904126324Sjhbvoid
905170294Sjeffusb_idle(void)
906181334Sjhb{
907170294Sjeff	int old_level = usb_proc_level;
908126324Sjhb	int old_giant = Giant.owned;
909181334Sjhb	int worked;
910181334Sjhb
911126324Sjhb	device_run_interrupts(usb_pci_root);
912126324Sjhb
913126324Sjhb	do {
914129241Sbde		worked = 0;
915129241Sbde		Giant.owned = 0;
916126324Sjhb
917181334Sjhb		while (++usb_proc_level < USB_PROC_MAX)
918155741Sdavidxu			worked |= usb_do_process(usb_process + usb_proc_level);
919126324Sjhb
920170294Sjeff		usb_proc_level = old_level;
921126324Sjhb		Giant.owned = old_giant;
922126324Sjhb
923170294Sjeff	} while (worked);
924126324Sjhb}
925126324Sjhb
926155741Sdavidxuvoid
927126324Sjhbusb_init(void)
928126324Sjhb{
929126324Sjhb	sysinit_run(sysinit_data);
930126324Sjhb}
931126324Sjhb
932126324Sjhbvoid
933181334Sjhbusb_uninit(void)
934126324Sjhb{
935129241Sbde	sysinit_run(sysuninit_data);
936173600Sjulian}
937170294Sjeff
938170294Sjeffstatic void
939170294Sjeffusb_process_init_sub(struct usb_process *up)
940170294Sjeff{
941170294Sjeff	TAILQ_INIT(&up->up_qhead);
942170294Sjeff
943170294Sjeff	cv_init(&up->up_cv, "-");
944170294Sjeff	cv_init(&up->up_drain, "usbdrain");
945181334Sjhb
946126324Sjhb	up->up_mtx = &usb_proc_mtx;
947170294Sjeff}
948170294Sjeff
949170294Sjeffstatic void
950170294Sjeffusb_process_init(void *arg)
951170294Sjeff{
952181334Sjhb	uint8_t x;
953126324Sjhb
954154936Sjhb	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
955177372Sjeff
956177372Sjeff	for (x = 0; x != USB_PROC_MAX; x++)
957177372Sjeff		usb_process_init_sub(&usb_process[x]);
958177372Sjeff
959177372Sjeff}
960177372SjeffSYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
961177372Sjeff
962177372Sjeffstatic int
963177372Sjeffusb_do_process(struct usb_process *up)
964177372Sjeff{
965177372Sjeff	struct usb_proc_msg *pm;
966177372Sjeff	int worked = 0;
967177372Sjeff
968177372Sjeff	mtx_lock(&usb_proc_mtx);
969177372Sjeff
970177372Sjeffrepeat:
971177372Sjeff	pm = TAILQ_FIRST(&up->up_qhead);
972177372Sjeff
973177372Sjeff	if (pm != NULL) {
974177372Sjeff
975177372Sjeff		worked = 1;
976177372Sjeff
977177372Sjeff		(pm->pm_callback) (pm);
978177372Sjeff
979177372Sjeff		if (pm == TAILQ_FIRST(&up->up_qhead)) {
980177372Sjeff			/* nothing changed */
981177372Sjeff			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
982177372Sjeff			pm->pm_qentry.tqe_prev = NULL;
983177372Sjeff		}
984177372Sjeff		goto repeat;
985177372Sjeff	}
986177372Sjeff	mtx_unlock(&usb_proc_mtx);
987177372Sjeff
988177372Sjeff	return (worked);
989177372Sjeff}
990177372Sjeff
991177372Sjeffvoid   *
992177372Sjeffusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
993177372Sjeff{
994177372Sjeff	struct usb_proc_msg *pm0 = _pm0;
995177372Sjeff	struct usb_proc_msg *pm1 = _pm1;
996177372Sjeff	struct usb_proc_msg *pm2;
997177372Sjeff	usb_size_t d;
998177372Sjeff	uint8_t t;
999177372Sjeff
1000177372Sjeff	t = 0;
1001177372Sjeff
1002177372Sjeff	if (pm0->pm_qentry.tqe_prev) {
1003177372Sjeff		t |= 1;
1004177372Sjeff	}
1005177372Sjeff	if (pm1->pm_qentry.tqe_prev) {
1006177372Sjeff		t |= 2;
1007177372Sjeff	}
1008177372Sjeff	if (t == 0) {
1009177372Sjeff		/*
1010177372Sjeff		 * No entries are queued. Queue "pm0" and use the existing
1011177372Sjeff		 * message number.
1012177372Sjeff		 */
1013177372Sjeff		pm2 = pm0;
1014177372Sjeff	} else if (t == 1) {
1015177372Sjeff		/* Check if we need to increment the message number. */
1016177372Sjeff		if (pm0->pm_num == up->up_msg_num) {
1017177372Sjeff			up->up_msg_num++;
1018177372Sjeff		}
1019177372Sjeff		pm2 = pm1;
1020177372Sjeff	} else if (t == 2) {
1021177372Sjeff		/* Check if we need to increment the message number. */
1022177372Sjeff		if (pm1->pm_num == up->up_msg_num) {
1023177372Sjeff			up->up_msg_num++;
1024177372Sjeff		}
1025177372Sjeff		pm2 = pm0;
1026177372Sjeff	} else if (t == 3) {
1027177372Sjeff		/*
1028177372Sjeff		 * Both entries are queued. Re-queue the entry closest to
1029177372Sjeff		 * the end.
1030177372Sjeff		 */
1031177372Sjeff		d = (pm1->pm_num - pm0->pm_num);
1032177372Sjeff
1033177372Sjeff		/* Check sign after subtraction */
1034177372Sjeff		if (d & 0x80000000) {
1035177372Sjeff			pm2 = pm0;
1036177372Sjeff		} else {
1037177372Sjeff			pm2 = pm1;
1038177372Sjeff		}
1039177372Sjeff
1040177372Sjeff		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1041177372Sjeff	} else {
1042177372Sjeff		pm2 = NULL;		/* panic - should not happen */
1043177372Sjeff	}
1044177372Sjeff
1045177372Sjeff	/* Put message last on queue */
1046177372Sjeff
1047177372Sjeff	pm2->pm_num = up->up_msg_num;
1048177372Sjeff	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1049177372Sjeff
1050177372Sjeff	return (pm2);
1051177372Sjeff}
1052177372Sjeff
1053177372Sjeff/*------------------------------------------------------------------------*
1054177372Sjeff *	usb_proc_is_gone
1055177372Sjeff *
1056177372Sjeff * Return values:
1057177372Sjeff *    0: USB process is running
1058177372Sjeff * Else: USB process is tearing down
1059177372Sjeff *------------------------------------------------------------------------*/
1060177372Sjeffuint8_t
1061177372Sjeffusb_proc_is_gone(struct usb_process *up)
1062177372Sjeff{
1063177372Sjeff	return (0);
1064177372Sjeff}
1065177372Sjeff
1066177372Sjeff/*------------------------------------------------------------------------*
1067177372Sjeff *	usb_proc_mwait
1068177372Sjeff *
1069177372Sjeff * This function will return when the USB process message pointed to
1070177372Sjeff * by "pm" is no longer on a queue. This function must be called
1071177372Sjeff * having "usb_proc_mtx" locked.
1072177372Sjeff *------------------------------------------------------------------------*/
1073177372Sjeffvoid
1074177372Sjeffusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1075177372Sjeff{
1076177372Sjeff	struct usb_proc_msg *pm0 = _pm0;
1077177372Sjeff	struct usb_proc_msg *pm1 = _pm1;
1078177372Sjeff
1079177372Sjeff	/* Just remove the messages from the queue. */
1080177372Sjeff	if (pm0->pm_qentry.tqe_prev) {
1081177372Sjeff		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1082177372Sjeff		pm0->pm_qentry.tqe_prev = NULL;
1083177372Sjeff	}
1084177372Sjeff	if (pm1->pm_qentry.tqe_prev) {
1085177372Sjeff		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1086177372Sjeff		pm1->pm_qentry.tqe_prev = NULL;
1087177372Sjeff	}
1088177372Sjeff}
1089177372Sjeff
1090177372Sjeff/*------------------------------------------------------------------------*
1091177372Sjeff * SYSTEM attach
1092177372Sjeff *------------------------------------------------------------------------*/
1093177372Sjeff
1094177372Sjeffstatic device_method_t pci_methods[] = {
1095177372Sjeff	DEVMETHOD_END
1096177372Sjeff};
1097177372Sjeff
1098177372Sjeffstatic driver_t pci_driver = {
1099177372Sjeff	.name = "pci",
1100177372Sjeff	.methods = pci_methods,
1101177372Sjeff};
1102177372Sjeff
1103177372Sjeffstatic devclass_t pci_devclass;
1104177372Sjeff
1105177372SjeffDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1106154936Sjhb
1107154936Sjhbstatic const char *usb_pci_devices[] = {
1108154936Sjhb#ifdef USB_PROBE_LIST
1109154936Sjhb	USB_PROBE_LIST
1110154936Sjhb#endif
1111154944Simp};
1112154936Sjhb
1113154944Simp#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1114154936Sjhb
1115154936Sjhbstatic device_t usb_pci_dev[USB_PCI_USB_MAX];
1116154936Sjhb
1117154936Sjhbstatic void
1118154936Sjhbusb_pci_mod_load(void *arg)
1119154936Sjhb{
1120154936Sjhb	uint32_t x;
1121154936Sjhb
1122154936Sjhb	usb_pci_root = device_add_child(NULL, "pci", -1);
1123154936Sjhb	if (usb_pci_root == NULL)
1124154936Sjhb		return;
1125154936Sjhb
1126154936Sjhb	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1127154936Sjhb		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1128154936Sjhb		if (usb_pci_dev[x] == NULL)
1129154936Sjhb			continue;
1130154936Sjhb		if (device_probe_and_attach(usb_pci_dev[x])) {
1131154936Sjhb			device_printf(usb_pci_dev[x],
1132154936Sjhb			    "WARNING: Probe and attach failed!\n");
1133154936Sjhb		}
1134154936Sjhb	}
1135154936Sjhb}
1136154936SjhbSYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1137154936Sjhb
1138154936Sjhbstatic void
1139154936Sjhbusb_pci_mod_unload(void *arg)
1140154936Sjhb{
1141154936Sjhb	uint32_t x;
1142154936Sjhb
1143154936Sjhb	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1144154936Sjhb		if (usb_pci_dev[x]) {
1145154936Sjhb			device_detach(usb_pci_dev[x]);
1146154936Sjhb			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1147154936Sjhb		}
1148164325Spjd	}
1149154936Sjhb	if (usb_pci_root)
1150154936Sjhb		device_delete_child(NULL, usb_pci_root);
1151154936Sjhb}
1152154936SjhbSYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1153154936Sjhb
1154165272Skmacy/*------------------------------------------------------------------------*
1155165272Skmacy * MALLOC API
1156165272Skmacy *------------------------------------------------------------------------*/
1157165272Skmacy
1158165272Skmacy#define	USB_POOL_ALIGN 8
1159165272Skmacy
1160165272Skmacystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1161165272Skmacystatic uint32_t usb_pool_rem = USB_POOL_SIZE;
1162165272Skmacystatic uint32_t usb_pool_entries;
1163180930Sjhb
1164165272Skmacystruct malloc_hdr {
1165165272Skmacy	TAILQ_ENTRY(malloc_hdr) entry;
1166154936Sjhb	uint32_t size;
1167157823Sjhb} __aligned(USB_POOL_ALIGN);
1168157823Sjhb
1169183054Ssamstatic TAILQ_HEAD(, malloc_hdr) malloc_head =
1170154936Sjhb	TAILQ_HEAD_INITIALIZER(malloc_head);
1171
1172void   *
1173usb_malloc(unsigned long size)
1174{
1175	struct malloc_hdr *hdr;
1176
1177	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1178	size += sizeof(struct malloc_hdr);
1179
1180	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1181		if (hdr->size == size)
1182			break;
1183	}
1184
1185	if (hdr) {
1186		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1187		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1188
1189		TAILQ_REMOVE(&malloc_head, hdr, entry);
1190		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1191		return (hdr + 1);
1192	}
1193	if (usb_pool_rem >= size) {
1194		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1195		hdr->size = size;
1196
1197		usb_pool_rem -= size;
1198		usb_pool_entries++;
1199
1200		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1201		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1202
1203		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1204		return (hdr + 1);
1205	}
1206	return (NULL);
1207}
1208
1209void
1210usb_free(void *arg)
1211{
1212	struct malloc_hdr *hdr;
1213
1214	if (arg == NULL)
1215		return;
1216
1217	hdr = arg;
1218	hdr--;
1219
1220	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1221}
1222
1223char   *
1224usb_strdup(const char *str)
1225{
1226	char *tmp;
1227	int len;
1228
1229	len = 1 + strlen(str);
1230
1231	tmp = usb_malloc(len);
1232	if (tmp == NULL)
1233		return (NULL);
1234
1235	memcpy(tmp, str, len);
1236	return (tmp);
1237}
1238