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.