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);
}