;;******************************************************************************** ;; @module ps2_keyboard ;; @type driver ;; @details: ;; Support for a PS2 Keyboard using the shift register of a 6522 VIA ;; @section Reading a scancode/command answer ;; Pressing a key causes 11 bits to be sent: 1 start - 8 scancode - 1 parity - 1 stop ;; The VIA is set up to interrupt after 8 bits have been shifted into the shift register ;; from the external clock pulses of the keyboard (additional hardware required to ;; address the hardware bug of the VIA, where bit get lost when the external clock ;; transition happens during falling edge of PHI2). After reading the shift register, ;; the VIAs T2 timer is set to interrupt after the last 3 bits have been shifted in, ;; which takes about ~230ms. ;; T2 is used because it leaves to more versatile T1 available for something else ;; @section Processing a scancode ;; The scancode may be processed by storing the address of a handler subroutine in ;; ps2kb::scancode_handler. This handler can load the scancode byte from ps2kb::scancode. ;; ;; ;; To use a different layout, change the enum K and the CHARS_NOMOD and CHARS_MODSHIFT ;; @warning ;; The value with which the timer is loaded must depends on the clock frequency ;; of the keyboard and the computer ;; ;;******************************************************************************** .ifndef INCLUDE_PS2_KEYBOARD INCLUDE_PS2_KEYBOARD = 1 .include "system.h65" .scope ps2kb Import ps2kb,init,begin_receive,send_command,scancode,status,scancode_handler Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_byte, _send_irq_shift_reg_handler, _send_irq_timer_handler, Import ps2kb, send_last_bits, send_cmd, send_data, key_read, prev_status VIA = IO1 ; Enough time must pass for 3 bits to be shifted in. TIMER_RECV = 230 ; 230 ms (@1MHz) ; Enough time must pass for one bit must be shifted out (parity), ; but at most two (parity+stop). ; After that, the interrupt must have happened because the keyboard will pull data low. ; At that point, the SR needs to be set to input again TIMER_SEND = 230 ; 180 ms (@1MHz) ; use RA4 to pull the clock low PULL_REG = IO::RANH PULL_DDR = IO::DDRA PULL_MASK_CLK = %00010000 ; PULL_MASK_DAT = %00001000 NO_DATA = $ff ; indicates that no data byte should be send .enum STATUS RECEIVE_KEYS = %10000000 RECEIVE_ANSWER = %01000000 SEND_CMD = %00100000 SEND_DATA = %00010000 SEND_CMD_WAIT = %00001000 NONE = %00000000 .endenum .endscope .endif ; guard