diff options
author | mav <mav@FreeBSD.org> | 2011-03-24 08:56:12 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2011-03-24 08:56:12 +0000 |
commit | 3ac96e446e1ad0ef2ed2f3c9424937047f0bfc2a (patch) | |
tree | 7e4a3c1b43ef2ce0f557ae174dfffc9df9f8a346 /sys/dev/led | |
parent | ad433c09b32c442209795217720d42efac493286 (diff) | |
download | FreeBSD-src-3ac96e446e1ad0ef2ed2f3c9424937047f0bfc2a.zip FreeBSD-src-3ac96e446e1ad0ef2ed2f3c9424937047f0bfc2a.tar.gz |
MFgraid/head r218174:
Add simple in-kernel API for controlling leds.
Diffstat (limited to 'sys/dev/led')
-rw-r--r-- | sys/dev/led/led.c | 156 | ||||
-rw-r--r-- | sys/dev/led/led.h | 2 |
2 files changed, 94 insertions, 64 deletions
diff --git a/sys/dev/led/led.c b/sys/dev/led/led.c index 521006c..e2a4370 100644 --- a/sys/dev/led/led.c +++ b/sys/dev/led/led.c @@ -26,6 +26,7 @@ __FBSDID("$FreeBSD$"); struct ledsc { LIST_ENTRY(ledsc) list; + char *name; void *private; int unit; led_t *func; @@ -83,71 +84,43 @@ led_timeout(void *p) } static int -led_state(struct cdev *dev, struct sbuf *sb, int state) +led_state(struct ledsc *sc, struct sbuf **sb, int state) { struct sbuf *sb2 = NULL; - struct ledsc *sc; - mtx_lock(&led_mtx); - sc = dev->si_drv1; - if (sc != NULL) { - sb2 = sc->spec; - sc->spec = sb; - if (sb != NULL) { - sc->str = sbuf_data(sb); - sc->ptr = sc->str; - } else { - sc->str = NULL; - sc->ptr = NULL; - sc->func(sc->private, state); - } - sc->count = 0; + sb2 = sc->spec; + sc->spec = *sb; + if (*sb != NULL) { + sc->str = sbuf_data(*sb); + sc->ptr = sc->str; + } else { + sc->str = NULL; + sc->ptr = NULL; + sc->func(sc->private, state); } - mtx_unlock(&led_mtx); - if (sb2 != NULL) - sbuf_delete(sb2); - if (sc == NULL) - return (ENXIO); + sc->count = 0; + *sb = sb2; return(0); } static int -led_write(struct cdev *dev, struct uio *uio, int ioflag) +led_parse(const char *s, struct sbuf **sb, int *state) { - int error; - char *s, *s2; - struct sbuf *sb = NULL; - int i; - - if (dev->si_drv1 == NULL) - return (ENXIO); - - if (uio->uio_resid > 512) - return (EINVAL); - s2 = s = malloc(uio->uio_resid + 1, M_DEVBUF, M_WAITOK); - s[uio->uio_resid] = '\0'; - error = uiomove(s, uio->uio_resid, uio); - if (error) { - free(s2, M_DEVBUF); - return (error); - } + int i, error; /* * Handle "on" and "off" immediately so people can flash really * fast from userland if they want to */ if (*s == '0' || *s == '1') { - error = led_state(dev, NULL, *s & 1); - free(s2, M_DEVBUF); - return(error); + *state = *s & 1; + return (0); } - sb = sbuf_new_auto(); - if (sb == NULL) { - free(s2, M_DEVBUF); + *state = 0; + *sb = sbuf_new_auto(); + if (*sb == NULL) return (ENOMEM); - } - switch(s[0]) { /* * Flash, default is 100msec/100msec. @@ -158,7 +131,7 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) i = s[1] - '1'; else i = 0; - sbuf_printf(sb, "%c%c", 'A' + i, 'a' + i); + sbuf_printf(*sb, "%c%c", 'A' + i, 'a' + i); break; /* * Digits, flashes out numbers. @@ -172,10 +145,10 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) if (i == 0) i = 10; for (; i > 1; i--) - sbuf_cat(sb, "Aa"); - sbuf_cat(sb, "Aj"); + sbuf_cat(*sb, "Aa"); + sbuf_cat(*sb, "Aj"); } - sbuf_cat(sb, "jj"); + sbuf_cat(*sb, "jj"); break; /* * String, roll your own. @@ -190,7 +163,7 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) (*s >= 'A' && *s <= 'J') || *s == 'U' || *s <= 'u' || *s == '.') - sbuf_bcat(sb, s, 1); + sbuf_bcat(*sb, s, 1); } break; /* @@ -205,29 +178,82 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) case 'm': for(s++; *s; s++) { if (*s == '.') - sbuf_cat(sb, "aA"); + sbuf_cat(*sb, "aA"); else if (*s == '-') - sbuf_cat(sb, "aC"); + sbuf_cat(*sb, "aC"); else if (*s == ' ') - sbuf_cat(sb, "b"); + sbuf_cat(*sb, "b"); else if (*s == '\n') - sbuf_cat(sb, "d"); + sbuf_cat(*sb, "d"); } - sbuf_cat(sb, "j"); + sbuf_cat(*sb, "j"); break; default: - sbuf_delete(sb); - free(s2, M_DEVBUF); + sbuf_delete(*sb); return (EINVAL); } - error = sbuf_finish(sb); - free(s2, M_DEVBUF); - if (error != 0 || sbuf_len(sb) == 0) { - sbuf_delete(sb); + error = sbuf_finish(*sb); + if (error != 0 || sbuf_len(*sb) == 0) { + *sb = NULL; + return (error); + } + return (0); +} + +static int +led_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct ledsc *sc; + char *s; + struct sbuf *sb = NULL; + int error, state = 0; + + if (uio->uio_resid > 512) + return (EINVAL); + s = malloc(uio->uio_resid + 1, M_DEVBUF, M_WAITOK); + s[uio->uio_resid] = '\0'; + error = uiomove(s, uio->uio_resid, uio); + if (error) { + free(s, M_DEVBUF); return (error); } + error = led_parse(s, &sb, &state); + free(s, M_DEVBUF); + if (error) + return (error); + mtx_lock(&led_mtx); + sc = dev->si_drv1; + if (sc != NULL) + error = led_state(sc, &sb, state); + mtx_unlock(&led_mtx); + if (sb != NULL) + sbuf_delete(sb); + return (error); +} - return (led_state(dev, sb, 0)); +int +led_set(char const *name, char const *cmd) +{ + struct ledsc *sc; + struct sbuf *sb = NULL; + int error, state = 0; + + error = led_parse(cmd, &sb, &state); + if (error) + return (error); + mtx_lock(&led_mtx); + LIST_FOREACH(sc, &led_list, list) { + if (strcmp(sc->name, name) == 0) + break; + } + if (sc != NULL) + error = led_state(sc, &sb, state); + else + error = ENOENT; + mtx_unlock(&led_mtx); + if (sb != NULL) + sbuf_delete(sb); + return (0); } static struct cdevsw led_cdevsw = { @@ -250,6 +276,7 @@ led_create_state(led_t *func, void *priv, char const *name, int state) sc = malloc(sizeof *sc, M_LED, M_WAITOK | M_ZERO); sx_xlock(&led_sx); + sc->name = strdup(name, M_LED); sc->unit = alloc_unr(led_unit); sc->private = priv; sc->func = func; @@ -287,6 +314,7 @@ led_destroy(struct cdev *dev) destroy_dev(dev); if (sc->spec != NULL) sbuf_delete(sc->spec); + free(sc->name, M_LED); free(sc, M_LED); sx_xunlock(&led_sx); } diff --git a/sys/dev/led/led.h b/sys/dev/led/led.h index bbf301e..84992c2 100644 --- a/sys/dev/led/led.h +++ b/sys/dev/led/led.h @@ -18,4 +18,6 @@ struct cdev *led_create_state(led_t *, void *, char const *, int); struct cdev *led_create(led_t *, void *, char const *); void led_destroy(struct cdev *); +int led_set(char const *, char const *); + #endif |