Source to enhanced Everex front-panel driver

Steve Friedl friedl at bang.UUCP
Sat Sep 30 07:37:26 AEST 1989


Hi folks,

     Some time ago Dave Carlson from Micropen posted a
quick+dirty driver for the front-panel LED display on the Everex
STEP 386 family, and at the time I was working on my own.  Mine
is a lot more flexible, as it gives access to the panel to the
user (via /dev/led), and I've been using it for months.

     I always run a program in the background that updates
the time constantly in HH:MM:SS format, and in general I like
it a lot.  I suspect that you could use this for feedback from
some noninteractive program, and kernel debugging might be
another good use for it.

     I wrote this on the Everex STEP 386/25 running AT&T System V
Release 3.2, but you get to figure out how to make it work
elsewhere.  This is my first driver, so comments and feedback
(flames too) are welcome.

     This code is in the public domain and can be used for
anything by anybody.

     Steve


#----------------------------- cut here -------------------------

# to unbundle, sh this file
echo Makefile 1>&2
cat >Makefile <<'End of Makefile'
CFLAGS	= -O -DAT386 -DINKERNEL -DiAPX386

led.o: led.c

Driver.o: led.o
	ld -r -o $@ led.o

install:	Driver.o
	/etc/conf/bin/idinstall -k -a led ; touch $@

uninstall:	Driver.o
	/etc/conf/bin/idinstall -k -d led ; touch $@

update:		Driver.o
	/etc/conf/bin/idinstall -k -u led ; touch $@

build : update
	/etc/conf/bin/idbuild ; touch $@

ledtime : ledtime.c
	${CC} -o $@ -O ledtime.c
End of Makefile
echo Master 1>&2
cat >Master <<'End of Master'
led	Iw	ico		led	0	0	1	1	-1
End of Master
echo Node 1>&2
cat >Node <<'End of Node'
led	led	c	0
End of Node
echo System 1>&2
cat >System <<'End of System'
led	Y	1	0	0	0	0	0	0	0
End of System
echo led.c 1>&2
cat >led.c <<'End of led.c'
/*
 * led.c
 *
 * Written by:	Stephen J. Friedl
 *		V-Systems, Inc.
 *		friedl at vsi.com
 *		29 July, 1989
 *
 *	This is a driver for the front-panel LEDs on an Everex
 *	STEP system.  This is an eight-character display, and is
 *	normally driven by the BIOS to show the current drive,
 *	cylinder, and head being accessed.  UNIX bypasses the BIOS
 *	entirely, so it freezes shortly after bootup.
 *
 *	This is a _really_simple_ driver with two parts.  First,
 *	you can make the thing display some cute signon message
 *	when the machine boots, and then later change it with
 *	a normal write(2) system call.  See the docs on the
 *	"ledwrite()" function below for restrictions.
 *
 *	This driver has been tested on an Everex STEP/25 running
 *	real AT&T System V Release 3.2.  Information about the
 *	usage of the 8042 UPI has been derived from the Everex
 *	STEP 386 Hardware Service and Maintenance Guide, part
 *	number KIT 00076-00 (about a hundred bucks from your
 *	Authorized Everex dealer).
 *
 *	========================================================
 *	In the spirit of free interchange of { hopefully } high-
 *	quality software, this driver is released to the public
 *	domain and can be used for any purposes at all, including
 *	personal, commercial, military, blackmail, etc.
 *
 *	Have fun, folks.
 *	========================================================
 */
#include	<sys/types.h>
#include	<sys/signal.h>
#include	<sys/dir.h>
#include	<sys/param.h>
#include	<sys/errno.h>
#include	<sys/user.h>
#include	<sys/inline.h>

/*----------------------------------------------------------------------
 * Stuff for ANSI C (someday).
 */
#ifndef	__STDC__
#  define	const		/*nothing*/
#endif

#define		LED_WIDTH	8

/*----------------------------------------------------------------------
 * Everex 8042 UPI controller chip port defines
 */
#define 	DATA		0x60
#define 	COMMAND		0x64
#define 	STATUS		0x64

#define 	BUSY		0x02

#define		WAITBUSY()	while (inb(STATUS)&BUSY)

/*----------------------------------------------------------------------
 * program_leds()
 *
 *	Given a NUL-terminated string, program the LEDs to display
 *	this value.  Up to {LED_WIDTH} characters are displayed, and
 *	spaces are added at the end for padding.  No examination of
 *	the characters to be displayed is done.  Note that a newline
 *	appears as an ugly character and is probably not what you
 *	want.
 *
 *	===NOTE=== this routine demands that the address provided
 *	be valid.  Be careful.
 *
 *	If you want to use this routine for kernel debugging -- we
 *	have not done this -- you will have to remove the "static"
 *	storage class specifier below.
 */
static void
program_leds(str)
char const	*str;
{
int	n;

	intr_disable();			/* this looks like a copout...	*/

	WAITBUSY();			/* wait for 8042 to be unbusy	*/

	outb(COMMAND, 0xb0);		/* initialize display		*/

	/*--------------------------------------------------------------
	 * now, for up to eight characters, update the display.  We stick
	 * on spaces at the end if the user-provided string is shorter.
	 * Newlines look funny so we really should trap them out, but
	 * it won't be so bad to make the user strip it out on his/her own.
	 */
	for (n = 0; n < LED_WIDTH; n++)
	{
		WAITBUSY();
		outb(DATA, *str ? *str++ : ' ');
	}

	intr_restore();
}

/*----------------------------------------------------------------------
 * ledinit()
 *
 *	This is called by the kernel early in the boot sequence, and we
 *	simply display some more reasonable message here instead of the
 *	last cylinder accessed by the BIOS.  This can be whatever you like,
 *	and it is automatically truncated to proper width.
 *
 *	Be creative!
 */
void
ledinit()
{
	program_leds("386 UNIX");
}

/*----------------------------------------------------------------------
 * ledwrite()
 *
 *	Do the actual write to the display.  Note that each write(2)
 *	call is treated separately, and the message to be displayed
 *	must all be written at once (i.e., character-at-a-time writes
 *	won't do what's intended).  If you don't like this, we can
 *	always change the driver to require ioctls() for character
 *	output and *really* make it inconvenient...
 */
/*ARGSUSED*/
void
ledwrite(dev)
int	dev;
{
char		ledbuf[LED_WIDTH+1];	/* buffer for the message	*/
unsigned int	count;			/* # of chars to write		*/

	/*--------------------------------------------------------------
	 * We can only write a few characters, so just limit the
	 * length here.
	 */
	count = (u.u_count > LED_WIDTH) ? LED_WIDTH : u.u_count;

	/*--------------------------------------------------------------
	 * grab the characters from the user space and return a fault
	 * error on a bad address.
	 */
	if (copyin(u.u_base, ledbuf, count) == -1)
		u.u_error = EFAULT;
	else
	{
		ledbuf[count] = '\0';	/* NUL-terminated, remember?	*/
		program_leds(ledbuf);	/* do it!			*/
	}
}
End of led.c
echo ledtime.c 1>&2
cat >ledtime.c <<'End of ledtime.c'
/*
 * ledtime()
 *
 * written by:	Stephen J. Friedl
 *		V-Systems, Inc.
 *		+1 714 545 6442
 *		friedl at vsi.com
 *
 *	This program sits in the background and writes the current
 *	time to stdout.  It is meant to be directed at /dev/led
 *	so the Everex front-panel display always shows the time.
 *	It should be run out of /etc/rc2.d (I use S12ledtime) and
 *	looks like:
 *
 *		/usr/local/bin/ledtime > /dev/led &
 *
 *	This is in the public domain (not that you couldn't figure
 *	this out in about two minutes anyway).
 */
#include	<stdio.h>
#include	<sys/types.h>
#include	<time.h>

main()
{
	while (1)
	{
	struct tm	*tm;
	time_t		now;		/* current UNIX time		*/
	int		len;		/* length of the time buffer	*/
	char		buf[40];	/* buffer for the time string	*/

		(void)time(&now);
		tm = localtime(&now);
		len = sprintf(buf, "%02d:%02d:%02d\n",
		  tm->tm_hour, tm->tm_min, tm->tm_sec);
		(void)write(fileno(stdout), buf, len);
		(void)sleep(1);
	}
	/*NOTREACHED*/
}
End of ledtime.c

#----------------------------- cut here -------------------------

-- 
Stephen J. Friedl  /  Software Consultant  /  Tustin, CA  /  + 714 544 6561
3B2-kind-of-guy    /  {attmail uunet}!vsi!{bang!}friedl   /  friedl at vsi.com

"C is a disease." - Philippe Kahn, head honcho of Borland



More information about the Comp.unix.i386 mailing list