#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vrled.c,v 1.9 2012/10/27 17:17:56 chs Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/reboot.h>
#include <machine/bus.h>
#include <machine/config_hook.h>
#include <hpcmips/vr/vripif.h>
#include <hpcmips/vr/vrledvar.h>
#include <hpcmips/vr/vrledreg.h>
#ifdef VRLEDDEBUG
#ifndef VRLEDDEBUG_CONF
#define VRLEDDEBUG_CONF 0
#endif
int vrleddebug = VRLEDDEBUG_CONF;
#define DPRINTF(arg) if (vrleddebug) printf arg;
#define VPRINTF(arg) if (bootverbose||vrleddebug) printf arg;
#else
#define DPRINTF(arg)
#define VPRINTF(arg) if (bootverbose) printf arg;
#endif
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");
vrled_write(sc, LEDINT_REG_W, LEDINT_ALL);
sc->sc_state_cnt = 1;
vrled_write(sc, LEDASTC_REG_W, 1);
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;
}
int
vrled_intr(void *arg)
{
struct vrled_softc *sc = arg;
unsigned int intstat;
intstat = vrled_read(sc, LEDINT_REG_W);
vrled_write(sc, LEDINT_REG_W, intstat);
if (intstat&LEDINT_AUTOSTOP) {
vrled_change_state(sc);
}
return (0);
}
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);
vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP);
sc->sc_state = LEDOFF;
sc->sc_next = LEDOFF;
}
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);
vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP|LEDCNT_BLINK);
sc->sc_state = LEDON;
sc->sc_next = LEDON;
}
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);
vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP);
vrled_write(sc, LEDCNT_REG_W, LEDCNT_AUTOSTOP|LEDCNT_BLINK);
sc->sc_state = sc->sc_next;
}
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);
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;
}
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;
}
}
void
vrled_set_state(struct vrled_softc *sc, vrled_status state)
{
int ledstate;
ledstate = vrled_read(sc, LEDCNT_REG_W);
if (ledstate&LEDCNT_BLINK) {
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);
}
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);
}