summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/led/led.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/led/led.c')
-rw-r--r--freebsd/sys/dev/led/led.c160
1 files changed, 92 insertions, 68 deletions
diff --git a/freebsd/sys/dev/led/led.c b/freebsd/sys/dev/led/led.c
index db609a45..c87f7f9d 100644
--- a/freebsd/sys/dev/led/led.c
+++ b/freebsd/sys/dev/led/led.c
@@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$");
struct ledsc {
LIST_ENTRY(ledsc) list;
+ char *name;
void *private;
int unit;
led_t *func;
@@ -85,71 +86,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.
@@ -160,7 +133,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.
@@ -174,10 +147,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.
@@ -192,7 +165,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;
/*
@@ -207,33 +180,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);
}
- sbuf_finish(sb);
- free(s2, M_DEVBUF);
- if (sbuf_overflowed(sb)) {
- sbuf_delete(sb);
- return (ENOMEM);
+ error = sbuf_finish(*sb);
+ if (error != 0 || sbuf_len(*sb) == 0) {
+ *sb = NULL;
+ return (error);
}
- if (sbuf_len(sb) == 0) {
- sbuf_delete(sb);
- return (0);
+ 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);
+}
+
+int
+led_set(char const *name, char const *cmd)
+{
+ struct ledsc *sc;
+ struct sbuf *sb = NULL;
+ int error, state = 0;
- return (led_state(dev, sb, 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 = {
@@ -256,6 +278,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;
@@ -293,6 +316,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);
}