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