doskeyb
diff keyb.c @ 0:c2b210a70ce9
initial DOS keyboard driver commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 23 Sep 2013 03:42:39 +0300 |
parents | |
children | da4c014bb055 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/keyb.c Mon Sep 23 03:42:39 2013 +0300 1.3 @@ -0,0 +1,183 @@ 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 char keystate[256]; 1.49 + 1.50 +#define ADVANCE(x) ((x) = ((x) + 1) % buffer_size) 1.51 + 1.52 +int kb_init(int bufsz) 1.53 +{ 1.54 + if(DONE_INIT) { 1.55 + fprintf(stderr, "keyboard driver already initialized!\n"); 1.56 + return 0; 1.57 + } 1.58 + 1.59 + buffer_size = bufsz; 1.60 + if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) { 1.61 + fprintf(stderr, "failed to allocate input buffer, continuing without\n"); 1.62 + buffer_size = 0; 1.63 + } 1.64 + buf_ridx = buf_widx = 0; 1.65 + last_key = -1; 1.66 + 1.67 + memset(keystate, 0, sizeof keystate); 1.68 + 1.69 + /* set our interrupt handler */ 1.70 + _disable(); 1.71 + prev_handler = _dos_getvect(KB_INTR); 1.72 + _dos_setvect(KB_INTR, kbintr); 1.73 + _enable(); 1.74 + 1.75 + return 0; 1.76 +} 1.77 + 1.78 +void kb_shutdown(void) 1.79 +{ 1.80 + if(!DONE_INIT) { 1.81 + return; 1.82 + } 1.83 + 1.84 + /* restore the original interrupt handler */ 1.85 + _disable(); 1.86 + _dos_setvect(KB_INTR, prev_handler); 1.87 + _enable(); 1.88 + 1.89 + free(buffer); 1.90 +} 1.91 + 1.92 +int kb_isdown(int key) 1.93 +{ 1.94 + return (int)keystate[key]; 1.95 +} 1.96 + 1.97 +void kb_wait(void) 1.98 +{ 1.99 + int key; 1.100 + while((key = kb_getkey()) == -1) { 1.101 + /* put the processor to sleep while waiting for keypresses, but first 1.102 + * make sure interrupts are enabled, or we'll sleep forever 1.103 + */ 1.104 + __asm { 1.105 + sti 1.106 + hlt 1.107 + } 1.108 + } 1.109 + kb_putback(key); 1.110 +} 1.111 + 1.112 +int kb_getkey(void) 1.113 +{ 1.114 + int res; 1.115 + 1.116 + if(buffer) { 1.117 + if(buf_ridx == buf_widx) { 1.118 + return -1; 1.119 + } 1.120 + res = buffer[buf_ridx]; 1.121 + ADVANCE(buf_ridx); 1.122 + } else { 1.123 + res = last_key; 1.124 + last_key = -1; 1.125 + } 1.126 + return res; 1.127 +} 1.128 + 1.129 +void kb_putback(int key) 1.130 +{ 1.131 + if(buffer) { 1.132 + /* go back a place */ 1.133 + if(--buf_ridx < 0) { 1.134 + buf_ridx += buffer_size; 1.135 + } 1.136 + 1.137 + /* if the write end hasn't caught up with us, go back one place 1.138 + * and put it there, otherwise just overwrite the oldest key which 1.139 + * is right where we were. 1.140 + */ 1.141 + if(buf_ridx == buf_widx) { 1.142 + ADVANCE(buf_ridx); 1.143 + } 1.144 + 1.145 + buffer[buf_ridx] = key; 1.146 + } else { 1.147 + last_key = key; 1.148 + } 1.149 +} 1.150 + 1.151 +static void __interrupt __far kbintr() 1.152 +{ 1.153 + unsigned char code; 1.154 + int key, press; 1.155 + 1.156 + code = inp(KB_PORT); 1.157 + 1.158 + if(code >= 128) { 1.159 + press = 0; 1.160 + code -= 128; 1.161 + } else { 1.162 + press = 1; 1.163 + } 1.164 + 1.165 + key = scantbl[code]; 1.166 + 1.167 + if(press) { 1.168 + /* append to buffer */ 1.169 + last_key = key; 1.170 + if(buffer_size > 0) { 1.171 + buffer[buf_widx] = key; 1.172 + ADVANCE(buf_widx); 1.173 + /* if the write end overtook the read end, advance the read end 1.174 + * too, to discard the oldest keypress from the buffer 1.175 + */ 1.176 + if(buf_widx == buf_ridx) { 1.177 + ADVANCE(buf_ridx); 1.178 + } 1.179 + } 1.180 + } 1.181 + 1.182 + /* and update keystate table */ 1.183 + keystate[key] = press; 1.184 + 1.185 + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ 1.186 +}