398 lines
8.5 KiB
C
398 lines
8.5 KiB
C
/* $NetBSD: vrled.c,v 1.7 2003/07/15 02:29:36 lukem 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 <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: vrled.c,v 1.7 2003/07/15 02:29:36 lukem 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 /* 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(struct device *, struct cfdata *, void *);
|
|
static void vrledattach(struct device *, struct device *, 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(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(struct device *parent, struct cfdata *cf, void *aux)
|
|
{
|
|
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
vrledattach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct vrled_softc *sc = (struct vrled_softc *)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 */
|