deepstone
diff src/keyb.c @ 33:03a0b307706a
added proper keyboard handling
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 23 Sep 2013 04:34:43 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/keyb.c Mon Sep 23 04:34:43 2013 +0300 1.3 @@ -0,0 +1,194 @@ 1.4 +/* 1.5 +DOS interrupt-based keyboard driver. 1.6 +Copyright (C) 2013 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with the program. If not, see <http://www.gnu.org/licenses/> 1.20 +*/ 1.21 +#define KEYB_C_ 1.22 + 1.23 +#include <stdio.h> 1.24 +#include <stdlib.h> 1.25 +#include <string.h> 1.26 +#include <conio.h> 1.27 +#include <dos.h> 1.28 +#include <i86.h> 1.29 +#include "keyb.h" 1.30 +#include "scancode.h" 1.31 + 1.32 +#define KB_INTR 0x9 1.33 +#define KB_PORT 0x60 1.34 + 1.35 +#define PIC1_CMD_PORT 0x20 1.36 +#define OCW2_EOI (1 << 5) 1.37 + 1.38 +#define DONE_INIT (prev_handler) 1.39 + 1.40 +static void __interrupt __far kbintr(); 1.41 + 1.42 +static void (__interrupt __far *prev_handler)(); 1.43 + 1.44 +static int *buffer; 1.45 +static int buffer_size, buf_ridx, buf_widx; 1.46 +static int last_key; 1.47 + 1.48 +static unsigned int num_pressed; 1.49 +static unsigned char keystate[256]; 1.50 + 1.51 +#define ADVANCE(x) ((x) = ((x) + 1) % buffer_size) 1.52 + 1.53 +int kb_init(int bufsz) 1.54 +{ 1.55 + if(DONE_INIT) { 1.56 + fprintf(stderr, "keyboard driver already initialized!\n"); 1.57 + return 0; 1.58 + } 1.59 + 1.60 + buffer_size = bufsz; 1.61 + if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) { 1.62 + fprintf(stderr, "failed to allocate input buffer, continuing without\n"); 1.63 + buffer_size = 0; 1.64 + } 1.65 + buf_ridx = buf_widx = 0; 1.66 + last_key = -1; 1.67 + 1.68 + memset(keystate, 0, sizeof keystate); 1.69 + num_pressed = 0; 1.70 + 1.71 + /* set our interrupt handler */ 1.72 + _disable(); 1.73 + prev_handler = _dos_getvect(KB_INTR); 1.74 + _dos_setvect(KB_INTR, kbintr); 1.75 + _enable(); 1.76 + 1.77 + return 0; 1.78 +} 1.79 + 1.80 +void kb_shutdown(void) 1.81 +{ 1.82 + if(!DONE_INIT) { 1.83 + return; 1.84 + } 1.85 + 1.86 + /* restore the original interrupt handler */ 1.87 + _disable(); 1.88 + _dos_setvect(KB_INTR, prev_handler); 1.89 + _enable(); 1.90 + 1.91 + free(buffer); 1.92 +} 1.93 + 1.94 +int kb_isdown(int key) 1.95 +{ 1.96 + if(key == KB_ANY) { 1.97 + return num_pressed; 1.98 + } 1.99 + return (int)keystate[key]; 1.100 +} 1.101 + 1.102 +void kb_wait(void) 1.103 +{ 1.104 + int key; 1.105 + while((key = kb_getkey()) == -1) { 1.106 + /* put the processor to sleep while waiting for keypresses, but first 1.107 + * make sure interrupts are enabled, or we'll sleep forever 1.108 + */ 1.109 + __asm { 1.110 + sti 1.111 + hlt 1.112 + } 1.113 + } 1.114 + kb_putback(key); 1.115 +} 1.116 + 1.117 +int kb_getkey(void) 1.118 +{ 1.119 + int res; 1.120 + 1.121 + if(buffer) { 1.122 + if(buf_ridx == buf_widx) { 1.123 + return -1; 1.124 + } 1.125 + res = buffer[buf_ridx]; 1.126 + ADVANCE(buf_ridx); 1.127 + } else { 1.128 + res = last_key; 1.129 + last_key = -1; 1.130 + } 1.131 + return res; 1.132 +} 1.133 + 1.134 +void kb_putback(int key) 1.135 +{ 1.136 + if(buffer) { 1.137 + /* go back a place */ 1.138 + if(--buf_ridx < 0) { 1.139 + buf_ridx += buffer_size; 1.140 + } 1.141 + 1.142 + /* if the write end hasn't caught up with us, go back one place 1.143 + * and put it there, otherwise just overwrite the oldest key which 1.144 + * is right where we were. 1.145 + */ 1.146 + if(buf_ridx == buf_widx) { 1.147 + ADVANCE(buf_ridx); 1.148 + } 1.149 + 1.150 + buffer[buf_ridx] = key; 1.151 + } else { 1.152 + last_key = key; 1.153 + } 1.154 +} 1.155 + 1.156 +static void __interrupt __far kbintr() 1.157 +{ 1.158 + unsigned char code; 1.159 + int key, press; 1.160 + 1.161 + code = inp(KB_PORT); 1.162 + 1.163 + if(code >= 128) { 1.164 + press = 0; 1.165 + code -= 128; 1.166 + 1.167 + if(num_pressed > 0) { 1.168 + num_pressed--; 1.169 + } 1.170 + } else { 1.171 + press = 1; 1.172 + 1.173 + num_pressed++; 1.174 + } 1.175 + 1.176 + key = scantbl[code]; 1.177 + 1.178 + if(press) { 1.179 + /* append to buffer */ 1.180 + last_key = key; 1.181 + if(buffer_size > 0) { 1.182 + buffer[buf_widx] = key; 1.183 + ADVANCE(buf_widx); 1.184 + /* if the write end overtook the read end, advance the read end 1.185 + * too, to discard the oldest keypress from the buffer 1.186 + */ 1.187 + if(buf_widx == buf_ridx) { 1.188 + ADVANCE(buf_ridx); 1.189 + } 1.190 + } 1.191 + } 1.192 + 1.193 + /* and update keystate table */ 1.194 + keystate[key] = press; 1.195 + 1.196 + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ 1.197 +}