[comp.sys.nsc.32k] Need help with following hack.

jkh@meepmeep.pcs.com (Jordan K. Hubbard) (03/19/91)

I've sat looking at my PC532 for the last 2 weeks with this nagging
feeling in the back of my brain that something wasn't quite right.
Something... Missing.

"Hmmmmm" I said. "Something's missing.. Could it be long filenames?"
I added long file names. "Could it be the pi calculator?" I added pi.
"Perhaps some GNU tool is missing.." I added all the GNU utils.
Damn. Still not right..

Then last night it hit me. "Aha! (ouch!)" said I. "I can't blink the
friggin' lights!! How are we expected to use a machine where the
lights don't even blink?!? I mean.. I mean.. Gawwwwd!"

To make your lights blink under software control and bring world
peace in your lifetime, do the following:

Add the following as "lib/other/setled.c":

---- cut ----
#include <lib.h>

/*
 * Why did I put this under FS? Well.. LEDS are I/O, sort of.
 */
PUBLIC int setleds(mask)
unsigned char mask;
{
  return(callm1(FS, SETLEDS, mask, 0, 0, 0, NIL_PTR, NIL_PTR));
}
---- cut ----

And add the following as "kernel-1.3/leds.c":

---- cut ----
#include "kernel.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/mmu.h>

/*
 * This code sets a specific LED to on or off. Jordan K. Hubbard, 15mar91.
 * Idea & code mostly borrowed from Bruce's monitor, with some parts
 * written in C instead of assembly for no particular reason.
 */

#define SCSI_ADR	0x30000000              /* SCSI address */
#define ICU_ADR		0xfffffe00		/* ICU address */
#define ICU_IO		(ICU_ADR+20)
#define ICU_DIR		(ICU_ADR+21)
#define ICU_DATA	(ICU_ADR+19)
#define ICU_SCSI_BIT	0x80

#define RD_ADR(adr)	(*((volatile unsigned char *)(adr)))
#define WR_ADR(adr,val)	(*((volatile unsigned char *)(adr))=(val))

/*
 * DANGER Will Robinson - this code will break you badly if
 * you so much as think of using the AIC6250 for I/O since it
 * assumes that the DP8490 is what's selected most of the
 * time. Actually, this code is going to break anyway the moment we get
 * the first bus peripherals working, regardless of which SCSI controller
 * is being used for Disk I/O. Perhaps things will be a little more
 * pessimistic then anyway and everyone will be expected to always assume
 * that the controller they're interested in always needs to be selected
 * first. That would simplify things here.
 */
PUBLIC void do_set_leds(mask)
unsigned char mask;
{
	/* First, select the AIC6250 SCSI controller */
	RD_ADR (ICU_IO) &= ~ICU_SCSI_BIT;	/* i/o, not port	*/
	RD_ADR (ICU_DIR) &= ~ICU_SCSI_BIT;	/* output		*/
	RD_ADR (ICU_DATA) |= ICU_SCSI_BIT;	/* select AIC6250	*/

	/* Now set the state of the LEDs according to mask */
	/* Don't know if we need to set clock every time, but why not	*/
	WR_ADR(SCSI_ADR,	0x8);		/* select register 8	*/
	WR_ADR(SCSI_ADR+1,	0x4);		/* no reset, 20Mhz clk	*/
	WR_ADR(SCSI_ADR,	0x7);		/* select register 7	*/
	WR_ADR(SCSI_ADR+1,	0x10);		/* output to port A	*/
	WR_ADR(SCSI_ADR,	0xd);		/* select register D	*/
	WR_ADR(SCSI_ADR+1,	mask);		/* set LED status	*/

	/* Now reselect the DP8490 controller so that I/O works again */
	RD_ADR (ICU_IO) &= ~ICU_SCSI_BIT;	/* i/o, not port	*/
	RD_ADR (ICU_DIR) &= ~ICU_SCSI_BIT;	/* output		*/
	RD_ADR (ICU_DATA) &= ICU_SCSI_BIT;	/* select DP8490	*/
}
---- cut ----

Now, finally, insert the following into fs/misc.c someplace:

---- cut ----
/*===========================================================================*
 *                              do_setleds                                   *
 *===========================================================================*/PUBLIC int do_setleds()
{
	/*
	 * I'm too lazy to add another name to param.h so I just use
	 * the message field directly.
	 */
	do_set_leds((unsigned char)m.m1_i1);
}
---- cut ----

Now all that remains to be done is for you to select a message number
for the new setleds() call. I used 45, though you can use whatever
you prefer (as long as it fits within the range of NCALLS, of course).
Once you've decided, add a new define called SETLEDS for it in
include/minix/callnr.h and add the appropriate table entry in fs/table.c
as well.

Recompile your kernel and lib, reboot, then compile and run this small
program:

/* Silly program to count in binary on your lights */
main()
{
	unsigned char c;
	volatile int i;

	for (c = 0; c < 256; c++) {
		setleds(c);
		for (i = 0; i < 50000; i++)
			;	/* delay */
	}
}


There! Your life is now complete.

Now the subject line did say "help wanted" and there is, in fact, a
fly in this here ointment. In order to set the LEDS, we need to talk
to the AIC6250 controller. At the same time, the kernel is servicing
interrupts and stuff and occasionally some of these like to invoke
things that write to the disk, which requires the DP8490 to be
selected.  As long as setleds() is called from user mode, this happens
just fine and everybody is happy. However, the fun of watching the
lights pong back and forth soon pales and one starts to think of an
actual practical use (what!? sacrilege!) for such things.

  The first thing that came to my twisted mind was an idle indicator;
e.g, the slower the lights blink, the more your system is doing.
Problem is, the only place to really stick such an idle indicator is
in idle.c since the scheduler doesn't implement true priorities and
there's no way to have a process "niced" into the background. This is
where the problem with the selected controller rears its ugly head.
Putting a call to do_set_leds() [going direct to the kernel routine
since we ARE the kernel here] in idle.c will cause the LEDS to flash
very nicely for awhile and then the system crashes on disk I/O errors.

 I must confess that I don't really understand everything that's going
on with the controller arbitration here. Do the kernel service routines
expect to select the DP8490 controller ONCE and have it stay selected
once and forever after? Do I need to somehow lock something out before
switching controllers? I tried disabling interrupts during the switch,
but that had very nasty side-effects.

Please oh gurus, enlighted this poor confused purveyor of useless
diversions.

					Jordan