- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / keyboard.cc
blob667d31c59b15bfc48bcaf857390c77ab23bae589
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: keyboard.cc,v 1.135 2008/09/18 17:18:36 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 // Now features proper implementation of keyboard opcodes 0xF4 to 0xF6
29 // Silently ignores PS/2 keyboard extensions (0xF7 to 0xFD)
30 // Explicit panic on resend (0xFE)
32 // Emmanuel Marty <core@ggi-project.org>
34 // NB: now the PS/2 mouse support is in, outb changes meaning
35 // in conjunction with auxb
36 // auxb == 0 && outb == 0 => both buffers empty (nothing to read)
37 // auxb == 0 && outb == 1 => keyboard controller output buffer full
38 // auxb == 1 && outb == 0 => not used
39 // auxb == 1 && outb == 1 => mouse output buffer full.
40 // (das)
42 // Notes from Christophe Bothamy <cbbochs@free.fr>
44 // This file includes code from Ludovic Lange (http://ludovic.lange.free.fr)
45 // Implementation of 3 scancodes sets mf1,mf2,mf3 with or without translation.
46 // Default is mf2 with translation
47 // Ability to switch between scancodes sets
48 // Ability to turn translation on or off
50 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
51 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
52 // is used to know when we are exporting symbols and when we are importing.
53 #define BX_PLUGGABLE
55 #include "iodev.h"
56 #include <math.h>
57 #include "scancodes.h"
59 #define LOG_THIS theKeyboard->
60 #define VERBOSE_KBD_DEBUG 0
63 bx_keyb_c *theKeyboard = NULL;
65 int libkeyboard_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
67 // Create one instance of the keyboard device object.
68 theKeyboard = new bx_keyb_c();
69 // Before this plugin was loaded, pluginKeyboard pointed to a stub.
70 // Now make it point to the real thing.
71 bx_devices.pluginKeyboard = theKeyboard;
72 // Register this device.
73 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theKeyboard, BX_PLUGIN_KEYBOARD);
74 return(0); // Success
77 void libkeyboard_LTX_plugin_fini(void)
79 delete theKeyboard;
82 bx_keyb_c::bx_keyb_c()
84 put("KBD");
85 settype(KBDLOG);
86 pastebuf = NULL;
89 bx_keyb_c::~bx_keyb_c()
91 // remove runtime parameter handler
92 SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set_handler(NULL);
93 SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->set_handler(NULL);
94 if (pastebuf != NULL) {
95 delete [] pastebuf;
97 #if BX_WITH_WX
98 bx_list_c *list = (bx_list_c*)SIM->get_param(BXPN_WX_KBD_STATE);
99 if (list != NULL) {
100 list->clear();
102 #endif
103 BX_DEBUG(("Exit"));
106 // flush internal buffer and reset keyboard settings to power-up condition
107 void bx_keyb_c::resetinternals(bx_bool powerup)
109 BX_KEY_THIS s.kbd_internal_buffer.num_elements = 0;
110 for (int i=0; i<BX_KBD_ELEMENTS; i++)
111 BX_KEY_THIS s.kbd_internal_buffer.buffer[i] = 0;
112 BX_KEY_THIS s.kbd_internal_buffer.head = 0;
114 BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
116 // Default scancode set is mf2 (translation is controlled by the 8042)
117 BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
118 BX_KEY_THIS s.kbd_controller.current_scancodes_set = 1;
120 if (powerup) {
121 BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
122 BX_KEY_THIS s.kbd_internal_buffer.delay = 1; // 500 mS
123 BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = 0x0b; // 10.9 chars/sec
127 void bx_keyb_c::init(void)
129 BX_DEBUG(("Init $Id: keyboard.cc,v 1.135 2008/09/18 17:18:36 sshwarts Exp $"));
130 Bit32u i;
132 DEV_register_irq(1, "8042 Keyboard controller");
133 DEV_register_irq(12, "8042 Keyboard controller (PS/2 mouse)");
135 DEV_register_ioread_handler(this, read_handler,
136 0x0060, "8042 Keyboard controller", 1);
137 DEV_register_ioread_handler(this, read_handler,
138 0x0064, "8042 Keyboard controller", 1);
139 DEV_register_iowrite_handler(this, write_handler,
140 0x0060, "8042 Keyboard controller", 1);
141 DEV_register_iowrite_handler(this, write_handler,
142 0x0064, "8042 Keyboard controller", 1);
143 BX_KEY_THIS timer_handle = bx_pc_system.register_timer(this, timer_handler,
144 SIM->get_param_num(BXPN_KBD_SERIAL_DELAY)->get(), 1, 1,
145 "8042 Keyboard controller");
147 resetinternals(1);
149 BX_KEY_THIS s.kbd_internal_buffer.led_status = 0;
150 BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
152 BX_KEY_THIS s.mouse_internal_buffer.num_elements = 0;
153 for (i=0; i<BX_MOUSE_BUFF_SIZE; i++)
154 BX_KEY_THIS s.mouse_internal_buffer.buffer[i] = 0;
155 BX_KEY_THIS s.mouse_internal_buffer.head = 0;
157 BX_KEY_THIS s.kbd_controller.pare = 0;
158 BX_KEY_THIS s.kbd_controller.tim = 0;
159 BX_KEY_THIS s.kbd_controller.auxb = 0;
160 BX_KEY_THIS s.kbd_controller.keyl = 1;
161 BX_KEY_THIS s.kbd_controller.c_d = 1;
162 BX_KEY_THIS s.kbd_controller.sysf = 0;
163 BX_KEY_THIS s.kbd_controller.inpb = 0;
164 BX_KEY_THIS s.kbd_controller.outb = 0;
166 BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
167 BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
168 BX_KEY_THIS s.kbd_controller.allow_irq1 = 1;
169 BX_KEY_THIS s.kbd_controller.allow_irq12 = 1;
170 BX_KEY_THIS s.kbd_controller.kbd_output_buffer = 0;
171 BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
172 BX_KEY_THIS s.kbd_controller.last_comm = 0;
173 BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
174 BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
175 BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
176 BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
177 BX_KEY_THIS s.kbd_controller.bat_in_progress = 0;
178 BX_KEY_THIS s.kbd_controller.scancodes_translate = 1;
180 BX_KEY_THIS s.kbd_controller.timer_pending = 0;
182 // Mouse initialization stuff
183 BX_KEY_THIS s.mouse.captured = SIM->get_param_bool(BXPN_MOUSE_ENABLED)->get();
184 BX_KEY_THIS s.mouse.type = SIM->get_param_enum(BXPN_MOUSE_TYPE)->get();
185 BX_KEY_THIS s.mouse.sample_rate = 100; // reports per second
186 BX_KEY_THIS s.mouse.resolution_cpmm = 4; // 4 counts per millimeter
187 BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
188 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_RESET;
189 BX_KEY_THIS s.mouse.enable = 0;
190 BX_KEY_THIS s.mouse.delayed_dx = 0;
191 BX_KEY_THIS s.mouse.delayed_dy = 0;
192 BX_KEY_THIS s.mouse.delayed_dz = 0;
193 BX_KEY_THIS s.mouse.im_request = 0; // wheel mouse mode request
194 BX_KEY_THIS s.mouse.im_mode = 0; // wheel mouse mode
196 for (i=0; i<BX_KBD_CONTROLLER_QSIZE; i++)
197 BX_KEY_THIS s.controller_Q[i] = 0;
198 BX_KEY_THIS s.controller_Qsize = 0;
199 BX_KEY_THIS s.controller_Qsource = 0;
201 // clear paste buffer
202 BX_KEY_THIS pastebuf = NULL;
203 BX_KEY_THIS pastebuf_len = 0;
204 BX_KEY_THIS pastebuf_ptr = 0;
205 BX_KEY_THIS paste_delay_changed(SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->get());
206 BX_KEY_THIS paste_service = 0;
207 BX_KEY_THIS stop_paste = 0;
209 // mouse port installed on system board
210 DEV_cmos_set_reg(0x14, DEV_cmos_get_reg(0x14) | 0x04);
212 // add keyboard LEDs to the statusbar
213 BX_KEY_THIS statusbar_id[0] = bx_gui->register_statusitem("NUM");
214 BX_KEY_THIS statusbar_id[1] = bx_gui->register_statusitem("CAPS");
215 BX_KEY_THIS statusbar_id[2] = bx_gui->register_statusitem("SCRL");
217 #if BX_WITH_WX
218 bx_param_num_c *param;
219 bx_list_c *list;
220 if (SIM->get_param("wxdebug") != NULL) {
221 // register shadow params (Experimental, not a complete list by far)
222 list = (bx_list_c*)SIM->get_param(BXPN_WX_KBD_STATE);
223 if (list == NULL) {
224 list = new bx_list_c(SIM->get_param("wxdebug"), "keyboard",
225 "Keyboard State", 20);
227 new bx_shadow_bool_c(list, "irq1_req",
228 "Keyboard IRQ1 requested",
229 &BX_KEY_THIS s.kbd_controller.irq1_requested);
230 new bx_shadow_bool_c(list, "irq12_req",
231 "Keyboard IRQ12 requested",
232 &BX_KEY_THIS s.kbd_controller.irq12_requested);
233 param = new bx_shadow_num_c(list, "timer_pending",
234 &BX_KEY_THIS s.kbd_controller.timer_pending);
235 param->set_label("Keyboard timer pending");
236 new bx_shadow_bool_c(list, "pare",
237 "Keyboard PARE",
238 &BX_KEY_THIS s.kbd_controller.pare);
239 new bx_shadow_bool_c(list, "tim",
240 "Keyboard TIM",
241 &BX_KEY_THIS s.kbd_controller.tim);
242 new bx_shadow_bool_c(list, "auxb",
243 "Keyboard AUXB",
244 &BX_KEY_THIS s.kbd_controller.auxb);
245 new bx_shadow_bool_c(list, "keyl",
246 "Keyboard KEYL",
247 &BX_KEY_THIS s.kbd_controller.keyl);
248 new bx_shadow_bool_c(list, "c_d",
249 "Keyboard C_D",
250 &BX_KEY_THIS s.kbd_controller.c_d);
251 new bx_shadow_bool_c(list, "sysf",
252 "Keyboard SYSF",
253 &BX_KEY_THIS s.kbd_controller.sysf);
254 new bx_shadow_bool_c(list, "inpb",
255 "Keyboard INPB",
256 &BX_KEY_THIS s.kbd_controller.inpb);
257 new bx_shadow_bool_c(list, "outb",
258 "Keyboard OUTB",
259 &BX_KEY_THIS s.kbd_controller.outb);
261 #endif
263 // init runtime parameters
264 SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set_handler(kbd_param_handler);
265 SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set_runtime_param(1);
266 SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->set_handler(kbd_param_handler);
267 SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->set_runtime_param(1);
270 void bx_keyb_c::reset(unsigned type)
272 if (BX_KEY_THIS pastebuf != NULL) {
273 BX_KEY_THIS stop_paste = 1;
277 void bx_keyb_c::register_state(void)
279 int i;
280 char name[4];
281 bx_list_c *buffer;
283 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "keyboard", "Keyboard State", 7);
284 bx_list_c *ctrl = new bx_list_c(list, "controller", 23);
285 BXRS_PARAM_BOOL(ctrl, tim, BX_KEY_THIS s.kbd_controller.tim);
286 BXRS_PARAM_BOOL(ctrl, auxb, BX_KEY_THIS s.kbd_controller.auxb);
287 BXRS_PARAM_BOOL(ctrl, c_d, BX_KEY_THIS s.kbd_controller.c_d);
288 BXRS_PARAM_BOOL(ctrl, sysf, BX_KEY_THIS s.kbd_controller.sysf);
289 BXRS_PARAM_BOOL(ctrl, inpb, BX_KEY_THIS s.kbd_controller.inpb);
290 BXRS_PARAM_BOOL(ctrl, outb, BX_KEY_THIS s.kbd_controller.outb);
291 BXRS_PARAM_BOOL(ctrl, kbd_clock_enabled, BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
292 BXRS_PARAM_BOOL(ctrl, aux_clock_enabled, BX_KEY_THIS s.kbd_controller.aux_clock_enabled);
293 BXRS_PARAM_BOOL(ctrl, allow_irq1, BX_KEY_THIS s.kbd_controller.allow_irq1);
294 BXRS_PARAM_BOOL(ctrl, allow_irq12, BX_KEY_THIS s.kbd_controller.allow_irq12);
295 BXRS_HEX_PARAM_FIELD(ctrl, kbd_output_buffer, BX_KEY_THIS s.kbd_controller.kbd_output_buffer);
296 BXRS_HEX_PARAM_FIELD(ctrl, aux_output_buffer, BX_KEY_THIS s.kbd_controller.aux_output_buffer);
297 BXRS_HEX_PARAM_FIELD(ctrl, last_comm, BX_KEY_THIS s.kbd_controller.last_comm);
298 BXRS_DEC_PARAM_FIELD(ctrl, expecting_port60h, BX_KEY_THIS s.kbd_controller.expecting_port60h);
299 BXRS_DEC_PARAM_FIELD(ctrl, expecting_mouse_parameter, BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter);
300 BXRS_HEX_PARAM_FIELD(ctrl, last_mouse_command, BX_KEY_THIS s.kbd_controller.last_mouse_command);
301 BXRS_DEC_PARAM_FIELD(ctrl, timer_pending, BX_KEY_THIS s.kbd_controller.timer_pending);
302 BXRS_PARAM_BOOL(ctrl, irq1_requested, BX_KEY_THIS s.kbd_controller.irq1_requested);
303 BXRS_PARAM_BOOL(ctrl, irq12_requested, BX_KEY_THIS s.kbd_controller.irq12_requested);
304 BXRS_PARAM_BOOL(ctrl, scancodes_translate, BX_KEY_THIS s.kbd_controller.scancodes_translate);
305 BXRS_PARAM_BOOL(ctrl, expecting_scancodes_set, BX_KEY_THIS s.kbd_controller.expecting_scancodes_set);
306 BXRS_DEC_PARAM_FIELD(ctrl, current_scancodes_set, BX_KEY_THIS s.kbd_controller.current_scancodes_set);
307 BXRS_PARAM_BOOL(ctrl, bat_in_progress, BX_KEY_THIS s.kbd_controller.bat_in_progress);
308 bx_list_c *mouse = new bx_list_c(list, "mouse", 12);
309 BXRS_DEC_PARAM_FIELD(mouse, sample_rate, BX_KEY_THIS s.mouse.sample_rate);
310 BXRS_DEC_PARAM_FIELD(mouse, resolution_cpmm, BX_KEY_THIS s.mouse.resolution_cpmm);
311 BXRS_DEC_PARAM_FIELD(mouse, scaling, BX_KEY_THIS s.mouse.scaling);
312 BXRS_DEC_PARAM_FIELD(mouse, mode, BX_KEY_THIS s.mouse.mode);
313 BXRS_DEC_PARAM_FIELD(mouse, saved_mode, BX_KEY_THIS s.mouse.saved_mode);
314 BXRS_PARAM_BOOL(mouse, enable, BX_KEY_THIS s.mouse.enable);
315 BXRS_DEC_PARAM_FIELD(mouse, button_status, BX_KEY_THIS s.mouse.button_status);
316 BXRS_DEC_PARAM_FIELD(mouse, delayed_dx, BX_KEY_THIS s.mouse.delayed_dx);
317 BXRS_DEC_PARAM_FIELD(mouse, delayed_dy, BX_KEY_THIS s.mouse.delayed_dy);
318 BXRS_DEC_PARAM_FIELD(mouse, delayed_dz, BX_KEY_THIS s.mouse.delayed_dz);
319 BXRS_DEC_PARAM_FIELD(mouse, im_request, BX_KEY_THIS s.mouse.im_request);
320 BXRS_PARAM_BOOL(mouse, im_mode, BX_KEY_THIS s.mouse.im_mode);
321 bx_list_c *kbdbuf = new bx_list_c(list, "kbd_internal_buffer", 9);
322 BXRS_DEC_PARAM_FIELD(kbdbuf, num_elements, BX_KEY_THIS s.kbd_internal_buffer.num_elements);
323 buffer = new bx_list_c(kbdbuf, "buffer", BX_KBD_ELEMENTS);
324 for (i=0; i<BX_KBD_ELEMENTS; i++) {
325 sprintf(name, "%d", i);
326 new bx_shadow_num_c(buffer, name, &BX_KEY_THIS s.kbd_internal_buffer.buffer[i], BASE_HEX);
328 BXRS_DEC_PARAM_FIELD(kbdbuf, head, BX_KEY_THIS s.kbd_internal_buffer.head);
329 BXRS_PARAM_BOOL(kbdbuf, expecting_typematic, BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic);
330 BXRS_PARAM_BOOL(kbdbuf, expecting_led_write, BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write);
331 BXRS_DEC_PARAM_FIELD(kbdbuf, delay, BX_KEY_THIS s.kbd_internal_buffer.delay);
332 BXRS_DEC_PARAM_FIELD(kbdbuf, repeat_rate, BX_KEY_THIS s.kbd_internal_buffer.repeat_rate);
333 BXRS_DEC_PARAM_FIELD(kbdbuf, led_status, BX_KEY_THIS s.kbd_internal_buffer.led_status);
334 BXRS_PARAM_BOOL(kbdbuf, scanning_enabled, BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled);
335 bx_list_c *mousebuf = new bx_list_c(list, "mouse_internal_buffer", 3);
336 BXRS_DEC_PARAM_FIELD(mousebuf, num_elements, BX_KEY_THIS s.mouse_internal_buffer.num_elements);
337 buffer = new bx_list_c(mousebuf, "buffer", BX_MOUSE_BUFF_SIZE);
338 for (i=0; i<BX_MOUSE_BUFF_SIZE; i++) {
339 sprintf(name, "%d", i);
340 new bx_shadow_num_c(buffer, name, &BX_KEY_THIS s.mouse_internal_buffer.buffer[i], BASE_HEX);
342 BXRS_DEC_PARAM_FIELD(mousebuf, head, BX_KEY_THIS s.mouse_internal_buffer.head);
343 buffer = new bx_list_c(list, "controller_Q", BX_KBD_CONTROLLER_QSIZE);
344 for (i=0; i<BX_KBD_CONTROLLER_QSIZE; i++) {
345 sprintf(name, "%d", i);
346 new bx_shadow_num_c(buffer, name, &BX_KEY_THIS s.controller_Q[i], BASE_HEX);
348 BXRS_DEC_PARAM_FIELD(list, controller_Qsize, BX_KEY_THIS s.controller_Qsize);
349 BXRS_DEC_PARAM_FIELD(list, controller_Qsource, BX_KEY_THIS s.controller_Qsource);
352 void bx_keyb_c::after_restore_state(void)
354 Bit8u value = BX_KEY_THIS s.kbd_internal_buffer.led_status;
355 if (value != 0) {
356 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[0], value & 0x02);
357 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[1], value & 0x04);
358 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[2], value & 0x01);
362 Bit64s bx_keyb_c::kbd_param_handler(bx_param_c *param, int set, Bit64s val)
364 if (set) {
365 char pname[BX_PATHNAME_LEN];
366 param->get_param_path(pname, BX_PATHNAME_LEN);
367 if (!strcmp(pname, BXPN_MOUSE_ENABLED)) {
368 bx_gui->mouse_enabled_changed(val!=0);
369 BX_KEY_THIS mouse_enabled_changed(val!=0);
370 } else if (!strcmp(pname, BXPN_KBD_PASTE_DELAY)) {
371 BX_KEY_THIS paste_delay_changed((Bit32u)val);
372 } else {
373 BX_PANIC(("kbd_param_handler called with unexpected parameter '%s'", pname));
376 return val;
379 void bx_keyb_c::paste_delay_changed(Bit32u value)
381 BX_KEY_THIS pastedelay = value / BX_IODEV_HANDLER_PERIOD;
382 BX_INFO(("will paste characters every %d keyboard ticks",BX_KEY_THIS pastedelay));
385 // static IO port read callback handler
386 // redirects to non-static class handler to avoid virtual functions
388 // read function - the big picture:
389 // if address == data port then
390 // if byte for mouse then return it
391 // else if byte for keyboard then return it
392 // else address== status port
393 // assemble the status bits and return them.
395 Bit32u bx_keyb_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
397 #if !BX_USE_KEY_SMF
398 bx_keyb_c *class_ptr = (bx_keyb_c *)this_ptr;
400 return (class_ptr->read(address, io_len));
403 Bit32u bx_keyb_c::read(Bit32u address, unsigned io_len)
405 #else
406 UNUSED(this_ptr);
407 #endif // !BX_USE_KEY_SMF
408 Bit8u val;
410 if (address == 0x60) { /* output buffer */
411 if (BX_KEY_THIS s.kbd_controller.auxb) { /* mouse byte available */
412 val = BX_KEY_THIS s.kbd_controller.aux_output_buffer;
413 BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
414 BX_KEY_THIS s.kbd_controller.outb = 0;
415 BX_KEY_THIS s.kbd_controller.auxb = 0;
416 BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
418 if (BX_KEY_THIS s.controller_Qsize) {
419 unsigned i;
420 BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
421 BX_KEY_THIS s.kbd_controller.outb = 1;
422 BX_KEY_THIS s.kbd_controller.auxb = 1;
423 if (BX_KEY_THIS s.kbd_controller.allow_irq12)
424 BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
425 for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
426 // move Q elements towards head of queue by one
427 BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
429 BX_KEY_THIS s.controller_Qsize--;
432 DEV_pic_lower_irq(12);
433 activate_timer();
434 BX_DEBUG(("[mouse] read from 0x%02x returns 0x%02x", address, val));
435 return val;
437 else if (BX_KEY_THIS s.kbd_controller.outb) { /* kbd byte available */
438 val = BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
439 BX_KEY_THIS s.kbd_controller.outb = 0;
440 BX_KEY_THIS s.kbd_controller.auxb = 0;
441 BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
442 BX_KEY_THIS s.kbd_controller.bat_in_progress = 0;
444 if (BX_KEY_THIS s.controller_Qsize) {
445 unsigned i;
446 BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
447 BX_KEY_THIS s.kbd_controller.outb = 1;
448 BX_KEY_THIS s.kbd_controller.auxb = 1;
449 if (BX_KEY_THIS s.kbd_controller.allow_irq1)
450 BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
451 for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
452 // move Q elements towards head of queue by one
453 BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
455 BX_DEBUG(("s.controller_Qsize: %02X",BX_KEY_THIS s.controller_Qsize));
456 BX_KEY_THIS s.controller_Qsize--;
459 DEV_pic_lower_irq(1);
460 activate_timer();
461 BX_DEBUG(("READ(%02x) = %02x", (unsigned) address, (unsigned) val));
462 return val;
464 else {
465 BX_DEBUG(("num_elements = %d", BX_KEY_THIS s.kbd_internal_buffer.num_elements));
466 BX_DEBUG(("read from port 60h with outb empty"));
467 return BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
471 #if BX_CPU_LEVEL >= 2
472 else if (address == 0x64) { /* status register */
473 val = (BX_KEY_THIS s.kbd_controller.pare << 7) |
474 (BX_KEY_THIS s.kbd_controller.tim << 6) |
475 (BX_KEY_THIS s.kbd_controller.auxb << 5) |
476 (BX_KEY_THIS s.kbd_controller.keyl << 4) |
477 (BX_KEY_THIS s.kbd_controller.c_d << 3) |
478 (BX_KEY_THIS s.kbd_controller.sysf << 2) |
479 (BX_KEY_THIS s.kbd_controller.inpb << 1) |
480 BX_KEY_THIS s.kbd_controller.outb;
481 BX_KEY_THIS s.kbd_controller.tim = 0;
482 return val;
485 #else /* BX_CPU_LEVEL > 0 */
486 /* XT MODE, System 8255 Mode Register */
487 else if (address == 0x64) { /* status register */
488 BX_DEBUG(("IO read from port 64h, system 8255 mode register"));
489 return BX_KEY_THIS s.kbd_controller.outb;
491 #endif /* BX_CPU_LEVEL > 0 */
493 BX_PANIC(("unknown address in io read to keyboard port %x",
494 (unsigned) address));
495 return 0; /* keep compiler happy */
498 // static IO port write callback handler
499 // redirects to non-static class handler to avoid virtual functions
501 void bx_keyb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
503 #if !BX_USE_KEY_SMF
504 bx_keyb_c *class_ptr = (bx_keyb_c *)this_ptr;
505 class_ptr->write(address, value, io_len);
508 void bx_keyb_c::write(Bit32u address, Bit32u value, unsigned io_len)
510 #else
511 UNUSED(this_ptr);
512 #endif // !BX_USE_KEY_SMF
513 Bit8u command_byte;
514 static int kbd_initialized=0;
516 BX_DEBUG(("keyboard: 8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
518 switch (address) {
519 case 0x60: // input buffer
520 // if expecting data byte from command last sent to port 64h
521 if (BX_KEY_THIS s.kbd_controller.expecting_port60h) {
522 BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
523 // data byte written last to 0x60
524 BX_KEY_THIS s.kbd_controller.c_d = 0;
525 if (BX_KEY_THIS s.kbd_controller.inpb) {
526 BX_PANIC(("write to port 60h, not ready for write"));
528 switch (BX_KEY_THIS s.kbd_controller.last_comm) {
529 case 0x60: // write command byte
531 bx_bool scan_convert, disable_keyboard,
532 disable_aux;
534 scan_convert = (value >> 6) & 0x01;
535 disable_aux = (value >> 5) & 0x01;
536 disable_keyboard = (value >> 4) & 0x01;
537 BX_KEY_THIS s.kbd_controller.sysf = (value >> 2) & 0x01;
538 BX_KEY_THIS s.kbd_controller.allow_irq1 = (value >> 0) & 0x01;
539 BX_KEY_THIS s.kbd_controller.allow_irq12 = (value >> 1) & 0x01;
540 set_kbd_clock_enable(!disable_keyboard);
541 set_aux_clock_enable(!disable_aux);
542 if (BX_KEY_THIS s.kbd_controller.allow_irq12 && BX_KEY_THIS s.kbd_controller.auxb)
543 BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
544 else if (BX_KEY_THIS s.kbd_controller.allow_irq1 && BX_KEY_THIS s.kbd_controller.outb)
545 BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
547 BX_DEBUG((" allow_irq12 set to %u",
548 (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12));
549 if (!scan_convert)
550 BX_INFO(("keyboard: scan convert turned off"));
552 // (mch) NT needs this
553 BX_KEY_THIS s.kbd_controller.scancodes_translate = scan_convert;
555 break;
556 case 0xcb: // write keyboard controller mode
557 BX_DEBUG(("write keyboard controller mode with value %02xh", (unsigned) value));
558 break;
559 case 0xd1: // write output port
560 BX_DEBUG(("write output port with value %02xh", (unsigned) value));
561 BX_DEBUG(("write output port : %sable A20",(value & 0x02)?"en":"dis"));
562 BX_SET_ENABLE_A20((value & 0x02) != 0);
563 if (!(value & 0x01)) {
564 BX_INFO(("write output port : processor reset requested!"));
565 bx_pc_system.Reset(BX_RESET_SOFTWARE);
567 break;
568 case 0xd4: // Write to mouse
569 // I don't think this enables the AUX clock
570 //set_aux_clock_enable(1); // enable aux clock line
571 kbd_ctrl_to_mouse(value);
572 // ??? should I reset to previous value of aux enable?
573 break;
575 case 0xd3: // write mouse output buffer
576 // Queue in mouse output buffer
577 controller_enQ(value, 1);
578 break;
580 case 0xd2:
581 // Queue in keyboard output buffer
582 controller_enQ(value, 0);
583 break;
585 default:
586 BX_PANIC(("=== unsupported write to port 60h(lastcomm=%02x): %02x",
587 (unsigned) BX_KEY_THIS s.kbd_controller.last_comm, (unsigned) value));
589 } else {
590 // data byte written last to 0x60
591 BX_KEY_THIS s.kbd_controller.c_d = 0;
592 BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
593 /* pass byte to keyboard */
594 /* ??? should conditionally pass to mouse device here ??? */
595 if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0) {
596 set_kbd_clock_enable(1);
598 kbd_ctrl_to_kbd(value);
600 break;
602 case 0x64: // control register
603 // command byte written last to 0x64
604 BX_KEY_THIS s.kbd_controller.c_d = 1;
605 BX_KEY_THIS s.kbd_controller.last_comm = value;
606 // most commands NOT expecting port60 write next
607 BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
609 switch (value) {
610 case 0x20: // get keyboard command byte
611 BX_DEBUG(("get keyboard command byte"));
612 // controller output buffer must be empty
613 if (BX_KEY_THIS s.kbd_controller.outb) {
614 BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
615 break;
617 command_byte =
618 (BX_KEY_THIS s.kbd_controller.scancodes_translate << 6) |
619 ((!BX_KEY_THIS s.kbd_controller.aux_clock_enabled) << 5) |
620 ((!BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) << 4) |
621 (0 << 3) |
622 (BX_KEY_THIS s.kbd_controller.sysf << 2) |
623 (BX_KEY_THIS s.kbd_controller.allow_irq12 << 1) |
624 (BX_KEY_THIS s.kbd_controller.allow_irq1 << 0);
625 controller_enQ(command_byte, 0);
626 break;
627 case 0x60: // write command byte
628 BX_DEBUG(("write command byte"));
629 // following byte written to port 60h is command byte
630 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
631 break;
633 case 0xa0:
634 BX_DEBUG(("keyboard BIOS name not supported"));
635 break;
637 case 0xa1:
638 BX_DEBUG(("keyboard BIOS version not supported"));
639 break;
641 case 0xa7: // disable the aux device
642 set_aux_clock_enable(0);
643 BX_DEBUG(("aux device disabled"));
644 break;
645 case 0xa8: // enable the aux device
646 set_aux_clock_enable(1);
647 BX_DEBUG(("aux device enabled"));
648 break;
649 case 0xa9: // Test Mouse Port
650 // controller output buffer must be empty
651 if (BX_KEY_THIS s.kbd_controller.outb) {
652 BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
653 break;
655 controller_enQ(0x00, 0); // no errors detected
656 break;
657 case 0xaa: // motherboard controller self test
658 BX_DEBUG(("Self Test"));
659 if (kbd_initialized == 0) {
660 BX_KEY_THIS s.controller_Qsize = 0;
661 BX_KEY_THIS s.kbd_controller.outb = 0;
662 kbd_initialized++;
664 // controller output buffer must be empty
665 if (BX_KEY_THIS s.kbd_controller.outb) {
666 BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
667 break;
669 // (mch) Why is this commented out??? Enabling
670 BX_KEY_THIS s.kbd_controller.sysf = 1; // self test complete
671 controller_enQ(0x55, 0); // controller OK
672 break;
673 case 0xab: // Interface Test
674 // controller output buffer must be empty
675 if (BX_KEY_THIS s.kbd_controller.outb) {
676 BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
677 break;
679 controller_enQ(0x00, 0);
680 break;
681 case 0xad: // disable keyboard
682 set_kbd_clock_enable(0);
683 BX_DEBUG(("keyboard disabled"));
684 break;
685 case 0xae: // enable keyboard
686 set_kbd_clock_enable(1);
687 BX_DEBUG(("keyboard enabled"));
688 break;
689 case 0xaf: // get controller version
690 BX_INFO(("'get controller version' not supported yet"));
691 break;
692 case 0xc0: // read input port
693 // controller output buffer must be empty
694 if (BX_KEY_THIS s.kbd_controller.outb) {
695 BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
696 break;
698 // keyboard not inhibited
699 controller_enQ(0x80, 0);
700 break;
701 case 0xca: // read keyboard controller mode
702 controller_enQ(0x01, 0); // PS/2 (MCA)interface
703 break;
704 case 0xcb: // write keyboard controller mode
705 BX_DEBUG(("write keyboard controller mode"));
706 // write keyboard controller mode to bit 0 of port 0x60
707 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
708 break;
709 case 0xd0: // read output port: next byte read from port 60h
710 BX_DEBUG(("io write to port 64h, command d0h (partial)"));
711 // controller output buffer must be empty
712 if (BX_KEY_THIS s.kbd_controller.outb) {
713 BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
714 break;
716 controller_enQ(
717 (BX_KEY_THIS s.kbd_controller.irq12_requested << 5) |
718 (BX_KEY_THIS s.kbd_controller.irq1_requested << 4) |
719 (BX_GET_ENABLE_A20() << 1) |
720 0x01, 0);
721 break;
723 case 0xd1: // write output port: next byte written to port 60h
724 BX_DEBUG(("write output port"));
725 // following byte to port 60h written to output port
726 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
727 break;
729 case 0xd3: // write mouse output buffer
730 //FIXME: Why was this a panic?
731 BX_DEBUG(("io write 0x64: command = 0xD3(write mouse outb)"));
732 // following byte to port 60h written to output port as mouse write.
733 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
734 break;
736 case 0xd4: // write to mouse
737 BX_DEBUG(("io write 0x64: command = 0xD4 (write to mouse)"));
738 // following byte written to port 60h
739 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
740 break;
742 case 0xd2: // write keyboard output buffer
743 BX_DEBUG(("io write 0x64: write keyboard output buffer"));
744 BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
745 break;
746 case 0xdd: // Disable A20 Address Line
747 BX_SET_ENABLE_A20(0);
748 break;
749 case 0xdf: // Enable A20 Address Line
750 BX_SET_ENABLE_A20(1);
751 break;
752 case 0xc1: // Continuous Input Port Poll, Low
753 case 0xc2: // Continuous Input Port Poll, High
754 case 0xe0: // Read Test Inputs
755 BX_PANIC(("io write 0x64: command = %02xh", (unsigned) value));
756 break;
758 case 0xfe: // System (cpu?) Reset, transition to real mode
759 BX_INFO(("io write 0x64: command 0xfe: reset cpu"));
760 bx_pc_system.Reset(BX_RESET_SOFTWARE);
761 break;
763 default:
764 if (value==0xff || (value>=0xf0 && value<=0xfd)) {
765 /* useless pulse output bit commands ??? */
766 BX_DEBUG(("io write to port 64h, useless command %02x",
767 (unsigned) value));
768 return;
770 BX_ERROR(("unsupported io write to keyboard port %x, value = %x",
771 (unsigned) address, (unsigned) value));
772 break;
774 break;
776 default:
777 BX_PANIC(("unknown address in bx_keyb_c::write()"));
781 // service_paste_buf() transfers data from the paste buffer to the hardware
782 // keyboard buffer. It tries to transfer as many chars as possible at a
783 // time, but because different chars require different numbers of scancodes
784 // we have to be conservative. Note that this process depends on the
785 // keymap tables to know what chars correspond to what keys, and which
786 // chars require a shift or other modifier.
787 void bx_keyb_c::service_paste_buf()
789 if (!BX_KEY_THIS pastebuf) return;
790 BX_DEBUG(("service_paste_buf: ptr at %d out of %d", BX_KEY_THIS pastebuf_ptr, BX_KEY_THIS pastebuf_len));
791 int fill_threshold = BX_KBD_ELEMENTS - 8;
792 BX_KEY_THIS paste_service = 1;
793 while ((BX_KEY_THIS pastebuf_ptr < BX_KEY_THIS pastebuf_len) && !BX_KEY_THIS stop_paste) {
794 if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= fill_threshold) {
795 BX_KEY_THIS paste_service = 0;
796 return;
798 // there room in the buffer for a keypress and a key release.
799 // send one keypress and a key release.
800 Bit8u byte = BX_KEY_THIS pastebuf[BX_KEY_THIS pastebuf_ptr];
801 BXKeyEntry *entry = bx_keymap.findAsciiChar(byte);
802 if (!entry) {
803 BX_ERROR(("paste character 0x%02x ignored", byte));
804 } else {
805 BX_DEBUG(("pasting character 0x%02x. baseKey is %04x", byte, entry->baseKey));
806 if (entry->modKey != BX_KEYMAP_UNKNOWN)
807 BX_KEY_THIS gen_scancode(entry->modKey);
808 BX_KEY_THIS gen_scancode(entry->baseKey);
809 BX_KEY_THIS gen_scancode(entry->baseKey | BX_KEY_RELEASED);
810 if (entry->modKey != BX_KEYMAP_UNKNOWN)
811 BX_KEY_THIS gen_scancode(entry->modKey | BX_KEY_RELEASED);
813 BX_KEY_THIS pastebuf_ptr++;
815 // reached end of pastebuf. free the memory it was using.
816 delete [] BX_KEY_THIS pastebuf;
817 BX_KEY_THIS pastebuf = NULL;
818 BX_KEY_THIS stop_paste = 0;
819 BX_KEY_THIS paste_service = 0;
822 // paste_bytes schedules an arbitrary number of ASCII characters to be
823 // inserted into the hardware queue as it become available. Any previous
824 // paste which is still in progress will be thrown out. BYTES is a pointer
825 // to a region of memory containing the chars to be pasted. When the paste
826 // is complete, the keyboard code will call delete [] bytes;
827 void bx_keyb_c::paste_bytes(Bit8u *bytes, Bit32s length)
829 BX_DEBUG(("paste_bytes: %d bytes", length));
830 if (BX_KEY_THIS pastebuf) {
831 BX_ERROR(("previous paste was not completed! %d chars lost",
832 BX_KEY_THIS pastebuf_len - BX_KEY_THIS pastebuf_ptr));
833 delete [] BX_KEY_THIS pastebuf; // free the old paste buffer
835 BX_KEY_THIS pastebuf = bytes;
836 BX_KEY_THIS pastebuf_ptr = 0;
837 BX_KEY_THIS pastebuf_len = length;
838 BX_KEY_THIS service_paste_buf();
841 void bx_keyb_c::gen_scancode(Bit32u key)
843 unsigned char *scancode;
844 Bit8u i;
846 if ((BX_KEY_THIS pastebuf != NULL) && (!BX_KEY_THIS paste_service)) {
847 BX_KEY_THIS stop_paste = 1;
848 return;
851 BX_DEBUG(("gen_scancode(): %s %s", bx_keymap.getBXKeyName(key), (key >> 31)?"released":"pressed"));
853 if (!BX_KEY_THIS s.kbd_controller.scancodes_translate)
854 BX_DEBUG(("keyboard: gen_scancode with scancode_translate cleared"));
856 // Ignore scancode if keyboard clock is driven low
857 if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0)
858 return;
860 // Ignore scancode if scanning is disabled
861 if (BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled==0)
862 return;
864 // Switch between make and break code
865 if (key & BX_KEY_RELEASED)
866 scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].brek;
867 else
868 scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].make;
870 #if BX_SUPPORT_PCIUSB
871 if (DEV_usb_keyboard_connected()) {
872 // if we have a keyboard/keypad installed, we need to call its handler first
873 if (DEV_usb_key_enq(scancode)) return;
875 #endif
877 if (BX_KEY_THIS s.kbd_controller.scancodes_translate) {
878 // Translate before send
879 Bit8u escaped=0x00;
881 for (i=0; i<strlen((const char *)scancode); i++) {
882 if (scancode[i] == 0xF0)
883 escaped=0x80;
884 else {
885 BX_DEBUG(("gen_scancode(): writing translated %02x",translation8042[scancode[i] ] | escaped));
886 kbd_enQ(translation8042[scancode[i]] | escaped);
887 escaped=0x00;
891 else {
892 // Send raw data
893 for (i=0; i<strlen((const char *)scancode); i++) {
894 BX_DEBUG(("gen_scancode(): writing raw %02x",scancode[i]));
895 kbd_enQ(scancode[i]);
901 void BX_CPP_AttrRegparmN(1)
902 bx_keyb_c::set_kbd_clock_enable(Bit8u value)
904 bx_bool prev_kbd_clock_enabled;
906 if (value==0) {
907 BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 0;
908 } else {
909 /* is another byte waiting to be sent from the keyboard ? */
910 prev_kbd_clock_enabled = BX_KEY_THIS s.kbd_controller.kbd_clock_enabled;
911 BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
913 if (prev_kbd_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0) {
914 activate_timer();
919 void bx_keyb_c::set_aux_clock_enable(Bit8u value)
921 bx_bool prev_aux_clock_enabled;
923 BX_DEBUG(("set_aux_clock_enable(%u)", (unsigned) value));
924 if (value==0) {
925 BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
926 } else {
927 /* is another byte waiting to be sent from the keyboard ? */
928 prev_aux_clock_enabled = BX_KEY_THIS s.kbd_controller.aux_clock_enabled;
929 BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 1;
930 if (prev_aux_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0)
931 activate_timer();
935 Bit8u bx_keyb_c::get_kbd_enable(void)
937 BX_DEBUG(("get_kbd_enable(): getting kbd_clock_enabled of: %02x",
938 (unsigned) BX_KEY_THIS s.kbd_controller.kbd_clock_enabled));
940 return(BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
943 void bx_keyb_c::controller_enQ(Bit8u data, unsigned source)
945 // source is 0 for keyboard, 1 for mouse
947 BX_DEBUG(("controller_enQ(%02x) source=%02x", (unsigned) data,source));
949 // see if we need to Q this byte from the controller
950 // remember this includes mouse bytes.
951 if (BX_KEY_THIS s.kbd_controller.outb) {
952 if (BX_KEY_THIS s.controller_Qsize >= BX_KBD_CONTROLLER_QSIZE)
953 BX_PANIC(("controller_enq(): controller_Q full!"));
954 BX_KEY_THIS s.controller_Q[BX_KEY_THIS s.controller_Qsize++] = data;
955 BX_KEY_THIS s.controller_Qsource = source;
956 return;
959 // the Q is empty
960 if (source == 0) { // keyboard
961 BX_KEY_THIS s.kbd_controller.kbd_output_buffer = data;
962 BX_KEY_THIS s.kbd_controller.outb = 1;
963 BX_KEY_THIS s.kbd_controller.auxb = 0;
964 BX_KEY_THIS s.kbd_controller.inpb = 0;
965 if (BX_KEY_THIS s.kbd_controller.allow_irq1)
966 BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
967 } else { // mouse
968 BX_KEY_THIS s.kbd_controller.aux_output_buffer = data;
969 BX_KEY_THIS s.kbd_controller.outb = 1;
970 BX_KEY_THIS s.kbd_controller.auxb = 1;
971 BX_KEY_THIS s.kbd_controller.inpb = 0;
972 if (BX_KEY_THIS s.kbd_controller.allow_irq12)
973 BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
977 void bx_keyb_c::kbd_enQ_imm(Bit8u val)
979 int tail;
981 if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
982 BX_PANIC(("internal keyboard buffer full (imm)"));
983 return;
986 /* enqueue scancode in multibyte internal keyboard buffer */
987 tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
988 BX_KBD_ELEMENTS;
990 BX_KEY_THIS s.kbd_controller.kbd_output_buffer = val;
991 BX_KEY_THIS s.kbd_controller.outb = 1;
993 if (BX_KEY_THIS s.kbd_controller.allow_irq1)
994 BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
997 void bx_keyb_c::kbd_enQ(Bit8u scancode)
999 int tail;
1001 BX_DEBUG(("kbd_enQ(0x%02x)", (unsigned) scancode));
1003 if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
1004 BX_INFO(("internal keyboard buffer full, ignoring scancode.(%02x)",
1005 (unsigned) scancode));
1006 return;
1009 /* enqueue scancode in multibyte internal keyboard buffer */
1010 BX_DEBUG(("kbd_enQ: putting scancode 0x%02x in internal buffer",
1011 (unsigned) scancode));
1012 tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
1013 BX_KBD_ELEMENTS;
1014 BX_KEY_THIS s.kbd_internal_buffer.buffer[tail] = scancode;
1015 BX_KEY_THIS s.kbd_internal_buffer.num_elements++;
1017 if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) {
1018 activate_timer();
1019 BX_DEBUG(("activating timer..."));
1020 return;
1024 bx_bool bx_keyb_c::mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3, Bit8u b4)
1026 int bytes = 3;
1027 if (BX_KEY_THIS s.mouse.im_mode) bytes = 4;
1029 if ((BX_KEY_THIS s.mouse_internal_buffer.num_elements + bytes) >= BX_MOUSE_BUFF_SIZE) {
1030 return(0); /* buffer doesn't have the space */
1033 mouse_enQ(b1);
1034 mouse_enQ(b2);
1035 mouse_enQ(b3);
1036 if (BX_KEY_THIS s.mouse.im_mode) mouse_enQ(b4);
1038 return(1);
1041 void bx_keyb_c::mouse_enQ(Bit8u mouse_data)
1043 int tail;
1045 BX_DEBUG(("mouse_enQ(%02x)", (unsigned) mouse_data));
1047 if (BX_KEY_THIS s.mouse_internal_buffer.num_elements >= BX_MOUSE_BUFF_SIZE) {
1048 BX_ERROR(("[mouse] internal mouse buffer full, ignoring mouse data.(%02x)",
1049 (unsigned) mouse_data));
1050 return;
1053 /* enqueue mouse data in multibyte internal mouse buffer */
1054 tail = (BX_KEY_THIS s.mouse_internal_buffer.head + BX_KEY_THIS s.mouse_internal_buffer.num_elements) %
1055 BX_MOUSE_BUFF_SIZE;
1056 BX_KEY_THIS s.mouse_internal_buffer.buffer[tail] = mouse_data;
1057 BX_KEY_THIS s.mouse_internal_buffer.num_elements++;
1059 if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.aux_clock_enabled) {
1060 activate_timer();
1061 return;
1065 void bx_keyb_c::kbd_ctrl_to_kbd(Bit8u value)
1068 BX_DEBUG(("controller passed byte %02xh to keyboard", value));
1070 if (BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic) {
1071 BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
1072 BX_KEY_THIS s.kbd_internal_buffer.delay = (value >> 5) & 0x03;
1073 switch (BX_KEY_THIS s.kbd_internal_buffer.delay) {
1074 case 0: BX_INFO(("setting delay to 250 mS (unused)")); break;
1075 case 1: BX_INFO(("setting delay to 500 mS (unused)")); break;
1076 case 2: BX_INFO(("setting delay to 750 mS (unused)")); break;
1077 case 3: BX_INFO(("setting delay to 1000 mS (unused)")); break;
1079 BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = value & 0x1f;
1080 double cps = 1 /((double)(8 + (value & 0x07)) * (double)exp(log((double)2) * (double)((value >> 3) & 0x03)) * 0.00417);
1081 BX_INFO(("setting repeat rate to %.1f cps (unused)", cps));
1082 kbd_enQ(0xFA); // send ACK
1083 return;
1086 if (BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write) {
1087 BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
1088 BX_KEY_THIS s.kbd_internal_buffer.led_status = value;
1089 BX_DEBUG(("LED status set to %02x",
1090 (unsigned) BX_KEY_THIS s.kbd_internal_buffer.led_status));
1091 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[0], value & 0x02);
1092 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[1], value & 0x04);
1093 bx_gui->statusbar_setitem(BX_KEY_THIS statusbar_id[2], value & 0x01);
1094 kbd_enQ(0xFA); // send ACK %%%
1095 return;
1098 if (BX_KEY_THIS s.kbd_controller.expecting_scancodes_set) {
1099 BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
1100 if(value != 0) {
1101 if(value < 4) {
1102 BX_KEY_THIS s.kbd_controller.current_scancodes_set = (value-1);
1103 BX_INFO(("Switched to scancode set %d",
1104 (unsigned) BX_KEY_THIS s.kbd_controller.current_scancodes_set + 1));
1105 kbd_enQ(0xFA);
1106 } else {
1107 BX_ERROR(("Received scancodes set out of range: %d", value));
1108 kbd_enQ(0xFF); // send ERROR
1110 } else {
1111 // Send ACK (SF patch #1159626)
1112 kbd_enQ(0xFA);
1113 // Send current scancodes set to port 0x60
1114 kbd_enQ(1 + (BX_KEY_THIS s.kbd_controller.current_scancodes_set));
1116 return;
1119 switch (value) {
1120 case 0x00: // ??? ignore and let OS timeout with no response
1121 kbd_enQ(0xFA); // send ACK %%%
1122 break;
1124 case 0x05: // ???
1125 // (mch) trying to get this to work...
1126 BX_KEY_THIS s.kbd_controller.sysf = 1;
1127 kbd_enQ_imm(0xfe);
1128 break;
1130 case 0xed: // LED Write
1131 BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 1;
1132 kbd_enQ_imm(0xFA); // send ACK %%%
1133 break;
1135 case 0xee: // echo
1136 kbd_enQ(0xEE); // return same byte (EEh) as echo diagnostic
1137 break;
1139 case 0xf0: // Select alternate scan code set
1140 BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 1;
1141 BX_DEBUG(("Expecting scancode set info..."));
1142 kbd_enQ(0xFA); // send ACK
1143 break;
1145 case 0xf2: // identify keyboard
1146 BX_INFO(("identify keyboard command received"));
1148 // XT sends nothing, AT sends ACK
1149 // MFII with translation sends ACK+ABh+41h
1150 // MFII without translation sends ACK+ABh+83h
1151 if (SIM->get_param_enum(BXPN_KBD_TYPE)->get() != BX_KBD_XT_TYPE) {
1152 kbd_enQ(0xFA);
1153 if (SIM->get_param_enum(BXPN_KBD_TYPE)->get() == BX_KBD_MF_TYPE) {
1154 kbd_enQ(0xAB);
1156 if(BX_KEY_THIS s.kbd_controller.scancodes_translate)
1157 kbd_enQ(0x41);
1158 else
1159 kbd_enQ(0x83);
1162 break;
1164 case 0xf3: // typematic info
1165 BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 1;
1166 BX_INFO(("setting typematic info"));
1167 kbd_enQ(0xFA); // send ACK
1168 break;
1170 case 0xf4: // enable keyboard
1171 BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
1172 kbd_enQ(0xFA); // send ACK
1173 break;
1175 case 0xf5: // reset keyboard to power-up settings and disable scanning
1176 resetinternals(1);
1177 kbd_enQ(0xFA); // send ACK
1178 BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 0;
1179 BX_INFO(("reset-disable command received"));
1180 break;
1182 case 0xf6: // reset keyboard to power-up settings and enable scanning
1183 resetinternals(1);
1184 kbd_enQ(0xFA); // send ACK
1185 BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
1186 BX_INFO(("reset-enable command received"));
1187 break;
1189 case 0xfe: // resend. aiiee.
1190 BX_PANIC(("got 0xFE (resend)"));
1191 break;
1193 case 0xff: // reset: internal keyboard reset and afterwards the BAT
1194 BX_DEBUG(("reset command received"));
1195 resetinternals(1);
1196 kbd_enQ(0xFA); // send ACK
1197 BX_KEY_THIS s.kbd_controller.bat_in_progress = 1;
1198 kbd_enQ(0xAA); // BAT test passed
1199 break;
1201 case 0xd3:
1202 kbd_enQ(0xfa);
1203 break;
1205 case 0xf7: // PS/2 Set All Keys To Typematic
1206 case 0xf8: // PS/2 Set All Keys to Make/Break
1207 case 0xf9: // PS/2 PS/2 Set All Keys to Make
1208 case 0xfa: // PS/2 Set All Keys to Typematic Make/Break
1209 case 0xfb: // PS/2 Set Key Type to Typematic
1210 case 0xfc: // PS/2 Set Key Type to Make/Break
1211 case 0xfd: // PS/2 Set Key Type to Make
1212 default:
1213 BX_ERROR(("kbd_ctrl_to_kbd(): got value of 0x%02x", value));
1214 kbd_enQ(0xFE); /* send NACK */
1215 break;
1219 void bx_keyb_c::timer_handler(void *this_ptr)
1221 bx_keyb_c *class_ptr = (bx_keyb_c *)this_ptr;
1222 unsigned retval;
1224 retval=class_ptr->periodic(1);
1226 if(retval&0x01)
1227 DEV_pic_raise_irq(1);
1228 if(retval&0x02)
1229 DEV_pic_raise_irq(12);
1232 unsigned bx_keyb_c::periodic(Bit32u usec_delta)
1234 /* static int multiple=0; */
1235 static unsigned count_before_paste=0;
1236 Bit8u retval;
1238 UNUSED(usec_delta);
1240 if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) {
1241 if(++count_before_paste>=BX_KEY_THIS pastedelay) {
1242 // after the paste delay, consider adding moving more chars
1243 // from the paste buffer to the keyboard buffer.
1244 BX_KEY_THIS service_paste_buf();
1245 count_before_paste=0;
1249 retval = BX_KEY_THIS s.kbd_controller.irq1_requested | (BX_KEY_THIS s.kbd_controller.irq12_requested << 1);
1250 BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
1251 BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
1253 if (BX_KEY_THIS s.kbd_controller.timer_pending == 0) {
1254 return(retval);
1257 if (usec_delta >= BX_KEY_THIS s.kbd_controller.timer_pending) {
1258 BX_KEY_THIS s.kbd_controller.timer_pending = 0;
1259 } else {
1260 BX_KEY_THIS s.kbd_controller.timer_pending -= usec_delta;
1261 return(retval);
1264 if (BX_KEY_THIS s.kbd_controller.outb) {
1265 return(retval);
1268 /* nothing in outb, look for possible data xfer from keyboard or mouse */
1269 if (BX_KEY_THIS s.kbd_internal_buffer.num_elements &&
1270 (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled || BX_KEY_THIS s.kbd_controller.bat_in_progress)) {
1271 BX_DEBUG(("service_keyboard: key in internal buffer waiting"));
1272 BX_KEY_THIS s.kbd_controller.kbd_output_buffer =
1273 BX_KEY_THIS s.kbd_internal_buffer.buffer[BX_KEY_THIS s.kbd_internal_buffer.head];
1274 BX_KEY_THIS s.kbd_controller.outb = 1;
1275 // commented out since this would override the current state of the
1276 // mouse buffer flag - no bug seen - just seems wrong (das)
1277 // BX_KEY_THIS s.kbd_controller.auxb = 0;
1278 BX_KEY_THIS s.kbd_internal_buffer.head = (BX_KEY_THIS s.kbd_internal_buffer.head + 1) %
1279 BX_KBD_ELEMENTS;
1280 BX_KEY_THIS s.kbd_internal_buffer.num_elements--;
1281 if (BX_KEY_THIS s.kbd_controller.allow_irq1)
1282 BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
1283 } else {
1284 create_mouse_packet(0);
1285 if (BX_KEY_THIS s.kbd_controller.aux_clock_enabled && BX_KEY_THIS s.mouse_internal_buffer.num_elements) {
1286 BX_DEBUG(("service_keyboard: key(from mouse) in internal buffer waiting"));
1287 BX_KEY_THIS s.kbd_controller.aux_output_buffer =
1288 BX_KEY_THIS s.mouse_internal_buffer.buffer[BX_KEY_THIS s.mouse_internal_buffer.head];
1290 BX_KEY_THIS s.kbd_controller.outb = 1;
1291 BX_KEY_THIS s.kbd_controller.auxb = 1;
1292 BX_KEY_THIS s.mouse_internal_buffer.head = (BX_KEY_THIS s.mouse_internal_buffer.head + 1) %
1293 BX_MOUSE_BUFF_SIZE;
1294 BX_KEY_THIS s.mouse_internal_buffer.num_elements--;
1295 if (BX_KEY_THIS s.kbd_controller.allow_irq12)
1296 BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
1297 } else {
1298 BX_DEBUG(("service_keyboard(): no keys waiting"));
1301 return(retval);
1304 void bx_keyb_c::activate_timer(void)
1306 if (BX_KEY_THIS s.kbd_controller.timer_pending == 0) {
1307 BX_KEY_THIS s.kbd_controller.timer_pending = 1;
1311 void bx_keyb_c::kbd_ctrl_to_mouse(Bit8u value)
1313 // if we are not using a ps2 mouse, some of the following commands need to return different values
1314 bx_bool is_ps2 = 0;
1315 if ((BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_PS2) ||
1316 (BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_IMPS2)) is_ps2 = 1;
1318 BX_DEBUG(("MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
1319 BX_DEBUG((" enable = %u", (unsigned) BX_KEY_THIS s.mouse.enable));
1320 BX_DEBUG((" allow_irq12 = %u",
1321 (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12));
1322 BX_DEBUG((" aux_clock_enabled = %u",
1323 (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled));
1325 // an ACK (0xFA) is always the first response to any valid input
1326 // received from the system other than Set-Wrap-Mode & Resend-Command
1328 if (BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter) {
1329 BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
1330 switch (BX_KEY_THIS s.kbd_controller.last_mouse_command) {
1331 case 0xf3: // Set Mouse Sample Rate
1332 BX_KEY_THIS s.mouse.sample_rate = value;
1333 BX_DEBUG(("[mouse] Sampling rate set: %d Hz", value));
1334 if ((value == 200) && (!BX_KEY_THIS s.mouse.im_request)) {
1335 BX_KEY_THIS s.mouse.im_request = 1;
1336 } else if ((value == 100) && (BX_KEY_THIS s.mouse.im_request == 1)) {
1337 BX_KEY_THIS s.mouse.im_request = 2;
1338 } else if ((value == 80) && (BX_KEY_THIS s.mouse.im_request == 2)) {
1339 if (BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_IMPS2) {
1340 BX_INFO(("wheel mouse mode enabled"));
1341 BX_KEY_THIS s.mouse.im_mode = 1;
1342 } else {
1343 BX_INFO(("wheel mouse mode request rejected"));
1345 BX_KEY_THIS s.mouse.im_request = 0;
1346 } else {
1347 BX_KEY_THIS s.mouse.im_request = 0;
1349 controller_enQ(0xFA, 1); // ack
1350 break;
1352 case 0xe8: // Set Mouse Resolution
1353 switch (value) {
1354 case 0:
1355 BX_KEY_THIS s.mouse.resolution_cpmm = 1;
1356 break;
1357 case 1:
1358 BX_KEY_THIS s.mouse.resolution_cpmm = 2;
1359 break;
1360 case 2:
1361 BX_KEY_THIS s.mouse.resolution_cpmm = 4;
1362 break;
1363 case 3:
1364 BX_KEY_THIS s.mouse.resolution_cpmm = 8;
1365 break;
1366 default:
1367 BX_PANIC(("[mouse] Unknown resolution %d", value));
1368 break;
1370 BX_DEBUG(("[mouse] Resolution set to %d counts per mm",
1371 BX_KEY_THIS s.mouse.resolution_cpmm));
1373 controller_enQ(0xFA, 1); // ack
1374 break;
1376 default:
1377 BX_PANIC(("MOUSE: unknown last command (%02xh)", (unsigned) BX_KEY_THIS s.kbd_controller.last_mouse_command));
1379 } else {
1380 BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
1381 BX_KEY_THIS s.kbd_controller.last_mouse_command = value;
1383 // test for wrap mode first
1384 if (BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
1385 // if not a reset command or reset wrap mode
1386 // then just echo the byte.
1387 if ((value != 0xff) && (value != 0xec)) {
1388 if (bx_dbg.mouse)
1389 BX_INFO(("[mouse] wrap mode: Ignoring command %0X02.",value));
1390 controller_enQ(value,1);
1391 // bail out
1392 return;
1395 switch (value) {
1396 case 0xe6: // Set Mouse Scaling to 1:1
1397 controller_enQ(0xFA, 1); // ACK
1398 BX_KEY_THIS s.mouse.scaling = 2;
1399 BX_DEBUG(("[mouse] Scaling set to 1:1"));
1400 break;
1402 case 0xe7: // Set Mouse Scaling to 2:1
1403 controller_enQ(0xFA, 1); // ACK
1404 BX_KEY_THIS s.mouse.scaling = 2;
1405 BX_DEBUG(("[mouse] Scaling set to 2:1"));
1406 break;
1408 case 0xe8: // Set Mouse Resolution
1409 controller_enQ(0xFA, 1); // ACK
1410 BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
1411 break;
1413 case 0xea: // Set Stream Mode
1414 if (bx_dbg.mouse)
1415 BX_INFO(("[mouse] Mouse stream mode on."));
1416 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_STREAM;
1417 controller_enQ(0xFA, 1); // ACK
1418 break;
1420 case 0xec: // Reset Wrap Mode
1421 // unless we are in wrap mode ignore the command
1422 if (BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
1423 if (bx_dbg.mouse)
1424 BX_INFO(("[mouse] Mouse wrap mode off."));
1425 // restore previous mode except disable stream mode reporting.
1426 // ### TODO disabling reporting in stream mode
1427 BX_KEY_THIS s.mouse.mode = BX_KEY_THIS s.mouse.saved_mode;
1428 controller_enQ(0xFA, 1); // ACK
1430 break;
1431 case 0xee: // Set Wrap Mode
1432 // ### TODO flush output queue.
1433 // ### TODO disable interrupts if in stream mode.
1434 if (bx_dbg.mouse)
1435 BX_INFO(("[mouse] Mouse wrap mode on."));
1436 BX_KEY_THIS s.mouse.saved_mode = BX_KEY_THIS s.mouse.mode;
1437 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_WRAP;
1438 controller_enQ(0xFA, 1); // ACK
1439 break;
1441 case 0xf0: // Set Remote Mode (polling mode, i.e. not stream mode.)
1442 if (bx_dbg.mouse)
1443 BX_INFO(("[mouse] Mouse remote mode on."));
1444 // ### TODO should we flush/discard/ignore any already queued packets?
1445 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_REMOTE;
1446 controller_enQ(0xFA, 1); // ACK
1447 break;
1449 case 0xf2: // Read Device Type
1450 controller_enQ(0xFA, 1); // ACK
1451 if (BX_KEY_THIS s.mouse.im_mode)
1452 controller_enQ(0x03, 1); // Device ID (wheel z-mouse)
1453 else
1454 controller_enQ(0x00, 1); // Device ID (standard)
1455 BX_DEBUG(("[mouse] Read mouse ID"));
1456 break;
1458 case 0xf3: // Set Mouse Sample Rate (sample rate written to port 60h)
1459 controller_enQ(0xFA, 1); // ACK
1460 BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
1461 break;
1463 case 0xf4: // Enable (in stream mode)
1464 // is a mouse present?
1465 if (is_ps2) {
1466 BX_KEY_THIS s.mouse.enable = 1;
1467 controller_enQ(0xFA, 1); // ACK
1468 BX_DEBUG(("[mouse] Mouse enabled (stream mode)"));
1469 } else {
1470 // a mouse isn't present. We need to return a 0xFE (resend) instead of a 0xFA (ACK)
1471 controller_enQ(0xFE, 1); // RESEND
1472 BX_KEY_THIS s.kbd_controller.tim = 1;
1474 break;
1476 case 0xf5: // Disable (in stream mode)
1477 BX_KEY_THIS s.mouse.enable = 0;
1478 controller_enQ(0xFA, 1); // ACK
1479 BX_DEBUG(("[mouse] Mouse disabled (stream mode)"));
1480 break;
1482 case 0xf6: // Set Defaults
1483 BX_KEY_THIS s.mouse.sample_rate = 100; /* reports per second (default) */
1484 BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
1485 BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
1486 BX_KEY_THIS s.mouse.enable = 0;
1487 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_STREAM;
1488 controller_enQ(0xFA, 1); // ACK
1489 BX_DEBUG(("[mouse] Set Defaults"));
1490 break;
1492 case 0xff: // Reset
1493 // is a mouse present?
1494 if (is_ps2) {
1495 BX_KEY_THIS s.mouse.sample_rate = 100; /* reports per second (default) */
1496 BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
1497 BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
1498 BX_KEY_THIS s.mouse.mode = MOUSE_MODE_RESET;
1499 BX_KEY_THIS s.mouse.enable = 0;
1500 if (BX_KEY_THIS s.mouse.im_mode)
1501 BX_INFO(("wheel mouse mode disabled"));
1502 BX_KEY_THIS s.mouse.im_mode = 0;
1503 /* (mch) NT expects an ack here */
1504 controller_enQ(0xFA, 1); // ACK
1505 controller_enQ(0xAA, 1); // completion code
1506 controller_enQ(0x00, 1); // ID code (standard after reset)
1507 BX_DEBUG(("[mouse] Mouse reset"));
1508 } else {
1509 // a mouse isn't present. We need to return a 0xFE (resend) instead of a 0xFA (ACK)
1510 controller_enQ(0xFE, 1); // RESEND
1511 BX_KEY_THIS s.kbd_controller.tim = 1;
1513 break;
1515 case 0xe9: // Get mouse information
1516 // should we ack here? (mch): Yes
1517 controller_enQ(0xFA, 1); // ACK
1518 controller_enQ(BX_KEY_THIS s.mouse.get_status_byte(), 1); // status
1519 controller_enQ(BX_KEY_THIS s.mouse.get_resolution_byte(), 1); // resolution
1520 controller_enQ(BX_KEY_THIS s.mouse.sample_rate, 1); // sample rate
1521 BX_DEBUG(("[mouse] Get mouse information"));
1522 break;
1524 case 0xeb: // Read Data (send a packet when in Remote Mode)
1525 controller_enQ(0xFA, 1); // ACK
1526 // perhaps we should be adding some movement here.
1527 mouse_enQ_packet(((BX_KEY_THIS s.mouse.button_status & 0x0f) | 0x08),
1528 0x00, 0x00, 0x00); // bit3 of first byte always set
1529 //assumed we really aren't in polling mode, a rather odd assumption.
1530 BX_ERROR(("[mouse] Warning: Read Data command partially supported."));
1531 break;
1533 case 0xbb: // OS/2 Warp 3 uses this command
1534 BX_ERROR(("[mouse] ignoring 0xbb command"));
1535 break;
1537 default:
1538 // If PS/2 mouse present, send NACK for unknown commands, otherwise ignore
1539 if (is_ps2) {
1540 BX_ERROR(("[mouse] kbd_ctrl_to_mouse(): got value of 0x%02x", value));
1541 controller_enQ(0xFE, 1); /* send NACK */
1547 void bx_keyb_c::create_mouse_packet(bx_bool force_enq)
1549 Bit8u b1, b2, b3, b4;
1551 if(BX_KEY_THIS s.mouse_internal_buffer.num_elements && !force_enq)
1552 return;
1554 Bit16s delta_x = BX_KEY_THIS s.mouse.delayed_dx;
1555 Bit16s delta_y = BX_KEY_THIS s.mouse.delayed_dy;
1556 Bit8u button_state=BX_KEY_THIS s.mouse.button_status | 0x08;
1558 if(!force_enq && !delta_x && !delta_y) {
1559 return;
1562 if(delta_x>254) delta_x=254;
1563 if(delta_x<-254) delta_x=-254;
1564 if(delta_y>254) delta_y=254;
1565 if(delta_y<-254) delta_y=-254;
1567 b1 = (button_state & 0x0f) | 0x08; // bit3 always set
1569 if ((delta_x>=0) && (delta_x<=255)) {
1570 b2 = (Bit8u) delta_x;
1571 BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
1573 else if (delta_x > 255) {
1574 b2 = (Bit8u) 0xff;
1575 BX_KEY_THIS s.mouse.delayed_dx-=255;
1577 else if (delta_x >= -256) {
1578 b2 = (Bit8u) delta_x;
1579 b1 |= 0x10;
1580 BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
1582 else {
1583 b2 = (Bit8u) 0x00;
1584 b1 |= 0x10;
1585 BX_KEY_THIS s.mouse.delayed_dx+=256;
1588 if ((delta_y>=0) && (delta_y<=255)) {
1589 b3 = (Bit8u) delta_y;
1590 BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
1592 else if (delta_y > 255) {
1593 b3 = (Bit8u) 0xff;
1594 BX_KEY_THIS s.mouse.delayed_dy-=255;
1596 else if (delta_y >= -256) {
1597 b3 = (Bit8u) delta_y;
1598 b1 |= 0x20;
1599 BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
1601 else {
1602 b3 = (Bit8u) 0x00;
1603 b1 |= 0x20;
1604 BX_KEY_THIS s.mouse.delayed_dy+=256;
1607 b4 = (Bit8u) -BX_KEY_THIS s.mouse.delayed_dz;
1609 mouse_enQ_packet(b1, b2, b3, b4);
1613 void bx_keyb_c::mouse_enabled_changed(bx_bool enabled)
1615 BX_KEY_THIS s.mouse.captured = enabled;
1616 #if BX_SUPPORT_PCIUSB
1617 // if an usb mouse is connected, notify the device about the status change
1618 if (DEV_usb_mouse_connected()) {
1619 DEV_usb_mouse_enabled_changed(enabled);
1620 return;
1622 #endif
1624 if (BX_KEY_THIS s.mouse.delayed_dx || BX_KEY_THIS s.mouse.delayed_dy ||
1625 BX_KEY_THIS s.mouse.delayed_dz) {
1626 create_mouse_packet(1);
1628 BX_KEY_THIS s.mouse.delayed_dx=0;
1629 BX_KEY_THIS s.mouse.delayed_dy=0;
1630 BX_KEY_THIS s.mouse.delayed_dz=0;
1631 BX_DEBUG(("PS/2 mouse %s", enabled?"enabled":"disabled"));
1634 void bx_keyb_c::mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state)
1636 bool force_enq=0;
1638 // If mouse events are disabled on the GUI headerbar, don't
1639 // generate any mouse data
1640 if (!BX_KEY_THIS s.mouse.captured)
1641 return;
1643 #if BX_SUPPORT_PCIUSB
1644 // if an usb mouse is connected, redirect mouse data to the usb device
1645 if (DEV_usb_mouse_connected()) {
1646 DEV_usb_mouse_enq(delta_x, delta_y, delta_z, button_state);
1647 return;
1649 #endif
1651 // if type == serial, redirect mouse data to the serial device
1652 if ((BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_SERIAL) ||
1653 (BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_SERIAL_WHEEL) ||
1654 (BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_SERIAL_MSYS)) {
1655 DEV_serial_mouse_enq(delta_x, delta_y, delta_z, button_state);
1656 return;
1659 #if BX_SUPPORT_BUSMOUSE
1660 // if type == bus, redirect mouse data to the bus device
1661 if (BX_KEY_THIS s.mouse.type == BX_MOUSE_TYPE_BUS) {
1662 DEV_bus_mouse_enq(delta_x, delta_y, 0, button_state);
1663 return;
1665 #endif
1667 // don't generate interrupts if we are in remote mode.
1668 if (BX_KEY_THIS s.mouse.mode == MOUSE_MODE_REMOTE)
1669 // is there any point in doing any work if we don't act on the result
1670 // so go home.
1671 return;
1673 // Note: enable only applies in STREAM MODE.
1674 if (BX_KEY_THIS s.mouse.enable==0)
1675 return;
1677 // scale down the motion
1678 if ((delta_x < -1) || (delta_x > 1))
1679 delta_x /= 2;
1680 if ((delta_y < -1) || (delta_y > 1))
1681 delta_y /= 2;
1683 if (!BX_KEY_THIS s.mouse.im_mode)
1684 delta_z = 0;
1686 #ifdef VERBOSE_KBD_DEBUG
1687 if (delta_x != 0 || delta_y != 0 || delta_z != 0)
1688 BX_DEBUG(("[mouse] Dx=%d Dy=%d Dz=%d", delta_x, delta_y, delta_z));
1689 #endif /* ifdef VERBOSE_KBD_DEBUG */
1691 if ((delta_x==0) && (delta_y==0) && (delta_z==0) && (BX_KEY_THIS s.mouse.button_status == (button_state & 0x7))) {
1692 BX_DEBUG(("Ignoring useless mouse_motion call:"));
1693 BX_DEBUG(("This should be fixed in the gui code."));
1694 return;
1697 if ((BX_KEY_THIS s.mouse.button_status != (button_state & 0x7)) || delta_z) {
1698 force_enq=1;
1701 BX_KEY_THIS s.mouse.button_status = button_state & 0x7;
1703 if(delta_x>255) delta_x=255;
1704 if(delta_y>255) delta_y=255;
1705 if(delta_x<-256) delta_x=-256;
1706 if(delta_y<-256) delta_y=-256;
1708 BX_KEY_THIS s.mouse.delayed_dx+=delta_x;
1709 BX_KEY_THIS s.mouse.delayed_dy+=delta_y;
1710 BX_KEY_THIS s.mouse.delayed_dz = delta_z;
1712 if((BX_KEY_THIS s.mouse.delayed_dx>255)||
1713 (BX_KEY_THIS s.mouse.delayed_dx<-256)||
1714 (BX_KEY_THIS s.mouse.delayed_dy>255)||
1715 (BX_KEY_THIS s.mouse.delayed_dy<-256)) {
1716 force_enq=1;
1719 create_mouse_packet(force_enq);