eobish
diff src/dos/keyb.c @ 7:6a350c554e46
started DOS port
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 19 Jan 2015 15:49:14 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/dos/keyb.c Mon Jan 19 15:49:14 2015 +0200 1.3 @@ -0,0 +1,201 @@ 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 + switch(key) { 1.97 + case KB_ANY: 1.98 + return num_pressed; 1.99 + 1.100 + case KB_ALT: 1.101 + return keystate[KB_LALT] + keystate[KB_RALT]; 1.102 + 1.103 + case KB_CTRL: 1.104 + return keystate[KB_LCTRL] + keystate[KB_RCTRL]; 1.105 + } 1.106 + return keystate[key]; 1.107 +} 1.108 + 1.109 +void kb_wait(void) 1.110 +{ 1.111 + int key; 1.112 + while((key = kb_getkey()) == -1) { 1.113 + /* put the processor to sleep while waiting for keypresses, but first 1.114 + * make sure interrupts are enabled, or we'll sleep forever 1.115 + */ 1.116 + __asm { 1.117 + sti 1.118 + hlt 1.119 + } 1.120 + } 1.121 + kb_putback(key); 1.122 +} 1.123 + 1.124 +int kb_getkey(void) 1.125 +{ 1.126 + int res; 1.127 + 1.128 + if(buffer) { 1.129 + if(buf_ridx == buf_widx) { 1.130 + return -1; 1.131 + } 1.132 + res = buffer[buf_ridx]; 1.133 + ADVANCE(buf_ridx); 1.134 + } else { 1.135 + res = last_key; 1.136 + last_key = -1; 1.137 + } 1.138 + return res; 1.139 +} 1.140 + 1.141 +void kb_putback(int key) 1.142 +{ 1.143 + if(buffer) { 1.144 + /* go back a place */ 1.145 + if(--buf_ridx < 0) { 1.146 + buf_ridx += buffer_size; 1.147 + } 1.148 + 1.149 + /* if the write end hasn't caught up with us, go back one place 1.150 + * and put it there, otherwise just overwrite the oldest key which 1.151 + * is right where we were. 1.152 + */ 1.153 + if(buf_ridx == buf_widx) { 1.154 + ADVANCE(buf_ridx); 1.155 + } 1.156 + 1.157 + buffer[buf_ridx] = key; 1.158 + } else { 1.159 + last_key = key; 1.160 + } 1.161 +} 1.162 + 1.163 +static void __interrupt __far kbintr() 1.164 +{ 1.165 + unsigned char code; 1.166 + int key, press; 1.167 + 1.168 + code = inp(KB_PORT); 1.169 + 1.170 + if(code >= 128) { 1.171 + press = 0; 1.172 + code -= 128; 1.173 + 1.174 + if(num_pressed > 0) { 1.175 + num_pressed--; 1.176 + } 1.177 + } else { 1.178 + press = 1; 1.179 + 1.180 + num_pressed++; 1.181 + } 1.182 + 1.183 + key = scantbl[code]; 1.184 + 1.185 + if(press) { 1.186 + /* append to buffer */ 1.187 + last_key = key; 1.188 + if(buffer_size > 0) { 1.189 + buffer[buf_widx] = key; 1.190 + ADVANCE(buf_widx); 1.191 + /* if the write end overtook the read end, advance the read end 1.192 + * too, to discard the oldest keypress from the buffer 1.193 + */ 1.194 + if(buf_widx == buf_ridx) { 1.195 + ADVANCE(buf_ridx); 1.196 + } 1.197 + } 1.198 + } 1.199 + 1.200 + /* and update keystate table */ 1.201 + keystate[key] = press; 1.202 + 1.203 + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ 1.204 +}