PS/2 to Sun mouse converter

by Martin D. J. Rosenau

Abstract

The following text describes a circuit I developed that allows you to connect a PS/2 mouse to a Sun Microsystems workstation. It is mainly based on a 8051 compatible microcontroller. Special functions (such as mouse wheels) are ignored by the circuit and are ignored.

Warning

The device has been tested with my mouse and my computer. I cannot give you a warranty that it will work with your mouse and your computer. Under bad circumstances the device might damage your mouse or your computer. You use the circuit on your own risk !!!

Parts list

  • 1 Microcontroller, 8051 or MCS51 compatible (I use the Atmel 89S8252); minimum: 1k ROM, 64 bytes RAM
  • 1 (or 2) capacitor, 1uF
  • 3 (or 4) resistors, 1k
  • 1 quartz crystal or resonator (12 or 24 MHz)
  • 2 capacitors, value depending on crystal or resonator (30pF)
  • Sun mouse connector (Mini-Din-8, male)
  • PS/2 connector (Mini-DIN-6, female)
  • One button or switch (for reset)
  • wires, board, ... (what every circuit needs)
    Depending on the Microcontroller other resonator frequencies and other capacitors must be used.

    The sun mouse plug

    The sun mouse plug has the following pinout. Original sun mice have a plug with only 3 pins; 5 pins are missing. These missing pins should not be used:

    The Protocol

    Unlike "/dev/mouse" (that uses the 3 byte Sun protocol) the 5 byte Mouse Systems protocol is used on the hardware side. The signals coming from the mouse are the same a serial Mouse Systems mouse would send but the logic level is inverted TTL. This means a "0" is represented by +5V and a "1" by 0V. The following drawing shows one byte transmitted this way:

    The 5 bytes have the following meaning:
    Byte 1: 10000LMR
    Byte 2: X1
    Byte 3: Y1
    Byte 4: X2
    Byte 5: Y2
    The last 4 bytes are signed values that might have a value of 10000xxx, too, so there is no possibility to detect the first byte of the packet. On the other hand a value of 10000xxx would be such a fast mouse movement that such values never appear so 10000xxx can be seen as indication of the start of a new packet.
    The real X movement is (X1+X2) (positive=left). The circuit uses X2=constant=0. All movement data is transmitted over X1. The same is true for Y1/Y2 (positive=up).

    Schematics


    This schematics is based on another shematics developed by me that is used to connect PS/2 mice to the RS232 port.
    The pin numbers at the MCU are valid for the DIP 40 variant of the 89S8252. If you use another device please read the device manual for correct pin numbers.
    This schematics assumes that all port 3 pins are open-collector bidirectional I/O pins (that may have a pull-up resistor). The current version of the firmware assumes all pins to be in high- impedance mode (= HIGH) on power-on. You can even use different pins for input, output and interrupt (Ext #0, falling edge) if the source code is modified.
    You may use a soft reset button or not. If you do not use one you must either connect pin 13 to High or modify the firmware (normally pin 13 is connected to High using a pull-up resistor internally !). If you do not use a soft reset button you need a hard reset button that uses the Reset pin (pin 9). This variant requires a 4th resistor to avoid a shortcut of the capacitor.

    Firmware source code

    ; PS/2 to Sun mouse converter
    ; Needs an (extended ?) 8051
    ; Copyright (c) 2003 by Martin D. J. Rosenau
    ;
    ; Memory usage:
    ; 1Dh: Used by the PS/2 receiver
    ; 1Eh..1Fh: Used by the PS/2 transmitter
    ; 20h: Used by the serial routine
    ; 21h: Bit0: PS/2 bit received (cleared by other routines)
    ;      Bit1:
    ; 22h: First byte of a packet received
    ; 23h: First byte (button state) of the last packet translated
    ; 24h: Relative X movement
    ; 25h: Relative Y movement
    ; 26h..27h: Used by the main program
    ; 30h..33h: Serial send buffer
    ; 34h: Number of bytes in the serial buffer
    ;      If N>4 the last byte is repeated (N-3) times.
    ; 35h..38h: Used by the serial routines
    ; 39h: Byte received from PS/2 port
    ; 3Ah..3Dh: Used by the PS/2 receiver
    ; 3Eh..3Fh: Used by the PS/2 transmitter
    ;
    ; Ports:
    ; 3.1 - Mouse data (output)
    ; 3.2/INT0 - PS/2 clock (TTL; IN&OUT)
    ; 3.3 - LOW = Reset
    ; 3.7 - PS/2 data (TTL; IN&OUT)
    ;
    
    ; Definition of the port bits
    ; You may change the pins; PS/2 clock
    ; must be the same pin as INT0 !
    PS2IN       bit 0B7h
    PS2OUT      bit 0B7h
    MSRESET     bit 0B3h
    PS2CLOCKIN  bit 0B2h
    PS2CLOCKOUT bit 0B2h
    SERIALOUT   bit 0B1h
    
    ; Some crystal frequency dependent values
    ; You must change these values when
    ; using a different crystal !
    ; about MHz*(2.5) -> 60 for 24 MHz
    TIME1       equ 60
    ; 100h-(MHz*(2.15)) -> 0CCh for 24 MHz
    TIME2       equ 0CCh
    
    ; Header
      sjmp start
      org 3
      ljmp onclockin
      org 1Bh
      ljmp ontimer1
      org 40h
    
    ; The start of it...
    start:
      ; Wait until an initialize
      ; signal is received...
      clr SERIALOUT
      clr 9
      mov 0A8h,#0
      mov C,MSRESET
      jnc start
      ; Initialize the serial port
      acall serinit
      mov 34h,#0
      ; Clear the PS/2 port and enable it
      clr 8
      setb 88h
      mov 3Ah,#0
      mov 23h,#0
      mov 24h,#0
      mov 25h,#0
      mov 1Dh,#0
      ; Send initialition data to the PS/2 mouse
      mov A,#0F4h
      acall ps2send
      acall ps2read
      mov A,#0E7h
      acall ps2send
      acall ps2read
      mov A,#0E8h
      acall ps2send
      acall ps2read
      mov A,#1
      acall ps2send
      acall ps2read
      setb 0A8h
      setb 9
    
      ; The working loop
      ; Restart the program any time RTS goes low.
    waitfirst:
      ; Wait while a serial transmission is done
      mov A,34h
      jnz waitfirst
      ; "Reset" detected
      mov C,MSRESET
      jnc start
      ; Did the mouse position or buttons change ?
      mov A,24h
      jnz mousechanged
      mov A,25h
      jnz mousechanged
      mov A,22h
      xrl A,23h
      anl A,#7
      jz waitfirst
    mousechanged:
      ; The mouse position changed, so a packet must be sent...
      mov 26h,24h
      mov 24h,#0
      mov 27h,25h
      mov 25h,#0
      mov 23h,22h
      ; Buttons
      mov A,#080h
      mov C,18h
      mov 0E2h,C
      mov C,19h
      mov 0E0h,C
      mov C,1Ah
      mov 0E1h,C
      xrl A,#7
      ; Finish the packet
      mov 30h,A
      mov A,26h
    ;  anl A,#7Fh
      mov 31h,A
      mov A,27h
    ;  anl A,#7Fh
      mov 32h,A
      mov 33h,#0
      mov 34h,#5
      ; Restart
      sjmp waitfirst
    
    ; PS/2 clock line detected
    onclockin:
      mov 3Bh,A
      mov 3Ch,0D0h
      mov A,3Ah
      jnz notfirstps2
      ; It is a start bit => MUST be 0 !
      mov C,PS2IN
      jc onclockend
      mov 3Ah,#10
      sjmp onclockend
    
    notfirstps2:
      dec 3Ah
      dec A
      jnz notstopbit
      ; It is a stop bit
      mov C,PS2IN
      jnc onclockend
      mov 39h,3Dh
      setb 8
      mov C,9
      jc onautops2
      sjmp onclockend
    notstopbit:
      dec A
      ; Ignore parity
      jz onclockend
      mov A,3Dh
      mov C,PS2IN
      rrc A
      mov 3Dh,A
    onclockend:
      mov A,3Bh
      mov 0D0h,3Ch
      reti
    onautops2:
      ; Automatically process PS/2 data
      mov A,1Dh
      dec A
      jnz isnot2
      ; 2nd byte
      inc 1Dh
      mov A,39h
      add A,24h
      mov 24h,A
      sjmp onclockend
    isnot2:
      ; 3rd byte
      dec A
      jnz isnot3
      mov 1Dh,#0
      mov A,39h
      add A,25h
      mov 25h,A
      sjmp onclockend
    isnot3:
      ; 1st byte
      mov A,39h
      mov C,0E3h
      jnc onclockend
      mov 22h,A
      mov 1Dh,#1
      sjmp onclockend
    
    ; Initialize the serial routine
    serinit:
      clr SERIALOUT
      mov 0A8h,#0
      mov 89h,#0
      mov 8Dh,0
      mov 34h,#0
      mov 35h,#0
      setb 8Eh
      mov 0A8h,#88h
      ret
    
    ; Read a single byte from the PS/2 port
    ps2read:
      setb 0A8h
      mov C,8
      jnc ps2read
      mov A,39h
      clr 8
      ret
    
    ; Send a byte over the PS/2 port
    ; Disables the external interrupt.
    ps2send:
      clr 0A8h
      mov 1Eh,A
      mov 1Fh,A
      ; Wait some time
      mov A,128
    ps2waitpre:
      dec A
      jnz ps2waitpre
      ; Inhibit
      clr PS2CLOCKOUT
      mov A,#TIME1
    ps2dowait:
      dec A
      jnz ps2dowait
      setb PS2CLOCKOUT
      clr PS2OUT
      ; Send all bits
      mov 3Fh,#8
    nextbitps2:
      mov A,1Fh
      rrc A
      mov 1Fh,A
      acall sendps2bit
      dec 3Fh
      mov A,3Fh
      jnz nextbitps2
      ; Send the parity bit
      mov A,1Eh
      xrl A,#1
      mov C,0D0h
      acall sendps2bit
      ; Send the stop bit and receive the ACK bit
      setb C
      acall sendps2bit
      setb C
      acall sendps2bit
    ackwait:
      mov C,PS2IN
      jnc ackwait
      ret
    
    ; Send a bit (C) to the PS/2 port
    sendps2bit:
      mov 3Eh,0D0h
    sendps21:
      mov C,PS2CLOCKIN
      jc sendps21
      mov 0D0h,3Eh
      mov PS2OUT,C
    sendps22:
      mov C,PS2CLOCKIN
      jnc sendps22
      mov 0D0h,3Eh
      ret
    
    ; Timer 1 interrupt routine: Serial port
    ; emulation (the hardware UART is no used)
    ontimer1:
      ; restart the timer
      mov 8Dh,#TIME2
      ; save the accumulator
      mov 37h,A
      mov 38h,0D0h
      ; is a byte currently being sent ?
      mov A,35h
      jnz duringsend
      ; No bytes is currently being sent
      ; Start one ?
      mov A,34h
      jnz beginsend
      ; Exit the interrupt
    ontimer1end:
      mov A,37h
      mov 0D0h,38h
      reti
    beginsend:
      ; begin sending a byte
      mov 20h,30h
      mov 30h,31h
      mov 31h,32h
      mov 32h,33h
      dec 34h
      setb SERIALOUT
      ; Still 9 bits to be sent (including
      ; 1 stop bit)
      mov 35h,#9
      sjmp ontimer1end
    duringsend:
      ; What to do while transmitting a byte...
      dec 35h
      mov A,20h
      setb C
      rrc A
      cpl C
      mov SERIALOUT,C
      mov 20h,A
      sjmp ontimer1end
    
    end

    Compiled firmware

    Here is the compiled firmware in HEX file format. The program is compiled for the following configuration:
  • Crystal frequency: 24 MHz
  • Device: Atmel 89S8252 (should work on most other devices, too)
  • Port 3.1 is used as Sun mouse output
  • Port 3.2 is used as bidirectional PS/2 clock port and is the falling-edge interrupt #0 pin
  • Port 3.3 is the negated Reset input
  • Port 3.7 is used as bidirectional PS/2 data port
    :02000000803E40
    :030003000200C830
    :03001B0002019748
    :10004000C2B1C20975A800A2B350F53128753400B9
    :10005000C208D288753A0075230075240075250002
    :10006000751D0074F4314A313F74E7314A313F74F1
    :10007000E8314A313F7401314A313FD2A8D209E513
    :100080003470FCA2B350B9E524700CE5257008E586
    :10009000226523540760E8852426752400852527DA
    :1000A0007525008522237480A21892E2A21992E09D
    :1000B000A21A92E16407F530E526F531E527F5321D
    :1000C00075330075340580B7F53B85D03CE53A7053
    :1000D00009A2B74023753A0A801E153A14700FA280
    :1000E000B75015853D39D208A2094012800A146024
    :1000F00007E53DA2B713F53DE53B853CD032E51D54
    :1001000014700A051DE5392524F52480EB14700BC5
    :10011000751D00E5392525F52580DDE539A2E3507B
    :10012000D7F522751D0180D0C2B175A80075890070
    :1001300085008D753400753500D28E75A88822D261
    :10014000A8A20850FAE539C20822C2A8F51EF51F78
    :10015000E5801470FDC2B2743C1470FDD2B2C2B717
    :10016000753F08E51F13F51F3183153FE53F70F319
    :10017000E51E6401A2D03183D33183D33183A2B78A
    :1001800050FC2285D03EA2B240FC853ED092B7A260
    :10019000B250FC853ED022758DCCF53785D038E540
    :1001A00035701FE5347006E5378538D0328530204C
    :1001B0008531308532318533321534D2B175350908
    :0F01C00080E51535E520D313B392B1F52080D833
    :00000001FF

    Usage

    After connecting the mouse (and possibly after power-up) the reset button must be pressed !
    Copyright © 2003 by Martin D. J. Rosenau