Index: sys/dev/led/led.c =================================================================== --- sys/dev/led/led.c +++ sys/dev/led/led.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -41,21 +42,23 @@ char *ptr; int count; time_t last_second; + bool in_use; + bool destroying; }; static struct unrhdr *led_unit; static struct mtx led_mtx; static struct sx led_sx; static LIST_HEAD(, ledsc) led_list = LIST_HEAD_INITIALIZER(led_list); -static struct callout led_ch; static int blinkers = 0; static MALLOC_DEFINE(M_LED, "LED", "LED driver"); static void -led_timeout(void *p) +led_timeout(void) { struct ledsc *sc; + int state; LIST_FOREACH(sc, &led_list, list) { if (sc->ptr == NULL) @@ -72,20 +75,42 @@ if (sc->last_second == time_second) continue; sc->last_second = time_second; - sc->func(sc->private, *sc->ptr == 'U'); + state = *sc->ptr == 'U'; } else if (*sc->ptr >= 'a' && *sc->ptr <= 'j') { - sc->func(sc->private, 0); + state = 0; sc->count = (*sc->ptr & 0xf) - 1; } else if (*sc->ptr >= 'A' && *sc->ptr <= 'J') { - sc->func(sc->private, 1); + state = 1; sc->count = (*sc->ptr & 0xf) - 1; } sc->ptr++; if (*sc->ptr == '\0') sc->ptr = sc->str; + sc->in_use = true; + mtx_unlock(&led_mtx); + sc->func(sc->private, state); + mtx_lock(&led_mtx); + sc->in_use = false; + if (sc->destroying) + wakeup(sc); } - if (blinkers > 0) - callout_reset(&led_ch, hz / 10, led_timeout, p); +} + +static void +led_blinker_thread(void *arg __unused) +{ + int timeout; + + mtx_lock(&led_mtx); + for (;;) { + if (blinkers > 0) + timeout = hz / 10; + else + timeout = 0; + (void)mtx_sleep(&led_list, &led_mtx, 0, "blnkwt", timeout); + led_timeout(); + } + mtx_unlock(&led_mtx); } static int @@ -95,11 +120,13 @@ sb2 = sc->spec; sc->spec = *sb; + sc->count = 0; if (*sb != NULL) { sc->str = sbuf_data(*sb); if (sc->ptr == NULL) { blinkers++; - callout_reset(&led_ch, hz / 10, led_timeout, NULL); + if (blinkers == 1) + wakeup(&led_list); } sc->ptr = sc->str; } else { @@ -107,9 +134,12 @@ if (sc->ptr != NULL) blinkers--; sc->ptr = NULL; + sc->in_use = true; + mtx_unlock(&led_mtx); sc->func(sc->private, state); + mtx_lock(&led_mtx); + sc->in_use = false; } - sc->count = 0; *sb = sb2; return(0); } @@ -298,9 +328,9 @@ mtx_lock(&led_mtx); sc->dev->si_drv1 = sc; LIST_INSERT_HEAD(&led_list, sc, list); + mtx_unlock(&led_mtx); if (state != -1) sc->func(sc->private, state != 0); - mtx_unlock(&led_mtx); return (sc->dev); } @@ -312,12 +342,13 @@ mtx_lock(&led_mtx); sc = dev->si_drv1; + sc->destroying = true; + while (sc->in_use) + (void)mtx_sleep(sc, &led_mtx, 0, "ledbsy", 0); dev->si_drv1 = NULL; if (sc->ptr != NULL) blinkers--; LIST_REMOVE(sc, list); - if (LIST_EMPTY(&led_list)) - callout_stop(&led_ch); mtx_unlock(&led_mtx); sx_xlock(&led_sx); @@ -337,7 +368,11 @@ led_unit = new_unrhdr(0, INT_MAX, NULL); mtx_init(&led_mtx, "LED mtx", NULL, MTX_DEF); sx_init(&led_sx, "LED sx"); - callout_init_mtx(&led_ch, &led_mtx, 0); + + if (kproc_create(led_blinker_thread, NULL, NULL, 0, 0, + "led blinker") != 0) { + panic("led_drvinit: can't create thread"); + } } SYSINIT(leddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, led_drvinit, NULL);