diff options
| author | shige <shige@NetBSD.org> | 2005-09-04 12:20:15 +0000 |
|---|---|---|
| committer | shige <shige@NetBSD.org> | 2005-09-04 12:20:15 +0000 |
| commit | 044ec00fc2142dbb8db7c0113059864485da1178 (patch) | |
| tree | dfa80bcbbb4f54c1fd15e943baedff8dfbfd3276 /sys | |
| parent | 100f9bce034c71f708a5e372f0dad3f10df8be7d (diff) | |
Support LED-control via sysctl (on=1/off=0).
Sysctl name: hw.obsled.led{1,2,4}.
Submitted by kiyohara.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/arch/evbppc/obs405/dev/obsled.c | 104 |
1 files changed, 95 insertions, 9 deletions
diff --git a/sys/arch/evbppc/obs405/dev/obsled.c b/sys/arch/evbppc/obs405/dev/obsled.c index 519560690c1..e91db58ab6a 100644 --- a/sys/arch/evbppc/obs405/dev/obsled.c +++ b/sys/arch/evbppc/obs405/dev/obsled.c @@ -1,4 +1,4 @@ -/* $NetBSD: obsled.c,v 1.2 2005/03/18 14:12:34 shige Exp $ */ +/* $NetBSD: obsled.c,v 1.3 2005/09/04 12:20:15 shige Exp $ */ /* * Copyright (c) 2004 Shigeyuki Fukushima. @@ -31,11 +31,12 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: obsled.c,v 1.2 2005/03/18 14:12:34 shige Exp $"); +__KERNEL_RCSID(0, "$NetBSD: obsled.c,v 1.3 2005/09/04 12:20:15 shige Exp $"); #include <sys/param.h> #include <sys/device.h> #include <sys/queue.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <machine/obs266.h> @@ -46,10 +47,14 @@ struct obsled_softc { struct device sc_dev; gpio_tag_t sc_tag; int sc_addr; + int sc_led_state; /* LED status (ON=1/OFF=0) */ + int sc_led_state_mib; }; static void obsled_attach(struct device *, struct device *, void *); static int obsled_match(struct device *, struct cfdata *, void *); +static int obsled_sysctl_verify(SYSCTLFN_PROTO); +static void obsled_set_state(struct obsled_softc *); CFATTACH_DECL(obsled, sizeof(struct obsled_softc), obsled_match, obsled_attach, NULL, NULL); @@ -75,15 +80,53 @@ obsled_attach(struct device *parent, struct device *self, void *aux) { struct obsled_softc *sc = (struct obsled_softc *)self; struct gpio_attach_args *ga = aux; - int led = (1 << sc->sc_dev.dv_unit); + struct sysctlnode *node; + int err, node_mib; + char led_name[5]; + /* int led = (1 << sc->sc_dev.dv_unit); */ - aprint_naive(": OpenBlockS LED%d\n", led); - aprint_normal(": OpenBlockS LED%d\n", led); + snprintf(led_name, sizeof(led_name), + "led%d", (1 << sc->sc_dev.dv_unit) & 0x7); + aprint_naive(": OpenBlockS %s\n", led_name); + aprint_normal(": OpenBlockS %s\n", led_name); sc->sc_tag = ga->ga_tag; sc->sc_addr = ga->ga_addr; + sc->sc_led_state = 0; obs266_led_set(OBS266_LED_OFF); + + /* add sysctl interface */ + err = sysctl_createv(NULL, 0, + NULL, NULL, + 0, CTLTYPE_NODE, + "hw", + NULL, + NULL, 0, NULL, 0, + CTL_HW, CTL_EOL); + if (err != 0) + return; + err = sysctl_createv(NULL, 0, + NULL, (const struct sysctlnode **)&node, + 0, CTLTYPE_NODE, + "obsled", + NULL, + NULL, 0, NULL, 0, + CTL_HW, CTL_CREATE, CTL_EOL); + if (err != 0) + return; + node_mib = node->sysctl_num; + err = sysctl_createv(NULL, 0, + NULL, (const struct sysctlnode **)&node, + CTLFLAG_READWRITE, CTLTYPE_INT, + led_name, + SYSCTL_DESCR("OpenBlockS LED state (0=off, 1=on)"), + obsled_sysctl_verify, 0, sc, 0, + CTL_HW, node_mib, CTL_CREATE, CTL_EOL); + if (err != 0) + return; + + sc->sc_led_state_mib = node->sysctl_num; #if 0 { gpio_tag_t tag = sc->sc_tag; @@ -92,20 +135,63 @@ obsled_attach(struct device *parent, struct device *self, void *aux) #endif } +static int +obsled_sysctl_verify(SYSCTLFN_ARGS) +{ + struct obsled_softc *sc = rnode->sysctl_data; + struct sysctlnode node; + int err, state; + + node = *rnode; + state = sc->sc_led_state; + node.sysctl_data = &state; + + err = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (err != 0 || newp == NULL) + return err; + + if (node.sysctl_num == sc->sc_led_state_mib) { + if (state < 0 || state > 1) + return EINVAL; + sc->sc_led_state = state; + obsled_set_state(sc); + } + + return 0; +} + +static void +obsled_set_state(struct obsled_softc *sc) +{ + gpio_tag_t tag = sc->sc_tag; + + (*(tag)->io_or_write)((tag)->cookie, + sc->sc_addr, + (~(sc->sc_led_state) & 1)); + /* GPIO LED input ON=0/OFF=1 */ +} + +/* + * Setting LED interface for inside kernel. + * Argumnt `led' is 3-bit LED state (led=0-7/ON=1/OFF=0). + */ void obs266_led_set(int led) { struct device *dp = NULL; struct devicelist *dlp = &alldevs; + /* + * Sarching "obsled" devices from device tree. + * Do you have something better idea? + */ for (dp = TAILQ_FIRST(dlp); dp != NULL; dp = TAILQ_NEXT(dp, dv_list)) { if (dp->dv_cfdata != NULL && strcmp(dp->dv_cfdata->cf_name, "obsled") == 0) { struct obsled_softc *sc = (struct obsled_softc *)dp; - gpio_tag_t tag = sc->sc_tag; - int bit = (led & (1 << dp->dv_unit)) >> dp->dv_unit; - (*(tag)->io_or_write)((tag)->cookie, - sc->sc_addr, (~bit & 1)); + sc->sc_led_state = + (led & (1 << dp->dv_unit)) >> dp->dv_unit; + obsled_set_state(sc); } } } |
