/* $NetBSD: vrled.c,v 1.9 2012/10/27 17:17:56 chs Exp $ */ /* * Copyright (c) 2000 SATO Kazumi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: vrled.c,v 1.9 2012/10/27 17:17:56 chs Exp $"); #include #include #include #include #include #include #include #include #include #ifdef VRLEDDEBUG #ifndef VRLEDDEBUG_CONF #define VRLEDDEBUG_CONF 0 #endif /* VRLEDDEBUG_CONF */ int vrleddebug = VRLEDDEBUG_CONF; #define DPRINTF(arg) if (vrleddebug) printf arg; #define VPRINTF(arg) if (bootverbose||vrleddebug) printf arg; #else /* VRLEDDEBUG */ #define DPRINTF(arg) #define VPRINTF(arg) if (bootverbose) printf arg; #endif /* VRLEDDEBUG */ static int vrledmatch(device_t, cfdata_t, void *); static void vrledattach(device_t, device_t, void *); static void vrled_write(struct vrled_softc *, int, unsigned short); static unsigned short vrled_read(struct vrled_softc *, int); static void vrled_stop(struct vrled_softc *); static void vrled_on(struct vrled_softc *); static void vrled_blink(struct vrled_softc *); static void vrled_flash(struct vrled_softc *); static void vrled_change_state(struct vrled_softc *); static int vrled_event(void *, int, long, void *); int vrled_intr(void *); CFATTACH_DECL_NEW(vrled, sizeof(struct vrled_softc), vrledmatch, vrledattach, NULL, NULL); struct vrled_softc *this_led; static inline void vrled_write(struct vrled_softc *sc, int port, unsigned short val) { bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); } static inline unsigned short vrled_read(struct vrled_softc *sc, int port) { return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port)); } static int vrledmatch(device_t parent, cfdata_t cf, void *aux) { return (1); } static void vrledattach(device_t parent, device_t self, void *aux) { struct vrled_softc *sc = device_private(self); struct vrip_attach_args *va = aux; bus_space_tag_t iot = va->va_iot; bus_space_handle_t ioh; if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) { printf(": can't map bus space\n"); return; } sc->sc_iot = iot; sc->sc_ioh = ioh; if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit, 0, IPL_TTY, vrled_intr, sc))) { printf (": can't map interrupt line.\n"); return; } printf("\n"); /* clear interrupt status */ vrled_write(sc, LEDINT_REG_W, LEDINT_ALL); /* basic setup */ sc->sc_state_cnt = 1; vrled_write(sc, LEDASTC_REG_W, 1); /* 1time */ vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP); vrled_stop(sc); sc->sc_hook = config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_LED, CONFIG_HOOK_SHARE, vrled_event, sc); this_led = sc; } /* * LED interrupt handler. * */ int vrled_intr(void *arg) { struct vrled_softc *sc = arg; unsigned int intstat; intstat = vrled_read(sc, LEDINT_REG_W); /* clear interrupt status */ vrled_write(sc, LEDINT_REG_W, intstat); if (intstat&LEDINT_AUTOSTOP) { vrled_change_state(sc); } return (0); } /* * LED turn OFF * */ void vrled_stop(struct vrled_softc *sc) { vrled_write(sc, LEDHTS_REG_W, LEDHTS_DIV16SEC); vrled_write(sc, LEDLTS_REG_W, LEDLTS_4SEC); vrled_write(sc, LEDASTC_REG_W, 2); /* 2time */ vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP); sc->sc_state = LEDOFF; sc->sc_next = LEDOFF; } /* * LED turn ON * */ void vrled_on(struct vrled_softc *sc) { vrled_write(sc, LEDHTS_REG_W, LEDHTS_SEC); vrled_write(sc, LEDLTS_REG_W, LEDLTS_DIV16SEC); vrled_write(sc, LEDASTC_REG_W, 2); /* 2time */ vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP|LEDCNT_BLINK); sc->sc_state = LEDON; sc->sc_next = LEDON; } /* * LED blink * */ void vrled_blink(struct vrled_softc *sc) { int ledhts; int ledlts; switch (sc->sc_next) { case LED1SB: ledhts = LEDHTS_DIV2SEC; ledlts = LEDLTS_DIV2SEC; break; case LED2SB: ledhts = LEDHTS_SEC; ledlts = LEDLTS_SEC; break; default: vrled_stop(sc); return; } vrled_write(sc, LEDHTS_REG_W, ledhts); vrled_write(sc, LEDLTS_REG_W, ledlts); vrled_write(sc, LEDASTC_REG_W, 2); /* 2time */ vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP); vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP|LEDCNT_BLINK); sc->sc_state = sc->sc_next; } /* * LED flash once * */ void vrled_flash(struct vrled_softc *sc) { int ledhts; int ledlts; switch (sc->sc_next) { case LED8DIVF: ledhts = LEDHTS_DIV16SEC; ledlts = LEDLTS_DIV16SEC; break; case LED4DIVF: ledhts = LEDHTS_DIV8SEC; ledlts = LEDLTS_DIV8SEC; break; case LED2DIVF: ledhts = LEDHTS_DIV4SEC; ledlts = LEDLTS_DIV4SEC; break; case LED1SF: ledhts = LEDHTS_DIV2SEC; ledlts = LEDLTS_DIV2SEC; break; default: vrled_stop(sc); return; } vrled_write(sc, LEDHTS_REG_W, ledhts); vrled_write(sc, LEDLTS_REG_W, ledlts); vrled_write(sc, LEDASTC_REG_W, 2); /* 2time */ vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP|LEDCNT_BLINK); sc->sc_state = sc->sc_next; sc->sc_next = LEDOFF; sc->sc_state_cnt = 1; } /* * Change LED state * */ void vrled_change_state(struct vrled_softc *sc) { switch (sc->sc_next) { case LEDOFF: vrled_stop(sc); break; case LEDON: vrled_on(sc); break; case LED1SB: case LED2SB: vrled_blink(sc); break; case LED8DIVF: case LED4DIVF: case LED2DIVF: case LED1SF: vrled_flash(sc); break; default: vrled_stop(sc); break; } } /* * Set LED state * */ void vrled_set_state(struct vrled_softc *sc, vrled_status state) { int ledstate; ledstate = vrled_read(sc, LEDCNT_REG_W); if (ledstate&LEDCNT_BLINK) { /* currently processing */ if (sc->sc_next == state) sc->sc_state_cnt++; switch (sc->sc_next) { case LEDOFF: case LEDON: sc->sc_next = state; break; case LED8DIVF: case LED4DIVF: case LED2DIVF: case LED1SF: switch (state) { case LEDOFF: case LED8DIVF: case LED4DIVF: case LED2DIVF: case LED1SF: sc->sc_next = state; break; default: break; } break; case LED1SB: case LED2SB: switch (state) { case LEDOFF: case LEDON: case LED1SB: case LED2SB: sc->sc_next = state; break; default: break; } break; default: sc->sc_next = LEDOFF; break; } return; } sc->sc_next = state; vrled_change_state(sc); } /* * LED config hook events * */ int vrled_event(void *ctx, int type, long id, void *msg) { struct vrled_softc *sc = (struct vrled_softc *)ctx; int why =*(int *)msg; if (type != CONFIG_HOOK_SET || id != CONFIG_HOOK_LED) return (1); if (msg == NULL) return (1); switch (why) { case CONFIG_HOOK_LED_OFF: vrled_set_state(sc, LEDOFF); break; case CONFIG_HOOK_LED_ON: vrled_set_state(sc, LEDON); break; case CONFIG_HOOK_LED_FLASH: vrled_set_state(sc, LED8DIVF); break; case CONFIG_HOOK_LED_FLASH2: vrled_set_state(sc, LED4DIVF); break; case CONFIG_HOOK_LED_FLASH5: vrled_set_state(sc, LED2DIVF); break; case CONFIG_HOOK_LED_BLINK: vrled_set_state(sc, LED1SB); break; case CONFIG_HOOK_LED_BLINK2: vrled_set_state(sc, LED2SB); break; default: vrled_set_state(sc, LEDOFF); } return (0); } /* end */