1246145Shselasky/* $FreeBSD: stable/11/stand/kshim/bsd_kernel.c 315221 2017-03-14 02:06:03Z pfg $ */
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;
38291405Szbbint (*bus_alloc_resource_any_cb)(struct resource *res, device_t dev,
39291405Szbb    int type, int *rid, unsigned int flags);
40291405Szbbint (*ofw_bus_status_ok_cb)(device_t dev);
41291405Szbbint (*ofw_bus_is_compatible_cb)(device_t dev, char *name);
42246145Shselasky
43246145Shselaskystatic void
44246145Shselaskymtx_system_init(void *arg)
45246145Shselasky{
46246145Shselasky	mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE);
47246145Shselasky}
48246145ShselaskySYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL);
49246145Shselasky
50294547Swmaint
51294547Swmabus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
52294547Swma		   bus_size_t boundary, bus_addr_t lowaddr,
53294547Swma		   bus_addr_t highaddr, bus_dma_filter_t *filter,
54294547Swma		   void *filterarg, bus_size_t maxsize, int nsegments,
55294547Swma		   bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
56294547Swma		   void *lockfuncarg, bus_dma_tag_t *dmat)
57294547Swma{
58294547Swma	struct bus_dma_tag *ret;
59294547Swma
60294547Swma	ret = malloc(sizeof(struct bus_dma_tag), XXX, XXX);
61294547Swma	if (*dmat == NULL)
62294547Swma		return (ENOMEM);
63294547Swma	ret->alignment = alignment;
64294547Swma	ret->maxsize = maxsize;
65294547Swma
66294547Swma	*dmat = ret;
67294547Swma
68294547Swma	return (0);
69294547Swma}
70294547Swma
71294547Swmaint
72294547Swmabus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
73294547Swma    bus_dmamap_t *mapp)
74294547Swma{
75294547Swma	void *addr;
76294547Swma
77294547Swma	addr = malloc(dmat->maxsize + dmat->alignment, XXX, XXX);
78315221Spfg	if (addr == NULL)
79294547Swma		return (ENOMEM);
80294547Swma
81294547Swma	*mapp = addr;
82294547Swma	addr = (void*)(((uintptr_t)addr + dmat->alignment - 1) & ~(dmat->alignment - 1));
83294547Swma
84294547Swma	*vaddr = addr;
85294547Swma	return (0);
86294547Swma}
87294547Swma
88294547Swmaint
89294547Swmabus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
90294547Swma    bus_size_t buflen, bus_dmamap_callback_t *callback,
91294547Swma    void *callback_arg, int flags)
92294547Swma{
93294547Swma	bus_dma_segment_t segs[1];
94294547Swma
95294547Swma	segs[0].ds_addr = (uintptr_t)buf;
96294547Swma	segs[0].ds_len = buflen;
97294547Swma
98294547Swma	(*callback)(callback_arg, segs, 1, 0);
99294547Swma
100294547Swma	return (0);
101294547Swma}
102294547Swma
103294547Swmavoid
104294547Swmabus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
105294547Swma{
106294547Swma
107294547Swma	free(map, XXX);
108294547Swma}
109294547Swma
110294547Swmaint
111294547Swmabus_dma_tag_destroy(bus_dma_tag_t dmat)
112294547Swma{
113294547Swma
114294547Swma	free(dmat, XXX);
115294547Swma	return (0);
116294547Swma}
117294547Swma
118291405Szbbstruct resource *
119291405Szbbbus_alloc_resource_any(device_t dev, int type, int *rid, unsigned int flags)
120291405Szbb{
121291405Szbb	struct resource *res;
122291405Szbb	int ret = EINVAL;
123291405Szbb
124291405Szbb	res = malloc(sizeof(*res), XXX, XXX);
125291405Szbb	if (res == NULL)
126291405Szbb		return (NULL);
127291405Szbb
128291405Szbb	res->__r_i = malloc(sizeof(struct resource_i), XXX, XXX);
129291405Szbb	if (res->__r_i == NULL) {
130291405Szbb		free(res, XXX);
131291405Szbb		return (NULL);
132291405Szbb	}
133291405Szbb
134291405Szbb	if (bus_alloc_resource_any_cb != NULL)
135291405Szbb		ret = (*bus_alloc_resource_any_cb)(res, dev, type, rid, flags);
136291405Szbb	if (ret == 0)
137291405Szbb		return (res);
138291405Szbb
139291405Szbb	free(res->__r_i, XXX);
140291405Szbb	free(res, XXX);
141291405Szbb	return (NULL);
142291405Szbb}
143291405Szbb
144291405Szbbint
145291405Szbbbus_alloc_resources(device_t dev, struct resource_spec *rs,
146291405Szbb    struct resource **res)
147291405Szbb{
148291405Szbb	int i;
149291405Szbb
150291405Szbb	for (i = 0; rs[i].type != -1; i++)
151291405Szbb		res[i] = NULL;
152291405Szbb	for (i = 0; rs[i].type != -1; i++) {
153291405Szbb		res[i] = bus_alloc_resource_any(dev,
154291405Szbb		    rs[i].type, &rs[i].rid, rs[i].flags);
155291405Szbb		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
156291405Szbb			bus_release_resources(dev, rs, res);
157291405Szbb			return (ENXIO);
158291405Szbb		}
159291405Szbb	}
160291405Szbb	return (0);
161291405Szbb}
162291405Szbb
163246145Shselaskyvoid
164291405Szbbbus_release_resources(device_t dev, const struct resource_spec *rs,
165291405Szbb    struct resource **res)
166291405Szbb{
167291405Szbb	int i;
168291405Szbb
169291405Szbb	for (i = 0; rs[i].type != -1; i++)
170291405Szbb		if (res[i] != NULL) {
171291405Szbb			bus_release_resource(
172291405Szbb			    dev, rs[i].type, rs[i].rid, res[i]);
173291405Szbb			res[i] = NULL;
174291405Szbb		}
175291405Szbb}
176291405Szbb
177291405Szbbint
178291405Szbbbus_setup_intr(device_t dev, struct resource *r, int flags,
179291405Szbb    driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep)
180291405Szbb{
181291405Szbb
182291405Szbb	dev->dev_irq_filter = filter;
183291405Szbb	dev->dev_irq_fn = handler;
184291405Szbb	dev->dev_irq_arg = arg;
185291405Szbb
186291405Szbb	return (0);
187291405Szbb}
188291405Szbb
189291405Szbbint
190291405Szbbbus_teardown_intr(device_t dev, struct resource *r, void *cookie)
191291405Szbb{
192291405Szbb
193291405Szbb	dev->dev_irq_filter = NULL;
194291405Szbb	dev->dev_irq_fn = NULL;
195291405Szbb	dev->dev_irq_arg = NULL;
196291405Szbb
197291405Szbb	return (0);
198291405Szbb}
199291405Szbb
200291405Szbbint
201291405Szbbbus_release_resource(device_t dev, int type, int rid, struct resource *r)
202291405Szbb{
203291405Szbb	/* Resource releasing is not supported */
204291405Szbb	return (EINVAL);
205291405Szbb}
206291405Szbb
207291405Szbbint
208291405Szbbbus_generic_attach(device_t dev)
209291405Szbb{
210291405Szbb	device_t child;
211291405Szbb
212291405Szbb	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
213291405Szbb		device_probe_and_attach(child);
214291405Szbb	}
215291405Szbb
216291405Szbb	return (0);
217291405Szbb}
218291405Szbb
219291405Szbbbus_space_tag_t
220291405Szbbrman_get_bustag(struct resource *r)
221291405Szbb{
222291405Szbb
223291405Szbb	return (r->r_bustag);
224291405Szbb}
225291405Szbb
226291405Szbbbus_space_handle_t
227291405Szbbrman_get_bushandle(struct resource *r)
228291405Szbb{
229291405Szbb
230291405Szbb	return (r->r_bushandle);
231291405Szbb}
232291405Szbb
233291405Szbbu_long
234291405Szbbrman_get_size(struct resource *r)
235291405Szbb{
236291405Szbb
237291405Szbb	return (r->__r_i->r_end - r->__r_i->r_start + 1);
238291405Szbb}
239291405Szbb
240291405Szbbint
241291405Szbbofw_bus_status_okay(device_t dev)
242291405Szbb{
243291405Szbb	if (ofw_bus_status_ok_cb == NULL)
244291405Szbb		return (0);
245291405Szbb
246291405Szbb	return ((*ofw_bus_status_ok_cb)(dev));
247291405Szbb}
248291405Szbb
249291405Szbbint
250291405Szbbofw_bus_is_compatible(device_t dev, char *name)
251291405Szbb{
252291405Szbb	if (ofw_bus_is_compatible_cb == NULL)
253291405Szbb		return (0);
254291405Szbb
255291405Szbb	return ((*ofw_bus_is_compatible_cb)(dev, name));
256291405Szbb}
257291405Szbb
258291405Szbbvoid
259246145Shselaskymtx_init(struct mtx *mtx, const char *name, const char *type, int opt)
260246145Shselasky{
261246145Shselasky	mtx->owned = 0;
262246145Shselasky	mtx->parent = mtx;
263246145Shselasky}
264246145Shselasky
265246145Shselaskyvoid
266246145Shselaskymtx_lock(struct mtx *mtx)
267246145Shselasky{
268246145Shselasky	mtx = mtx->parent;
269246145Shselasky	mtx->owned++;
270246145Shselasky}
271246145Shselasky
272246145Shselaskyvoid
273246145Shselaskymtx_unlock(struct mtx *mtx)
274246145Shselasky{
275246145Shselasky	mtx = mtx->parent;
276246145Shselasky	mtx->owned--;
277246145Shselasky}
278246145Shselasky
279246145Shselaskyint
280246145Shselaskymtx_owned(struct mtx *mtx)
281246145Shselasky{
282246145Shselasky	mtx = mtx->parent;
283246145Shselasky	return (mtx->owned != 0);
284246145Shselasky}
285246145Shselasky
286246145Shselaskyvoid
287246145Shselaskymtx_destroy(struct mtx *mtx)
288246145Shselasky{
289246145Shselasky	/* NOP */
290246145Shselasky}
291246145Shselasky
292246145Shselasky/*------------------------------------------------------------------------*
293246145Shselasky * Implementation of shared/exclusive mutex API
294246145Shselasky *------------------------------------------------------------------------*/
295246145Shselasky
296246145Shselaskyvoid
297246145Shselaskysx_init_flags(struct sx *sx, const char *name, int flags)
298246145Shselasky{
299246145Shselasky	sx->owned = 0;
300246145Shselasky}
301246145Shselasky
302246145Shselaskyvoid
303246145Shselaskysx_destroy(struct sx *sx)
304246145Shselasky{
305246145Shselasky	/* NOP */
306246145Shselasky}
307246145Shselasky
308246145Shselaskyvoid
309246145Shselaskysx_xlock(struct sx *sx)
310246145Shselasky{
311246145Shselasky	sx->owned++;
312246145Shselasky}
313246145Shselasky
314246145Shselaskyvoid
315246145Shselaskysx_xunlock(struct sx *sx)
316246145Shselasky{
317246145Shselasky	sx->owned--;
318246145Shselasky}
319246145Shselasky
320246145Shselaskyint
321246145Shselaskysx_xlocked(struct sx *sx)
322246145Shselasky{
323246145Shselasky	return (sx->owned != 0);
324246145Shselasky}
325246145Shselasky
326246145Shselasky/*------------------------------------------------------------------------*
327246145Shselasky * Implementaiton of condition variable API
328246145Shselasky *------------------------------------------------------------------------*/
329246145Shselasky
330246145Shselaskyvoid
331246145Shselaskycv_init(struct cv *cv, const char *desc)
332246145Shselasky{
333246145Shselasky	cv->sleeping = 0;
334246145Shselasky}
335246145Shselasky
336246145Shselaskyvoid
337246145Shselaskycv_destroy(struct cv *cv)
338246145Shselasky{
339246145Shselasky	/* NOP */
340246145Shselasky}
341246145Shselasky
342246145Shselaskyvoid
343246145Shselaskycv_wait(struct cv *cv, struct mtx *mtx)
344246145Shselasky{
345246145Shselasky	cv_timedwait(cv, mtx, -1);
346246145Shselasky}
347246145Shselasky
348246145Shselaskyint
349246145Shselaskycv_timedwait(struct cv *cv, struct mtx *mtx, int timo)
350246145Shselasky{
351246145Shselasky	int start = ticks;
352246145Shselasky	int delta;
353291403Szbb	int time = 0;
354246145Shselasky
355246145Shselasky	if (cv->sleeping)
356246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
357246145Shselasky
358246145Shselasky	cv->sleeping = 1;
359246145Shselasky
360246145Shselasky	while (cv->sleeping) {
361246145Shselasky		if (timo >= 0) {
362246145Shselasky			delta = ticks - start;
363246145Shselasky			if (delta >= timo || delta < 0)
364246145Shselasky				break;
365246145Shselasky		}
366246145Shselasky		mtx_unlock(mtx);
367246145Shselasky
368246145Shselasky		usb_idle();
369246145Shselasky
370291403Szbb		if (++time >= (1000000 / hz)) {
371291403Szbb			time = 0;
372291403Szbb			callout_process(1);
373291403Szbb		}
374291403Szbb
375291403Szbb		/* Sleep for 1 us */
376291403Szbb		delay(1);
377291403Szbb
378246145Shselasky		mtx_lock(mtx);
379246145Shselasky	}
380246145Shselasky
381246145Shselasky	if (cv->sleeping) {
382246145Shselasky		cv->sleeping = 0;
383246145Shselasky		return (EWOULDBLOCK);	/* not allowed */
384246145Shselasky	}
385246145Shselasky	return (0);
386246145Shselasky}
387246145Shselasky
388246145Shselaskyvoid
389246145Shselaskycv_signal(struct cv *cv)
390246145Shselasky{
391246145Shselasky	cv->sleeping = 0;
392246145Shselasky}
393246145Shselasky
394246145Shselaskyvoid
395246145Shselaskycv_broadcast(struct cv *cv)
396246145Shselasky{
397246145Shselasky	cv->sleeping = 0;
398246145Shselasky}
399246145Shselasky
400246145Shselasky/*------------------------------------------------------------------------*
401246145Shselasky * Implementation of callout API
402246145Shselasky *------------------------------------------------------------------------*/
403246145Shselasky
404246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *);
405246145Shselasky
406246145Shselaskyvolatile int ticks = 0;
407246145Shselasky
408246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
409246145Shselasky
410246145Shselaskystatic struct mtx mtx_callout;
411246145Shselaskystatic struct usb_proc_msg callout_msg[2];
412246145Shselasky
413246145Shselaskystatic void
414246145Shselaskycallout_system_init(void *arg)
415246145Shselasky{
416246145Shselasky	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
417246145Shselasky
418246145Shselasky	callout_msg[0].pm_callback = &callout_proc_msg;
419246145Shselasky	callout_msg[1].pm_callback = &callout_proc_msg;
420246145Shselasky}
421246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
422246145Shselasky
423246145Shselaskystatic void
424246145Shselaskycallout_callback(struct callout *c)
425246145Shselasky{
426246145Shselasky	mtx_lock(c->mtx);
427246145Shselasky
428246145Shselasky	mtx_lock(&mtx_callout);
429246145Shselasky	if (c->entry.le_prev != NULL) {
430246145Shselasky		LIST_REMOVE(c, entry);
431246145Shselasky		c->entry.le_prev = NULL;
432246145Shselasky	}
433246145Shselasky	mtx_unlock(&mtx_callout);
434246145Shselasky
435306255Shselasky	if (c->c_func != NULL)
436306255Shselasky		(c->c_func) (c->c_arg);
437246145Shselasky
438246145Shselasky	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
439246145Shselasky		mtx_unlock(c->mtx);
440246145Shselasky}
441246145Shselasky
442246145Shselaskyvoid
443246145Shselaskycallout_process(int timeout)
444246145Shselasky{
445246145Shselasky	ticks += timeout;
446246145Shselasky	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
447246145Shselasky}
448246145Shselasky
449246145Shselaskystatic void
450246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg)
451246145Shselasky{
452246145Shselasky	struct callout *c;
453246145Shselasky	int delta;
454246145Shselasky
455246145Shselaskyrepeat:
456246145Shselasky	mtx_lock(&mtx_callout);
457246145Shselasky
458246145Shselasky	LIST_FOREACH(c, &head_callout, entry) {
459246145Shselasky
460246145Shselasky		delta = c->timeout - ticks;
461246145Shselasky		if (delta < 0) {
462246145Shselasky			mtx_unlock(&mtx_callout);
463246145Shselasky
464246145Shselasky			callout_callback(c);
465246145Shselasky
466246145Shselasky			goto repeat;
467246145Shselasky		}
468246145Shselasky	}
469246145Shselasky	mtx_unlock(&mtx_callout);
470246145Shselasky}
471246145Shselasky
472246145Shselaskyvoid
473246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
474246145Shselasky{
475246145Shselasky	memset(c, 0, sizeof(*c));
476246145Shselasky
477246145Shselasky	if (mtx == NULL)
478246145Shselasky		mtx = &Giant;
479246145Shselasky
480246145Shselasky	c->mtx = mtx;
481246145Shselasky	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
482246145Shselasky}
483246145Shselasky
484246145Shselaskyvoid
485246145Shselaskycallout_reset(struct callout *c, int to_ticks,
486246145Shselasky    void (*func) (void *), void *arg)
487246145Shselasky{
488246145Shselasky	callout_stop(c);
489246145Shselasky
490306255Shselasky	c->c_func = func;
491306255Shselasky	c->c_arg = arg;
492246145Shselasky	c->timeout = ticks + to_ticks;
493246145Shselasky
494246145Shselasky	mtx_lock(&mtx_callout);
495246145Shselasky	LIST_INSERT_HEAD(&head_callout, c, entry);
496246145Shselasky	mtx_unlock(&mtx_callout);
497246145Shselasky}
498246145Shselasky
499246145Shselaskyvoid
500246145Shselaskycallout_stop(struct callout *c)
501246145Shselasky{
502246145Shselasky	mtx_lock(&mtx_callout);
503246145Shselasky
504246145Shselasky	if (c->entry.le_prev != NULL) {
505246145Shselasky		LIST_REMOVE(c, entry);
506246145Shselasky		c->entry.le_prev = NULL;
507246145Shselasky	}
508246145Shselasky	mtx_unlock(&mtx_callout);
509246145Shselasky
510306255Shselasky	c->c_func = NULL;
511306255Shselasky	c->c_arg = NULL;
512246145Shselasky}
513246145Shselasky
514246145Shselaskyvoid
515246145Shselaskycallout_drain(struct callout *c)
516246145Shselasky{
517246145Shselasky	if (c->mtx == NULL)
518246145Shselasky		return;			/* not initialised */
519246145Shselasky
520246145Shselasky	mtx_lock(c->mtx);
521246145Shselasky	callout_stop(c);
522246145Shselasky	mtx_unlock(c->mtx);
523246145Shselasky}
524246145Shselasky
525246145Shselaskyint
526246145Shselaskycallout_pending(struct callout *c)
527246145Shselasky{
528246145Shselasky	int retval;
529246145Shselasky
530246145Shselasky	mtx_lock(&mtx_callout);
531246145Shselasky	retval = (c->entry.le_prev != NULL);
532246145Shselasky	mtx_unlock(&mtx_callout);
533246145Shselasky
534246145Shselasky	return (retval);
535246145Shselasky}
536246145Shselasky
537246145Shselasky/*------------------------------------------------------------------------*
538246145Shselasky * Implementation of device API
539246145Shselasky *------------------------------------------------------------------------*/
540246145Shselasky
541246145Shselaskystatic const char unknown_string[] = { "unknown" };
542246145Shselasky
543246145Shselaskystatic TAILQ_HEAD(, module_data) module_head =
544246145Shselasky    TAILQ_HEAD_INITIALIZER(module_head);
545246145Shselasky
546246145Shselaskystatic uint8_t
547246145Shselaskydevclass_equal(const char *a, const char *b)
548246145Shselasky{
549246145Shselasky	char ta, tb;
550246145Shselasky
551246145Shselasky	if (a == b)
552246145Shselasky		return (1);
553246145Shselasky
554246145Shselasky	while (1) {
555246145Shselasky		ta = *a;
556246145Shselasky		tb = *b;
557246145Shselasky		if (ta != tb)
558246145Shselasky			return (0);
559246145Shselasky		if (ta == 0)
560246145Shselasky			break;
561246145Shselasky		a++;
562246145Shselasky		b++;
563246145Shselasky	}
564246145Shselasky	return (1);
565246145Shselasky}
566246145Shselasky
567246145Shselaskyint
568246145Shselaskybus_generic_resume(device_t dev)
569246145Shselasky{
570246145Shselasky	return (0);
571246145Shselasky}
572246145Shselasky
573246145Shselaskyint
574246145Shselaskybus_generic_shutdown(device_t dev)
575246145Shselasky{
576246145Shselasky	return (0);
577246145Shselasky}
578246145Shselasky
579246145Shselaskyint
580246145Shselaskybus_generic_suspend(device_t dev)
581246145Shselasky{
582246145Shselasky	return (0);
583246145Shselasky}
584246145Shselasky
585246145Shselaskyint
586246145Shselaskybus_generic_print_child(device_t dev, device_t child)
587246145Shselasky{
588246145Shselasky	return (0);
589246145Shselasky}
590246145Shselasky
591246145Shselaskyvoid
592246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver)
593246145Shselasky{
594246145Shselasky	return;
595246145Shselasky}
596246145Shselasky
597246145Shselaskydevice_t
598246145Shselaskydevice_get_parent(device_t dev)
599246145Shselasky{
600246145Shselasky	return (dev ? dev->dev_parent : NULL);
601246145Shselasky}
602246145Shselasky
603246145Shselaskyvoid
604266396Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter,
605266396Shselasky    driver_intr_t *fn, void *arg)
606246145Shselasky{
607266396Shselasky	dev->dev_irq_filter = filter;
608246145Shselasky	dev->dev_irq_fn = fn;
609246145Shselasky	dev->dev_irq_arg = arg;
610246145Shselasky}
611246145Shselasky
612246145Shselaskyvoid
613246145Shselaskydevice_run_interrupts(device_t parent)
614246145Shselasky{
615246145Shselasky	device_t child;
616246145Shselasky
617246145Shselasky	if (parent == NULL)
618246145Shselasky		return;
619246145Shselasky
620246145Shselasky	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
621266396Shselasky		int status;
622266396Shselasky		if (child->dev_irq_filter != NULL)
623266396Shselasky			status = child->dev_irq_filter(child->dev_irq_arg);
624266396Shselasky		else
625266396Shselasky			status = FILTER_SCHEDULE_THREAD;
626266396Shselasky
627266396Shselasky		if (status == FILTER_SCHEDULE_THREAD) {
628266396Shselasky			if (child->dev_irq_fn != NULL)
629266396Shselasky				(child->dev_irq_fn) (child->dev_irq_arg);
630266396Shselasky		}
631246145Shselasky	}
632246145Shselasky}
633246145Shselasky
634246145Shselaskyvoid
635246145Shselaskydevice_set_ivars(device_t dev, void *ivars)
636246145Shselasky{
637246145Shselasky	dev->dev_aux = ivars;
638246145Shselasky}
639246145Shselasky
640246145Shselaskyvoid   *
641246145Shselaskydevice_get_ivars(device_t dev)
642246145Shselasky{
643246145Shselasky	return (dev ? dev->dev_aux : NULL);
644246145Shselasky}
645246145Shselasky
646246145Shselaskyint
647246145Shselaskydevice_get_unit(device_t dev)
648246145Shselasky{
649246145Shselasky	return (dev ? dev->dev_unit : 0);
650246145Shselasky}
651246145Shselasky
652246145Shselaskyint
653246145Shselaskybus_generic_detach(device_t dev)
654246145Shselasky{
655246145Shselasky	device_t child;
656246145Shselasky	int error;
657246145Shselasky
658246145Shselasky	if (!dev->dev_attached)
659246145Shselasky		return (EBUSY);
660246145Shselasky
661246145Shselasky	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
662246145Shselasky		if ((error = device_detach(child)) != 0)
663246145Shselasky			return (error);
664246145Shselasky	}
665246145Shselasky	return (0);
666246145Shselasky}
667246145Shselasky
668246145Shselaskyconst char *
669246145Shselaskydevice_get_nameunit(device_t dev)
670246145Shselasky{
671246145Shselasky	if (dev && dev->dev_nameunit[0])
672246145Shselasky		return (dev->dev_nameunit);
673246145Shselasky
674246145Shselasky	return (unknown_string);
675246145Shselasky}
676246145Shselasky
677246145Shselaskystatic uint8_t
678246145Shselaskydevclass_create(devclass_t *dc_pp)
679246145Shselasky{
680246145Shselasky	if (dc_pp == NULL) {
681246145Shselasky		return (1);
682246145Shselasky	}
683246145Shselasky	if (dc_pp[0] == NULL) {
684246145Shselasky		dc_pp[0] = malloc(sizeof(**(dc_pp)),
685246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
686246145Shselasky
687246145Shselasky		if (dc_pp[0] == NULL) {
688246145Shselasky			return (1);
689246145Shselasky		}
690246145Shselasky	}
691246145Shselasky	return (0);
692246145Shselasky}
693246145Shselasky
694246145Shselaskystatic const struct module_data *
695246145Shselaskydevclass_find_create(const char *classname)
696246145Shselasky{
697246145Shselasky	const struct module_data *mod;
698246145Shselasky
699246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
700246145Shselasky		if (devclass_equal(mod->mod_name, classname)) {
701246145Shselasky			if (devclass_create(mod->devclass_pp)) {
702246145Shselasky				continue;
703246145Shselasky			}
704246145Shselasky			return (mod);
705246145Shselasky		}
706246145Shselasky	}
707246145Shselasky	return (NULL);
708246145Shselasky}
709246145Shselasky
710246145Shselaskystatic uint8_t
711246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev)
712246145Shselasky{
713246145Shselasky	device_t *pp_dev;
714246145Shselasky	device_t *end;
715246145Shselasky	uint8_t unit;
716246145Shselasky
717246145Shselasky	pp_dev = mod->devclass_pp[0]->dev_list;
718246145Shselasky	end = pp_dev + DEVCLASS_MAXUNIT;
719246145Shselasky	unit = 0;
720246145Shselasky
721246145Shselasky	while (pp_dev != end) {
722246145Shselasky		if (*pp_dev == NULL) {
723246145Shselasky			*pp_dev = dev;
724246145Shselasky			dev->dev_unit = unit;
725246145Shselasky			dev->dev_module = mod;
726246145Shselasky			snprintf(dev->dev_nameunit,
727246145Shselasky			    sizeof(dev->dev_nameunit),
728246145Shselasky			    "%s%d", device_get_name(dev), unit);
729246145Shselasky			return (0);
730246145Shselasky		}
731246145Shselasky		pp_dev++;
732246145Shselasky		unit++;
733246145Shselasky	}
734246145Shselasky	DPRINTF("Could not add device to devclass.\n");
735246145Shselasky	return (1);
736246145Shselasky}
737246145Shselasky
738246145Shselaskystatic void
739246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev)
740246145Shselasky{
741246145Shselasky	if (mod == NULL) {
742246145Shselasky		return;
743246145Shselasky	}
744246145Shselasky	mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL;
745246145Shselasky	dev->dev_module = NULL;
746246145Shselasky}
747246145Shselasky
748246145Shselaskystatic device_t
749246145Shselaskymake_device(device_t parent, const char *name)
750246145Shselasky{
751246145Shselasky	device_t dev = NULL;
752246145Shselasky	const struct module_data *mod = NULL;
753246145Shselasky
754246145Shselasky	if (name) {
755246145Shselasky
756246145Shselasky		mod = devclass_find_create(name);
757246145Shselasky
758246145Shselasky		if (!mod) {
759246145Shselasky
760246145Shselasky			DPRINTF("%s:%d:%s: can't find device "
761246145Shselasky			    "class %s\n", __FILE__, __LINE__,
762246145Shselasky			    __FUNCTION__, name);
763246145Shselasky
764246145Shselasky			goto done;
765246145Shselasky		}
766246145Shselasky	}
767246145Shselasky	dev = malloc(sizeof(*dev),
768246145Shselasky	    M_DEVBUF, M_WAITOK | M_ZERO);
769246145Shselasky
770246145Shselasky	if (dev == NULL)
771246145Shselasky		goto done;
772246145Shselasky
773246145Shselasky	dev->dev_parent = parent;
774246145Shselasky	TAILQ_INIT(&dev->dev_children);
775246145Shselasky
776246145Shselasky	if (name) {
777246145Shselasky		dev->dev_fixed_class = 1;
778246145Shselasky		if (devclass_add_device(mod, dev)) {
779246145Shselasky			goto error;
780246145Shselasky		}
781246145Shselasky	}
782246145Shselaskydone:
783246145Shselasky	return (dev);
784246145Shselasky
785246145Shselaskyerror:
786246145Shselasky	if (dev) {
787246145Shselasky		free(dev, M_DEVBUF);
788246145Shselasky	}
789246145Shselasky	return (NULL);
790246145Shselasky}
791246145Shselasky
792246145Shselaskydevice_t
793246145Shselaskydevice_add_child(device_t dev, const char *name, int unit)
794246145Shselasky{
795246145Shselasky	device_t child;
796246145Shselasky
797246145Shselasky	if (unit != -1) {
798246145Shselasky		device_printf(dev, "Unit is not -1\n");
799246145Shselasky	}
800246145Shselasky	child = make_device(dev, name);
801246145Shselasky	if (child == NULL) {
802246145Shselasky		device_printf(dev, "Could not add child '%s'\n", name);
803246145Shselasky		goto done;
804246145Shselasky	}
805246145Shselasky	if (dev == NULL) {
806246145Shselasky		/* no parent */
807246145Shselasky		goto done;
808246145Shselasky	}
809246145Shselasky	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
810246145Shselaskydone:
811246145Shselasky	return (child);
812246145Shselasky}
813246145Shselasky
814246145Shselaskyint
815246145Shselaskydevice_delete_child(device_t dev, device_t child)
816246145Shselasky{
817246145Shselasky	int error = 0;
818246145Shselasky	device_t grandchild;
819246145Shselasky
820308401Shselasky	/* detach parent before deleting children, if any */
821308401Shselasky	error = device_detach(child);
822308401Shselasky	if (error)
823308401Shselasky		goto done;
824246145Shselasky
825308401Shselasky	/* remove children second */
826246145Shselasky	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
827246145Shselasky		error = device_delete_child(child, grandchild);
828246145Shselasky		if (error) {
829246145Shselasky			device_printf(dev, "Error deleting child!\n");
830246145Shselasky			goto done;
831246145Shselasky		}
832246145Shselasky	}
833246145Shselasky
834246145Shselasky	devclass_delete_device(child->dev_module, child);
835246145Shselasky
836246145Shselasky	if (dev != NULL) {
837246145Shselasky		/* remove child from parent */
838246145Shselasky		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
839246145Shselasky	}
840246145Shselasky	free(child, M_DEVBUF);
841246145Shselasky
842246145Shselaskydone:
843246145Shselasky	return (error);
844246145Shselasky}
845246145Shselasky
846246145Shselaskyint
847246145Shselaskydevice_delete_children(device_t dev)
848246145Shselasky{
849246145Shselasky	device_t child;
850246145Shselasky	int error = 0;
851246145Shselasky
852246145Shselasky	while ((child = TAILQ_FIRST(&dev->dev_children))) {
853246145Shselasky		error = device_delete_child(dev, child);
854246145Shselasky		if (error) {
855246145Shselasky			device_printf(dev, "Error deleting child!\n");
856246145Shselasky			break;
857246145Shselasky		}
858246145Shselasky	}
859246145Shselasky	return (error);
860246145Shselasky}
861246145Shselasky
862246145Shselaskyvoid
863246145Shselaskydevice_quiet(device_t dev)
864246145Shselasky{
865246145Shselasky	dev->dev_quiet = 1;
866246145Shselasky}
867246145Shselasky
868246145Shselaskyconst char *
869246145Shselaskydevice_get_desc(device_t dev)
870246145Shselasky{
871246145Shselasky	if (dev)
872246145Shselasky		return &(dev->dev_desc[0]);
873246145Shselasky	return (unknown_string);
874246145Shselasky}
875246145Shselasky
876246145Shselaskystatic int
877246145Shselaskydefault_method(void)
878246145Shselasky{
879246145Shselasky	/* do nothing */
880246145Shselasky	DPRINTF("Default method called\n");
881246145Shselasky	return (0);
882246145Shselasky}
883246145Shselasky
884246145Shselaskyvoid   *
885246145Shselaskydevice_get_method(device_t dev, const char *what)
886246145Shselasky{
887246145Shselasky	const struct device_method *mtod;
888246145Shselasky
889246145Shselasky	mtod = dev->dev_module->driver->methods;
890246145Shselasky	while (mtod->func != NULL) {
891246145Shselasky		if (devclass_equal(mtod->desc, what)) {
892246145Shselasky			return (mtod->func);
893246145Shselasky		}
894246145Shselasky		mtod++;
895246145Shselasky	}
896246145Shselasky	return ((void *)&default_method);
897246145Shselasky}
898246145Shselasky
899246145Shselaskyconst char *
900246145Shselaskydevice_get_name(device_t dev)
901246145Shselasky{
902246145Shselasky	if (dev == NULL)
903246145Shselasky		return (unknown_string);
904246145Shselasky
905246145Shselasky	return (dev->dev_module->driver->name);
906246145Shselasky}
907246145Shselasky
908246145Shselaskystatic int
909246145Shselaskydevice_allocate_softc(device_t dev)
910246145Shselasky{
911246145Shselasky	const struct module_data *mod;
912246145Shselasky
913246145Shselasky	mod = dev->dev_module;
914246145Shselasky
915246145Shselasky	if ((dev->dev_softc_alloc == 0) &&
916246145Shselasky	    (mod->driver->size != 0)) {
917246145Shselasky		dev->dev_sc = malloc(mod->driver->size,
918246145Shselasky		    M_DEVBUF, M_WAITOK | M_ZERO);
919246145Shselasky
920246145Shselasky		if (dev->dev_sc == NULL)
921246145Shselasky			return (ENOMEM);
922246145Shselasky
923246145Shselasky		dev->dev_softc_alloc = 1;
924246145Shselasky	}
925246145Shselasky	return (0);
926246145Shselasky}
927246145Shselasky
928246145Shselaskyint
929246145Shselaskydevice_probe_and_attach(device_t dev)
930246145Shselasky{
931246145Shselasky	const struct module_data *mod;
932246145Shselasky	const char *bus_name_parent;
933246145Shselasky
934246145Shselasky	bus_name_parent = device_get_name(device_get_parent(dev));
935246145Shselasky
936246145Shselasky	if (dev->dev_attached)
937246145Shselasky		return (0);		/* fail-safe */
938246145Shselasky
939246145Shselasky	if (dev->dev_fixed_class) {
940246145Shselasky
941246145Shselasky		mod = dev->dev_module;
942246145Shselasky
943246145Shselasky		if (DEVICE_PROBE(dev) <= 0) {
944246145Shselasky
945246145Shselasky			if (device_allocate_softc(dev) == 0) {
946246145Shselasky
947246145Shselasky				if (DEVICE_ATTACH(dev) == 0) {
948246145Shselasky					/* success */
949246145Shselasky					dev->dev_attached = 1;
950246145Shselasky					return (0);
951246145Shselasky				}
952246145Shselasky			}
953246145Shselasky		}
954246145Shselasky		device_detach(dev);
955246145Shselasky
956246145Shselasky		goto error;
957246145Shselasky	}
958246145Shselasky	/*
959246145Shselasky         * Else find a module for our device, if any
960246145Shselasky         */
961246145Shselasky
962246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
963246145Shselasky		if (devclass_equal(mod->bus_name, bus_name_parent)) {
964246145Shselasky			if (devclass_create(mod->devclass_pp)) {
965246145Shselasky				continue;
966246145Shselasky			}
967246145Shselasky			if (devclass_add_device(mod, dev)) {
968246145Shselasky				continue;
969246145Shselasky			}
970246145Shselasky			if (DEVICE_PROBE(dev) <= 0) {
971246145Shselasky
972246145Shselasky				if (device_allocate_softc(dev) == 0) {
973246145Shselasky
974246145Shselasky					if (DEVICE_ATTACH(dev) == 0) {
975246145Shselasky						/* success */
976246145Shselasky						dev->dev_attached = 1;
977246145Shselasky						return (0);
978246145Shselasky					}
979246145Shselasky				}
980246145Shselasky			}
981246145Shselasky			/* else try next driver */
982246145Shselasky
983246145Shselasky			device_detach(dev);
984246145Shselasky		}
985246145Shselasky	}
986246145Shselasky
987246145Shselaskyerror:
988246145Shselasky	return (ENODEV);
989246145Shselasky}
990246145Shselasky
991246145Shselaskyint
992246145Shselaskydevice_detach(device_t dev)
993246145Shselasky{
994246145Shselasky	const struct module_data *mod = dev->dev_module;
995246145Shselasky	int error;
996246145Shselasky
997246145Shselasky	if (dev->dev_attached) {
998246145Shselasky
999246145Shselasky		error = DEVICE_DETACH(dev);
1000246145Shselasky		if (error) {
1001246145Shselasky			return error;
1002246145Shselasky		}
1003246145Shselasky		dev->dev_attached = 0;
1004246145Shselasky	}
1005246145Shselasky	device_set_softc(dev, NULL);
1006246145Shselasky
1007246145Shselasky	if (dev->dev_fixed_class == 0)
1008246145Shselasky		devclass_delete_device(mod, dev);
1009246145Shselasky
1010246145Shselasky	return (0);
1011246145Shselasky}
1012246145Shselasky
1013246145Shselaskyvoid
1014246145Shselaskydevice_set_softc(device_t dev, void *softc)
1015246145Shselasky{
1016246145Shselasky	if (dev->dev_softc_alloc) {
1017246145Shselasky		free(dev->dev_sc, M_DEVBUF);
1018246145Shselasky		dev->dev_sc = NULL;
1019246145Shselasky	}
1020246145Shselasky	dev->dev_sc = softc;
1021246145Shselasky	dev->dev_softc_alloc = 0;
1022246145Shselasky}
1023246145Shselasky
1024246145Shselaskyvoid   *
1025246145Shselaskydevice_get_softc(device_t dev)
1026246145Shselasky{
1027246145Shselasky	if (dev == NULL)
1028246145Shselasky		return (NULL);
1029246145Shselasky
1030246145Shselasky	return (dev->dev_sc);
1031246145Shselasky}
1032246145Shselasky
1033246145Shselaskyint
1034246145Shselaskydevice_is_attached(device_t dev)
1035246145Shselasky{
1036246145Shselasky	return (dev->dev_attached);
1037246145Shselasky}
1038246145Shselasky
1039246145Shselaskyvoid
1040246145Shselaskydevice_set_desc(device_t dev, const char *desc)
1041246145Shselasky{
1042246145Shselasky	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
1043246145Shselasky}
1044246145Shselasky
1045246145Shselaskyvoid
1046246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc)
1047246145Shselasky{
1048246145Shselasky	device_set_desc(dev, desc);
1049246145Shselasky}
1050246145Shselasky
1051246145Shselaskyvoid   *
1052246145Shselaskydevclass_get_softc(devclass_t dc, int unit)
1053246145Shselasky{
1054246145Shselasky	return (device_get_softc(devclass_get_device(dc, unit)));
1055246145Shselasky}
1056246145Shselasky
1057246145Shselaskyint
1058246145Shselaskydevclass_get_maxunit(devclass_t dc)
1059246145Shselasky{
1060246145Shselasky	int max_unit = 0;
1061246145Shselasky
1062246145Shselasky	if (dc) {
1063246145Shselasky		max_unit = DEVCLASS_MAXUNIT;
1064246145Shselasky		while (max_unit--) {
1065246145Shselasky			if (dc->dev_list[max_unit]) {
1066246145Shselasky				break;
1067246145Shselasky			}
1068246145Shselasky		}
1069246145Shselasky		max_unit++;
1070246145Shselasky	}
1071246145Shselasky	return (max_unit);
1072246145Shselasky}
1073246145Shselasky
1074246145Shselaskydevice_t
1075246145Shselaskydevclass_get_device(devclass_t dc, int unit)
1076246145Shselasky{
1077246145Shselasky	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
1078246145Shselasky	    NULL : dc->dev_list[unit]);
1079246145Shselasky}
1080246145Shselasky
1081246145Shselaskydevclass_t
1082246145Shselaskydevclass_find(const char *classname)
1083246145Shselasky{
1084246145Shselasky	const struct module_data *mod;
1085246145Shselasky
1086246145Shselasky	TAILQ_FOREACH(mod, &module_head, entry) {
1087291405Szbb		if (devclass_equal(mod->driver->name, classname))
1088246145Shselasky			return (mod->devclass_pp[0]);
1089246145Shselasky	}
1090246145Shselasky	return (NULL);
1091246145Shselasky}
1092246145Shselasky
1093246145Shselaskyvoid
1094246145Shselaskymodule_register(void *data)
1095246145Shselasky{
1096246145Shselasky	struct module_data *mdata = data;
1097246145Shselasky
1098246145Shselasky	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
1099246145Shselasky}
1100246145Shselasky
1101246145Shselasky/*------------------------------------------------------------------------*
1102246145Shselasky * System startup
1103246145Shselasky *------------------------------------------------------------------------*/
1104246145Shselasky
1105246145Shselaskystatic void
1106246145Shselaskysysinit_run(const void **ppdata)
1107246145Shselasky{
1108246145Shselasky	const struct sysinit *psys;
1109246145Shselasky
1110246145Shselasky	while ((psys = *ppdata) != NULL) {
1111246145Shselasky		(psys->func) (psys->data);
1112246145Shselasky		ppdata++;
1113246145Shselasky	}
1114246145Shselasky}
1115246145Shselasky
1116246145Shselasky/*------------------------------------------------------------------------*
1117246145Shselasky * USB process API
1118246145Shselasky *------------------------------------------------------------------------*/
1119246145Shselasky
1120246145Shselaskystatic int usb_do_process(struct usb_process *);
1121246145Shselaskystatic int usb_proc_level = -1;
1122246145Shselaskystatic struct mtx usb_proc_mtx;
1123246145Shselasky
1124246145Shselaskyvoid
1125246145Shselaskyusb_idle(void)
1126246145Shselasky{
1127246145Shselasky	int old_level = usb_proc_level;
1128246145Shselasky	int old_giant = Giant.owned;
1129246145Shselasky	int worked;
1130246145Shselasky
1131246145Shselasky	device_run_interrupts(usb_pci_root);
1132246145Shselasky
1133246145Shselasky	do {
1134246145Shselasky		worked = 0;
1135246145Shselasky		Giant.owned = 0;
1136246145Shselasky
1137246145Shselasky		while (++usb_proc_level < USB_PROC_MAX)
1138246145Shselasky			worked |= usb_do_process(usb_process + usb_proc_level);
1139246145Shselasky
1140246145Shselasky		usb_proc_level = old_level;
1141246145Shselasky		Giant.owned = old_giant;
1142246145Shselasky
1143246145Shselasky	} while (worked);
1144246145Shselasky}
1145246145Shselasky
1146246145Shselaskyvoid
1147246145Shselaskyusb_init(void)
1148246145Shselasky{
1149246145Shselasky	sysinit_run(sysinit_data);
1150246145Shselasky}
1151246145Shselasky
1152246145Shselaskyvoid
1153246145Shselaskyusb_uninit(void)
1154246145Shselasky{
1155246145Shselasky	sysinit_run(sysuninit_data);
1156246145Shselasky}
1157246145Shselasky
1158246145Shselaskystatic void
1159246145Shselaskyusb_process_init_sub(struct usb_process *up)
1160246145Shselasky{
1161246145Shselasky	TAILQ_INIT(&up->up_qhead);
1162246145Shselasky
1163246145Shselasky	cv_init(&up->up_cv, "-");
1164246145Shselasky	cv_init(&up->up_drain, "usbdrain");
1165246145Shselasky
1166246145Shselasky	up->up_mtx = &usb_proc_mtx;
1167246145Shselasky}
1168246145Shselasky
1169246145Shselaskystatic void
1170246145Shselaskyusb_process_init(void *arg)
1171246145Shselasky{
1172246145Shselasky	uint8_t x;
1173246145Shselasky
1174246145Shselasky	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
1175246145Shselasky
1176246145Shselasky	for (x = 0; x != USB_PROC_MAX; x++)
1177246145Shselasky		usb_process_init_sub(&usb_process[x]);
1178246145Shselasky
1179246145Shselasky}
1180246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
1181246145Shselasky
1182246145Shselaskystatic int
1183246145Shselaskyusb_do_process(struct usb_process *up)
1184246145Shselasky{
1185246145Shselasky	struct usb_proc_msg *pm;
1186246145Shselasky	int worked = 0;
1187246145Shselasky
1188246145Shselasky	mtx_lock(&usb_proc_mtx);
1189246145Shselasky
1190246145Shselaskyrepeat:
1191246145Shselasky	pm = TAILQ_FIRST(&up->up_qhead);
1192246145Shselasky
1193246145Shselasky	if (pm != NULL) {
1194246145Shselasky
1195246145Shselasky		worked = 1;
1196246145Shselasky
1197246145Shselasky		(pm->pm_callback) (pm);
1198246145Shselasky
1199246145Shselasky		if (pm == TAILQ_FIRST(&up->up_qhead)) {
1200246145Shselasky			/* nothing changed */
1201246145Shselasky			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
1202246145Shselasky			pm->pm_qentry.tqe_prev = NULL;
1203246145Shselasky		}
1204246145Shselasky		goto repeat;
1205246145Shselasky	}
1206246145Shselasky	mtx_unlock(&usb_proc_mtx);
1207246145Shselasky
1208246145Shselasky	return (worked);
1209246145Shselasky}
1210246145Shselasky
1211246145Shselaskyvoid   *
1212246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
1213246145Shselasky{
1214246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1215246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1216246145Shselasky	struct usb_proc_msg *pm2;
1217246145Shselasky	usb_size_t d;
1218246145Shselasky	uint8_t t;
1219246145Shselasky
1220246145Shselasky	t = 0;
1221246145Shselasky
1222246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1223246145Shselasky		t |= 1;
1224246145Shselasky	}
1225246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1226246145Shselasky		t |= 2;
1227246145Shselasky	}
1228246145Shselasky	if (t == 0) {
1229246145Shselasky		/*
1230246145Shselasky		 * No entries are queued. Queue "pm0" and use the existing
1231246145Shselasky		 * message number.
1232246145Shselasky		 */
1233246145Shselasky		pm2 = pm0;
1234246145Shselasky	} else if (t == 1) {
1235246145Shselasky		/* Check if we need to increment the message number. */
1236246145Shselasky		if (pm0->pm_num == up->up_msg_num) {
1237246145Shselasky			up->up_msg_num++;
1238246145Shselasky		}
1239246145Shselasky		pm2 = pm1;
1240246145Shselasky	} else if (t == 2) {
1241246145Shselasky		/* Check if we need to increment the message number. */
1242246145Shselasky		if (pm1->pm_num == up->up_msg_num) {
1243246145Shselasky			up->up_msg_num++;
1244246145Shselasky		}
1245246145Shselasky		pm2 = pm0;
1246246145Shselasky	} else if (t == 3) {
1247246145Shselasky		/*
1248246145Shselasky		 * Both entries are queued. Re-queue the entry closest to
1249246145Shselasky		 * the end.
1250246145Shselasky		 */
1251246145Shselasky		d = (pm1->pm_num - pm0->pm_num);
1252246145Shselasky
1253246145Shselasky		/* Check sign after subtraction */
1254246145Shselasky		if (d & 0x80000000) {
1255246145Shselasky			pm2 = pm0;
1256246145Shselasky		} else {
1257246145Shselasky			pm2 = pm1;
1258246145Shselasky		}
1259246145Shselasky
1260246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1261246145Shselasky	} else {
1262246145Shselasky		pm2 = NULL;		/* panic - should not happen */
1263246145Shselasky	}
1264246145Shselasky
1265246145Shselasky	/* Put message last on queue */
1266246145Shselasky
1267246145Shselasky	pm2->pm_num = up->up_msg_num;
1268246145Shselasky	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1269246145Shselasky
1270246145Shselasky	return (pm2);
1271246145Shselasky}
1272246145Shselasky
1273246145Shselasky/*------------------------------------------------------------------------*
1274246145Shselasky *	usb_proc_is_gone
1275246145Shselasky *
1276246145Shselasky * Return values:
1277246145Shselasky *    0: USB process is running
1278246145Shselasky * Else: USB process is tearing down
1279246145Shselasky *------------------------------------------------------------------------*/
1280246145Shselaskyuint8_t
1281246145Shselaskyusb_proc_is_gone(struct usb_process *up)
1282246145Shselasky{
1283246145Shselasky	return (0);
1284246145Shselasky}
1285246145Shselasky
1286246145Shselasky/*------------------------------------------------------------------------*
1287246145Shselasky *	usb_proc_mwait
1288246145Shselasky *
1289246145Shselasky * This function will return when the USB process message pointed to
1290246145Shselasky * by "pm" is no longer on a queue. This function must be called
1291246145Shselasky * having "usb_proc_mtx" locked.
1292246145Shselasky *------------------------------------------------------------------------*/
1293246145Shselaskyvoid
1294246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1295246145Shselasky{
1296246145Shselasky	struct usb_proc_msg *pm0 = _pm0;
1297246145Shselasky	struct usb_proc_msg *pm1 = _pm1;
1298246145Shselasky
1299246145Shselasky	/* Just remove the messages from the queue. */
1300246145Shselasky	if (pm0->pm_qentry.tqe_prev) {
1301246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1302246145Shselasky		pm0->pm_qentry.tqe_prev = NULL;
1303246145Shselasky	}
1304246145Shselasky	if (pm1->pm_qentry.tqe_prev) {
1305246145Shselasky		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1306246145Shselasky		pm1->pm_qentry.tqe_prev = NULL;
1307246145Shselasky	}
1308246145Shselasky}
1309246145Shselasky
1310246145Shselasky/*------------------------------------------------------------------------*
1311246145Shselasky * SYSTEM attach
1312246145Shselasky *------------------------------------------------------------------------*/
1313246145Shselasky
1314266882Shselasky#ifdef USB_PCI_PROBE_LIST
1315246145Shselaskystatic device_method_t pci_methods[] = {
1316246145Shselasky	DEVMETHOD_END
1317246145Shselasky};
1318246145Shselasky
1319246145Shselaskystatic driver_t pci_driver = {
1320246145Shselasky	.name = "pci",
1321246145Shselasky	.methods = pci_methods,
1322246145Shselasky};
1323246145Shselasky
1324246145Shselaskystatic devclass_t pci_devclass;
1325246145Shselasky
1326246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1327246145Shselasky
1328246145Shselaskystatic const char *usb_pci_devices[] = {
1329266882Shselasky	USB_PCI_PROBE_LIST
1330246145Shselasky};
1331246145Shselasky
1332246145Shselasky#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1333246145Shselasky
1334246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX];
1335246145Shselasky
1336246145Shselaskystatic void
1337246145Shselaskyusb_pci_mod_load(void *arg)
1338246145Shselasky{
1339246145Shselasky	uint32_t x;
1340246145Shselasky
1341246145Shselasky	usb_pci_root = device_add_child(NULL, "pci", -1);
1342246145Shselasky	if (usb_pci_root == NULL)
1343246145Shselasky		return;
1344246145Shselasky
1345246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1346246145Shselasky		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1347246145Shselasky		if (usb_pci_dev[x] == NULL)
1348246145Shselasky			continue;
1349246145Shselasky		if (device_probe_and_attach(usb_pci_dev[x])) {
1350246145Shselasky			device_printf(usb_pci_dev[x],
1351246145Shselasky			    "WARNING: Probe and attach failed!\n");
1352246145Shselasky		}
1353246145Shselasky	}
1354246145Shselasky}
1355246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1356246145Shselasky
1357246145Shselaskystatic void
1358246145Shselaskyusb_pci_mod_unload(void *arg)
1359246145Shselasky{
1360246145Shselasky	uint32_t x;
1361246145Shselasky
1362246145Shselasky	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1363246145Shselasky		if (usb_pci_dev[x]) {
1364246145Shselasky			device_detach(usb_pci_dev[x]);
1365246145Shselasky			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1366246145Shselasky		}
1367246145Shselasky	}
1368246145Shselasky	if (usb_pci_root)
1369246145Shselasky		device_delete_child(NULL, usb_pci_root);
1370246145Shselasky}
1371246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1372266882Shselasky#endif
1373246145Shselasky
1374246145Shselasky/*------------------------------------------------------------------------*
1375246145Shselasky * MALLOC API
1376246145Shselasky *------------------------------------------------------------------------*/
1377246145Shselasky
1378266882Shselasky#ifndef HAVE_MALLOC
1379246145Shselasky#define	USB_POOL_ALIGN 8
1380246145Shselasky
1381246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1382246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE;
1383246145Shselaskystatic uint32_t usb_pool_entries;
1384246145Shselasky
1385246145Shselaskystruct malloc_hdr {
1386246145Shselasky	TAILQ_ENTRY(malloc_hdr) entry;
1387246145Shselasky	uint32_t size;
1388246145Shselasky} __aligned(USB_POOL_ALIGN);
1389246145Shselasky
1390246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head =
1391246145Shselasky	TAILQ_HEAD_INITIALIZER(malloc_head);
1392246145Shselasky
1393246145Shselaskyvoid   *
1394246145Shselaskyusb_malloc(unsigned long size)
1395246145Shselasky{
1396246145Shselasky	struct malloc_hdr *hdr;
1397246145Shselasky
1398246145Shselasky	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1399246145Shselasky	size += sizeof(struct malloc_hdr);
1400246145Shselasky
1401246145Shselasky	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1402246145Shselasky		if (hdr->size == size)
1403246145Shselasky			break;
1404246145Shselasky	}
1405246145Shselasky
1406246145Shselasky	if (hdr) {
1407266882Shselasky		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1408246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1409246145Shselasky
1410246145Shselasky		TAILQ_REMOVE(&malloc_head, hdr, entry);
1411246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1412246145Shselasky		return (hdr + 1);
1413246145Shselasky	}
1414246145Shselasky	if (usb_pool_rem >= size) {
1415246145Shselasky		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1416246145Shselasky		hdr->size = size;
1417246145Shselasky
1418246145Shselasky		usb_pool_rem -= size;
1419246145Shselasky		usb_pool_entries++;
1420246145Shselasky
1421266882Shselasky		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1422246145Shselasky		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1423246145Shselasky
1424246145Shselasky		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1425246145Shselasky		return (hdr + 1);
1426246145Shselasky	}
1427246145Shselasky	return (NULL);
1428246145Shselasky}
1429246145Shselasky
1430246145Shselaskyvoid
1431246145Shselaskyusb_free(void *arg)
1432246145Shselasky{
1433246145Shselasky	struct malloc_hdr *hdr;
1434246145Shselasky
1435246145Shselasky	if (arg == NULL)
1436246145Shselasky		return;
1437246145Shselasky
1438246145Shselasky	hdr = arg;
1439246145Shselasky	hdr--;
1440246145Shselasky
1441246145Shselasky	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1442246145Shselasky}
1443266882Shselasky#endif
1444246145Shselasky
1445246145Shselaskychar   *
1446246145Shselaskyusb_strdup(const char *str)
1447246145Shselasky{
1448246145Shselasky	char *tmp;
1449246145Shselasky	int len;
1450246145Shselasky
1451246145Shselasky	len = 1 + strlen(str);
1452246145Shselasky
1453266882Shselasky	tmp = malloc(len,XXX,XXX);
1454246145Shselasky	if (tmp == NULL)
1455246145Shselasky		return (NULL);
1456246145Shselasky
1457246145Shselasky	memcpy(tmp, str, len);
1458246145Shselasky	return (tmp);
1459246145Shselasky}
1460