Ever since I stopped using a Sun SparcStation as desktop (around 94 or so) I wanted a decent Type 4 or 5 on my pc - alas, the Type 4/5 are serial keyboards and hence not directly supported by normal pcs.

 Sun Type 5c goodness

Getting the Type 5 to work under Linux wouldn't have been too hard (it's serial after all), but that isn't good enough: I wanted a decent solution that also work for BIOS interaction and in Windows (and even the Linux-only solution would have required soldering up a TTL inverter). So why not build a converter?

Being lazy until recently I compromised (sort-of) by using an IBM Model M: my Model M was made in 84, weighs a ton and a half, and works beautifully...but it's very very noisy (a consequence of the buckling spring mechanism) and that finally got on my nerves. About eight or nine years ago I saw this Sun to PS/2 converter project, which unfortunately is rather complex to build and uses very obsolete hardware to pull it off...too much of a hassle. And the few commercial converters that I could find were ridiculously expensive. So finally I built my own converter which needs only two active and one passive component: one PIC16F628a microprocessor to do the heavy lifting, one 7404 TTL inverter and one capacitor. Together with a bit of prototyping board, a PS/2 cable with plug and a female minidin-8 socket I estimate the total cost to be no higher than AUD15. Mine actually cost less: I bought some 16F628s in bulk some time ago, the 7404 was an ancient left-over (markings indicate it was made in the 80s...), the PS/2 cable and plug came from a dead donor keyboard and the minidin-8 socket I recycled out of a dead Sun. And what about the software? That's my contribution. (Open Source, of course.)

More recently, after having decided to build my own PS/2-based converter I found out that Marijn Kentie has created a PIC-based one that does Sun-Type-4/5-to-USB, with a PIC18F. silly hat on But his is written in C and therefore less cool than my handcrafted PIC assembler code. silly hat off

Preliminaries: Sun

The Type 4 and 5 Sun keyboards are very simple beasts explained nicely in the SPARC Keyboard Specs: they communicate with the host using RS-232 at 1200 bps, 8N1 - but with inverted TTL logic levels (0V = 1, 5V = 0). +5V power is provided together with the signal. All keys have a one-byte code that is sent on "make" (key pressed) and code+0x80 is sent on "break" (key release). No typematic repeat, that is handled by the host. The keyboard has a few more keys than normal pc keyboards, and one more LED, on the compose key. The keyboard also has only a few trivially simple commands (reset, led setting, beeper on/off and click on/off). The pinout of the minidin-8 connector is straightforward. And that's all there is to it. Neat, simple, efficient. Dealing with this stuff on a PIC is easy, especially when you use one with USART built-in, like the 16F628 - the only necessary extra is a 7404 inverter to translate the signal levels.

Preliminaries: PS/2

The electrical PS/2 protocol is ugly, to put it politely. The PS/2 keyboard protocol is fucking horrible, and that's still putting it politely! The electrical part is described very well by Adam Chapweske over there, but his treatise lacks precise timing information - that I found in this application note. It's a two-wire bidirectional protocol, with a "master" (the host) that isn't mastering anything but the art of interrupting progress at any time it feels like it: the only thing the master ever does is tell the slave to stop whatever it's doing or to start clocking. With PS/2 it's the slave that outputs the clock pulses. Device-to-host transmissions work different from host-to-device, adding to the fun for an implementor. At least all transmissions are done in bytes. Some of the borderline cases I didn't find any precise information on (e.g. the timing sequence of the host-to-device clocking request; the best I could find is 'host pulls clock low, then pulls data low, then releases clock'), but there seems to be a lot of leeway in the spec (e.g. pulse length can be anything between 25us and 50us). And the electrical part is easy, compared to the backwards-compatible mess that the PS/2 keyboard protocol is: most of the crappy stuff dates back to 84-key PC/XT keyboards and contains lots of really lousy design decisions made by IBM.

IBM: It may be slow, but it's hard to use. -- Simon Cozens

The best explanation/material collection for the scan codes I found to be the one collected by John Savard. In as few words as possible: keys send make and break codes ("scan codes" in PS/2 parlance), just like the Sun does - but the codes follow no useful scheme whatsoever and differ in size: anywhere from 1 to 8 bytes. One key sends no break code at all, and in theory there's three different set of codes for any single key (fortunately only Set 2 is required nowadays). And to make all this even more fun, the typematic repeat must be handled by the device, there's multiple repeat/delay rates as well, and there's a bunch of generally superfluous commands that a keyboard should understand as well. Lots of joy! My students got a really good laugh out of it when I told them last week that I write code in assembler for fun (and indeed, the PS/2 part of this project was "lots" of fun, for masochistic values of lots).

My Converter

The PIC deals with the Sun using its built-in USART, with the 7404 inverter sitting inbetween. The PS/2 side is done "manually", bit-banging two ports of the PIC whose internal pullup resistors are enabled. The mechanical layout of my converter is trivial: a small piece of prototyping board holds two sockets for the PIC and the 7404, and one 22uF electrolytic capacitor sits near the PIC. One end of the board holds a female minidin-8 socket for the Sun keyboard plug, and the PS/2 cable was soldered in at the other end. Power comes from the PS/2 connector, and powers everything: the PIC, the 7404 and the Sun keyboard. Here is my prototype (with extra in-circuit programming sockets):

 sunkbd converter top sunkbd converter solderside

The electrical setup is about as trivial, and shown on this schema.

sunkbd

I've even cooked up a small PCB design (untested, though). These PNGs are 300dpi and if you use this for a toner transfer you'll have to mirror the silk side but not the solder side.

 top side, unmirrored solder side, ALSO UNMIRRORED!

Limitations

  • My converter presents a somewhat dumb keyboard to the host: any and all PS/2 commands are acknowledged (in best "yes, minister!" tradition) - and most are then completely ignored. Implemented are: Reset, Get ID and Set LEDs. The keyboard also doesn't request resends from the host, nor does it act upon the hosts' resend requests - I haven't seen any need for those in practice.

    Apparently all modern keyboard controllers (8042-clones embedded in the SuperIO chips) don't care about the extra commands and don't even pass them on to the keyboards.

  • The repeat rate is fixed at 250ms initial delay, then 30 keys per second.

  • The Compose LED on the Sun keyboard isn't known to PS/2, and the converter arbitarily associates it with bit 3 of the Set LEDs argument (bits 0 to 2 are num, caps and scroll lock). If you can convince your OS/hardware to pass the extra bit then your compose LED will be controllable; otherwise it'll stay off.

  • The keyboard's buzzer or the key click functions are not accessible via PS/2, so those are off.

  • The handling of the Print Screen key is simplified: while the standards say that it should be wrapped in the scancodes for shift (plus an extra annoyance byte), the converter doesn't do that. Neither does it create the sysreq scan code with alt held down.

I have found that all OS's I tried (linux and win) work fine with that - it looks like the keyboard controller fixes up the scancode as required.

  • Similarly, the numlock handling is simplified: According to this MS keyboard scan code specification, a keyboard should remember all modifiers held down while numlock is in use and modify the scancodes sent accordingly. This is a ridiculously crappy setup (what do we have the damn make/break codes for, except for the host to figure out which keys are currently down?) and it's also not necessary in practice.

  • The extra keys on the Sun keyboard were mapped to the nearest equivalents I could find in various sources.

The power key is mapped to ACPI Power, the brightness/volume and mute keys are mapped to the Windows Multimedia Keyboard scancodes and so is the Stop key.

The left and right Meta keys (Diamond on the Sun keyboard) are mapped to Left and Right Window key, respectively. The Compose key is mapped to the Windows Menu key.

For the non-obvious ones (Help, Undo/Again, Copy/Paste/Cut, Props, Front, Open, Find) I used scan codes from Savard's list.

On Unix systems the mapping of these is trivial (Linux: setkeycodes for a few, then Xmodmap to make them available under X). on Windows systems you'll have to use a remapper tool or frob the registry by hand. I've tried SharpKeys which works fine for the remapping, and Hoekeys for attaching actions to keys.

Code! Code! Code!

The code is as simple and robust as I could make it, and pretty well documented - I think. The keycode to scancode translation is done with two tables, one 128 byte one (for the one-byte scancodes) and one 27 byte one (for the two byte scancodes). The Pause key is handled separately. As the 16F628 has only 128 byte of EEPROM the two tables are done using the trusty old computed-goto method. Sun input is handled via an interrupt handler which pushes key codes into a small (8 byte) inbound fifo. The main loop monitors the PS/2 bus for activity (remember, the PIC has to clock for the host on request) and otherwise processes key codes from the input fifo: it translates them into scan codes and pushes those into an output fifo (16 bytes deep). The main loop also empties that fifo by sending out pending scancodes whenever the PS/2 bus allows it, and furthermore deals with the few PS/2 commands that are implemented. Sending to the Sun keyboard is done via the USART, and due to the PIC hardware that's a fire-and-forget operation (for up to two sequential bytes). Another part of the interrupt handler deals with timeouts: a timer is armed whenever a make code is processed (and disarmed on break) and when the timer expires the interrupt handler inserts another copy of the held-down key code into the inbound fifo and rearms the timer (initial 250ms, then 33ms). And that's about it.

For those of you who like to tinker with the source: go for it! It is, as usual, GPL-licensed and as such freely available for your use. Here is the list of files:

  • the main program code: sunkbd.asm
  • the fifo helper routines: fifo.inc
  • some delay helper routines: delay.inc
  • and for convenience here's the compiled code, ready for your PIC: sunkbd.hex

Enjoy!

Update (Mon 21.02.2011 16:34):

Steve Powers noticed that I swapped the +5 and Gnd lines on the PCB design, and I've updated the images to correct that.

Update (Fri 21.09.2012 05:38):
I just heard from Ed Robbins that he built my design successfully and that it also works fine behind a PS/2 to USB converter (roundabout but less hassle than converting directly from sun to usb). He did note a bug in my schematic and that I didn't mention the orientation for the plugs. So I've redone the schematic (and the PCB) to correct that problem, but I took the lazy way out for the plug orientation: the schematic now just lists the standard pin numbers. For completeness' sake here are the pinouts for the female sockets, looking at the socket face (source gedasymbols.org):

[ published on Thu 11.03.2010 18:45 | filed in mystuff | ]
Debian Silver Server
© Alexander Zangerl