342 lines
13 KiB
C
342 lines
13 KiB
C
/*
|
||
*
|
||
* RetroBSD - PS2 keyboard driver for the Maximite PIC32 board
|
||
*
|
||
* Copyright (C) 2011 Rob Judd <judd@ob-wan.com>
|
||
* All rights reserved. The three clause ("New" or "Modified")
|
||
* Berkeley software License Agreement specifies the terms and
|
||
* conditions for redistribution.
|
||
*
|
||
*/
|
||
|
||
/*
|
||
../kbd.c: In function 'initKBD':
|
||
../kbd.c:155:8: error: request for member 'ON' in something not a structure or union
|
||
../kbd.c:156:8: error: request for member 'CNPUE15' in something not a structure or union
|
||
../kbd.c:157:8: error: request for member 'CNPUE16' in something not a structure or union
|
||
../kbd.c: In function 'readKBD':
|
||
../kbd.c:173:9: error: request for member 'RD7' in something not a structure or union
|
||
../kbd.c:174:9: error: request for member 'RD6' in something not a structure or union
|
||
*
|
||
* This driver uses a 20uS timer, probably too fast
|
||
*/
|
||
|
||
#include "sys/types.h"
|
||
#include "machine/io.h"
|
||
#include "kbd.h"
|
||
|
||
//#define TRACE printf
|
||
#ifndef TRACE
|
||
#define TRACE(...)
|
||
#endif
|
||
|
||
// I2C registers
|
||
struct kbdreg {
|
||
//
|
||
};
|
||
|
||
#define USASCII 1
|
||
//#define RUSSIAN 1
|
||
|
||
#define true 1
|
||
#define false 0
|
||
#define PS2CLOCK 1//PORTD.RD6
|
||
#define PS2DATA 2//PORTD.RD7
|
||
#define QUEUE_SIZE 256
|
||
|
||
extern volatile char in_queue[QUEUE_SIZE];
|
||
extern volatile int in_queue_head, in_queue_tail;
|
||
volatile int abort;
|
||
|
||
#define POLL 20*(CPU_KHZ/1000) // # clock cycles for 20uS between keyboard reads
|
||
#define TIMEOUT 500*(CPU_KHZ/1000) // # clock cycles for 500uS timeout
|
||
|
||
enum {PS2START, PS2BIT, PS2PARITY, PS2STOP};
|
||
|
||
// Keyboard state machine and buffer
|
||
int state;
|
||
unsigned char key_buff;
|
||
int key_state, key_count, key_parity, key_timer;
|
||
|
||
// IBM keyboard scancode set 2 - Special Keys
|
||
#define F1 0x0e
|
||
#define F2 0x0f
|
||
#define F3 0x10
|
||
#define F4 0x11
|
||
#define F5 0x12
|
||
#define F6 0x13
|
||
#define F7 0x14 // maps to F5
|
||
#define F8 0x15
|
||
#define F9 0x16
|
||
#define F10 0x17
|
||
#define F11 0x18
|
||
#define F12 0x19
|
||
|
||
#define NUM 0x00
|
||
#define BKSP 0x08
|
||
#define TAB 0x09
|
||
#define L_ALT 0x11
|
||
#define L_SHF 0x12
|
||
#define L_CTL 0x14
|
||
#define CAPS 0x58
|
||
#define R_SHF 0x59
|
||
#define ENTER 0x0d
|
||
#define ESC 0x1b
|
||
#define SCRL 0x7e
|
||
|
||
#ifdef USASCII
|
||
//
|
||
// Map of standard keyboard, US ASCII layout
|
||
//
|
||
const char lowerKey[128]={
|
||
0, F9, 0, F5, F3, F1, F2, F12, //00
|
||
0, F10, F8, F6, F4, TAB, '`', 0, //08
|
||
0, 0, L_SHF, 0, L_CTL, 'q', '1', 0, //10
|
||
0, 0, 'z', 's', 'a', 'w', '2', 0, //18
|
||
0, 'c', 'x', 'd', 'e', '4', '3', 0, //20
|
||
0, ' ', 'v', 'f', 't', 'r', '5', 0, //28
|
||
0, 'n', 'b', 'h', 'g', 'y', '6', 0, //30
|
||
0, 0, 'm', 'j', 'u', '7', '8', 0, //38
|
||
0, ',', 'k', 'i', 'o', '0', '9', 0, //40
|
||
0, '.', '/', 'l', ';', 'p', '-', 0, //48
|
||
0, 0, '\'', 0, '[', '=', 0, 0, //50
|
||
CAPS, R_SHF, ENTER, ']', 0, '\\', 0, 0, //58
|
||
0, 0, 0, 0, 0, 0, BKSP, 0, //60
|
||
0, '1', 0, '4', '7', 0, 0, 0, //68
|
||
'0', '.', '2', '5', '6', '8', ESC, NUM, //70
|
||
F11, '+', '3', '-', '*', '9', 0, 0 //78
|
||
};
|
||
|
||
const char upperKey[128] = {
|
||
0, F9, 0, F5, F3, F1, F2, F12, //00
|
||
0, F10, F8, F6, F4, TAB, '~', 0, //08
|
||
0, 0, L_SHF, 0, L_CTL, 'Q', '!', 0, //10
|
||
0, 0, 'Z', 'S', 'A', 'W', '@', 0, //18
|
||
0, 'C', 'X', 'D', 'E', '$', '#', 0, //20
|
||
0, ' ', 'V', 'F', 'T', 'R', '%', 0, //28
|
||
0, 'N', 'B', 'H', 'G', 'Y', '^', 0, //30
|
||
0, 0, 'M', 'J', 'U', '&', '*', 0, //38
|
||
0, '<', 'K', 'I', 'O', ')', '(', 0, //40
|
||
0, '>', '?', 'L', ':', 'P', '_', 0, //48
|
||
0, 0, '\"', 0, '{', '+', 0, 0, //50
|
||
CAPS, R_SHF, ENTER, '}', 0, '|', 0, 0, //58
|
||
0, 0, 0, 0, 0, 0, BKSP, 0, //60
|
||
0, '1', 0, '4', '7', 0, 0, 0, //68
|
||
'0', '.', '2', '5', '6', '8', ESC, NUM, //70
|
||
F11, '+', '3', '-', '*', '9', 0, 0 //78
|
||
};
|
||
#elif defined RUSSIAN
|
||
//
|
||
// Map of standard keyboard, Russian Windows layout
|
||
//
|
||
const char lowerKey[128]={
|
||
0, F9, 0, F5, F3, F1, F2, F12, //00
|
||
0, F10, F8, F6, F4, TAB, 'ё', 0, //08
|
||
0, 0, L_SHF, 0, L_CTL, 'й', '1', 0, //10
|
||
0, 0, 'я', 'ы', 'ф', 'ц', '2', 0, //18
|
||
0, 'с', 'ч', 'в', 'у', '4', '3', 0, //20
|
||
0, ' ', 'м', 'а', 'е', 'к', '5', 0, //28
|
||
0, 'т', 'и', 'р', 'п', 'н', '6', 0, //30
|
||
0, 0, 'ь', 'о', 'г', '7', '8', 0, //38
|
||
0, 'б', 'л', 'ш', 'щ', '0', '9', 0, //40
|
||
0, 'ю', '.', 'д', 'ж', 'з', '-', 0, //48
|
||
0, 0, 'э', 0, 'х', '=', 0, 0, //50
|
||
CAPS, R_SHF, ENTER, 'ъ', 0, '\\', 0, 0, //58
|
||
0, 0, 0, 0, 0, 0, BKSP, 0, //60
|
||
0, '1', 0, '4', '7', 0, 0, 0, //68
|
||
'0', ',', '2', '5', '6', '8', ESC, NUM, //70
|
||
F11, '+', '3', '-', '*', '9', 0, 0 //78
|
||
};
|
||
|
||
const char upperKey[128] = {
|
||
0, F9, 0, F5, F3, F1, F2, F12, //00
|
||
0, F10, F8, F6, F4, TAB, 'Ё', 0, //08
|
||
0, 0, L_SHF, 0, L_CTL, 'Й', '!', 0, //10
|
||
0, 0, 'Я', 'Ы', 'Ф', 'Ц', '\"', 0, //18
|
||
0, 'С', 'Ч', 'В', 'У', ';', '№', 0, //20
|
||
0, ' ', 'М', 'А', 'Е', 'К', '%', 0, //28
|
||
0, 'Т', 'И', 'Р', 'П', 'Н', ':', 0, //30
|
||
0, 0, 'Ь', 'О', 'Г', '?', '*', 0, //38
|
||
0, 'Б', 'Л', 'Ш', 'Щ', ')', '(', 0, //40
|
||
0, 'Ю', ',', 'Д', 'Ж', 'З', '_', 0, //48
|
||
0, 0, 'Э', 0, 'Х', '+', 0, 0, //50
|
||
CAPS, R_SHF, ENTER, 'Ъ', 0, '/', 0, 0, //58
|
||
0, 0, 0, 0, 0, 0, BKSP, 0, //60
|
||
0, '1', 0, '4', '7', 0, 0, 0, //68
|
||
'0', ',', '2', '5', '6', '8', ESC, NUM, //70
|
||
F11, '+', '3', '-', '*', '9', 0, 0 //78
|
||
};
|
||
#endif
|
||
|
||
/*
|
||
Standard PC init sequence:
|
||
|
||
Keyboard: AA Self-test passed ;Keyboard controller init
|
||
Host: ED Set/Reset Status Indicators
|
||
Keyboard: FA Acknowledge
|
||
Host: 00 Turn off all LEDs
|
||
Keyboard: FA Acknowledge
|
||
Host: F2 Read ID
|
||
Keyboard: FA Acknowledge
|
||
Keyboard: AB First byte of ID
|
||
Host: ED Set/Reset Status Indicators ;BIOS init
|
||
Keyboard: FA Acknowledge
|
||
Host: 02 Turn on Num Lock LED
|
||
Keyboard: FA Acknowledge
|
||
Host: F3 Set Typematic Rate/Delay ;Windows init
|
||
Keyboard: FA Acknowledge
|
||
Host: 20 500 ms / 30.0 reports/sec
|
||
Keyboard: FA Acknowledge
|
||
Host: F4 Enable
|
||
Keyboard: FA Acknowledge
|
||
Host: F3 Set Typematic Rate/delay
|
||
Keyboard: FA Acknowledge
|
||
Host: 00 250 ms / 30.0 reports/sec
|
||
Keyboard: FA Acknowledge
|
||
*/
|
||
|
||
char init_kbd(void)
|
||
{
|
||
// enable pullups on the clock and data lines.
|
||
// This stops them from floating and generating random chars when no keyboard is attached
|
||
// CNCON.ON = 1; // turn on Change Notice for interrupt
|
||
// CNPUE.CNPUE15 = 1; // turn on the pullup for pin D6 also called CN15
|
||
// CNPUE.CNPUE16 = 1; // turn on the pullup for pin D7 also called CN16
|
||
|
||
return false;
|
||
}
|
||
|
||
void read_kbd(void)
|
||
{
|
||
int data = PS2DATA;
|
||
int clock = PS2CLOCK;
|
||
static char key_up = false;
|
||
static unsigned char code = 0;
|
||
static unsigned then = 0;
|
||
unsigned now = mips_read_c0_register (C0_COUNT, 0);
|
||
|
||
// Is it time to poll the keyboard yet?
|
||
if ((int) (now - then) < POLL)
|
||
return;
|
||
else
|
||
then = now;
|
||
|
||
if (key_state) { // if clock was high, key_state = 1
|
||
if (!clock) { // PS2CLOCK == 0, falling edge detected
|
||
key_state = 0; // transition to state 0
|
||
key_timer = TIMEOUT; // restart the counter
|
||
|
||
switch(state){
|
||
default:
|
||
case PS2START:
|
||
if(!data) { // PS2DATA == 0
|
||
key_count = 8; // init bit counter
|
||
key_parity = 0; // init parity check
|
||
code = 0;
|
||
state = PS2BIT;
|
||
}
|
||
break;
|
||
|
||
case PS2BIT:
|
||
code >>= 1; // shift in data bit
|
||
if(data) // PS2DATA == 1
|
||
code |= 0x80;
|
||
key_parity ^= code;
|
||
if (--key_count == 0)
|
||
state = PS2PARITY; // all bits read
|
||
break;
|
||
|
||
case PS2PARITY:
|
||
if(data)
|
||
key_parity ^= 0x80;
|
||
if(key_parity & 0x80) // parity odd, continue
|
||
state = PS2STOP;
|
||
else
|
||
state = PS2START;
|
||
break;
|
||
|
||
case PS2STOP:
|
||
if(data) {
|
||
if(code == 0xf0)
|
||
key_up = true;
|
||
else {
|
||
|
||
char chr;
|
||
static char LShift = 0;
|
||
static char RShift = 0;
|
||
static char LCtrl = 0;
|
||
static char LAlt = 0;
|
||
static char CapsLock = 0;
|
||
|
||
if(key_up) { // check for special key release
|
||
key_up = false;
|
||
switch(code) {
|
||
case L_SHF: LShift = 0;
|
||
case R_SHF: RShift = 0;
|
||
case L_CTL: LCtrl = 0;
|
||
case L_ALT: LAlt = 0;
|
||
}
|
||
goto exit;
|
||
} else { // check for special key press
|
||
switch(code) {
|
||
case L_SHF: LShift = 1;
|
||
case R_SHF: RShift = 1;
|
||
case L_CTL: LCtrl = 1;
|
||
case L_ALT: LAlt = 1;
|
||
case CAPS: CapsLock = !CapsLock;
|
||
default: break;
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
if(LShift || RShift) // get the ASCII code
|
||
chr = lowerKey[code%128];
|
||
else
|
||
chr = upperKey[code%128];
|
||
|
||
if(!chr) // it was an unmapped key
|
||
break;
|
||
|
||
if(CapsLock && chr >= 'a' && chr <= 'z') // check for altered keys
|
||
chr -= 32;
|
||
if(LCtrl)
|
||
chr &= 0x1F;
|
||
|
||
in_queue[in_queue_head] = chr;
|
||
in_queue_head = (in_queue_head + 1) % QUEUE_SIZE;
|
||
|
||
if(chr == 3) { // check for CTL-C
|
||
in_queue_head = in_queue_tail = 0;
|
||
abort = true;
|
||
}
|
||
|
||
// PrintSignonToUSB = false; // show that the keyboard is in use
|
||
|
||
LAlt = LAlt; // not used yet
|
||
} // if key_up
|
||
exit:
|
||
code = 0;
|
||
} // if(data)
|
||
state = PS2START;
|
||
|
||
} // switch(state)
|
||
|
||
} // if(!clock)
|
||
|
||
} else // if(key_state)
|
||
key_state = 1; // PS2CLOCK == 1, rising edge detected
|
||
|
||
if ((key_timer -= POLL) <= 0)
|
||
state = PS2START; // timeout, reset state machine
|
||
|
||
return;
|
||
}
|
||
|
||
char write_kbd(u_char data)
|
||
{
|
||
|
||
// do something here
|
||
|
||
return false;
|
||
}
|