---------------------------------------------------------------------- Patch name: patch.plugins3 Author: Bryce Denney Date: Wed Dec 12 17:56:11 EST 2001 Detailed description: This patch replaces the Bochs keyboard with a slightly modified version of the plex86 keyboard device, which is implemented as a plugin. This is sort of a proof of concept, rather than anything that I'm about to check in. It uses GNU libtool to compile the plex86 keyboard code into a shared library, and installs that shared library in /tmp/bochslib/libplex-keyboard.so. Then the new code in plugin.cc (which is adapted from the plex86 plugin code) loads the libplex-keyboard library during initialization and installs the plex86 keyboard instead of the bochs keyboard. I chose the keyboard because it takes about 2 seconds to test that it's basically working, and because the bochs and plex86 implementations hadn't changed very much since they split. If you look at plex-keyboard.cc and plex-keyboard.h, it is fundamentally the same as the current plex86 code. I have changed lots of names from bx_* to plex_* just to reduce confusion and mayhem when I was compiling with both kbd implementations. I didn't change anything except to get it to compile. Patch was created with: cvs diff -u Apply patch to what version: cvs current as of 12/12/2001 Instructions: To patch, go to main bochs directory. Type "patch -p0 < THIS_PATCH_FILE". ---------------------------------------------------------------------- Index: Makefile.in =================================================================== RCS file: /cvsroot/bochs/bochs/Makefile.in,v retrieving revision 1.62 diff -u -r1.62 Makefile.in --- Makefile.in 2001/12/10 21:31:20 1.62 +++ Makefile.in 2001/12/13 03:03:42 @@ -78,7 +78,7 @@ CXXFLAGS = @CXXFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ +LIBS = @LIBS@ -ldl # To compile with readline: # linux needs just -lreadline # solaris needs -lreadline -lcurses @@ -123,6 +123,7 @@ NONINLINE_OBJS = \ logio.o \ main.o \ + plugin.o \ load32bitOShack.o \ state_file.o \ pc_system.o \ @@ -140,7 +141,7 @@ INSTRUMENT_LIB = @INSTRUMENT_DIR@/libinstrument.a FPU_LIB = fpu/libfpu.a READLINE_LIB = @READLINE_LIB@ -EXTRA_LINK_OPTS = @EXTRA_LINK_OPTS@ +EXTRA_LINK_OPTS = @EXTRA_LINK_OPTS@ -ldl BX_OBJS = @NONINLINE_VAR@ @@ -158,12 +159,12 @@ @EXTERNAL_DEPENDENCY@ -bochs@EXE@: @IODEV_LIB_VAR@ @DEBUGGER_VAR@ \ +bochs@EXE@: @IODEV_LIB_VAR@ iodev/libplex-keyboard.la @DEBUGGER_VAR@ \ cpu/libcpu.a memory/libmemory.a gui/libgui.a \ @DISASM_VAR@ @INSTRUMENT_VAR@ @DYNAMIC_VAR@ $(BX_OBJS) \ $(SIMX86_OBJS) \ $(FPU_LIB) - @LINK@ $(BX_OBJS) \ + libtool --mode=link @LINK@ -export-dynamic $(BX_OBJS) \ $(SIMX86_OBJS) \ iodev/libiodev.a \ cpu/libcpu.a memory/libmemory.a gui/libgui.a \ @@ -191,6 +192,9 @@ echo '// This file is generated by "make bxversion.h"' >> bxversion.h echo "#define VER_STRING \"$(VER_STRING)\"" >> bxversion.h echo "#define REL_STRING \"$(REL_STRING)\"" >> bxversion.h + +iodev/libplex-keyboard.la:: + (cd iodev; make libplex-keyboard.la) iodev/libiodev.a:: cd iodev @COMMAND_SEPARATOR@ Index: bochs.h =================================================================== RCS file: /cvsroot/bochs/bochs/bochs.h,v retrieving revision 1.56 diff -u -r1.56 bochs.h --- bochs.h 2001/12/12 10:43:36 1.56 +++ bochs.h 2001/12/13 03:03:42 @@ -73,6 +73,7 @@ #include "osdep.h" /* platform dependent includes and defines */ #include "debug/debug.h" #include "bxversion.h" +#include "plugin.h" #include "gui/siminterface.h" Index: main.cc =================================================================== RCS file: /cvsroot/bochs/bochs/main.cc,v retrieving revision 1.80 diff -u -r1.80 main.cc --- main.cc 2001/12/12 10:43:36 1.80 +++ main.cc 2001/12/13 03:03:45 @@ -118,7 +118,9 @@ // if after init, notify the GUI if (set && SIM->get_init_done ()) { bx_gui.mouse_enabled_changed (val!=0); - bx_keyboard.mouse_enabled_changed (val!=0); + // FIXME: while adding plugin support, I'm not going to bother + // with this function for now. + //bx_keyboard.mouse_enabled_changed (val!=0); } break; case BXP_PARPORT1_ENABLE: @@ -913,6 +915,10 @@ #else bx_init_hardware(); + + BX_INFO (("Now I will load the plex86 keyboard plugin...")); + bx_init_plugin (); + BX_INFO (("Done loading the plex86 keyboard plugin")); if (bx_options.load32bitOSImage.OwhichOS->get ()) { void bx_load32bitOSimagehack(void); Index: plugin.cc =================================================================== RCS file: plugin.cc diff -N plugin.cc --- /dev/null Thu May 24 22:33:05 2001 +++ plugin.cc Wed Dec 12 19:03:47 2001 @@ -0,0 +1,841 @@ +/* + * plex86: run multiple x86 operating systems concurrently + * Copyright (C) 1999-2000 The plex86 developers team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "bochs.h" +#include "plugin.h" + +#define LOG_THIS genlog-> + +Bit32u (* pluginGetCMOSReg)(unsigned reg) = 0; +void (* pluginSetCMOSReg)(unsigned reg, Bit32u val) = 0; +void (* pluginMouseMotion)(int d_x, int d_y, unsigned button_state) = 0; +void (* pluginGenScancode)(Bit32u scancode) = 0; +plugin_t *plugins = NULL; /* Head of the linked list of plugins */ +static void plugin_init_one(plugin_t *plugin); + +#if 0 +/************************************************************************/ +/* Plugin initialization / deinitialization */ +/************************************************************************/ + + +/* Some builtin (default pass-through) Write-Cache functions, when + * no Write-Cache plugins are loaded to override these. These are + * strict pass-through functions + */ + +static Bit64u builtinWCLSeek(int fd, Bit64u off64, int whence); +static unsigned builtinWCRead(int fd, void *buffer, unsigned len); +static unsigned builtinWCWrite(int fd, void *buffer, unsigned len); +static void builtinWCCommit(int fd); + +static Bit32u builtinHDReadHandler(Bit32u address, + unsigned io_len); +static void builtinHDWriteHandler(Bit32u address, + Bit32u value, unsigned io_len); +static void builtinVGARedrawArea(unsigned x0, unsigned y0, + unsigned width, unsigned height); + + +pluginCallbacks_t pluginCallbacks; + +plugin_t *plugins = NULL; /* Head of the linked list of plugins */ +void (*pluginHRQHackCallback)(void); +unsigned pluginHRQ = 0; + +extern int filehdl; /* File handle for /dev/plex86 */ + +Bit32u (* pluginGetCMOSReg)(unsigned reg) = 0; +void (* pluginSetCMOSReg)(unsigned reg, Bit32u val) = 0; +void (* pluginCMOSChecksum)(void) = 0; +void (* pluginMouseMotion)(int d_x, int d_y, unsigned button_state) = 0; +void (* pluginGenScancode)(Bit32u scancode) = 0; +unsigned (* pluginRegisterDMAChannel)( + unsigned channel, + void (* dma_read)(Bit8u *data_byte), + void (* dma_write)(Bit8u *data_byte) + ) = 0; +void (* pluginDMASetDRQ)(unsigned channel, unsigned val) = 0; +unsigned (* pluginDMAGetTC)(void) = 0; + +Bit32u (* pluginHDReadHandler)(Bit32u address, + unsigned io_len) = 0; +void (* pluginHDWriteHandler)(Bit32u address, + Bit32u value, unsigned io_len) = 0; +void (* pluginVGARedrawArea)(unsigned x0, unsigned y0, + unsigned width, unsigned height) = 0; + +bx_debug_t bx_dbg; // xxx Fix me, bochs hack +bx_options_t bx_options; // xxx Fix me, bochs hack + +// xxx Fix me, bochs hack + void +bx_panic(char *fmt, ...) +{ + va_list ap; + +#if 0 + if (bx_logfd) { + fprintf(bx_logfd, "panic, "); + + va_start(ap, fmt); + vfprintf(bx_logfd, fmt, ap); + va_end(ap); + } +#endif + fprintf(stderr, "bochs: panic, "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + plugin_abort (); +} + +// xxx Fix me, bochs hack + void +bx_printf(char *fmt, ...) +{ + va_list ap; + +#if 0 + if (bx_logfd) { + va_start(ap, fmt); + vfprintf(bx_logfd, fmt, ap); + va_end(ap); + } +#endif + fprintf(stderr, "bochs: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + + + +#if 0 +void +plugin_init_all (void) +{ + plugin_t *plugin; + + for (plugin = plugins; plugin; plugin = plugin->next) + { + char *arg_ptr = plugin->args; + + /* process the command line */ + plugin->argc = 0; + while (plugin->argc < MAX_ARGC) + { + while (*arg_ptr && isspace (*arg_ptr)) + arg_ptr++; + + if (!*arg_ptr) + break; + plugin->argv[plugin->argc++] = arg_ptr; + + while (*arg_ptr && !isspace (*arg_ptr)) + arg_ptr++; + + if (!*arg_ptr) + break; + *arg_ptr++ = '\0'; + } + + /* initialize the plugin */ + if (plugin->init (plugin, plugin->argc, plugin->argv)) + { + fprintf (stderr, "Plugin initialization failed for %s\n", plugin->name); + plugin_abort(); + } + + plugin->initialized = 1; + } + + return; +} +#endif + + + plugin_t * +plugin_unload(plugin_t *plugin) +{ + int i; + plugin_t *dead_plug; + + if (plugin->initialized) + plugin->fini (); + + for (i=0; i<256; i++) + plugin_free_intr (plugin, i); + + dlclose (plugin->handle); + free (plugin->name); + free (plugin->args); + + dead_plug = plugin; + plugin = plugin->next; + free (dead_plug); + + return plugin; +} + + +void +plugin_fini_all (void) +{ + plugin_t *plugin; + + for (plugin = plugins; plugin; plugin = plugin_unload (plugin)); + + return; +} + + + +#if 0 +#define BX_MAX_IRQS 16 +#define BX_NO_IRQ -1 +const char *irq_handler_name[BX_MAX_IRQS]; + + for (i=0; i < BX_MAX_IRQS; i++) { + irq_handler_name[i] = NULL; + } +#endif + + void +pluginUnregisterIRQ(unsigned irq, const char *name) +{ +#warning "Finish pluginUnregisterIRQ" +#if 0 + if (irq >= BX_MAX_IRQS) { + bx_panic("IO device %s tried to unregister IRQ %d above %u\n", + name, irq, (unsigned) BX_MAX_IRQS-1); + } + + if (!irq_handler_name[irq]) { + bx_printf("IO device %s tried to unregister IRQ %d, not registered\n", + name, irq); + return; + } + + if (strcmp(irq_handler_name[irq], name)) { + bx_printf("IRQ %u not registered to %s but to %s\n", irq, + name, irq_handler_name[irq]); + return; + } + irq_handler_name[irq] = NULL; +#endif +} + + +/************************************************************************/ +/* Software interrupt handling */ +/************************************************************************/ + +static struct intr_t +{ + plugin_t *plugin; + handler_t handler; + struct intr_t *next; +} +*ints[256]; /* Heads of linked lists for each int */ + + +int +plugin_alloc_intr (plugin_t *plugin, handler_t handler, int vec) +{ + struct intr_t *intr; + + for (intr = ints[vec]; intr != NULL; intr = intr->next) + { + if (intr->plugin == plugin) + return -1; + } + + if (ints[vec] == NULL && vm_alloc_intr (vec)) + return -1; + + intr = malloc (sizeof (struct intr_t)); + intr->plugin = plugin; + intr->handler = handler; + intr->next = ints[vec]; + ints[vec] = intr; + + return 0; +} + + + void +plugin_free_intr (plugin_t *plugin, int vec) +{ + struct intr_t *intr, *dummy; + + if ((intr = ints[vec]) == NULL) + return; + + if (intr->plugin == plugin) + { + dummy = intr; + ints[vec] = intr->next; + free (dummy); + } + else + for (; intr != NULL; intr = intr->next) + { + if (intr->next == NULL) + break; + + if (intr->next->plugin == plugin) + { + dummy = intr->next; + intr->next = intr->next->next; + free (dummy); + + break; + } + } + + if (ints[vec] == NULL) + vm_release_intr (vec); + + return; +} + + + int +plugin_emulate_int(int vec) +{ + struct intr_t *intr; + int reflect = 0; + + for (intr = ints[vec]; intr != NULL; intr = intr->next) + { + if (intr->handler (EVT_INT, vec, 0, 0, NULL)) + reflect = 1; + } + + return reflect; +} + + + +/************************************************************************/ +/* VM control */ +/************************************************************************/ + +void +plugin_abort (void) +{ + vm_abort (); + return; +} + + + +/************************************************************************/ +/* Plugin pending */ +/************************************************************************/ + +/* + * NOTE: This code was explicitly written to be reentrant using atomic + * XCHG, because it will usually be called from signal handlers and + * the like. None of the other plugin functions are reentrant, so + * a plugin wanting to perform plugin operations after reception + * of a signal should always use these functions to pend for CPU + * time. + */ + + +/************************************************************************/ +/* */ +/************************************************************************/ + +void (*memMapFunct)(Bit32u, unsigned, unsigned, Bit32u *) = NULL; + + void +plugin_register_mem_map_IO( void (*f)(Bit32u, unsigned, unsigned, Bit32u *), + Bit32u range0, Bit32u range1) +{ + memMapFunct = f; +} + + +/************************************************************************/ +/* Timing control */ +/************************************************************************/ + +static void (*save_funct)(Bit64u) = NULL; +static void (*periodic_funct)(void) = NULL; + + + void +plugin_register_elapsed(void (*funct)(Bit64u)) +{ + save_funct = funct; +} + + void +plugin_register_periodic(void (*funct)(void)) +{ + periodic_funct = funct; +} + + + void +plugin_call_elapsed( Bit64u elapsed ) +{ + if (save_funct) + save_funct(elapsed); +} + + void +plugin_handle_periodic(void) +{ + static Bit64u prev_user_usec = 0; + Bit64u new_user_usec; + volatile extern Bit64u user_time_usec; + + if (!periodic_funct) return; + +#warning "fix: need exclusive access to variable used by async handler" + new_user_usec = user_time_usec; + if ( (new_user_usec - prev_user_usec) >= 500000 ) { + prev_user_usec = new_user_usec; + periodic_funct(); + } +} + + + +/************************************************************************/ +/* Plugin system: plex86 startup function */ +/************************************************************************/ + +#define ZERO_ARRAY(a) memset (a, 0, sizeof(a)) + + void +plugin_startup(void) +{ + ZERO_ARRAY(ints); + + /* Register builtin Write-Cache functions, so we have some defaults + * until overloaded by plugins + */ + pluginRegisterWriteCache(builtinWCLSeek, builtinWCRead, builtinWCWrite, + builtinWCCommit); + pluginGetCMOSReg = builtinGetCMOSReg; + pluginSetCMOSReg = builtinSetCMOSReg; + pluginCMOSChecksum = builtinCMOSChecksum; + pluginMouseMotion = builtinMouseMotion; + pluginGenScancode = builtinGenScancode; + pluginRegisterDMAChannel = builtinRegisterDMAChannel; + pluginDMASetDRQ = builtinDMASetDRQ; + pluginDMAGetTC = builtinDMAGetTC; + + pluginHDReadHandler = builtinHDReadHandler; + pluginHDWriteHandler = builtinHDWriteHandler; + + pluginVGARedrawArea = builtinVGARedrawArea; +} + + void +builtinCMOSChecksum(void) +{ + fprintf(stderr, "builtinCMOSChecksum called, no CMOS plugin loaded?\n"); + vm_abort(); +} + + void +builtinMouseMotion(int d_x, int d_y, unsigned button_state) +{ + fprintf(stderr, "builtinMouseMotion called, not overloaded by keyboard" + " plugin?\n"); + vm_abort(); +} + + void +builtinGenScancode(Bit32u scancode) +{ + fprintf(stderr, "builtinGenScancode called, not overloaded by keyboard" + " plugin?\n"); + vm_abort(); +} + + unsigned +builtinRegisterDMAChannel( + unsigned channel, + void (* dma_read)(Bit8u *data_byte), + void (* dma_write)(Bit8u *data_byte) + ) +{ + fprintf(stderr, "builtinRegisterDMAChannel called, not overloaded by DMA" + " plugin?\n"); + vm_abort(); + return 0; +} + + void +builtinDMASetDRQ(unsigned channel, unsigned val) +{ + fprintf(stderr, "builtinDMASetDRQ( called, not overloaded by DMA" + " plugin?\n"); + vm_abort(); +} + + unsigned +builtinDMAGetTC(void) +{ + fprintf(stderr, "builtinDMAGetTC called, not overloaded by DMA" + " plugin?\n"); + vm_abort(); + return 0; +} + + Bit32u +builtinHDReadHandler(Bit32u address, unsigned io_len) +{ + fprintf(stderr, "builtinHDReadHandler called, HD plugin not loaded?" + " plugin?\n"); + vm_abort(); + return 0; +} + + void +builtinHDWriteHandler(Bit32u address, Bit32u value, unsigned io_len) +{ + fprintf(stderr, "builtinHDWriteHandler called, HD plugin not loaded?" + " plugin?\n"); + vm_abort(); +} + + void +builtinVGARedrawArea(unsigned x0, unsigned y0, + unsigned width, unsigned height) +{ +} + + Bit64u +builtinWCLSeek(int fd, Bit64u off64, int whence) +{ + return( lseek(fd, (off_t) off64, whence) ); +} + + unsigned +builtinWCRead(int fd, void *buffer, unsigned len) +{ + return( read(fd, buffer, len) ); +} + + unsigned +builtinWCWrite(int fd, void *buffer, unsigned len) +{ + return( write(fd, buffer, len) ); +} + + void +builtinWCCommit(int fd) +{ + fprintf(stderr, "builtin Write-Cache Commit (nop)\n"); +} + + +// xxx Fix these +int plugin_emulate_inport(int port, int op_size, int count, void *loc) +{ + fprintf(stderr, "plugin_emulate_inport:\n"); + vm_abort(); +} + +int plugin_emulate_outport(int port, int op_size, int count, void *loc) +{ + fprintf(stderr, "plugin_emulate_outport:\n"); + vm_abort(); +} + + void +pluginTriggerIRQ(unsigned irq) +{ + int ret; + irqMsg_t irqMsg; + + irqMsg.irq = irq; + irqMsg.on = 1; + + ret = ioctl(filehdl, PLEX86_IRQ, &irqMsg); + if (ret == -1) { + perror ("ioctl PLEX86_IRQ: "); + vm_abort(); + } +} + + void +pluginUntriggerIRQ(unsigned irq) +{ + int ret; + irqMsg_t irqMsg; + + irqMsg.irq = irq; + irqMsg.on = 0; + + ret = ioctl(filehdl, PLEX86_IRQ, &irqMsg); + if (ret == -1) { + perror ("ioctl PLEX86_IRQ: "); + vm_abort(); + } +} + + void +pluginSetHRQ(unsigned val) +{ + pluginHRQ = val; +} + + void +pluginSetHRQHackCallback( void (*callback)(void) ) +{ + pluginHRQHackCallback = callback; +} + + void +pluginResetSignal(unsigned sig) +{ + fprintf(stderr, "pluginResetSignal: unimplemented\n"); + vm_abort(); +} +#endif + + Bit32u +builtinGetCMOSReg(unsigned reg) +{ + Bit8u val = bx_cmos.s.reg[reg]; + BX_INFO(("plugin reading cmos register 0x%02x = 0x%02x", reg, val)); + return val; +} + + void +builtinSetCMOSReg(unsigned reg, Bit32u val) +{ + BX_ASSERT (reg >= 0 && reg < BX_NUM_CMOS_REGS); + bx_cmos.s.reg[reg] = val; + BX_INFO(("plugin writing 0x%02x to cmos register 0x%02x", val, reg)); +} + + void +builtinMouseMotion(int d_x, int d_y, unsigned button_state) +{ + BX_PANIC(("builtinMouseMotion called, not overloaded by keyboard" + " plugin?\n")); + abort(); +} + + void +builtinGenScancode(Bit32u scancode) +{ + BX_PANIC(("builtinGenScancode called, not overloaded by keyboard" + " plugin?\n")); + abort(); +} + + +#define KBD_PLUGIN "/tmp/bochslib/libplex-keyboard.so" +int bx_init_plugin () +{ + pluginGetCMOSReg = builtinGetCMOSReg; + pluginSetCMOSReg = builtinSetCMOSReg; + pluginMouseMotion = builtinMouseMotion; + pluginGenScancode = builtinGenScancode; + plugin_load (KBD_PLUGIN, ""); + /* + void *handle = dlopen (KBD_PLUGIN, RTLD_LAZY); + if (!handle) { + BX_ERROR (("could not open kbd plugin %s", KBD_PLUGIN)); + BX_PANIC (("dlopen error: %s", dlerror ())); + exit (1); + } + */ + BX_INFO (("opened keyboard library")); +} + + void +plugin_load (char *name, char *args) +{ + plugin_t *plugin; + const char *plug_err; + + plugin = (plugin_t *)malloc (sizeof (plugin_t)); + if (!plugin) + { + perror ("malloc"); + exit (1); + } + + plugin->name = name; + plugin->args = args; + plugin->initialized = 0; + + plugin->handle = dlopen (name, RTLD_LAZY); + if (!plugin->handle) + { + fputs (dlerror (), stderr); + exit (1); + } + + plugin->init = + (int (*)(struct _plugin_t *, int, char *[])) /* monster typecast */ + dlsym (plugin->handle, PLUGIN_INIT); + if ((plug_err = dlerror ()) != NULL) + { + BX_PANIC (("could not find init: %s", plug_err)); + plugin_abort (); + } + + plugin->fini = (void (*)(void)) dlsym (plugin->handle, PLUGIN_FINI); + if ((plug_err = dlerror ()) != NULL) + { + BX_PANIC (("could not find fini: %s", plug_err)); + plugin_abort (); + } + + /* Insert plugin at the _end_ of the plugin linked list. */ + plugin->next = NULL; + + if (!plugins) + { + /* Empty list, this become the first entry. */ + plugins = plugin; + } + else + { + /* Non-empty list. Add to end. */ + plugin_t *temp = plugins; + + while (temp->next) + temp = temp->next; + + temp->next = plugin; + } + +plugin_init_one(plugin); + + return; +} + +void +plugin_init_one(plugin_t *plugin) +{ + char *arg_ptr = plugin->args; + + /* process the command line */ + plugin->argc = 0; + while (plugin->argc < MAX_ARGC) + { + while (*arg_ptr && isspace (*arg_ptr)) + arg_ptr++; + + if (!*arg_ptr) + break; + plugin->argv[plugin->argc++] = arg_ptr; + + while (*arg_ptr && !isspace (*arg_ptr)) + arg_ptr++; + + if (!*arg_ptr) + break; + *arg_ptr++ = '\0'; + } + + /* initialize the plugin */ + if (plugin->init (plugin, plugin->argc, plugin->argv)) + { + fprintf (stderr, "Plugin initialization failed for %s\n", plugin->name); + plugin_abort(); + } + + plugin->initialized = 1; +} + +void +plugin_abort (void) +{ + BX_PANIC (("plugin load aborted")); + abort(); +} + + void +pluginRegisterIRQ(unsigned irq, const char *name) +{ +#warning "Finish pluginRegisterIRQ" + BX_ERROR(("pluginRegisterIRQ not complete")); + +#if 0 + if (irq >= BX_MAX_IRQS) { + bx_panic("IO device %s registered with IRQ=%d above %u\n", + name, irq, (unsigned) BX_MAX_IRQS-1); + } + if (irq_handler_name[irq]) { + bx_panic("IRQ %u conflict, %s with %s\n", irq, + irq_handler_name[irq], name); + } + irq_handler_name[irq] = name; +#endif +} + + int +pluginRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, + unsigned base, const char *name, unsigned len) +{ + BX_ASSERT (len==1); + bx_devices.register_io_read_handler (thisPtr, callback, base, name); + BX_INFO(("plugin registered I/O read address at %04x", base)); +} + + int +pluginRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, + unsigned base, const char *name, unsigned len) +{ + BX_ASSERT (len==1); + bx_devices.register_io_write_handler (thisPtr, callback, base, name); + BX_INFO(("plugin registered I/O write address at %04x", base)); +} + +int +pluginRegisterTimer(void *this_ptr, void (*funct)(void *), + Bit32u useconds, Boolean continuous, Boolean active) +{ + int id = bx_pc_system.register_timer (this_ptr, funct, useconds, continuous, active); + BX_INFO (("plugin registered timer %d", id)); + return id; +} + +void +pluginActivateTimer(unsigned id, Bit32u usec, Boolean continuous) +{ + bx_pc_system.activate_timer (id, usec, continuous); + BX_INFO(("plugin activated timer %d", id)); +} + +void +pluginTriggerIRQ(unsigned irq) +{ + BX_INFO(("plugin triggered irq %d", irq)); + bx_pic.trigger_irq (irq); +} + + Index: plugin.h =================================================================== RCS file: plugin.h diff -N plugin.h --- /dev/null Thu May 24 22:33:05 2001 +++ plugin.h Wed Dec 12 19:03:47 2001 @@ -0,0 +1,338 @@ +/* + * plex86: run multiple x86 operating systems concurrently + * Copyright (C) 1999-2000 The plex86 developers team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PLUGIN_H +#define __PLUGIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BX_EVENT_MOUSE_MOTION(dx, dy, state) \ + ((*pluginMouseMotion)(dx, dy, state)) +#define BX_EVENT_GEN_SCANCODE(scancode) \ + ((*pluginGenScancode)(scancode)) + +#include + +#define PLUGIN_INIT "plugin_init" +#define PLUGIN_FINI "plugin_fini" + +#define MAX_ARGC 10 + +typedef enum +{ + EVT_INPORT, EVT_OUTPORT, EVT_INT +} event_t; + +typedef int (*handler_t) + (event_t event, int data, int op_size, int count, void *loc); + +typedef Bit32u (*ioReadHandler_t)(void *, Bit32u, unsigned); +typedef void (*ioWriteHandler_t)(void *, Bit32u, Bit32u, unsigned); + +typedef struct _plugin_t +{ + int initialized; + void *handle; + int argc; + char *name, *args, *argv[MAX_ARGC]; + int (*init)(struct _plugin_t *plugin, int argc, char *argv[]); + void (*fini)(void); + struct _plugin_t *next; +} plugin_t; + +extern plugin_t *plugins; + +void plugin_startup (void); +void plugin_load (char *name, char *args); +plugin_t *plugin_unload (plugin_t *plugin); +void plugin_init_all (void); +void plugin_fini_all (void); + + +/* === IO port stuff === */ +int pluginRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, + unsigned base, const char *name, unsigned len); +int pluginRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, + unsigned base, const char *name, unsigned len); + +/* === IRQ stuff === */ +extern void pluginRegisterIRQ(unsigned irq, const char *name); +extern void pluginUnregisterIRQ(unsigned irq, const char *name); +extern void pluginTriggerIRQ(unsigned irq); +extern void pluginUntriggerIRQ(unsigned irq); + + +/* === CMOS query/set stuff === */ + +/* These are function pointers. At startup time, they are set to + * builtin default handlers which will cause an abort if called. + * A CMOS plugin should set these pointers to real handler functions. + */ +extern Bit32u (* pluginGetCMOSReg)(unsigned reg); +extern void (* pluginSetCMOSReg)(unsigned reg, Bit32u val); +extern void (* pluginCMOSChecksum)(void); + + +/* === A20 enable line stuff === */ +extern unsigned pluginGetA20E(void); +extern void pluginSetA20E(unsigned val); + + +/* === Keyboard/Mouse input stuff === */ +extern void (* pluginMouseMotion)(int d_x, int d_y, unsigned button_state); +extern void (* pluginGenScancode)(Bit32u scancode); + + +/* === DMA stuff === */ +extern unsigned (* pluginRegisterDMAChannel)( + unsigned channel, + void (* dma_read)(Bit8u *data_byte), + void (* dma_write)(Bit8u *data_byte) + ); +extern void (* pluginDMASetDRQ)(unsigned channel, unsigned val); +extern unsigned (* pluginDMAGetTC)(void); + +/* === Hard drive / floppy port sharing hack === */ +extern Bit32u (* pluginHDReadHandler)(Bit32u address, + unsigned io_len); +extern void (* pluginHDWriteHandler)(Bit32u address, + Bit32u value, unsigned io_len); + +/* === VGA stuff === */ +extern void (* pluginVGARedrawArea)(unsigned x0, unsigned y0, + unsigned width, unsigned height); + +#if 0 +/* === Mega hacks for bochs IO devices === */ +void bx_printf(char *fmt, ...); +void bx_panic(char *fmt, ...); + +typedef struct { + Boolean floppy; + Boolean keyboard; + Boolean video; + Boolean disk; + Boolean pit; + Boolean pic; + Boolean bios; + Boolean cmos; + Boolean interrupts; + Boolean exceptions; + Boolean unsupported; + Boolean temp; + Boolean reset; + Boolean debugger; + Boolean mouse; + Boolean io; + Boolean xms; + Boolean v8086; + Boolean paging; + Boolean creg; + Boolean dreg; + Boolean dma; + Boolean unsupported_io; + Boolean serial; + Boolean cdrom; +#ifdef MAGIC_BREAKPOINT + Boolean magic_break_enabled; +#endif /* MAGIC_BREAKPOINT */ + void* record_io; + } bx_debug_t; + + +typedef struct { + char path[512]; + unsigned type; + unsigned initial_status; + } bx_floppy_options; + +typedef struct { + Boolean present; + char path[512]; + unsigned int cylinders; + unsigned int heads; + unsigned int spt; + } bx_disk_options; + +typedef struct +{ + Boolean present; + char dev[512]; + Boolean inserted; +} bx_cdrom_options; + +typedef struct { + char *path; + unsigned long address; + } bx_rom_options; + +typedef struct { + char *path; + } bx_vgarom_options; + +typedef struct { + size_t megs; + } bx_mem_options; + +typedef struct { + char *path; + Boolean cmosImage; + unsigned int time0; + } bx_cmos_options; + +typedef struct { + int valid; + unsigned ioaddr; + unsigned irq; + unsigned char macaddr[6]; + char *ethmod; + char *ethdev; + } bx_ne2k_options; + +typedef struct { + char *midifile, *wavefile, *logfile; + unsigned int midimode, wavemode, loglevel; + Bit32u dmatimer; + } bx_sb16_options; + +typedef struct { + bx_floppy_options floppya; + bx_floppy_options floppyb; + bx_disk_options diskc; + bx_disk_options diskd; + bx_cdrom_options cdromd; + bx_sb16_options sb16; + char bootdrive[2]; + unsigned long vga_update_interval; + unsigned long keyboard_serial_delay; + unsigned long floppy_command_delay; + unsigned long ips; + Boolean mouse_enabled; + Boolean private_colormap; + Boolean i440FXSupport; + bx_cmos_options cmos; + bx_ne2k_options ne2k; + Boolean newHardDriveSupport; + } bx_options_t; + +extern bx_options_t bx_options; +extern bx_debug_t bx_dbg; +#endif + + +int plugin_emulate_inport (int port, int op_size, int count, void *loc); +int plugin_emulate_outport (int port, int op_size, int count, void *loc); +int plugin_alloc_intr (plugin_t *plugin, handler_t handler, int vec); +void plugin_free_intr (plugin_t *plugin, int vec); +int plugin_emulate_int (int vec); + +typedef void (*plugin_pending_t)(void); +int plugin_acknowledge_intr (void); +void plugin_enqueue (plugin_pending_t func); +void plugin_handle_pending (void); +void plugin_register_elapsed(void (*funct)(Bit64u)); +void plugin_register_periodic(void (*funct)(void)); +void plugin_register_mem_map_IO( + void (*f)(Bit32u, unsigned, unsigned, Bit32u *), + Bit32u, Bit32u); +void plugin_call_elapsed (Bit64u elapsed); +void plugin_handle_periodic(void); +int pluginRegisterTimer(void *this_ptr, void (*funct)(void *), + Bit32u useconds, Boolean continuous, + Boolean active); +void pluginActivateTimer(unsigned id, Bit32u usec, Boolean continuous); +void pluginDeactivateTimer(unsigned id); +void pluginSetHRQ(unsigned val); +void pluginSetHRQHackCallback( void (*callback)(void) ); + +void pluginResetSignal(unsigned sig); + +extern Bit32u builtinGetCMOSReg(unsigned reg); +extern void builtinSetCMOSReg(unsigned reg, Bit32u val); +extern void builtinCMOSChecksum(void); +extern void builtinMouseMotion(int d_x, int d_y, unsigned button_state); +extern void builtinGenScancode(Bit32u scancode); +extern unsigned builtinRegisterDMAChannel( + unsigned channel, + void (* dma_read)(Bit8u *data_byte), + void (* dma_write)(Bit8u *data_byte) + ); +extern void builtinDMASetDRQ(unsigned channel, unsigned val); +extern unsigned builtinDMAGetTC(void); + +extern void (*pluginHRQHackCallback)(void); +extern unsigned pluginHRQ; + +extern void (*memMapFunct)(Bit32u, unsigned, unsigned, Bit32u *); + +void plugin_abort (void); + +/* Atomic XCHG for reentrant function plugin_enqueue() */ +#define XCHG(x,y) \ + ({ \ + typeof(x) p; \ + asm ( "xchg %0, %1" : "=r" (p) : "m" (x), "0" (y) : "memory" ); \ + p; \ + }) + +typedef struct { + Bit64u (*wcLSeek)(int fd, Bit64u off64, int whence); + unsigned (*wcRead)(int fd, void *buffer, unsigned len); + unsigned (*wcWrite)(int fd, void *buffer, unsigned len); + void (*wcCommit)(int fd); + } pluginCallbacks_t; + +extern pluginCallbacks_t pluginCallbacks; + +#define pluginRegisterWriteCache(LS, R, W, C) \ + ({ \ + pluginCallbacks.wcLSeek = LS; \ + pluginCallbacks.wcRead = R; \ + pluginCallbacks.wcWrite = W; \ + pluginCallbacks.wcCommit = C; \ + }) + +#define pluginWCLSeek(fd, off64, whence) \ + pluginCallbacks.wcLSeek(fd, off64, whence) + +#define pluginWCRead(fd, buffer, len) \ + pluginCallbacks.wcRead(fd, buffer, len) + +#define pluginWCWrite(fd, buffer, len) \ + pluginCallbacks.wcWrite(fd, buffer, len) + +#define pluginWCCommit(fd) \ + pluginCallbacks.wcCommit(fd) + +// FIXME: called from bochs main (hack) +int bx_init_plugin (); + +// every plugin must define these, within the extern"C" block, so that +// a non-mangled function symbol is available in the shared library. +void plugin_fini(void); +int plugin_init(plugin_t *plugin, int argc, char *argv[]); + + +#ifdef __cplusplus +}; +#endif + +#endif /* __PLUGIN_H */ Index: gui/x.cc =================================================================== RCS file: /cvsroot/bochs/bochs/gui/x.cc,v retrieving revision 1.24 diff -u -r1.24 x.cc --- gui/x.cc 2001/12/08 13:42:55 1.24 +++ gui/x.cc 2001/12/13 03:03:47 @@ -24,7 +24,6 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - extern "C" { #include #include @@ -765,7 +764,7 @@ warp_cursor(warp_home_x-current_x, warp_home_y-current_y); //BX_INFO(("xxx: MOUSE_MOTION: dx=%d, dy=%d", (int) dx, (int) dy)); - bx_devices.keyboard->mouse_motion( dx, dy, mouse_button_state); + BX_EVENT_MOUSE_MOTION (dx, dy, mouse_button_state); //if (warped) { // prev_x = current_x = -1; // prev_y = current_y = -1; @@ -930,7 +929,7 @@ if (press_release) key_event |= BX_KEY_RELEASED; - bx_devices.keyboard->gen_scancode(key_event); + BX_EVENT_GEN_SCANCODE(key_event); } Index: iodev/Makefile.in =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/Makefile.in,v retrieving revision 1.12 diff -u -r1.12 Makefile.in --- iodev/Makefile.in 2001/12/07 21:56:15 1.12 +++ iodev/Makefile.in 2001/12/13 03:03:49 @@ -63,7 +63,7 @@ floppy.o \ harddrv.o \ @IODEBUG_OBJS@ \ - keyboard.o \ + \ parallel.o \ serial.o \ $(VIDEO_OBJS) \ @@ -85,7 +85,13 @@ .@CPP_SUFFIX@.o: $(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(BX_INCDIRS) @CXXFP@$< @OFP@$@ +all: libiodev.a libplex-keyboard.la +libplex-keyboard.la: plex-keyboard.cc plex-keyboard.h + libtool --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(BX_INCDIRS) plex-keyboard.cc + libtool --mode=link $(CXX) plex-keyboard.lo -o libplex-keyboard.la -rpath /tmp/bochslib + -mkdir /tmp/bochslib + libtool --mode=install cp libplex-keyboard.la /tmp/bochslib libiodev.a: $(BX_OBJS) @RMCOMMAND@ libiodev.a Index: iodev/devices.cc =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/devices.cc,v retrieving revision 1.18 diff -u -r1.18 devices.cc --- iodev/devices.cc 2001/10/03 13:10:38 1.18 +++ iodev/devices.cc 2001/12/13 03:03:49 @@ -56,7 +56,8 @@ pci = NULL; #endif pit = NULL; - keyboard = NULL; + // disable so I can use the plex86 keyboard plugin + //keyboard = NULL; dma = NULL; floppy = NULL; cmos = NULL; @@ -171,8 +172,9 @@ dma = &bx_dma; dma->init(this); - keyboard = &bx_keyboard; - keyboard->init(this, cmos); + //disable so I can use plex86 keyboard plugin + //keyboard = &bx_keyboard; + //keyboard->init(this, cmos); #if BX_IODEBUG_SUPPORT iodebug = &bx_iodebug; @@ -305,6 +307,23 @@ } #endif +#if 1 + // separate calls to bx_gui.handle_events from the keyboard code. + { + static int multiple=0; + if ( ++multiple==10) + { + multiple=0; + bx_gui.handle_events(); + } + } +#endif + +#if 0 + // the plex86 keyboard has its own timer handler and triggers IRQs on its + // own, so while using the plex86 keyboard plugin, this code is not needed. + // Except, that the keyboard->periodic() function happens to call + // bx_gui.handle_events for all GUI events. retval = keyboard->periodic( TIMER_DELTA ); if (retval & 0x01) { if (bx_dbg.keyboard) @@ -313,6 +332,7 @@ } if (retval & 0x02) pic->trigger_irq(12); +#endif #if BX_SUPPORT_APIC // update local APIC timers Index: iodev/iodev.h =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/iodev.h,v retrieving revision 1.10 diff -u -r1.10 iodev.h --- iodev/iodev.h 2001/10/03 13:10:38 1.10 +++ iodev/iodev.h 2001/12/13 03:03:50 @@ -39,7 +39,7 @@ class bx_pit_c; -class bx_keyb_c; +//class bx_keyb_c; class bx_dma_c; class bx_floppy_ctrl_c; class bx_cmos_c; @@ -98,7 +98,7 @@ bx_ioapic_c *ioapic; bx_pci_c *pci; bx_pit_c *pit; - bx_keyb_c *keyboard; + //bx_keyb_c *keyboard; bx_dma_c *dma; bx_floppy_ctrl_c *floppy; bx_cmos_c *cmos; @@ -162,7 +162,8 @@ #if BX_IODEBUG_SUPPORT # include "iodev/iodebug.h" #endif -#include "iodev/keyboard.h" +// maybe should be disabled while testing plex86 keyboard plugin +//#include "iodev/keyboard.h" #include "iodev/parallel.h" #include "iodev/pic.h" #include "iodev/pit.h" Index: iodev/plex-keyboard.cc =================================================================== RCS file: iodev/plex-keyboard.cc diff -N plex-keyboard.cc --- /dev/null Thu May 24 22:33:05 2001 +++ iodev/plex-keyboard.cc Wed Dec 12 19:03:51 2001 @@ -0,0 +1,1360 @@ +// Copyright (C) 2000 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +// Now features proper implementation of keyboard opcodes 0xF4 to 0xF6 +// Silently ignores PS/2 keyboard extensions (0xF7 to 0xFD) +// Explicit panic on resend (0xFE) +// +// Emmanuel Marty + + +#include "bochs.h" +#include "plex-keyboard.h" + + +//FIXME +#define LOG_THIS genlog-> +//FIXME +#define bx_printf printf +#define bx_panic printf + +#define MOUSE_MODE_RESET 10 +#define MOUSE_MODE_STREAM 11 +#define MOUSE_MODE_REMOTE 12 +#define MOUSE_MODE_WRAP 13 + + +#if BX_USE_KEY_SMF +plex_keyb_c plex_keyboard; +#define this (&plex_keyboard) +#endif + + int +plugin_init(plugin_t *plugin, int argc, char *argv[]) +{ + plex_keyb_c *keyboard; + +#if BX_USE_KEY_SMF + keyboard = &plex_keyboard; +#else + keyboard = new plex_keyb_c(); +#endif + keyboard->init(); + + return(0); // Success +} + + void +plugin_fini(void) +{ +} + + static void +keybMouseMotion(int dx, int dy, unsigned mouse_button_state) +{ + plex_keyboard.mouse_motion( dx, dy, mouse_button_state); +} + + static void +keybGenScancode(Bit32u key_event) +{ + plex_keyboard.gen_scancode(key_event); +} + + +plex_keyb_c::plex_keyb_c(void) +{ + // constructor + // should zero out state info here??? + memset( &s, 0, sizeof(s) ); + pluginMouseMotion = keybMouseMotion; + pluginGenScancode = keybGenScancode; +} + +plex_keyb_c::~plex_keyb_c(void) +{ + // destructor +} + + +// flush internal buffer and reset keyboard settings to power-up condition + void +plex_keyb_c::resetinternals(Boolean powerup) +{ + Bit32u i; + + PLEX_KEY_THIS s.kbd_internal_buffer.num_elements = 0; + for (i=0; iget (), 0, 0); + + resetinternals(1); + + PLEX_KEY_THIS s.kbd_internal_buffer.led_status = 0; + PLEX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1; + + PLEX_KEY_THIS s.mouse_internal_buffer.num_elements = 0; + for (i=0; iread(address, io_len) ); +} + + + Bit32u +plex_keyb_c::read(Bit32u address, unsigned io_len) +{ +#else + UNUSED(this_ptr); +#endif // !BX_USE_KEY_SMF + + Bit32u ret = 0; + + if (io_len > 1) + BX_PANIC(("kbd: io read to address %08x, len=%u\n", + (unsigned) address, (unsigned) io_len)); + + +//bx_printf("# KBD: read from port 0x%04x\n", (unsigned) address); + + if (address == 0x60) { /* output buffer */ + Bit8u val; + if (PLEX_KEY_THIS s.kbd_controller.auxb) { /* mouse byte available */ + val = PLEX_KEY_THIS s.kbd_controller.aux_output_buffer; + PLEX_KEY_THIS s.kbd_controller.aux_output_buffer = 0; + PLEX_KEY_THIS s.kbd_controller.outb = 0; + PLEX_KEY_THIS s.kbd_controller.auxb = 0; + + if (PLEX_KEY_THIS s.controller_Qsize) { + unsigned i; + PLEX_KEY_THIS s.kbd_controller.aux_output_buffer = PLEX_KEY_THIS s.controller_Q[0]; + PLEX_KEY_THIS s.kbd_controller.outb = 1; + PLEX_KEY_THIS s.kbd_controller.auxb = 1; + if (PLEX_KEY_THIS s.kbd_controller.allow_irq12) + pluginTriggerIRQ(12); + for (i=0; i= 2 + else if (address == 0x64) { /* status register */ + Bit8u val; + + val = (PLEX_KEY_THIS s.kbd_controller.pare << 7) | + (PLEX_KEY_THIS s.kbd_controller.tim << 6) | + (PLEX_KEY_THIS s.kbd_controller.auxb << 5) | + (PLEX_KEY_THIS s.kbd_controller.keyl << 4) | + (PLEX_KEY_THIS s.kbd_controller.c_d << 3) | + (PLEX_KEY_THIS s.kbd_controller.sysf << 2) | + (PLEX_KEY_THIS s.kbd_controller.inpb << 1) | + PLEX_KEY_THIS s.kbd_controller.outb; + RETURN(val); + } + +#else /* BX_CPU_LEVEL > 0 */ + /* XT MODE, System 8255 Mode Register */ + else if (address == 0x64) { /* status register */ + if (bx_dbg.keyboard) + bx_printf("KBD: IO read from port 64h, system 8255 mode register\n"); + RETURN(PLEX_KEY_THIS s.kbd_controller.outb); + } +#endif /* BX_CPU_LEVEL > 0 */ + + else { + BX_PANIC(("KBD: unknown address in io read to keyboard port %x\n", + (unsigned) address)); + RETURN(0); /* keep compiler happy */ + } + + read_return: + if (bx_dbg.keyboard) + bx_printf("keyboard: 8-bit read from %04x = %02x\n", (unsigned)address, ret); + return ret; +} + + + // static IO port write callback handler + // redirects to non-static class handler to avoid virtual functions + + void +plex_keyb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len) +{ +#if !BX_USE_KEY_SMF + plex_keyb_c *class_ptr = (plex_keyb_c *) this_ptr; + + class_ptr->write(address, value, io_len); +} + + void +plex_keyb_c::write( Bit32u address, Bit32u value, unsigned io_len) +{ +#else + UNUSED(this_ptr); +#endif // !BX_USE_KEY_SMF + Bit8u command_byte; + + if (io_len > 1) + BX_PANIC(("kbd: io write to address %08x, len=%u\n", + (unsigned) address, (unsigned) io_len)); + + if (bx_dbg.keyboard) + bx_printf("keyboard: 8-bit write to %04x = %02x\n", (unsigned)address, (unsigned)value); + + +//bx_printf("# KBD: WRITE(%02x) = %02x\n", (unsigned) address, +// (unsigned) value); + + switch (address) { + case 0x60: // input buffer + // if expecting data byte from command last sent to port 64h + if (PLEX_KEY_THIS s.kbd_controller.expecting_port60h) { + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 0; + // data byte written last to 0x60 + PLEX_KEY_THIS s.kbd_controller.c_d = 0; + if (PLEX_KEY_THIS s.kbd_controller.inpb) { + bx_panic("KBD: write to port 60h, not ready for write\n"); + } + switch (PLEX_KEY_THIS s.kbd_controller.last_comm) { + case 0x60: // write command byte + { + Boolean scan_convert, disable_keyboard, + disable_aux; + + scan_convert = (value >> 6) & 0x01; + disable_aux = (value >> 5) & 0x01; + disable_keyboard = (value >> 4) & 0x01; + PLEX_KEY_THIS s.kbd_controller.sysf = (value >> 2) & 0x01; + PLEX_KEY_THIS s.kbd_controller.allow_irq1 = (value >> 0) & 0x01; + PLEX_KEY_THIS s.kbd_controller.allow_irq12 = (value >> 1) & 0x01; + set_kbd_clock_enable(!disable_keyboard); + set_aux_clock_enable(!disable_aux); + if (PLEX_KEY_THIS s.kbd_controller.allow_irq12 && PLEX_KEY_THIS s.kbd_controller.auxb) + pluginTriggerIRQ(12); + else if (PLEX_KEY_THIS s.kbd_controller.allow_irq1 && PLEX_KEY_THIS s.kbd_controller.outb) + pluginTriggerIRQ(1); + +//bx_printf("# allow_irq12 set to %u\n", (unsigned) +// PLEX_KEY_THIS s.kbd_controller.allow_irq12); + if ( !scan_convert ) + bx_printf("keyboard: (mch) scan convert turned off\n"); + + // (mch) NT needs this + PLEX_KEY_THIS s.kbd_controller.scan_convert = scan_convert; + } + break; + case 0xd1: // write output port + if (bx_dbg.keyboard) + bx_printf("KBD: write output port with value %02xh\n", + (unsigned) value); + BX_SET_ENABLE_A20( (value & 0x02) != 0 ); + if (!(value & 0x01)) BX_PANIC(("KBD: IO write: processor reset requested!\n")); + break; + case 0xd4: // Write to mouse + // I don't think this enables the AUX clock + //set_aux_clock_enable(1); // enable aux clock line + kbd_ctrl_to_mouse(value); + // ??? should I reset to previous value of aux enable? + break; + + case 0xd3: // write mouse output buffer + // Queue in mouse output buffer + controller_enQ(value, 1); + break; + + default: + BX_PANIC(("KBD: === unsupported write to port 60h(lastcomm=%02x): %02x\n", + (unsigned) PLEX_KEY_THIS s.kbd_controller.last_comm, (unsigned) value)); + } + } + else { + // data byte written last to 0x60 + PLEX_KEY_THIS s.kbd_controller.c_d = 0; + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 0; + /* pass byte to keyboard */ + /* ??? should conditionally pass to mouse device here ??? */ + if (PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0) { + bx_printf("KBD: keyboard disabled & send of byte %02x to kbd\n", + (unsigned) value); + } + kbd_ctrl_to_kbd(value); + } + break; + + case 0x64: // control register + // command byte written last to 0x64 + PLEX_KEY_THIS s.kbd_controller.c_d = 1; + PLEX_KEY_THIS s.kbd_controller.last_comm = value; + // most commands NOT expecting port60 write next + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 0; + + switch (value) { + case 0x20: // get keyboard command byte + if (bx_dbg.keyboard) + bx_printf("KBD: get keyboard command byte\n"); + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + command_byte = + (PLEX_KEY_THIS s.kbd_controller.scan_convert << 6) | + ((!PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled) << 5) | + ((!PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled) << 4) | + (0 << 3) | + (PLEX_KEY_THIS s.kbd_controller.sysf << 2) | + (PLEX_KEY_THIS s.kbd_controller.allow_irq12 << 1) | + (PLEX_KEY_THIS s.kbd_controller.allow_irq1 << 0); + controller_enQ(command_byte, 0); + break; + case 0x60: // write command byte + if (bx_dbg.keyboard) + bx_printf("KBD: write command byte\n"); + // following byte written to port 60h is command byte + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 1; + break; + + case 0xa1: + bx_printf ("KBD: Dummy out Green PC for now : 0xa1\n"); + break; + + case 0xa7: // disable the aux device + set_aux_clock_enable(0); + if (bx_dbg.keyboard) bx_printf("KBD: aux device disabled\n"); + break; + case 0xa8: // enable the aux device + set_aux_clock_enable(1); + if (bx_dbg.keyboard) bx_printf("KBD: aux device enabled\n"); + break; + case 0xa9: // Test Mouse Port + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + controller_enQ(0x00, 0); // no errors detected + break; + case 0xaa: // motherboard controller self test + if (bx_dbg.keyboard) bx_printf("KBD: Self Test\n"); + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + // (mch) Why is this commented out??? Enabling + PLEX_KEY_THIS s.kbd_controller.sysf = 1; // self test complete + controller_enQ(0x55, 0); // controller OK + break; + case 0xab: // Interface Test + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + controller_enQ(0x00, 0); + break; + case 0xad: // disable keyboard + set_kbd_clock_enable(0); + if (bx_dbg.keyboard) bx_printf("KBD: keyboard disabled\n"); + break; + case 0xae: // enable keyboard + set_kbd_clock_enable(1); + if (bx_dbg.keyboard) bx_printf("KBD: keyboard enabled\n"); + break; + case 0xc0: // read input port + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + // keyboard power normal + controller_enQ(0x00, 0); + break; + case 0xd0: // read output port: next byte read from port 60h + if (bx_dbg.keyboard) + bx_printf("KBD: io write to port 64h, command d0h (partial)\n"); + // controller output buffer must be empty + if (PLEX_KEY_THIS s.kbd_controller.outb) { +bx_panic("kbd: OUTB set and command 0x%02x encountered\n", value); + break; + } + controller_enQ( + (PLEX_KEY_THIS s.kbd_controller.auxb << 5) | + (PLEX_KEY_THIS s.kbd_controller.outb << 4) | + (BX_GET_ENABLE_A20() << 1) | + 0x01, 0); + break; + + case 0xd1: // write output port: next byte written to port 60h + if (bx_dbg.keyboard) + bx_printf("KBD: write output port\n"); + // following byte to port 60h written to output port + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 1; + break; + + case 0xd3: // write mouse output buffer + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 1; + break; + + case 0xd4: // write to mouse + if (bx_dbg.mouse) + bx_printf("KBD: io write 0x64: command = 0xD4 (write to mouse)\n"); + // following byte written to port 60h + PLEX_KEY_THIS s.kbd_controller.expecting_port60h = 1; + break; + + case 0xd2: // write keyboard output buffer + case 0xdd: // Disable A20 Address Line + case 0xdf: // Enable A20 Address Line + case 0xc1: // Continuous Input Port Poll, Low + case 0xc2: // Continuous Input Port Poll, High + case 0xe0: // Read Test Inputs + bx_panic("KBD: io write 0x64: command = %02xh\n", (unsigned) value); + break; + + case 0xfe: // System Reset, transition to real mode + if (bx_dbg.keyboard) + bx_printf("KBD: system reset\n"); + bx_panic("system reset via KBD ctrl command FEh\n"); + // Use bx_pc_system if necessary bx_cpu.reset_cpu(); + pluginResetSignal( 0 ); + break; + + default: + if (value==0xff || (value>=0xf0 && value<=0xfd)) { + /* useless pulse output bit commands ??? */ + if (bx_dbg.keyboard) + bx_printf("KBD: io write to port 64h, useless command %02x\n", + (unsigned) value); + return; + } + bx_panic("KBD: unsupported io write to keyboard port %x, value = %x\n", + (unsigned) address, (unsigned) value); + break; + } + break; + + default: bx_panic("KBD: unknown address in plex_keyb_c::write()\n"); + } +} + + + void +plex_keyb_c::gen_scancode(Bit32u key) +{ + Bit8u scancode; + + if (bx_dbg.record_io) { + //fprintf((FILE*)bx_dbg.record_io, "gen_scancode %lld %x\n", bx_pc_system.time_ticks(), key); + } + + if (!PLEX_KEY_THIS s.kbd_controller.scan_convert) + bx_panic("keyboard: gen_scancode with scan_convert cleared\n"); + + if (bx_dbg.keyboard) + bx_printf("KBD: gen_scancode(): scancode: %08x\n", (unsigned) key); + + // Ignore scancode if keyboard clock is driven low + if (PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0) + return; + + // Ignore scancode if scanning is disabled + if (PLEX_KEY_THIS s.kbd_internal_buffer.scanning_enabled==0) + return; + + // should deal with conversions from KSCAN to system scan codes here + + switch (key & 0xff) { + case BX_KEY_CTRL_L: scancode = 0x1d; break; + case BX_KEY_CTRL_R: scancode = 0x1d; break; + case BX_KEY_SHIFT_L: scancode = 0x2a; break; + case BX_KEY_SHIFT_R: scancode = 0x36; break; + case BX_KEY_ESC: scancode = 0x01; break; + + case BX_KEY_ALT_L: scancode = 0x38; break; + + case BX_KEY_A: scancode = 0x1e; break; + case BX_KEY_B: scancode = 0x30; break; + case BX_KEY_C: scancode = 0x2e; break; + case BX_KEY_D: scancode = 0x20; break; + case BX_KEY_E: scancode = 0x12; break; + case BX_KEY_F: scancode = 0x21; break; + case BX_KEY_G: scancode = 0x22; break; + case BX_KEY_H: scancode = 0x23; break; + case BX_KEY_I: scancode = 0x17; break; + case BX_KEY_J: scancode = 0x24; break; + case BX_KEY_K: scancode = 0x25; break; + case BX_KEY_L: scancode = 0x26; break; + case BX_KEY_M: scancode = 0x32; break; + case BX_KEY_N: scancode = 0x31; break; + case BX_KEY_O: scancode = 0x18; break; + case BX_KEY_P: scancode = 0x19; break; + case BX_KEY_Q: scancode = 0x10; break; + case BX_KEY_R: scancode = 0x13; break; + case BX_KEY_S: scancode = 0x1f; break; + case BX_KEY_T: scancode = 0x14; break; + case BX_KEY_U: scancode = 0x16; break; + case BX_KEY_V: scancode = 0x2f; break; + case BX_KEY_W: scancode = 0x11; break; + case BX_KEY_X: scancode = 0x2d; break; + case BX_KEY_Y: scancode = 0x15; break; + case BX_KEY_Z: scancode = 0x2c; break; + + case BX_KEY_0: scancode = 0x0b; break; + case BX_KEY_1: scancode = 0x02; break; + case BX_KEY_2: scancode = 0x03; break; + case BX_KEY_3: scancode = 0x04; break; + case BX_KEY_4: scancode = 0x05; break; + case BX_KEY_5: scancode = 0x06; break; + case BX_KEY_6: scancode = 0x07; break; + case BX_KEY_7: scancode = 0x08; break; + case BX_KEY_8: scancode = 0x09; break; + case BX_KEY_9: scancode = 0x0a; break; + + case BX_KEY_SPACE: scancode = 0x39; break; + case BX_KEY_SINGLE_QUOTE: scancode = 0x28; break; + case BX_KEY_COMMA: scancode = 0x33; break; + case BX_KEY_PERIOD: scancode = 0x34; break; + case BX_KEY_SLASH: scancode = 0x35; break; + + case BX_KEY_SEMICOLON: scancode = 0x27; break; + case BX_KEY_EQUALS: scancode = 0x0d; break; + + case BX_KEY_LEFT_BRACKET: scancode = 0x1a; break; + case BX_KEY_BACKSLASH: scancode = 0x2b; break; + case BX_KEY_RIGHT_BRACKET: scancode = 0x1b; break; + case BX_KEY_MINUS: scancode = 0x0c; break; + case BX_KEY_GRAVE: scancode = 0x29; break; + + case BX_KEY_BACKSPACE: scancode = 0x0e; break; + case BX_KEY_ENTER: scancode = 0x1c; break; + case BX_KEY_TAB: scancode = 0x0f; break; + + case BX_KEY_LEFT: + //bx_printf("# Grey left-arrow key not on 83-key keyboard\n"); + scancode = 0x4b; break; + case BX_KEY_RIGHT: + //bx_printf("# Grey right-arrow key not on 83-key keyboard\n"); + scancode = 0x4d; break; + case BX_KEY_UP: + //bx_printf("# Grey up-arrow key not on 83-key keyboard\n"); + scancode = 0x48; break; + case BX_KEY_DOWN: + //bx_printf("# Grey down-arrow key not on 83-key keyboard\n"); + scancode = 0x50; break; + + case BX_KEY_KP_LEFT: scancode = 0x4b; break; + case BX_KEY_KP_RIGHT: scancode = 0x4d; break; + case BX_KEY_KP_UP: scancode = 0x48; break; + case BX_KEY_KP_DOWN: scancode = 0x50; break; + + case BX_KEY_INSERT: + bx_printf("# Grey insert key not on 83-key keyboard\n"); + return; + case BX_KEY_DELETE: + bx_printf("# Grey delete key not on 83-key keyboard\n"); + return; + case BX_KEY_HOME: + bx_printf("# Grey home key not on 83-key keyboard\n"); + return; + case BX_KEY_END: + bx_printf("# Grey end key not on 83-key keyboard\n"); + return; + case BX_KEY_PAGE_UP: + bx_printf("# Grey page-up key not on 83-key keyboard\n"); + return; + case BX_KEY_PAGE_DOWN: + bx_printf("# Grey page-down key not on 83-key keyboard\n"); + return; + + case BX_KEY_KP_INSERT: scancode = 0x52; break; + case BX_KEY_KP_DELETE: scancode = 0x53; break; + case BX_KEY_KP_HOME: scancode = 0x47; break; + case BX_KEY_KP_END: scancode = 0x4f; break; + case BX_KEY_KP_PAGE_UP: scancode = 0x49; break; + case BX_KEY_KP_PAGE_DOWN: scancode = 0x51; break; + + case BX_KEY_KP_ADD: scancode = 0x4e; break; + case BX_KEY_KP_SUBTRACT: scancode = 0x4a; break; + case BX_KEY_KP_5: scancode = 0x4c; break; + case BX_KEY_KP_ENTER: + bx_printf("# Grey Enter key not on 83-key keyboard\n"); + return; + case BX_KEY_KP_MULTIPLY: + bx_printf("# Grey Multiply key not on 83-key keyboard\n"); + return; + case BX_KEY_KP_DIVIDE: + bx_printf("# Grey Divide key not on 83-key keyboard\n"); + return; + case BX_KEY_NUM_LOCK: scancode = 0x45; break; + + case BX_KEY_F1: scancode = 0x3b; break; + case BX_KEY_F2: scancode = 0x3c; break; + case BX_KEY_F3: scancode = 0x3d; break; + case BX_KEY_F4: scancode = 0x3e; break; + case BX_KEY_F5: scancode = 0x3f; break; + case BX_KEY_F6: scancode = 0x40; break; + case BX_KEY_F7: scancode = 0x41; break; + case BX_KEY_F8: scancode = 0x42; break; + case BX_KEY_F9: scancode = 0x43; break; + case BX_KEY_F10: scancode = 0x44; break; + + default: + bx_printf("# plex_keyb_c::gen_scancode : Unhandled %u\n", + (unsigned) key); + return; + } + if (key & BX_KEY_RELEASED) + scancode |= 0x80; + kbd_enQ(scancode); +} + + + + void +plex_keyb_c::set_kbd_clock_enable(Bit8u value) +{ + Boolean prev_kbd_clock_enabled; + + if (value==0) { + PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 0; + } + else { + /* is another byte waiting to be sent from the keyboard ? */ + prev_kbd_clock_enabled = PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled; + PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1; + + if (prev_kbd_clock_enabled==0 && PLEX_KEY_THIS s.kbd_controller.outb==0) { + activate_timer(); + } + } +} + + + + void +plex_keyb_c::set_aux_clock_enable(Bit8u value) +{ + Boolean prev_aux_clock_enabled; + + if (bx_dbg.keyboard) + bx_printf("set_aux_clock_enable(%u)\n", (unsigned) value); + if (value==0) { + PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0; + } + else { + /* is another byte waiting to be sent from the keyboard ? */ + prev_aux_clock_enabled = PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled; + PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled = 1; + if (prev_aux_clock_enabled==0 && PLEX_KEY_THIS s.kbd_controller.outb==0) + activate_timer(); + } +} + + Bit8u +plex_keyb_c::get_kbd_enable(void) +{ +#ifdef BX_DEBUG + if (bx_dbg.keyboard) + bx_printf("KBD: get_kbd_enable(): getting kbd_clock_enabled of: %02x\n", + (unsigned) PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled); +#endif + + return(PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled); +} + + void +plex_keyb_c::controller_enQ(Bit8u data, unsigned source) +{ + // source is 0 for keyboard, 1 for mouse + + if (bx_dbg.keyboard) + bx_printf("controller_enQ(%02x)\n", (unsigned) data); + + if (PLEX_KEY_THIS s.kbd_controller.outb) + bx_printf("KBD: controller_enQ(): OUTB set!\n"); + + // see if we need to Q this byte from the controller + if (PLEX_KEY_THIS s.kbd_controller.outb) { + if (PLEX_KEY_THIS s.controller_Qsize >= BX_KBD_CONTROLLER_QSIZE) + bx_panic("KBD: controller_enq(): controller_Q full!\n"); + PLEX_KEY_THIS s.controller_Q[PLEX_KEY_THIS s.controller_Qsize++] = data; + PLEX_KEY_THIS s.controller_Qsource = source; + return; + } + + if (source == 0) { // keyboard + PLEX_KEY_THIS s.kbd_controller.kbd_output_buffer = data; + PLEX_KEY_THIS s.kbd_controller.outb = 1; + PLEX_KEY_THIS s.kbd_controller.auxb = 0; + PLEX_KEY_THIS s.kbd_controller.inpb = 0; + if (PLEX_KEY_THIS s.kbd_controller.allow_irq1) + pluginTriggerIRQ(1); + } + else { // mouse + PLEX_KEY_THIS s.kbd_controller.aux_output_buffer = data; + PLEX_KEY_THIS s.kbd_controller.outb = 1; + PLEX_KEY_THIS s.kbd_controller.auxb = 1; + PLEX_KEY_THIS s.kbd_controller.inpb = 0; + if (PLEX_KEY_THIS s.kbd_controller.allow_irq12) + pluginTriggerIRQ(12); + } +} + +void +plex_keyb_c::kbd_enQ_imm(Bit8u val) +{ + int tail; + + if (PLEX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) { + bx_panic("KBD: internal keyboard buffer full (imm)\n"); + return; + } + + /* enqueue scancode in multibyte internal keyboard buffer */ + tail = (PLEX_KEY_THIS s.kbd_internal_buffer.head + PLEX_KEY_THIS s.kbd_internal_buffer.num_elements) % + BX_KBD_ELEMENTS; + + PLEX_KEY_THIS s.kbd_controller.kbd_output_buffer = val; + PLEX_KEY_THIS s.kbd_controller.outb = 1; + + if (PLEX_KEY_THIS s.kbd_controller.allow_irq1) + pluginTriggerIRQ(1); +} + + + void +plex_keyb_c::kbd_enQ(Bit8u scancode) +{ + int tail; + + if (bx_dbg.keyboard) + bx_printf("enQ(%02x)\n", (unsigned) scancode); + + if (PLEX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) { + bx_printf("KBD: internal keyboard buffer full, ignoring scancode.(%02x)\n", + (unsigned) scancode); + return; + } + + /* enqueue scancode in multibyte internal keyboard buffer */ + if (bx_dbg.keyboard) + bx_printf("KBD: enQ: putting scancode %02x in internal buffer\n", + (unsigned) scancode); + tail = (PLEX_KEY_THIS s.kbd_internal_buffer.head + PLEX_KEY_THIS s.kbd_internal_buffer.num_elements) % + BX_KBD_ELEMENTS; + PLEX_KEY_THIS s.kbd_internal_buffer.buffer[tail] = scancode; + PLEX_KEY_THIS s.kbd_internal_buffer.num_elements++; + + if (!PLEX_KEY_THIS s.kbd_controller.outb && PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled) { + activate_timer(); +//bx_printf("# activating timer...\n"); + return; + } +//bx_printf("# not activating timer...\n"); +//bx_printf("# allow_irq1 = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.allow_irq1); +//bx_printf("# outb = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.outb); +//bx_printf("# clock_enab = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled); +//bx_printf("# out_buffer = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.kbd_output_buffer); +} + + Boolean +plex_keyb_c::mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3) +{ + if ((PLEX_KEY_THIS s.mouse_internal_buffer.num_elements + 3) >= BX_MOUSE_BUFF_SIZE) { + return(0); /* buffer doesn't have the space */ + } + +//bx_printf("mouse: enQ_packet(%02x, %02x, %02x)\n", +// (unsigned) b1, (unsigned) b2, (unsigned) b3); + + mouse_enQ(b1); + mouse_enQ(b2); + mouse_enQ(b3); + return(1); +} + + + void +plex_keyb_c::mouse_enQ(Bit8u mouse_data) +{ + int tail; + + if (bx_dbg.mouse) + bx_printf("mouse_enQ(%02x)\n", (unsigned) mouse_data); + + if (PLEX_KEY_THIS s.mouse_internal_buffer.num_elements >= BX_MOUSE_BUFF_SIZE) { + bx_printf("mouse: internal mouse buffer full, ignoring mouse data.(%02x)\n", + (unsigned) mouse_data); + return; + } +//bx_printf("# mouse_enq() aux_clock_enabled = %u\n", +// (unsigned) PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled); + + /* enqueue mouse data in multibyte internal mouse buffer */ + tail = (PLEX_KEY_THIS s.mouse_internal_buffer.head + PLEX_KEY_THIS s.mouse_internal_buffer.num_elements) % + BX_MOUSE_BUFF_SIZE; + PLEX_KEY_THIS s.mouse_internal_buffer.buffer[tail] = mouse_data; + PLEX_KEY_THIS s.mouse_internal_buffer.num_elements++; + + if (!PLEX_KEY_THIS s.kbd_controller.outb && PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled) { + activate_timer(); +//bx_printf("# activating timer...\n"); + return; + } +//bx_printf("# not activating timer...\n"); +//bx_printf("# allow_irq12= %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.allow_irq12); +//bx_printf("# outb = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.outb); +//bx_printf("# clock_enab = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled); +//bx_printf("# out_buffer = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.aux_output_buffer); +} + + void +plex_keyb_c::kbd_ctrl_to_kbd(Bit8u value) +{ + if (bx_dbg.keyboard) + bx_printf("KBD: controller passed byte %02xh to keyboard\n"); + + if (PLEX_KEY_THIS s.kbd_internal_buffer.expecting_typematic) { + PLEX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0; + PLEX_KEY_THIS s.kbd_internal_buffer.delay = (value >> 5) & 0x03; + switch (PLEX_KEY_THIS s.kbd_internal_buffer.delay) { + case 0: bx_printf("KBD: setting delay to 250 mS\n"); break; + case 1: bx_printf("KBD: setting delay to 250 mS\n"); break; + case 2: bx_printf("KBD: setting delay to 250 mS\n"); break; + case 3: bx_printf("KBD: setting delay to 250 mS\n"); break; + } + PLEX_KEY_THIS s.kbd_internal_buffer.repeat_rate = value & 0x1f; + bx_printf("KBD: setting repeat rate to %u\n", (unsigned) value); + kbd_enQ(0xFA); // send ACK + return; + } + + if (PLEX_KEY_THIS s.kbd_internal_buffer.expecting_led_write) { + PLEX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0; + PLEX_KEY_THIS s.kbd_internal_buffer.led_status = value; + BX_INFO(("KBD: LED status set to %02x\n", + (unsigned) PLEX_KEY_THIS s.kbd_internal_buffer.led_status)); + kbd_enQ(0xFA); // send ACK %%% + return; + } + + switch (value) { + case 0x00: // ??? ignore and let OS timeout with no response + kbd_enQ(0xFA); // send ACK %%% + return; + break; + + case 0x05: // ??? + // (mch) trying to get this to work... + PLEX_KEY_THIS s.kbd_controller.sysf = 1; + kbd_enQ_imm(0xfe); + return; + break; + + case 0xed: // LED Write + PLEX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 1; + kbd_enQ(0xFA); // send ACK %%% + return; + break; + + case 0xee: // echo + kbd_enQ(0xEE); // return same byte (EEh) as echo diagnostic + return; + break; + + case 0xf0: // set scancode - let OS time out + bx_printf("KBD: set scancode command received\n"); + return; + + case 0xf2: // identify keyboard + bx_printf("KBD: indentify keyboard command received\n"); + kbd_enQ(0xFA); // AT sends ACK, MFII sends ACK+ABh+41h + return; + break; + + case 0xf3: // typematic info + PLEX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 1; + bx_printf("KBD: setting typematic info\n"); + kbd_enQ(0xFA); // send ACK + return; + break; + + case 0xf4: // flush scancodes buffer and modes, then enable keyboard + resetinternals(0); + kbd_enQ(0xFA); // send ACK + PLEX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1; + return; + break; + + case 0xf5: // reset keyboard to power-up settings and disable scanning + resetinternals(1); + kbd_enQ(0xFA); // send ACK + PLEX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 0; + bx_printf ("KBD: reset-disable command received\n"); + return; + break; + + case 0xf6: // reset keyboard to power-up settings and enable scanning + resetinternals(1); + kbd_enQ(0xFA); // send ACK + PLEX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1; + bx_printf ("KBD: reset-enable command received\n"); + return; + break; + + case 0xf7: // PS/2 Set All Keys To Typematic + case 0xf8: // PS/2 Set All Keys to Make/Break + case 0xf9: // PS/2 PS/2 Set All Keys to Make + case 0xfa: // PS/2 Set All Keys to Typematic Make/Break + case 0xfb: // PS/2 Set Key Type to Typematic + case 0xfc: // PS/2 Set Key Type to Make/Break + case 0xfd: // PS/2 Set Key Type to Make + // Silently ignore and let the OS timeout, for now. + // If anyone has code around that makes use of that, I can + // provide documentation on their behavior (ask core@ggi-project.org) + return; + break; + + case 0xfe: // resend. aiiee. + bx_panic ("KBD: got 0xFE (resend)\n"); + return; + break; + + case 0xff: // reset: internal keyboard reset and afterwards the BAT + bx_printf("KBD: rest command received\n"); + kbd_enQ(0xFA); // send ACK + kbd_enQ(0xAA); // BAT test passed + return; + break; + +case 0xd3: + kbd_enQ(0xfa); + return; + + default: + bx_panic("KBD: kbd_ctrl_to_kbd(): got value of %02x\n", + (unsigned) value); + kbd_enQ(0xFA); /* send ACK ??? */ + return; + break; + } +} + + void +plex_keyb_c::timer_handler(void *this_ptr) +{ + plex_keyb_c *class_ptr = (plex_keyb_c *) this_ptr; + + class_ptr->periodic( bx_options.Okeyboard_serial_delay->get () ); +} + + void +plex_keyb_c::periodic( Bit32u usec_delta ) +{ + PLEX_KEY_THIS s.timer_pending = 0; + if (PLEX_KEY_THIS s.kbd_controller.outb) { + return; + } + + /* nothing in outb, look for possible data xfer from keyboard or mouse */ + if (PLEX_KEY_THIS s.kbd_controller.kbd_clock_enabled && PLEX_KEY_THIS s.kbd_internal_buffer.num_elements) { +//bx_printf("# servicing keyboard code\n"); + if (bx_dbg.keyboard) + bx_printf("KBD: service_keyboard: key in internal buffer waiting\n"); + PLEX_KEY_THIS s.kbd_controller.kbd_output_buffer = + PLEX_KEY_THIS s.kbd_internal_buffer.buffer[PLEX_KEY_THIS s.kbd_internal_buffer.head]; + PLEX_KEY_THIS s.kbd_controller.outb = 1; + PLEX_KEY_THIS s.kbd_controller.auxb = 0; +//bx_printf("# ___kbd::periodic kbd\n"); + PLEX_KEY_THIS s.kbd_internal_buffer.head = (PLEX_KEY_THIS s.kbd_internal_buffer.head + 1) % + BX_KBD_ELEMENTS; + PLEX_KEY_THIS s.kbd_internal_buffer.num_elements--; + if (PLEX_KEY_THIS s.kbd_controller.allow_irq1) + pluginTriggerIRQ(1); + } + else if (PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled && PLEX_KEY_THIS s.mouse_internal_buffer.num_elements) { +//bx_printf("# servicing mouse code\n"); + if (bx_dbg.mouse) + bx_printf("KBD: service_keyboard: key in internal buffer waiting\n"); + PLEX_KEY_THIS s.kbd_controller.aux_output_buffer = + PLEX_KEY_THIS s.mouse_internal_buffer.buffer[PLEX_KEY_THIS s.mouse_internal_buffer.head]; + + PLEX_KEY_THIS s.kbd_controller.outb = 1; + PLEX_KEY_THIS s.kbd_controller.auxb = 1; +//bx_printf("# ___kbd:periodic aux\n"); + PLEX_KEY_THIS s.mouse_internal_buffer.head = (PLEX_KEY_THIS s.mouse_internal_buffer.head + 1) % + BX_MOUSE_BUFF_SIZE; + PLEX_KEY_THIS s.mouse_internal_buffer.num_elements--; +//bx_printf("# allow12 = %u\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.allow_irq12); + if (PLEX_KEY_THIS s.kbd_controller.allow_irq12) + pluginTriggerIRQ(12); + } + else { +//bx_printf("# servicing no code\n"); + if (bx_dbg.keyboard) { + bx_printf("KBD: service_keyboard(): no keys waiting\n"); + } + } +} + + + + + void +plex_keyb_c::activate_timer(void) +{ + if (PLEX_KEY_THIS s.timer_pending == 0) { + PLEX_KEY_THIS s.timer_pending = 1; + pluginActivateTimer( PLEX_KEY_THIS timer_handle, + (unsigned) bx_options.Okeyboard_serial_delay->get (), 0); + } +} + + + + void +plex_keyb_c::kbd_ctrl_to_mouse(Bit8u value) +{ +bx_printf("MOUSE: kbd_ctrl_to_mouse(%02xh)\n", (unsigned) value); +bx_printf(" enable = %u\n", (unsigned) PLEX_KEY_THIS s.mouse.enable); +bx_printf(" allow_irq12 = %u\n", + (unsigned) PLEX_KEY_THIS s.kbd_controller.allow_irq12); +bx_printf(" aux_clock_enabled = %u\n", + (unsigned) PLEX_KEY_THIS s.kbd_controller.aux_clock_enabled); +//bx_printf("# MOUSE: kbd_ctrl_to_mouse(%02xh)\n", (unsigned) value); + + // an ACK (0xFA) is always the first response to any valid input + // received from the system other than Set-Wrap-Mode & Resend-Command + + + if (PLEX_KEY_THIS s.kbd_controller.expecting_mouse_parameter) { + PLEX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0; + switch (PLEX_KEY_THIS s.kbd_controller.last_mouse_command) { + case 0xf3: // Set Mouse Sample Rate + PLEX_KEY_THIS s.mouse.sample_rate = value; + if (bx_dbg.mouse) + bx_printf("[mouse] Sampling rate set: %d Hz\n", value); + controller_enQ(0xFA, 1); // ack + break; + + case 0xe8: // Set Mouse Resolution + switch (value) { + case 0: + PLEX_KEY_THIS s.mouse.resolution_cpmm = 1; + break; + case 1: + PLEX_KEY_THIS s.mouse.resolution_cpmm = 2; + break; + case 2: + PLEX_KEY_THIS s.mouse.resolution_cpmm = 4; + break; + case 3: + PLEX_KEY_THIS s.mouse.resolution_cpmm = 8; + break; + default: + bx_panic("[mouse] Unknown resolution %d\n", value); + break; + } + if (bx_dbg.mouse) + bx_printf("[mouse] Resolution set to %d counts per mm\n", + PLEX_KEY_THIS s.mouse.resolution_cpmm); + + controller_enQ(0xFA, 1); // ack + break; + + default: + bx_panic("MOUSE: unknown last command (%02xh)\n", (unsigned) PLEX_KEY_THIS s.kbd_controller.last_mouse_command); + } + } else { + PLEX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0; + PLEX_KEY_THIS s.kbd_controller.last_mouse_command = value; + switch ( value ) { + case 0xe6: // Set Mouse Scaling to 1:1 + controller_enQ(0xFA, 1); // ACK + PLEX_KEY_THIS s.mouse.scaling = 2; + if (bx_dbg.mouse) + bx_printf("[mouse] Scaling set to 1:1\n"); + break; + + case 0xe7: // Set Mouse Scaling to 2:1 + controller_enQ(0xFA, 1); // ACK + PLEX_KEY_THIS s.mouse.scaling = 2; + if (bx_dbg.mouse) + bx_printf("[mouse] Scaling set to 2:1\n"); + break; + + case 0xe8: // Set Mouse Resolution + controller_enQ(0xFA, 1); // ACK + PLEX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1; + break; + + case 0xf2: // Read Device Type + controller_enQ(0xFA, 1); // ACK + controller_enQ(0x00, 1); // Device ID + if (bx_dbg.mouse) + bx_printf("[mouse] Read mouse ID\n"); + break; + + case 0xf3: // Set Mouse Sample Rate (sample rate written to port 60h) + controller_enQ(0xFA, 1); // ACK + PLEX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1; + break; + + case 0xf4: // Enable (in stream mode) + PLEX_KEY_THIS s.mouse.enable = 1; + controller_enQ(0xFA, 1); // ACK + if (bx_dbg.mouse) + bx_printf("[mouse] Mouse enabled (stream mode)\n"); + break; + + case 0xf5: // Disable (in stream mode) + PLEX_KEY_THIS s.mouse.enable = 0; + controller_enQ(0xFA, 1); // ACK + if (bx_dbg.mouse) + bx_printf("[mouse] Mouse disabled (stream mode)\n"); + break; + + case 0xff: // Reset + PLEX_KEY_THIS s.mouse.sample_rate = 100; /* reports per second (default) */ + PLEX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */ + PLEX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */ + PLEX_KEY_THIS s.mouse.mode = MOUSE_MODE_RESET; + PLEX_KEY_THIS s.mouse.enable = 0; + /* (mch) NT expects an ack here */ + controller_enQ(0xFA, 1); // ACK + controller_enQ(0xAA, 1); // completion code + controller_enQ(0x00, 1); // ID code (normal mouse, wheelmouse has id 0x3) + if (bx_dbg.mouse) + bx_printf("[mouse] Mouse reset\n"); + break; + + case 0xe9: // Get mouse information + // should we ack here? (mch): Yes + controller_enQ(0xFA, 1); // ACK + controller_enQ(PLEX_KEY_THIS s.mouse.get_status_byte(), 1); // status + controller_enQ(PLEX_KEY_THIS s.mouse.get_resolution_byte(), 1); // resolution + controller_enQ(PLEX_KEY_THIS s.mouse.sample_rate, 1); // sample rate + if (bx_dbg.mouse) + bx_printf("[mouse] Get mouse information\n"); + break; + + default: + bx_panic("MOUSE: kbd_ctrl_to_mouse(%02xh)\n", (unsigned) value); + } + } +} + + void +plex_keyb_c::mouse_motion(int delta_x, int delta_y, unsigned button_state) +{ + Bit8u b1, b2, b3; + + // If mouse events are disabled on the GUI headerbar, don't + // generate any mouse data + if (bx_options.Omouse_enabled->get ()==0) + return; + + if ( PLEX_KEY_THIS s.mouse.enable==0 ) + return; + + // scale down the motion + if ( (delta_x < -1) || (delta_x > 1) ) + delta_x /= 2; + if ( (delta_y < -1) || (delta_y > 1) ) + delta_y /= 2; + + //bx_printf("# MOUSE: Dx=%d Dy=%d\n", + // delta_x, delta_y); + + b1 = (button_state & 0x0f) | 0x08; // bit3 always set + + PLEX_KEY_THIS s.mouse.button_status = button_state & 0x3; + + if ( (delta_x>=0) && (delta_x<=255) ) { + b2 = delta_x; + } + else if ( delta_x > 255 ) { + b2 = 0xff; + } + else if ( delta_x >= -256 ) { + b2 = delta_x; + b1 |= 0x10; + } + else { + b2 = 0x00; + b1 |= 0x10; + } + + if ( (delta_y>=0) && (delta_y<=255) ) { + b3 = delta_y; + } + else if ( delta_y > 255 ) { + b3 = 0xff; + } + else if ( delta_y >= -256 ) { + b3 = delta_y; + b1 |= 0x20; + } + else { + b3 = 0x00; + b1 |= 0x20; + } + mouse_enQ_packet(b1, b2, b3); +} + + + void +plex_keyb_c::put_scancode( unsigned char *code, int count ) +{ + for ( int i = 0 ; i < count ; i++ ) { + kbd_enQ( code[i] ); + } + + return; +} Index: iodev/plex-keyboard.h =================================================================== RCS file: plex-keyboard.h diff -N iodev/plex-keyboard.h --- /dev/null Thu May 24 22:33:05 2001 +++ iodev/plex-keyboard.h Wed Dec 12 19:03:51 2001 @@ -0,0 +1,183 @@ +// Copyright (C) 2000 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + +#ifndef _PLEX_PCKEY_H +#define _PLEX_PCKEY_H + + +#define BX_KBD_ELEMENTS 16 +#define BX_MOUSE_BUFF_SIZE 48 + + + +#if BX_USE_KEY_SMF +# define BX_KEY_SMF static +# define PLEX_KEY_THIS plex_keyboard. +#else +# define BX_KEY_SMF +# define PLEX_KEY_THIS this-> +#endif + + + +class plex_keyb_c { +public: + plex_keyb_c(void); + ~plex_keyb_c(void); + BX_KEY_SMF void init(void); + BX_KEY_SMF void gen_scancode(Bit32u scancode); + BX_KEY_SMF Bit8u get_kbd_enable(void); + BX_KEY_SMF void mouse_motion(int delta_x, int delta_y, unsigned button_state); + BX_KEY_SMF void mouse_button(unsigned mouse_state); + BX_KEY_SMF void periodic( Bit32u usec_delta ); + BX_KEY_SMF void put_scancode( unsigned char *code, int count ); + +private: + + static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len); + static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len); +#if !BX_USE_KEY_SMF + void write(Bit32u address, Bit32u value, unsigned io_len); + Bit32u read(Bit32u address, unsigned io_len); +#endif + + struct { + struct { + /* status bits */ + Boolean pare; + Boolean tim; + Boolean auxb; + Boolean keyl; + Boolean c_d; /* 1=command to port 64h, 0=data to port 60h */ + Boolean sysf; + Boolean inpb; + Boolean outb; + + Boolean scan_convert; + Boolean kbd_clock_enabled; + Boolean aux_clock_enabled; + Boolean allow_irq1; + Boolean allow_irq12; + Bit8u kbd_output_buffer; + Bit8u aux_output_buffer; + Bit8u last_comm; + Bit8u expecting_port60h; + Bit8u expecting_mouse_parameter; + Bit8u last_mouse_command; + } kbd_controller; + + struct mouseStruct { + Bit8u sample_rate; + Bit8u resolution_cpmm; // resolution in counts per mm + Bit8u scaling; + Bit8u mode; + Boolean enable; + + Bit8u get_status_byte () + { + Bit8u ret = 0; + // we're always in stream mode (right?) + ret |= (enable << 5); + ret |= (scaling == 1) ? 0 : (1 << 4); + ret |= ((button_status & 0x1) << 2); + ret |= ((button_status & 0x2) << 0); + return ret; + } + + Bit8u get_resolution_byte () + { + Bit8u ret = 0; + + switch (resolution_cpmm) { + case 1: + ret = 0; + break; + + case 2: + ret = 1; + break; + + case 4: + ret = 2; + break; + + case 8: + ret = 3; + break; + + default: + //FIXME + genlog->panic ("[mouse] invalid resolution_cpmm"); + }; + return ret; + } + + Bit8u button_status; + } mouse; + + struct { + int num_elements; + Bit8u buffer[BX_KBD_ELEMENTS]; + int head; + Boolean expecting_typematic; + Boolean expecting_led_write; + Bit8u delay; + Bit8u repeat_rate; + Bit8u led_status; + Boolean scanning_enabled; + } kbd_internal_buffer; + + struct { + int num_elements; + Bit8u buffer[BX_MOUSE_BUFF_SIZE]; + int head; + } mouse_internal_buffer; +#define BX_KBD_CONTROLLER_QSIZE 5 + Bit8u controller_Q[BX_KBD_CONTROLLER_QSIZE]; + unsigned controller_Qsize; + unsigned controller_Qsource; // 0=keyboard, 1=mouse + unsigned timer_pending; + } s; // State information for saving/loading + + BX_KEY_SMF void resetinternals(Boolean powerup); + BX_KEY_SMF void set_kbd_clock_enable(Bit8u value); + BX_KEY_SMF void set_aux_clock_enable(Bit8u value); + BX_KEY_SMF void kbd_ctrl_to_kbd(Bit8u value); + BX_KEY_SMF void kbd_ctrl_to_mouse(Bit8u value); + BX_KEY_SMF void kbd_enQ(Bit8u scancode); + BX_KEY_SMF void kbd_enQ_imm(Bit8u val); + BX_KEY_SMF void activate_timer(void); + BX_KEY_SMF void controller_enQ(Bit8u data, unsigned source); + BX_KEY_SMF Boolean mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3); + BX_KEY_SMF void mouse_enQ(Bit8u mouse_data); + static void timer_handler(void *); + void timer(void); + int timer_handle; + }; + +#if BX_USE_KEY_SMF +extern plex_keyb_c plex_keyboard; +#endif + +#endif // #ifndef _PLEX_PCKEY_H