xref: /freebsd/stand/kshim/bsd_kernel.c (revision 40d7ba08773751ff7d0df1a3f112b32d1d04e5ec)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
3ca987d46SWarner Losh  *
4ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
5ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
6ca987d46SWarner Losh  * are met:
7ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
8ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
9ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
10ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
11ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
12ca987d46SWarner Losh  *
13ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23ca987d46SWarner Losh  * SUCH DAMAGE.
24ca987d46SWarner Losh  */
25ca987d46SWarner Losh 
26ca987d46SWarner Losh #include <bsd_global.h>
27ca987d46SWarner Losh 
28ca987d46SWarner Losh struct usb_process usb_process[USB_PROC_MAX];
29ca987d46SWarner Losh 
30ca987d46SWarner Losh static device_t usb_pci_root;
31ca987d46SWarner Losh 
32ca987d46SWarner Losh int (*bus_alloc_resource_any_cb)(struct resource *res, device_t dev,
33ca987d46SWarner Losh     int type, int *rid, unsigned int flags);
34ca987d46SWarner Losh int (*ofw_bus_status_ok_cb)(device_t dev);
35ca987d46SWarner Losh int (*ofw_bus_is_compatible_cb)(device_t dev, char *name);
36ca987d46SWarner Losh 
3734602358SHans Petter Selasky /*------------------------------------------------------------------------*
3834602358SHans Petter Selasky  * Implementation of busdma API
3934602358SHans Petter Selasky  *------------------------------------------------------------------------*/
40ca987d46SWarner Losh int
bus_dma_tag_create(bus_dma_tag_t parent,bus_size_t alignment,bus_size_t boundary,bus_addr_t lowaddr,bus_addr_t highaddr,bus_dma_filter_t * filter,void * filterarg,bus_size_t maxsize,int nsegments,bus_size_t maxsegsz,int flags,bus_dma_lock_t * lockfunc,void * lockfuncarg,bus_dma_tag_t * dmat)41ca987d46SWarner Losh bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
42ca987d46SWarner Losh 		   bus_size_t boundary, bus_addr_t lowaddr,
43ca987d46SWarner Losh 		   bus_addr_t highaddr, bus_dma_filter_t *filter,
44ca987d46SWarner Losh 		   void *filterarg, bus_size_t maxsize, int nsegments,
45ca987d46SWarner Losh 		   bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
46ca987d46SWarner Losh 		   void *lockfuncarg, bus_dma_tag_t *dmat)
47ca987d46SWarner Losh {
48ca987d46SWarner Losh 	struct bus_dma_tag *ret;
49ca987d46SWarner Losh 
50ca987d46SWarner Losh 	ret = malloc(sizeof(struct bus_dma_tag), XXX, XXX);
51ca987d46SWarner Losh 	if (*dmat == NULL)
52ca987d46SWarner Losh 		return (ENOMEM);
53ca987d46SWarner Losh 	ret->alignment = alignment;
54ca987d46SWarner Losh 	ret->maxsize = maxsize;
55ca987d46SWarner Losh 
56ca987d46SWarner Losh 	*dmat = ret;
57ca987d46SWarner Losh 
58ca987d46SWarner Losh 	return (0);
59ca987d46SWarner Losh }
60ca987d46SWarner Losh 
61ca987d46SWarner Losh int
bus_dmamem_alloc(bus_dma_tag_t dmat,void ** vaddr,int flags,bus_dmamap_t * mapp)62ca987d46SWarner Losh bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
63ca987d46SWarner Losh     bus_dmamap_t *mapp)
64ca987d46SWarner Losh {
65ca987d46SWarner Losh 	void *addr;
66ca987d46SWarner Losh 
67ca987d46SWarner Losh 	addr = malloc(dmat->maxsize + dmat->alignment, XXX, XXX);
68ca987d46SWarner Losh 	if (addr == NULL)
69ca987d46SWarner Losh 		return (ENOMEM);
70ca987d46SWarner Losh 
71ca987d46SWarner Losh 	*mapp = addr;
72ca987d46SWarner Losh 	addr = (void*)(((uintptr_t)addr + dmat->alignment - 1) & ~(dmat->alignment - 1));
73ca987d46SWarner Losh 
74ca987d46SWarner Losh 	*vaddr = addr;
75ca987d46SWarner Losh 	return (0);
76ca987d46SWarner Losh }
77ca987d46SWarner Losh 
78ca987d46SWarner Losh int
bus_dmamap_load(bus_dma_tag_t dmat,bus_dmamap_t map,void * buf,bus_size_t buflen,bus_dmamap_callback_t * callback,void * callback_arg,int flags)79ca987d46SWarner Losh bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
80ca987d46SWarner Losh     bus_size_t buflen, bus_dmamap_callback_t *callback,
81ca987d46SWarner Losh     void *callback_arg, int flags)
82ca987d46SWarner Losh {
83ca987d46SWarner Losh 	bus_dma_segment_t segs[1];
84ca987d46SWarner Losh 
85ca987d46SWarner Losh 	segs[0].ds_addr = (uintptr_t)buf;
86ca987d46SWarner Losh 	segs[0].ds_len = buflen;
87ca987d46SWarner Losh 
88ca987d46SWarner Losh 	(*callback)(callback_arg, segs, 1, 0);
89ca987d46SWarner Losh 
90ca987d46SWarner Losh 	return (0);
91ca987d46SWarner Losh }
92ca987d46SWarner Losh 
93ca987d46SWarner Losh void
bus_dmamap_sync(bus_dma_tag_t dmat,bus_dmamap_t map,int flags)94cc7b5411SHans Petter Selasky bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, int flags)
95cc7b5411SHans Petter Selasky {
96cc7b5411SHans Petter Selasky 	/* Assuming coherent memory */
97cc7b5411SHans Petter Selasky 	__asm__ __volatile__("": : :"memory");
98cc7b5411SHans Petter Selasky }
99cc7b5411SHans Petter Selasky 
100cc7b5411SHans Petter Selasky void
bus_dmamem_free(bus_dma_tag_t dmat,void * vaddr,bus_dmamap_t map)101ca987d46SWarner Losh bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
102ca987d46SWarner Losh {
103ca987d46SWarner Losh 
104ca987d46SWarner Losh 	free(map, XXX);
105ca987d46SWarner Losh }
106ca987d46SWarner Losh 
107ca987d46SWarner Losh int
bus_dma_tag_destroy(bus_dma_tag_t dmat)108ca987d46SWarner Losh bus_dma_tag_destroy(bus_dma_tag_t dmat)
109ca987d46SWarner Losh {
110ca987d46SWarner Losh 
111ca987d46SWarner Losh 	free(dmat, XXX);
112ca987d46SWarner Losh 	return (0);
113ca987d46SWarner Losh }
114ca987d46SWarner Losh 
11534602358SHans Petter Selasky /*------------------------------------------------------------------------*
11634602358SHans Petter Selasky  * Implementation of resource management API
11734602358SHans Petter Selasky  *------------------------------------------------------------------------*/
11834602358SHans Petter Selasky 
119ca987d46SWarner Losh struct resource *
bus_alloc_resource_any(device_t dev,int type,int * rid,unsigned int flags)120ca987d46SWarner Losh bus_alloc_resource_any(device_t dev, int type, int *rid, unsigned int flags)
121ca987d46SWarner Losh {
122ca987d46SWarner Losh 	struct resource *res;
123ca987d46SWarner Losh 	int ret = EINVAL;
124ca987d46SWarner Losh 
125ca987d46SWarner Losh 	res = malloc(sizeof(*res), XXX, XXX);
126ca987d46SWarner Losh 	if (res == NULL)
127ca987d46SWarner Losh 		return (NULL);
128ca987d46SWarner Losh 
129ca987d46SWarner Losh 	res->__r_i = malloc(sizeof(struct resource_i), XXX, XXX);
130ca987d46SWarner Losh 	if (res->__r_i == NULL) {
131ca987d46SWarner Losh 		free(res, XXX);
132ca987d46SWarner Losh 		return (NULL);
133ca987d46SWarner Losh 	}
134ca987d46SWarner Losh 
135ca987d46SWarner Losh 	if (bus_alloc_resource_any_cb != NULL)
136ca987d46SWarner Losh 		ret = (*bus_alloc_resource_any_cb)(res, dev, type, rid, flags);
137ca987d46SWarner Losh 	if (ret == 0)
138ca987d46SWarner Losh 		return (res);
139ca987d46SWarner Losh 
140ca987d46SWarner Losh 	free(res->__r_i, XXX);
141ca987d46SWarner Losh 	free(res, XXX);
142ca987d46SWarner Losh 	return (NULL);
143ca987d46SWarner Losh }
144ca987d46SWarner Losh 
145ca987d46SWarner Losh int
bus_alloc_resources(device_t dev,struct resource_spec * rs,struct resource ** res)146ca987d46SWarner Losh bus_alloc_resources(device_t dev, struct resource_spec *rs,
147ca987d46SWarner Losh     struct resource **res)
148ca987d46SWarner Losh {
149ca987d46SWarner Losh 	int i;
150ca987d46SWarner Losh 
151ca987d46SWarner Losh 	for (i = 0; rs[i].type != -1; i++)
152ca987d46SWarner Losh 		res[i] = NULL;
153ca987d46SWarner Losh 	for (i = 0; rs[i].type != -1; i++) {
154ca987d46SWarner Losh 		res[i] = bus_alloc_resource_any(dev,
155ca987d46SWarner Losh 		    rs[i].type, &rs[i].rid, rs[i].flags);
156ca987d46SWarner Losh 		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
157ca987d46SWarner Losh 			bus_release_resources(dev, rs, res);
158ca987d46SWarner Losh 			return (ENXIO);
159ca987d46SWarner Losh 		}
160ca987d46SWarner Losh 	}
161ca987d46SWarner Losh 	return (0);
162ca987d46SWarner Losh }
163ca987d46SWarner Losh 
164ca987d46SWarner Losh void
bus_release_resources(device_t dev,const struct resource_spec * rs,struct resource ** res)165ca987d46SWarner Losh bus_release_resources(device_t dev, const struct resource_spec *rs,
166ca987d46SWarner Losh     struct resource **res)
167ca987d46SWarner Losh {
168ca987d46SWarner Losh 	int i;
169ca987d46SWarner Losh 
170ca987d46SWarner Losh 	for (i = 0; rs[i].type != -1; i++)
171ca987d46SWarner Losh 		if (res[i] != NULL) {
172ca987d46SWarner Losh 			bus_release_resource(
173ca987d46SWarner Losh 			    dev, rs[i].type, rs[i].rid, res[i]);
174ca987d46SWarner Losh 			res[i] = NULL;
175ca987d46SWarner Losh 		}
176ca987d46SWarner Losh }
177ca987d46SWarner Losh 
178ca987d46SWarner Losh int
bus_setup_intr(device_t dev,struct resource * r,int flags,driver_filter_t filter,driver_intr_t handler,void * arg,void ** cookiep)179ca987d46SWarner Losh bus_setup_intr(device_t dev, struct resource *r, int flags,
180ca987d46SWarner Losh     driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep)
181ca987d46SWarner Losh {
182ca987d46SWarner Losh 
183ca987d46SWarner Losh 	dev->dev_irq_filter = filter;
184ca987d46SWarner Losh 	dev->dev_irq_fn = handler;
185ca987d46SWarner Losh 	dev->dev_irq_arg = arg;
186ca987d46SWarner Losh 
187ca987d46SWarner Losh 	return (0);
188ca987d46SWarner Losh }
189ca987d46SWarner Losh 
190ca987d46SWarner Losh int
bus_teardown_intr(device_t dev,struct resource * r,void * cookie)191ca987d46SWarner Losh bus_teardown_intr(device_t dev, struct resource *r, void *cookie)
192ca987d46SWarner Losh {
193ca987d46SWarner Losh 
194ca987d46SWarner Losh 	dev->dev_irq_filter = NULL;
195ca987d46SWarner Losh 	dev->dev_irq_fn = NULL;
196ca987d46SWarner Losh 	dev->dev_irq_arg = NULL;
197ca987d46SWarner Losh 
198ca987d46SWarner Losh 	return (0);
199ca987d46SWarner Losh }
200ca987d46SWarner Losh 
201ca987d46SWarner Losh int
bus_release_resource(device_t dev,int type,int rid,struct resource * r)202ca987d46SWarner Losh bus_release_resource(device_t dev, int type, int rid, struct resource *r)
203ca987d46SWarner Losh {
204ca987d46SWarner Losh 	/* Resource releasing is not supported */
205ca987d46SWarner Losh 	return (EINVAL);
206ca987d46SWarner Losh }
207ca987d46SWarner Losh 
2084378bd38SJohn Baldwin void
bus_attach_children(device_t dev)2094378bd38SJohn Baldwin bus_attach_children(device_t dev)
210ca987d46SWarner Losh {
211ca987d46SWarner Losh 	device_t child;
212ca987d46SWarner Losh 
213ca987d46SWarner Losh 	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
214ca987d46SWarner Losh 		device_probe_and_attach(child);
215ca987d46SWarner Losh 	}
216ca987d46SWarner Losh }
217ca987d46SWarner Losh 
218ca987d46SWarner Losh bus_space_tag_t
rman_get_bustag(struct resource * r)219ca987d46SWarner Losh rman_get_bustag(struct resource *r)
220ca987d46SWarner Losh {
221ca987d46SWarner Losh 
222ca987d46SWarner Losh 	return (r->r_bustag);
223ca987d46SWarner Losh }
224ca987d46SWarner Losh 
225ca987d46SWarner Losh bus_space_handle_t
rman_get_bushandle(struct resource * r)226ca987d46SWarner Losh rman_get_bushandle(struct resource *r)
227ca987d46SWarner Losh {
228ca987d46SWarner Losh 
229ca987d46SWarner Losh 	return (r->r_bushandle);
230ca987d46SWarner Losh }
231ca987d46SWarner Losh 
232ca987d46SWarner Losh u_long
rman_get_size(struct resource * r)233ca987d46SWarner Losh rman_get_size(struct resource *r)
234ca987d46SWarner Losh {
235ca987d46SWarner Losh 
236ca987d46SWarner Losh 	return (r->__r_i->r_end - r->__r_i->r_start + 1);
237ca987d46SWarner Losh }
238ca987d46SWarner Losh 
239ca987d46SWarner Losh int
ofw_bus_status_okay(device_t dev)240ca987d46SWarner Losh ofw_bus_status_okay(device_t dev)
241ca987d46SWarner Losh {
242ca987d46SWarner Losh 	if (ofw_bus_status_ok_cb == NULL)
243ca987d46SWarner Losh 		return (0);
244ca987d46SWarner Losh 
245ca987d46SWarner Losh 	return ((*ofw_bus_status_ok_cb)(dev));
246ca987d46SWarner Losh }
247ca987d46SWarner Losh 
248ca987d46SWarner Losh int
ofw_bus_is_compatible(device_t dev,char * name)249ca987d46SWarner Losh ofw_bus_is_compatible(device_t dev, char *name)
250ca987d46SWarner Losh {
251ca987d46SWarner Losh 	if (ofw_bus_is_compatible_cb == NULL)
252ca987d46SWarner Losh 		return (0);
253ca987d46SWarner Losh 
254ca987d46SWarner Losh 	return ((*ofw_bus_is_compatible_cb)(dev, name));
255ca987d46SWarner Losh }
256ca987d46SWarner Losh 
25734602358SHans Petter Selasky /*------------------------------------------------------------------------*
25834602358SHans Petter Selasky  * Implementation of mutex API
25934602358SHans Petter Selasky  *------------------------------------------------------------------------*/
26034602358SHans Petter Selasky 
26134602358SHans Petter Selasky struct mtx Giant;
26234602358SHans Petter Selasky 
26334602358SHans Petter Selasky static void
mtx_system_init(void * arg)26434602358SHans Petter Selasky mtx_system_init(void *arg)
26534602358SHans Petter Selasky {
26634602358SHans Petter Selasky 	mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE);
26734602358SHans Petter Selasky }
26834602358SHans Petter Selasky SYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL);
26934602358SHans Petter Selasky 
270ca987d46SWarner Losh void
mtx_init(struct mtx * mtx,const char * name,const char * type,int opt)271ca987d46SWarner Losh mtx_init(struct mtx *mtx, const char *name, const char *type, int opt)
272ca987d46SWarner Losh {
273ca987d46SWarner Losh 	mtx->owned = 0;
274ca987d46SWarner Losh 	mtx->parent = mtx;
275ca987d46SWarner Losh }
276ca987d46SWarner Losh 
277ca987d46SWarner Losh void
mtx_lock(struct mtx * mtx)278ca987d46SWarner Losh mtx_lock(struct mtx *mtx)
279ca987d46SWarner Losh {
280ca987d46SWarner Losh 	mtx = mtx->parent;
281ca987d46SWarner Losh 	mtx->owned++;
282ca987d46SWarner Losh }
283ca987d46SWarner Losh 
284ca987d46SWarner Losh void
mtx_unlock(struct mtx * mtx)285ca987d46SWarner Losh mtx_unlock(struct mtx *mtx)
286ca987d46SWarner Losh {
287ca987d46SWarner Losh 	mtx = mtx->parent;
288ca987d46SWarner Losh 	mtx->owned--;
289ca987d46SWarner Losh }
290ca987d46SWarner Losh 
291ca987d46SWarner Losh int
mtx_owned(struct mtx * mtx)292ca987d46SWarner Losh mtx_owned(struct mtx *mtx)
293ca987d46SWarner Losh {
294ca987d46SWarner Losh 	mtx = mtx->parent;
295ca987d46SWarner Losh 	return (mtx->owned != 0);
296ca987d46SWarner Losh }
297ca987d46SWarner Losh 
298ca987d46SWarner Losh void
mtx_destroy(struct mtx * mtx)299ca987d46SWarner Losh mtx_destroy(struct mtx *mtx)
300ca987d46SWarner Losh {
301ca987d46SWarner Losh 	/* NOP */
302ca987d46SWarner Losh }
303ca987d46SWarner Losh 
304ca987d46SWarner Losh /*------------------------------------------------------------------------*
305ca987d46SWarner Losh  * Implementation of shared/exclusive mutex API
306ca987d46SWarner Losh  *------------------------------------------------------------------------*/
307ca987d46SWarner Losh 
308ca987d46SWarner Losh void
sx_init_flags(struct sx * sx,const char * name,int flags)309ca987d46SWarner Losh sx_init_flags(struct sx *sx, const char *name, int flags)
310ca987d46SWarner Losh {
311ca987d46SWarner Losh 	sx->owned = 0;
312ca987d46SWarner Losh }
313ca987d46SWarner Losh 
314ca987d46SWarner Losh void
sx_destroy(struct sx * sx)315ca987d46SWarner Losh sx_destroy(struct sx *sx)
316ca987d46SWarner Losh {
317ca987d46SWarner Losh 	/* NOP */
318ca987d46SWarner Losh }
319ca987d46SWarner Losh 
320ca987d46SWarner Losh void
sx_xlock(struct sx * sx)321ca987d46SWarner Losh sx_xlock(struct sx *sx)
322ca987d46SWarner Losh {
323ca987d46SWarner Losh 	sx->owned++;
324ca987d46SWarner Losh }
325ca987d46SWarner Losh 
326ca987d46SWarner Losh void
sx_xunlock(struct sx * sx)327ca987d46SWarner Losh sx_xunlock(struct sx *sx)
328ca987d46SWarner Losh {
329ca987d46SWarner Losh 	sx->owned--;
330ca987d46SWarner Losh }
331ca987d46SWarner Losh 
332ca987d46SWarner Losh int
sx_xlocked(struct sx * sx)333ca987d46SWarner Losh sx_xlocked(struct sx *sx)
334ca987d46SWarner Losh {
335ca987d46SWarner Losh 	return (sx->owned != 0);
336ca987d46SWarner Losh }
337ca987d46SWarner Losh 
338ca987d46SWarner Losh /*------------------------------------------------------------------------*
339ca987d46SWarner Losh  * Implementaiton of condition variable API
340ca987d46SWarner Losh  *------------------------------------------------------------------------*/
341ca987d46SWarner Losh 
342ca987d46SWarner Losh void
cv_init(struct cv * cv,const char * desc)343ca987d46SWarner Losh cv_init(struct cv *cv, const char *desc)
344ca987d46SWarner Losh {
345ca987d46SWarner Losh 	cv->sleeping = 0;
346ca987d46SWarner Losh }
347ca987d46SWarner Losh 
348ca987d46SWarner Losh void
cv_destroy(struct cv * cv)349ca987d46SWarner Losh cv_destroy(struct cv *cv)
350ca987d46SWarner Losh {
351ca987d46SWarner Losh 	/* NOP */
352ca987d46SWarner Losh }
353ca987d46SWarner Losh 
354ca987d46SWarner Losh void
cv_wait(struct cv * cv,struct mtx * mtx)355ca987d46SWarner Losh cv_wait(struct cv *cv, struct mtx *mtx)
356ca987d46SWarner Losh {
357ca987d46SWarner Losh 	cv_timedwait(cv, mtx, -1);
358ca987d46SWarner Losh }
359ca987d46SWarner Losh 
360ca987d46SWarner Losh int
cv_timedwait(struct cv * cv,struct mtx * mtx,int timo)361ca987d46SWarner Losh cv_timedwait(struct cv *cv, struct mtx *mtx, int timo)
362ca987d46SWarner Losh {
363ca987d46SWarner Losh 	int start = ticks;
364ca987d46SWarner Losh 	int delta;
365ca987d46SWarner Losh 	int time = 0;
366ca987d46SWarner Losh 
367ca987d46SWarner Losh 	if (cv->sleeping)
368ca987d46SWarner Losh 		return (EWOULDBLOCK);	/* not allowed */
369ca987d46SWarner Losh 
370ca987d46SWarner Losh 	cv->sleeping = 1;
371ca987d46SWarner Losh 
372ca987d46SWarner Losh 	while (cv->sleeping) {
373ca987d46SWarner Losh 		if (timo >= 0) {
374ca987d46SWarner Losh 			delta = ticks - start;
375ca987d46SWarner Losh 			if (delta >= timo || delta < 0)
376ca987d46SWarner Losh 				break;
377ca987d46SWarner Losh 		}
378ca987d46SWarner Losh 		mtx_unlock(mtx);
379ca987d46SWarner Losh 
380ca987d46SWarner Losh 		usb_idle();
381ca987d46SWarner Losh 
382ca987d46SWarner Losh 		if (++time >= (1000000 / hz)) {
383ca987d46SWarner Losh 			time = 0;
384ca987d46SWarner Losh 			callout_process(1);
385ca987d46SWarner Losh 		}
386ca987d46SWarner Losh 
387ca987d46SWarner Losh 		/* Sleep for 1 us */
388ca987d46SWarner Losh 		delay(1);
389ca987d46SWarner Losh 
390ca987d46SWarner Losh 		mtx_lock(mtx);
391ca987d46SWarner Losh 	}
392ca987d46SWarner Losh 
393ca987d46SWarner Losh 	if (cv->sleeping) {
394ca987d46SWarner Losh 		cv->sleeping = 0;
395ca987d46SWarner Losh 		return (EWOULDBLOCK);	/* not allowed */
396ca987d46SWarner Losh 	}
397ca987d46SWarner Losh 	return (0);
398ca987d46SWarner Losh }
399ca987d46SWarner Losh 
400ca987d46SWarner Losh void
cv_signal(struct cv * cv)401ca987d46SWarner Losh cv_signal(struct cv *cv)
402ca987d46SWarner Losh {
403ca987d46SWarner Losh 	cv->sleeping = 0;
404ca987d46SWarner Losh }
405ca987d46SWarner Losh 
406ca987d46SWarner Losh void
cv_broadcast(struct cv * cv)407ca987d46SWarner Losh cv_broadcast(struct cv *cv)
408ca987d46SWarner Losh {
409ca987d46SWarner Losh 	cv->sleeping = 0;
410ca987d46SWarner Losh }
411ca987d46SWarner Losh 
412ca987d46SWarner Losh /*------------------------------------------------------------------------*
413ca987d46SWarner Losh  * Implementation of callout API
414ca987d46SWarner Losh  *------------------------------------------------------------------------*/
415ca987d46SWarner Losh 
416ca987d46SWarner Losh static void callout_proc_msg(struct usb_proc_msg *);
417ca987d46SWarner Losh 
418ca987d46SWarner Losh volatile int ticks = 0;
419ca987d46SWarner Losh 
420ca987d46SWarner Losh static LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
421ca987d46SWarner Losh 
422ca987d46SWarner Losh static struct mtx mtx_callout;
423ca987d46SWarner Losh static struct usb_proc_msg callout_msg[2];
424ca987d46SWarner Losh 
425ca987d46SWarner Losh static void
callout_system_init(void * arg)426ca987d46SWarner Losh callout_system_init(void *arg)
427ca987d46SWarner Losh {
428ca987d46SWarner Losh 	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
429ca987d46SWarner Losh 
430ca987d46SWarner Losh 	callout_msg[0].pm_callback = &callout_proc_msg;
431ca987d46SWarner Losh 	callout_msg[1].pm_callback = &callout_proc_msg;
432ca987d46SWarner Losh }
433ca987d46SWarner Losh SYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
434ca987d46SWarner Losh 
435ca987d46SWarner Losh static void
callout_callback(struct callout * c)436ca987d46SWarner Losh callout_callback(struct callout *c)
437ca987d46SWarner Losh {
438ca987d46SWarner Losh 	mtx_lock(c->mtx);
439ca987d46SWarner Losh 
440ca987d46SWarner Losh 	mtx_lock(&mtx_callout);
441ca987d46SWarner Losh 	if (c->entry.le_prev != NULL) {
442ca987d46SWarner Losh 		LIST_REMOVE(c, entry);
443ca987d46SWarner Losh 		c->entry.le_prev = NULL;
444ca987d46SWarner Losh 	}
445ca987d46SWarner Losh 	mtx_unlock(&mtx_callout);
446ca987d46SWarner Losh 
447ca987d46SWarner Losh 	if (c->c_func != NULL)
448ca987d46SWarner Losh 		(c->c_func) (c->c_arg);
449ca987d46SWarner Losh 
450ca987d46SWarner Losh 	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
451ca987d46SWarner Losh 		mtx_unlock(c->mtx);
452ca987d46SWarner Losh }
453ca987d46SWarner Losh 
454ca987d46SWarner Losh void
callout_process(int timeout)455ca987d46SWarner Losh callout_process(int timeout)
456ca987d46SWarner Losh {
457ca987d46SWarner Losh 	ticks += timeout;
458ca987d46SWarner Losh 	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
459ca987d46SWarner Losh }
460ca987d46SWarner Losh 
461ca987d46SWarner Losh static void
callout_proc_msg(struct usb_proc_msg * pmsg)462ca987d46SWarner Losh callout_proc_msg(struct usb_proc_msg *pmsg)
463ca987d46SWarner Losh {
464ca987d46SWarner Losh 	struct callout *c;
465ca987d46SWarner Losh 	int delta;
466ca987d46SWarner Losh 
467ca987d46SWarner Losh repeat:
468ca987d46SWarner Losh 	mtx_lock(&mtx_callout);
469ca987d46SWarner Losh 
470ca987d46SWarner Losh 	LIST_FOREACH(c, &head_callout, entry) {
471ca987d46SWarner Losh 
472ca987d46SWarner Losh 		delta = c->timeout - ticks;
473ca987d46SWarner Losh 		if (delta < 0) {
474ca987d46SWarner Losh 			mtx_unlock(&mtx_callout);
475ca987d46SWarner Losh 
476ca987d46SWarner Losh 			callout_callback(c);
477ca987d46SWarner Losh 
478ca987d46SWarner Losh 			goto repeat;
479ca987d46SWarner Losh 		}
480ca987d46SWarner Losh 	}
481ca987d46SWarner Losh 	mtx_unlock(&mtx_callout);
482ca987d46SWarner Losh }
483ca987d46SWarner Losh 
484ca987d46SWarner Losh void
callout_init_mtx(struct callout * c,struct mtx * mtx,int flags)485ca987d46SWarner Losh callout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
486ca987d46SWarner Losh {
487ca987d46SWarner Losh 	memset(c, 0, sizeof(*c));
488ca987d46SWarner Losh 
489ca987d46SWarner Losh 	if (mtx == NULL)
490ca987d46SWarner Losh 		mtx = &Giant;
491ca987d46SWarner Losh 
492ca987d46SWarner Losh 	c->mtx = mtx;
493ca987d46SWarner Losh 	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
494ca987d46SWarner Losh }
495ca987d46SWarner Losh 
496ca987d46SWarner Losh void
callout_reset(struct callout * c,int to_ticks,void (* func)(void *),void * arg)497ca987d46SWarner Losh callout_reset(struct callout *c, int to_ticks,
498ca987d46SWarner Losh     void (*func) (void *), void *arg)
499ca987d46SWarner Losh {
500ca987d46SWarner Losh 	callout_stop(c);
501ca987d46SWarner Losh 
502ca987d46SWarner Losh 	c->c_func = func;
503ca987d46SWarner Losh 	c->c_arg = arg;
504ca987d46SWarner Losh 	c->timeout = ticks + to_ticks;
505ca987d46SWarner Losh 
506ca987d46SWarner Losh 	mtx_lock(&mtx_callout);
507ca987d46SWarner Losh 	LIST_INSERT_HEAD(&head_callout, c, entry);
508ca987d46SWarner Losh 	mtx_unlock(&mtx_callout);
509ca987d46SWarner Losh }
510ca987d46SWarner Losh 
511ca987d46SWarner Losh void
callout_stop(struct callout * c)512ca987d46SWarner Losh callout_stop(struct callout *c)
513ca987d46SWarner Losh {
514ca987d46SWarner Losh 	mtx_lock(&mtx_callout);
515ca987d46SWarner Losh 
516ca987d46SWarner Losh 	if (c->entry.le_prev != NULL) {
517ca987d46SWarner Losh 		LIST_REMOVE(c, entry);
518ca987d46SWarner Losh 		c->entry.le_prev = NULL;
519ca987d46SWarner Losh 	}
520ca987d46SWarner Losh 	mtx_unlock(&mtx_callout);
521ca987d46SWarner Losh 
522ca987d46SWarner Losh 	c->c_func = NULL;
523ca987d46SWarner Losh 	c->c_arg = NULL;
524ca987d46SWarner Losh }
525ca987d46SWarner Losh 
526ca987d46SWarner Losh void
callout_drain(struct callout * c)527ca987d46SWarner Losh callout_drain(struct callout *c)
528ca987d46SWarner Losh {
529ca987d46SWarner Losh 	if (c->mtx == NULL)
530ca987d46SWarner Losh 		return;			/* not initialised */
531ca987d46SWarner Losh 
532ca987d46SWarner Losh 	mtx_lock(c->mtx);
533ca987d46SWarner Losh 	callout_stop(c);
534ca987d46SWarner Losh 	mtx_unlock(c->mtx);
535ca987d46SWarner Losh }
536ca987d46SWarner Losh 
537ca987d46SWarner Losh int
callout_pending(struct callout * c)538ca987d46SWarner Losh callout_pending(struct callout *c)
539ca987d46SWarner Losh {
540ca987d46SWarner Losh 	int retval;
541ca987d46SWarner Losh 
542ca987d46SWarner Losh 	mtx_lock(&mtx_callout);
543ca987d46SWarner Losh 	retval = (c->entry.le_prev != NULL);
544ca987d46SWarner Losh 	mtx_unlock(&mtx_callout);
545ca987d46SWarner Losh 
546ca987d46SWarner Losh 	return (retval);
547ca987d46SWarner Losh }
548ca987d46SWarner Losh 
549ca987d46SWarner Losh /*------------------------------------------------------------------------*
550ca987d46SWarner Losh  * Implementation of device API
551ca987d46SWarner Losh  *------------------------------------------------------------------------*/
552ca987d46SWarner Losh 
553ca987d46SWarner Losh static const char unknown_string[] = { "unknown" };
554ca987d46SWarner Losh 
555ca987d46SWarner Losh static TAILQ_HEAD(, module_data) module_head =
556ca987d46SWarner Losh     TAILQ_HEAD_INITIALIZER(module_head);
557ee15875cSJohn Baldwin static TAILQ_HEAD(, devclass) devclasses =
558ee15875cSJohn Baldwin     TAILQ_HEAD_INITIALIZER(devclasses);
559ca987d46SWarner Losh 
560ca987d46SWarner Losh int
bus_generic_resume(device_t dev)561ca987d46SWarner Losh bus_generic_resume(device_t dev)
562ca987d46SWarner Losh {
563ca987d46SWarner Losh 	return (0);
564ca987d46SWarner Losh }
565ca987d46SWarner Losh 
566ca987d46SWarner Losh int
bus_generic_shutdown(device_t dev)567ca987d46SWarner Losh bus_generic_shutdown(device_t dev)
568ca987d46SWarner Losh {
569ca987d46SWarner Losh 	return (0);
570ca987d46SWarner Losh }
571ca987d46SWarner Losh 
572ca987d46SWarner Losh int
bus_generic_suspend(device_t dev)573ca987d46SWarner Losh bus_generic_suspend(device_t dev)
574ca987d46SWarner Losh {
575ca987d46SWarner Losh 	return (0);
576ca987d46SWarner Losh }
577ca987d46SWarner Losh 
578ca987d46SWarner Losh int
bus_generic_print_child(device_t dev,device_t child)579ca987d46SWarner Losh bus_generic_print_child(device_t dev, device_t child)
580ca987d46SWarner Losh {
581ca987d46SWarner Losh 	return (0);
582ca987d46SWarner Losh }
583ca987d46SWarner Losh 
584ca987d46SWarner Losh void
bus_generic_driver_added(device_t dev,driver_t * driver)585ca987d46SWarner Losh bus_generic_driver_added(device_t dev, driver_t *driver)
586ca987d46SWarner Losh {
587ca987d46SWarner Losh 	return;
588ca987d46SWarner Losh }
589ca987d46SWarner Losh 
590ca987d46SWarner Losh device_t
device_get_parent(device_t dev)591ca987d46SWarner Losh device_get_parent(device_t dev)
592ca987d46SWarner Losh {
593ca987d46SWarner Losh 	return (dev ? dev->dev_parent : NULL);
594ca987d46SWarner Losh }
595ca987d46SWarner Losh 
596ca987d46SWarner Losh void
device_set_interrupt(device_t dev,driver_filter_t * filter,driver_intr_t * fn,void * arg)597ca987d46SWarner Losh device_set_interrupt(device_t dev, driver_filter_t *filter,
598ca987d46SWarner Losh     driver_intr_t *fn, void *arg)
599ca987d46SWarner Losh {
600ca987d46SWarner Losh 	dev->dev_irq_filter = filter;
601ca987d46SWarner Losh 	dev->dev_irq_fn = fn;
602ca987d46SWarner Losh 	dev->dev_irq_arg = arg;
603ca987d46SWarner Losh }
604ca987d46SWarner Losh 
605ca987d46SWarner Losh void
device_run_interrupts(device_t parent)606ca987d46SWarner Losh device_run_interrupts(device_t parent)
607ca987d46SWarner Losh {
608ca987d46SWarner Losh 	device_t child;
609ca987d46SWarner Losh 
610ca987d46SWarner Losh 	if (parent == NULL)
611ca987d46SWarner Losh 		return;
612ca987d46SWarner Losh 
613ca987d46SWarner Losh 	TAILQ_FOREACH(child, &parent->dev_children, dev_link) {
614ca987d46SWarner Losh 		int status;
615ca987d46SWarner Losh 		if (child->dev_irq_filter != NULL)
616ca987d46SWarner Losh 			status = child->dev_irq_filter(child->dev_irq_arg);
617ca987d46SWarner Losh 		else
618ca987d46SWarner Losh 			status = FILTER_SCHEDULE_THREAD;
619ca987d46SWarner Losh 
620ca987d46SWarner Losh 		if (status == FILTER_SCHEDULE_THREAD) {
621ca987d46SWarner Losh 			if (child->dev_irq_fn != NULL)
622ca987d46SWarner Losh 				(child->dev_irq_fn) (child->dev_irq_arg);
623ca987d46SWarner Losh 		}
624ca987d46SWarner Losh 	}
625ca987d46SWarner Losh }
626ca987d46SWarner Losh 
627ca987d46SWarner Losh void
device_set_ivars(device_t dev,void * ivars)628ca987d46SWarner Losh device_set_ivars(device_t dev, void *ivars)
629ca987d46SWarner Losh {
630ca987d46SWarner Losh 	dev->dev_aux = ivars;
631ca987d46SWarner Losh }
632ca987d46SWarner Losh 
633ca987d46SWarner Losh void   *
device_get_ivars(device_t dev)634ca987d46SWarner Losh device_get_ivars(device_t dev)
635ca987d46SWarner Losh {
636ca987d46SWarner Losh 	return (dev ? dev->dev_aux : NULL);
637ca987d46SWarner Losh }
638ca987d46SWarner Losh 
639ca987d46SWarner Losh int
device_get_unit(device_t dev)640ca987d46SWarner Losh device_get_unit(device_t dev)
641ca987d46SWarner Losh {
642ca987d46SWarner Losh 	return (dev ? dev->dev_unit : 0);
643ca987d46SWarner Losh }
644ca987d46SWarner Losh 
645ca987d46SWarner Losh int
bus_detach_children(device_t dev)6468e4535eeSJohn Baldwin bus_detach_children(device_t dev)
647ca987d46SWarner Losh {
648ca987d46SWarner Losh 	device_t child;
649ca987d46SWarner Losh 	int error;
650ca987d46SWarner Losh 
651ca987d46SWarner Losh 	if (!dev->dev_attached)
652ca987d46SWarner Losh 		return (EBUSY);
653ca987d46SWarner Losh 
654ca987d46SWarner Losh 	TAILQ_FOREACH(child, &dev->dev_children, dev_link) {
655ca987d46SWarner Losh 		if ((error = device_detach(child)) != 0)
656ca987d46SWarner Losh 			return (error);
657ca987d46SWarner Losh 	}
658ca987d46SWarner Losh 	return (0);
659ca987d46SWarner Losh }
660ca987d46SWarner Losh 
6618e4535eeSJohn Baldwin int
bus_generic_detach(device_t dev)6628e4535eeSJohn Baldwin bus_generic_detach(device_t dev)
6638e4535eeSJohn Baldwin {
6648e4535eeSJohn Baldwin 	int error;
6658e4535eeSJohn Baldwin 
6668e4535eeSJohn Baldwin 	error = bus_detach_children(dev);
6678e4535eeSJohn Baldwin 	if (error == 0)
6688e4535eeSJohn Baldwin 		error = device_delete_children(dev);
6698e4535eeSJohn Baldwin 	return (error);
6708e4535eeSJohn Baldwin }
6718e4535eeSJohn Baldwin 
672ca987d46SWarner Losh const char *
device_get_nameunit(device_t dev)673ca987d46SWarner Losh device_get_nameunit(device_t dev)
674ca987d46SWarner Losh {
675ca987d46SWarner Losh 	if (dev && dev->dev_nameunit[0])
676ca987d46SWarner Losh 		return (dev->dev_nameunit);
677ca987d46SWarner Losh 
678ca987d46SWarner Losh 	return (unknown_string);
679ca987d46SWarner Losh }
680ca987d46SWarner Losh 
681ee15875cSJohn Baldwin static devclass_t
devclass_create(const char * classname)682ee15875cSJohn Baldwin devclass_create(const char *classname)
683ca987d46SWarner Losh {
684ee15875cSJohn Baldwin 	devclass_t dc;
685ca987d46SWarner Losh 
686ee15875cSJohn Baldwin 	dc = malloc(sizeof(*dc), M_DEVBUF, M_WAITOK | M_ZERO);
687ee15875cSJohn Baldwin 	if (dc == NULL) {
688ca987d46SWarner Losh 		return (NULL);
689ca987d46SWarner Losh 	}
690ee15875cSJohn Baldwin 	dc->name = classname;
691ee15875cSJohn Baldwin 	TAILQ_INSERT_TAIL(&devclasses, dc, link);
692ee15875cSJohn Baldwin 	return (dc);
693ee15875cSJohn Baldwin }
694ee15875cSJohn Baldwin 
695ee15875cSJohn Baldwin static devclass_t
devclass_find_create(const char * classname)696ee15875cSJohn Baldwin devclass_find_create(const char *classname)
697ee15875cSJohn Baldwin {
698ee15875cSJohn Baldwin 	devclass_t dc;
699ee15875cSJohn Baldwin 
700ee15875cSJohn Baldwin 	dc = devclass_find(classname);
701ee15875cSJohn Baldwin 	if (dc == NULL)
702ee15875cSJohn Baldwin 		dc = devclass_create(classname);
703ee15875cSJohn Baldwin 	return (dc);
704ee15875cSJohn Baldwin }
705ca987d46SWarner Losh 
706ca987d46SWarner Losh static uint8_t
devclass_add_device(devclass_t dc,device_t dev)707ee15875cSJohn Baldwin devclass_add_device(devclass_t dc, device_t dev)
708ca987d46SWarner Losh {
709ca987d46SWarner Losh 	device_t *pp_dev;
710ca987d46SWarner Losh 	device_t *end;
711ca987d46SWarner Losh 	uint8_t unit;
712ca987d46SWarner Losh 
713ee15875cSJohn Baldwin 	pp_dev = dc->dev_list;
714ca987d46SWarner Losh 	end = pp_dev + DEVCLASS_MAXUNIT;
715ca987d46SWarner Losh 	unit = 0;
716ca987d46SWarner Losh 
717ca987d46SWarner Losh 	while (pp_dev != end) {
718ca987d46SWarner Losh 		if (*pp_dev == NULL) {
719ca987d46SWarner Losh 			*pp_dev = dev;
720ee15875cSJohn Baldwin 			dev->dev_class = dc;
721ca987d46SWarner Losh 			dev->dev_unit = unit;
722ca987d46SWarner Losh 			snprintf(dev->dev_nameunit,
723ca987d46SWarner Losh 			    sizeof(dev->dev_nameunit),
724ee15875cSJohn Baldwin 			    "%s%d", dc->name, unit);
725ca987d46SWarner Losh 			return (0);
726ca987d46SWarner Losh 		}
727ca987d46SWarner Losh 		pp_dev++;
728ca987d46SWarner Losh 		unit++;
729ca987d46SWarner Losh 	}
730ca987d46SWarner Losh 	DPRINTF("Could not add device to devclass.\n");
731ca987d46SWarner Losh 	return (1);
732ca987d46SWarner Losh }
733ca987d46SWarner Losh 
734ca987d46SWarner Losh static void
devclass_delete_device(devclass_t dc,device_t dev)735ee15875cSJohn Baldwin devclass_delete_device(devclass_t dc, device_t dev)
736ca987d46SWarner Losh {
737ee15875cSJohn Baldwin 	if (dc == NULL) {
738ca987d46SWarner Losh 		return;
739ca987d46SWarner Losh 	}
740ee15875cSJohn Baldwin 	dc->dev_list[dev->dev_unit] = NULL;
741ee15875cSJohn Baldwin 	dev->dev_class = NULL;
742ca987d46SWarner Losh }
743ca987d46SWarner Losh 
744ca987d46SWarner Losh static device_t
make_device(device_t parent,const char * name)745ca987d46SWarner Losh make_device(device_t parent, const char *name)
746ca987d46SWarner Losh {
747ca987d46SWarner Losh 	device_t dev = NULL;
748ee15875cSJohn Baldwin 	devclass_t dc = NULL;
749ca987d46SWarner Losh 
750ca987d46SWarner Losh 	if (name) {
751ca987d46SWarner Losh 
752ee15875cSJohn Baldwin 		dc = devclass_find_create(name);
753ca987d46SWarner Losh 
754ee15875cSJohn Baldwin 		if (!dc) {
755ca987d46SWarner Losh 
756ca987d46SWarner Losh 			DPRINTF("%s:%d:%s: can't find device "
757ca987d46SWarner Losh 			    "class %s\n", __FILE__, __LINE__,
758ca987d46SWarner Losh 			    __FUNCTION__, name);
759ca987d46SWarner Losh 
760ca987d46SWarner Losh 			goto done;
761ca987d46SWarner Losh 		}
762ca987d46SWarner Losh 	}
763ca987d46SWarner Losh 	dev = malloc(sizeof(*dev),
764ca987d46SWarner Losh 	    M_DEVBUF, M_WAITOK | M_ZERO);
765ca987d46SWarner Losh 
766ca987d46SWarner Losh 	if (dev == NULL)
767ca987d46SWarner Losh 		goto done;
768ca987d46SWarner Losh 
769ca987d46SWarner Losh 	dev->dev_parent = parent;
770ca987d46SWarner Losh 	TAILQ_INIT(&dev->dev_children);
771ca987d46SWarner Losh 
772ca987d46SWarner Losh 	if (name) {
773ca987d46SWarner Losh 		dev->dev_fixed_class = 1;
774ee15875cSJohn Baldwin 		if (devclass_add_device(dc, dev)) {
775ca987d46SWarner Losh 			goto error;
776ca987d46SWarner Losh 		}
777ca987d46SWarner Losh 	}
778ca987d46SWarner Losh done:
779ca987d46SWarner Losh 	return (dev);
780ca987d46SWarner Losh 
781ca987d46SWarner Losh error:
782ca987d46SWarner Losh 	if (dev) {
783ca987d46SWarner Losh 		free(dev, M_DEVBUF);
784ca987d46SWarner Losh 	}
785ca987d46SWarner Losh 	return (NULL);
786ca987d46SWarner Losh }
787ca987d46SWarner Losh 
788ca987d46SWarner Losh device_t
device_add_child(device_t dev,const char * name,int unit)789ca987d46SWarner Losh device_add_child(device_t dev, const char *name, int unit)
790ca987d46SWarner Losh {
791ca987d46SWarner Losh 	device_t child;
792ca987d46SWarner Losh 
793ca987d46SWarner Losh 	if (unit != -1) {
794ca987d46SWarner Losh 		device_printf(dev, "Unit is not -1\n");
795ca987d46SWarner Losh 	}
796ca987d46SWarner Losh 	child = make_device(dev, name);
797ca987d46SWarner Losh 	if (child == NULL) {
798ca987d46SWarner Losh 		device_printf(dev, "Could not add child '%s'\n", name);
799ca987d46SWarner Losh 		goto done;
800ca987d46SWarner Losh 	}
801ca987d46SWarner Losh 	if (dev == NULL) {
802ca987d46SWarner Losh 		/* no parent */
803ca987d46SWarner Losh 		goto done;
804ca987d46SWarner Losh 	}
805ca987d46SWarner Losh 	TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link);
806ca987d46SWarner Losh done:
807ca987d46SWarner Losh 	return (child);
808ca987d46SWarner Losh }
809ca987d46SWarner Losh 
810ca987d46SWarner Losh int
device_delete_child(device_t dev,device_t child)811ca987d46SWarner Losh device_delete_child(device_t dev, device_t child)
812ca987d46SWarner Losh {
813ca987d46SWarner Losh 	int error = 0;
814ca987d46SWarner Losh 	device_t grandchild;
815ca987d46SWarner Losh 
816ca987d46SWarner Losh 	/* detach parent before deleting children, if any */
817ca987d46SWarner Losh 	error = device_detach(child);
818ca987d46SWarner Losh 	if (error)
819ca987d46SWarner Losh 		goto done;
820ca987d46SWarner Losh 
821ca987d46SWarner Losh 	/* remove children second */
822ca987d46SWarner Losh 	while ((grandchild = TAILQ_FIRST(&child->dev_children))) {
823ca987d46SWarner Losh 		error = device_delete_child(child, grandchild);
824ca987d46SWarner Losh 		if (error) {
825ca987d46SWarner Losh 			device_printf(dev, "Error deleting child!\n");
826ca987d46SWarner Losh 			goto done;
827ca987d46SWarner Losh 		}
828ca987d46SWarner Losh 	}
829ca987d46SWarner Losh 
830ee15875cSJohn Baldwin 	if (child->dev_class != NULL)
831ee15875cSJohn Baldwin 		devclass_delete_device(child->dev_class, child);
832ca987d46SWarner Losh 
833ca987d46SWarner Losh 	if (dev != NULL) {
834ca987d46SWarner Losh 		/* remove child from parent */
835ca987d46SWarner Losh 		TAILQ_REMOVE(&dev->dev_children, child, dev_link);
836ca987d46SWarner Losh 	}
837ca987d46SWarner Losh 	free(child, M_DEVBUF);
838ca987d46SWarner Losh 
839ca987d46SWarner Losh done:
840ca987d46SWarner Losh 	return (error);
841ca987d46SWarner Losh }
842ca987d46SWarner Losh 
843ca987d46SWarner Losh int
device_delete_children(device_t dev)844ca987d46SWarner Losh device_delete_children(device_t dev)
845ca987d46SWarner Losh {
846ca987d46SWarner Losh 	device_t child;
847ca987d46SWarner Losh 	int error = 0;
848ca987d46SWarner Losh 
849ca987d46SWarner Losh 	while ((child = TAILQ_FIRST(&dev->dev_children))) {
850ca987d46SWarner Losh 		error = device_delete_child(dev, child);
851ca987d46SWarner Losh 		if (error) {
852ca987d46SWarner Losh 			device_printf(dev, "Error deleting child!\n");
853ca987d46SWarner Losh 			break;
854ca987d46SWarner Losh 		}
855ca987d46SWarner Losh 	}
856ca987d46SWarner Losh 	return (error);
857ca987d46SWarner Losh }
858ca987d46SWarner Losh 
859ca987d46SWarner Losh void
device_quiet(device_t dev)860ca987d46SWarner Losh device_quiet(device_t dev)
861ca987d46SWarner Losh {
862ca987d46SWarner Losh 	dev->dev_quiet = 1;
863ca987d46SWarner Losh }
864ca987d46SWarner Losh 
865ca987d46SWarner Losh const char *
device_get_desc(device_t dev)866ca987d46SWarner Losh device_get_desc(device_t dev)
867ca987d46SWarner Losh {
868ca987d46SWarner Losh 	if (dev)
869ca987d46SWarner Losh 		return &(dev->dev_desc[0]);
870ca987d46SWarner Losh 	return (unknown_string);
871ca987d46SWarner Losh }
872ca987d46SWarner Losh 
873ca987d46SWarner Losh static int
default_method(void)874ca987d46SWarner Losh default_method(void)
875ca987d46SWarner Losh {
876ca987d46SWarner Losh 	/* do nothing */
877ca987d46SWarner Losh 	DPRINTF("Default method called\n");
878ca987d46SWarner Losh 	return (0);
879ca987d46SWarner Losh }
880ca987d46SWarner Losh 
881ca987d46SWarner Losh void   *
device_get_method(device_t dev,const char * what)882ca987d46SWarner Losh device_get_method(device_t dev, const char *what)
883ca987d46SWarner Losh {
884ca987d46SWarner Losh 	const struct device_method *mtod;
885ca987d46SWarner Losh 
886ca987d46SWarner Losh 	mtod = dev->dev_module->driver->methods;
887ca987d46SWarner Losh 	while (mtod->func != NULL) {
888*40d7ba08SJohn Baldwin 		if (strcmp(mtod->desc, what) == 0) {
889ca987d46SWarner Losh 			return (mtod->func);
890ca987d46SWarner Losh 		}
891ca987d46SWarner Losh 		mtod++;
892ca987d46SWarner Losh 	}
893ca987d46SWarner Losh 	return ((void *)&default_method);
894ca987d46SWarner Losh }
895ca987d46SWarner Losh 
896ca987d46SWarner Losh const char *
device_get_name(device_t dev)897ca987d46SWarner Losh device_get_name(device_t dev)
898ca987d46SWarner Losh {
899ee15875cSJohn Baldwin 	if (dev == NULL || dev->dev_module == NULL)
900ca987d46SWarner Losh 		return (unknown_string);
901ca987d46SWarner Losh 
902ca987d46SWarner Losh 	return (dev->dev_module->driver->name);
903ca987d46SWarner Losh }
904ca987d46SWarner Losh 
905ca987d46SWarner Losh static int
device_allocate_softc(device_t dev)906ca987d46SWarner Losh device_allocate_softc(device_t dev)
907ca987d46SWarner Losh {
908ca987d46SWarner Losh 	const struct module_data *mod;
909ca987d46SWarner Losh 
910ca987d46SWarner Losh 	mod = dev->dev_module;
911ca987d46SWarner Losh 
912ca987d46SWarner Losh 	if ((dev->dev_softc_alloc == 0) &&
913ca987d46SWarner Losh 	    (mod->driver->size != 0)) {
914ca987d46SWarner Losh 		dev->dev_sc = malloc(mod->driver->size,
915ca987d46SWarner Losh 		    M_DEVBUF, M_WAITOK | M_ZERO);
916ca987d46SWarner Losh 
917ca987d46SWarner Losh 		if (dev->dev_sc == NULL)
918ca987d46SWarner Losh 			return (ENOMEM);
919ca987d46SWarner Losh 
920ca987d46SWarner Losh 		dev->dev_softc_alloc = 1;
921ca987d46SWarner Losh 	}
922ca987d46SWarner Losh 	return (0);
923ca987d46SWarner Losh }
924ca987d46SWarner Losh 
925ca987d46SWarner Losh int
device_probe_and_attach(device_t dev)926ca987d46SWarner Losh device_probe_and_attach(device_t dev)
927ca987d46SWarner Losh {
928ca987d46SWarner Losh 	const struct module_data *mod;
929ca987d46SWarner Losh 	const char *bus_name_parent;
930ee15875cSJohn Baldwin 	devclass_t dc;
931ca987d46SWarner Losh 
932ca987d46SWarner Losh 	if (dev->dev_attached)
933ca987d46SWarner Losh 		return (0);		/* fail-safe */
934ca987d46SWarner Losh 
935ca987d46SWarner Losh 	/*
936ee15875cSJohn Baldwin          * Find a module for our device, if any
937ca987d46SWarner Losh          */
938ee15875cSJohn Baldwin 	bus_name_parent = device_get_name(device_get_parent(dev));
939ca987d46SWarner Losh 
940ca987d46SWarner Losh 	TAILQ_FOREACH(mod, &module_head, entry) {
941*40d7ba08SJohn Baldwin 		if (strcmp(mod->bus_name, bus_name_parent) != 0)
942ee15875cSJohn Baldwin 			continue;
943ee15875cSJohn Baldwin 
944ee15875cSJohn Baldwin 		dc = devclass_find(mod->mod_name);
945ee15875cSJohn Baldwin 
946ee15875cSJohn Baldwin 		/* Does this device need assigning to the new devclass? */
947ee15875cSJohn Baldwin 		if (dev->dev_class != dc) {
948ee15875cSJohn Baldwin 			if (dev->dev_fixed_class)
949ee15875cSJohn Baldwin 				continue;
950ee15875cSJohn Baldwin 			if (dev->dev_class != NULL)
951ee15875cSJohn Baldwin 				devclass_delete_device(dev->dev_class, dev);
952ee15875cSJohn Baldwin 			if (devclass_add_device(dc, dev)) {
953ca987d46SWarner Losh 				continue;
954ca987d46SWarner Losh 			}
955ca987d46SWarner Losh 		}
956ee15875cSJohn Baldwin 
957ee15875cSJohn Baldwin 		dev->dev_module = mod;
958ca987d46SWarner Losh 		if (DEVICE_PROBE(dev) <= 0) {
959ca987d46SWarner Losh 
960ca987d46SWarner Losh 			if (device_allocate_softc(dev) == 0) {
961ca987d46SWarner Losh 
962ca987d46SWarner Losh 				if (DEVICE_ATTACH(dev) == 0) {
963ca987d46SWarner Losh 					/* success */
964ca987d46SWarner Losh 					dev->dev_attached = 1;
965ca987d46SWarner Losh 					return (0);
966ca987d46SWarner Losh 				}
967ca987d46SWarner Losh 			}
968ca987d46SWarner Losh 		}
969ca987d46SWarner Losh 		/* else try next driver */
970ca987d46SWarner Losh 
971ca987d46SWarner Losh 		device_detach(dev);
972ca987d46SWarner Losh 	}
973ca987d46SWarner Losh 
974ca987d46SWarner Losh 	return (ENODEV);
975ca987d46SWarner Losh }
976ca987d46SWarner Losh 
977ca987d46SWarner Losh int
device_detach(device_t dev)978ca987d46SWarner Losh device_detach(device_t dev)
979ca987d46SWarner Losh {
980ca987d46SWarner Losh 	const struct module_data *mod = dev->dev_module;
981ca987d46SWarner Losh 	int error;
982ca987d46SWarner Losh 
983ca987d46SWarner Losh 	if (dev->dev_attached) {
984ca987d46SWarner Losh 
985ca987d46SWarner Losh 		error = DEVICE_DETACH(dev);
986ca987d46SWarner Losh 		if (error) {
987ca987d46SWarner Losh 			return error;
988ca987d46SWarner Losh 		}
989ca987d46SWarner Losh 		dev->dev_attached = 0;
990ca987d46SWarner Losh 	}
991ca987d46SWarner Losh 	device_set_softc(dev, NULL);
992ee15875cSJohn Baldwin 	dev->dev_module = NULL;
993ca987d46SWarner Losh 
994ca987d46SWarner Losh 	if (dev->dev_fixed_class == 0)
995ee15875cSJohn Baldwin 		devclass_delete_device(dev->dev_class, dev);
996ca987d46SWarner Losh 
997ca987d46SWarner Losh 	return (0);
998ca987d46SWarner Losh }
999ca987d46SWarner Losh 
1000ca987d46SWarner Losh void
device_set_softc(device_t dev,void * softc)1001ca987d46SWarner Losh device_set_softc(device_t dev, void *softc)
1002ca987d46SWarner Losh {
1003ca987d46SWarner Losh 	if (dev->dev_softc_alloc) {
1004ca987d46SWarner Losh 		free(dev->dev_sc, M_DEVBUF);
1005ca987d46SWarner Losh 		dev->dev_sc = NULL;
1006ca987d46SWarner Losh 	}
1007ca987d46SWarner Losh 	dev->dev_sc = softc;
1008ca987d46SWarner Losh 	dev->dev_softc_alloc = 0;
1009ca987d46SWarner Losh }
1010ca987d46SWarner Losh 
1011ca987d46SWarner Losh void   *
device_get_softc(device_t dev)1012ca987d46SWarner Losh device_get_softc(device_t dev)
1013ca987d46SWarner Losh {
1014ca987d46SWarner Losh 	if (dev == NULL)
1015ca987d46SWarner Losh 		return (NULL);
1016ca987d46SWarner Losh 
1017ca987d46SWarner Losh 	return (dev->dev_sc);
1018ca987d46SWarner Losh }
1019ca987d46SWarner Losh 
1020ca987d46SWarner Losh int
device_is_attached(device_t dev)1021ca987d46SWarner Losh device_is_attached(device_t dev)
1022ca987d46SWarner Losh {
1023ca987d46SWarner Losh 	return (dev->dev_attached);
1024ca987d46SWarner Losh }
1025ca987d46SWarner Losh 
1026ca987d46SWarner Losh void
device_set_desc(device_t dev,const char * desc)1027ca987d46SWarner Losh device_set_desc(device_t dev, const char *desc)
1028ca987d46SWarner Losh {
1029ca987d46SWarner Losh 	snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc);
1030ca987d46SWarner Losh }
1031ca987d46SWarner Losh 
1032ca987d46SWarner Losh void
device_set_desc_copy(device_t dev,const char * desc)1033ca987d46SWarner Losh device_set_desc_copy(device_t dev, const char *desc)
1034ca987d46SWarner Losh {
1035ca987d46SWarner Losh 	device_set_desc(dev, desc);
1036ca987d46SWarner Losh }
1037ca987d46SWarner Losh 
1038ca987d46SWarner Losh void   *
devclass_get_softc(devclass_t dc,int unit)1039ca987d46SWarner Losh devclass_get_softc(devclass_t dc, int unit)
1040ca987d46SWarner Losh {
1041ca987d46SWarner Losh 	return (device_get_softc(devclass_get_device(dc, unit)));
1042ca987d46SWarner Losh }
1043ca987d46SWarner Losh 
1044ca987d46SWarner Losh int
devclass_get_maxunit(devclass_t dc)1045ca987d46SWarner Losh devclass_get_maxunit(devclass_t dc)
1046ca987d46SWarner Losh {
1047ca987d46SWarner Losh 	int max_unit = 0;
1048ca987d46SWarner Losh 
1049ca987d46SWarner Losh 	if (dc) {
1050ca987d46SWarner Losh 		max_unit = DEVCLASS_MAXUNIT;
1051ca987d46SWarner Losh 		while (max_unit--) {
1052ca987d46SWarner Losh 			if (dc->dev_list[max_unit]) {
1053ca987d46SWarner Losh 				break;
1054ca987d46SWarner Losh 			}
1055ca987d46SWarner Losh 		}
1056ca987d46SWarner Losh 		max_unit++;
1057ca987d46SWarner Losh 	}
1058ca987d46SWarner Losh 	return (max_unit);
1059ca987d46SWarner Losh }
1060ca987d46SWarner Losh 
1061ca987d46SWarner Losh device_t
devclass_get_device(devclass_t dc,int unit)1062ca987d46SWarner Losh devclass_get_device(devclass_t dc, int unit)
1063ca987d46SWarner Losh {
1064ca987d46SWarner Losh 	return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ?
1065ca987d46SWarner Losh 	    NULL : dc->dev_list[unit]);
1066ca987d46SWarner Losh }
1067ca987d46SWarner Losh 
1068ca987d46SWarner Losh devclass_t
devclass_find(const char * classname)1069ca987d46SWarner Losh devclass_find(const char *classname)
1070ca987d46SWarner Losh {
1071ee15875cSJohn Baldwin 	devclass_t dc;
1072ca987d46SWarner Losh 
1073ee15875cSJohn Baldwin 	TAILQ_FOREACH(dc, &devclasses, link) {
1074*40d7ba08SJohn Baldwin 		if (strcmp(dc->name, classname) == 0)
1075ee15875cSJohn Baldwin 			return (dc);
1076ca987d46SWarner Losh 	}
1077ca987d46SWarner Losh 	return (NULL);
1078ca987d46SWarner Losh }
1079ca987d46SWarner Losh 
1080ca987d46SWarner Losh void
module_register(void * data)1081ca987d46SWarner Losh module_register(void *data)
1082ca987d46SWarner Losh {
1083ca987d46SWarner Losh 	struct module_data *mdata = data;
1084ca987d46SWarner Losh 
1085ca987d46SWarner Losh 	TAILQ_INSERT_TAIL(&module_head, mdata, entry);
1086ee15875cSJohn Baldwin 	(void)devclass_find_create(mdata->mod_name);
1087ca987d46SWarner Losh }
1088ca987d46SWarner Losh 
1089ca987d46SWarner Losh /*------------------------------------------------------------------------*
1090ca987d46SWarner Losh  * System startup
1091ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1092ca987d46SWarner Losh 
1093ca987d46SWarner Losh static void
sysinit_run(const void ** ppdata)1094ca987d46SWarner Losh sysinit_run(const void **ppdata)
1095ca987d46SWarner Losh {
1096ca987d46SWarner Losh 	const struct sysinit *psys;
1097ca987d46SWarner Losh 
1098ca987d46SWarner Losh 	while ((psys = *ppdata) != NULL) {
1099ca987d46SWarner Losh 		(psys->func) (psys->data);
1100ca987d46SWarner Losh 		ppdata++;
1101ca987d46SWarner Losh 	}
1102ca987d46SWarner Losh }
1103ca987d46SWarner Losh 
1104ca987d46SWarner Losh /*------------------------------------------------------------------------*
1105ca987d46SWarner Losh  * USB process API
1106ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1107ca987d46SWarner Losh 
1108ca987d46SWarner Losh static int usb_do_process(struct usb_process *);
1109ca987d46SWarner Losh static int usb_proc_level = -1;
1110ca987d46SWarner Losh static struct mtx usb_proc_mtx;
1111ca987d46SWarner Losh 
1112ca987d46SWarner Losh void
usb_idle(void)1113ca987d46SWarner Losh usb_idle(void)
1114ca987d46SWarner Losh {
1115ca987d46SWarner Losh 	int old_level = usb_proc_level;
1116ca987d46SWarner Losh 	int old_giant = Giant.owned;
1117ca987d46SWarner Losh 	int worked;
1118ca987d46SWarner Losh 
1119ca987d46SWarner Losh 	device_run_interrupts(usb_pci_root);
1120ca987d46SWarner Losh 
1121ca987d46SWarner Losh 	do {
1122ca987d46SWarner Losh 		worked = 0;
1123ca987d46SWarner Losh 		Giant.owned = 0;
1124ca987d46SWarner Losh 
1125ca987d46SWarner Losh 		while (++usb_proc_level < USB_PROC_MAX)
1126ca987d46SWarner Losh 			worked |= usb_do_process(usb_process + usb_proc_level);
1127ca987d46SWarner Losh 
1128ca987d46SWarner Losh 		usb_proc_level = old_level;
1129ca987d46SWarner Losh 		Giant.owned = old_giant;
1130ca987d46SWarner Losh 
1131ca987d46SWarner Losh 	} while (worked);
1132ca987d46SWarner Losh }
1133ca987d46SWarner Losh 
1134ca987d46SWarner Losh void
usb_init(void)1135ca987d46SWarner Losh usb_init(void)
1136ca987d46SWarner Losh {
1137ca987d46SWarner Losh 	sysinit_run(sysinit_data);
1138ca987d46SWarner Losh }
1139ca987d46SWarner Losh 
1140ca987d46SWarner Losh void
usb_uninit(void)1141ca987d46SWarner Losh usb_uninit(void)
1142ca987d46SWarner Losh {
1143ca987d46SWarner Losh 	sysinit_run(sysuninit_data);
1144ca987d46SWarner Losh }
1145ca987d46SWarner Losh 
1146ca987d46SWarner Losh static void
usb_process_init_sub(struct usb_process * up)1147ca987d46SWarner Losh usb_process_init_sub(struct usb_process *up)
1148ca987d46SWarner Losh {
1149ca987d46SWarner Losh 	TAILQ_INIT(&up->up_qhead);
1150ca987d46SWarner Losh 
1151ca987d46SWarner Losh 	cv_init(&up->up_cv, "-");
1152ca987d46SWarner Losh 	cv_init(&up->up_drain, "usbdrain");
1153ca987d46SWarner Losh 
1154ca987d46SWarner Losh 	up->up_mtx = &usb_proc_mtx;
1155ca987d46SWarner Losh }
1156ca987d46SWarner Losh 
1157ca987d46SWarner Losh static void
usb_process_init(void * arg)1158ca987d46SWarner Losh usb_process_init(void *arg)
1159ca987d46SWarner Losh {
1160ca987d46SWarner Losh 	uint8_t x;
1161ca987d46SWarner Losh 
1162ca987d46SWarner Losh 	mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE);
1163ca987d46SWarner Losh 
1164ca987d46SWarner Losh 	for (x = 0; x != USB_PROC_MAX; x++)
1165ca987d46SWarner Losh 		usb_process_init_sub(&usb_process[x]);
1166ca987d46SWarner Losh 
1167ca987d46SWarner Losh }
1168ca987d46SWarner Losh SYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL);
1169ca987d46SWarner Losh 
1170ca987d46SWarner Losh static int
usb_do_process(struct usb_process * up)1171ca987d46SWarner Losh usb_do_process(struct usb_process *up)
1172ca987d46SWarner Losh {
1173ca987d46SWarner Losh 	struct usb_proc_msg *pm;
1174ca987d46SWarner Losh 	int worked = 0;
1175ca987d46SWarner Losh 
1176ca987d46SWarner Losh 	mtx_lock(&usb_proc_mtx);
1177ca987d46SWarner Losh 
1178ca987d46SWarner Losh repeat:
1179ca987d46SWarner Losh 	pm = TAILQ_FIRST(&up->up_qhead);
1180ca987d46SWarner Losh 
1181ca987d46SWarner Losh 	if (pm != NULL) {
1182ca987d46SWarner Losh 
1183ca987d46SWarner Losh 		worked = 1;
1184ca987d46SWarner Losh 
1185ca987d46SWarner Losh 		(pm->pm_callback) (pm);
1186ca987d46SWarner Losh 
1187ca987d46SWarner Losh 		if (pm == TAILQ_FIRST(&up->up_qhead)) {
1188ca987d46SWarner Losh 			/* nothing changed */
1189ca987d46SWarner Losh 			TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
1190ca987d46SWarner Losh 			pm->pm_qentry.tqe_prev = NULL;
1191ca987d46SWarner Losh 		}
1192ca987d46SWarner Losh 		goto repeat;
1193ca987d46SWarner Losh 	}
1194ca987d46SWarner Losh 	mtx_unlock(&usb_proc_mtx);
1195ca987d46SWarner Losh 
1196ca987d46SWarner Losh 	return (worked);
1197ca987d46SWarner Losh }
1198ca987d46SWarner Losh 
1199ca987d46SWarner Losh void   *
usb_proc_msignal(struct usb_process * up,void * _pm0,void * _pm1)1200ca987d46SWarner Losh usb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
1201ca987d46SWarner Losh {
1202ca987d46SWarner Losh 	struct usb_proc_msg *pm0 = _pm0;
1203ca987d46SWarner Losh 	struct usb_proc_msg *pm1 = _pm1;
1204ca987d46SWarner Losh 	struct usb_proc_msg *pm2;
1205ca987d46SWarner Losh 	usb_size_t d;
1206ca987d46SWarner Losh 	uint8_t t;
1207ca987d46SWarner Losh 
1208ca987d46SWarner Losh 	t = 0;
1209ca987d46SWarner Losh 
1210ca987d46SWarner Losh 	if (pm0->pm_qentry.tqe_prev) {
1211ca987d46SWarner Losh 		t |= 1;
1212ca987d46SWarner Losh 	}
1213ca987d46SWarner Losh 	if (pm1->pm_qentry.tqe_prev) {
1214ca987d46SWarner Losh 		t |= 2;
1215ca987d46SWarner Losh 	}
1216ca987d46SWarner Losh 	if (t == 0) {
1217ca987d46SWarner Losh 		/*
1218ca987d46SWarner Losh 		 * No entries are queued. Queue "pm0" and use the existing
1219ca987d46SWarner Losh 		 * message number.
1220ca987d46SWarner Losh 		 */
1221ca987d46SWarner Losh 		pm2 = pm0;
1222ca987d46SWarner Losh 	} else if (t == 1) {
1223ca987d46SWarner Losh 		/* Check if we need to increment the message number. */
1224ca987d46SWarner Losh 		if (pm0->pm_num == up->up_msg_num) {
1225ca987d46SWarner Losh 			up->up_msg_num++;
1226ca987d46SWarner Losh 		}
1227ca987d46SWarner Losh 		pm2 = pm1;
1228ca987d46SWarner Losh 	} else if (t == 2) {
1229ca987d46SWarner Losh 		/* Check if we need to increment the message number. */
1230ca987d46SWarner Losh 		if (pm1->pm_num == up->up_msg_num) {
1231ca987d46SWarner Losh 			up->up_msg_num++;
1232ca987d46SWarner Losh 		}
1233ca987d46SWarner Losh 		pm2 = pm0;
1234ca987d46SWarner Losh 	} else if (t == 3) {
1235ca987d46SWarner Losh 		/*
1236ca987d46SWarner Losh 		 * Both entries are queued. Re-queue the entry closest to
1237ca987d46SWarner Losh 		 * the end.
1238ca987d46SWarner Losh 		 */
1239ca987d46SWarner Losh 		d = (pm1->pm_num - pm0->pm_num);
1240ca987d46SWarner Losh 
1241ca987d46SWarner Losh 		/* Check sign after subtraction */
1242ca987d46SWarner Losh 		if (d & 0x80000000) {
1243ca987d46SWarner Losh 			pm2 = pm0;
1244ca987d46SWarner Losh 		} else {
1245ca987d46SWarner Losh 			pm2 = pm1;
1246ca987d46SWarner Losh 		}
1247ca987d46SWarner Losh 
1248ca987d46SWarner Losh 		TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
1249ca987d46SWarner Losh 	} else {
1250ca987d46SWarner Losh 		pm2 = NULL;		/* panic - should not happen */
1251ca987d46SWarner Losh 	}
1252ca987d46SWarner Losh 
1253ca987d46SWarner Losh 	/* Put message last on queue */
1254ca987d46SWarner Losh 
1255ca987d46SWarner Losh 	pm2->pm_num = up->up_msg_num;
1256ca987d46SWarner Losh 	TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
1257ca987d46SWarner Losh 
1258ca987d46SWarner Losh 	return (pm2);
1259ca987d46SWarner Losh }
1260ca987d46SWarner Losh 
1261ca987d46SWarner Losh /*------------------------------------------------------------------------*
1262ca987d46SWarner Losh  *	usb_proc_is_gone
1263ca987d46SWarner Losh  *
1264ca987d46SWarner Losh  * Return values:
1265ca987d46SWarner Losh  *    0: USB process is running
1266ca987d46SWarner Losh  * Else: USB process is tearing down
1267ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1268ca987d46SWarner Losh uint8_t
usb_proc_is_gone(struct usb_process * up)1269ca987d46SWarner Losh usb_proc_is_gone(struct usb_process *up)
1270ca987d46SWarner Losh {
1271ca987d46SWarner Losh 	return (0);
1272ca987d46SWarner Losh }
1273ca987d46SWarner Losh 
1274ca987d46SWarner Losh /*------------------------------------------------------------------------*
1275ca987d46SWarner Losh  *	usb_proc_mwait
1276ca987d46SWarner Losh  *
1277ca987d46SWarner Losh  * This function will return when the USB process message pointed to
1278ca987d46SWarner Losh  * by "pm" is no longer on a queue. This function must be called
1279ca987d46SWarner Losh  * having "usb_proc_mtx" locked.
1280ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1281ca987d46SWarner Losh void
usb_proc_mwait(struct usb_process * up,void * _pm0,void * _pm1)1282ca987d46SWarner Losh usb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
1283ca987d46SWarner Losh {
1284ca987d46SWarner Losh 	struct usb_proc_msg *pm0 = _pm0;
1285ca987d46SWarner Losh 	struct usb_proc_msg *pm1 = _pm1;
1286ca987d46SWarner Losh 
1287ca987d46SWarner Losh 	/* Just remove the messages from the queue. */
1288ca987d46SWarner Losh 	if (pm0->pm_qentry.tqe_prev) {
1289ca987d46SWarner Losh 		TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
1290ca987d46SWarner Losh 		pm0->pm_qentry.tqe_prev = NULL;
1291ca987d46SWarner Losh 	}
1292ca987d46SWarner Losh 	if (pm1->pm_qentry.tqe_prev) {
1293ca987d46SWarner Losh 		TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
1294ca987d46SWarner Losh 		pm1->pm_qentry.tqe_prev = NULL;
1295ca987d46SWarner Losh 	}
1296ca987d46SWarner Losh }
1297ca987d46SWarner Losh 
1298ca987d46SWarner Losh /*------------------------------------------------------------------------*
1299ca987d46SWarner Losh  * SYSTEM attach
1300ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1301ca987d46SWarner Losh 
1302ca987d46SWarner Losh #ifdef USB_PCI_PROBE_LIST
1303ca987d46SWarner Losh static device_method_t pci_methods[] = {
1304ca987d46SWarner Losh 	DEVMETHOD_END
1305ca987d46SWarner Losh };
1306ca987d46SWarner Losh 
1307ca987d46SWarner Losh static driver_t pci_driver = {
1308ca987d46SWarner Losh 	.name = "pci",
1309ca987d46SWarner Losh 	.methods = pci_methods,
1310ca987d46SWarner Losh };
1311ca987d46SWarner Losh 
1312ca987d46SWarner Losh static devclass_t pci_devclass;
1313ca987d46SWarner Losh 
1314ca987d46SWarner Losh DRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1315ca987d46SWarner Losh 
1316ca987d46SWarner Losh static const char *usb_pci_devices[] = {
1317ca987d46SWarner Losh 	USB_PCI_PROBE_LIST
1318ca987d46SWarner Losh };
1319ca987d46SWarner Losh 
1320ca987d46SWarner Losh #define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1321ca987d46SWarner Losh 
1322ca987d46SWarner Losh static device_t usb_pci_dev[USB_PCI_USB_MAX];
1323ca987d46SWarner Losh 
1324ca987d46SWarner Losh static void
usb_pci_mod_load(void * arg)1325ca987d46SWarner Losh usb_pci_mod_load(void *arg)
1326ca987d46SWarner Losh {
1327ca987d46SWarner Losh 	uint32_t x;
1328ca987d46SWarner Losh 
1329ca987d46SWarner Losh 	usb_pci_root = device_add_child(NULL, "pci", -1);
1330ca987d46SWarner Losh 	if (usb_pci_root == NULL)
1331ca987d46SWarner Losh 		return;
1332ca987d46SWarner Losh 
1333ca987d46SWarner Losh 	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1334ca987d46SWarner Losh 		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1335ca987d46SWarner Losh 		if (usb_pci_dev[x] == NULL)
1336ca987d46SWarner Losh 			continue;
1337ca987d46SWarner Losh 		if (device_probe_and_attach(usb_pci_dev[x])) {
1338ca987d46SWarner Losh 			device_printf(usb_pci_dev[x],
1339ca987d46SWarner Losh 			    "WARNING: Probe and attach failed!\n");
1340ca987d46SWarner Losh 		}
1341ca987d46SWarner Losh 	}
1342ca987d46SWarner Losh }
1343ca987d46SWarner Losh SYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1344ca987d46SWarner Losh 
1345ca987d46SWarner Losh static void
usb_pci_mod_unload(void * arg)1346ca987d46SWarner Losh usb_pci_mod_unload(void *arg)
1347ca987d46SWarner Losh {
1348ca987d46SWarner Losh 	uint32_t x;
1349ca987d46SWarner Losh 
1350ca987d46SWarner Losh 	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1351ca987d46SWarner Losh 		if (usb_pci_dev[x]) {
1352ca987d46SWarner Losh 			device_detach(usb_pci_dev[x]);
1353ca987d46SWarner Losh 			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1354ca987d46SWarner Losh 		}
1355ca987d46SWarner Losh 	}
1356ca987d46SWarner Losh 	if (usb_pci_root)
1357ca987d46SWarner Losh 		device_delete_child(NULL, usb_pci_root);
1358ca987d46SWarner Losh }
1359ca987d46SWarner Losh SYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1360ca987d46SWarner Losh #endif
1361ca987d46SWarner Losh 
1362ca987d46SWarner Losh /*------------------------------------------------------------------------*
1363ca987d46SWarner Losh  * MALLOC API
1364ca987d46SWarner Losh  *------------------------------------------------------------------------*/
1365ca987d46SWarner Losh 
1366ca987d46SWarner Losh #ifndef HAVE_MALLOC
1367ca987d46SWarner Losh #define	USB_POOL_ALIGN 8
1368ca987d46SWarner Losh 
1369ca987d46SWarner Losh static uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1370ca987d46SWarner Losh static uint32_t usb_pool_rem = USB_POOL_SIZE;
1371ca987d46SWarner Losh static uint32_t usb_pool_entries;
1372ca987d46SWarner Losh 
1373ca987d46SWarner Losh struct malloc_hdr {
1374ca987d46SWarner Losh 	TAILQ_ENTRY(malloc_hdr) entry;
1375ca987d46SWarner Losh 	uint32_t size;
1376ca987d46SWarner Losh } __aligned(USB_POOL_ALIGN);
1377ca987d46SWarner Losh 
1378ca987d46SWarner Losh static TAILQ_HEAD(, malloc_hdr) malloc_head =
1379ca987d46SWarner Losh 	TAILQ_HEAD_INITIALIZER(malloc_head);
1380ca987d46SWarner Losh 
1381ca987d46SWarner Losh void   *
usb_malloc(unsigned long size)1382ca987d46SWarner Losh usb_malloc(unsigned long size)
1383ca987d46SWarner Losh {
1384ca987d46SWarner Losh 	struct malloc_hdr *hdr;
1385ca987d46SWarner Losh 
1386ca987d46SWarner Losh 	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1387ca987d46SWarner Losh 	size += sizeof(struct malloc_hdr);
1388ca987d46SWarner Losh 
1389ca987d46SWarner Losh 	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1390ca987d46SWarner Losh 		if (hdr->size == size)
1391ca987d46SWarner Losh 			break;
1392ca987d46SWarner Losh 	}
1393ca987d46SWarner Losh 
1394ca987d46SWarner Losh 	if (hdr) {
1395ca987d46SWarner Losh 		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1396ca987d46SWarner Losh 		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1397ca987d46SWarner Losh 
1398ca987d46SWarner Losh 		TAILQ_REMOVE(&malloc_head, hdr, entry);
1399ca987d46SWarner Losh 		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1400ca987d46SWarner Losh 		return (hdr + 1);
1401ca987d46SWarner Losh 	}
1402ca987d46SWarner Losh 	if (usb_pool_rem >= size) {
1403ca987d46SWarner Losh 		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1404ca987d46SWarner Losh 		hdr->size = size;
1405ca987d46SWarner Losh 
1406ca987d46SWarner Losh 		usb_pool_rem -= size;
1407ca987d46SWarner Losh 		usb_pool_entries++;
1408ca987d46SWarner Losh 
1409ca987d46SWarner Losh 		DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1410ca987d46SWarner Losh 		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1411ca987d46SWarner Losh 
1412ca987d46SWarner Losh 		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1413ca987d46SWarner Losh 		return (hdr + 1);
1414ca987d46SWarner Losh 	}
1415ca987d46SWarner Losh 	return (NULL);
1416ca987d46SWarner Losh }
1417ca987d46SWarner Losh 
1418ca987d46SWarner Losh void
usb_free(void * arg)1419ca987d46SWarner Losh usb_free(void *arg)
1420ca987d46SWarner Losh {
1421ca987d46SWarner Losh 	struct malloc_hdr *hdr;
1422ca987d46SWarner Losh 
1423ca987d46SWarner Losh 	if (arg == NULL)
1424ca987d46SWarner Losh 		return;
1425ca987d46SWarner Losh 
1426ca987d46SWarner Losh 	hdr = arg;
1427ca987d46SWarner Losh 	hdr--;
1428ca987d46SWarner Losh 
1429ca987d46SWarner Losh 	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1430ca987d46SWarner Losh }
1431ca987d46SWarner Losh #endif
1432ca987d46SWarner Losh 
1433ca987d46SWarner Losh char   *
usb_strdup(const char * str)1434ca987d46SWarner Losh usb_strdup(const char *str)
1435ca987d46SWarner Losh {
1436ca987d46SWarner Losh 	char *tmp;
1437ca987d46SWarner Losh 	int len;
1438ca987d46SWarner Losh 
1439ca987d46SWarner Losh 	len = 1 + strlen(str);
1440ca987d46SWarner Losh 
1441ca987d46SWarner Losh 	tmp = malloc(len,XXX,XXX);
1442ca987d46SWarner Losh 	if (tmp == NULL)
1443ca987d46SWarner Losh 		return (NULL);
1444ca987d46SWarner Losh 
1445ca987d46SWarner Losh 	memcpy(tmp, str, len);
1446ca987d46SWarner Losh 	return (tmp);
1447ca987d46SWarner Losh }
1448