/* * * RetroBSD - PS2 keyboard driver for the Maximite PIC32 board * * Copyright (C) 2011 Rob Judd * 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; }