Subject: Re: diagnostic leds on CPU board
To: None <mouse@Holo.Rodents.Montreal.QC.CA>
From: Chuck Cranor <chuck@dworkin.wustl.edu>
List: port-sparc
Date: 01/21/1997 11:09:05
>I don't know anything about the LEDs on the back of the VME-based SPARC
>machines.
It is very easy to control the LEDs on the sun4 sparc. There is a
control register at address 0x70000000 of the ASI_CONTROL space. This
write-only register can be accessed with stba(). Note that the bits
are inverted.
When I was trying to teach someone how to write a device driver I used
the led devices as an example [based on something Ron Minnich wrote while
at SRC]. I'll include that sample driver below.
chuck
/*
* simple sun4 led driver.
*/
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/fcntl.h>
#include <sys/device.h>
#include <sys/ioccom.h>
#include <sys/errno.h>
#include <sparc/sparc/asm.h>
#include <machine/ctlreg.h>
/*
* hardware interface:
*/
#define DIAGREG 0x70000000
#define setled(val) stba(DIAGREG, ASI_CONTROL, ~ (val))
/*
* ioctl interface:
*/
#define LEDGET _IOR('l',1,int)
#define LEDALT _IOW('l',2,int)
/*
* global variable usrled.
* if (usrled > 0)
* then a program has /dev/led open and has control of the LEDs
* else
* /dev/led is not open and the kernel can control the LEDs
*
* [e.g. could be used by locore to frob the LEDs sunos style when
* they are not in use]
*/
int usrled;
/*
* config glue:
*/
int ledmatch __P((struct device *, void *, void *));
void ledattach __P((struct device *, struct device *, void *));
struct ledsoftc {
struct device dev; /* required. must be first in softc */
int value; /* software copy of diagreg. note that the
hardware register is WRITE-ONLY, so if we want
a process to be able to read the led value we
must keep a software copy. */
};
struct cfdriver ledcd = {
NULL, "led", ledmatch, ledattach, DV_DULL, sizeof(struct ledsoftc)
};
int
ledmatch (parent, vcf, args)
struct device *parent;
void *vcf, *args;
{
if (cputyp == CPU_SUN4) {
return(1); /* sun4 only, and they all have it */
} else {
return(0);
}
}
void
ledattach(parent, self, args)
struct device *parent, *self;
void *args;
{
struct ledsoftc *dv;
/* init device and softc */
dv = (struct ledsoftc *) self;
dv->value = 0x0;
setled(0x0);
printf("\n");
}
ledopen (dev, oflags, devtype, p)
dev_t dev;
int oflags, devtype;
struct prop *p;
{
int unit = minor(dev);
if (unit >= ledcd.cd_ndevs || ledcd.cd_devs[unit] == NULL)
return (ENXIO);
usrled++;
return(0);
}
ledclose(dev, fflag, devtype, p)
dev_t dev;
int fflag, devtype;
struct prop *p;
{
usrled--;
return(0);
}
int
ledioctl(dev, cmd, data, flags, p)
dev_t dev;
u_long cmd;
register caddr_t data;
int flags;
struct proc *p;
{
int *val = (int *)data;
register struct ledsoftc *sc = ledcd.cd_devs[minor(dev)];
if (sc == NULL) return(ENXIO);
switch (cmd) {
case LEDALT: /* set LEDs */
setled(*val);
sc->value = *val;
break;
case LEDGET: /* get LED current value */
*val = sc->value;
break;
default:
return(ENOTTY);
}
return(0);
}