PCem

view src/keyboard_at.c @ 132:2b9cea0be424

Improvements to PC speaker - fixes sound on Beyond Castle Wolfenstein and probably other games as well.
author TomW
date Wed Jul 16 20:44:29 2014 +0100
parents a10f75a7a701
children 26a55112027e
line source
1 #include "ibm.h"
2 #include "io.h"
3 #include "mem.h"
4 #include "pic.h"
5 #include "pit.h"
6 #include "sound.h"
7 #include "sound_speaker.h"
8 #include "timer.h"
10 #include "keyboard.h"
11 #include "keyboard_at.h"
13 #define STAT_PARITY 0x80
14 #define STAT_RTIMEOUT 0x40
15 #define STAT_TTIMEOUT 0x20
16 #define STAT_MFULL 0x20
17 #define STAT_LOCK 0x10
18 #define STAT_CD 0x08
19 #define STAT_SYSFLAG 0x04
20 #define STAT_IFULL 0x02
21 #define STAT_OFULL 0x01
23 struct
24 {
25 int initialised;
26 int want60;
27 int wantirq, wantirq12;
28 uint8_t command;
29 uint8_t status;
30 uint8_t mem[0x20];
31 uint8_t out;
33 uint8_t input_port;
34 uint8_t output_port;
36 uint8_t key_command;
37 int key_wantdata;
38 } keyboard_at;
40 static uint8_t key_ctrl_queue[16];
41 static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0;
43 static uint8_t key_queue[16];
44 static int key_queue_start = 0, key_queue_end = 0;
46 static uint8_t mouse_queue[16];
47 int mouse_queue_start = 0, mouse_queue_end = 0;
49 void keyboard_at_poll()
50 {
51 keybsenddelay += (1000 * TIMER_USEC);
52 if (keyboard_at.wantirq)
53 {
54 keyboard_at.wantirq = 0;
55 picint(2);
56 // pclog("keyboard_at : take IRQ\n");
57 }
58 else if (keyboard_at.wantirq12)
59 {
60 keyboard_at.wantirq12 = 0;
61 picint(0x1000);
62 // pclog("keyboard_at : take IRQ 12\n");
63 }
64 if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
65 mouse_queue_start != mouse_queue_end)
66 {
67 // pclog("Reading %02X from the mouse queue at %i\n", keyboard_at.out, key_queue_start);
68 keyboard_at.out = mouse_queue[mouse_queue_start];
69 mouse_queue_start = (mouse_queue_start + 1) & 0xf;
70 keyboard_at.status |= STAT_OFULL | STAT_MFULL;
71 keyboard_at.status &= ~STAT_IFULL;
72 if (keyboard_at.mem[0] & 0x02)
73 keyboard_at.wantirq12 = 1;
74 }
75 else if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
76 key_queue_start != key_queue_end)
77 {
78 // pclog("Reading %02X from the key queue at %i\n", keyboard_at.out, key_queue_start);
79 keyboard_at.out = key_queue[key_queue_start];
80 key_queue_start = (key_queue_start + 1) & 0xf;
81 keyboard_at.status |= STAT_OFULL;
82 keyboard_at.status &= ~STAT_IFULL;
83 if (keyboard_at.mem[0] & 0x01)
84 keyboard_at.wantirq = 1;
85 }
86 else if (!(keyboard_at.status & STAT_OFULL) &&
87 key_ctrl_queue_start != key_ctrl_queue_end)
88 {
89 // pclog("Reading %02X from the key ctrl_queue at %i\n", keyboard_at.out, key_ctrl_queue_start);
90 keyboard_at.out = key_ctrl_queue[key_ctrl_queue_start];
91 key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf;
92 keyboard_at.status |= STAT_OFULL;
93 keyboard_at.status &= ~STAT_IFULL;
94 if (keyboard_at.mem[0] & 0x01)
95 keyboard_at.wantirq = 1;
96 }
97 }
99 void keyboard_at_adddata(uint8_t val)
100 {
101 // if (keyboard_at.status & STAT_OFULL)
102 // {
103 key_ctrl_queue[key_ctrl_queue_end] = val;
104 key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf;
105 // pclog("keyboard_at : %02X added to queue\n", val);
106 /* return;
107 }
108 keyboard_at.out = val;
109 keyboard_at.status |= STAT_OFULL;
110 keyboard_at.status &= ~STAT_IFULL;
111 if (keyboard_at.mem[0] & 0x01)
112 keyboard_at.wantirq = 1;
113 pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/
114 }
116 void keyboard_at_adddata_keyboard(uint8_t val)
117 {
118 /* if (val == 0x1c)
119 {
120 key_1c++;
121 if (key_1c == 4)
122 output = 3;
123 }*/
124 key_queue[key_queue_end] = val;
125 key_queue_end = (key_queue_end + 1) & 0xf;
126 // pclog("keyboard_at : %02X added to key queue\n", val);
127 return;
128 }
130 void keyboard_at_adddata_mouse(uint8_t val)
131 {
132 mouse_queue[mouse_queue_end] = val;
133 mouse_queue_end = (mouse_queue_end + 1) & 0xf;
134 // pclog("keyboard_at : %02X added to mouse queue\n", val);
135 return;
136 }
138 void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
139 {
140 // pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]);
141 /* if (ram[8] == 0xc3)
142 {
143 output = 3;
144 }*/
145 switch (port)
146 {
147 case 0x60:
148 if (keyboard_at.want60)
149 {
150 /*Write to controller*/
151 keyboard_at.want60 = 0;
152 switch (keyboard_at.command)
153 {
154 case 0x60: case 0x61: case 0x62: case 0x63:
155 case 0x64: case 0x65: case 0x66: case 0x67:
156 case 0x68: case 0x69: case 0x6a: case 0x6b:
157 case 0x6c: case 0x6d: case 0x6e: case 0x6f:
158 case 0x70: case 0x71: case 0x72: case 0x73:
159 case 0x74: case 0x75: case 0x76: case 0x77:
160 case 0x78: case 0x79: case 0x7a: case 0x7b:
161 case 0x7c: case 0x7d: case 0x7e: case 0x7f:
162 keyboard_at.mem[keyboard_at.command & 0x1f] = val;
163 if (keyboard_at.command == 0x60)
164 {
165 if ((val & 1) && (keyboard_at.status & STAT_OFULL))
166 keyboard_at.wantirq = 1;
167 if (!(val & 1) && keyboard_at.wantirq)
168 keyboard_at.wantirq = 0;
169 }
170 break;
172 case 0xcb: /*AMI - set keyboard mode*/
173 break;
175 case 0xcf: /*??? - sent by MegaPC BIOS*/
176 break;
178 case 0xd1: /*Write output port*/
179 // pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc);
180 if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/
181 {
182 mem_a20_key = val & 0x02;
183 mem_a20_recalc();
184 // pclog("Rammask change to %08X %02X\n", rammask, val & 0x02);
185 flushmmucache();
186 }
187 keyboard_at.output_port = val;
188 break;
190 case 0xd3: /*Write to mouse output buffer*/
191 keyboard_at_adddata_mouse(val);
192 break;
194 case 0xd4: /*Write to mouse*/
195 if (mouse_write)
196 mouse_write(val);
197 break;
199 default:
200 pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command);
201 // dumpregs();
202 // exit(-1);
203 }
204 }
205 else
206 {
207 /*Write to keyboard*/
208 keyboard_at.mem[0] &= ~0x10;
209 if (keyboard_at.key_wantdata)
210 {
211 keyboard_at.key_wantdata = 0;
212 switch (keyboard_at.key_command)
213 {
214 case 0xed: /*Set/reset LEDs*/
215 keyboard_at_adddata_keyboard(0xfa);
216 break;
218 case 0xf3: /*Set typematic rate/delay*/
219 keyboard_at_adddata_keyboard(0xfa);
220 break;
222 default:
223 pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command);
224 // dumpregs();
225 // exit(-1);
226 }
227 }
228 else
229 {
230 keyboard_at.key_command = val;
231 switch (val)
232 {
233 case 0x05: /*??? - sent by NT 4.0*/
234 keyboard_at_adddata_keyboard(0xfe);
235 break;
237 case 0xed: /*Set/reset LEDs*/
238 keyboard_at.key_wantdata = 1;
239 keyboard_at_adddata_keyboard(0xfa);
240 break;
242 case 0xf2: /*Read ID*/
243 keyboard_at_adddata_keyboard(0xfa);
244 keyboard_at_adddata_keyboard(0xab);
245 keyboard_at_adddata_keyboard(0x41);
246 break;
248 case 0xf3: /*Set typematic rate/delay*/
249 keyboard_at.key_wantdata = 1;
250 keyboard_at_adddata_keyboard(0xfa);
251 break;
253 case 0xf4: /*Enable keyboard*/
254 keyboard_scan = 1;
255 break;
257 case 0xff: /*Reset*/
258 key_queue_start = key_queue_end = 0; /*Clear key queue*/
259 keyboard_at_adddata_keyboard(0xfa);
260 keyboard_at_adddata_keyboard(0xaa);
261 break;
263 default:
264 pclog("Bad AT keyboard command %02X\n", val);
265 keyboard_at_adddata_keyboard(0xfe);
266 // dumpregs();
267 // exit(-1);
268 }
269 }
270 }
271 break;
273 case 0x61:
274 ppi.pb = val;
275 speaker_gated = val & 1;
276 speaker_enable = val & 2;
277 if (speaker_enable)
278 was_speaker_enable = 1;
279 pit_set_gate(2, val & 1);
280 break;
282 case 0x64:
283 keyboard_at.want60 = 0;
284 keyboard_at.command = val;
285 /*New controller command*/
286 switch (val)
287 {
288 case 0x20: case 0x21: case 0x22: case 0x23:
289 case 0x24: case 0x25: case 0x26: case 0x27:
290 case 0x28: case 0x29: case 0x2a: case 0x2b:
291 case 0x2c: case 0x2d: case 0x2e: case 0x2f:
292 case 0x30: case 0x31: case 0x32: case 0x33:
293 case 0x34: case 0x35: case 0x36: case 0x37:
294 case 0x38: case 0x39: case 0x3a: case 0x3b:
295 case 0x3c: case 0x3d: case 0x3e: case 0x3f:
296 keyboard_at_adddata(keyboard_at.mem[val & 0x1f]);
297 break;
299 case 0x60: case 0x61: case 0x62: case 0x63:
300 case 0x64: case 0x65: case 0x66: case 0x67:
301 case 0x68: case 0x69: case 0x6a: case 0x6b:
302 case 0x6c: case 0x6d: case 0x6e: case 0x6f:
303 case 0x70: case 0x71: case 0x72: case 0x73:
304 case 0x74: case 0x75: case 0x76: case 0x77:
305 case 0x78: case 0x79: case 0x7a: case 0x7b:
306 case 0x7c: case 0x7d: case 0x7e: case 0x7f:
307 keyboard_at.want60 = 1;
308 break;
310 case 0xa1: /*AMI - get controlled version*/
311 break;
313 case 0xa7: /*Disable mouse port*/
314 break;
316 case 0xa9: /*Test mouse port*/
317 keyboard_at_adddata(0x00); /*no error*/
318 break;
320 case 0xaa: /*Self-test*/
321 if (!keyboard_at.initialised)
322 {
323 keyboard_at.initialised = 1;
324 key_ctrl_queue_start = key_ctrl_queue_end = 0;
325 keyboard_at.status &= ~STAT_OFULL;
326 }
327 keyboard_at.status |= STAT_SYSFLAG;
328 keyboard_at.mem[0] |= 0x04;
329 keyboard_at_adddata(0x55);
330 break;
332 case 0xab: /*Interface test*/
333 keyboard_at_adddata(0x00); /*no error*/
334 break;
336 case 0xad: /*Disable keyboard*/
337 keyboard_at.mem[0] |= 0x10;
338 break;
340 case 0xae: /*Enable keyboard*/
341 keyboard_at.mem[0] &= ~0x10;
342 break;
344 case 0xc0: /*Read input port*/
345 keyboard_at_adddata(keyboard_at.input_port);
346 keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc);
347 break;
349 case 0xc9: /*AMI - block P22 and P23 ??? */
350 break;
352 case 0xca: /*AMI - read keyboard mode*/
353 keyboard_at_adddata(0x00); /*ISA mode*/
354 break;
356 case 0xcb: /*AMI - set keyboard mode*/
357 keyboard_at.want60 = 1;
358 break;
360 case 0xcf: /*??? - sent by MegaPC BIOS*/
361 keyboard_at.want60 = 1;
362 break;
364 case 0xd0: /*Read output port*/
365 keyboard_at_adddata(keyboard_at.output_port);
366 break;
368 case 0xd1: /*Write output port*/
369 keyboard_at.want60 = 1;
370 break;
372 case 0xd3: /*Write mouse output buffer*/
373 keyboard_at.want60 = 1;
374 break;
376 case 0xd4: /*Write to mouse*/
377 keyboard_at.want60 = 1;
378 break;
380 case 0xe0: /*Read test inputs*/
381 keyboard_at_adddata(0x00);
382 break;
384 case 0xef: /*??? - sent by AMI486*/
385 break;
387 case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/
388 softresetx86(); /*Pulse reset!*/
389 break;
391 case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/
392 break;
394 default:
395 pclog("Bad AT keyboard controller command %02X\n", val);
396 // dumpregs();
397 // exit(-1);
398 }
399 }
400 }
402 uint8_t keyboard_at_read(uint16_t port, void *priv)
403 {
404 uint8_t temp = 0xff;
405 cycles -= 4;
406 // if (port != 0x61) pclog("keyboard_at : read %04X ", port);
407 switch (port)
408 {
409 case 0x60:
410 temp = keyboard_at.out;
411 keyboard_at.status &= ~(STAT_OFULL | STAT_MFULL);
412 keyboard_at.wantirq = keyboard_at.wantirq12 = 0;
413 break;
415 case 0x61:
416 if (ppispeakon) return (ppi.pb&~0xC0)|0x20;
417 return ppi.pb&~0xC0;
418 break;
420 case 0x64:
421 temp = keyboard_at.status;
422 keyboard_at.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT);
423 break;
424 }
425 // if (port != 0x61) pclog("%02X %08X\n", temp, rammask);
426 return temp;
427 }
429 void keyboard_at_reset()
430 {
431 keyboard_at.initialised = 0;
432 keyboard_at.status = STAT_LOCK | STAT_CD;
433 keyboard_at.mem[0] = 0x11;
434 keyboard_at.wantirq = 0;
435 keyboard_at.output_port = 0;
436 keyboard_at.input_port = 0xb0;
438 keyboard_at.key_wantdata = 0;
440 keyboard_scan = 1;
441 }
443 void keyboard_at_init()
444 {
445 //return;
446 io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL, NULL);
447 keyboard_at_reset();
448 keyboard_send = keyboard_at_adddata_keyboard;
449 keyboard_poll = keyboard_at_poll;
450 mouse_write = NULL;
452 timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
453 }