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
383269921Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter,
384269921Shselasky    driver_intr_t *fn, void *arg)
385246145Shselasky{
386269921Shselasky	dev->dev_irq_filter = filter;
387246145Shselasky	dev->dev_irq_fn = fn;
388246145Shselasky	dev->dev_irq_arg = arg;
389246145Shselasky}
390246145Shselasky
391246145Shselaskyvoid
392246145Shselaskydevice_run_interrupts(device_t parent)
393246145Shselasky{
394246145Shselasky	device_t child;
395246145Shselasky
396246145Shselasky	if (parent == NULL)
397246145Shselasky		return;
398246145Shselasky
399246145Shselasky	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
400269921Shselasky		int status;
401269921Shselasky		if (child->dev_irq_filter != NULL)
402269921Shselasky			status = child->dev_irq_filter(child->dev_irq_arg);
403269921Shselasky		else
404269921Shselasky			status = FILTER_SCHEDULE_THREAD;
405269921Shselasky
406269921Shselasky		if (status == FILTER_SCHEDULE_THREAD) {
407269921Shselasky			if (child->dev_irq_fn != NULL)
408269921Shselasky				(child->dev_irq_fn) (child->dev_irq_arg);
409269921Shselasky		}
410246145Shselasky	}
411246145Shselasky}
412246145Shselasky
413246145Shselaskyvoid
414246145Shselaskydevice_set_ivars(device_t dev, void *ivars)
415246145Shselasky{
416246145Shselasky	dev->dev_aux = ivars;
417246145Shselasky}
418246145Shselasky
419246145Shselaskyvoid   *
420246145Shselaskydevice_get_ivars(device_t dev)
421246145Shselasky{
422246145Shselasky	return (dev ? dev->dev_aux : NULL);
423246145Shselasky}
424246145Shselasky
425246145Shselaskyint
426246145Shselaskydevice_get_unit(device_t dev)
427246145Shselasky{
428246145Shselasky	return (dev ? dev->dev_unit : 0);
429246145Shselasky}
430246145Shselasky
431246145Shselaskyint
432246145Shselaskybus_generic_detach(device_t dev)
433246145Shselasky{
434246145Shselasky	device_t child;
435246145Shselasky	int error;
436246145Shselasky
437246145Shselasky	if (!dev->dev_attached)
438246145Shselasky		return (EBUSY);
439246145Shselasky
440246145Shselasky	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
441246145Shselasky		if ((error = device_detach(child)) != 0)
442246145Shselasky			return (error);
443246145Shselasky	}
444246145Shselasky	return (0);
445246145Shselasky}
446246145Shselasky
447246145Shselaskyconst char *
448246145Shselaskydevice_get_nameunit(device_t dev)
449246145Shselasky{
450246145Shselasky	if (dev && dev->dev_nameunit[0])
451246145Shselasky		return (dev->dev_nameunit);
452246145Shselasky
453246145Shselasky	return (unknown_string);
454246145Shselasky}
455246145Shselasky
456246145Shselaskystatic uint8_t
457246145Shselaskydevclass_create(devclass_t *dc_pp)
458246145Shselasky{
459246145Shselasky	if (dc_pp == NULL) {
460246145Shselasky		return (1);
461246145Shselasky	}
462246145Shselasky	if (dc_pp[0] == NULL) {
463246145Shselasky		dc_pp[0] = malloc(sizeof(**(dc_pp)),
464246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
465246145Shselasky
466246145Shselasky		if (dc_pp[0] == NULL) {
467246145Shselasky			return (1);
468246145Shselasky		}
469246145Shselasky	}
470246145Shselasky	return (0);
471246145Shselasky}
472246145Shselasky
473246145Shselaskystatic const struct module_data *
474246145Shselaskydevclass_find_create(const char *classname)
475246145Shselasky{
476246145Shselasky	const struct module_data *mod;
477246145Shselasky
478246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
479246145Shselasky		if (devclass_equal(mod->mod_name, classname)) {
480246145Shselasky			if (devclass_create(mod->devclass_pp)) {
481246145Shselasky				continue;
482246145Shselasky			}
483246145Shselasky			return (mod);
484246145Shselasky		}
485246145Shselasky	}
486246145Shselasky	return (NULL);
487246145Shselasky}
488246145Shselasky
489246145Shselaskystatic uint8_t
490246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev)
491246145Shselasky{
492246145Shselasky	device_t *pp_dev;
493246145Shselasky	device_t *end;
494246145Shselasky	uint8_t unit;
495246145Shselasky
496246145Shselasky	pp_dev = mod->devclass_pp[0]->dev_list;
497246145Shselasky	end = pp_dev + DEVCLASS_MAXUNIT;
498246145Shselasky	unit = 0;
499246145Shselasky
500246145Shselasky	while (pp_dev != end) {
501246145Shselasky		if (*pp_dev == NULL) {
502246145Shselasky			*pp_dev = dev;
503246145Shselasky			dev->dev_unit = unit;
504246145Shselasky			dev->dev_module = mod;
505246145Shselasky			snprintf(dev->dev_nameunit,
506246145Shselasky			    sizeof(dev->dev_nameunit),
507246145Shselasky			    "%s%d", device_get_name(dev), unit);
508246145Shselasky			return (0);
509246145Shselasky		}
510246145Shselasky		pp_dev++;
511246145Shselasky		unit++;
512246145Shselasky	}
513246145Shselasky	DPRINTF("Could not add device to devclass.\n");
514246145Shselasky	return (1);
515246145Shselasky}
516246145Shselasky
517246145Shselaskystatic void
518246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev)
519246145Shselasky{
520246145Shselasky	if (mod == NULL) {
521246145Shselasky		return;
522246145Shselasky	}
523246145Shselasky	mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL;
524246145Shselasky	dev->dev_module = NULL;
525246145Shselasky}
526246145Shselasky
527246145Shselaskystatic device_t
528246145Shselaskymake_device(device_t parent, const char *name)
529246145Shselasky{
530246145Shselasky	device_t dev = NULL;
531246145Shselasky	const struct module_data *mod = NULL;
532246145Shselasky
533246145Shselasky	if (name) {
534246145Shselasky
535246145Shselasky		mod = devclass_find_create(name);
536246145Shselasky
537246145Shselasky		if (!mod) {
538246145Shselasky
539246145Shselasky			DPRINTF("%s:%d:%s: can't find device "
540246145Shselasky			    "class %s\n", __FILE__, __LINE__,
541246145Shselasky			    __FUNCTION__, name);
542246145Shselasky
543246145Shselasky			goto done;
544246145Shselasky		}
545246145Shselasky	}
546246145Shselasky	dev = malloc(sizeof(*dev),
547246145Shselasky	    M_DEVBUF, M_WAITOK | M_ZERO);
548246145Shselasky
549246145Shselasky	if (dev == NULL)
550246145Shselasky		goto done;
551246145Shselasky
552246145Shselasky	dev->dev_parent = parent;
553246145Shselasky	TAILQ_INIT(&dev->dev_children);
554246145Shselasky
555246145Shselasky	if (name) {
556246145Shselasky		dev->dev_fixed_class = 1;
557246145Shselasky		if (devclass_add_device(mod, dev)) {
558246145Shselasky			goto error;
559246145Shselasky		}
560246145Shselasky	}
561246145Shselaskydone:
562246145Shselasky	return (dev);
563246145Shselasky
564246145Shselaskyerror:
565246145Shselasky	if (dev) {
566246145Shselasky		free(dev, M_DEVBUF);
567246145Shselasky	}
568246145Shselasky	return (NULL);
569246145Shselasky}
570246145Shselasky
571246145Shselaskydevice_t
572246145Shselaskydevice_add_child(device_t dev, const char *name, int unit)
573246145Shselasky{
574246145Shselasky	device_t child;
575246145Shselasky
576246145Shselasky	if (unit != -1) {
577246145Shselasky		device_printf(dev, "Unit is not -1\n");
578246145Shselasky	}
579246145Shselasky	child = make_device(dev, name);
580246145Shselasky	if (child == NULL) {
581246145Shselasky		device_printf(dev, "Could not add child '%s'\n", name);
582246145Shselasky		goto done;
583246145Shselasky	}
584246145Shselasky	if (dev == NULL) {
585246145Shselasky		/* no parent */
586246145Shselasky		goto done;
587246145Shselasky	}
588246145Shselasky	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
589246145Shselaskydone:
590246145Shselasky	return (child);
591246145Shselasky}
592246145Shselasky
593246145Shselaskyint
594246145Shselaskydevice_delete_child(device_t dev, device_t child)
595246145Shselasky{
596246145Shselasky	int error = 0;
597246145Shselasky	device_t grandchild;
598246145Shselasky
599246145Shselasky	/* remove children first */
600246145Shselasky
601246145Shselasky	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
602246145Shselasky		error = device_delete_child(child, grandchild);
603246145Shselasky		if (error) {
604246145Shselasky			device_printf(dev, "Error deleting child!\n");
605246145Shselasky			goto done;
606246145Shselasky		}
607246145Shselasky	}
608246145Shselasky
609246145Shselasky	error = device_detach(child);
610246145Shselasky
611246145Shselasky	if (error)
612246145Shselasky		goto done;
613246145Shselasky
614246145Shselasky	devclass_delete_device(child->dev_module, child);
615246145Shselasky
616246145Shselasky	if (dev != NULL) {
617246145Shselasky		/* remove child from parent */
618246145Shselasky		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
619246145Shselasky	}
620246145Shselasky	free(child, M_DEVBUF);
621246145Shselasky
622246145Shselaskydone:
623246145Shselasky	return (error);
624246145Shselasky}
625246145Shselasky
626246145Shselaskyint
627246145Shselaskydevice_delete_children(device_t dev)
628246145Shselasky{
629246145Shselasky	device_t child;
630246145Shselasky	int error = 0;
631246145Shselasky
632246145Shselasky	while ((child = TAILQ_FIRST(&dev->dev_children))) {
633246145Shselasky		error = device_delete_child(dev, child);
634246145Shselasky		if (error) {
635246145Shselasky			device_printf(dev, "Error deleting child!\n");
636246145Shselasky			break;
637246145Shselasky		}
638246145Shselasky	}
639246145Shselasky	return (error);
640246145Shselasky}
641246145Shselasky
642246145Shselaskyvoid
643246145Shselaskydevice_quiet(device_t dev)
644246145Shselasky{
645246145Shselasky	dev->dev_quiet = 1;
646246145Shselasky}
647246145Shselasky
648246145Shselaskyconst char *
649246145Shselaskydevice_get_desc(device_t dev)
650246145Shselasky{
651246145Shselasky	if (dev)
652246145Shselasky		return &(dev->dev_desc[0]);
653246145Shselasky	return (unknown_string);
654246145Shselasky}
655246145Shselasky
656246145Shselaskystatic int
657246145Shselaskydefault_method(void)
658246145Shselasky{
659246145Shselasky	/* do nothing */
660246145Shselasky	DPRINTF("Default method called\n");
661246145Shselasky	return (0);
662246145Shselasky}
663246145Shselasky
664246145Shselaskyvoid   *
665246145Shselaskydevice_get_method(device_t dev, const char *what)
666246145Shselasky{
667246145Shselasky	const struct device_method *mtod;
668246145Shselasky
669246145Shselasky	mtod = dev->dev_module->driver->methods;
670246145Shselasky	while (mtod->func != NULL) {
671246145Shselasky		if (devclass_equal(mtod->desc, what)) {
672246145Shselasky			return (mtod->func);
673246145Shselasky		}
674246145Shselasky		mtod++;
675246145Shselasky	}
676246145Shselasky	return ((void *)&default_method);
677246145Shselasky}
678246145Shselasky
679246145Shselaskyconst char *
680246145Shselaskydevice_get_name(device_t dev)
681246145Shselasky{
682246145Shselasky	if (dev == NULL)
683246145Shselasky		return (unknown_string);
684246145Shselasky
685246145Shselasky	return (dev->dev_module->driver->name);
686246145Shselasky}
687246145Shselasky
688246145Shselaskystatic int
689246145Shselaskydevice_allocate_softc(device_t dev)
690246145Shselasky{
691246145Shselasky	const struct module_data *mod;
692246145Shselasky
693246145Shselasky	mod = dev->dev_module;
694246145Shselasky
695246145Shselasky	if ((dev->dev_softc_alloc == 0) &&
696246145Shselasky	    (mod->driver->size != 0)) {
697246145Shselasky		dev->dev_sc = malloc(mod->driver->size,
698246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
699246145Shselasky
700246145Shselasky		if (dev->dev_sc == NULL)
701246145Shselasky			return (ENOMEM);
702246145Shselasky
703246145Shselasky		dev->dev_softc_alloc = 1;
704246145Shselasky	}
705246145Shselasky	return (0);
706246145Shselasky}
707246145Shselasky
708246145Shselaskyint
709246145Shselaskydevice_probe_and_attach(device_t dev)
710246145Shselasky{
711246145Shselasky	const struct module_data *mod;
712246145Shselasky	const char *bus_name_parent;
713246145Shselasky
714246145Shselasky	bus_name_parent = device_get_name(device_get_parent(dev));
715246145Shselasky
716246145Shselasky	if (dev->dev_attached)
717246145Shselasky		return (0);		/* fail-safe */
718246145Shselasky
719246145Shselasky	if (dev->dev_fixed_class) {
720246145Shselasky
721246145Shselasky		mod = dev->dev_module;
722246145Shselasky
723246145Shselasky		if (DEVICE_PROBE(dev) <= 0) {
724246145Shselasky
725246145Shselasky			if (device_allocate_softc(dev) == 0) {
726246145Shselasky
727246145Shselasky				if (DEVICE_ATTACH(dev) == 0) {
728246145Shselasky					/* success */
729246145Shselasky					dev->dev_attached = 1;
730246145Shselasky					return (0);
731246145Shselasky				}
732246145Shselasky			}
733246145Shselasky		}
734246145Shselasky		device_detach(dev);
735246145Shselasky
736246145Shselasky		goto error;
737246145Shselasky	}
738246145Shselasky	/*
739246145Shselasky         * Else find a module for our device, if any
740246145Shselasky         */
741246145Shselasky
742246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
743246145Shselasky		if (devclass_equal(mod->bus_name, bus_name_parent)) {
744246145Shselasky			if (devclass_create(mod->devclass_pp)) {
745246145Shselasky				continue;
746246145Shselasky			}
747246145Shselasky			if (devclass_add_device(mod, dev)) {
748246145Shselasky				continue;
749246145Shselasky			}
750246145Shselasky			if (DEVICE_PROBE(dev) <= 0) {
751246145Shselasky
752246145Shselasky				if (device_allocate_softc(dev) == 0) {
753246145Shselasky
754246145Shselasky					if (DEVICE_ATTACH(dev) == 0) {
755246145Shselasky						/* success */
756246145Shselasky						dev->dev_attached = 1;
757246145Shselasky						return (0);
758246145Shselasky					}
759246145Shselasky				}
760246145Shselasky			}
761246145Shselasky			/* else try next driver */
762246145Shselasky
763246145Shselasky			device_detach(dev);
764246145Shselasky		}
765246145Shselasky	}
766246145Shselasky
767246145Shselaskyerror:
768246145Shselasky	return (ENODEV);
769246145Shselasky}
770246145Shselasky
771246145Shselaskyint
772246145Shselaskydevice_detach(device_t dev)
773246145Shselasky{
774246145Shselasky	const struct module_data *mod = dev->dev_module;
775246145Shselasky	int error;
776246145Shselasky
777246145Shselasky	if (dev->dev_attached) {
778246145Shselasky
779246145Shselasky		error = DEVICE_DETACH(dev);
780246145Shselasky		if (error) {
781246145Shselasky			return error;
782246145Shselasky		}
783246145Shselasky		dev->dev_attached = 0;
784246145Shselasky	}
785246145Shselasky	device_set_softc(dev, NULL);
786246145Shselasky
787246145Shselasky	if (dev->dev_fixed_class == 0)
788246145Shselasky		devclass_delete_device(mod, dev);
789246145Shselasky
790246145Shselasky	return (0);
791246145Shselasky}
792246145Shselasky
793246145Shselaskyvoid
794246145Shselaskydevice_set_softc(device_t dev, void *softc)
795246145Shselasky{
796246145Shselasky	if (dev->dev_softc_alloc) {
797246145Shselasky		free(dev->dev_sc, M_DEVBUF);
798246145Shselasky		dev->dev_sc = NULL;
799246145Shselasky	}
800246145Shselasky	dev->dev_sc = softc;
801246145Shselasky	dev->dev_softc_alloc = 0;
802246145Shselasky}
803246145Shselasky
804246145Shselaskyvoid   *
805246145Shselaskydevice_get_softc(device_t dev)
806246145Shselasky{
807246145Shselasky	if (dev == NULL)
808246145Shselasky		return (NULL);
809246145Shselasky
810246145Shselasky	return (dev->dev_sc);
811246145Shselasky}
812246145Shselasky
813246145Shselaskyint
814246145Shselaskydevice_is_attached(device_t dev)
815246145Shselasky{
816246145Shselasky	return (dev->dev_attached);
817246145Shselasky}
818246145Shselasky
819246145Shselaskyvoid
820246145Shselaskydevice_set_desc(device_t dev, const char *desc)
821246145Shselasky{
822246145Shselasky	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
823246145Shselasky}
824246145Shselasky
825246145Shselaskyvoid
826246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc)
827246145Shselasky{
828246145Shselasky	device_set_desc(dev, desc);
829246145Shselasky}
830246145Shselasky
831246145Shselaskyvoid   *
832246145Shselaskydevclass_get_softc(devclass_t dc, int unit)
833246145Shselasky{
834246145Shselasky	return (device_get_softc(devclass_get_device(dc, unit)));
835246145Shselasky}
836246145Shselasky
837246145Shselaskyint
838246145Shselaskydevclass_get_maxunit(devclass_t dc)
839246145Shselasky{
840246145Shselasky	int max_unit = 0;
841246145Shselasky
842246145Shselasky	if (dc) {
843246145Shselasky		max_unit = DEVCLASS_MAXUNIT;
844246145Shselasky		while (max_unit--) {
845246145Shselasky			if (dc->dev_list[max_unit]) {
846246145Shselasky				break;
847246145Shselasky			}
848246145Shselasky		}
849246145Shselasky		max_unit++;
850246145Shselasky	}
851246145Shselasky	return (max_unit);
852246145Shselasky}
853246145Shselasky
854246145Shselaskydevice_t
855246145Shselaskydevclass_get_device(devclass_t dc, int unit)
856246145Shselasky{
857246145Shselasky	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
858246145Shselasky	    NULL : dc->dev_list[unit]);
859246145Shselasky}
860246145Shselasky
861246145Shselaskydevclass_t
862246145Shselaskydevclass_find(const char *classname)
863246145Shselasky{
864246145Shselasky	const struct module_data *mod;
865246145Shselasky
866246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
867246145Shselasky		if (devclass_equal(mod->mod_name, classname))
868246145Shselasky			return (mod->devclass_pp[0]);
869246145Shselasky	}
870246145Shselasky	return (NULL);
871246145Shselasky}
872246145Shselasky
873246145Shselaskyvoid
874246145Shselaskymodule_register(void *data)
875246145Shselasky{
876246145Shselasky	struct module_data *mdata = data;
877246145Shselasky
878246145Shselasky	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
879246145Shselasky}
880246145Shselasky
881246145Shselasky/*------------------------------------------------------------------------*
882246145Shselasky * System startup
883246145Shselasky *------------------------------------------------------------------------*/
884246145Shselasky
885246145Shselaskystatic void
886246145Shselaskysysinit_run(const void **ppdata)
887246145Shselasky{
888246145Shselasky	const struct sysinit *psys;
889246145Shselasky
890246145Shselasky	while ((psys = *ppdata) != NULL) {
891246145Shselasky		(psys->func) (psys->data);
892246145Shselasky		ppdata++;
893246145Shselasky	}
894246145Shselasky}
895246145Shselasky
896246145Shselasky/*------------------------------------------------------------------------*
897246145Shselasky * USB process API
898246145Shselasky *------------------------------------------------------------------------*/
899246145Shselasky
900246145Shselaskystatic int usb_do_process(struct usb_process *);
901246145Shselaskystatic int usb_proc_level = -1;
902246145Shselaskystatic struct mtx usb_proc_mtx;
903246145Shselasky
904246145Shselaskyvoid
905246145Shselaskyusb_idle(void)
906246145Shselasky{
907246145Shselasky	int old_level = usb_proc_level;
908246145Shselasky	int old_giant = Giant.owned;
909246145Shselasky	int worked;
910246145Shselasky
911246145Shselasky	device_run_interrupts(usb_pci_root);
912246145Shselasky
913246145Shselasky	do {
914246145Shselasky		worked = 0;
915246145Shselasky		Giant.owned = 0;
916246145Shselasky
917246145Shselasky		while (++usb_proc_level < USB_PROC_MAX)
918246145Shselasky			worked |= usb_do_process(usb_process + usb_proc_level);
919246145Shselasky
920246145Shselasky		usb_proc_level = old_level;
921246145Shselasky		Giant.owned = old_giant;
922246145Shselasky
923246145Shselasky	} while (worked);
924246145Shselasky}
925246145Shselasky
926246145Shselaskyvoid
927246145Shselaskyusb_init(void)
928246145Shselasky{
929246145Shselasky	sysinit_run(sysinit_data);
930246145Shselasky}
931246145Shselasky
932246145Shselaskyvoid
933246145Shselaskyusb_uninit(void)
934246145Shselasky{
935246145Shselasky	sysinit_run(sysuninit_data);
936246145Shselasky}
937246145Shselasky
938246145Shselaskystatic void
939246145Shselaskyusb_process_init_sub(struct usb_process *up)
940246145Shselasky{
941246145Shselasky	TAILQ_INIT(&up->up_qhead);
942246145Shselasky
943246145Shselasky	cv_init(&up->up_cv, "-");
944246145Shselasky	cv_init(&up->up_drain, "usbdrain");
945246145Shselasky
946246145Shselasky	up->up_mtx = &usb_proc_mtx;
947246145Shselasky}
948246145Shselasky
949246145Shselaskystatic void
950246145Shselaskyusb_process_init(void *arg)
951246145Shselasky{
952246145Shselasky	uint8_t x;
953246145Shselasky
954246145Shselasky	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
955246145Shselasky
956246145Shselasky	for (x = 0; x != USB_PROC_MAX; x++)
957246145Shselasky		usb_process_init_sub(&usb_process[x]);
958246145Shselasky
959246145Shselasky}
960246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
961246145Shselasky
962246145Shselaskystatic int
963246145Shselaskyusb_do_process(struct usb_process *up)
964246145Shselasky{
965246145Shselasky	struct usb_proc_msg *pm;
966246145Shselasky	int worked = 0;
967246145Shselasky
968246145Shselasky	mtx_lock(&usb_proc_mtx);
969246145Shselasky
970246145Shselaskyrepeat:
971246145Shselasky	pm = TAILQ_FIRST(&up->up_qhead);
972246145Shselasky
973246145Shselasky	if (pm != NULL) {
974246145Shselasky
975246145Shselasky		worked = 1;
976246145Shselasky
977246145Shselasky		(pm->pm_callback) (pm);
978246145Shselasky
979246145Shselasky		if (pm == TAILQ_FIRST(&up->up_qhead)) {
980246145Shselasky			/* nothing changed */
981246145Shselasky			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
982246145Shselasky			pm->pm_qentry.tqe_prev = NULL;
983246145Shselasky		}
984246145Shselasky		goto repeat;
985246145Shselasky	}
986246145Shselasky	mtx_unlock(&usb_proc_mtx);
987246145Shselasky
988246145Shselasky	return (worked);
989246145Shselasky}
990246145Shselasky
991246145Shselaskyvoid   *
992246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
993246145Shselasky{
994246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
995246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
996246145Shselasky	struct usb_proc_msg *pm2;
997246145Shselasky	usb_size_t d;
998246145Shselasky	uint8_t t;
999246145Shselasky
1000246145Shselasky	t = 0;
1001246145Shselasky
1002246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1003246145Shselasky		t |= 1;
1004246145Shselasky	}
1005246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1006246145Shselasky		t |= 2;
1007246145Shselasky	}
1008246145Shselasky	if (t == 0) {
1009246145Shselasky		/*
1010246145Shselasky		 * No entries are queued. Queue "pm0" and use the existing
1011246145Shselasky		 * message number.
1012246145Shselasky		 */
1013246145Shselasky		pm2 = pm0;
1014246145Shselasky	} else if (t == 1) {
1015246145Shselasky		/* Check if we need to increment the message number. */
1016246145Shselasky		if (pm0->pm_num == up->up_msg_num) {
1017246145Shselasky			up->up_msg_num++;
1018246145Shselasky		}
1019246145Shselasky		pm2 = pm1;
1020246145Shselasky	} else if (t == 2) {
1021246145Shselasky		/* Check if we need to increment the message number. */
1022246145Shselasky		if (pm1->pm_num == up->up_msg_num) {
1023246145Shselasky			up->up_msg_num++;
1024246145Shselasky		}
1025246145Shselasky		pm2 = pm0;
1026246145Shselasky	} else if (t == 3) {
1027246145Shselasky		/*
1028246145Shselasky		 * Both entries are queued. Re-queue the entry closest to
1029246145Shselasky		 * the end.
1030246145Shselasky		 */
1031246145Shselasky		d = (pm1->pm_num - pm0->pm_num);
1032246145Shselasky
1033246145Shselasky		/* Check sign after subtraction */
1034246145Shselasky		if (d & 0x80000000) {
1035246145Shselasky			pm2 = pm0;
1036246145Shselasky		} else {
1037246145Shselasky			pm2 = pm1;
1038246145Shselasky		}
1039246145Shselasky
1040246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1041246145Shselasky	} else {
1042246145Shselasky		pm2 = NULL;		/* panic - should not happen */
1043246145Shselasky	}
1044246145Shselasky
1045246145Shselasky	/* Put message last on queue */
1046246145Shselasky
1047246145Shselasky	pm2->pm_num = up->up_msg_num;
1048246145Shselasky	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1049246145Shselasky
1050246145Shselasky	return (pm2);
1051246145Shselasky}
1052246145Shselasky
1053246145Shselasky/*------------------------------------------------------------------------*
1054246145Shselasky *	usb_proc_is_gone
1055246145Shselasky *
1056246145Shselasky * Return values:
1057246145Shselasky *    0: USB process is running
1058246145Shselasky * Else: USB process is tearing down
1059246145Shselasky *------------------------------------------------------------------------*/
1060246145Shselaskyuint8_t
1061246145Shselaskyusb_proc_is_gone(struct usb_process *up)
1062246145Shselasky{
1063246145Shselasky	return (0);
1064246145Shselasky}
1065246145Shselasky
1066246145Shselasky/*------------------------------------------------------------------------*
1067246145Shselasky *	usb_proc_mwait
1068246145Shselasky *
1069246145Shselasky * This function will return when the USB process message pointed to
1070246145Shselasky * by "pm" is no longer on a queue. This function must be called
1071246145Shselasky * having "usb_proc_mtx" locked.
1072246145Shselasky *------------------------------------------------------------------------*/
1073246145Shselaskyvoid
1074246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1075246145Shselasky{
1076246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1077246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1078246145Shselasky
1079246145Shselasky	/* Just remove the messages from the queue. */
1080246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1081246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1082246145Shselasky		pm0->pm_qentry.tqe_prev = NULL;
1083246145Shselasky	}
1084246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1085246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1086246145Shselasky		pm1->pm_qentry.tqe_prev = NULL;
1087246145Shselasky	}
1088246145Shselasky}
1089246145Shselasky
1090246145Shselasky/*------------------------------------------------------------------------*
1091246145Shselasky * SYSTEM attach
1092246145Shselasky *------------------------------------------------------------------------*/
1093246145Shselasky
1094246145Shselaskystatic device_method_t pci_methods[] = {
1095246145Shselasky	DEVMETHOD_END
1096246145Shselasky};
1097246145Shselasky
1098246145Shselaskystatic driver_t pci_driver = {
1099246145Shselasky	.name = "pci",
1100246145Shselasky	.methods = pci_methods,
1101246145Shselasky};
1102246145Shselasky
1103246145Shselaskystatic devclass_t pci_devclass;
1104246145Shselasky
1105246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1106246145Shselasky
1107246145Shselaskystatic const char *usb_pci_devices[] = {
1108246145Shselasky#ifdef USB_PROBE_LIST
1109246145Shselasky	USB_PROBE_LIST
1110246145Shselasky#endif
1111246145Shselasky};
1112246145Shselasky
1113246145Shselasky#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1114246145Shselasky
1115246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX];
1116246145Shselasky
1117246145Shselaskystatic void
1118246145Shselaskyusb_pci_mod_load(void *arg)
1119246145Shselasky{
1120246145Shselasky	uint32_t x;
1121246145Shselasky
1122246145Shselasky	usb_pci_root = device_add_child(NULL, "pci", -1);
1123246145Shselasky	if (usb_pci_root == NULL)
1124246145Shselasky		return;
1125246145Shselasky
1126246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1127246145Shselasky		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1128246145Shselasky		if (usb_pci_dev[x] == NULL)
1129246145Shselasky			continue;
1130246145Shselasky		if (device_probe_and_attach(usb_pci_dev[x])) {
1131246145Shselasky			device_printf(usb_pci_dev[x],
1132246145Shselasky			    "WARNING: Probe and attach failed!\n");
1133246145Shselasky		}
1134246145Shselasky	}
1135246145Shselasky}
1136246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1137246145Shselasky
1138246145Shselaskystatic void
1139246145Shselaskyusb_pci_mod_unload(void *arg)
1140246145Shselasky{
1141246145Shselasky	uint32_t x;
1142246145Shselasky
1143246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1144246145Shselasky		if (usb_pci_dev[x]) {
1145246145Shselasky			device_detach(usb_pci_dev[x]);
1146246145Shselasky			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1147246145Shselasky		}
1148246145Shselasky	}
1149246145Shselasky	if (usb_pci_root)
1150246145Shselasky		device_delete_child(NULL, usb_pci_root);
1151246145Shselasky}
1152246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1153246145Shselasky
1154246145Shselasky/*------------------------------------------------------------------------*
1155246145Shselasky * MALLOC API
1156246145Shselasky *------------------------------------------------------------------------*/
1157246145Shselasky
1158246145Shselasky#define	USB_POOL_ALIGN 8
1159246145Shselasky
1160246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1161246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE;
1162246145Shselaskystatic uint32_t usb_pool_entries;
1163246145Shselasky
1164246145Shselaskystruct malloc_hdr {
1165246145Shselasky	TAILQ_ENTRY(malloc_hdr) entry;
1166246145Shselasky	uint32_t size;
1167246145Shselasky} __aligned(USB_POOL_ALIGN);
1168246145Shselasky
1169246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head =
1170246145Shselasky	TAILQ_HEAD_INITIALIZER(malloc_head);
1171246145Shselasky
1172246145Shselaskyvoid   *
1173246145Shselaskyusb_malloc(unsigned long size)
1174246145Shselasky{
1175246145Shselasky	struct malloc_hdr *hdr;
1176246145Shselasky
1177246145Shselasky	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1178246145Shselasky	size += sizeof(struct malloc_hdr);
1179246145Shselasky
1180246145Shselasky	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1181246145Shselasky		if (hdr->size == size)
1182246145Shselasky			break;
1183246145Shselasky	}
1184246145Shselasky
1185246145Shselasky	if (hdr) {
1186246145Shselasky		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1187246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1188246145Shselasky
1189246145Shselasky		TAILQ_REMOVE(&malloc_head, hdr, entry);
1190246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1191246145Shselasky		return (hdr + 1);
1192246145Shselasky	}
1193246145Shselasky	if (usb_pool_rem >= size) {
1194246145Shselasky		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1195246145Shselasky		hdr->size = size;
1196246145Shselasky
1197246145Shselasky		usb_pool_rem -= size;
1198246145Shselasky		usb_pool_entries++;
1199246145Shselasky
1200246145Shselasky		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1201246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1202246145Shselasky
1203246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1204246145Shselasky		return (hdr + 1);
1205246145Shselasky	}
1206246145Shselasky	return (NULL);
1207246145Shselasky}
1208246145Shselasky
1209246145Shselaskyvoid
1210246145Shselaskyusb_free(void *arg)
1211246145Shselasky{
1212246145Shselasky	struct malloc_hdr *hdr;
1213246145Shselasky
1214246145Shselasky	if (arg == NULL)
1215246145Shselasky		return;
1216246145Shselasky
1217246145Shselasky	hdr = arg;
1218246145Shselasky	hdr--;
1219246145Shselasky
1220246145Shselasky	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1221246145Shselasky}
1222246145Shselasky
1223246145Shselaskychar   *
1224246145Shselaskyusb_strdup(const char *str)
1225246145Shselasky{
1226246145Shselasky	char *tmp;
1227246145Shselasky	int len;
1228246145Shselasky
1229246145Shselasky	len = 1 + strlen(str);
1230246145Shselasky
1231246145Shselasky	tmp = usb_malloc(len);
1232246145Shselasky	if (tmp == NULL)
1233246145Shselasky		return (NULL);
1234246145Shselasky
1235246145Shselasky	memcpy(tmp, str, len);
1236246145Shselasky	return (tmp);
1237246145Shselasky}
1238