[comp.os.minix] How do you turn on the AT's LEDs?

ast@cs.vu.nl (Andy Tanenbaum) (01/23/88)

My tty.c doesn't turn on the keyboard LEDs on the AT because I couldn't
figure out how to do it.  If somebody knows how to control these things,
please post it, and maybe Jim can include that in the new one.  I presume
there is some I/O port with a 1 bit per LED, but I don't know which.  If
somebody has an AT Technical Reference Manual, see if you can figure it
out by looking in the BIOS.  If you call up your friendly local IBM dealer
and say "How do I turn on the LED on the Caps Lock key?" He will probably
say "Easy, just depress the Caps Lock key."  I think we are going to have
to reverse engineer this one.

Andy Tanenbaum (ast@cs.vu.nl)

rde@eagle.ukc.ac.uk (R.D.Eager) (01/25/88)

Expires:

Sender:

Followup-To:



I  believe the LEDs are controlled locally by the keyboard hardware (the
8248 or whatever it is). They are set OFF at reset, then toggled  "with"
the  keystrokes.  I don't think you can control them down the wire...but
I may be wrong.
-- 
           Bob Eager
           rde@ukc.UUCP
           ...!mcvax!ukc!rde
           Phone: +44 227 764000 ext 7589

V050KY8G@ubvms.bitnet (01/25/88)

As you probably know, the PC or AT keyboard is accessed through a couple of
ports, one of which is a "command" port.  Commands to the keyboard include:

Command name			Opcode to send to command port (hex)

reset				FF
resend				FE
NOP				FD to F7 and F2 to EF
Set Default			F6
Default Disable			F5
Enable				F4
Set Typematic Rate/Delay	F3
(this is auto-repeat)
Echo (diagnostic aid)		EE

Finally, the one you are curious about:

Set/Reset Mode Indicators	ED

Basically, the CPU is responsible for keeping track of the states of the 
lights, for you cannot query the keyboard as to what the current states 
are, but merely jam out a new set of LED settings.  This will (no doubt)
involve using the capslock and numlock variables in the tty driver where, 
if the code out of the scan code translate table is a certain code, the 
value of the variable is logically (not bit-wise) inverted.  After any one 
of these inversions take place, all (3 of them, if you wanna include scroll 
lock) values will have to be "assembled" into what IBM calls an "options  
byte" which is the "argument" to the mode LEDs command.  The options byte 
is laid out as follows:

Bit position	LED

7 to 3		(reserved)
2		Caps Lock
1		Numeric Lock
0		Scroll Lock

Handshaking is as follows:

When keyboard command port would be ready to receive a command code, send 
the EDh command
Keyboard sends 'ACK' (stops "everything" waiting for the options byte)
Send options byte (0 in bit to extinguish, 1 in bit to light up)
Keyboard sends 'ACK'

If the keyboard receives another valid command byte instead of the options 
byte, the lights remain "untouched," and that command is processed
(Set/Reset command is aborted).

I haven't looked deep enough in the docs how exacly to do the actual 
keyboard I/O, but I remeber exactly where I saw this, because I wanted to 
add this to MINIX also, but never stuck with the project long enough to get 
it done.  I figure this is enough to get someone (???) started, as long as 
this someone can fill in the details of the port addresses and so on.


As a separate matter, the problem I have been having with MINIX is the hard 
disk routines.  I am running (currently 1.1) on a SAM 3001 (AT compatible) 
with a jumper installed for 10MHz and a Segate 20Mb.  Ocasionally, without 
any warning or apparent cause, the winchester task is waiting for a reply 
from hardware, which it never gets.  I added an additional function key 
(F10) dump to the kernel and determined that this occurs when the disk 
controller's sector buffer is expecting to be serviced (data needs moving).  
Maybe this has been fixed in V1.2, maybe not.  Help?

Incidentally, I saw a message earlier about someone having problems getting 
a hard disk to work with MINIX on partition 2.  MINIX would not access any 
partitions on this system (Samsung) greater than 17 blocks big until the 
hard disk driver was modified in a coupla places in the initialization code 
(the particular mods I did were to change a coupla logical ORs ("||") to 
bit-wise ORs ("|") where the disk controller was being told about the 
number of sectors per track and so on.  This disk has 17 sectors per track, 
so therefore MINIX must have been using track 0 and 1 on any given 
cylinder, and getting errors when the disk controller didn't "think" the same 
way that MINIX "thought").

ast@cs.vu.nl (Andy Tanenbaum) (01/25/88)

In article <4240@eagle.ukc.ac.uk> rde@ukc.ac.uk (R.D.Eager) writes:
>
>I  believe the LEDs are controlled locally by the keyboard hardware (the
>8248 or whatever it is). They are set OFF at reset, then toggled  "with"
>the  keystrokes.  I don't think you can control them down the wire...

As everyone with MINIX on an AT has observed, hitting caps lock does not turn
on the LED.  Thus if they are controlled by the 8248, it is doing a very poor
job.  Maybe somebody has to initialize the 8248 to tell them to do it, but I
doubt it.  Given the level of the keyboard interface (both make and break
are reported with interrupts, and scan codes rather than ASCII characters are
returned), I'd be surprised if LED driving were handled internally in the
keyboard.  Practically nothing else is.  Thus the question remains: does
anyone know how to turn them on and off (check your BIOS listing).

Andy Tanenbaum (ast@cs.vu.nl)

BOTCHAIR%UOGUELPH.BITNET@cunyvm.cuny.edu (Alex Bewley) (01/27/88)

   The keyboard lights can definitely be set.  But only on an AT, it's data
path is two-way.  But on the XT, you can't (or so I think).  For the XT I
believe that the lights are controlled internally by the keyboard, which
explains why they are backwards sometimes after a program screws around with
some memory locations.  I'll poke around the BIOS tonight and see what I can
find.

    Alex

jcmorris@mitre-bedford.ARPA (Joseph C. Morris) (01/28/88)

In article <1836@botter.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>As everyone with MINIX on an AT has observed, hitting caps lock does not turn
>on the LED.

That depends on the flavor of your keyboard.  The replacement PC keyboards
for the pre-AT machines (translation: the machines for which IBM doesn't
provide LED's) all toggle the lights based on keystrokes in the keyboard,
and I wouldn't be surprised to find that several of the AT clones took the
same el cheapo approach.

BIOS in the true-Blue AT's includes about two pages of code listing to
turn the LED's on and off, so it's not a trivial exercise.  The actual
hardware code isn't complex; the fun comes because you have to disable the
keyboard (after ensuring that it isn't busy with some previous function),
send the necessary bit pattern, re-enable the keyboard, mess with the
interrupt controller, go out for a beer, and finally set switches to
stop the next process from doing anything to the keyboard interface until
the keyboard processor acknowledges that it has accepted your order to
change the LED display.

There's no assurance that the various clone manufacturers have implemented
anything like this design.  Since relatively few programs have a need for
messing with this interface (MINIX, for example) it probably wasn't seen 
as a real issue when the boxes were designed.

Joe Morris

jcmorris@mitre-bedford.ARPA (Joseph C. Morris) (01/28/88)

In article <1836@botter.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>As everyone with MINIX on an AT has observed, hitting caps lock does not turn
>on the LED.

(Another response to Andy's message):

This is a pseudo-code summary of the LED code in the original AT.  As
usual, no guarantees, and your mileage may vary.  (This code doesn't
exactly match the executive summary I recently posted.  It's amazing 
how much detail one can find in a program when you read it carefully...8-)=

write_led(bits):
        IF led_update_in_progress THEN EXIT
        SET led_update_in_progress
        DISMISS_INTERRUPT                       [send EOI to port 020h]
        CALL kb_send (LED_CMD)                  [LED_CMD = 007h]
        IF send_err GOTO sl2
        CALL kb_send (bits)                     [low three bits set 3 LED's]
        IF send_err GOTO sl3
sl2:    CALL kb_send (KB_ENABLE)                [KB_ENABLE = 0f4h]
sl3:    RESET led_update_in_progress
	RESET send_err
        EXIT

kb_send(byte):
sd0:    RESET kb_fa
        RESET kb_fe
sd5:    IN KB_STATUS                            [KB_STATUS = port 064h]
        IF inpt_buf_full THEN GOTO sd5          [inpt_buf_full = 002h]
        OUT PORT_A,byte                         [PORT_A = port 060h]
sd1:    IF (kb_fa or kb_fe) THEN GOTO sd3
        IF NOT 01a00_times_here THEN GOTO sd1   [approx. 10 msec]
sd2:    IF NOT 3rd_time_here THEN GOTO sd0      [retry limit]
        SET send_err
        EXIT
sd3:    IF kb_fa THEN EXIT                      [if keyboard acknowledge]
        GOTO sd2                                [must be resend order]

[part of keyboard interrupt follows:]
        ...                                     [scan code has been read
        ...                                      from keyboard]
        IF SCAN EQ kb_ack THEN                  [kb_ack =  0fah]
                {                               [keyboard acknowledge]
                SET kb_fa
                GOTO kb_exit                    [exit from keyboard interrupt]
                }
        IF SCAN EQ kb_resend THEN               [kb_resend = 0feh]
                {                               [keyboard requests resend]
                SET kb_fe
                GOTO kb_exit
                }
        ...

Hope this helps...

/Joe Morris

BOTCHAIR%UOGUELPH.BITNET@cunyvm.cuny.edu (Alex Bewley) (01/30/88)

   Wow, that's nice pseudo-code.  A cross between C, FORTRAN, Modula-2,
assembly language and who knows what else.

       Alex

pjh@root.co.uk (Paul Haffenden) (02/02/88)

I have had a big struggle with getting the leds lights on my AT based
machine. Here is the code I use. I'm running V.3 on a 386 so it may
not be exactly what you want. My biggest problem is knowing when to
send the command to the keyboard. I check the input buffer full bit
but the keyboard will lock up if I don't have the delays in.

Here it is:

Keystate is a global int that indicates the state of the control keys
like shift and control. The bottom three bits are used to specify
the led status, so by just anding them I can load it directly into
the keyboard.

#define KB	0x60
#define	KBSTATUS	0x64
#define	LEDWRITE	0xed
#define INPUTFULL	2

/* the led defines */

#define		CAPSLOCK	0x04
#define		NUMSET		0x02
#define		SCROLLSET	0x01


/*
 * set up the keyboard leds.
 */

loadled()
{
	int led;
	int x1,x2,x3;
	int s;
	int n1,n2,n3;

	s = spl7();
	
	led = keystate & 0x7;
	x1 = 0xffff;
	do
	{
		tenmicrosec();
	}
	while(((n1=inb(KBSTATUS)) & INPUTFULL) && --x1);
	tenmicrosec();	tenmicrosec();	tenmicrosec();
	outb(KB,LEDWRITE);
	x2 = 0xffff;
	do
	{
		tenmicrosec();
	}
	while(((n2=inb(KBSTATUS)) & INPUTFULL) && --x2);
	tenmicrosec();	tenmicrosec();	tenmicrosec();
	outb(KB,led);
	tenmicrosec();
	x3 = 0xffff;
	while(((n3=inb(KBSTATUS)) & INPUTFULL) && --x3)
		;
/*printf("n1 x1 0x%x 0x%x n2 x2 0x%x 0x%x n3 x3 0x%x 0x%x\n",n1,x1,n2,x2,n3,x3);*/
	splx(s);

}	

If someone knows the correct way to do it without the finger in the air
delays please post it.

Paul.