bsd_kernel.c revision 269921
111820Sjulian/* $FreeBSD: stable/10/sys/boot/usb/bsd_kernel.c 269921 2014-08-13 08:18:49Z hselasky $ */
211820Sjulian/*-
311820Sjulian * Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
411820Sjulian *
511820Sjulian * Redistribution and use in source and binary forms, with or without
611820Sjulian * modification, are permitted provided that the following conditions
711820Sjulian * are met:
811820Sjulian * 1. Redistributions of source code must retain the above copyright
911820Sjulian *    notice, this list of conditions and the following disclaimer.
1011820Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1111820Sjulian *    notice, this list of conditions and the following disclaimer in the
1211820Sjulian *    documentation and/or other materials provided with the distribution.
1311820Sjulian *
1411820Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1511820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1611820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1711820Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1811820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1911820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2011820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2111820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2211820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2311820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2411820Sjulian * SUCH DAMAGE.
2511820Sjulian */
2611820Sjulian
2711820Sjulian#include <bsd_global.h>
2811820Sjulian
2911820Sjulianstruct usb_process usb_process[USB_PROC_MAX];
3011820Sjulian
3111820Sjulianstatic device_t usb_pci_root;
3211820Sjulian
3311820Sjulian/*------------------------------------------------------------------------*
3411820Sjulian * Implementation of mutex API
3511820Sjulian *------------------------------------------------------------------------*/
3611820Sjulian
3711820Sjulianstruct mtx Giant;
3850479Speter
3911820Sjulianstatic void
4011820Sjulianmtx_system_init(void *arg)
4111820Sjulian{
42122760Strhodes	mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE);
4311820Sjulian}
4411820SjulianSYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL);
4511820Sjulian
4611820Sjulianvoid
4711820Sjulianmtx_init(struct mtx *mtx, const char *name, const char *type, int opt)
4811820Sjulian{
4911820Sjulian	mtx->owned = 0;
5011820Sjulian	mtx->parent = mtx;
5111820Sjulian}
5211820Sjulian
5320287Swollmanvoid
5411820Sjulianmtx_lock(struct mtx *mtx)
5511820Sjulian{
5611820Sjulian	mtx = mtx->parent;
5711820Sjulian	mtx->owned++;
5859218Simp}
5911820Sjulian
60122760Strhodesvoid
6111820Sjulianmtx_unlock(struct mtx *mtx)
6211820Sjulian{
6311820Sjulian	mtx = mtx->parent;
6411820Sjulian	mtx->owned--;
6511820Sjulian}
6611820Sjulian
6711820Sjulianint
6811820Sjulianmtx_owned(struct mtx *mtx)
6911820Sjulian{
7011820Sjulian	mtx = mtx->parent;
7111820Sjulian	return (mtx->owned != 0);
7211820Sjulian}
7311820Sjulian
7411820Sjulianvoid
7511820Sjulianmtx_destroy(struct mtx *mtx)
7611820Sjulian{
7711820Sjulian	/* NOP */
7811820Sjulian}
7911820Sjulian
8011820Sjulian/*------------------------------------------------------------------------*
8111820Sjulian * Implementation of shared/exclusive mutex API
8211820Sjulian *------------------------------------------------------------------------*/
8311820Sjulian
84128186Sluigivoid
8511820Sjuliansx_init_flags(struct sx *sx, const char *name, int flags)
8611820Sjulian{
8711820Sjulian	sx->owned = 0;
8811820Sjulian}
8911820Sjulian
9011820Sjulianvoid
9111820Sjuliansx_destroy(struct sx *sx)
9211820Sjulian{
9311820Sjulian	/* NOP */
9411820Sjulian}
9511820Sjulian
9611820Sjulianvoid
9711820Sjuliansx_xlock(struct sx *sx)
9811820Sjulian{
9911820Sjulian	sx->owned++;
10011820Sjulian}
10111820Sjulian
102128186Sluigivoid
10311820Sjuliansx_xunlock(struct sx *sx)
10411820Sjulian{
10511820Sjulian	sx->owned--;
10611820Sjulian}
10711820Sjulian
10811820Sjulianint
10911820Sjuliansx_xlocked(struct sx *sx)
11011820Sjulian{
11111820Sjulian	return (sx->owned != 0);
11211820Sjulian}
11311820Sjulian
11411820Sjulian/*------------------------------------------------------------------------*
11511820Sjulian * Implementaiton of condition variable API
11611820Sjulian *------------------------------------------------------------------------*/
11711820Sjulian
11811820Sjulianvoid
11911820Sjuliancv_init(struct cv *cv, const char *desc)
12011820Sjulian{
12111820Sjulian	cv->sleeping = 0;
12211820Sjulian}
12311820Sjulian
12411820Sjulianvoid
12511820Sjuliancv_destroy(struct cv *cv)
12611820Sjulian{
12711820Sjulian	/* NOP */
12811820Sjulian}
12911820Sjulian
13011820Sjulianvoid
13111820Sjuliancv_wait(struct cv *cv, struct mtx *mtx)
13211820Sjulian{
13311820Sjulian	cv_timedwait(cv, mtx, -1);
13411820Sjulian}
13511820Sjulian
13611820Sjulianint
13711820Sjuliancv_timedwait(struct cv *cv, struct mtx *mtx, int timo)
13811820Sjulian{
13911820Sjulian	int start = ticks;
14011820Sjulian	int delta;
14111820Sjulian
14211820Sjulian	if (cv->sleeping)
14311820Sjulian		return (EWOULDBLOCK);	/* not allowed */
14411820Sjulian
14511820Sjulian	cv->sleeping = 1;
14611820Sjulian
14711820Sjulian	while (cv->sleeping) {
14811820Sjulian		if (timo >= 0) {
14911820Sjulian			delta = ticks - start;
15011820Sjulian			if (delta >= timo || delta < 0)
15111820Sjulian				break;
15211820Sjulian		}
15311820Sjulian		mtx_unlock(mtx);
15411820Sjulian
15511820Sjulian		usb_idle();
15611820Sjulian
15711820Sjulian		mtx_lock(mtx);
15811820Sjulian	}
15911820Sjulian
16011820Sjulian	if (cv->sleeping) {
16111820Sjulian		cv->sleeping = 0;
16211820Sjulian		return (EWOULDBLOCK);	/* not allowed */
16311820Sjulian	}
16411820Sjulian	return (0);
16511820Sjulian}
16611820Sjulian
16711820Sjulianvoid
16811820Sjuliancv_signal(struct cv *cv)
16911820Sjulian{
17011820Sjulian	cv->sleeping = 0;
17111820Sjulian}
17211820Sjulian
17311820Sjulianvoid
17411820Sjuliancv_broadcast(struct cv *cv)
17511820Sjulian{
17611820Sjulian	cv->sleeping = 0;
17711820Sjulian}
17811820Sjulian
17911820Sjulian/*------------------------------------------------------------------------*
18011820Sjulian * Implementation of callout API
18111820Sjulian *------------------------------------------------------------------------*/
18211820Sjulian
18343713Sjhaystatic void callout_proc_msg(struct usb_proc_msg *);
18443713Sjhay
18543713Sjhayvolatile int ticks = 0;
18611820Sjulian
18711820Sjulianstatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout);
18811820Sjulian
18911820Sjulianstatic struct mtx mtx_callout;
19011820Sjulianstatic struct usb_proc_msg callout_msg[2];
19111820Sjulian
19211820Sjulianstatic void
19311820Sjuliancallout_system_init(void *arg)
19411820Sjulian{
19511820Sjulian	mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE);
19611820Sjulian
19711820Sjulian	callout_msg[0].pm_callback = &callout_proc_msg;
19811820Sjulian	callout_msg[1].pm_callback = &callout_proc_msg;
19911820Sjulian}
20011820SjulianSYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL);
20111820Sjulian
20211820Sjulianstatic void
20311820Sjuliancallout_callback(struct callout *c)
20411820Sjulian{
20511820Sjulian	mtx_lock(c->mtx);
20611820Sjulian
20711820Sjulian	mtx_lock(&mtx_callout);
20811820Sjulian	if (c->entry.le_prev != NULL) {
20911820Sjulian		LIST_REMOVE(c, entry);
21011820Sjulian		c->entry.le_prev = NULL;
21111820Sjulian	}
21211820Sjulian	mtx_unlock(&mtx_callout);
21311820Sjulian
21411820Sjulian	if (c->func)
21511820Sjulian		(c->func) (c->arg);
21611820Sjulian
21711820Sjulian	if (!(c->flags & CALLOUT_RETURNUNLOCKED))
21811820Sjulian		mtx_unlock(c->mtx);
21911820Sjulian}
22011820Sjulian
22111820Sjulianvoid
22211820Sjuliancallout_process(int timeout)
22311820Sjulian{
22411820Sjulian	ticks += timeout;
22511820Sjulian	usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]);
22611820Sjulian}
22711820Sjulian
22811820Sjulianstatic void
22911820Sjuliancallout_proc_msg(struct usb_proc_msg *pmsg)
23011820Sjulian{
23111820Sjulian	struct callout *c;
23211820Sjulian	int delta;
23311820Sjulian
23411820Sjulianrepeat:
23511820Sjulian	mtx_lock(&mtx_callout);
23611820Sjulian
23711820Sjulian	LIST_FOREACH(c, &head_callout, entry) {
23811820Sjulian
23914165Sjulian		delta = c->timeout - ticks;
24011820Sjulian		if (delta < 0) {
24111820Sjulian			mtx_unlock(&mtx_callout);
24211820Sjulian
24311820Sjulian			callout_callback(c);
24411820Sjulian
24511820Sjulian			goto repeat;
24611820Sjulian		}
24711820Sjulian	}
24811820Sjulian	mtx_unlock(&mtx_callout);
24911820Sjulian}
25011820Sjulian
25111820Sjulianvoid
25211820Sjuliancallout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
25311820Sjulian{
254122760Strhodes	memset(c, 0, sizeof(*c));
25511820Sjulian
25611820Sjulian	if (mtx == NULL)
25711820Sjulian		mtx = &Giant;
25811820Sjulian
25911820Sjulian	c->mtx = mtx;
26011820Sjulian	c->flags = (flags & CALLOUT_RETURNUNLOCKED);
26111820Sjulian}
26214165Sjulian
26314165Sjulianvoid
26414165Sjuliancallout_reset(struct callout *c, int to_ticks,
26514165Sjulian    void (*func) (void *), void *arg)
26614165Sjulian{
26711820Sjulian	callout_stop(c);
26811820Sjulian
26911820Sjulian	c->func = func;
27011820Sjulian	c->arg = arg;
27111820Sjulian	c->timeout = ticks + to_ticks;
27211820Sjulian
27311820Sjulian	mtx_lock(&mtx_callout);
27411820Sjulian	LIST_INSERT_HEAD(&head_callout, c, entry);
27511820Sjulian	mtx_unlock(&mtx_callout);
27611820Sjulian}
27711820Sjulian
27811820Sjulianvoid
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
1094static device_method_t pci_methods[] = {
1095	DEVMETHOD_END
1096};
1097
1098static driver_t pci_driver = {
1099	.name = "pci",
1100	.methods = pci_methods,
1101};
1102
1103static devclass_t pci_devclass;
1104
1105DRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0);
1106
1107static const char *usb_pci_devices[] = {
1108#ifdef USB_PROBE_LIST
1109	USB_PROBE_LIST
1110#endif
1111};
1112
1113#define	USB_PCI_USB_MAX	(sizeof(usb_pci_devices) / sizeof(void *))
1114
1115static device_t usb_pci_dev[USB_PCI_USB_MAX];
1116
1117static void
1118usb_pci_mod_load(void *arg)
1119{
1120	uint32_t x;
1121
1122	usb_pci_root = device_add_child(NULL, "pci", -1);
1123	if (usb_pci_root == NULL)
1124		return;
1125
1126	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1127		usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1);
1128		if (usb_pci_dev[x] == NULL)
1129			continue;
1130		if (device_probe_and_attach(usb_pci_dev[x])) {
1131			device_printf(usb_pci_dev[x],
1132			    "WARNING: Probe and attach failed!\n");
1133		}
1134	}
1135}
1136SYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0);
1137
1138static void
1139usb_pci_mod_unload(void *arg)
1140{
1141	uint32_t x;
1142
1143	for (x = 0; x != USB_PCI_USB_MAX; x++) {
1144		if (usb_pci_dev[x]) {
1145			device_detach(usb_pci_dev[x]);
1146			device_delete_child(usb_pci_root, usb_pci_dev[x]);
1147		}
1148	}
1149	if (usb_pci_root)
1150		device_delete_child(NULL, usb_pci_root);
1151}
1152SYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0);
1153
1154/*------------------------------------------------------------------------*
1155 * MALLOC API
1156 *------------------------------------------------------------------------*/
1157
1158#define	USB_POOL_ALIGN 8
1159
1160static uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN);
1161static uint32_t usb_pool_rem = USB_POOL_SIZE;
1162static uint32_t usb_pool_entries;
1163
1164struct malloc_hdr {
1165	TAILQ_ENTRY(malloc_hdr) entry;
1166	uint32_t size;
1167} __aligned(USB_POOL_ALIGN);
1168
1169static TAILQ_HEAD(, malloc_hdr) malloc_head =
1170	TAILQ_HEAD_INITIALIZER(malloc_head);
1171
1172void   *
1173usb_malloc(unsigned long size)
1174{
1175	struct malloc_hdr *hdr;
1176
1177	size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1);
1178	size += sizeof(struct malloc_hdr);
1179
1180	TAILQ_FOREACH(hdr, &malloc_head, entry) {
1181		if (hdr->size == size)
1182			break;
1183	}
1184
1185	if (hdr) {
1186		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1187		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1188
1189		TAILQ_REMOVE(&malloc_head, hdr, entry);
1190		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1191		return (hdr + 1);
1192	}
1193	if (usb_pool_rem >= size) {
1194		hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem);
1195		hdr->size = size;
1196
1197		usb_pool_rem -= size;
1198		usb_pool_entries++;
1199
1200		printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n",
1201		    (int)usb_pool_entries, (int)usb_pool_rem, (int)size);
1202
1203		memset(hdr + 1, 0, hdr->size - sizeof(*hdr));
1204		return (hdr + 1);
1205	}
1206	return (NULL);
1207}
1208
1209void
1210usb_free(void *arg)
1211{
1212	struct malloc_hdr *hdr;
1213
1214	if (arg == NULL)
1215		return;
1216
1217	hdr = arg;
1218	hdr--;
1219
1220	TAILQ_INSERT_TAIL(&malloc_head, hdr, entry);
1221}
1222
1223char   *
1224usb_strdup(const char *str)
1225{
1226	char *tmp;
1227	int len;
1228
1229	len = 1 + strlen(str);
1230
1231	tmp = usb_malloc(len);
1232	if (tmp == NULL)
1233		return (NULL);
1234
1235	memcpy(tmp, str, len);
1236	return (tmp);
1237}
1238