another directory rename: failstar -> fail
"failstar" sounds like a name for a cruise liner from the 80s. As "*" isn't a desirable part of directory names, just name the whole thing "fail/", the core parts being stored in "fail/core/". Additionally fixing two build system dependency issues: - missing jobserver -> protomessages dependency - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain file dependencies ... cmake for the win) git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
899
bochs/iodev/Makefile.in
Normal file
899
bochs/iodev/Makefile.in
Normal file
@ -0,0 +1,899 @@
|
||||
# Copyright (C) 2001 The Bochs Project
|
||||
#
|
||||
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# Makefile for the iodev component of bochs
|
||||
|
||||
|
||||
@SUFFIX_LINE@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
datarootdir = @datarootdir@
|
||||
mandir = @mandir@
|
||||
man1dir = $(mandir)/man1
|
||||
man5dir = $(mandir)/man5
|
||||
docdir = $(datarootdir)/doc/bochs
|
||||
sharedir = $(datarootdir)/bochs
|
||||
top_builddir = ..
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
CXX = @CXX@
|
||||
CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@ @GUI_CXXFLAGS@
|
||||
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
RANLIB = @RANLIB@
|
||||
PLUGIN_PATH=@libdir@
|
||||
top_builddir = ..
|
||||
LIBTOOL=@LIBTOOL@
|
||||
WIN32_DLL_IMPORT_LIBRARY=../dllexports.a
|
||||
|
||||
CDROM_OBJS = @CDROM_OBJS@
|
||||
SOUNDLOW_OBJS = @SOUNDLOW_OBJS@
|
||||
NETLOW_OBJS = @NETLOW_OBJS@
|
||||
USBDEV_OBJS = @USBDEV_OBJS@
|
||||
SCSI_OBJS = @SCSI_OBJS@
|
||||
|
||||
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
|
||||
LOCAL_CXXFLAGS = $(MCH_CFLAGS)
|
||||
|
||||
PCIDEV_CXXFLAGS = -I$(srcdir)/../host/linux/pcidev
|
||||
|
||||
OBJS_THAT_CANNOT_BE_PLUGINS = \
|
||||
devices.o \
|
||||
virt_timer.o \
|
||||
slowdown_timer.o \
|
||||
$(MCH_OBJS)
|
||||
|
||||
OBJS_THAT_CAN_BE_PLUGINS = \
|
||||
pic.o \
|
||||
pit_wrap.o \
|
||||
serial.o \
|
||||
parallel.o \
|
||||
floppy.o \
|
||||
keyboard.o \
|
||||
vga.o \
|
||||
biosdev.o \
|
||||
cmos.o \
|
||||
harddrv.o \
|
||||
hdimage.o \
|
||||
dma.o \
|
||||
unmapped.o \
|
||||
extfpuirq.o \
|
||||
speaker.o \
|
||||
busmouse.o \
|
||||
ioapic.o \
|
||||
soundmod.o \
|
||||
@GAME_OBJS@ \
|
||||
@PCI_OBJ@ \
|
||||
@USBCORE_OBJ@ \
|
||||
@SB16_OBJS@ \
|
||||
@NE2K_OBJS@ \
|
||||
@IODEBUG_OBJS@
|
||||
|
||||
OBJS_THAT_SUPPORT_OTHER_PLUGINS = \
|
||||
pit82c54.o \
|
||||
scancodes.o \
|
||||
serial_raw.o \
|
||||
svga_cirrus.o \
|
||||
vmware3.o \
|
||||
vmware4.o \
|
||||
vvfat.o \
|
||||
$(CDROM_OBJS) \
|
||||
$(SOUNDLOW_OBJS) \
|
||||
$(NETLOW_OBJS) \
|
||||
$(USBDEV_OBJS) \
|
||||
$(SCSI_OBJS)
|
||||
|
||||
NONPLUGIN_OBJS = @IODEV_NON_PLUGIN_OBJS@
|
||||
PLUGIN_OBJS = @IODEV_PLUGIN_OBJS@
|
||||
SOUND_LINK_OPTS = @SOUND_LINK_OPTS@
|
||||
|
||||
all: libiodev.a
|
||||
|
||||
plugins: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@)
|
||||
|
||||
libiodev.a: $(NONPLUGIN_OBJS)
|
||||
@RMCOMMAND@ libiodev.a
|
||||
@MAKELIB@ $(NONPLUGIN_OBJS)
|
||||
@RANLIB@ libiodev.a
|
||||
|
||||
# standard compile rule for C++ files
|
||||
.@CPP_SUFFIX@.o:
|
||||
$(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
|
||||
|
||||
pcidev.o : pcidev.@CPP_SUFFIX@
|
||||
$(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(PCIDEV_CXXFLAGS) @CXXFP@$< @OFP@$@
|
||||
|
||||
##### building plugins with libtool
|
||||
%.lo: %.@CPP_SUFFIX@
|
||||
$(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
|
||||
|
||||
pcidev.lo : pcidev.@CPP_SUFFIX@
|
||||
$(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(PCIDEV_CXXFLAGS) $< -o $@
|
||||
|
||||
libbx_%.la: %.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH)
|
||||
|
||||
# special link rules for plugins that require more than one object file
|
||||
libbx_harddrv.la: harddrv.lo $(CDROM_OBJS:.o=.lo)
|
||||
$(LIBTOOL) --mode=link $(CXX) -module harddrv.lo $(CDROM_OBJS:.o=.lo) -o libbx_harddrv.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_hdimage.la: hdimage.lo vmware3.lo vmware4.lo vvfat.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module hdimage.lo vmware3.lo vmware4.lo vvfat.lo -o libbx_hdimage.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_keyboard.la: keyboard.lo scancodes.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module keyboard.lo scancodes.lo -o libbx_keyboard.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_pit_wrap.la: pit82c54.lo pit_wrap.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module pit82c54.lo pit_wrap.lo -o libbx_pit.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_soundmod.la: soundmod.lo $(SOUNDLOW_OBJS:.o=.lo)
|
||||
$(LIBTOOL) --mode=link $(CXX) -module soundmod.lo $(SOUNDLOW_OBJS:.o=.lo) -o libbx_soundmod.la -rpath $(PLUGIN_PATH) $(SOUND_LINK_OPTS)
|
||||
|
||||
libbx_ne2k.la: ne2k.lo $(NETLOW_OBJS:.o=.lo)
|
||||
$(LIBTOOL) --mode=link $(CXX) -module ne2k.lo $(NETLOW_OBJS:.o=.lo) -o libbx_ne2k.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_pcipnic.la: pcipnic.lo $(NETLOW_OBJS:.o=.lo)
|
||||
$(LIBTOOL) --mode=link $(CXX) -module pcipnic.lo $(NETLOW_OBJS:.o=.lo) -o libbx_pcipnic.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_serial.la: serial.lo serial_raw.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module serial.lo serial_raw.lo -o libbx_serial.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_vga.la: vga.lo svga_cirrus.lo
|
||||
$(LIBTOOL) --mode=link $(CXX) -module vga.lo svga_cirrus.lo -o libbx_vga.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
libbx_usb_common.la: usb_common.lo $(USBDEV_OBJS:.o=.lo) scsi_device.lo $(CDROM_OBJS:.o=.lo)
|
||||
$(LIBTOOL) --mode=link $(CXX) -module usb_common.lo $(USBDEV_OBJS:.o=.lo) scsi_device.lo $(CDROM_OBJS:.o=.lo) -o libbx_usb_common.la -rpath $(PLUGIN_PATH)
|
||||
|
||||
#### building DLLs for win32 (tested on cygwin only)
|
||||
bx_%.dll: %.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o $@ $< $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
# special link rules for plugins that require more than one object file
|
||||
bx_harddrv.dll: harddrv.o $(CDROM_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_harddrv.dll harddrv.o $(CDROM_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_hdimage.dll: hdimage.o vmware3.o vmware4.o vvfat.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_hdimage.dll hdimage.o vmware3.o vmware4.o vvfat.o $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_keyboard.dll: keyboard.o scancodes.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_keyboard.dll keyboard.o scancodes.o $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_pit_wrap.dll: pit82c54.o pit_wrap.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_pit.dll pit82c54.o pit_wrap.o $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_soundmod.dll: soundmod.o $(SOUNDLOW_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_soundmod.dll soundmod.o $(SOUNDLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY) -lwinmm
|
||||
|
||||
bx_ne2k.dll: ne2k.o $(NETLOW_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_ne2k.dll ne2k.o $(NETLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_pcipnic.dll: pcipnic.o $(NETLOW_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_pcipnic.dll pcipnic.o $(NETLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_gameport.dll: gameport.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_gameport.dll gameport.o $(WIN32_DLL_IMPORT_LIBRARY) -lwinmm
|
||||
|
||||
bx_serial.dll: serial.o serial_raw.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_serial.dll serial.o serial_raw.o $(WIN32_DLL_IMPORT_LIBRARY) -lwsock32
|
||||
|
||||
bx_vga.dll: vga.o svga_cirrus.o
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_vga.dll vga.o svga_cirrus.o $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
bx_usb_common.dll: usb_common.o $(USBDEV_OBJS) scsi_device.o $(CDROM_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -shared -o bx_usb_common.dll usb_common.o $(USBDEV_OBJS) scsi_device.o $(CDROM_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
|
||||
|
||||
##### end DLL section
|
||||
|
||||
clean:
|
||||
@RMCOMMAND@ -rf .libs *.lo *.o *.la *.a *.dll
|
||||
|
||||
dist-clean: clean
|
||||
@RMCOMMAND@ Makefile
|
||||
|
||||
###########################################
|
||||
# dependencies generated by
|
||||
# gcc -MM -I.. -I../instrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g'
|
||||
# gcc -MM -I.. -I../instrument/stubs *.cc | \
|
||||
# sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's/\.o:/.lo:/g'
|
||||
#
|
||||
# This means that every source file is listed twice, once with a .o rule
|
||||
# and then again with an identical .lo rule. The .lo rules are used when
|
||||
# building plugins.
|
||||
###########################################
|
||||
acpi.o: acpi.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h acpi.h
|
||||
biosdev.o: biosdev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h biosdev.h
|
||||
busmouse.o: busmouse.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h busmouse.h
|
||||
cdrom_amigaos.o: cdrom_amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h scsi_commands.h cdrom.h
|
||||
cdrom_beos.o: cdrom_beos.@CPP_SUFFIX@ cdrom_beos.h
|
||||
cdrom.o: cdrom.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
|
||||
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
|
||||
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
|
||||
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
|
||||
cdrom.h
|
||||
cmos.o: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h cmos.h
|
||||
crc32.o: crc32.@CPP_SUFFIX@ crc32.h ../config.h
|
||||
devices.o: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ../iodev/virt_timer.h \
|
||||
../iodev/slowdown_timer.h
|
||||
dma.o: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h dma.h
|
||||
eth_arpback.o: eth_arpback.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth.o: eth.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_fbsd.o: eth_fbsd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth_linux.o: eth_linux.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_null.o: eth_null.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_packetmaker.o: eth_packetmaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h \
|
||||
../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth_tap.o: eth_tap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_tuntap.o: eth_tuntap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_vde.o: eth_vde.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_vnet.o: eth_vnet.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_win32.o: eth_win32.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
extfpuirq.o: extfpuirq.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h extfpuirq.h
|
||||
floppy.o: floppy.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h floppy.h
|
||||
gameport.o: gameport.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h gameport.h
|
||||
guest2host.o: guest2host.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h guest2host.h
|
||||
harddrv.o: harddrv.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h harddrv.h hdimage.h \
|
||||
cdrom.h
|
||||
hdimage.o: hdimage.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h \
|
||||
vmware4.h vvfat.h
|
||||
ioapic.o: ioapic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ioapic.h
|
||||
iodebug.o: iodebug.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
keyboard.o: keyboard.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ../gui/keymap.h \
|
||||
keyboard.h scancodes.h
|
||||
ne2k.o: ne2k.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h ne2k.h eth.h
|
||||
parallel.o: parallel.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h parallel.h
|
||||
pci2isa.o: pci2isa.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pci2isa.h
|
||||
pci.o: pci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h
|
||||
pcidev.o: pcidev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
pci_ide.o: pci_ide.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pci_ide.h
|
||||
pcipnic.o: pcipnic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
pcivga.o: pcivga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pcivga.h
|
||||
pic.o: pic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pic.h
|
||||
pit82c54.o: pit82c54.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pit82c54.h
|
||||
pit_wrap.o: pit_wrap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pit_wrap.h pit82c54.h \
|
||||
virt_timer.h speaker.h
|
||||
sb16.o: sb16.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h sb16.h soundmod.h \
|
||||
soundlnx.h soundwin.h soundosx.h
|
||||
scancodes.o: scancodes.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h scancodes.h
|
||||
scsi_device.o: scsi_device.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h cdrom.h \
|
||||
scsi_device.h
|
||||
serial.o: serial.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h serial.h
|
||||
serial_raw.o: serial_raw.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
slowdown_timer.o: slowdown_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h slowdown_timer.h
|
||||
soundlnx.o: soundlnx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h
|
||||
soundmod.o: soundmod.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h \
|
||||
soundosx.h soundwin.h
|
||||
soundosx.o: soundosx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundosx.h
|
||||
soundwin.o: soundwin.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundwin.h
|
||||
speaker.o: speaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h speaker.h
|
||||
svga_cirrus.o: svga_cirrus.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h vga.h svga_cirrus.h
|
||||
unmapped.o: unmapped.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h unmapped.h
|
||||
usb_common.o: usb_common.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hid.h usb_hub.h usb_msd.h usb_printer.h
|
||||
usb_hid.o: usb_hid.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hid.h
|
||||
usb_hub.o: usb_hub.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hub.h
|
||||
usb_msd.o: usb_msd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h cdrom.h \
|
||||
hdimage.h scsi_device.h usb_msd.h
|
||||
usb_ohci.o: usb_ohci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
|
||||
usb_ohci.h
|
||||
usb_printer.o: usb_printer.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_printer.h
|
||||
usb_uhci.o: usb_uhci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
|
||||
usb_uhci.h
|
||||
vga.o: vga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h vga.h
|
||||
virt_timer.o: virt_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h virt_timer.h
|
||||
vmware3.o: vmware3.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h
|
||||
vmware4.o: vmware4.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware4.h
|
||||
vvfat.o: vvfat.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vvfat.h
|
||||
acpi.lo: acpi.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h acpi.h
|
||||
biosdev.lo: biosdev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h biosdev.h
|
||||
busmouse.lo: busmouse.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h busmouse.h
|
||||
cdrom_amigaos.lo: cdrom_amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h scsi_commands.h cdrom.h
|
||||
cdrom_beos.lo: cdrom_beos.@CPP_SUFFIX@ cdrom_beos.h
|
||||
cdrom.lo: cdrom.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
|
||||
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
|
||||
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
|
||||
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
|
||||
cdrom.h
|
||||
cmos.lo: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h cmos.h
|
||||
crc32.lo: crc32.@CPP_SUFFIX@ crc32.h ../config.h
|
||||
devices.lo: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ../iodev/virt_timer.h \
|
||||
../iodev/slowdown_timer.h
|
||||
dma.lo: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h dma.h
|
||||
eth_arpback.lo: eth_arpback.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth.lo: eth.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_fbsd.lo: eth_fbsd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth_linux.lo: eth_linux.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_null.lo: eth_null.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_packetmaker.lo: eth_packetmaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h \
|
||||
../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
eth_tap.lo: eth_tap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_tuntap.lo: eth_tuntap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_vde.lo: eth_vde.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_vnet.lo: eth_vnet.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h eth.h
|
||||
eth_win32.lo: eth_win32.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
extfpuirq.lo: extfpuirq.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h extfpuirq.h
|
||||
floppy.lo: floppy.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h floppy.h
|
||||
gameport.lo: gameport.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h gameport.h
|
||||
guest2host.lo: guest2host.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h guest2host.h
|
||||
harddrv.lo: harddrv.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h harddrv.h hdimage.h \
|
||||
cdrom.h
|
||||
hdimage.lo: hdimage.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h \
|
||||
vmware4.h vvfat.h
|
||||
ioapic.lo: ioapic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ioapic.h
|
||||
iodebug.lo: iodebug.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
keyboard.lo: keyboard.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h ../gui/keymap.h \
|
||||
keyboard.h scancodes.h
|
||||
ne2k.lo: ne2k.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h ne2k.h eth.h
|
||||
parallel.lo: parallel.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h parallel.h
|
||||
pci2isa.lo: pci2isa.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pci2isa.h
|
||||
pci.lo: pci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h
|
||||
pcidev.lo: pcidev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
pci_ide.lo: pci_ide.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pci_ide.h
|
||||
pcipnic.lo: pcipnic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
pcivga.lo: pcivga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h pcivga.h
|
||||
pic.lo: pic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pic.h
|
||||
pit82c54.lo: pit82c54.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pit82c54.h
|
||||
pit_wrap.lo: pit_wrap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pit_wrap.h pit82c54.h \
|
||||
virt_timer.h speaker.h
|
||||
sb16.lo: sb16.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h sb16.h soundmod.h \
|
||||
soundlnx.h soundwin.h soundosx.h
|
||||
scancodes.lo: scancodes.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h scancodes.h
|
||||
scsi_device.lo: scsi_device.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h cdrom.h \
|
||||
scsi_device.h
|
||||
serial.lo: serial.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h serial.h
|
||||
serial_raw.lo: serial_raw.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h
|
||||
slowdown_timer.lo: slowdown_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h slowdown_timer.h
|
||||
soundlnx.lo: soundlnx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h
|
||||
soundmod.lo: soundmod.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h \
|
||||
soundosx.h soundwin.h
|
||||
soundosx.lo: soundosx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundosx.h
|
||||
soundwin.lo: soundwin.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundwin.h
|
||||
speaker.lo: speaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h speaker.h
|
||||
svga_cirrus.lo: svga_cirrus.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h vga.h svga_cirrus.h
|
||||
unmapped.lo: unmapped.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h unmapped.h
|
||||
usb_common.lo: usb_common.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hid.h usb_hub.h usb_msd.h usb_printer.h
|
||||
usb_hid.lo: usb_hid.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hid.h
|
||||
usb_hub.lo: usb_hub.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_hub.h
|
||||
usb_msd.lo: usb_msd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h cdrom.h \
|
||||
hdimage.h scsi_device.h usb_msd.h
|
||||
usb_ohci.lo: usb_ohci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
|
||||
usb_ohci.h
|
||||
usb_printer.lo: usb_printer.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
|
||||
usb_printer.h
|
||||
usb_uhci.lo: usb_uhci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
|
||||
usb_uhci.h
|
||||
vga.lo: vga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h vga.h
|
||||
virt_timer.lo: virt_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h virt_timer.h
|
||||
vmware3.lo: vmware3.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h
|
||||
vmware4.lo: vmware4.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware4.h
|
||||
vvfat.lo: vvfat.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
|
||||
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
|
||||
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
|
||||
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h hdimage.h vvfat.h
|
||||
586
bochs/iodev/acpi.cc
Normal file
586
bochs/iodev/acpi.cc
Normal file
@ -0,0 +1,586 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2006 Volker Ruppert
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// PIIX4 ACPI support
|
||||
//
|
||||
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI && BX_SUPPORT_ACPI
|
||||
|
||||
#include "pci.h"
|
||||
#include "acpi.h"
|
||||
|
||||
#define LOG_THIS theACPIController->
|
||||
|
||||
bx_acpi_ctrl_c* theACPIController = NULL;
|
||||
|
||||
// FIXME
|
||||
const Bit8u acpi_pm_iomask[64] = {2, 0, 2, 0, 2, 0, 0, 0, 4, 0, 0, 0, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 1, 1, 0, 0, 7, 7, 0, 0, 7, 7, 7, 7,
|
||||
7, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
const Bit8u acpi_sm_iomask[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 2, 0, 0, 0};
|
||||
|
||||
#define PM_FREQ 3579545
|
||||
|
||||
#define ACPI_DBG_IO_ADDR 0xb044
|
||||
|
||||
#define RSM_STS (1 << 15)
|
||||
#define PWRBTN_STS (1 << 8)
|
||||
|
||||
#define RTC_EN (1 << 10)
|
||||
#define PWRBTN_EN (1 << 8)
|
||||
#define GBL_EN (1 << 5)
|
||||
#define TMROF_EN (1 << 0)
|
||||
|
||||
#define SCI_EN (1 << 0)
|
||||
|
||||
#define SUS_EN (1 << 13)
|
||||
|
||||
#define ACPI_ENABLE 0xf1
|
||||
#define ACPI_DISABLE 0xf0
|
||||
|
||||
extern void apic_bus_deliver_smi(void);
|
||||
|
||||
int libacpi_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theACPIController = new bx_acpi_ctrl_c();
|
||||
bx_devices.pluginACPIController = theACPIController;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theACPIController, BX_PLUGIN_ACPI);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void libacpi_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theACPIController;
|
||||
}
|
||||
|
||||
/* ported from QEMU: compute with 96 bit intermediate result: (a*b)/c */
|
||||
Bit64u muldiv64(Bit64u a, Bit32u b, Bit32u c)
|
||||
{
|
||||
union {
|
||||
Bit64u ll;
|
||||
struct {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
Bit32u high, low;
|
||||
#else
|
||||
Bit32u low, high;
|
||||
#endif
|
||||
} l;
|
||||
} u, res;
|
||||
Bit64u rl, rh;
|
||||
|
||||
u.ll = a;
|
||||
rl = (Bit64u)u.l.low * (Bit64u)b;
|
||||
rh = (Bit64u)u.l.high * (Bit64u)b;
|
||||
rh += (rl >> 32);
|
||||
res.l.high = (Bit32u)(rh / c);
|
||||
res.l.low = (Bit32u)(((rh % c) << 32) + (rl & 0xffffffff)) / c;
|
||||
return res.ll;
|
||||
}
|
||||
|
||||
bx_acpi_ctrl_c::bx_acpi_ctrl_c()
|
||||
{
|
||||
put("ACPI");
|
||||
s.timer_index = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
bx_acpi_ctrl_c::~bx_acpi_ctrl_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::init(void)
|
||||
{
|
||||
// called once when bochs initializes
|
||||
|
||||
unsigned i;
|
||||
|
||||
BX_ACPI_THIS s.devfunc = BX_PCI_DEVICE(1, 3);
|
||||
DEV_register_pci_handlers(this, &BX_ACPI_THIS s.devfunc, BX_PLUGIN_ACPI,
|
||||
"ACPI Controller");
|
||||
|
||||
if (BX_ACPI_THIS s.timer_index == BX_NULL_TIMER_HANDLE) {
|
||||
BX_ACPI_THIS s.timer_index =
|
||||
bx_pc_system.register_timer(this, timer_handler, 1000, 0, 0, "ACPI");
|
||||
}
|
||||
DEV_register_iowrite_handler(this, write_handler, ACPI_DBG_IO_ADDR, "ACPI", 4);
|
||||
|
||||
for (i=0; i<256; i++) {
|
||||
BX_ACPI_THIS s.pci_conf[i] = 0x0;
|
||||
}
|
||||
BX_ACPI_THIS s.pm_base = 0x0;
|
||||
BX_ACPI_THIS s.sm_base = 0x0;
|
||||
|
||||
// readonly registers
|
||||
static const struct init_vals_t {
|
||||
unsigned addr;
|
||||
unsigned char val;
|
||||
} init_vals[] = {
|
||||
{ 0x00, 0x86 }, { 0x01, 0x80 },
|
||||
{ 0x02, 0x13 }, { 0x03, 0x71 },
|
||||
{ 0x08, 0x03 }, // revision number
|
||||
{ 0x0a, 0x80 }, // other bridge device
|
||||
{ 0x0b, 0x06 }, // bridge device
|
||||
{ 0x0e, 0x00 }, // header type
|
||||
{ 0x3d, BX_PCI_INTA } // interrupt pin #1
|
||||
};
|
||||
for (i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
|
||||
BX_ACPI_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::reset(unsigned type)
|
||||
{
|
||||
BX_ACPI_THIS s.pci_conf[0x04] = 0x00; // command_io + command_mem
|
||||
BX_ACPI_THIS s.pci_conf[0x05] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x06] = 0x80; // status_devsel_medium
|
||||
BX_ACPI_THIS s.pci_conf[0x07] = 0x02;
|
||||
BX_ACPI_THIS s.pci_conf[0x3c] = 0x00; // IRQ
|
||||
|
||||
// PM base 0x40 - 0x43
|
||||
BX_ACPI_THIS s.pci_conf[0x40] = 0x01;
|
||||
BX_ACPI_THIS s.pci_conf[0x41] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x42] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x43] = 0x00;
|
||||
|
||||
// clear DEVACTB register on PIIX4 ACPI reset
|
||||
BX_ACPI_THIS s.pci_conf[0x58] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x59] = 0x00;
|
||||
|
||||
// device resources
|
||||
BX_ACPI_THIS s.pci_conf[0x5a] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x5b] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x5f] = 0x90;
|
||||
BX_ACPI_THIS s.pci_conf[0x63] = 0x60;
|
||||
BX_ACPI_THIS s.pci_conf[0x67] = 0x98;
|
||||
|
||||
// SM base 0x90 - 0x93
|
||||
BX_ACPI_THIS s.pci_conf[0x90] = 0x01;
|
||||
BX_ACPI_THIS s.pci_conf[0x91] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x92] = 0x00;
|
||||
BX_ACPI_THIS s.pci_conf[0x93] = 0x00;
|
||||
|
||||
BX_ACPI_THIS s.pmsts = 0;
|
||||
BX_ACPI_THIS s.pmen = 0;
|
||||
BX_ACPI_THIS s.pmcntrl = 0;
|
||||
BX_ACPI_THIS s.tmr_overflow_time = 0xffffff;
|
||||
|
||||
BX_ACPI_THIS s.smbus.stat = 0;
|
||||
BX_ACPI_THIS s.smbus.ctl = 0;
|
||||
BX_ACPI_THIS s.smbus.cmd = 0;
|
||||
BX_ACPI_THIS s.smbus.addr = 0;
|
||||
BX_ACPI_THIS s.smbus.data0 = 0;
|
||||
BX_ACPI_THIS s.smbus.data1 = 0;
|
||||
BX_ACPI_THIS s.smbus.index = 0;
|
||||
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
BX_ACPI_THIS s.smbus.data[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "acpi", "ACPI Controller State", 6);
|
||||
BXRS_HEX_PARAM_FIELD(list, pmsts, BX_ACPI_THIS s.pmsts);
|
||||
BXRS_HEX_PARAM_FIELD(list, pmen, BX_ACPI_THIS s.pmen);
|
||||
BXRS_HEX_PARAM_FIELD(list, pmcntrl, BX_ACPI_THIS s.pmcntrl);
|
||||
BXRS_HEX_PARAM_FIELD(list, tmr_overflow_time, BX_ACPI_THIS s.tmr_overflow_time);
|
||||
bx_list_c *smbus = new bx_list_c(list, "smbus", "ACPI SMBus", 8);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, stat, BX_ACPI_THIS s.smbus.stat);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, ctl, BX_ACPI_THIS s.smbus.ctl);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, cmd, BX_ACPI_THIS s.smbus.cmd);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, addr, BX_ACPI_THIS s.smbus.addr);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, data0, BX_ACPI_THIS s.smbus.data0);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, data1, BX_ACPI_THIS s.smbus.data1);
|
||||
BXRS_HEX_PARAM_FIELD(smbus, index, BX_ACPI_THIS s.smbus.index);
|
||||
bx_list_c *data = new bx_list_c(smbus, "data", "ACPI SMBus data", 32);
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
char name[6];
|
||||
sprintf(name, "0x%02x", i);
|
||||
new bx_shadow_num_c(data, name, &BX_ACPI_THIS s.smbus.data[i], BASE_HEX);
|
||||
}
|
||||
register_pci_state(list, BX_ACPI_THIS s.pci_conf);
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::after_restore_state(void)
|
||||
{
|
||||
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
|
||||
&BX_ACPI_THIS s.pm_base,
|
||||
&BX_ACPI_THIS s.pci_conf[0x40],
|
||||
64, &acpi_pm_iomask[0], "ACPI PM base"))
|
||||
{
|
||||
BX_INFO(("new PM base address: 0x%04x", BX_ACPI_THIS s.pm_base));
|
||||
}
|
||||
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
|
||||
&BX_ACPI_THIS s.sm_base,
|
||||
&BX_ACPI_THIS s.pci_conf[0x90],
|
||||
16, &acpi_sm_iomask[0], "ACPI SM base"))
|
||||
{
|
||||
BX_INFO(("new SM base address: 0x%04x", BX_ACPI_THIS s.sm_base));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::set_irq_level(bx_bool level)
|
||||
{
|
||||
DEV_pci_set_irq(BX_ACPI_THIS s.devfunc, BX_ACPI_THIS s.pci_conf[0x3d], level);
|
||||
}
|
||||
|
||||
Bit32u bx_acpi_ctrl_c::get_pmtmr(void)
|
||||
{
|
||||
Bit64u value = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
|
||||
return (Bit32u)(value & 0xffffff);
|
||||
}
|
||||
|
||||
Bit16u bx_acpi_ctrl_c::get_pmsts(void)
|
||||
{
|
||||
Bit16u pmsts = BX_ACPI_THIS s.pmsts;
|
||||
Bit64u value = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
|
||||
if (value >= BX_ACPI_THIS s.tmr_overflow_time)
|
||||
BX_ACPI_THIS s.pmsts |= TMROF_EN;
|
||||
return pmsts;
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::pm_update_sci(void)
|
||||
{
|
||||
Bit16u pmsts = get_pmsts();
|
||||
bx_bool sci_level = (((pmsts & BX_ACPI_THIS s.pmen) &
|
||||
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
|
||||
BX_ACPI_THIS set_irq_level(sci_level);
|
||||
// schedule a timer interruption if needed
|
||||
if ((BX_ACPI_THIS s.pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
|
||||
Bit64u expire_time = muldiv64(BX_ACPI_THIS s.tmr_overflow_time, 1000000, PM_FREQ);
|
||||
bx_pc_system.activate_timer(BX_ACPI_THIS s.timer_index, (Bit32u)expire_time, 0);
|
||||
} else {
|
||||
bx_pc_system.deactivate_timer(BX_ACPI_THIS s.timer_index);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::generate_smi(Bit8u value)
|
||||
{
|
||||
/* ACPI specs 3.0, 4.7.2.5 */
|
||||
if (value == ACPI_ENABLE) {
|
||||
BX_ACPI_THIS s.pmcntrl |= SCI_EN;
|
||||
} else if (value == ACPI_DISABLE) {
|
||||
BX_ACPI_THIS s.pmcntrl &= ~SCI_EN;
|
||||
}
|
||||
|
||||
if (BX_ACPI_THIS s.pci_conf[0x5b] & 0x02) {
|
||||
apic_bus_deliver_smi();
|
||||
}
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_acpi_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_ACPI_SMF
|
||||
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_acpi_ctrl_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_ACPI_SMF
|
||||
Bit8u reg = address & 0x3f;
|
||||
Bit32u value = 0xffffffff;
|
||||
|
||||
if ((address & 0xffc0) == BX_ACPI_THIS s.pm_base) {
|
||||
if ((BX_ACPI_THIS s.pci_conf[0x80] & 0x01) == 0) {
|
||||
return value;
|
||||
}
|
||||
switch (reg) {
|
||||
case 0x00:
|
||||
value = BX_ACPI_THIS get_pmsts();
|
||||
break;
|
||||
case 0x02:
|
||||
value = BX_ACPI_THIS s.pmen;
|
||||
break;
|
||||
case 0x04:
|
||||
value = BX_ACPI_THIS s.pmcntrl;
|
||||
break;
|
||||
case 0x08:
|
||||
value = BX_ACPI_THIS get_pmtmr();
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("ACPI read from PM register 0x%02x not implemented yet", reg));
|
||||
}
|
||||
BX_DEBUG(("ACPI read from PM register 0x%02x returns 0x%08x", reg, value));
|
||||
} else {
|
||||
if (((BX_ACPI_THIS s.pci_conf[0x04] & 0x01) == 0) &&
|
||||
((BX_ACPI_THIS s.pci_conf[0xd2] & 0x01) == 0)) {
|
||||
return value;
|
||||
}
|
||||
switch (reg) {
|
||||
case 0x00:
|
||||
value = BX_ACPI_THIS s.smbus.stat;
|
||||
break;
|
||||
case 0x02:
|
||||
BX_ACPI_THIS s.smbus.index = 0;
|
||||
value = BX_ACPI_THIS s.smbus.ctl & 0x1f;
|
||||
break;
|
||||
case 0x03:
|
||||
value = BX_ACPI_THIS s.smbus.cmd;
|
||||
break;
|
||||
case 0x04:
|
||||
value = BX_ACPI_THIS s.smbus.addr;
|
||||
break;
|
||||
case 0x05:
|
||||
value = BX_ACPI_THIS s.smbus.data0;
|
||||
break;
|
||||
case 0x06:
|
||||
value = BX_ACPI_THIS s.smbus.data1;
|
||||
break;
|
||||
case 0x07:
|
||||
value = BX_ACPI_THIS s.smbus.data[BX_ACPI_THIS s.smbus.index++];
|
||||
if (BX_ACPI_THIS s.smbus.index > 31) {
|
||||
BX_ACPI_THIS s.smbus.index = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
BX_INFO(("ACPI read from SMBus register 0x%02x not implemented yet", reg));
|
||||
}
|
||||
BX_DEBUG(("ACPI read from SMBus register 0x%02x returns 0x%08x", reg, value));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_acpi_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_ACPI_SMF
|
||||
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_ACPI_SMF
|
||||
Bit8u reg = address & 0x3f;
|
||||
|
||||
if ((address & 0xffc0) == BX_ACPI_THIS s.pm_base) {
|
||||
if ((BX_ACPI_THIS s.pci_conf[0x80] & 0x01) == 0) {
|
||||
return;
|
||||
}
|
||||
BX_DEBUG(("ACPI write to PM register 0x%02x, value = 0x%04x", reg, value));
|
||||
switch (reg) {
|
||||
case 0x00:
|
||||
{
|
||||
Bit16u pmsts = BX_ACPI_THIS get_pmsts();
|
||||
if (pmsts & value & TMROF_EN) {
|
||||
// if TMRSTS is reset, then compute the new overflow time
|
||||
Bit64u d = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
|
||||
BX_ACPI_THIS s.tmr_overflow_time = (d + BX_CONST64(0x800000)) & ~BX_CONST64(0x7fffff);
|
||||
}
|
||||
BX_ACPI_THIS s.pmsts &= ~value;
|
||||
BX_ACPI_THIS pm_update_sci();
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
BX_ACPI_THIS s.pmen = value;
|
||||
BX_ACPI_THIS pm_update_sci();
|
||||
break;
|
||||
case 0x04:
|
||||
{
|
||||
BX_ACPI_THIS s.pmcntrl = value & ~(SUS_EN);
|
||||
if (value & SUS_EN) {
|
||||
// change suspend type
|
||||
Bit16u sus_typ = (value >> 10) & 7;
|
||||
switch (sus_typ) {
|
||||
case 0: // soft power off
|
||||
bx_user_quit = 1;
|
||||
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
|
||||
BX_PANIC(("ACPI control: soft power off"));
|
||||
break;
|
||||
case 1:
|
||||
BX_INFO(("ACPI control: suspend to ram"));
|
||||
BX_ACPI_THIS s.pmsts |= (RSM_STS | PWRBTN_STS);
|
||||
DEV_cmos_set_reg(0xF, 0xFE);
|
||||
bx_pc_system.Reset(BX_RESET_HARDWARE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("ACPI write to PM register 0x%02x not implemented yet", reg));
|
||||
}
|
||||
} else if ((address & 0xfff0) == BX_ACPI_THIS s.sm_base) {
|
||||
if (((BX_ACPI_THIS s.pci_conf[0x04] & 0x01) == 0) &&
|
||||
((BX_ACPI_THIS s.pci_conf[0xd2] & 0x01) == 0)) {
|
||||
return;
|
||||
}
|
||||
BX_DEBUG(("ACPI write to SMBus register 0x%02x, value = 0x%04x", reg, value));
|
||||
switch (reg) {
|
||||
case 0x00:
|
||||
BX_ACPI_THIS s.smbus.stat = 0;
|
||||
BX_ACPI_THIS s.smbus.index = 0;
|
||||
break;
|
||||
case 0x02:
|
||||
BX_ACPI_THIS s.smbus.ctl = 0;
|
||||
// TODO: execute SMBus command
|
||||
break;
|
||||
case 0x03:
|
||||
BX_ACPI_THIS s.smbus.cmd = 0;
|
||||
break;
|
||||
case 0x04:
|
||||
BX_ACPI_THIS s.smbus.addr = 0;
|
||||
break;
|
||||
case 0x05:
|
||||
BX_ACPI_THIS s.smbus.data0 = 0;
|
||||
break;
|
||||
case 0x06:
|
||||
BX_ACPI_THIS s.smbus.data1 = 0;
|
||||
break;
|
||||
case 0x07:
|
||||
BX_ACPI_THIS s.smbus.data[BX_ACPI_THIS s.smbus.index++] = value;
|
||||
if (BX_ACPI_THIS s.smbus.index > 31) {
|
||||
BX_ACPI_THIS s.smbus.index = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("ACPI write to SMBus register 0x%02x not implemented yet", reg));
|
||||
}
|
||||
} else {
|
||||
BX_DEBUG(("DBG: 0x%08x", value));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
|
||||
class_ptr->timer();
|
||||
}
|
||||
|
||||
void bx_acpi_ctrl_c::timer()
|
||||
{
|
||||
BX_ACPI_THIS pm_update_sci();
|
||||
}
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_acpi_ctrl_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_ACPI_THIS s.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// static pci configuration space write callback handler
|
||||
void bx_acpi_ctrl_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
Bit8u value8, oldval;
|
||||
bx_bool pm_base_change = 0, sm_base_change = 0;
|
||||
|
||||
if ((address >= 0x10) && (address < 0x34))
|
||||
return;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value8 = (value >> (i*8)) & 0xFF;
|
||||
oldval = BX_ACPI_THIS s.pci_conf[address+i];
|
||||
switch (address+i) {
|
||||
case 0x04:
|
||||
value8 = (value8 & 0xfe) | (value & 0x01);
|
||||
goto set_value;
|
||||
break;
|
||||
case 0x06: // disallowing write to status lo-byte (is that expected?)
|
||||
break;
|
||||
case 0x3c:
|
||||
if (value8 != oldval) {
|
||||
BX_INFO(("new irq line = %d", value8));
|
||||
}
|
||||
goto set_value;
|
||||
break;
|
||||
case 0x40:
|
||||
value8 = (value8 & 0xc0) | 0x01;
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
pm_base_change |= (value8 != oldval);
|
||||
goto set_value;
|
||||
break;
|
||||
case 0x90:
|
||||
value8 = (value8 & 0xf0) | 0x01;
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
sm_base_change |= (value8 != oldval);
|
||||
default:
|
||||
set_value:
|
||||
BX_ACPI_THIS s.pci_conf[address+i] = value8;
|
||||
}
|
||||
}
|
||||
if (pm_base_change) {
|
||||
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
|
||||
&BX_ACPI_THIS s.pm_base,
|
||||
&BX_ACPI_THIS s.pci_conf[0x40],
|
||||
64, &acpi_pm_iomask[0], "ACPI PM base"))
|
||||
{
|
||||
BX_INFO(("new PM base address: 0x%04x", BX_ACPI_THIS s.pm_base));
|
||||
}
|
||||
}
|
||||
if (sm_base_change) {
|
||||
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
|
||||
&BX_ACPI_THIS s.sm_base,
|
||||
&BX_ACPI_THIS s.pci_conf[0x90],
|
||||
16, &acpi_sm_iomask[0], "ACPI SM base"))
|
||||
{
|
||||
BX_INFO(("new SM base address: 0x%04x", BX_ACPI_THIS s.sm_base));
|
||||
}
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI
|
||||
86
bochs/iodev/acpi.h
Normal file
86
bochs/iodev/acpi.h
Normal file
@ -0,0 +1,86 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2006 Volker Ruppert
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_ACPI_H
|
||||
#define BX_IODEV_ACPI_H
|
||||
|
||||
#if BX_USE_ACPI_SMF
|
||||
# define BX_ACPI_SMF static
|
||||
# define BX_ACPI_THIS theACPIController->
|
||||
# define BX_ACPI_THIS_PTR theACPIController
|
||||
#else
|
||||
# define BX_ACPI_SMF
|
||||
# define BX_ACPI_THIS this->
|
||||
# define BX_ACPI_THIS_PTR this
|
||||
#endif
|
||||
|
||||
class bx_acpi_ctrl_c : public bx_acpi_ctrl_stub_c {
|
||||
public:
|
||||
bx_acpi_ctrl_c();
|
||||
virtual ~bx_acpi_ctrl_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void generate_smi(Bit8u value);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
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_ACPI_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
BX_ACPI_SMF void timer(void);
|
||||
|
||||
private:
|
||||
BX_ACPI_SMF void set_irq_level(bx_bool level);
|
||||
BX_ACPI_SMF Bit32u get_pmtmr(void);
|
||||
BX_ACPI_SMF Bit16u get_pmsts(void);
|
||||
BX_ACPI_SMF void pm_update_sci(void);
|
||||
static void timer_handler(void *);
|
||||
|
||||
struct {
|
||||
Bit8u pci_conf[256];
|
||||
Bit8u devfunc;
|
||||
Bit32u pm_base;
|
||||
Bit32u sm_base;
|
||||
Bit16u pmsts;
|
||||
Bit16u pmen;
|
||||
Bit16u pmcntrl;
|
||||
Bit64u tmr_overflow_time;
|
||||
int timer_index;
|
||||
struct {
|
||||
Bit8u stat;
|
||||
Bit8u ctl;
|
||||
Bit8u cmd;
|
||||
Bit8u addr;
|
||||
Bit8u data0;
|
||||
Bit8u data1;
|
||||
Bit8u index;
|
||||
Bit8u data[32];
|
||||
} smbus;
|
||||
} s;
|
||||
};
|
||||
|
||||
#endif
|
||||
210
bochs/iodev/aspi-win32.h
Normal file
210
bochs/iodev/aspi-win32.h
Normal file
@ -0,0 +1,210 @@
|
||||
//
|
||||
// iodev/aspi-win32.h
|
||||
// $Id$
|
||||
//
|
||||
// This file was copied from cdrecord 1.9 under libscg/scg/aspi-win32.h.
|
||||
// The only modification is related to use of the PACKED keyword.
|
||||
//
|
||||
|
||||
#ifndef __ASPI_WIN32_H_
|
||||
#define __ASPI_WIN32_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef PACKED
|
||||
// It seems that VC++ has no PACKED keyword but Cygwin does. We can just
|
||||
// define PACKED to be empty if it's not already defined by the system
|
||||
// headers.
|
||||
#define PACKED /* empty */
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
** SCSI MISCELLANEOUS EQUATES
|
||||
***************************************************************************/
|
||||
#define SENSE_LEN 14 /* Default sense buffer length */
|
||||
#define SRB_DIR_SCSI 0x00 /* Direction determined by SCSI */
|
||||
#define SRB_POSTING 0x01 /* Enable ASPI posting */
|
||||
#define SRB_ENABLE_RESIDUAL_COUNT 0x04 /* Enable residual byte count */
|
||||
/* reporting */
|
||||
#define SRB_DIR_IN 0x08 /* Transfer from SCSI target to */
|
||||
/* host */
|
||||
#define SRB_DIR_OUT 0x10 /* Transfer from host to SCSI */
|
||||
/* target */
|
||||
#define SRB_EVENT_NOTIFY 0x40 /* Enable ASPI event notification */
|
||||
#define RESIDUAL_COUNT_SUPPORTED 0x02 /* Extended buffer flag */
|
||||
#define MAX_SRB_TIMEOUT 1080001u /* 30 hour maximum timeout in sec */
|
||||
#define DEFAULT_SRB_TIMEOUT 1080001u /* use max.timeout by default */
|
||||
|
||||
/***************************************************************************
|
||||
** ASPI command definitions
|
||||
***************************************************************************/
|
||||
#define SC_HA_INQUIRY 0x00 /* Host adapter inquiry */
|
||||
#define SC_GET_DEV_TYPE 0x01 /* Get device type */
|
||||
#define SC_EXEC_SCSI_CMD 0x02 /* Execute SCSI command */
|
||||
#define SC_ABORT_SRB 0x03 /* Abort an SRB */
|
||||
#define SC_RESET_DEV 0x04 /* SCSI bus device reset */
|
||||
#define SC_SET_HA_PARMS 0x05 /* Set HA parameters */
|
||||
#define SC_GET_DISK_INFO 0x06 /* Get Disk */
|
||||
#define SC_RESCAN_SCSI_BUS 0x07 /* Rebuild SCSI device map */
|
||||
#define SC_GETSET_TIMEOUTS 0x08 /* Get/Set target timeouts */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** SRB Status
|
||||
***************************************************************************/
|
||||
#define SS_PENDING 0x00 /* SRB being processed */
|
||||
#define SS_COMP 0x01 /* SRB completed without error */
|
||||
#define SS_ABORTED 0x02 /* SRB aborted */
|
||||
#define SS_ABORT_FAIL 0x03 /* Unable to abort SRB */
|
||||
#define SS_ERR 0x04 /* SRB completed with error */
|
||||
#define SS_INVALID_CMD 0x80 /* Invalid ASPI command */
|
||||
#define SS_INVALID_HA 0x81 /* Invalid host adapter number */
|
||||
#define SS_NO_DEVICE 0x82 /* SCSI device not installed */
|
||||
#define SS_INVALID_SRB 0xE0 /* Invalid parameter set in SRB */
|
||||
#define SS_OLD_MANAGER 0xE1 /* ASPI manager doesn't support */
|
||||
/* windows */
|
||||
#define SS_BUFFER_ALIGN 0xE1 /* Buffer not aligned (replaces */
|
||||
/* SS_OLD_MANAGER in Win32) */
|
||||
#define SS_ILLEGAL_MODE 0xE2 /* Unsupported Windows mode */
|
||||
#define SS_NO_ASPI 0xE3 /* No ASPI managers */
|
||||
#define SS_FAILED_INIT 0xE4 /* ASPI for windows failed init */
|
||||
#define SS_ASPI_IS_BUSY 0xE5 /* No resources available to */
|
||||
/* execute command */
|
||||
#define SS_BUFFER_TO_BIG 0xE6 /* Buffer size too big to handle */
|
||||
#define SS_BUFFER_TOO_BIG 0xE6 /* Correct spelling of 'too' */
|
||||
#define SS_MISMATCHED_COMPONENTS 0xE7 /* The DLLs/EXEs of ASPI don't */
|
||||
/* version check */
|
||||
#define SS_NO_ADAPTERS 0xE8 /* No host adapters to manager */
|
||||
#define SS_INSUFFICIENT_RESOURCES 0xE9 /* Couldn't allocate resources */
|
||||
/* needed to init */
|
||||
#define SS_ASPI_IS_SHUTDOWN 0xEA /* Call came to ASPI after */
|
||||
/* PROCESS_DETACH */
|
||||
#define SS_BAD_INSTALL 0xEB /* The DLL or other components */
|
||||
/* are installed wrong */
|
||||
|
||||
/***************************************************************************
|
||||
** Host Adapter Status
|
||||
***************************************************************************/
|
||||
#define HASTAT_OK 0x00 /* No error detected by HA */
|
||||
#define HASTAT_SEL_TO 0x11 /* Selection Timeout */
|
||||
#define HASTAT_DO_DU 0x12 /* Data overrun/data underrun */
|
||||
#define HASTAT_BUS_FREE 0x13 /* Unexpected bus free */
|
||||
#define HASTAT_PHASE_ERR 0x14 /* Target bus phase sequence */
|
||||
#define HASTAT_TIMEOUT 0x09 /* Timed out while SRB was */
|
||||
/* waiting to be processed */
|
||||
#define HASTAT_COMMAND_TIMEOUT 0x0B /* Adapter timed out while */
|
||||
/* processing SRB */
|
||||
#define HASTAT_MESSAGE_REJECT 0x0D /* While processing the SRB, the */
|
||||
/* adapter received a MESSAGE */
|
||||
#define HASTAT_BUS_RESET 0x0E /* A bus reset was detected */
|
||||
#define HASTAT_PARITY_ERROR 0x0F /* A parity error was detected */
|
||||
#define HASTAT_REQUEST_SENSE_FAILED 0x10 /* The adapter failed in issuing */
|
||||
|
||||
/***************************************************************************
|
||||
** SRB - HOST ADAPTER INQUIRIY - SC_HA_INQUIRY (0)
|
||||
***************************************************************************/
|
||||
typedef struct {
|
||||
BYTE SRB_Cmd; /* 00/000 ASPI command code == SC_HA_INQUIRY */
|
||||
BYTE SRB_Status; /* 01/001 ASPI command status byte */
|
||||
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
|
||||
BYTE SRB_Flags; /* 03/003 ASPI request flags */
|
||||
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
|
||||
BYTE HA_Count; /* 08/008 Number of host adapters present */
|
||||
BYTE HA_SCSI_ID; /* 09/009 SCSI ID of host adapter */
|
||||
BYTE HA_ManagerId[16]; /* 0a/010 String describing the manager */
|
||||
BYTE HA_Identifier[16]; /* 1a/026 String describing the host adapter */
|
||||
BYTE HA_Unique[16]; /* 2a/042 Host Adapter Unique parameters */
|
||||
WORD HA_Rsvd1; /* 3a/058 Reserved, must = 0 */
|
||||
} PACKED SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1)
|
||||
***************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */
|
||||
BYTE SRB_Status; /* 01/001 ASPI command status byte */
|
||||
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
|
||||
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
|
||||
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
|
||||
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
|
||||
BYTE SRB_Lun; /* 09/009 Target's LUN number */
|
||||
BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */
|
||||
BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */
|
||||
} PACKED SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2)
|
||||
***************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_EXEC_SCSI_CMD */
|
||||
BYTE SRB_Status; /* 01/001 ASPI command status byte */
|
||||
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
|
||||
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
|
||||
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
|
||||
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
|
||||
BYTE SRB_Lun; /* 09/009 Target's LUN */
|
||||
WORD SRB_Rsvd1; /* 0a/010 Reserved for alignment */
|
||||
DWORD SRB_BufLen; /* 0c/012 Data Allocation Length */
|
||||
BYTE FAR *SRB_BufPointer; /* 10/016 Data Buffer Pointer */
|
||||
BYTE SRB_SenseLen; /* 14/020 Sense Allocation Length */
|
||||
BYTE SRB_CDBLen; /* 15/021 CDB Length */
|
||||
BYTE SRB_HaStat; /* 16/022 Host Adapter Status */
|
||||
BYTE SRB_TargStat; /* 17/023 Target Status */
|
||||
VOID FAR *SRB_PostProc; /* 18/024 Post routine */
|
||||
BYTE SRB_Rsvd2[20]; /* 1c/028 Reserved, must = 0 */
|
||||
BYTE CDBByte[16]; /* 30/048 SCSI CDB */
|
||||
BYTE SenseArea[SENSE_LEN+2]; /* 40/064 Request Sense buffer */
|
||||
} PACKED SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_ABORT_SRB */
|
||||
BYTE SRB_Status; /* 01/001 ASPI command status byte */
|
||||
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
|
||||
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
|
||||
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
|
||||
void *SRB_ToAbort; /* 08/008 Pointer to SRB to abort */
|
||||
} PACKED SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** SRB - BUS DEVICE RESET - SC_RESET_DEV (4)
|
||||
***************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_RESET_DEV */
|
||||
BYTE SRB_Status; /* 01/001 ASPI command status byte */
|
||||
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
|
||||
DWORD SRB_Flags; /* 04/004 Reserved */
|
||||
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
|
||||
BYTE SRB_Lun; /* 09/009 Target's LUN number */
|
||||
BYTE SRB_Rsvd1[12]; /* 0A/010 Reserved for alignment */
|
||||
BYTE SRB_HaStat; /* 16/022 Host Adapter Status */
|
||||
BYTE SRB_TargStat; /* 17/023 Target Status */
|
||||
VOID FAR *SRB_PostProc; /* 18/024 Post routine */
|
||||
BYTE SRB_Rsvd2[36]; /* 1C/028 Reserved, must = 0 */
|
||||
} SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset;
|
||||
|
||||
typedef struct tag_ASPI32BUFF
|
||||
{
|
||||
PBYTE AB_BufPointer;
|
||||
DWORD AB_BufLen;
|
||||
DWORD AB_ZeroFill;
|
||||
DWORD AB_Reserved;
|
||||
} PACKED ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE SRB_Cmd;
|
||||
BYTE SRB_Status;
|
||||
BYTE SRB_HaId;
|
||||
BYTE SRB_Flags;
|
||||
DWORD SRB_Hdr_Rsvd;
|
||||
} SRB, *PSRB, FAR *LPSRB;
|
||||
|
||||
#endif
|
||||
219
bochs/iodev/biosdev.cc
Normal file
219
bochs/iodev/biosdev.cc
Normal file
@ -0,0 +1,219 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
// Here are the virtual ports use to display messages from the bioses :
|
||||
//
|
||||
// 0x0400 : rombios Panic port with line number
|
||||
// 0x0401 : rombios Panic port with message, panic flag or line number
|
||||
// 0x0402 : rombios Info port with message
|
||||
// 0x0403 : rombios Debug port with message
|
||||
//
|
||||
// 0x0500 : vgabios Info port with message
|
||||
// 0x0501 : vgabios Panic port with line number
|
||||
// 0x0502 : vgabios Panic port with message, panic flag or line number
|
||||
// 0x0503 : vgabios Debug port with message
|
||||
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "biosdev.h"
|
||||
|
||||
bx_biosdev_c *theBiosDevice = NULL;
|
||||
|
||||
logfunctions *bioslog;
|
||||
logfunctions *vgabioslog;
|
||||
|
||||
int libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theBiosDevice = new bx_biosdev_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libbiosdev_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theBiosDevice;
|
||||
}
|
||||
|
||||
bx_biosdev_c::bx_biosdev_c(void)
|
||||
{
|
||||
bioslog = new logfunctions();
|
||||
bioslog->put("BIOS");
|
||||
|
||||
vgabioslog = new logfunctions();
|
||||
vgabioslog->put("VBIOS");
|
||||
}
|
||||
|
||||
bx_biosdev_c::~bx_biosdev_c(void)
|
||||
{
|
||||
bioslog->ldebug("Exit");
|
||||
if (bioslog != NULL) {
|
||||
delete bioslog;
|
||||
bioslog = NULL;
|
||||
}
|
||||
if (vgabioslog != NULL) {
|
||||
delete vgabioslog;
|
||||
vgabioslog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_biosdev_c::init(void)
|
||||
{
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0400, "Bios Panic Port 1", 3);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0401, "Bios Panic Port 2", 3);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios Info Port", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0403, "Bios Debug Port", 1);
|
||||
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0501, "VGABios Panic Port 1", 3);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0502, "VGABios Panic Port 2", 3);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0503, "VGABios Debug Port", 1);
|
||||
|
||||
s.bios_message_i = 0;
|
||||
s.bios_panic_flag = 0;
|
||||
s.vgabios_message_i = 0;
|
||||
s.vgabios_panic_flag = 0;
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_biosdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_BIOS_SMF
|
||||
bx_biosdev_c *class_ptr = (bx_biosdev_c *) this_ptr;
|
||||
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_biosdev_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_BIOS_SMF
|
||||
UNUSED(io_len);
|
||||
|
||||
|
||||
switch (address) {
|
||||
// 0x400-0x401 are used as panic ports for the rombios
|
||||
case 0x0401:
|
||||
if (value==0) {
|
||||
// The next message sent to the info port will cause a panic
|
||||
BX_BIOS_THIS s.bios_panic_flag = 1;
|
||||
break;
|
||||
} else if (BX_BIOS_THIS s.bios_message_i > 0) {
|
||||
// if there are bits of message in the buffer, print them as the
|
||||
// panic message. Otherwise fall into the next case.
|
||||
if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE)
|
||||
BX_BIOS_THIS s.bios_message_i = BX_BIOS_MESSAGE_SIZE-1;
|
||||
BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i] = 0;
|
||||
BX_BIOS_THIS s.bios_message_i = 0;
|
||||
bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
|
||||
break;
|
||||
}
|
||||
case 0x0400:
|
||||
if (value > 0) {
|
||||
bioslog->panic("BIOS panic at rombios.c, line %d", value);
|
||||
}
|
||||
break;
|
||||
|
||||
// 0x0402 is used as the info port for the rombios
|
||||
// 0x0403 is used as the debug port for the rombios
|
||||
case 0x0402:
|
||||
case 0x0403:
|
||||
BX_BIOS_THIS s.bios_message[BX_BIOS_THIS s.bios_message_i] =
|
||||
(Bit8u) value;
|
||||
BX_BIOS_THIS s.bios_message_i ++;
|
||||
if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE) {
|
||||
BX_BIOS_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
|
||||
BX_BIOS_THIS s.bios_message_i = 0;
|
||||
if (address==0x403)
|
||||
bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
|
||||
else
|
||||
bioslog->info("%s", BX_BIOS_THIS s.bios_message);
|
||||
} else if ((value & 0xff) == '\n') {
|
||||
BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i - 1 ] = 0;
|
||||
BX_BIOS_THIS s.bios_message_i = 0;
|
||||
if (BX_BIOS_THIS s.bios_panic_flag==1)
|
||||
bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
|
||||
else if (address==0x403)
|
||||
bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
|
||||
else
|
||||
bioslog->info("%s", BX_BIOS_THIS s.bios_message);
|
||||
BX_BIOS_THIS s.bios_panic_flag = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
// 0x501-0x502 are used as panic ports for the vgabios
|
||||
case 0x0502:
|
||||
if (value==0) {
|
||||
BX_BIOS_THIS s.vgabios_panic_flag = 1;
|
||||
break;
|
||||
} else if (BX_BIOS_THIS s.vgabios_message_i > 0) {
|
||||
// if there are bits of message in the buffer, print them as the
|
||||
// panic message. Otherwise fall into the next case.
|
||||
if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE)
|
||||
BX_BIOS_THIS s.vgabios_message_i = BX_BIOS_MESSAGE_SIZE-1;
|
||||
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i] = 0;
|
||||
BX_BIOS_THIS s.vgabios_message_i = 0;
|
||||
vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
break;
|
||||
}
|
||||
case 0x0501:
|
||||
if (value > 0) {
|
||||
vgabioslog->panic("VGABIOS panic at vgabios.c, line %d", value);
|
||||
}
|
||||
break;
|
||||
|
||||
// 0x0500 is used as the message port for the vgabios
|
||||
case 0x0500:
|
||||
case 0x0503:
|
||||
BX_BIOS_THIS s.vgabios_message[BX_BIOS_THIS s.vgabios_message_i] =
|
||||
(Bit8u) value;
|
||||
BX_BIOS_THIS s.vgabios_message_i ++;
|
||||
if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE) {
|
||||
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
|
||||
BX_BIOS_THIS s.vgabios_message_i = 0;
|
||||
if (address==0x503)
|
||||
vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
else
|
||||
vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
} else if ((value & 0xff) == '\n') {
|
||||
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i - 1 ] = 0;
|
||||
BX_BIOS_THIS s.vgabios_message_i = 0;
|
||||
if (BX_BIOS_THIS s.vgabios_panic_flag==1)
|
||||
vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
else if (address==0x503)
|
||||
vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
else
|
||||
vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
|
||||
BX_BIOS_THIS s.vgabios_panic_flag = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
61
bochs/iodev/biosdev.h
Normal file
61
bochs/iodev/biosdev.h
Normal file
@ -0,0 +1,61 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
#ifndef BX_IODEV_BIOSDEV_H
|
||||
#define BX_IODEV_BIOSDEV_H
|
||||
|
||||
#define BX_BIOS_MESSAGE_SIZE 80
|
||||
|
||||
#if BX_USE_BIOS_SMF
|
||||
# define BX_BIOS_SMF static
|
||||
# define BX_BIOS_THIS theBiosDevice->
|
||||
#else
|
||||
# define BX_BIOS_SMF
|
||||
# define BX_BIOS_THIS this->
|
||||
#endif
|
||||
|
||||
class bx_biosdev_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_biosdev_c();
|
||||
virtual ~bx_biosdev_c();
|
||||
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type) {}
|
||||
|
||||
private:
|
||||
|
||||
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
|
||||
#if !BX_USE_BIOS_SMF
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
|
||||
struct {
|
||||
Bit8u bios_message[BX_BIOS_MESSAGE_SIZE];
|
||||
unsigned int bios_message_i;
|
||||
bx_bool bios_panic_flag;
|
||||
|
||||
Bit8u vgabios_message[BX_BIOS_MESSAGE_SIZE];
|
||||
unsigned int vgabios_message_i;
|
||||
bx_bool vgabios_panic_flag;
|
||||
} s; // state information
|
||||
};
|
||||
|
||||
#endif
|
||||
331
bochs/iodev/busmouse.cc
Normal file
331
bochs/iodev/busmouse.cc
Normal file
@ -0,0 +1,331 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
// Initial code by Ben Lunt 'fys frontiernet net'
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "busmouse.h"
|
||||
|
||||
#if BX_SUPPORT_BUSMOUSE
|
||||
|
||||
#define LOG_THIS theBusMouse->
|
||||
|
||||
bx_busm_c *theBusMouse = NULL;
|
||||
|
||||
int libbusmouse_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
// Create one instance of the busmouse device object.
|
||||
theBusMouse = new bx_busm_c();
|
||||
// Register this device.
|
||||
BX_REGISTER_DEVICE_DEVMODEL (plugin, type, theBusMouse, BX_PLUGIN_BUSMOUSE);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libbusmouse_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theBusMouse;
|
||||
}
|
||||
|
||||
bx_busm_c::bx_busm_c()
|
||||
{
|
||||
put("BUSM");
|
||||
}
|
||||
|
||||
bx_busm_c::~bx_busm_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_busm_c::init(void)
|
||||
{
|
||||
BX_DEBUG(("Init $Id$"));
|
||||
|
||||
DEV_register_irq(BUS_MOUSE_IRQ, "Bus Mouse");
|
||||
|
||||
// Call our timer routine at 30hz
|
||||
BX_BUSM_THIS timer_index =
|
||||
bx_pc_system.register_timer(this, timer_handler, 33334, 1, 1, "bus mouse timer");
|
||||
|
||||
for (int i=0x23C; i<=0x23F; i++) {
|
||||
DEV_register_ioread_handler(this, read_handler, i, "Bus Mouse", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, i, "Bus Mouse", 1);
|
||||
}
|
||||
DEV_register_default_mouse(this, mouse_enq_static, NULL);
|
||||
|
||||
BX_BUSM_THIS mouse_delayed_dx = 0;
|
||||
BX_BUSM_THIS mouse_delayed_dy = 0;
|
||||
BX_BUSM_THIS current_x =
|
||||
BX_BUSM_THIS current_y =
|
||||
BX_BUSM_THIS current_b = 0;
|
||||
|
||||
BX_BUSM_THIS sig_port_sequ = 0;
|
||||
BX_BUSM_THIS interrupts = 0; // interrupts off
|
||||
BX_BUSM_THIS command_val = 0; // command byte
|
||||
BX_BUSM_THIS cur_command = 0;
|
||||
|
||||
// the control port values
|
||||
BX_BUSM_THIS control_val =
|
||||
BX_BUSM_THIS control.mode_set =
|
||||
BX_BUSM_THIS control.modeA_select =
|
||||
BX_BUSM_THIS control.portA_dir =
|
||||
BX_BUSM_THIS control.portC_upper_dir =
|
||||
BX_BUSM_THIS control.modeBC_select =
|
||||
BX_BUSM_THIS control.portB_dir =
|
||||
BX_BUSM_THIS control.portC_lower_dir =
|
||||
BX_BUSM_THIS control_val = 0;
|
||||
|
||||
BX_INFO(("Initialized BusMouse"));
|
||||
}
|
||||
|
||||
void bx_busm_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "busmouse", "Busmouse State", 12);
|
||||
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dx);
|
||||
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dy);
|
||||
BXRS_HEX_PARAM_FIELD(list, current_x, BX_BUSM_THIS current_x);
|
||||
BXRS_HEX_PARAM_FIELD(list, current_y, BX_BUSM_THIS current_y);
|
||||
BXRS_HEX_PARAM_FIELD(list, current_b, BX_BUSM_THIS current_b);
|
||||
BXRS_HEX_PARAM_FIELD(list, sig_port_sequ, BX_BUSM_THIS sig_port_sequ);
|
||||
BXRS_HEX_PARAM_FIELD(list, control_val, BX_BUSM_THIS control_val);
|
||||
|
||||
bx_list_c *ctrl = new bx_list_c(list, "control", 7);
|
||||
BXRS_PARAM_BOOL(ctrl, mode_set, BX_BUSM_THIS control.mode_set);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, modeA_select, BX_BUSM_THIS control.modeA_select);
|
||||
BXRS_PARAM_BOOL(ctrl, portA_dir, BX_BUSM_THIS control.portA_dir);
|
||||
BXRS_PARAM_BOOL(ctrl, portC_upper_dir, BX_BUSM_THIS control.portC_upper_dir);
|
||||
BXRS_PARAM_BOOL(ctrl, modeBC_select, BX_BUSM_THIS control.modeBC_select);
|
||||
BXRS_PARAM_BOOL(ctrl, portB_dir, BX_BUSM_THIS control.portB_dir);
|
||||
BXRS_PARAM_BOOL(ctrl, portC_lower_dir, BX_BUSM_THIS control.portC_lower_dir);
|
||||
|
||||
BXRS_PARAM_BOOL(list, interrupts, BX_BUSM_THIS interrupts);
|
||||
BXRS_PARAM_BOOL(list, packet_update, BX_BUSM_THIS packet_update);
|
||||
BXRS_HEX_PARAM_FIELD(list, cur_command, BX_BUSM_THIS cur_command);
|
||||
BXRS_HEX_PARAM_FIELD(list, command_val, BX_BUSM_THIS command_val);
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
Bit32u bx_busm_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_BUSM_SMF
|
||||
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_busm_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_BUSM_SMF
|
||||
|
||||
Bit8u value = 0;
|
||||
|
||||
switch (address) {
|
||||
case 0x023C:
|
||||
value = BX_BUSM_THIS control_val;
|
||||
/* value = (BX_BUSM_THIS control.mode_set ? 1<<7 : 0)
|
||||
* | (BX_BUSM_THIS control.modeA_select <<5)
|
||||
* | (BX_BUSM_THIS control.portA_dir ? 1<<4 : 0)
|
||||
* | (BX_BUSM_THIS control.portC_upper_dir ? 1<<3 : 0)
|
||||
* | (BX_BUSM_THIS control.modeBC_select ? 1<<2 : 0)
|
||||
* | (BX_BUSM_THIS control.portB_dir ? 1<<1 : 0)
|
||||
* | (BX_BUSM_THIS control.portC_lower_dir ? 1<<0 : 0);
|
||||
*/ break;
|
||||
case 0x023D: // data
|
||||
switch (BX_BUSM_THIS cur_command) {
|
||||
case 0x00: // read buttons
|
||||
value = BX_BUSM_THIS current_b;
|
||||
break;
|
||||
case 0x01: // read x
|
||||
value = BX_BUSM_THIS current_x;
|
||||
break;
|
||||
case 0x02: // read y
|
||||
value = BX_BUSM_THIS current_y;
|
||||
break;
|
||||
case 0x07: // command mode
|
||||
value = BX_BUSM_THIS command_val;
|
||||
break;
|
||||
default:
|
||||
BX_PANIC(("Unknown command to data port: %x", BX_BUSM_THIS cur_command));
|
||||
}
|
||||
break;
|
||||
case 0x023E: // sig
|
||||
if (!(BX_BUSM_THIS sig_port_sequ & 1))
|
||||
value = 0xDE;
|
||||
else
|
||||
value = 0x22; // Manufacture id?
|
||||
BX_BUSM_THIS sig_port_sequ++;
|
||||
break;
|
||||
case 0x023F:
|
||||
BX_PANIC(("Read from port 0x023F"));
|
||||
break;
|
||||
}
|
||||
|
||||
BX_INFO(("read from address 0x%04x, value = 0x%02x ", address, value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_busm_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_BUSM_SMF
|
||||
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_busm_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_BUSM_SMF
|
||||
|
||||
BX_INFO(("write to address 0x%04x, value = 0x%02x ", address, value));
|
||||
|
||||
switch (address) {
|
||||
case 0x023C: // control
|
||||
BX_BUSM_THIS control.mode_set = (value & 0x80) ? 1 : 0;
|
||||
BX_BUSM_THIS control.modeA_select = (value & 0x60) >> 5;
|
||||
BX_BUSM_THIS control.portA_dir = (value & 0x10) ? 1 : 0;
|
||||
BX_BUSM_THIS control.portC_upper_dir = (value & 0x08) ? 1 : 0;
|
||||
BX_BUSM_THIS control.modeBC_select = (value & 0x04) ? 1 : 0;
|
||||
BX_BUSM_THIS control.portB_dir = (value & 0x02) ? 1 : 0;
|
||||
BX_BUSM_THIS control.portC_lower_dir = (value & 0x01) ? 1 : 0;
|
||||
BX_BUSM_THIS control_val = value;
|
||||
|
||||
/*
|
||||
switch (value) {
|
||||
case 0x00: // read buttons
|
||||
case 0x01: // read x
|
||||
case 0x02: // read y
|
||||
case 0x07:
|
||||
BX_BUSM_THIS cur_command = (Bit8u) value;
|
||||
break;
|
||||
case 0x80: // reset
|
||||
BX_BUSM_THIS cur_command = 0x00;
|
||||
BX_BUSM_THIS command_val = 0x80;
|
||||
break;
|
||||
default:
|
||||
BX_PANIC(("Unknown command to control port %x", value));
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case 0x023D: // data port
|
||||
switch (BX_BUSM_THIS cur_command) {
|
||||
case 0x07: // command mode
|
||||
switch (value) {
|
||||
case 0x10: // interrupts off
|
||||
BX_BUSM_THIS interrupts = 0;
|
||||
break;
|
||||
case 0x11: // interrupts on
|
||||
BX_BUSM_THIS interrupts = 1;
|
||||
break;
|
||||
default:
|
||||
BX_BUSM_THIS command_val = value;
|
||||
if ((value & 0x20) == 0)
|
||||
DEV_pic_lower_irq(BUS_MOUSE_IRQ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_PANIC(("Unknown command written to data port: %x", BX_BUSM_THIS cur_command));
|
||||
}
|
||||
break;
|
||||
case 0x023E:
|
||||
BX_PANIC(("Write to port 0x023E"));
|
||||
break;
|
||||
case 0x023F:
|
||||
BX_PANIC(("Write to port 0x023F"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_busm_c::mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state)
|
||||
{
|
||||
((bx_busm_c*)dev)->mouse_enq(delta_x, delta_y, delta_z, button_state);
|
||||
}
|
||||
|
||||
void bx_busm_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state)
|
||||
{
|
||||
// scale down the motion
|
||||
if ((delta_x < -1) || (delta_x > 1))
|
||||
delta_x /= 2;
|
||||
if ((delta_y < -1) || (delta_y > 1))
|
||||
delta_y /= 2;
|
||||
|
||||
if(delta_x>127) delta_x=127;
|
||||
if(delta_y>127) delta_y=127;
|
||||
if(delta_x<-128) delta_x=-128;
|
||||
if(delta_y<-128) delta_y=-128;
|
||||
|
||||
BX_BUSM_THIS mouse_delayed_dx+=delta_x;
|
||||
BX_BUSM_THIS mouse_delayed_dy-=delta_y;
|
||||
|
||||
if (BX_BUSM_THIS mouse_delayed_dx > 127) {
|
||||
delta_x = 127;
|
||||
BX_BUSM_THIS mouse_delayed_dx -= 127;
|
||||
} else if (BX_BUSM_THIS mouse_delayed_dx < -128) {
|
||||
delta_x = -128;
|
||||
BX_BUSM_THIS mouse_delayed_dx += 128;
|
||||
} else {
|
||||
delta_x = BX_BUSM_THIS mouse_delayed_dx;
|
||||
BX_BUSM_THIS mouse_delayed_dx = 0;
|
||||
}
|
||||
if (BX_BUSM_THIS mouse_delayed_dy > 127) {
|
||||
delta_y = 127;
|
||||
BX_BUSM_THIS mouse_delayed_dy -= 127;
|
||||
} else if (BX_BUSM_THIS mouse_delayed_dy < -128) {
|
||||
delta_y = -128;
|
||||
BX_BUSM_THIS mouse_delayed_dy += 128;
|
||||
} else {
|
||||
delta_y = BX_BUSM_THIS mouse_delayed_dy;
|
||||
BX_BUSM_THIS mouse_delayed_dy = 0;
|
||||
}
|
||||
|
||||
if ((BX_BUSM_THIS cur_command & 0x20) == 0x00) {
|
||||
BX_BUSM_THIS current_x = (Bit8u) delta_x;
|
||||
BX_BUSM_THIS current_y = (Bit8u) delta_y;
|
||||
BX_BUSM_THIS current_b = (Bit8u) ~(((button_state & 0x01)<<2) | ((button_state & 0x02) >> 1));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_busm_c::timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
||||
class_ptr->busm_timer();
|
||||
}
|
||||
|
||||
// Called at 30hz
|
||||
void bx_busm_c::busm_timer(void)
|
||||
{
|
||||
// if interrupts are on, fire the interrupt
|
||||
if (BX_BUSM_THIS interrupts) {
|
||||
DEV_pic_raise_irq(BUS_MOUSE_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_BUSMOUSE
|
||||
108
bochs/iodev/busmouse.h
Normal file
108
bochs/iodev/busmouse.h
Normal file
@ -0,0 +1,108 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
#if BX_SUPPORT_BUSMOUSE
|
||||
|
||||
#ifndef _PCBUSM_H
|
||||
#define _PCBUSM_H
|
||||
|
||||
// these keywords should only be used in busmouse.cc
|
||||
#if BX_USE_BUSM_SMF
|
||||
# define BX_BUSM_SMF static
|
||||
# define BX_BUSM_THIS theBusMouse->
|
||||
#else
|
||||
# define BX_BUSM_SMF
|
||||
# define BX_BUSM_THIS
|
||||
#endif
|
||||
|
||||
#define BUS_MOUSE_IRQ 5
|
||||
|
||||
#define PORT_CONTROL 0x023C
|
||||
#define PORT_DATA 0x023D
|
||||
#define PORT_SIGNATURE 0x023E
|
||||
#define PORT_CONFIG 0x023F
|
||||
|
||||
class bx_busm_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_busm_c();
|
||||
virtual ~bx_busm_c();
|
||||
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type) {}
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
static void timer_handler(void *);
|
||||
void busm_timer(void);
|
||||
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
void mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
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_BUSM_SMF
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
#endif
|
||||
|
||||
int timer_index; // our timer index
|
||||
|
||||
int mouse_delayed_dx;
|
||||
int mouse_delayed_dy;
|
||||
Bit8u current_x, current_y, current_b;
|
||||
|
||||
// signature port
|
||||
Bit8u sig_port_sequ; // bit0: 0 or 1. A register read rotates between two values? 0xDE and Hardware ID?
|
||||
|
||||
// D7 = Mode set flag (1 = active)
|
||||
// D6,D5 = Mode selection (port A)
|
||||
// 00 = Mode 0 = Basic I/O
|
||||
// 01 = Mode 1 = Strobed I/O
|
||||
// 10 = Mode 2 = Bi-dir bus
|
||||
// D4 = Port A direction (1 = input)
|
||||
// D3 = Port C (upper 4 bits)
|
||||
// direction. (1 = input)
|
||||
// D2 = Mode selection (port B & C)
|
||||
// 0 = Mode 0 = Basic I/O
|
||||
// 1 = Mode 1 = Strobed I/O
|
||||
// D1 = Port B direction (1 = input)
|
||||
// D0 = Port C (lower 4 bits)
|
||||
// direction. (1 = input)
|
||||
Bit8u control_val;
|
||||
struct {
|
||||
bx_bool mode_set;
|
||||
Bit8u modeA_select;
|
||||
bx_bool portA_dir; // 1 = input
|
||||
bx_bool portC_upper_dir; // 1 = input
|
||||
bx_bool modeBC_select;
|
||||
bx_bool portB_dir; // 1 = input
|
||||
bx_bool portC_lower_dir; // 1 = input
|
||||
} control;
|
||||
|
||||
|
||||
bx_bool interrupts; // 0 or 1. interrupts off or on.
|
||||
bx_bool packet_update; // 0 or 1. allow the mouse to update the packet?
|
||||
|
||||
Bit8u cur_command; // current command
|
||||
Bit8u command_val; // current command val
|
||||
};
|
||||
|
||||
#endif // #ifndef _PCBUSM_H
|
||||
|
||||
#endif // BX_SUPPORT_BUSMOUSE
|
||||
1471
bochs/iodev/cdrom.cc
Normal file
1471
bochs/iodev/cdrom.cc
Normal file
File diff suppressed because it is too large
Load Diff
65
bochs/iodev/cdrom.h
Normal file
65
bochs/iodev/cdrom.h
Normal file
@ -0,0 +1,65 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
// Header file for low-level OS specific CDROM emulation
|
||||
|
||||
|
||||
class cdrom_interface : public logfunctions {
|
||||
public:
|
||||
cdrom_interface(const char *dev);
|
||||
virtual ~cdrom_interface(void);
|
||||
void init(void);
|
||||
|
||||
// Load CD-ROM. Returns 0 if CD is not ready.
|
||||
bx_bool insert_cdrom(const char *dev = NULL);
|
||||
|
||||
// Logically eject the CD.
|
||||
void eject_cdrom();
|
||||
|
||||
// Read CD TOC. Returns 0 if start track is out of bounds.
|
||||
bx_bool read_toc(Bit8u* buf, int* length, bx_bool msf, int start_track, int format);
|
||||
|
||||
// Return CD-ROM capacity (in 2048 byte frames)
|
||||
Bit32u capacity();
|
||||
|
||||
// Read a single block from the CD. Returns 0 on failure.
|
||||
bx_bool read_block(Bit8u* buf, Bit32u lba, int blocksize) BX_CPP_AttrRegparmN(3);
|
||||
|
||||
// Start (spin up) the CD.
|
||||
bx_bool start_cdrom();
|
||||
|
||||
// Seek for new block address.
|
||||
void seek(Bit32u lba);
|
||||
|
||||
private:
|
||||
int fd;
|
||||
char *path;
|
||||
|
||||
int using_file;
|
||||
#ifdef WIN32
|
||||
BOOL bUseASPI;
|
||||
HANDLE hFile;
|
||||
int hid;
|
||||
int tid;
|
||||
int lun;
|
||||
#endif
|
||||
};
|
||||
|
||||
271
bochs/iodev/cdrom_amigaos.cc
Normal file
271
bochs/iodev/cdrom_amigaos.cc
Normal file
@ -0,0 +1,271 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// These are the low-level CDROM functions which are called
|
||||
// from 'harddrv.cc'. They effect the OS specific functionality
|
||||
// needed by the CDROM emulation in 'harddrv.cc'. Mostly, just
|
||||
// ioctl() calls and such. Should be fairly easy to add support
|
||||
// for your OS if it is not supported yet.
|
||||
|
||||
|
||||
#include "bochs.h"
|
||||
#include "scsi_commands.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
#include <exec/types.h>
|
||||
#include <exec/memory.h>
|
||||
#include <devices/trackdisk.h>
|
||||
#include <devices/scsidisk.h>
|
||||
#include <dos/dos.h>
|
||||
#include <proto/dos.h>
|
||||
#include <proto/exec.h>
|
||||
#include <clib/alib_protos.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_THIS /* no SMF tricks here, not needed */
|
||||
|
||||
#define BX_CD_FRAMESIZE 2048
|
||||
#define CD_FRAMESIZE 2048
|
||||
#define SENSELEN 32
|
||||
#define MAX_DATA_LEN 252
|
||||
|
||||
int amiga_cd_unit;
|
||||
char amiga_cd_device[256];
|
||||
|
||||
struct MsgPort *CDMP; /* Pointer for message port */
|
||||
struct IOExtTD *CDIO; /* Pointer for IORequest */
|
||||
int cd_error;
|
||||
|
||||
typedef struct {
|
||||
UBYTE pad0;
|
||||
UBYTE trackType;
|
||||
UBYTE trackNum;
|
||||
UBYTE pad1;
|
||||
ULONG startFrame;
|
||||
} TOCENTRY;
|
||||
|
||||
typedef struct {
|
||||
UWORD length;
|
||||
UBYTE firstTrack;
|
||||
UBYTE lastTrack;
|
||||
TOCENTRY tocs[100];
|
||||
} TOC;
|
||||
|
||||
typedef struct {
|
||||
ULONG sectors;
|
||||
ULONG blocksize;
|
||||
} CAPACITY;
|
||||
|
||||
unsigned char sensebuf[SENSELEN];
|
||||
|
||||
int DoSCSI (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
|
||||
|
||||
cdrom_interface::cdrom_interface(char *dev)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
sscanf(dev, "%s%s", amiga_cd_device, buf);
|
||||
amiga_cd_unit = atoi(buf);
|
||||
|
||||
CDMP = CreateMsgPort();
|
||||
if (CDMP != NULL) {
|
||||
CDIO = (struct IOExtTD *)CreateIORequest(CDMP, sizeof(struct IOExtTD));
|
||||
if (CDIO != NULL) {
|
||||
cd_error = OpenDevice(amiga_cd_device, amiga_cd_unit, (struct IORequest *)CDIO, 0);
|
||||
if (cd_error != 0)
|
||||
BX_PANIC(("CD_Open: could not open device %s unit %d\n", amiga_cd_device, amiga_cd_unit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cdrom_interface::~cdrom_interface(void)
|
||||
{
|
||||
if (cd_error == 0) {
|
||||
CloseDevice((struct IORequest *)CDIO);
|
||||
}
|
||||
if (CDIO != NULL) {
|
||||
DeleteIORequest((struct IORequest *)CDIO);
|
||||
}
|
||||
if (CDMP != NULL) {
|
||||
DeleteMsgPort(CDMP);
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::insert_cdrom(char *dev)
|
||||
{
|
||||
Bit8u cdb[6];
|
||||
Bit8u buf[2*BX_CD_FRAMESIZE];
|
||||
Bit8u i = 0;
|
||||
|
||||
memset(cdb,0,sizeof(cdb));
|
||||
|
||||
cdb[0] = SCSI_DA_START_STOP_UNIT;
|
||||
cdb[4] = 1 | 2;
|
||||
|
||||
DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ);
|
||||
|
||||
/*Check if there's a valid media present in the drive*/
|
||||
CDIO->iotd_Req.io_Data = buf;
|
||||
CDIO->iotd_Req.io_Command = CMD_READ;
|
||||
CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE;
|
||||
CDIO->iotd_Req.io_Offset = BX_CD_FRAMESIZE;
|
||||
|
||||
for(i = 0; i < 200; i++) /*it takes a while for the cdrom to validate*/
|
||||
{
|
||||
DoIO((struct IORequest *)CDIO);
|
||||
if (CDIO->iotd_Req.io_Error == 0)
|
||||
break;
|
||||
Delay (10);
|
||||
}
|
||||
|
||||
if (CDIO->iotd_Req.io_Error != 0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_interface::eject_cdrom()
|
||||
{
|
||||
Bit8u cdb[6];
|
||||
|
||||
memset(cdb,0,sizeof(cdb));
|
||||
|
||||
cdb[0] = SCSI_DA_START_STOP_UNIT;
|
||||
cdb[4] = 0 | 2;
|
||||
|
||||
DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ);
|
||||
}
|
||||
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::read_toc(Bit8u* buf, int* length, bx_bool msf, int start_track, int format)
|
||||
{
|
||||
Bit8u cdb[10];
|
||||
TOC *toc;
|
||||
toc = (TOC*) buf;
|
||||
|
||||
if (format != 0)
|
||||
return false;
|
||||
|
||||
memset(cdb,0,sizeof(cdb));
|
||||
|
||||
cdb[0] = SCSI_CD_READ_TOC;
|
||||
|
||||
if (msf)
|
||||
cdb[1] = 2;
|
||||
else
|
||||
cdb[1] = 0;
|
||||
|
||||
cdb[6] = start_track;
|
||||
cdb[7] = sizeof(TOC)>>8;
|
||||
cdb[8] = sizeof(TOC)&0xFF;
|
||||
|
||||
DoSCSI((UBYTE *)buf, sizeof(TOC), cdb, sizeof(cdb), SCSIF_READ);
|
||||
|
||||
*length = toc->length + 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Bit32u
|
||||
cdrom_interface::capacity()
|
||||
{
|
||||
CAPACITY cap;
|
||||
Bit8u cdb[10];
|
||||
|
||||
memset(cdb,0,sizeof(cdb));
|
||||
cdb[0] = SCSI_DA_READ_CAPACITY;
|
||||
|
||||
int err;
|
||||
|
||||
if ((err = DoSCSI((UBYTE *)&cap, sizeof(cap),
|
||||
cdb, sizeof (cdb),
|
||||
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
|
||||
return(cap.sectors);
|
||||
else
|
||||
BX_PANIC (("Couldn't get media capacity"));
|
||||
}
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::read_block(Bit8u* buf, int lba, int blocksize)
|
||||
{
|
||||
CDIO->iotd_Req.io_Data = buf;
|
||||
CDIO->iotd_Req.io_Command = CMD_READ;
|
||||
CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE;
|
||||
CDIO->iotd_Req.io_Offset = lba * BX_CD_FRAMESIZE;
|
||||
DoIO((struct IORequest *)CDIO);
|
||||
|
||||
if (CDIO->iotd_Req.io_Error != 0) {
|
||||
BX_PANIC(("Error %d reading CD data sector: %ld", CDIO->iotd_Req.io_Error, lba));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::start_cdrom()
|
||||
{
|
||||
// Spin up the cdrom drive.
|
||||
|
||||
if (fd >= 0) {
|
||||
BX_INFO(("start_cdrom: your OS is not supported yet."));
|
||||
return 0; // OS not supported yet, return 0 always.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int DoSCSI(UBYTE *data, int datasize, Bit8u *cmd,int cmdsize, UBYTE direction)
|
||||
{
|
||||
struct SCSICmd scmd;
|
||||
|
||||
CDIO->iotd_Req.io_Command = HD_SCSICMD;
|
||||
CDIO->iotd_Req.io_Data = &scmd;
|
||||
CDIO->iotd_Req.io_Length = sizeof(scmd);
|
||||
|
||||
scmd.scsi_Data = (UWORD *)data;
|
||||
scmd.scsi_Length = datasize;
|
||||
scmd.scsi_SenseActual = 0;
|
||||
scmd.scsi_SenseData = sensebuf;
|
||||
scmd.scsi_SenseLength = SENSELEN;
|
||||
scmd.scsi_Command = cmd;
|
||||
scmd.scsi_CmdLength = cmdsize;
|
||||
scmd.scsi_Flags = SCSIF_AUTOSENSE | direction;
|
||||
|
||||
DoIO((struct IORequest *)CDIO);
|
||||
|
||||
if (CDIO->iotd_Req.io_Error != 0) {
|
||||
BX_PANIC(("DoSCSI: error %d", CDIO->iotd_Req.io_Error));
|
||||
}
|
||||
|
||||
return CDIO->iotd_Req.io_Error;
|
||||
}
|
||||
|
||||
void cdrom_interface::seek(int lba)
|
||||
{
|
||||
unsigned char buffer[BX_CD_FRAMESIZE];
|
||||
|
||||
read_block(buffer, lba, BX_CD_FRAMESIZE);
|
||||
}
|
||||
74
bochs/iodev/cdrom_beos.cc
Normal file
74
bochs/iodev/cdrom_beos.cc
Normal file
@ -0,0 +1,74 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cdrom_beos.h"
|
||||
|
||||
int GetLogicalBlockSize(int fd)
|
||||
{
|
||||
partition_info p_info;
|
||||
|
||||
if (ioctl(fd, B_GET_PARTITION_INFO, &p_info) == B_NO_ERROR)
|
||||
{
|
||||
//dprintf("GetLogicalBlockSize: ioctl suceed\n");
|
||||
return p_info.logical_block_size;
|
||||
}
|
||||
else //dprintf("GetLogicalBlockSize = ioctl returned error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetDeviceBlockSize(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
device_geometry dg;
|
||||
|
||||
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0)
|
||||
{
|
||||
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
return 512; /* just assume it's a plain old file or something */
|
||||
}
|
||||
|
||||
return dg.bytes_per_sector;
|
||||
}
|
||||
|
||||
off_t GetNumDeviceBlocks(int fd, int block_size)
|
||||
{
|
||||
struct stat st;
|
||||
device_geometry dg;
|
||||
|
||||
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0)
|
||||
{
|
||||
return (off_t)dg.cylinder_count *
|
||||
(off_t)dg.sectors_per_track *
|
||||
(off_t)dg.head_count;
|
||||
}
|
||||
|
||||
/* if the ioctl fails, try just stat'ing in case it's a regular file */
|
||||
if (fstat(fd, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size / block_size;
|
||||
}
|
||||
33
bochs/iodev/cdrom_beos.h
Normal file
33
bochs/iodev/cdrom_beos.h
Normal file
@ -0,0 +1,33 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef CDROM_BEOS_H
|
||||
#define CDROM_BEOS_H
|
||||
|
||||
#include <stddef.h> // for off_t
|
||||
|
||||
off_t GetNumDeviceBlocks(int fd, int block_size);
|
||||
int GetLogicalBlockSize(int fd);
|
||||
int GetDeviceBlockSize(int fd);
|
||||
|
||||
#endif
|
||||
828
bochs/iodev/cmos.cc
Normal file
828
bochs/iodev/cmos.cc
Normal file
@ -0,0 +1,828 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "cmos.h"
|
||||
|
||||
#define LOG_THIS theCmosDevice->
|
||||
|
||||
bx_cmos_c *theCmosDevice = NULL;
|
||||
|
||||
// CMOS register definitions from Ralf Brown's interrupt list v6.1, in a file
|
||||
// called cmos.lst. In cases where there are multiple uses for a given
|
||||
// register in the interrupt list, I only listed the purpose that Bochs
|
||||
// actually uses it for, but I wrote "alternatives" next to it.
|
||||
#define REG_SEC 0x00
|
||||
#define REG_SEC_ALARM 0x01
|
||||
#define REG_MIN 0x02
|
||||
#define REG_MIN_ALARM 0x03
|
||||
#define REG_HOUR 0x04
|
||||
#define REG_HOUR_ALARM 0x05
|
||||
#define REG_WEEK_DAY 0x06
|
||||
#define REG_MONTH_DAY 0x07
|
||||
#define REG_MONTH 0x08
|
||||
#define REG_YEAR 0x09
|
||||
#define REG_STAT_A 0x0a
|
||||
#define REG_STAT_B 0x0b
|
||||
#define REG_STAT_C 0x0c
|
||||
#define REG_STAT_D 0x0d
|
||||
#define REG_DIAGNOSTIC_STATUS 0x0e /* alternatives */
|
||||
#define REG_SHUTDOWN_STATUS 0x0f
|
||||
#define REG_EQUIPMENT_BYTE 0x14
|
||||
#define REG_CSUM_HIGH 0x2e
|
||||
#define REG_CSUM_LOW 0x2f
|
||||
#define REG_IBM_CENTURY_BYTE 0x32 /* alternatives */
|
||||
#define REG_IBM_PS2_CENTURY_BYTE 0x37 /* alternatives */
|
||||
|
||||
// Bochs CMOS map
|
||||
//
|
||||
// Idx Len Description
|
||||
// 0x10 1 floppy drive types
|
||||
// 0x11 1 configuration bits
|
||||
// 0x12 1 harddisk types
|
||||
// 0x13 1 advanced configuration bits
|
||||
// 0x15 2 base memory in 1k
|
||||
// 0x17 2 memory size above 1M in 1k
|
||||
// 0x19 2 extended harddisk types
|
||||
// 0x1b 9 harddisk configuration (hd0)
|
||||
// 0x24 9 harddisk configuration (hd1)
|
||||
// 0x2d 1 boot sequence (fd/hd)
|
||||
// 0x30 2 memory size above 1M in 1k
|
||||
// 0x34 2 memory size above 16M in 64k
|
||||
// 0x38 1 eltorito boot sequence (#3) + bootsig check
|
||||
// 0x39 2 ata translation policy (ata0...ata3)
|
||||
// 0x3d 1 eltorito boot sequence (#1 + #2)
|
||||
//
|
||||
// Qemu CMOS map
|
||||
//
|
||||
// Idx Len Description
|
||||
// 0x5b 3 extra memory above 4GB
|
||||
// 0x5f 1 number of processors
|
||||
|
||||
|
||||
Bit8u bcd_to_bin(Bit8u value, bx_bool is_binary)
|
||||
{
|
||||
if (is_binary)
|
||||
return value;
|
||||
else
|
||||
return ((value >> 4) * 10) + (value & 0x0f);
|
||||
}
|
||||
|
||||
Bit8u bin_to_bcd(Bit8u value, bx_bool is_binary)
|
||||
{
|
||||
if (is_binary)
|
||||
return value;
|
||||
else
|
||||
return ((value / 10) << 4) | (value % 10);
|
||||
}
|
||||
|
||||
int libcmos_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theCmosDevice = new bx_cmos_c();
|
||||
bx_devices.pluginCmosDevice = theCmosDevice;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theCmosDevice, BX_PLUGIN_CMOS);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libcmos_LTX_plugin_fini(void)
|
||||
{ if (theCmosDevice != NULL)
|
||||
{ delete theCmosDevice;
|
||||
theCmosDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bx_cmos_c::bx_cmos_c(void)
|
||||
{
|
||||
put("CMOS");
|
||||
|
||||
for (unsigned i=0; i<128; i++) s.reg[i] = 0;
|
||||
|
||||
s.periodic_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
s.one_second_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
s.uip_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
bx_cmos_c::~bx_cmos_c(void)
|
||||
{
|
||||
save_image();
|
||||
char *tmptime;
|
||||
if ((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) != NULL) {
|
||||
tmptime[strlen(tmptime)-1]='\0';
|
||||
BX_INFO(("Last time is %u (%s)", (unsigned) get_timeval(), tmptime));
|
||||
free(tmptime);
|
||||
}
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_cmos_c::init(void)
|
||||
{
|
||||
BX_DEBUG(("Init $Id$"));
|
||||
// CMOS RAM & RTC
|
||||
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0070, "CMOS RAM", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0071, "CMOS RAM", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0070, "CMOS RAM", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0071, "CMOS RAM", 1);
|
||||
DEV_register_irq(8, "CMOS RTC");
|
||||
if (BX_CMOS_THIS s.periodic_timer_index == BX_NULL_TIMER_HANDLE) {
|
||||
BX_CMOS_THIS s.periodic_timer_index =
|
||||
DEV_register_timer(this, periodic_timer_handler,
|
||||
1000000, 1,0, "cmos"); // continuous, not-active
|
||||
}
|
||||
if (BX_CMOS_THIS s.one_second_timer_index == BX_NULL_TIMER_HANDLE) {
|
||||
BX_CMOS_THIS s.one_second_timer_index =
|
||||
DEV_register_timer(this, one_second_timer_handler,
|
||||
1000000, 1,0, "cmos"); // continuous, not-active
|
||||
}
|
||||
if (BX_CMOS_THIS s.uip_timer_index == BX_NULL_TIMER_HANDLE) {
|
||||
BX_CMOS_THIS s.uip_timer_index =
|
||||
DEV_register_timer(this, uip_timer_handler,
|
||||
244, 0, 0, "cmos"); // one-shot, not-active
|
||||
}
|
||||
|
||||
if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_LOCAL) {
|
||||
BX_INFO(("Using local time for initial clock"));
|
||||
BX_CMOS_THIS s.timeval = time(NULL);
|
||||
} else if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_UTC) {
|
||||
bx_bool utc_ok = 0;
|
||||
|
||||
BX_INFO(("Using utc time for initial clock"));
|
||||
|
||||
BX_CMOS_THIS s.timeval = time(NULL);
|
||||
|
||||
#if BX_HAVE_GMTIME
|
||||
#if BX_HAVE_MKTIME
|
||||
struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
|
||||
utc_holder->tm_isdst = -1;
|
||||
utc_ok = 1;
|
||||
BX_CMOS_THIS s.timeval = mktime(utc_holder);
|
||||
#elif BX_HAVE_TIMELOCAL
|
||||
struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
|
||||
utc_holder->tm_isdst = 0; // XXX Is this correct???
|
||||
utc_ok = 1;
|
||||
BX_CMOS_THIS s.timeval = timelocal(utc_holder);
|
||||
#endif //BX_HAVE_MKTIME
|
||||
#endif //BX_HAVE_GMTIME
|
||||
|
||||
if (!utc_ok) {
|
||||
BX_ERROR(("UTC time is not supported on your platform. Using current time(NULL)"));
|
||||
}
|
||||
} else {
|
||||
BX_INFO(("Using specified time for initial clock"));
|
||||
BX_CMOS_THIS s.timeval = SIM->get_param_num(BXPN_CLOCK_TIME0)->get();
|
||||
}
|
||||
|
||||
// load CMOS from image file if requested.
|
||||
if (SIM->get_param_bool(BXPN_CMOSIMAGE_ENABLED)->get()) {
|
||||
int fd, ret;
|
||||
struct stat stat_buf;
|
||||
|
||||
fd = open(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr(), O_RDONLY
|
||||
#ifdef O_BINARY
|
||||
| O_BINARY
|
||||
#endif
|
||||
);
|
||||
if (fd < 0) {
|
||||
BX_PANIC(("trying to open cmos image file '%s'",
|
||||
SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()));
|
||||
}
|
||||
ret = fstat(fd, &stat_buf);
|
||||
if (ret) {
|
||||
BX_PANIC(("CMOS: could not fstat() image file."));
|
||||
}
|
||||
if ((stat_buf.st_size != 64) && (stat_buf.st_size != 128)) {
|
||||
BX_PANIC(("CMOS: image file size must be 64 or 128"));
|
||||
}
|
||||
|
||||
ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, (unsigned)stat_buf.st_size);
|
||||
if (ret != stat_buf.st_size) {
|
||||
BX_PANIC(("CMOS: error reading cmos file."));
|
||||
}
|
||||
close(fd);
|
||||
BX_INFO(("successfuly read from image file '%s'.",
|
||||
SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()));
|
||||
BX_CMOS_THIS s.rtc_mode_12hour = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x02) == 0);
|
||||
BX_CMOS_THIS s.rtc_mode_binary = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x04) != 0);
|
||||
if (SIM->get_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->get()) {
|
||||
update_timeval();
|
||||
} else {
|
||||
update_clock();
|
||||
}
|
||||
} else {
|
||||
// CMOS values generated
|
||||
BX_CMOS_THIS s.reg[REG_STAT_A] = 0x26;
|
||||
BX_CMOS_THIS s.reg[REG_STAT_B] = 0x02;
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
|
||||
BX_CMOS_THIS s.reg[REG_STAT_D] = 0x80;
|
||||
#if BX_SUPPORT_FPU == 1
|
||||
BX_CMOS_THIS s.reg[REG_EQUIPMENT_BYTE] |= 0x02;
|
||||
#endif
|
||||
BX_CMOS_THIS s.rtc_mode_12hour = 0;
|
||||
BX_CMOS_THIS s.rtc_mode_binary = 0;
|
||||
update_clock();
|
||||
}
|
||||
|
||||
char *tmptime;
|
||||
while((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) == NULL) {
|
||||
BX_PANIC(("Out of memory."));
|
||||
}
|
||||
tmptime[strlen(tmptime)-1]='\0';
|
||||
BX_INFO(("Setting initial clock to: %s (time0=%u)", tmptime, (Bit32u)BX_CMOS_THIS s.timeval));
|
||||
free(tmptime);
|
||||
|
||||
BX_CMOS_THIS s.timeval_change = 0;
|
||||
}
|
||||
|
||||
void bx_cmos_c::reset(unsigned type)
|
||||
{
|
||||
BX_CMOS_THIS s.cmos_mem_address = 0;
|
||||
|
||||
// RESET affects the following registers:
|
||||
// CRA: no effects
|
||||
// CRB: bits 4,5,6 forced to 0
|
||||
// CRC: bits 4,5,6,7 forced to 0
|
||||
// CRD: no effects
|
||||
BX_CMOS_THIS s.reg[REG_STAT_B] &= 0x8f;
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] = 0;
|
||||
|
||||
// One second timer for updating clock & alarm functions
|
||||
bx_pc_system.activate_timer(BX_CMOS_THIS s.one_second_timer_index,
|
||||
1000000, 1);
|
||||
|
||||
// handle periodic interrupt rate select
|
||||
BX_CMOS_THIS CRA_change();
|
||||
}
|
||||
|
||||
void bx_cmos_c::save_image(void)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
// save CMOS to image file if requested.
|
||||
if (SIM->get_param_bool(BXPN_CMOSIMAGE_ENABLED)->get()) {
|
||||
fd = open(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr(), O_WRONLY
|
||||
#ifdef O_BINARY
|
||||
| O_BINARY
|
||||
#endif
|
||||
);
|
||||
ret = ::write(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, 128);
|
||||
if (ret != 128) {
|
||||
BX_PANIC(("CMOS: error writing cmos file."));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_cmos_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "cmos", "CMOS State", 2);
|
||||
BXRS_HEX_PARAM_FIELD(list, mem_address, BX_CMOS_THIS s.cmos_mem_address);
|
||||
bx_list_c *ram = new bx_list_c(list, "ram", 128);
|
||||
for (unsigned i=0; i<128; i++) {
|
||||
char name[6];
|
||||
sprintf(name, "0x%02x", i);
|
||||
new bx_shadow_num_c(ram, name, &BX_CMOS_THIS s.reg[i], BASE_HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_cmos_c::after_restore_state(void)
|
||||
{
|
||||
BX_CMOS_THIS s.rtc_mode_12hour = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x02) == 0);
|
||||
BX_CMOS_THIS s.rtc_mode_binary = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x04) != 0);
|
||||
BX_CMOS_THIS update_timeval();
|
||||
BX_CMOS_THIS CRA_change();
|
||||
}
|
||||
|
||||
void bx_cmos_c::CRA_change(void)
|
||||
{
|
||||
Bit8u nibble, dcc;
|
||||
|
||||
// Periodic Interrupt timer
|
||||
nibble = BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f;
|
||||
dcc = (BX_CMOS_THIS s.reg[REG_STAT_A] >> 4) & 0x07;
|
||||
if ((nibble == 0) || ((dcc & 0x06) == 0)) {
|
||||
// No Periodic Interrupt Rate when 0, deactivate timer
|
||||
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
|
||||
BX_CMOS_THIS s.periodic_interval_usec = (Bit32u) -1; // max value
|
||||
} else {
|
||||
// values 0001b and 0010b are the same as 1000b and 1001b
|
||||
if (nibble <= 2)
|
||||
nibble += 7;
|
||||
BX_CMOS_THIS s.periodic_interval_usec = (unsigned) (1000000.0L /
|
||||
(32768.0L / (1 << (nibble - 1))));
|
||||
|
||||
// if Periodic Interrupt Enable bit set, activate timer
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40)
|
||||
bx_pc_system.activate_timer(BX_CMOS_THIS s.periodic_timer_index,
|
||||
BX_CMOS_THIS s.periodic_interval_usec, 1);
|
||||
else
|
||||
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_cmos_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_CMOS_SMF
|
||||
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_cmos_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif
|
||||
Bit8u ret8;
|
||||
|
||||
BX_DEBUG(("CMOS read of CMOS register 0x%02x", (unsigned) BX_CMOS_THIS s.cmos_mem_address));
|
||||
|
||||
switch (address) {
|
||||
case 0x0070:
|
||||
// this register is write-only on most machines
|
||||
BX_DEBUG(("read of index port 0x70. returning 0xff"));
|
||||
return(0xff);
|
||||
case 0x0071:
|
||||
ret8 = BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address];
|
||||
// all bits of Register C are cleared after a read occurs.
|
||||
if (BX_CMOS_THIS s.cmos_mem_address == REG_STAT_C) {
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
|
||||
DEV_pic_lower_irq(8);
|
||||
}
|
||||
return(ret8);
|
||||
|
||||
default:
|
||||
BX_PANIC(("unsupported cmos read, address=0x%04x!", (unsigned) address));
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
void bx_cmos_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_CMOS_SMF
|
||||
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_cmos_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_CMOS_SMF
|
||||
|
||||
BX_DEBUG(("CMOS write to address: 0x%04x = 0x%02x", address, value));
|
||||
|
||||
switch (address) {
|
||||
case 0x0070:
|
||||
BX_CMOS_THIS s.cmos_mem_address = value & 0x7F;
|
||||
break;
|
||||
|
||||
case 0x0071:
|
||||
switch (BX_CMOS_THIS s.cmos_mem_address) {
|
||||
case REG_SEC_ALARM: // seconds alarm
|
||||
case REG_MIN_ALARM: // minutes alarm
|
||||
case REG_HOUR_ALARM: // hours alarm
|
||||
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
|
||||
BX_DEBUG(("alarm time changed to %02x:%02x:%02x", BX_CMOS_THIS s.reg[REG_HOUR_ALARM],
|
||||
BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM]));
|
||||
break;
|
||||
|
||||
case REG_SEC: // seconds
|
||||
case REG_MIN: // minutes
|
||||
case REG_HOUR: // hours
|
||||
case REG_WEEK_DAY: // day of the week
|
||||
case REG_MONTH_DAY: // day of the month
|
||||
case REG_MONTH: // month
|
||||
case REG_YEAR: // year
|
||||
case REG_IBM_CENTURY_BYTE: // century
|
||||
case REG_IBM_PS2_CENTURY_BYTE: // century (PS/2)
|
||||
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
|
||||
if (BX_CMOS_THIS s.cmos_mem_address == REG_IBM_PS2_CENTURY_BYTE) {
|
||||
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = value;
|
||||
}
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80) {
|
||||
BX_CMOS_THIS s.timeval_change = 1;
|
||||
} else {
|
||||
update_timeval();
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_STAT_A: // Control Register A
|
||||
// bit 7: Update in Progress (read-only)
|
||||
// 1 = signifies time registers will be updated within 244us
|
||||
// 0 = time registers will not occur before 244us
|
||||
// note: this bit reads 0 when CRB bit 7 is 1
|
||||
// bit 6..4: Divider Chain Control
|
||||
// 000 oscillator disabled
|
||||
// 001 oscillator disabled
|
||||
// 010 Normal operation
|
||||
// 011 TEST
|
||||
// 100 TEST
|
||||
// 101 TEST
|
||||
// 110 Divider Chain RESET
|
||||
// 111 Divider Chain RESET
|
||||
// bit 3..0: Periodic Interrupt Rate Select
|
||||
// 0000 None
|
||||
// 0001 3.90625 ms
|
||||
// 0010 7.8125 ms
|
||||
// 0011 122.070 us
|
||||
// 0100 244.141 us
|
||||
// 0101 488.281 us
|
||||
// 0110 976.562 us
|
||||
// 0111 1.953125 ms
|
||||
// 1000 3.90625 ms
|
||||
// 1001 7.8125 ms
|
||||
// 1010 15.625 ms
|
||||
// 1011 31.25 ms
|
||||
// 1100 62.5 ms
|
||||
// 1101 125 ms
|
||||
// 1110 250 ms
|
||||
// 1111 500 ms
|
||||
|
||||
unsigned dcc;
|
||||
dcc = (value >> 4) & 0x07;
|
||||
if ((dcc & 0x06) == 0x06) {
|
||||
BX_INFO(("CRA: divider chain RESET"));
|
||||
} else if (dcc > 0x02) {
|
||||
BX_PANIC(("CRA: divider chain control 0x%02x", dcc));
|
||||
}
|
||||
BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x80;
|
||||
BX_CMOS_THIS s.reg[REG_STAT_A] |= (value & 0x7f);
|
||||
BX_CMOS_THIS CRA_change();
|
||||
break;
|
||||
|
||||
case REG_STAT_B: // Control Register B
|
||||
// bit 0: Daylight Savings Enable
|
||||
// 1 = enable daylight savings
|
||||
// 0 = disable daylight savings
|
||||
// bit 1: 24/12 hour mode
|
||||
// 1 = 24 hour format
|
||||
// 0 = 12 hour format
|
||||
// bit 2: Data Mode
|
||||
// 1 = binary format
|
||||
// 0 = BCD format
|
||||
// bit 3: "square wave enable"
|
||||
// Not supported and always read as 0
|
||||
// bit 4: Update Ended Interrupt Enable
|
||||
// 1 = enable generation of update ended interrupt
|
||||
// 0 = disable
|
||||
// bit 5: Alarm Interrupt Enable
|
||||
// 1 = enable generation of alarm interrupt
|
||||
// 0 = disable
|
||||
// bit 6: Periodic Interrupt Enable
|
||||
// 1 = enable generation of periodic interrupt
|
||||
// 0 = disable
|
||||
// bit 7: Set mode
|
||||
// 1 = user copy of time is "frozen" allowing time registers
|
||||
// to be accessed without regard for an occurance of an update
|
||||
// 0 = time updates occur normally
|
||||
|
||||
if (value & 0x01)
|
||||
BX_ERROR(("write status reg B, daylight savings unsupported"));
|
||||
|
||||
value &= 0xf7; // bit3 always 0
|
||||
// Note: setting bit 7 clears bit 4
|
||||
if (value & 0x80)
|
||||
value &= 0xef;
|
||||
|
||||
unsigned prev_CRB;
|
||||
prev_CRB = BX_CMOS_THIS s.reg[REG_STAT_B];
|
||||
BX_CMOS_THIS s.reg[REG_STAT_B] = value;
|
||||
if ((prev_CRB & 0x02) != (value & 0x02)) {
|
||||
BX_CMOS_THIS s.rtc_mode_12hour = ((value & 0x02) == 0);
|
||||
update_clock();
|
||||
}
|
||||
if ((prev_CRB & 0x04) != (value & 0x04)) {
|
||||
BX_CMOS_THIS s.rtc_mode_binary = ((value & 0x04) != 0);
|
||||
update_clock();
|
||||
}
|
||||
if ((prev_CRB & 0x40) != (value & 0x40)) {
|
||||
// Periodic Interrupt Enabled changed
|
||||
if (prev_CRB & 0x40) {
|
||||
// transition from 1 to 0, deactivate timer
|
||||
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
|
||||
} else {
|
||||
// transition from 0 to 1
|
||||
// if rate select is not 0, activate timer
|
||||
if ((BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f) != 0) {
|
||||
bx_pc_system.activate_timer(
|
||||
BX_CMOS_THIS s.periodic_timer_index,
|
||||
BX_CMOS_THIS s.periodic_interval_usec, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((prev_CRB >= 0x80) && (value < 0x80) && BX_CMOS_THIS s.timeval_change) {
|
||||
update_timeval();
|
||||
BX_CMOS_THIS s.timeval_change = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_STAT_C: // Control Register C
|
||||
case REG_STAT_D: // Control Register D
|
||||
BX_ERROR(("write to control register 0x%02x ignored (read-only)",
|
||||
BX_CMOS_THIS s.cmos_mem_address));
|
||||
break;
|
||||
|
||||
case REG_DIAGNOSTIC_STATUS:
|
||||
BX_DEBUG(("write register 0x0e: 0x%02x", value));
|
||||
BX_CMOS_THIS s.reg[REG_DIAGNOSTIC_STATUS] = value;
|
||||
break;
|
||||
|
||||
case REG_SHUTDOWN_STATUS:
|
||||
switch (value) {
|
||||
case 0x00: /* proceed with normal POST (soft reset) */
|
||||
BX_DEBUG(("Reg 0Fh(00): shutdown action = normal POST"));
|
||||
break;
|
||||
case 0x01: /* shutdown after memory size check */
|
||||
BX_DEBUG(("Reg 0Fh(01): request to change shutdown action"
|
||||
" to shutdown after memory size check"));
|
||||
break;
|
||||
case 0x02: /* shutdown after successful memory test */
|
||||
BX_DEBUG(("Reg 0Fh(02): request to change shutdown action"
|
||||
" to shutdown after successful memory test"));
|
||||
break;
|
||||
case 0x03: /* shutdown after failed memory test */
|
||||
BX_DEBUG(("Reg 0Fh(03): request to change shutdown action"
|
||||
" to shutdown after successful memory test"));
|
||||
break;
|
||||
case 0x04: /* jump to disk bootstrap routine */
|
||||
BX_DEBUG(("Reg 0Fh(04): request to change shutdown action "
|
||||
"to jump to disk bootstrap routine."));
|
||||
break;
|
||||
case 0x05: /* flush keyboard (issue EOI) and jump via 40h:0067h */
|
||||
BX_DEBUG(("Reg 0Fh(05): request to change shutdown action "
|
||||
"to flush keyboard (issue EOI) and jump via 40h:0067h."));
|
||||
break;
|
||||
case 0x06:
|
||||
BX_DEBUG(("Reg 0Fh(06): Shutdown after memory test !"));
|
||||
break;
|
||||
case 0x07: /* reset (after failed test in virtual mode) */
|
||||
BX_DEBUG(("Reg 0Fh(07): request to change shutdown action "
|
||||
"to reset (after failed test in virtual mode)."));
|
||||
break;
|
||||
case 0x08: /* used by POST during protected-mode RAM test (return to POST) */
|
||||
BX_DEBUG(("Reg 0Fh(08): request to change shutdown action "
|
||||
"to return to POST (used by POST during protected-mode RAM test)."));
|
||||
break;
|
||||
case 0x09: /* return to BIOS extended memory block move
|
||||
(interrupt 15h, func 87h was in progress) */
|
||||
BX_DEBUG(("Reg 0Fh(09): request to change shutdown action "
|
||||
"to return to BIOS extended memory block move."));
|
||||
break;
|
||||
case 0x0a: /* jump to DWORD pointer at 40:67 */
|
||||
BX_DEBUG(("Reg 0Fh(0a): request to change shutdown action"
|
||||
" to jump to DWORD at 40:67"));
|
||||
break;
|
||||
case 0x0b: /* iret to DWORD pointer at 40:67 */
|
||||
BX_DEBUG(("Reg 0Fh(0b): request to change shutdown action"
|
||||
" to iret to DWORD at 40:67"));
|
||||
break;
|
||||
case 0x0c: /* retf to DWORD pointer at 40:67 */
|
||||
BX_DEBUG(("Reg 0Fh(0c): request to change shutdown action"
|
||||
" to retf to DWORD at 40:67"));
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("unsupported shutdown status: 0x%02x!", value));
|
||||
}
|
||||
BX_CMOS_THIS s.reg[REG_SHUTDOWN_STATUS] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_DEBUG(("write reg 0x%02x: value = 0x%02x",
|
||||
BX_CMOS_THIS s.cmos_mem_address, value));
|
||||
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_cmos_c::checksum_cmos(void)
|
||||
{
|
||||
Bit16u sum = 0;
|
||||
for (unsigned i=0x10; i<=0x2d; i++)
|
||||
sum += BX_CMOS_THIS s.reg[i];
|
||||
BX_CMOS_THIS s.reg[REG_CSUM_HIGH] = (sum >> 8) & 0xff; /* checksum high */
|
||||
BX_CMOS_THIS s.reg[REG_CSUM_LOW] = (sum & 0xff); /* checksum low */
|
||||
}
|
||||
|
||||
void bx_cmos_c::periodic_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
|
||||
class_ptr->periodic_timer();
|
||||
}
|
||||
|
||||
void bx_cmos_c::periodic_timer()
|
||||
{
|
||||
// if periodic interrupts are enabled, trip IRQ 8, and
|
||||
// update status register C
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40) {
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xc0; // Interrupt Request, Periodic Int
|
||||
DEV_pic_raise_irq(8);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_cmos_c::one_second_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
|
||||
class_ptr->one_second_timer();
|
||||
}
|
||||
|
||||
void bx_cmos_c::one_second_timer()
|
||||
{
|
||||
// divider chain reset - RTC stopped
|
||||
if ((BX_CMOS_THIS s.reg[REG_STAT_A] & 0x60) == 0x60)
|
||||
return;
|
||||
|
||||
// update internal time/date buffer
|
||||
BX_CMOS_THIS s.timeval++;
|
||||
|
||||
// Dont update CMOS user copy of time/date if CRB bit7 is 1
|
||||
// Nothing else do to
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80)
|
||||
return;
|
||||
|
||||
BX_CMOS_THIS s.reg[REG_STAT_A] |= 0x80; // set UIP bit
|
||||
|
||||
// UIP timer for updating clock & alarm functions
|
||||
bx_pc_system.activate_timer(BX_CMOS_THIS s.uip_timer_index, 244, 0);
|
||||
}
|
||||
|
||||
void bx_cmos_c::uip_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
|
||||
class_ptr->uip_timer();
|
||||
}
|
||||
|
||||
void bx_cmos_c::uip_timer()
|
||||
{
|
||||
update_clock();
|
||||
|
||||
// if update interrupts are enabled, trip IRQ 8, and
|
||||
// update status register C
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x10) {
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0x90; // Interrupt Request, Update Ended
|
||||
DEV_pic_raise_irq(8);
|
||||
}
|
||||
|
||||
// compare CMOS user copy of time/date to alarm time/date here
|
||||
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x20) {
|
||||
// Alarm interrupts enabled
|
||||
bx_bool alarm_match = 1;
|
||||
if ((BX_CMOS_THIS s.reg[REG_SEC_ALARM] & 0xc0) != 0xc0) {
|
||||
// seconds alarm not in dont care mode
|
||||
if (BX_CMOS_THIS s.reg[REG_SEC] != BX_CMOS_THIS s.reg[REG_SEC_ALARM])
|
||||
alarm_match = 0;
|
||||
}
|
||||
if ((BX_CMOS_THIS s.reg[REG_MIN_ALARM] & 0xc0) != 0xc0) {
|
||||
// minutes alarm not in dont care mode
|
||||
if (BX_CMOS_THIS s.reg[REG_MIN] != BX_CMOS_THIS s.reg[REG_MIN_ALARM])
|
||||
alarm_match = 0;
|
||||
}
|
||||
if ((BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0xc0) != 0xc0) {
|
||||
// hours alarm not in dont care mode
|
||||
if (BX_CMOS_THIS s.reg[REG_HOUR] != BX_CMOS_THIS s.reg[REG_HOUR_ALARM])
|
||||
alarm_match = 0;
|
||||
}
|
||||
if (alarm_match) {
|
||||
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xa0; // Interrupt Request, Alarm Int
|
||||
DEV_pic_raise_irq(8);
|
||||
}
|
||||
}
|
||||
BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x7f; // clear UIP bit
|
||||
}
|
||||
|
||||
void bx_cmos_c::update_clock()
|
||||
{
|
||||
struct tm *time_calendar;
|
||||
unsigned year, month, day, century;
|
||||
Bit8u val_bcd, hour;
|
||||
|
||||
time_calendar = localtime(& BX_CMOS_THIS s.timeval);
|
||||
|
||||
// update seconds
|
||||
BX_CMOS_THIS s.reg[REG_SEC] = bin_to_bcd(time_calendar->tm_sec,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update minutes
|
||||
BX_CMOS_THIS s.reg[REG_MIN] = bin_to_bcd(time_calendar->tm_min,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update hours
|
||||
if (BX_CMOS_THIS s.rtc_mode_12hour) {
|
||||
hour = time_calendar->tm_hour;
|
||||
val_bcd = (hour > 11) ? 0x80 : 0x00;
|
||||
if (hour > 11) hour -= 12;
|
||||
if (hour == 0) hour = 12;
|
||||
val_bcd |= bin_to_bcd(hour, BX_CMOS_THIS s.rtc_mode_binary);
|
||||
BX_CMOS_THIS s.reg[REG_HOUR] = val_bcd;
|
||||
} else {
|
||||
BX_CMOS_THIS s.reg[REG_HOUR] = bin_to_bcd(time_calendar->tm_hour,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
}
|
||||
|
||||
// update day of the week
|
||||
day = time_calendar->tm_wday + 1; // 0..6 to 1..7
|
||||
BX_CMOS_THIS s.reg[REG_WEEK_DAY] = bin_to_bcd(day,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update day of the month
|
||||
day = time_calendar->tm_mday;
|
||||
BX_CMOS_THIS s.reg[REG_MONTH_DAY] = bin_to_bcd(day,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update month
|
||||
month = time_calendar->tm_mon + 1;
|
||||
BX_CMOS_THIS s.reg[REG_MONTH] = bin_to_bcd(month,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update year
|
||||
year = time_calendar->tm_year % 100;
|
||||
BX_CMOS_THIS s.reg[REG_YEAR] = bin_to_bcd(year,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update century
|
||||
century = (time_calendar->tm_year / 100) + 19;
|
||||
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = bin_to_bcd(century,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// Raul Hudea pointed out that some bioses also use reg 0x37 for the
|
||||
// century byte. Tony Heller says this is critical in getting WinXP to run.
|
||||
BX_CMOS_THIS s.reg[REG_IBM_PS2_CENTURY_BYTE] =
|
||||
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE];
|
||||
}
|
||||
|
||||
void bx_cmos_c::update_timeval()
|
||||
{
|
||||
struct tm time_calendar;
|
||||
Bit8u val_bin, pm_flag;
|
||||
|
||||
// update seconds
|
||||
time_calendar.tm_sec = bcd_to_bin(BX_CMOS_THIS s.reg[REG_SEC],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update minutes
|
||||
time_calendar.tm_min = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MIN],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update hours
|
||||
if (BX_CMOS_THIS s.rtc_mode_12hour) {
|
||||
pm_flag = BX_CMOS_THIS s.reg[REG_HOUR] & 0x80;
|
||||
val_bin = bcd_to_bin(BX_CMOS_THIS s.reg[REG_HOUR] & 0x70,
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
if ((val_bin < 12) & (pm_flag > 0)) {
|
||||
val_bin += 12;
|
||||
} else if ((val_bin == 12) & (pm_flag == 0)) {
|
||||
val_bin = 0;
|
||||
}
|
||||
time_calendar.tm_hour = val_bin;
|
||||
} else {
|
||||
time_calendar.tm_hour = bcd_to_bin(BX_CMOS_THIS s.reg[REG_HOUR],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
}
|
||||
|
||||
// update day of the month
|
||||
time_calendar.tm_mday = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MONTH_DAY],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
|
||||
// update month
|
||||
time_calendar.tm_mon = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MONTH],
|
||||
BX_CMOS_THIS s.rtc_mode_binary) - 1;
|
||||
|
||||
// update year
|
||||
val_bin = bcd_to_bin(BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
val_bin = (val_bin - 19) * 100;
|
||||
val_bin += bcd_to_bin(BX_CMOS_THIS s.reg[REG_YEAR],
|
||||
BX_CMOS_THIS s.rtc_mode_binary);
|
||||
time_calendar.tm_year = val_bin;
|
||||
|
||||
BX_CMOS_THIS s.timeval = mktime(& time_calendar);
|
||||
}
|
||||
91
bochs/iodev/cmos.h
Normal file
91
bochs/iodev/cmos.h
Normal file
@ -0,0 +1,91 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_CMOS_H
|
||||
#define BX_IODEV_CMOS_H
|
||||
|
||||
#if BX_USE_CMOS_SMF
|
||||
# define BX_CMOS_SMF static
|
||||
# define BX_CMOS_THIS theCmosDevice->
|
||||
#else
|
||||
# define BX_CMOS_SMF
|
||||
# define BX_CMOS_THIS this->
|
||||
#endif
|
||||
|
||||
|
||||
class bx_cmos_c : public bx_cmos_stub_c {
|
||||
public:
|
||||
bx_cmos_c();
|
||||
virtual ~bx_cmos_c();
|
||||
|
||||
virtual void init(void);
|
||||
virtual void checksum_cmos(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void save_image(void);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
virtual Bit32u get_reg(unsigned reg) {
|
||||
return s.reg[reg];
|
||||
}
|
||||
virtual void set_reg(unsigned reg, Bit32u val) {
|
||||
s.reg[reg] = val;
|
||||
}
|
||||
virtual time_t get_timeval() {
|
||||
return s.timeval;
|
||||
}
|
||||
|
||||
struct {
|
||||
int periodic_timer_index;
|
||||
Bit32u periodic_interval_usec;
|
||||
int one_second_timer_index;
|
||||
int uip_timer_index;
|
||||
time_t timeval;
|
||||
Bit8u cmos_mem_address;
|
||||
bx_bool timeval_change;
|
||||
bx_bool rtc_mode_12hour;
|
||||
bx_bool rtc_mode_binary;
|
||||
|
||||
Bit8u reg[128];
|
||||
} s; // state information
|
||||
|
||||
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_CMOS_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned len);
|
||||
#endif
|
||||
|
||||
public:
|
||||
static void periodic_timer_handler(void *);
|
||||
static void one_second_timer_handler(void *);
|
||||
static void uip_timer_handler(void *);
|
||||
BX_CMOS_SMF void periodic_timer(void);
|
||||
BX_CMOS_SMF void one_second_timer(void);
|
||||
BX_CMOS_SMF void uip_timer(void);
|
||||
private:
|
||||
BX_CMOS_SMF void update_clock(void);
|
||||
BX_CMOS_SMF void update_timeval(void);
|
||||
BX_CMOS_SMF void CRA_change(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
52
bochs/iodev/crc32.cc
Normal file
52
bochs/iodev/crc32.cc
Normal file
@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/* CRC-32 calculator
|
||||
* Adapted from http://www.createwindow.org/programming/crc32/
|
||||
*/
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
CRC_Generator::CRC_Generator() {
|
||||
init();
|
||||
}
|
||||
|
||||
void CRC_Generator::init(void)
|
||||
{
|
||||
Bit32u POLYNOMIAL = 0x04c11db7;
|
||||
int i;
|
||||
|
||||
for(i = 0; i<0xFF; i++) {
|
||||
int j;
|
||||
crc32_table[i]=reflect(i,8) << 24;
|
||||
for(j=0; j<8; j++)
|
||||
crc32_table[i] = (crc32_table[i]<<1)^(crc32_table[i] & (1<<31) ? POLYNOMIAL : 0);
|
||||
crc32_table[i] = reflect(crc32_table[i], 32);
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u CRC_Generator::reflect(Bit32u ref, Bit8u ch)
|
||||
{
|
||||
Bit32u value(0);
|
||||
int i;
|
||||
|
||||
for(i=1; i<(ch+1); i++) {
|
||||
if(ref & 1)
|
||||
value |= 1 << (ch-i);
|
||||
ref >>= 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Bit32u CRC_Generator::get_CRC(Bit8u * buf, Bit32u buflen)
|
||||
{
|
||||
Bit32u ulCRC(0xFFFFFFFF);
|
||||
Bit32u len(buflen);
|
||||
Bit8u * buffer=(Bit8u *) buf;
|
||||
|
||||
while(len--)
|
||||
ulCRC=(ulCRC>>8)^crc32_table[(ulCRC & 0xFF)^*buffer++];
|
||||
return ulCRC ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
25
bochs/iodev/crc32.h
Normal file
25
bochs/iodev/crc32.h
Normal file
@ -0,0 +1,25 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/* CRC-32 calculator
|
||||
* Adapted from http://www.createwindow.org/programming/crc32/
|
||||
*/
|
||||
|
||||
#ifndef _CRC_32_H_
|
||||
#define _CRC_32_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
class CRC_Generator {
|
||||
private:
|
||||
Bit32u crc32_table[256];
|
||||
Bit32u reflect(Bit32u ref, Bit8u ch);
|
||||
public:
|
||||
void init(void);
|
||||
CRC_Generator();
|
||||
Bit32u get_CRC(Bit8u * buf, Bit32u buflen);
|
||||
};
|
||||
|
||||
#endif //_CRC_32_H_
|
||||
|
||||
1212
bochs/iodev/devices.cc
Normal file
1212
bochs/iodev/devices.cc
Normal file
File diff suppressed because it is too large
Load Diff
109
bochs/iodev/devices.txt
Executable file
109
bochs/iodev/devices.txt
Executable file
@ -0,0 +1,109 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MOTHER BOARD (i440FX Support) devices.cc
|
||||
|
|
||||
+---- 82441FX (PMC) and 82442 (DBX) emulation pci.cc
|
||||
|
|
||||
+---- 82371SB (PIIX3) PCI ISA IDE XCELERATOR
|
||||
| |
|
||||
| +---- PCI-to-ISA bridge pci2isa.cc
|
||||
| +---- PCI IDE controller pci_ide.cc
|
||||
| |
|
||||
| +---- PIIX4 ACPI support acpi.cc
|
||||
|
|
||||
+---- PCI host device mapping (Linux only) pcidev.cc
|
||||
|
|
||||
+---- Integrated peripherals
|
||||
| |
|
||||
| +---- 8259A PIC pic.cc
|
||||
| +---- 82093AA I/O APIC ioapic.cc
|
||||
| +---- 8254/82C54 Programmable Interval Timer pit_wrap.cc, pit82c54.cc
|
||||
| | |
|
||||
| | +---- PC Speaker (lowlevel) speaker.cc
|
||||
|
|
||||
| +---- 8237 DMA controller dma.cc
|
||||
| +---- 82077A Floppy Drive Controller (*) floppy.cc
|
||||
| +---- CMOS device cmos.cc
|
||||
| +---- External circuit for #FERR pin extfpuirq.cc
|
||||
| +---- Parallel ports emulation parallel.cc
|
||||
| +---- UART 16550A Serial Port serial.cc
|
||||
| | |
|
||||
| | +---- Host specific Modules serial_raw.cc
|
||||
| |
|
||||
| +---- Standard PC gameport gameport.cc
|
||||
|
|
||||
+-------------- Debugging/Instrumentation biosdev.cc, iodebug.cc, unmapped.cc
|
||||
|
||||
Attached devices
|
||||
|
|
||||
+---- PS/2 Keyboard and Mouse keyboard.cc, scancodes.cc
|
||||
|
|
||||
+---- Bus Mouse (not complete) busmouse.cc
|
||||
|
|
||||
+---- Hard Drive + ATA controller harddrv.cc
|
||||
| |
|
||||
| +---- Hard Drive image support (*) hdimage.cc
|
||||
| | |
|
||||
| | +---- Additional Modules vmware3.cc, vmware4.cc, vvfat.cc
|
||||
| |
|
||||
| +---- CD/DVD-ROM image / device access (*) cdrom.cc
|
||||
| |
|
||||
| +---- Host specific Modules cdrom_amigaos.cc, cdrom_beos.cc
|
||||
+---- Network Support
|
||||
| |
|
||||
| +---- Network Devices
|
||||
| | |
|
||||
| | +---- NE2000 (ISA/PCI) ne2k.cc, pcipnic.cc
|
||||
| | +---- PCI Pseudo NIC pcipnic.cc
|
||||
| |
|
||||
| +---- Networking Modules eth.cc
|
||||
| | |
|
||||
| | +-- Host specific Modules eth_fbsd.cc, eth_linux.cc, eth_win32.cc
|
||||
| |
|
||||
| +---- Dummy module eth_null.cc
|
||||
| +---- ARP simulator eth_arpback.cc, eth_packetmaker.cc, crc32.cc
|
||||
| +---- TAP Interface eth_tap.cc
|
||||
| +---- TUN/TAP Interface eth_tuntap.cc
|
||||
| +---- VDE Interface eth_vde.cc
|
||||
| +---- virtual Ethernet locator eth_vnet.cc
|
||||
|
|
||||
+---- Graphics
|
||||
| |
|
||||
| +---- VGA, PCI VGA adapter vga.cc, pci_vga.cc
|
||||
| +---- Cirrus Logic PCI/ISA CLGD5446 SVGA adapter svga_cirrus.cc
|
||||
|
|
||||
+---- Sound support
|
||||
| |
|
||||
| +---- Sound Blaster SB16 sb16.cc
|
||||
| | |
|
||||
| | +-- Dummy / Control Module soundmod.cc
|
||||
| |
|
||||
| +---- Host specific Modules soundlnx.cc, soundosx.cc, soundwin.cc
|
||||
|
|
||||
+---- PCI USB adapter usb_common.cc
|
||||
|
|
||||
+---- Host Controllers
|
||||
| |
|
||||
| +---- USB OHCI adapter usb_ohci.cc
|
||||
| +---- USB UHCI adapter (PIIX3) usb_uhci.cc
|
||||
|
|
||||
+---- Attached USB devices
|
||||
| |
|
||||
| +-- Control Module usb_common.cc
|
||||
|
|
||||
+---- USB HID emulation usb_hid.cc
|
||||
+---- USB external HUB usb_hub.cc
|
||||
+---- USB mass storage device (*) usb_msd.cc, scsi_device.cc
|
||||
+---- USB HP DeskJet 920C printer usb_printer.cc
|
||||
|
||||
(*) USB MSD uses hdimage code and cdrom.cc for image / device access
|
||||
Floppy uses hdimage code for VVFAT support
|
||||
|
||||
BOCHS timer sycronisation modules
|
||||
|
|
||||
+---- Slowdown timer slowdown_timer.cc
|
||||
+---- Virtual timer virt_timer.cc
|
||||
|
||||
TODO:
|
||||
812
bochs/iodev/dma.cc
Normal file
812
bochs/iodev/dma.cc
Normal file
@ -0,0 +1,812 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "dma.h"
|
||||
|
||||
#define LOG_THIS theDmaDevice->
|
||||
|
||||
#define DMA_MODE_DEMAND 0
|
||||
#define DMA_MODE_SINGLE 1
|
||||
#define DMA_MODE_BLOCK 2
|
||||
#define DMA_MODE_CASCADE 3
|
||||
|
||||
bx_dma_c *theDmaDevice = NULL;
|
||||
|
||||
int libdma_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theDmaDevice = new bx_dma_c ();
|
||||
bx_devices.pluginDmaDevice = theDmaDevice;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theDmaDevice, BX_PLUGIN_DMA);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libdma_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theDmaDevice;
|
||||
}
|
||||
|
||||
bx_dma_c::bx_dma_c()
|
||||
{
|
||||
put("DMA");
|
||||
}
|
||||
|
||||
bx_dma_c::~bx_dma_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
unsigned bx_dma_c::registerDMA8Channel(unsigned channel,
|
||||
void (* dmaRead)(Bit8u *data_byte),
|
||||
void (* dmaWrite)(Bit8u *data_byte),
|
||||
const char *name)
|
||||
{
|
||||
if (channel > 3) {
|
||||
BX_PANIC(("registerDMA8Channel: invalid channel number(%u).", channel));
|
||||
return 0; // Fail
|
||||
}
|
||||
if (BX_DMA_THIS s[0].chan[channel].used) {
|
||||
BX_PANIC(("registerDMA8Channel: channel(%u) already in use.", channel));
|
||||
return 0; // Fail
|
||||
}
|
||||
BX_INFO(("channel %u used by %s", channel, name));
|
||||
BX_DMA_THIS h[channel].dmaRead8 = dmaRead;
|
||||
BX_DMA_THIS h[channel].dmaWrite8 = dmaWrite;
|
||||
BX_DMA_THIS s[0].chan[channel].used = 1;
|
||||
return 1; // OK
|
||||
}
|
||||
|
||||
unsigned bx_dma_c::registerDMA16Channel(unsigned channel,
|
||||
void (* dmaRead)(Bit16u *data_word),
|
||||
void (* dmaWrite)(Bit16u *data_word),
|
||||
const char *name)
|
||||
{
|
||||
if ((channel < 4) || (channel > 7)) {
|
||||
BX_PANIC(("registerDMA16Channel: invalid channel number(%u).", channel));
|
||||
return 0; // Fail
|
||||
}
|
||||
if (BX_DMA_THIS s[1].chan[channel & 0x03].used) {
|
||||
BX_PANIC(("registerDMA16Channel: channel(%u) already in use.", channel));
|
||||
return 0; // Fail
|
||||
}
|
||||
BX_INFO(("channel %u used by %s", channel, name));
|
||||
channel &= 0x03;
|
||||
BX_DMA_THIS h[channel].dmaRead16 = dmaRead;
|
||||
BX_DMA_THIS h[channel].dmaWrite16 = dmaWrite;
|
||||
BX_DMA_THIS s[1].chan[channel].used = 1;
|
||||
return 1; // OK
|
||||
}
|
||||
|
||||
unsigned bx_dma_c::unregisterDMAChannel(unsigned channel)
|
||||
{
|
||||
bx_bool ma_sl = (channel > 3);
|
||||
BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used = 0;
|
||||
BX_INFO(("channel %u no longer used", channel));
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned bx_dma_c::get_TC(void)
|
||||
{
|
||||
return BX_DMA_THIS TC;
|
||||
}
|
||||
|
||||
void bx_dma_c::init(void)
|
||||
{
|
||||
unsigned c, i, j;
|
||||
BX_DEBUG(("Init $Id$"));
|
||||
|
||||
/* 8237 DMA controller */
|
||||
|
||||
for (i=0; i < 2; i++) {
|
||||
for (j=0; j < 4; j++) {
|
||||
BX_DMA_THIS s[i].DRQ[j] = 0;
|
||||
BX_DMA_THIS s[i].DACK[j] = 0;
|
||||
}
|
||||
}
|
||||
BX_DMA_THIS HLDA = 0;
|
||||
BX_DMA_THIS TC = 0;
|
||||
|
||||
// 0000..000F
|
||||
for (i=0x0000; i<=0x000F; i++) {
|
||||
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
|
||||
}
|
||||
|
||||
// 00080..008F
|
||||
for (i=0x0080; i<=0x008F; i++) {
|
||||
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
|
||||
}
|
||||
|
||||
// 000C0..00DE
|
||||
for (i=0x00C0; i<=0x00DE; i+=2) {
|
||||
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
|
||||
}
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
for (c=0; c<4; c++) {
|
||||
BX_DMA_THIS s[i].chan[c].mode.mode_type = 0; // demand mode
|
||||
BX_DMA_THIS s[i].chan[c].mode.address_decrement = 0; // address increment
|
||||
BX_DMA_THIS s[i].chan[c].mode.autoinit_enable = 0; // autoinit disable
|
||||
BX_DMA_THIS s[i].chan[c].mode.transfer_type = 0; // verify
|
||||
BX_DMA_THIS s[i].chan[c].base_address = 0;
|
||||
BX_DMA_THIS s[i].chan[c].current_address = 0;
|
||||
BX_DMA_THIS s[i].chan[c].base_count = 0;
|
||||
BX_DMA_THIS s[i].chan[c].current_count = 0;
|
||||
BX_DMA_THIS s[i].chan[c].page_reg = 0;
|
||||
BX_DMA_THIS s[i].chan[c].used = 0;
|
||||
}
|
||||
}
|
||||
memset(&BX_DMA_THIS ext_page_reg[0], 0, 16);
|
||||
BX_DMA_THIS s[1].chan[0].used = 1; // cascade channel in use
|
||||
BX_INFO(("channel 4 used by cascade"));
|
||||
}
|
||||
|
||||
void bx_dma_c::reset(unsigned type)
|
||||
{
|
||||
reset_controller(0);
|
||||
reset_controller(1);
|
||||
}
|
||||
|
||||
void bx_dma_c::reset_controller(unsigned num)
|
||||
{
|
||||
BX_DMA_THIS s[num].mask[0] = 1;
|
||||
BX_DMA_THIS s[num].mask[1] = 1;
|
||||
BX_DMA_THIS s[num].mask[2] = 1;
|
||||
BX_DMA_THIS s[num].mask[3] = 1;
|
||||
BX_DMA_THIS s[num].ctrl_disabled = 0;
|
||||
BX_DMA_THIS s[num].command_reg = 0;
|
||||
BX_DMA_THIS s[num].status_reg = 0;
|
||||
BX_DMA_THIS s[num].flip_flop = 0;
|
||||
}
|
||||
|
||||
void bx_dma_c::register_state(void)
|
||||
{
|
||||
unsigned i, c;
|
||||
char name[6];
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "dma", "DMA State", 3);
|
||||
for (i=0; i<2; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
bx_list_c *ctrl = new bx_list_c(list, name, 8);
|
||||
BXRS_PARAM_BOOL(ctrl, flip_flop, BX_DMA_THIS s[i].flip_flop);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, status_reg, BX_DMA_THIS s[i].status_reg);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, command_reg, BX_DMA_THIS s[i].command_reg);
|
||||
BXRS_PARAM_BOOL(ctrl, ctrl_disabled, BX_DMA_THIS s[i].ctrl_disabled);
|
||||
for (c=0; c<4; c++) {
|
||||
sprintf(name, "%d", c);
|
||||
bx_list_c *chan = new bx_list_c(ctrl, name, 12);
|
||||
BXRS_PARAM_BOOL(chan, DRQ, BX_DMA_THIS s[i].DRQ[c]);
|
||||
BXRS_PARAM_BOOL(chan, DACK, BX_DMA_THIS s[i].DACK[c]);
|
||||
BXRS_PARAM_BOOL(chan, mask, BX_DMA_THIS s[i].mask[c]);
|
||||
BXRS_DEC_PARAM_FIELD(chan, mode_type, BX_DMA_THIS s[i].chan[c].mode.mode_type);
|
||||
BXRS_DEC_PARAM_FIELD(chan, address_decrement, BX_DMA_THIS s[i].chan[c].mode.address_decrement);
|
||||
BXRS_DEC_PARAM_FIELD(chan, autoinit_enable, BX_DMA_THIS s[i].chan[c].mode.autoinit_enable);
|
||||
BXRS_DEC_PARAM_FIELD(chan, transfer_type, BX_DMA_THIS s[i].chan[c].mode.transfer_type);
|
||||
BXRS_HEX_PARAM_FIELD(chan, base_address, BX_DMA_THIS s[i].chan[c].base_address);
|
||||
BXRS_HEX_PARAM_FIELD(chan, current_address, BX_DMA_THIS s[i].chan[c].current_address);
|
||||
BXRS_HEX_PARAM_FIELD(chan, base_count, BX_DMA_THIS s[i].chan[c].base_count);
|
||||
BXRS_HEX_PARAM_FIELD(chan, current_count, BX_DMA_THIS s[i].chan[c].current_count);
|
||||
BXRS_HEX_PARAM_FIELD(chan, page_reg, BX_DMA_THIS s[i].chan[c].page_reg);
|
||||
}
|
||||
}
|
||||
bx_list_c *extpg = new bx_list_c(list, "ext_page", 16);
|
||||
for (i=0; i<16; i++) {
|
||||
sprintf(name, "0x%02x", 0x80+i);
|
||||
new bx_shadow_num_c(extpg, name, &BX_DMA_THIS ext_page_reg[i], BASE_HEX);
|
||||
}
|
||||
}
|
||||
|
||||
// index to find channel from register number (only [0],[1],[2],[6] used)
|
||||
Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0};
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
Bit32u bx_dma_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_DMA_SMF
|
||||
bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
/* 8237 DMA controller */
|
||||
Bit32u BX_CPP_AttrRegparmN(2)
|
||||
bx_dma_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_DMA_SMF
|
||||
|
||||
Bit8u retval;
|
||||
Bit8u channel;
|
||||
|
||||
BX_DEBUG(("read addr=%04x", (unsigned) address));
|
||||
|
||||
#if BX_DMA_FLOPPY_IO < 1
|
||||
/* if we're not supporting DMA/floppy IO just return a bogus value */
|
||||
return(0xff);
|
||||
#endif
|
||||
|
||||
bx_bool ma_sl = (address >= 0xc0);
|
||||
|
||||
switch (address) {
|
||||
case 0x00: /* DMA-1 current address, channel 0 */
|
||||
case 0x02: /* DMA-1 current address, channel 1 */
|
||||
case 0x04: /* DMA-1 current address, channel 2 */
|
||||
case 0x06: /* DMA-1 current address, channel 3 */
|
||||
case 0xc0: /* DMA-2 current address, channel 0 */
|
||||
case 0xc4: /* DMA-2 current address, channel 1 */
|
||||
case 0xc8: /* DMA-2 current address, channel 2 */
|
||||
case 0xcc: /* DMA-2 current address, channel 3 */
|
||||
channel = (address >> (1 + ma_sl)) & 0x03;
|
||||
if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
return (BX_DMA_THIS s[ma_sl].chan[channel].current_address & 0xff);
|
||||
} else {
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
return (BX_DMA_THIS s[ma_sl].chan[channel].current_address >> 8);
|
||||
}
|
||||
|
||||
case 0x01: /* DMA-1 current count, channel 0 */
|
||||
case 0x03: /* DMA-1 current count, channel 1 */
|
||||
case 0x05: /* DMA-1 current count, channel 2 */
|
||||
case 0x07: /* DMA-1 current count, channel 3 */
|
||||
case 0xc2: /* DMA-2 current count, channel 0 */
|
||||
case 0xc6: /* DMA-2 current count, channel 1 */
|
||||
case 0xca: /* DMA-2 current count, channel 2 */
|
||||
case 0xce: /* DMA-2 current count, channel 3 */
|
||||
channel = (address >> (1 + ma_sl)) & 0x03;
|
||||
if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
return (BX_DMA_THIS s[ma_sl].chan[channel].current_count & 0xff);
|
||||
} else {
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
return (BX_DMA_THIS s[ma_sl].chan[channel].current_count >> 8);
|
||||
}
|
||||
|
||||
case 0x08: // DMA-1 Status Register
|
||||
case 0xd0: // DMA-2 Status Register
|
||||
// bit 7: 1 = channel 3 request
|
||||
// bit 6: 1 = channel 2 request
|
||||
// bit 5: 1 = channel 1 request
|
||||
// bit 4: 1 = channel 0 request
|
||||
// bit 3: 1 = channel 3 has reached terminal count
|
||||
// bit 2: 1 = channel 2 has reached terminal count
|
||||
// bit 1: 1 = channel 1 has reached terminal count
|
||||
// bit 0: 1 = channel 0 has reached terminal count
|
||||
// reading this register clears lower 4 bits (hold flags)
|
||||
retval = BX_DMA_THIS s[ma_sl].status_reg;
|
||||
BX_DMA_THIS s[ma_sl].status_reg &= 0xf0;
|
||||
return retval;
|
||||
|
||||
case 0x0d: // DMA-1: temporary register
|
||||
case 0xda: // DMA-2: temporary register
|
||||
// only used for memory-to-memory transfers
|
||||
// write to 0x0d / 0xda clears temporary register
|
||||
BX_ERROR(("DMA-%d: read of temporary register always returns 0", ma_sl+1));
|
||||
return 0;
|
||||
|
||||
case 0x0081: // DMA-1 page register, channel 2
|
||||
case 0x0082: // DMA-1 page register, channel 3
|
||||
case 0x0083: // DMA-1 page register, channel 1
|
||||
case 0x0087: // DMA-1 page register, channel 0
|
||||
channel = channelindex[address - 0x81];
|
||||
return BX_DMA_THIS s[0].chan[channel].page_reg;
|
||||
|
||||
case 0x0089: // DMA-2 page register, channel 2
|
||||
case 0x008a: // DMA-2 page register, channel 3
|
||||
case 0x008b: // DMA-2 page register, channel 1
|
||||
case 0x008f: // DMA-2 page register, channel 0
|
||||
channel = channelindex[address - 0x89];
|
||||
return BX_DMA_THIS s[1].chan[channel].page_reg;
|
||||
|
||||
case 0x0080:
|
||||
case 0x0084:
|
||||
case 0x0085:
|
||||
case 0x0086:
|
||||
case 0x0088:
|
||||
case 0x008c:
|
||||
case 0x008d:
|
||||
case 0x008e:
|
||||
BX_DEBUG(("read: extra page register 0x%04x (unused)", (unsigned) address));
|
||||
return BX_DMA_THIS ext_page_reg[address & 0x0f];
|
||||
|
||||
case 0x0f: // DMA-1: undocumented: read all mask bits
|
||||
case 0xde: // DMA-2: undocumented: read all mask bits
|
||||
retval = BX_DMA_THIS s[ma_sl].mask[0] |
|
||||
(BX_DMA_THIS s[ma_sl].mask[1] << 1) |
|
||||
(BX_DMA_THIS s[ma_sl].mask[2] << 2) |
|
||||
(BX_DMA_THIS s[ma_sl].mask[3] << 3);
|
||||
return (0xf0 | retval);
|
||||
|
||||
default:
|
||||
BX_ERROR(("read: unsupported address=%04x", (unsigned) address));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_dma_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_DMA_SMF
|
||||
bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
|
||||
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
|
||||
/* 8237 DMA controller */
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
bx_dma_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_DMA_SMF
|
||||
Bit8u set_mask_bit;
|
||||
Bit8u channel;
|
||||
|
||||
if (io_len > 1) {
|
||||
if ((io_len == 2) && (address == 0x0b)) {
|
||||
#if BX_USE_DMA_SMF
|
||||
BX_DMA_THIS write_handler(NULL, address, value & 0xff, 1);
|
||||
BX_DMA_THIS write_handler(NULL, address+1, value >> 8, 1);
|
||||
#else
|
||||
BX_DMA_THIS write(address, value & 0xff, 1);
|
||||
BX_DMA_THIS write(address+1, value >> 8, 1);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
BX_ERROR(("io write to address %08x, len=%u",
|
||||
(unsigned) address, (unsigned) io_len));
|
||||
return;
|
||||
}
|
||||
|
||||
BX_DEBUG(("write: address=%04x value=%02x",
|
||||
(unsigned) address, (unsigned) value));
|
||||
|
||||
#if BX_DMA_FLOPPY_IO < 1
|
||||
/* if we're not supporting DMA/floppy IO just return */
|
||||
return;
|
||||
#endif
|
||||
|
||||
bx_bool ma_sl = (address >= 0xc0);
|
||||
|
||||
switch (address) {
|
||||
case 0x00:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x06:
|
||||
case 0xc0:
|
||||
case 0xc4:
|
||||
case 0xc8:
|
||||
case 0xcc:
|
||||
channel = (address >> (1 + ma_sl)) & 0x03;
|
||||
BX_DEBUG((" DMA-%d base and current address, channel %d", ma_sl+1, channel));
|
||||
if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_address = value;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_address = value;
|
||||
} else { /* 2nd byte */
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_address |= (value << 8);
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_address |= (value << 8);
|
||||
BX_DEBUG((" base = %04x",
|
||||
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_address));
|
||||
BX_DEBUG((" curr = %04x",
|
||||
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_address));
|
||||
}
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
case 0x05:
|
||||
case 0x07:
|
||||
case 0xc2:
|
||||
case 0xc6:
|
||||
case 0xca:
|
||||
case 0xce:
|
||||
channel = (address >> (1 + ma_sl)) & 0x03;
|
||||
BX_DEBUG((" DMA-%d base and current count, channel %d", ma_sl+1, channel));
|
||||
if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_count = value;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_count = value;
|
||||
} else { /* 2nd byte */
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_count |= (value << 8);
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_count |= (value << 8);
|
||||
BX_DEBUG((" base = %04x",
|
||||
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
|
||||
BX_DEBUG((" curr = %04x",
|
||||
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_count));
|
||||
}
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
|
||||
break;
|
||||
|
||||
case 0x08: /* DMA-1: command register */
|
||||
case 0xd0: /* DMA-2: command register */
|
||||
if ((value & 0xfb) != 0x00)
|
||||
BX_ERROR(("write to command register: value 0x%02x not supported",
|
||||
(unsigned) value));
|
||||
BX_DMA_THIS s[ma_sl].command_reg = value;
|
||||
BX_DMA_THIS s[ma_sl].ctrl_disabled = (value >> 2) & 0x01;
|
||||
control_HRQ(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x09: // DMA-1: request register
|
||||
case 0xd2: // DMA-2: request register
|
||||
channel = value & 0x03;
|
||||
// note: write to 0x0d / 0xda clears this register
|
||||
if (value & 0x04) {
|
||||
// set request bit
|
||||
BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
|
||||
BX_DEBUG(("DMA-%d: set request bit for channel %u", ma_sl+1, (unsigned) channel));
|
||||
} else {
|
||||
// clear request bit
|
||||
BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
|
||||
BX_DEBUG(("DMA-%d: cleared request bit for channel %u", ma_sl+1, (unsigned) channel));
|
||||
}
|
||||
control_HRQ(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
case 0xd4:
|
||||
set_mask_bit = value & 0x04;
|
||||
channel = value & 0x03;
|
||||
BX_DMA_THIS s[ma_sl].mask[channel] = (set_mask_bit > 0);
|
||||
BX_DEBUG(("DMA-%d: set_mask_bit=%u, channel=%u, mask now=%02xh", ma_sl+1,
|
||||
(unsigned) set_mask_bit, (unsigned) channel, (unsigned) BX_DMA_THIS s[ma_sl].mask[channel]));
|
||||
control_HRQ(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x0b: /* DMA-1 mode register */
|
||||
case 0xd6: /* DMA-2 mode register */
|
||||
channel = value & 0x03;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type = (value >> 6) & 0x03;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement = (value >> 5) & 0x01;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable = (value >> 4) & 0x01;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type = (value >> 2) & 0x03;
|
||||
BX_DEBUG(("DMA-%d: mode register[%u] = %02x", ma_sl+1,
|
||||
(unsigned) channel, (unsigned) value));
|
||||
break;
|
||||
|
||||
case 0x0c: /* DMA-1 clear byte flip/flop */
|
||||
case 0xd8: /* DMA-2 clear byte flip/flop */
|
||||
BX_DEBUG(("DMA-%d: clear flip/flop", ma_sl+1));
|
||||
BX_DMA_THIS s[ma_sl].flip_flop = 0;
|
||||
break;
|
||||
|
||||
case 0x0d: // DMA-1: master clear
|
||||
case 0xda: // DMA-2: master clear
|
||||
BX_DEBUG(("DMA-%d: master clear", ma_sl+1));
|
||||
// writing any value to this port resets DMA controller 1 / 2
|
||||
// same action as a hardware reset
|
||||
// mask register is set (chan 0..3 disabled)
|
||||
// command, status, request, temporary, and byte flip-flop are all cleared
|
||||
reset_controller(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x0e: // DMA-1: clear mask register
|
||||
case 0xdc: // DMA-2: clear mask register
|
||||
BX_DEBUG(("DMA-%d: clear mask register", ma_sl+1));
|
||||
BX_DMA_THIS s[ma_sl].mask[0] = 0;
|
||||
BX_DMA_THIS s[ma_sl].mask[1] = 0;
|
||||
BX_DMA_THIS s[ma_sl].mask[2] = 0;
|
||||
BX_DMA_THIS s[ma_sl].mask[3] = 0;
|
||||
control_HRQ(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x0f: // DMA-1: write all mask bits
|
||||
case 0xde: // DMA-2: write all mask bits
|
||||
BX_DEBUG(("DMA-%d: write all mask bits", ma_sl+1));
|
||||
BX_DMA_THIS s[ma_sl].mask[0] = value & 0x01; value >>= 1;
|
||||
BX_DMA_THIS s[ma_sl].mask[1] = value & 0x01; value >>= 1;
|
||||
BX_DMA_THIS s[ma_sl].mask[2] = value & 0x01; value >>= 1;
|
||||
BX_DMA_THIS s[ma_sl].mask[3] = value & 0x01;
|
||||
control_HRQ(ma_sl);
|
||||
break;
|
||||
|
||||
case 0x81: /* DMA-1 page register, channel 2 */
|
||||
case 0x82: /* DMA-1 page register, channel 3 */
|
||||
case 0x83: /* DMA-1 page register, channel 1 */
|
||||
case 0x87: /* DMA-1 page register, channel 0 */
|
||||
/* address bits A16-A23 for DMA channel */
|
||||
channel = channelindex[address - 0x81];
|
||||
BX_DMA_THIS s[0].chan[channel].page_reg = value;
|
||||
BX_DEBUG(("DMA-1: page register %d = %02x", channel, (unsigned) value));
|
||||
break;
|
||||
|
||||
case 0x89: /* DMA-2 page register, channel 2 */
|
||||
case 0x8a: /* DMA-2 page register, channel 3 */
|
||||
case 0x8b: /* DMA-2 page register, channel 1 */
|
||||
case 0x8f: /* DMA-2 page register, channel 0 */
|
||||
/* address bits A16-A23 for DMA channel */
|
||||
channel = channelindex[address - 0x89];
|
||||
BX_DMA_THIS s[1].chan[channel].page_reg = value;
|
||||
BX_DEBUG(("DMA-2: page register %d = %02x", channel + 4, (unsigned) value));
|
||||
break;
|
||||
|
||||
case 0x0080:
|
||||
case 0x0084:
|
||||
case 0x0085:
|
||||
case 0x0086:
|
||||
case 0x0088:
|
||||
case 0x008c:
|
||||
case 0x008d:
|
||||
case 0x008e:
|
||||
BX_DEBUG(("write: extra page register 0x%04x (unused)", (unsigned) address));
|
||||
BX_DMA_THIS ext_page_reg[address & 0x0f] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("write ignored: %04xh = %02xh",
|
||||
(unsigned) address, (unsigned) value));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_dma_c::set_DRQ(unsigned channel, bx_bool val)
|
||||
{
|
||||
Bit32u dma_base, dma_roof;
|
||||
bx_bool ma_sl;
|
||||
|
||||
if (channel > 7) {
|
||||
BX_PANIC(("set_DRQ() channel > 7"));
|
||||
return;
|
||||
}
|
||||
ma_sl = (channel > 3);
|
||||
BX_DMA_THIS s[ma_sl].DRQ[channel & 0x03] = val;
|
||||
if (!BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used) {
|
||||
BX_PANIC(("set_DRQ(): channel %d not connected to device", channel));
|
||||
return;
|
||||
}
|
||||
channel &= 0x03;
|
||||
if (!val) {
|
||||
//BX_DEBUG(("bx_dma_c::DRQ(): val == 0"));
|
||||
// clear bit in status reg
|
||||
BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
|
||||
|
||||
control_HRQ(ma_sl);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
BX_INFO(("mask[%d]: %02x", channel, (unsigned) BX_DMA_THIS s[0].mask[channel]));
|
||||
BX_INFO(("flip_flop: %u", (unsigned) BX_DMA_THIS s[0].flip_flop));
|
||||
BX_INFO(("status_reg: %02x", (unsigned) BX_DMA_THIS s[0].status_reg));
|
||||
BX_INFO(("mode_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.mode_type));
|
||||
BX_INFO(("address_decrement: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.address_decrement));
|
||||
BX_INFO(("autoinit_enable: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.autoinit_enable));
|
||||
BX_INFO(("transfer_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.transfer_type));
|
||||
BX_INFO(("base_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_address));
|
||||
BX_INFO(("current_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_address));
|
||||
BX_INFO(("base_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_count));
|
||||
BX_INFO(("current_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_count));
|
||||
BX_INFO(("page_reg: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].page_reg));
|
||||
#endif
|
||||
|
||||
BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
|
||||
|
||||
if ((BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_SINGLE) &&
|
||||
(BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_DEMAND) &&
|
||||
(BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_CASCADE))
|
||||
{
|
||||
BX_PANIC(("set_DRQ: mode_type(%02x) not handled",
|
||||
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type));
|
||||
}
|
||||
|
||||
dma_base = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
|
||||
(BX_DMA_THIS s[ma_sl].chan[channel].base_address << ma_sl);
|
||||
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0) {
|
||||
dma_roof = dma_base + (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
|
||||
} else {
|
||||
dma_roof = dma_base - (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
|
||||
}
|
||||
if ((dma_base & (0x7fff0000 << ma_sl)) != (dma_roof & (0x7fff0000 << ma_sl))) {
|
||||
BX_INFO(("dma_base = %08x", (unsigned) dma_base));
|
||||
BX_INFO(("dma_base_count = %08x", (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
|
||||
BX_INFO(("dma_roof = %08x", (unsigned) dma_roof));
|
||||
BX_PANIC(("request outside %dk boundary", 64 << ma_sl));
|
||||
}
|
||||
|
||||
control_HRQ(ma_sl);
|
||||
}
|
||||
|
||||
void bx_dma_c::control_HRQ(bx_bool ma_sl)
|
||||
{
|
||||
unsigned channel;
|
||||
|
||||
// do nothing if controller is disabled
|
||||
if (BX_DMA_THIS s[ma_sl].ctrl_disabled)
|
||||
return;
|
||||
|
||||
// deassert HRQ if no DRQ is pending
|
||||
if ((BX_DMA_THIS s[ma_sl].status_reg & 0xf0) == 0) {
|
||||
if (ma_sl) {
|
||||
bx_pc_system.set_HRQ(0);
|
||||
} else {
|
||||
BX_DMA_THIS set_DRQ(4, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// find highest priority channel
|
||||
for (channel=0; channel<4; channel++) {
|
||||
if ((BX_DMA_THIS s[ma_sl].status_reg & (1 << (channel+4))) &&
|
||||
(BX_DMA_THIS s[ma_sl].mask[channel]==0)) {
|
||||
if (ma_sl) {
|
||||
// assert Hold ReQuest line to CPU
|
||||
bx_pc_system.set_HRQ(1);
|
||||
} else {
|
||||
// send DRQ to cascade channel of the master
|
||||
BX_DMA_THIS set_DRQ(4, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_dma_c::raise_HLDA(void)
|
||||
{
|
||||
unsigned channel;
|
||||
bx_phy_address phy_addr;
|
||||
bx_bool count_expired = 0;
|
||||
bx_bool ma_sl = 0;
|
||||
|
||||
BX_DMA_THIS HLDA = 1;
|
||||
// find highest priority channel
|
||||
for (channel=0; channel<4; channel++) {
|
||||
if ((BX_DMA_THIS s[1].status_reg & (1 << (channel+4))) &&
|
||||
(BX_DMA_THIS s[1].mask[channel]==0)) {
|
||||
ma_sl = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channel == 0) { // master cascade channel
|
||||
BX_DMA_THIS s[1].DACK[0] = 1;
|
||||
for (channel=0; channel<4; channel++) {
|
||||
if ((BX_DMA_THIS s[0].status_reg & (1 << (channel+4))) &&
|
||||
(BX_DMA_THIS s[0].mask[channel]==0)) {
|
||||
ma_sl = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channel >= 4) {
|
||||
// wait till they're unmasked
|
||||
return;
|
||||
}
|
||||
|
||||
//BX_DEBUG(("hlda: OK in response to DRQ(%u)", (unsigned) channel));
|
||||
phy_addr = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
|
||||
(BX_DMA_THIS s[ma_sl].chan[channel].current_address << ma_sl);
|
||||
|
||||
BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
|
||||
// check for expiration of count, so we can signal TC and DACK(n)
|
||||
// at the same time.
|
||||
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0)
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_address++;
|
||||
else
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_count--;
|
||||
if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
|
||||
// count expired, done with transfer
|
||||
// assert TC, deassert HRQ & DACK(n) lines
|
||||
BX_DMA_THIS s[ma_sl].status_reg |= (1 << channel); // hold TC in status reg
|
||||
BX_DMA_THIS TC = 1;
|
||||
count_expired = 1;
|
||||
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable == 0) {
|
||||
// set mask bit if not in autoinit mode
|
||||
BX_DMA_THIS s[ma_sl].mask[channel] = 1;
|
||||
}
|
||||
else {
|
||||
// count expired, but in autoinit mode
|
||||
// reload count and base address
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_address =
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_address;
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].current_count =
|
||||
BX_DMA_THIS s[ma_sl].chan[channel].base_count;
|
||||
}
|
||||
}
|
||||
|
||||
Bit8u data_byte;
|
||||
Bit16u data_word;
|
||||
|
||||
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 1) { // write
|
||||
// DMA controlled xfer of byte from I/O to Memory
|
||||
|
||||
if (!ma_sl) {
|
||||
if (BX_DMA_THIS h[channel].dmaWrite8)
|
||||
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
|
||||
else
|
||||
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
|
||||
|
||||
DEV_MEM_WRITE_PHYSICAL(phy_addr, 1, &data_byte);
|
||||
|
||||
BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte);
|
||||
}
|
||||
else {
|
||||
if (BX_DMA_THIS h[channel].dmaWrite16)
|
||||
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
|
||||
else
|
||||
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
|
||||
|
||||
DEV_MEM_WRITE_PHYSICAL(phy_addr, 2, (Bit8u*) &data_word);
|
||||
|
||||
BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
|
||||
}
|
||||
}
|
||||
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
|
||||
// DMA controlled xfer of byte from Memory to I/O
|
||||
|
||||
if (!ma_sl) {
|
||||
DEV_MEM_READ_PHYSICAL(phy_addr, 1, &data_byte);
|
||||
|
||||
if (BX_DMA_THIS h[channel].dmaRead8)
|
||||
BX_DMA_THIS h[channel].dmaRead8(&data_byte);
|
||||
|
||||
BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte);
|
||||
}
|
||||
else {
|
||||
DEV_MEM_READ_PHYSICAL(phy_addr, 2, (Bit8u*) &data_word);
|
||||
|
||||
if (BX_DMA_THIS h[channel].dmaRead16)
|
||||
BX_DMA_THIS h[channel].dmaRead16(&data_word);
|
||||
|
||||
BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
|
||||
}
|
||||
}
|
||||
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
|
||||
// verify
|
||||
|
||||
if (!ma_sl) {
|
||||
if (BX_DMA_THIS h[channel].dmaWrite8)
|
||||
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
|
||||
else
|
||||
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
|
||||
}
|
||||
else {
|
||||
if (BX_DMA_THIS h[channel].dmaWrite16)
|
||||
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
|
||||
else
|
||||
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BX_PANIC(("hlda: transfer_type 3 is undefined"));
|
||||
}
|
||||
|
||||
if (count_expired) {
|
||||
BX_DMA_THIS TC = 0; // clear TC, adapter card already notified
|
||||
BX_DMA_THIS HLDA = 0;
|
||||
bx_pc_system.set_HRQ(0); // clear HRQ to CPU
|
||||
BX_DMA_THIS s[ma_sl].DACK[channel] = 0; // clear DACK to adapter card
|
||||
if (!ma_sl) {
|
||||
BX_DMA_THIS set_DRQ(4, 0); // clear DRQ to cascade
|
||||
BX_DMA_THIS s[1].DACK[0] = 0; // clear DACK to cascade
|
||||
}
|
||||
}
|
||||
}
|
||||
104
bochs/iodev/dma.h
Normal file
104
bochs/iodev/dma.h
Normal file
@ -0,0 +1,104 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef _PCDMA_H
|
||||
#define _PCDMA_H
|
||||
|
||||
#if BX_USE_DMA_SMF
|
||||
# define BX_DMA_SMF static
|
||||
# define BX_DMA_THIS theDmaDevice->
|
||||
#else
|
||||
# define BX_DMA_SMF
|
||||
# define BX_DMA_THIS this->
|
||||
#endif
|
||||
|
||||
class bx_dma_c : public bx_dma_stub_c {
|
||||
public:
|
||||
bx_dma_c();
|
||||
virtual ~bx_dma_c();
|
||||
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void raise_HLDA(void);
|
||||
virtual void set_DRQ(unsigned channel, bx_bool val);
|
||||
virtual unsigned get_TC(void);
|
||||
virtual void register_state(void);
|
||||
|
||||
virtual unsigned registerDMA8Channel(unsigned channel,
|
||||
void (* dmaRead)(Bit8u *data_byte),
|
||||
void (* dmaWrite)(Bit8u *data_byte),
|
||||
const char *name);
|
||||
virtual unsigned registerDMA16Channel(unsigned channel,
|
||||
void (* dmaRead)(Bit16u *data_word),
|
||||
void (* dmaWrite)(Bit16u *data_word),
|
||||
const char *name);
|
||||
virtual unsigned unregisterDMAChannel(unsigned channel);
|
||||
|
||||
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_DMA_SMF
|
||||
Bit32u read (Bit32u address, unsigned io_len) BX_CPP_AttrRegparmN(2);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
|
||||
#endif
|
||||
BX_DMA_SMF void control_HRQ(bx_bool ma_sl);
|
||||
BX_DMA_SMF void reset_controller(unsigned num);
|
||||
|
||||
struct {
|
||||
bx_bool DRQ[4]; // DMA Request
|
||||
bx_bool DACK[4]; // DMA Acknowlege
|
||||
|
||||
bx_bool mask[4];
|
||||
bx_bool flip_flop;
|
||||
Bit8u status_reg;
|
||||
Bit8u command_reg;
|
||||
bx_bool ctrl_disabled;
|
||||
struct {
|
||||
struct {
|
||||
Bit8u mode_type;
|
||||
Bit8u address_decrement;
|
||||
Bit8u autoinit_enable;
|
||||
Bit8u transfer_type;
|
||||
} mode;
|
||||
Bit16u base_address;
|
||||
Bit16u current_address;
|
||||
Bit16u base_count;
|
||||
Bit16u current_count;
|
||||
Bit8u page_reg;
|
||||
bx_bool used;
|
||||
} chan[4]; /* DMA channels 0..3 */
|
||||
} s[2]; // state information DMA-1 / DMA-2
|
||||
|
||||
bx_bool HLDA; // Hold Acknowlege
|
||||
bx_bool TC; // Terminal Count
|
||||
|
||||
Bit8u ext_page_reg[16]; // Extra page registers (unused)
|
||||
|
||||
struct {
|
||||
void (* dmaRead8)(Bit8u *data_byte);
|
||||
void (* dmaWrite8)(Bit8u *data_byte);
|
||||
void (* dmaRead16)(Bit16u *data_word);
|
||||
void (* dmaWrite16)(Bit16u *data_word);
|
||||
} h[4]; // DMA read and write handlers
|
||||
};
|
||||
|
||||
#endif // #ifndef _PCDMA_H
|
||||
214
bochs/iodev/eth.cc
Normal file
214
bochs/iodev/eth.cc
Normal file
@ -0,0 +1,214 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// eth.cc - helper code to find and create pktmover classes
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
|
||||
// NE2000/ether stuff.
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS /* not needed */
|
||||
|
||||
eth_locator_c *eth_locator_c::all;
|
||||
|
||||
//
|
||||
// Each pktmover module has a static locator class that registers
|
||||
// here
|
||||
//
|
||||
eth_locator_c::eth_locator_c(const char *type)
|
||||
{
|
||||
next = all;
|
||||
all = this;
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
#ifdef ETH_NULL
|
||||
extern class bx_null_locator_c bx_null_match;
|
||||
#endif
|
||||
#ifdef ETH_FBSD
|
||||
extern class bx_fbsd_locator_c bx_fbsd_match;
|
||||
#endif
|
||||
#ifdef ETH_LINUX
|
||||
extern class bx_linux_locator_c bx_linux_match;
|
||||
#endif
|
||||
#ifdef ETH_WIN32
|
||||
extern class bx_win32_locator_c bx_win32_match;
|
||||
#endif
|
||||
#if HAVE_ETHERTAP
|
||||
extern class bx_tap_locator_c bx_tap_match;
|
||||
#endif
|
||||
#if HAVE_TUNTAP
|
||||
extern class bx_tuntap_locator_c bx_tuntap_match;
|
||||
#endif
|
||||
#if HAVE_VDE
|
||||
extern class bx_vde_locator_c bx_vde_match;
|
||||
#endif
|
||||
#ifdef ETH_ARPBACK
|
||||
extern class bx_arpback_locator_c bx_arpback_match;
|
||||
#endif
|
||||
extern class bx_vnet_locator_c bx_vnet_match;
|
||||
|
||||
//
|
||||
// Called by ethernet chip emulations to locate and create a pktmover
|
||||
// object
|
||||
//
|
||||
eth_pktmover_c *
|
||||
eth_locator_c::create(const char *type, const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh, bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
#ifdef eth_static_constructors
|
||||
for (eth_locator_c *p = all; p != NULL; p = p->next) {
|
||||
if (strcmp(type, p->type) == 0)
|
||||
return (p->allocate(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
#else
|
||||
eth_locator_c *ptr = 0;
|
||||
|
||||
#ifdef ETH_ARPBACK
|
||||
{
|
||||
if (!strcmp(type, "arpback"))
|
||||
ptr = (eth_locator_c *) &bx_arpback_match;
|
||||
}
|
||||
#endif
|
||||
#ifdef ETH_NULL
|
||||
{
|
||||
if (!strcmp(type, "null"))
|
||||
ptr = (eth_locator_c *) &bx_null_match;
|
||||
}
|
||||
#endif
|
||||
#ifdef ETH_FBSD
|
||||
{
|
||||
if (!strcmp(type, "fbsd"))
|
||||
ptr = (eth_locator_c *) &bx_fbsd_match;
|
||||
}
|
||||
#endif
|
||||
#ifdef ETH_LINUX
|
||||
{
|
||||
if (!strcmp(type, "linux"))
|
||||
ptr = (eth_locator_c *) &bx_linux_match;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_TUNTAP
|
||||
{
|
||||
if (!strcmp(type, "tuntap"))
|
||||
ptr = (eth_locator_c *) &bx_tuntap_match;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_VDE
|
||||
{
|
||||
if (!strcmp(type, "vde"))
|
||||
ptr = (eth_locator_c *) &bx_vde_match;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_ETHERTAP
|
||||
{
|
||||
if (!strcmp(type, "tap"))
|
||||
ptr = (eth_locator_c *) &bx_tap_match;
|
||||
}
|
||||
#endif
|
||||
#ifdef ETH_WIN32
|
||||
{
|
||||
if(!strcmp(type, "win32"))
|
||||
ptr = (eth_locator_c *) &bx_win32_match;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
if (!strcmp(type, "vnet"))
|
||||
ptr = (eth_locator_c *) &bx_vnet_match;
|
||||
}
|
||||
if (ptr)
|
||||
return (ptr->allocate(netif, macaddr, rxh, dev, script));
|
||||
#endif
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#if (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1) || (HAVE_VDE==1)
|
||||
|
||||
extern "C" {
|
||||
#include <sys/wait.h>
|
||||
};
|
||||
|
||||
// This is a utility script used for tuntap or ethertap
|
||||
int execute_script(bx_devmodel_c *netdev, const char* scriptname, char* arg1)
|
||||
{
|
||||
int pid,status;
|
||||
|
||||
if (!(pid=fork())) {
|
||||
char filename[BX_PATHNAME_LEN];
|
||||
if (scriptname[0]=='/') {
|
||||
strcpy(filename, scriptname);
|
||||
}
|
||||
else {
|
||||
getcwd(filename, BX_PATHNAME_LEN);
|
||||
strcat(filename, "/");
|
||||
strcat(filename, scriptname);
|
||||
}
|
||||
|
||||
// execute the script
|
||||
netdev->info("Executing script '%s %s'",filename,arg1);
|
||||
execle(filename, scriptname, arg1, NULL, NULL);
|
||||
|
||||
// if we get here there has been a problem
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
wait (&status);
|
||||
if (!WIFEXITED(status)) {
|
||||
return -1;
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
#endif // (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1)
|
||||
|
||||
void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool host_to_guest)
|
||||
{
|
||||
Bit8u *charbuf = (Bit8u *)buf;
|
||||
unsigned n;
|
||||
|
||||
if (!host_to_guest) {
|
||||
fprintf(pktlog_txt, "a packet from guest to host, length %u\n", len);
|
||||
} else {
|
||||
fprintf(pktlog_txt, "a packet from host to guest, length %u\n", len);
|
||||
}
|
||||
for (n = 0; n < len; n++) {
|
||||
if (((n % 16) == 0) && (n > 0))
|
||||
fprintf(pktlog_txt, "\n");
|
||||
fprintf(pktlog_txt, "%02x ", (unsigned)charbuf[n]);
|
||||
}
|
||||
fprintf(pktlog_txt, "\n--\n");
|
||||
fflush(pktlog_txt);
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING */
|
||||
83
bochs/iodev/eth.h
Normal file
83
bochs/iodev/eth.h
Normal file
@ -0,0 +1,83 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
|
||||
// NE2000/ether stuff.
|
||||
|
||||
// eth.h - see eth_null.cc for implementation details
|
||||
|
||||
#ifndef BX_ETH_H
|
||||
#define BX_ETH_H
|
||||
|
||||
#define BX_PACKET_BUFSIZE 2048 // Enough for an ether frame
|
||||
|
||||
typedef void (*eth_rx_handler_t)(void *arg, const void *buf, unsigned len);
|
||||
|
||||
static const Bit8u broadcast_macaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
|
||||
int execute_script(bx_devmodel_c *netdev, const char *name, char* arg1);
|
||||
void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool host_to_guest);
|
||||
|
||||
//
|
||||
// The eth_pktmover class is used by ethernet chip emulations
|
||||
// to interface to the outside world. An instance of this
|
||||
// would allow frames to be sent to and received from some
|
||||
// entity. An example would be the packet filter on a Unix
|
||||
// system, an NDIS driver in promisc mode on WinNT, or maybe
|
||||
// a simulated network that talks to another process.
|
||||
//
|
||||
class eth_pktmover_c {
|
||||
public:
|
||||
virtual void sendpkt(void *buf, unsigned io_len) = 0;
|
||||
virtual ~eth_pktmover_c () {}
|
||||
protected:
|
||||
bx_devmodel_c *netdev;
|
||||
eth_rx_handler_t rxh; // receive callback
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The eth_locator class is used by pktmover classes to register
|
||||
// their name. Chip emulations use the static 'create' method
|
||||
// to locate and instantiate a pktmover class.
|
||||
//
|
||||
class eth_locator_c {
|
||||
public:
|
||||
static eth_pktmover_c *create(const char *type, const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script);
|
||||
protected:
|
||||
eth_locator_c(const char *type);
|
||||
virtual ~eth_locator_c() {}
|
||||
virtual eth_pktmover_c *allocate(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script) = 0;
|
||||
private:
|
||||
static eth_locator_c *all;
|
||||
eth_locator_c *next;
|
||||
const char *type;
|
||||
};
|
||||
|
||||
#endif
|
||||
188
bochs/iodev/eth_arpback.cc
Normal file
188
bochs/iodev/eth_arpback.cc
Normal file
@ -0,0 +1,188 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// eth_arpback.cc - basic ethernet packetmover, only responds to ARP
|
||||
|
||||
// Various networking docs:
|
||||
// http://www.graphcomp.com/info/rfc/
|
||||
// rfc0826: arp
|
||||
// rfc0903: rarp
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(ETH_ARPBACK)
|
||||
|
||||
#include "eth.h"
|
||||
#include "crc32.h"
|
||||
#include "eth_packetmaker.h"
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
|
||||
//static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
|
||||
//static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x00, 0x00, 0x00, 0x00};
|
||||
//static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
|
||||
//static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
|
||||
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_arpback_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_arpback_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer(void);
|
||||
FILE *pktlog, *pktlog_txt;
|
||||
//Bit8u arpbuf[MAX_FRAME_SIZE];
|
||||
//Bit32u buflen;
|
||||
//bx_bool bufvalid;
|
||||
//CRC_Generator mycrc;
|
||||
eth_ETHmaker packetmaker;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_arpback_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_arpback_locator_c(void) : eth_locator_c("arpback") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_arpback_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_arpback_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_arpback_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_arpback_pktmover_c::bx_arpback_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
this->netdev = dev;
|
||||
BX_INFO(("arpback network driver"));
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
|
||||
1, 1, "eth_arpback"); // continuous, active
|
||||
this->rxh = rxh;
|
||||
//bufvalid=0;
|
||||
packetmaker.init();
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
// Start the rx poll
|
||||
// eventually Bryce wants txlog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
pktlog = fopen("ne2k-pkt.log", "wb");
|
||||
if (!pktlog) BX_PANIC(("open ne2k-pkt.log failed"));
|
||||
pktlog_txt = fopen("ne2k-pktlog.txt", "wb");
|
||||
if (!pktlog_txt) BX_PANIC(("open ne2k-pktlog.txt failed"));
|
||||
fprintf(pktlog_txt, "arpback packetmover readable log file\n");
|
||||
fprintf(pktlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(pktlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(pktlog_txt, "\n--\n");
|
||||
fflush(pktlog_txt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bx_arpback_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
if(io_len<BX_PACKET_BUFSIZE) {
|
||||
eth_packet barney;
|
||||
memcpy(barney.buf,buf,io_len);
|
||||
barney.len=io_len;
|
||||
if(packetmaker.ishandler(barney)) {
|
||||
packetmaker.sendpacket(barney);
|
||||
}
|
||||
/*
|
||||
if(( (!memcmp(buf, external_mac, 6)) || (!memcmp(buf, broadcast_macaddr, 6)) )
|
||||
&& (!memcmp(((Bit8u *)buf)+12, ethtype_arp, 2)) ) {
|
||||
Bit32u tempcrc;
|
||||
memcpy(arpbuf,buf,io_len); //move to temporary buffer
|
||||
memcpy(arpbuf, arpbuf+6, 6); //set destination to sender
|
||||
memcpy(arpbuf+6, external_mac, 6); //set sender to us
|
||||
memcpy(arpbuf+32, arpbuf+22, 10); //move destination to sender
|
||||
memcpy(arpbuf+22, external_mac, 6); //set sender to us
|
||||
memcpy(arpbuf+28, external_ip, 4); //set sender to us
|
||||
arpbuf[21]=2; //make this a reply and not a request
|
||||
tempcrc=mycrc.get_CRC(arpbuf,io_len);
|
||||
memcpy(arpbuf+io_len, &tempcrc, 4);
|
||||
buflen=io_len;//+4
|
||||
bufvalid=1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
BX_DEBUG(("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite (buf, io_len, 1, pktlog);
|
||||
if (n != 1) BX_ERROR (("fwrite to pktlog failed, length %u", io_len));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(pktlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(pktlog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_arpback_pktmover_c::rx_timer_handler (void * this_ptr)
|
||||
{
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
BX_DEBUG(("rx_timer_handler"));
|
||||
#endif
|
||||
bx_arpback_pktmover_c *class_ptr = ((bx_arpback_pktmover_c *)this_ptr);
|
||||
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void bx_arpback_pktmover_c::rx_timer (void)
|
||||
{
|
||||
eth_packet rubble;
|
||||
|
||||
if (packetmaker.getpacket(rubble)) {
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
write_pktlog_txt(pktlog_txt, rubble.buf, rubble.len, 1);
|
||||
#endif
|
||||
(*rxh)(this->netdev, rubble.buf, rubble.len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined(ETH_ARPBACK) */
|
||||
373
bochs/iodev/eth_fbsd.cc
Normal file
373
bochs/iodev/eth_fbsd.cc
Normal file
@ -0,0 +1,373 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
|
||||
// NE2000/ether stuff.
|
||||
|
||||
// eth_fbsd.cc - A FreeBSD packet filter implementation of
|
||||
// an ethernet pktmover. There are some problems and limitations
|
||||
// with FreeBSD:
|
||||
// - the source address of the frame is overwritten by
|
||||
// the hosts's source address. This causes problems with
|
||||
// learning bridges - since they cannot determine where
|
||||
// BOCHS 'is', they broadcast the frame to all ports.
|
||||
// - packets cannot be sent from BOCHS to the host
|
||||
// - TCP performance seems to be abysmal; I think this is
|
||||
// a timing problem somewhere.
|
||||
// - I haven't handled the case where multiple frames arrive
|
||||
// in a single BPF read.
|
||||
//
|
||||
// The /dev/bpf* devices need to be set up with the appropriate
|
||||
// permissions for this to work.
|
||||
//
|
||||
// The config line in .bochsrc should look something like:
|
||||
//
|
||||
// ne2k: ioaddr=0x280, irq=9, mac=00:a:b:c:1:2, ethmod=fbsd, ethdev=fxp0
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(ETH_FBSD)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
extern "C" {
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/bpf.h>
|
||||
#include <errno.h>
|
||||
};
|
||||
|
||||
#define BX_BPF_POLL 1000 // Poll for a frame every 250 usecs
|
||||
|
||||
#define BX_BPF_INSNSIZ 8 // number of bpf insns
|
||||
|
||||
// template filter for a unicast mac address and all
|
||||
// multicast/broadcast frames
|
||||
static const struct bpf_insn macfilter[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), // A <- P[2:4]
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2), // if A != 0xaaaaaaa GOTO LABEL-1
|
||||
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0), // A <- P[0:2]
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0), // if A == 0xaaaa GOTO ACCEPT
|
||||
// LABEL-1
|
||||
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0), // A <- P[0:1]
|
||||
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1), // if !(A & 1) GOTO LABEL-REJECT
|
||||
// LABEL-ACCEPT
|
||||
BPF_STMT(BPF_RET, 1514), // Accept packet
|
||||
// LABEL-REJECT
|
||||
BPF_STMT(BPF_RET, 0), // Reject packet
|
||||
};
|
||||
|
||||
// template filter for all frames
|
||||
static const struct bpf_insn promiscfilter[] = {
|
||||
BPF_STMT(BPF_RET, 1514)
|
||||
};
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_fbsd_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_fbsd_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
|
||||
private:
|
||||
char *fbsd_macaddr[6];
|
||||
int bpf_fd;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer(void);
|
||||
int rx_timer_index;
|
||||
struct bpf_insn filter[BX_BPF_INSNSIZ];
|
||||
FILE *ne2klog, *ne2klog_txt;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_fbsd_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_fbsd_locator_c(void) : eth_locator_c("fbsd") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_fbsd_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_fbsd_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
//
|
||||
// Open a bpf file descriptor, and attempt to bind to
|
||||
// the specified netif (Replicates libpcap open code)
|
||||
//
|
||||
bx_fbsd_pktmover_c::bx_fbsd_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
char device[sizeof "/dev/bpf000"];
|
||||
int tmpfd;
|
||||
int n = 0;
|
||||
struct ifreq ifr;
|
||||
struct bpf_version bv;
|
||||
struct bpf_program bp;
|
||||
u_int v;
|
||||
|
||||
this->netdev = dev;
|
||||
BX_INFO(("freebsd network driver"));
|
||||
memcpy(fbsd_macaddr, macaddr, 6);
|
||||
|
||||
do {
|
||||
(void)sprintf(device, "/dev/bpf%d", n++);
|
||||
this->bpf_fd = open(device, O_RDWR);
|
||||
BX_DEBUG(("tried %s, returned %d (%s)",device,this->bpf_fd,strerror(errno)));
|
||||
if(errno == EACCES)
|
||||
break;
|
||||
} while (this->bpf_fd == -1);
|
||||
|
||||
if (this->bpf_fd == -1) {
|
||||
BX_PANIC(("eth_freebsd: could not open packet filter: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(this->bpf_fd, BIOCVERSION, (caddr_t)&bv) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not retrieve bpf version"));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) {
|
||||
BX_PANIC(("eth_freebsd: bpf version mismatch between compilation and runtime"));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set buffer size
|
||||
v = BX_PACKET_BUFSIZE;
|
||||
if (ioctl(this->bpf_fd, BIOCSBLEN, (caddr_t)&v) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not set buffer size: %s", strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
(void)strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
|
||||
if (ioctl(this->bpf_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not enable interface '%s': %s", netif, strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd == -1;
|
||||
}
|
||||
|
||||
// Verify that the device is an ethernet.
|
||||
if (ioctl(this->bpf_fd, BIOCGDLT, (caddr_t)&v) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not retrieve datalink type: %s", strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
if (v != DLT_EN10MB) {
|
||||
BX_PANIC(("eth_freebsd: incorrect datalink type %d, expected 10mb ethernet", v));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Put the device into promisc mode. This could be optimised
|
||||
// to filter on a MAC address, broadcast, and all-multi,
|
||||
// but this will do for now.
|
||||
//
|
||||
if (ioctl(this->bpf_fd, BIOCPROMISC, NULL) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not enable promisc mode: %s", strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
v = 1;
|
||||
if (ioctl(this->bpf_fd, BIOCIMMEDIATE, &v) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not enable immediate mode"));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up non-blocking i/o
|
||||
v = 1;
|
||||
if (ioctl(this->bpf_fd, FIONBIO, &v) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not enable non-blocking i/o: %s", strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a filter
|
||||
#ifdef notdef
|
||||
memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
|
||||
bp.bf_len = 1;
|
||||
#else
|
||||
memcpy(&this->filter, macfilter, sizeof(macfilter));
|
||||
this->filter[1].k =
|
||||
(macaddr[2] & 0xff) << 24 |
|
||||
(macaddr[3] & 0xff) << 16 |
|
||||
(macaddr[4] & 0xff) << 8 |
|
||||
(macaddr[5] & 0xff);
|
||||
this->filter[3].k =
|
||||
(macaddr[0] & 0xff) << 8 |
|
||||
(macaddr[1] & 0xff);
|
||||
bp.bf_len = 8;
|
||||
#endif
|
||||
bp.bf_insns = &this->filter[0];
|
||||
if (ioctl(this->bpf_fd, BIOCSETF, &bp) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not set filter: %s", strerror(errno)));
|
||||
close(this->bpf_fd);
|
||||
this->bpf_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, BX_BPF_POLL,
|
||||
1, 1, "eth_fbsd"); // continuous, active
|
||||
|
||||
this->rxh = rxh;
|
||||
|
||||
#if BX_ETH_FBSD_LOGGING
|
||||
// eventually Bryce wants ne2klog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
ne2klog = fopen("ne2k.raw", "wb");
|
||||
if (!ne2klog) BX_PANIC(("open ne2k-tx.log failed"));
|
||||
ne2klog_txt = fopen("ne2k.txt", "wb");
|
||||
if (!ne2klog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
|
||||
fprintf(ne2klog_txt, "null packetmover readable log file\n");
|
||||
fprintf(ne2klog_txt, "net IF = %s\n", netif);
|
||||
fprintf(ne2klog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(ne2klog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(ne2klog_txt, "\n--\n");
|
||||
fflush(ne2klog_txt);
|
||||
#endif
|
||||
}
|
||||
|
||||
// the output routine - called with pre-formatted ethernet frame.
|
||||
void
|
||||
bx_fbsd_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
#if BX_ETH_FBSD_LOGGING
|
||||
BX_DEBUG(("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(buf, io_len, 1, ne2klog);
|
||||
if (n != 1) BX_ERROR(("fwrite to ne2klog failed", io_len));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(ne2klog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(ne2klog);
|
||||
#endif
|
||||
int status;
|
||||
|
||||
if (this->bpf_fd != -1)
|
||||
status = write(this->bpf_fd, buf, io_len);
|
||||
}
|
||||
|
||||
// The receive poll process
|
||||
void
|
||||
bx_fbsd_pktmover_c::rx_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_fbsd_pktmover_c *class_ptr = (bx_fbsd_pktmover_c *) this_ptr;
|
||||
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bx_fbsd_pktmover_c::rx_timer(void)
|
||||
{
|
||||
int nbytes = 0;
|
||||
unsigned char rxbuf[BX_PACKET_BUFSIZE];
|
||||
struct bpf_hdr *bhdr;
|
||||
struct bpf_stat bstat;
|
||||
static struct bpf_stat previous_bstat;
|
||||
int counter = 10;
|
||||
#define phdr ((unsigned char*)bhdr)
|
||||
|
||||
bhdr = (struct bpf_hdr *) rxbuf;
|
||||
nbytes = read(this->bpf_fd, rxbuf, sizeof(rxbuf));
|
||||
|
||||
while (phdr < (rxbuf + nbytes)) {
|
||||
if (ioctl(this->bpf_fd, BIOCGSTATS, &bstat) < 0) {
|
||||
BX_PANIC(("eth_freebsd: could not stat filter: %s", strerror(errno)));
|
||||
}
|
||||
if (bstat.bs_drop > previous_bstat.bs_drop) {
|
||||
BX_INFO(("eth_freebsd: %d packets dropped by the kernel.",
|
||||
bstat.bs_drop - previous_bstat.bs_drop));
|
||||
}
|
||||
previous_bstat = bstat;
|
||||
if (bhdr->bh_caplen < 20 || bhdr->bh_caplen > 1514) {
|
||||
BX_ERROR(("eth_freebsd: received too weird packet length: %d", bhdr->bh_caplen));
|
||||
}
|
||||
|
||||
// filter out packets sourced from this node
|
||||
if (memcmp(bhdr + bhdr->bh_hdrlen + 6, this->fbsd_macaddr, 6)) {
|
||||
(*rxh)(this->netdev, phdr + bhdr->bh_hdrlen, bhdr->bh_caplen);
|
||||
}
|
||||
|
||||
#if BX_ETH_FBSD_LOGGING
|
||||
BX_DEBUG(("receive packet length %u", nbytes));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
if (1 != fwrite(bhdr, bhdr->bh_caplen, 1, ne2klog)) {
|
||||
BX_PANIC(("fwrite to ne2klog failed: %s", strerror(errno)));
|
||||
}
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(ne2klog_txt, rxbuf, bhdr->bh_caplen, 1);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush (this->ne2klog);
|
||||
#endif
|
||||
|
||||
// Advance bhdr and phdr pointers to next packet
|
||||
bhdr = (struct bpf_hdr*) ((char*) bhdr + BPF_WORDALIGN(bhdr->bh_hdrlen + bhdr->bh_caplen));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined(ETH_FBSD) */
|
||||
|
||||
284
bochs/iodev/eth_linux.cc
Normal file
284
bochs/iodev/eth_linux.cc
Normal file
@ -0,0 +1,284 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
|
||||
// NE2000/ether stuff.
|
||||
|
||||
// eth_linux.cc - A Linux socket filter adaptation of the FreeBSD BPF driver
|
||||
// <splite@purdue.edu> 21 June 2001
|
||||
//
|
||||
// Problems and limitations:
|
||||
// - packets cannot be sent from BOCHS to the host
|
||||
// - Linux kernel sometimes gets network watchdog timeouts under emulation
|
||||
// - author doesn't know C++
|
||||
//
|
||||
// The config line in .bochsrc should look something like:
|
||||
//
|
||||
// ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:2, ethmod=linux, ethdev=eth0
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined (ETH_LINUX)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
extern "C" {
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/filter.h>
|
||||
};
|
||||
|
||||
#define BX_PACKET_POLL 1000 // Poll for a frame every 1000 usecs
|
||||
|
||||
// template filter for a unicast mac address and all
|
||||
// multicast/broadcast frames
|
||||
static const struct sock_filter macfilter[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
|
||||
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
|
||||
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
|
||||
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
|
||||
BPF_STMT(BPF_RET, 1514),
|
||||
BPF_STMT(BPF_RET, 0),
|
||||
};
|
||||
#define BX_LSF_ICNT 8 // number of lsf instructions in macfilter
|
||||
|
||||
#if 0
|
||||
// template filter for all frames
|
||||
static const struct sock_filter promiscfilter[] = {
|
||||
BPF_STMT(BPF_RET, 1514)
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_linux_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_linux_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
|
||||
private:
|
||||
unsigned char *linux_macaddr[6];
|
||||
int fd;
|
||||
int ifindex;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer(void);
|
||||
int rx_timer_index;
|
||||
struct sock_filter filter[BX_LSF_ICNT];
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_linux_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_linux_locator_c(void) : eth_locator_c("linux") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_linux_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_linux_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_linux_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
//
|
||||
bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
struct sockaddr_ll sll;
|
||||
struct packet_mreq mr;
|
||||
struct ifreq ifr;
|
||||
struct sock_fprog fp;
|
||||
|
||||
this->netdev = dev;
|
||||
memcpy(linux_macaddr, macaddr, 6);
|
||||
|
||||
// Open packet socket
|
||||
//
|
||||
if ((this->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
|
||||
if (errno == EACCES)
|
||||
BX_PANIC(("eth_linux: must be root or have CAP_NET_RAW capability to open socket"));
|
||||
else
|
||||
BX_PANIC(("eth_linux: could not open socket: %s", strerror(errno)));
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Translate interface name to index
|
||||
//
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, netif);
|
||||
if (ioctl(this->fd, SIOCGIFINDEX, &ifr) == -1) {
|
||||
BX_PANIC(("eth_linux: could not get index for interface '%s'\n", netif));
|
||||
close(fd);
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
this->ifindex = ifr.ifr_ifindex;
|
||||
|
||||
|
||||
// Bind to given interface
|
||||
//
|
||||
memset(&sll, 0, sizeof(sll));
|
||||
sll.sll_family = AF_PACKET;
|
||||
sll.sll_ifindex = this->ifindex;
|
||||
if (bind(fd, (struct sockaddr *)&sll, (socklen_t)sizeof(sll)) == -1) {
|
||||
BX_PANIC(("eth_linux: could not bind to interface '%s': %s\n", netif, strerror(errno)));
|
||||
close(fd);
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Put the device into promisc mode.
|
||||
//
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
mr.mr_ifindex = this->ifindex;
|
||||
mr.mr_type = PACKET_MR_PROMISC;
|
||||
if (setsockopt(this->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *)&mr, (socklen_t)sizeof(mr)) == -1) {
|
||||
BX_PANIC(("eth_linux: could not enable promisc mode: %s\n", strerror(errno)));
|
||||
close(this->fd);
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up non-blocking i/o
|
||||
if (fcntl(this->fd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
BX_PANIC(("eth_linux: could not set non-blocking i/o on socket"));
|
||||
close(this->fd);
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a filter
|
||||
#ifdef notdef
|
||||
memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
|
||||
fp.len = 1;
|
||||
#endif
|
||||
memcpy(&this->filter, macfilter, sizeof(macfilter));
|
||||
this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 |
|
||||
(macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
|
||||
this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
|
||||
fp.len = BX_LSF_ICNT;
|
||||
fp.filter = this->filter;
|
||||
BX_INFO(("eth_linux: fp.len=%d fp.filter=%lx", fp.len, (unsigned long) fp.filter));
|
||||
if (setsockopt(this->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fp, sizeof(fp)) < 0) {
|
||||
BX_PANIC(("eth_linux: could not set socket filter: %s", strerror(errno)));
|
||||
close(this->fd);
|
||||
this->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, BX_PACKET_POLL,
|
||||
1, 1, "eth_linux"); // continuous, active
|
||||
|
||||
this->rxh = rxh;
|
||||
BX_INFO(("linux network driver initialized: using interface %s", netif));
|
||||
}
|
||||
|
||||
// the output routine - called with pre-formatted ethernet frame.
|
||||
void
|
||||
bx_linux_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (this->fd != -1) {
|
||||
status = write(this->fd, buf, io_len);
|
||||
if (status == -1)
|
||||
BX_INFO(("eth_linux: write failed: %s", strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
// The receive poll process
|
||||
void
|
||||
bx_linux_pktmover_c::rx_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_linux_pktmover_c *class_ptr = (bx_linux_pktmover_c *) this_ptr;
|
||||
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void
|
||||
bx_linux_pktmover_c::rx_timer(void)
|
||||
{
|
||||
int nbytes = 0;
|
||||
Bit8u rxbuf[BX_PACKET_BUFSIZE];
|
||||
struct sockaddr_ll sll;
|
||||
socklen_t fromlen;
|
||||
|
||||
if (this->fd == -1)
|
||||
return;
|
||||
|
||||
fromlen = sizeof(sll);
|
||||
nbytes = recvfrom(this->fd, rxbuf, sizeof(rxbuf), 0, (struct sockaddr *)&sll, &fromlen);
|
||||
|
||||
if (nbytes == -1) {
|
||||
if (errno != EAGAIN)
|
||||
BX_INFO(("eth_linux: error receiving packet: %s\n", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
// this should be done with LSF someday
|
||||
// filter out packets sourced by us
|
||||
if (memcmp(sll.sll_addr, this->linux_macaddr, 6) == 0)
|
||||
return;
|
||||
// let through broadcast, multicast, and our mac address
|
||||
// if ((memcmp(rxbuf, broadcast_macaddr, 6) == 0) || (memcmp(rxbuf, this->linux_macaddr, 6) == 0) || rxbuf[0] & 0x01) {
|
||||
BX_DEBUG(("eth_linux: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
|
||||
(*rxh)(netdev, rxbuf, nbytes);
|
||||
// }
|
||||
}
|
||||
#endif /* if BX_NETWORKING && defined ETH_LINUX */
|
||||
148
bochs/iodev/eth_null.cc
Normal file
148
bochs/iodev/eth_null.cc
Normal file
@ -0,0 +1,148 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// eth_null.cc - skeleton code for an ethernet pktmover
|
||||
|
||||
// Various networking docs:
|
||||
// http://www.graphcomp.com/info/rfc/
|
||||
// rfc0826: arp
|
||||
// rfc0903: rarp
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_null_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_null_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_null_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_null_locator_c(void) : eth_locator_c("null") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_null_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_null_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_null_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_null_pktmover_c::bx_null_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
this->netdev = dev;
|
||||
BX_INFO(("null network driver"));
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
|
||||
1, 1, "eth_null"); // continuous, active
|
||||
this->rxh = rxh;
|
||||
// eventually Bryce wants txlog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
txlog = fopen("ne2k-tx.log", "wb");
|
||||
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
|
||||
txlog_txt = fopen("ne2k-txdump.txt", "wb");
|
||||
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
|
||||
fprintf(txlog_txt, "null packetmover readable log file\n");
|
||||
fprintf(txlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(txlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(txlog_txt, "\n--\n");
|
||||
fflush(txlog_txt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_null_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
BX_DEBUG (("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
size_t n = fwrite (buf, io_len, 1, txlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to txlog failed, io_len = %u", io_len));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(txlog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_null_pktmover_c::rx_timer_handler (void *this_ptr)
|
||||
{
|
||||
#if BX_ETH_NULL_LOGGING
|
||||
/// hey wait there is no receive data with a NULL ethernet, is there....
|
||||
|
||||
int io_len = 0;
|
||||
Bit8u buf[1];
|
||||
bx_null_pktmover_c *class_ptr = (bx_null_pktmover_c *) this_ptr;
|
||||
bx_devmodel_c *netdev = class_ptr->netdev;
|
||||
if (io_len > 0) {
|
||||
BX_DEBUG(("receive packet length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
size_t n = fwrite (buf, io_len, 1, class_ptr->rxlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to rxlog failed, io_len = %u", io_len));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(class_ptr->rxlog_txt, buf, io_len, 1);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(class_ptr->rxlog);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING */
|
||||
202
bochs/iodev/eth_packetmaker.cc
Normal file
202
bochs/iodev/eth_packetmaker.cc
Normal file
@ -0,0 +1,202 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(ETH_ARPBACK)
|
||||
|
||||
#include "eth_packetmaker.h"
|
||||
|
||||
bx_bool sendable(const eth_packet& outpacket) {
|
||||
//FINISH ME!
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit32u eth_IPmaker::datalen(const eth_packet& outpacket)
|
||||
{
|
||||
Bit32u out;
|
||||
out=((outpacket.buf[16]<<8)+outpacket.buf[17])-(4*(0xF & outpacket.buf[14]));
|
||||
return out;
|
||||
}
|
||||
|
||||
const Bit8u *eth_IPmaker::datagram(const eth_packet& outpacket)
|
||||
{
|
||||
const Bit8u *out;
|
||||
out=outpacket.buf+14+(4*(0xF & outpacket.buf[14]));
|
||||
return out;
|
||||
}
|
||||
|
||||
Bit32u eth_IPmaker::build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen)
|
||||
{
|
||||
Bit32u temp;
|
||||
Bit32u i;
|
||||
memcpy(pending.buf,internal_mac,6);
|
||||
memcpy(pending.buf+6,external_mac,6);
|
||||
memcpy(pending.buf+12,ethtype_ip,2);
|
||||
pending.buf[14]=0x45;
|
||||
pending.buf[15]=0;
|
||||
temp=datalen+20;
|
||||
pending.buf[16]=(temp>>8) & 0xFF;
|
||||
pending.buf[17]=temp & 0xFF;
|
||||
pending.buf[18]=0;
|
||||
pending.buf[19]=0;
|
||||
pending.buf[20]=0;
|
||||
pending.buf[21]=0;
|
||||
pending.buf[22]=30;
|
||||
pending.buf[23]=protocol;
|
||||
pending.buf[24]=0;
|
||||
pending.buf[25]=0;
|
||||
pending.buf[26]=(source>>24) & 0xFF;
|
||||
pending.buf[27]=(source>>16) & 0xFF;
|
||||
pending.buf[28]=(source>>8) & 0xFF;
|
||||
pending.buf[29]=(source) & 0xFF;
|
||||
pending.buf[30]=(dest>>24) & 0xFF;
|
||||
pending.buf[31]=(dest>>16) & 0xFF;
|
||||
pending.buf[32]=(dest>>8) & 0xFF;
|
||||
pending.buf[33]=(dest) & 0xFF;
|
||||
//Compute Checksum
|
||||
temp=0;
|
||||
for(i=14;i<34;i=i+2) {
|
||||
Bit32u addee=pending.buf[i];
|
||||
addee=(addee<<8) & pending.buf[i+1];
|
||||
temp=temp+addee;
|
||||
}
|
||||
temp=(temp>>16)+(temp&0xFFFF);
|
||||
temp=(temp>>16)+(temp&0xFFFF);
|
||||
pending.buf[24]=~(Bit8u)((temp>>8) & 0xFF);
|
||||
pending.buf[25]=~(Bit8u)(temp & 0xFF);
|
||||
return(34);
|
||||
}
|
||||
|
||||
Bit8u eth_IPmaker::protocol(const eth_packet& outpacket)
|
||||
{
|
||||
return (*(outpacket.buf+23) & 0xff);
|
||||
}
|
||||
|
||||
Bit32u eth_IPmaker::source(const eth_packet& outpacket)
|
||||
{
|
||||
Bit32u out=0xFF & *(outpacket.buf+26);
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+27));
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+28));
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+29));
|
||||
return out;
|
||||
}
|
||||
|
||||
Bit32u eth_IPmaker::destination(const eth_packet& outpacket)
|
||||
{
|
||||
Bit32u out=0xFF & *(outpacket.buf+30);
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+31));
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+32));
|
||||
out=(out<<8) | (0xFF & *(outpacket.buf+33));
|
||||
return out;
|
||||
}
|
||||
|
||||
void eth_IPmaker::init(void)
|
||||
{
|
||||
is_pending=0;
|
||||
}
|
||||
|
||||
void eth_ETHmaker::init(void)
|
||||
{
|
||||
arper.init();
|
||||
}
|
||||
|
||||
bx_bool eth_ETHmaker::getpacket(eth_packet& inpacket)
|
||||
{
|
||||
return arper.getpacket(inpacket);
|
||||
}
|
||||
|
||||
bx_bool eth_ETHmaker::ishandler(const eth_packet& outpacket)
|
||||
{
|
||||
if((outpacket.len>=60) &&
|
||||
( (!memcmp(outpacket.buf, external_mac, 6))
|
||||
|| (!memcmp(outpacket.buf, broadcast_macaddr, 6))) &&
|
||||
( (!memcmp(outpacket.buf+12, ethtype_arp, 2)) ||
|
||||
(!memcmp(outpacket.buf+12, ethtype_ip, 2))) &&
|
||||
(outpacket.len<PACKET_BUF_SIZE)
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool eth_ETHmaker::sendpacket(const eth_packet& outpacket)
|
||||
{
|
||||
return arper.sendpacket(outpacket);
|
||||
}
|
||||
|
||||
void eth_ARPmaker::init(void)
|
||||
{
|
||||
is_pending=0;
|
||||
pending.len=0;
|
||||
}
|
||||
|
||||
bx_bool eth_ARPmaker::getpacket(eth_packet& inpacket)
|
||||
{
|
||||
if(is_pending) {
|
||||
memcpy(inpacket.buf,pending.buf,pending.len);
|
||||
inpacket.len=pending.len;
|
||||
is_pending=0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool eth_ARPmaker::ishandler(const eth_packet& outpacket)
|
||||
{
|
||||
if((outpacket.len>=60) &&
|
||||
(!memcmp(outpacket.buf+12, ethtype_arp, 2)) &&
|
||||
(outpacket.len<PACKET_BUF_SIZE) &&
|
||||
( (!memcmp(outpacket.buf, external_mac, 6))
|
||||
|| (!memcmp(outpacket.buf, broadcast_macaddr, 6)) ) &&
|
||||
(!memcmp(outpacket.buf+38, external_ip, 4))
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool eth_ARPmaker::sendpacket(const eth_packet& outpacket)
|
||||
{
|
||||
if(is_pending || !ishandler(outpacket)) {
|
||||
return 0;
|
||||
} else {
|
||||
//Bit32u tempcrc;
|
||||
memcpy(pending.buf,outpacket.buf,outpacket.len); //move to temporary buffer
|
||||
memcpy(pending.buf, pending.buf+6, 6); //set destination to sender
|
||||
memcpy(pending.buf+6, external_mac, 6); //set sender to us
|
||||
memcpy(pending.buf+32, pending.buf+22, 10); //move destination to sender
|
||||
memcpy(pending.buf+22, external_mac, 6); //set sender to us
|
||||
memcpy(pending.buf+28, external_ip, 4); //set sender to us
|
||||
pending.buf[21]=2; //make this a reply and not a request
|
||||
//tempcrc=mycrc.get_CRC(pending.buf,len);
|
||||
//memcpy(pending.buf+len, &tempcrc, 4);
|
||||
pending.len=outpacket.len; //+4
|
||||
is_pending=1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined(ETH_ARPBACK) */
|
||||
146
bochs/iodev/eth_packetmaker.h
Normal file
146
bochs/iodev/eth_packetmaker.h
Normal file
@ -0,0 +1,146 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef _ETH_PACKETMAKER_H_
|
||||
#define _ETH_PACKETMAKER_H_
|
||||
|
||||
#ifdef ETH_ARPBACK
|
||||
|
||||
static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
|
||||
static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
|
||||
static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
|
||||
static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
|
||||
static const Bit8u ethtype_ip[]={0x08, 0x00, 0x00};
|
||||
static const Bit8u prot_udp=17;
|
||||
static const Bit8u prot_tcp=6;
|
||||
|
||||
|
||||
class eth_packet {
|
||||
public:
|
||||
Bit8u buf[BX_PACKET_BUFSIZE];
|
||||
Bit32u len;
|
||||
};
|
||||
|
||||
|
||||
class eth_packetmaker {
|
||||
public:
|
||||
virtual bx_bool getpacket(eth_packet& inpacket) = 0;
|
||||
virtual bx_bool ishandler(const eth_packet& outpacket) = 0;
|
||||
virtual bx_bool sendpacket(const eth_packet& outpacket) = 0;
|
||||
};
|
||||
|
||||
|
||||
class eth_ARPmaker : public eth_packetmaker {
|
||||
public:
|
||||
void init(void);
|
||||
bx_bool ishandler(const eth_packet& outpacket);
|
||||
bx_bool sendpacket(const eth_packet& outpacket);
|
||||
bx_bool getpacket(eth_packet& inpacket);
|
||||
private:
|
||||
eth_packet pending;
|
||||
bx_bool is_pending;
|
||||
};
|
||||
|
||||
|
||||
class eth_IPmaker : eth_packetmaker {
|
||||
public:
|
||||
void init(void);
|
||||
virtual bx_bool ishandler(const eth_packet& outpacket)=0;
|
||||
virtual bx_bool sendpacket(const eth_packet& outpacket)=0;
|
||||
virtual bx_bool getpacket(eth_packet& inpacket)=0;
|
||||
|
||||
protected:
|
||||
bx_bool sendable(const eth_packet& outpacket);
|
||||
|
||||
Bit32u source(const eth_packet& outpacket);
|
||||
Bit32u destination(const eth_packet& outpacket);
|
||||
Bit8u protocol(const eth_packet& outpacket);
|
||||
|
||||
const Bit8u * datagram(const eth_packet& outpacket);
|
||||
Bit32u datalen(const eth_packet& outpacket);
|
||||
|
||||
//Build a header in pending, return header length in bytes.
|
||||
Bit32u build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen);
|
||||
|
||||
eth_packet pending;
|
||||
bx_bool is_pending;
|
||||
|
||||
//Bit8u Version; //=4 (4 bits)
|
||||
//It better be!
|
||||
|
||||
//Bit8u IHL; //Header length in 32-bit bytes (4 bits)
|
||||
//Used to strip layer
|
||||
|
||||
//Bit8u Type_of_Service; //not relevent, set to 0;
|
||||
//Ignore on receive, set to 0 on send.
|
||||
|
||||
//Bit16u Total_Length;//length of the datagram in octets. use 576 or less;
|
||||
//Use 576 or less on send.
|
||||
//Use to get length on receive
|
||||
|
||||
//Bit16u Identification;//Identifier for assembling fragments
|
||||
//Ignore, we'll drop fragments
|
||||
|
||||
//Bit8u Flags;//0,Don't fragment, More Fragments (vs last fragment)
|
||||
//Set to 0 on send
|
||||
//Drop if more fragments set.
|
||||
|
||||
//Bit16u Fragment Offset;//where in the datagram this fragment belongs
|
||||
//Should be 0 for send and receive.
|
||||
|
||||
//Bit8u TTL;//Set to something sorta big.
|
||||
//Shouldn't be 0 on receive
|
||||
//Set to something big on send
|
||||
|
||||
//Bit8u Protocol;
|
||||
//Defines Protocol.
|
||||
//TCP=?, UDP=?
|
||||
|
||||
//Bit16u Header_Checksum;//16-bit one's complement of the one's complement
|
||||
//sum of all 16-bit words in header;
|
||||
//Could check on receive, must set on send.
|
||||
|
||||
//Bit32u Source;//source address
|
||||
//Bit32u Destination;//destination address
|
||||
};
|
||||
|
||||
/*
|
||||
class eth_TCPmaker : eth_packetmaker {
|
||||
};
|
||||
|
||||
class eth_UDPmaker : eth_packetmaker {
|
||||
};
|
||||
*/
|
||||
|
||||
class eth_ETHmaker : public eth_packetmaker {
|
||||
public:
|
||||
//handles all packets to a MAC addr.
|
||||
void init(void);
|
||||
virtual bx_bool getpacket(eth_packet& inpacket);
|
||||
virtual bx_bool ishandler(const eth_packet& outpacket);
|
||||
virtual bx_bool sendpacket(const eth_packet& outpacket);
|
||||
private:
|
||||
eth_ARPmaker arper;
|
||||
};
|
||||
|
||||
|
||||
#endif // ETH_ARPBACK
|
||||
#endif // _ETH_PACKETMAKER_H_
|
||||
|
||||
415
bochs/iodev/eth_tap.cc
Normal file
415
bochs/iodev/eth_tap.cc
Normal file
@ -0,0 +1,415 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// eth_tap.cc - TAP interface by Bryce Denney
|
||||
//
|
||||
// Here's how to get this working. On the host machine:
|
||||
// $ su root
|
||||
// # /sbin/insmod ethertap
|
||||
// Using /lib/modules/2.2.14-5.0/net/ethertap.o
|
||||
// # mknod /dev/tap0 c 36 16 # if not already there
|
||||
// # /sbin/ifconfig tap0 10.0.0.1
|
||||
// # /sbin/route add -host 10.0.0.2 gw 10.0.0.1
|
||||
//
|
||||
// Now you have a tap0 device which you can on the ifconfig output. The
|
||||
// tap0 interface has the IP address of 10.0.0.1. The bochs machine will have
|
||||
// the IP address 10.0.0.2.
|
||||
//
|
||||
// Compile a bochs version from March 8, 2002 or later with --enable-ne2000.
|
||||
// Add this ne2k line to your .bochsrc to activate the tap device.
|
||||
// ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
|
||||
// Don't change the mac or ethmod!
|
||||
//
|
||||
// Boot up DLX Linux in Bochs. Log in as root and then type the following
|
||||
// commands to set up networking:
|
||||
// # ifconfig eth0 10.0.0.2
|
||||
// # route add -net 10.0.0.0
|
||||
// # route add default gw 10.0.0.1
|
||||
// Now you should be able to ping from guest OS to your host machine, if
|
||||
// you give its IP number. I'm still having trouble with pings from the
|
||||
// host machine to the guest, so something is still not right. Symptoms: I
|
||||
// ping from the host to the guest's IP address 10.0.0.2. With tcpdump I can
|
||||
// see the ping going to Bochs, and then the ping reply coming from Bochs.
|
||||
// But the ping program itself does not see the responses....well every
|
||||
// once in a while it does, like 1 in 60 pings.
|
||||
//
|
||||
// host$ ping 10.0.0.2
|
||||
// PING 10.0.0.2 (10.0.0.2) from 10.0.0.1 : 56(84) bytes of data.
|
||||
//
|
||||
// Netstat output:
|
||||
// 20:29:59.018776 fe:fd:0:0:0:0 fe:fd:0:0:0:1 0800 98: 10.0.0.1 > 10.0.0.2: icmp: echo request
|
||||
// 4500 0054 2800 0000 4001 3ea7 0a00 0001
|
||||
// 0a00 0002 0800 09d3 a53e 0400 9765 893c
|
||||
// 3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
|
||||
// 1415 1617 1819
|
||||
// 20:29:59.023017 fe:fd:0:0:0:1 fe:fd:0:0:0:0 0800 98: 10.0.0.2 > 10.0.0.1: icmp: echo reply
|
||||
// 4500 0054 004a 0000 4001 665d 0a00 0002
|
||||
// 0a00 0001 0000 11d3 a53e 0400 9765 893c
|
||||
// 3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
|
||||
// 1415 1617 1819
|
||||
//
|
||||
// I suspect it may be related to the fact that ping 10.0.0.1 from the
|
||||
// host also doesn't work. Why wouldn't the host respond to its own IP
|
||||
// address on the tap0 device?
|
||||
//
|
||||
// Theoretically, if you set up packet forwarding (with masquerading) on the
|
||||
// host, you should be able to get Bochs talking to anyone on the internet.
|
||||
//
|
||||
|
||||
// Pavel Dufek (PD), CZ, 2008 - quick & dirty hack for Solaris 10 sparc tap
|
||||
// ala Qemu.
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(HAVE_ETHERTAP)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef __APPLE__
|
||||
#include <sys/poll.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
#if defined(__linux__)
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if.h>
|
||||
#elif BX_HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#if defined(__sun__)
|
||||
// Sun/Solaris specific defines/includes
|
||||
#define TUNNEWPPA (('T'<<16) | 0x0001)
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
|
||||
#define BX_ETH_TAP_LOGGING 0
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_tap_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_tap_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
int fd;
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer ();
|
||||
Bit8u guest_macaddr[6];
|
||||
#if BX_ETH_TAP_LOGGING
|
||||
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_tap_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_tap_locator_c(void) : eth_locator_c("tap") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_tap_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_tap_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_tap_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
int flags;
|
||||
char filename[BX_PATHNAME_LEN];
|
||||
|
||||
this->netdev = dev;
|
||||
if (strncmp (netif, "tap", 3) != 0) {
|
||||
BX_PANIC(("eth_tap: interface name (%s) must be tap0..tap15", netif));
|
||||
}
|
||||
#if defined(__sun__)
|
||||
strcpy(filename,"/dev/tap"); /* PD - device on Solaris is always the same */
|
||||
#else
|
||||
sprintf(filename, "/dev/%s", netif);
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
// check if the TAP devices is running, and turn on ARP. This is based
|
||||
// on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
BX_PANIC(("socket creation: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
|
||||
if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
BX_PANIC(("SIOCGIFFLAGS on %s: %s", netif, strerror(errno)));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
if (!(ifr.ifr_flags & IFF_RUNNING)) {
|
||||
BX_PANIC(("%s device is not running", netif));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
if ((ifr.ifr_flags & IFF_NOARP)){
|
||||
BX_INFO(("turn on ARP for %s device", netif));
|
||||
ifr.ifr_flags &= ~IFF_NOARP;
|
||||
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
BX_PANIC(("SIOCSIFFLAGS: %s", strerror(errno)));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
#endif
|
||||
|
||||
fd = open (filename, O_RDWR);
|
||||
if (fd < 0) {
|
||||
BX_PANIC(("open failed on TAP %s: %s", netif, strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
char *ptr; /* PD - ppa allocation ala qemu */
|
||||
char my_dev[10]; /* enough ... */
|
||||
int ppa=-1;
|
||||
struct strioctl strioc_ppa;
|
||||
|
||||
my_dev[10-1]=0;
|
||||
strncpy(my_dev,netif,10); /* following ptr= does not work with const char* */
|
||||
if( *my_dev ) { /* find the ppa number X from string tapX */
|
||||
ptr = my_dev;
|
||||
while( *ptr && !isdigit((int)*ptr) ) ptr++;
|
||||
ppa = atoi(ptr);
|
||||
}
|
||||
/* Assign a new PPA and get its unit number. */
|
||||
strioc_ppa.ic_cmd = TUNNEWPPA;
|
||||
strioc_ppa.ic_timout = 0;
|
||||
strioc_ppa.ic_len = sizeof(ppa);
|
||||
strioc_ppa.ic_dp = (char *)&ppa;
|
||||
if ((ppa = ioctl (fd, I_STR, &strioc_ppa)) < 0)
|
||||
BX_PANIC(("Can't assign new interface tap%d !",ppa));
|
||||
#endif
|
||||
|
||||
/* set O_ASYNC flag so that we can poll with read() */
|
||||
if ((flags = fcntl(fd, F_GETFL)) < 0) {
|
||||
BX_PANIC(("getflags on tap device: %s", strerror(errno)));
|
||||
}
|
||||
flags |= O_NONBLOCK;
|
||||
if (fcntl(fd, F_SETFL, flags) < 0) {
|
||||
BX_PANIC(("set tap device flags: %s", strerror(errno)));
|
||||
}
|
||||
|
||||
BX_INFO(("tap network drive: opened %s device", netif));
|
||||
|
||||
/* Execute the configuration script */
|
||||
char intname[IFNAMSIZ];
|
||||
strcpy(intname,netif);
|
||||
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
|
||||
{
|
||||
if (execute_script(this->netdev, script, intname) < 0)
|
||||
BX_ERROR(("execute script '%s' on %s failed", script, intname));
|
||||
}
|
||||
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
|
||||
1, 1, "eth_tap"); // continuous, active
|
||||
this->rxh = rxh;
|
||||
memcpy(&guest_macaddr[0], macaddr, 6);
|
||||
#if BX_ETH_TAP_LOGGING
|
||||
// eventually Bryce wants txlog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
txlog = fopen("ne2k-tx.log", "wb");
|
||||
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
|
||||
txlog_txt = fopen("ne2k-txdump.txt", "wb");
|
||||
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
|
||||
fprintf(txlog_txt, "tap packetmover readable log file\n");
|
||||
fprintf(txlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(txlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(txlog_txt, "\n--\n");
|
||||
fflush(txlog_txt);
|
||||
|
||||
rxlog = fopen("ne2k-rx.log", "wb");
|
||||
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
|
||||
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
|
||||
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
|
||||
fprintf(rxlog_txt, "tap packetmover readable log file\n");
|
||||
fprintf(rxlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(rxlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(rxlog_txt, "\n--\n");
|
||||
fflush(rxlog_txt);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_tap_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
Bit8u txbuf[BX_PACKET_BUFSIZE];
|
||||
txbuf[0] = 0;
|
||||
txbuf[1] = 0;
|
||||
unsigned int size;
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__APPLE__) || defined(__OpenBSD__) || defined(__sun__) // Should be fixed for other *BSD
|
||||
memcpy(txbuf, buf, io_len);
|
||||
/* PD - for Sun variant the retry cycle from qemu - mainly to be sure packet
|
||||
is really out */
|
||||
#if defined(__sun__)
|
||||
int ret;
|
||||
for(;;) {
|
||||
ret=write(fd, txbuf, io_len);
|
||||
if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
|
||||
} else {
|
||||
size=ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else /* not defined __sun__ */
|
||||
size = write(fd, txbuf, io_len);
|
||||
#endif /* whole condition about defined __sun__ */
|
||||
if (size != io_len) {
|
||||
#else /* not bsd/apple/sun style */
|
||||
memcpy(txbuf+2, buf, io_len);
|
||||
size = write(fd, txbuf, io_len+2);
|
||||
if (size != io_len+2) {
|
||||
#endif
|
||||
BX_PANIC(("write on tap device: %s", strerror(errno)));
|
||||
} else {
|
||||
BX_DEBUG(("wrote %d bytes + ev. 2 byte pad on tap", io_len));
|
||||
}
|
||||
#if BX_ETH_TAP_LOGGING
|
||||
BX_DEBUG(("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(buf, io_len, 1, txlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to txlog failed, io_len = %u", io_len));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(txlog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_tap_pktmover_c::rx_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_tap_pktmover_c *class_ptr = (bx_tap_pktmover_c *) this_ptr;
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void bx_tap_pktmover_c::rx_timer()
|
||||
{
|
||||
int nbytes;
|
||||
Bit8u buf[BX_PACKET_BUFSIZE];
|
||||
Bit8u *rxbuf;
|
||||
if (fd<0) return;
|
||||
#if defined(__sun__)
|
||||
struct strbuf sbuf;
|
||||
int f = 0;
|
||||
sbuf.maxlen = sizeof(buf);
|
||||
sbuf.buf = (char *)buf;
|
||||
nbytes = getmsg(fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
|
||||
#else
|
||||
nbytes = read (fd, buf, sizeof(buf));
|
||||
#endif
|
||||
|
||||
// hack: discard first two bytes
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__sun__) // Should be fixed for other *BSD
|
||||
rxbuf = buf;
|
||||
#else
|
||||
rxbuf = buf+2;
|
||||
nbytes-=2;
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
// hack: TAP device likes to create an ethernet header which has
|
||||
// the same source and destination address FE:FD:00:00:00:00.
|
||||
// Change the dest address to FE:FD:00:00:00:01.
|
||||
if (!memcmp(&rxbuf[0], &rxbuf[6], 6)) {
|
||||
rxbuf[5] = guest_macaddr[5];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nbytes>0)
|
||||
BX_DEBUG(("tap read returned %d bytes", nbytes));
|
||||
if (nbytes<0) {
|
||||
if (errno != EAGAIN)
|
||||
BX_ERROR(("tap read error: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
#if BX_ETH_TAP_LOGGING
|
||||
if (nbytes > 0) {
|
||||
BX_DEBUG(("receive packet length %u", nbytes));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(rxbuf, nbytes, 1, rxlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to rxlog failed, nbytes = %d", nbytes));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(rxlog);
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("eth_tap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
|
||||
if (nbytes < 60) {
|
||||
BX_INFO(("packet too short (%d), padding to 60", nbytes));
|
||||
nbytes = 60;
|
||||
}
|
||||
(*rxh)(netdev, rxbuf, nbytes);
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined HAVE_ETHERTAP */
|
||||
381
bochs/iodev/eth_tuntap.cc
Normal file
381
bochs/iodev/eth_tuntap.cc
Normal file
@ -0,0 +1,381 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// eth_tuntap.cc - TUN/TAP interface by Renzo Davoli <renzo@cs.unibo.it>
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(HAVE_TUNTAP)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define DIFNAMSIZ (IFNAMSIZ*2)
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef __APPLE__
|
||||
#include <sys/poll.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#ifdef __linux__
|
||||
#include <asm/types.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
#include <net/if_tap.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define BX_ETH_TUNTAP_LOGGING 0
|
||||
|
||||
int tun_alloc(char *dev);
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_tuntap_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_tuntap_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
int fd;
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer ();
|
||||
Bit8u guest_macaddr[6];
|
||||
#if BX_ETH_TUNTAP_LOGGING
|
||||
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_tuntap_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_tuntap_locator_c(void) : eth_locator_c("tuntap") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_tuntap_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_tuntap_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_tuntap_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_tuntap_pktmover_c::bx_tuntap_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
int flags;
|
||||
|
||||
this->netdev = dev;
|
||||
#ifdef NEVERDEF
|
||||
if (strncmp (netif, "tun", 3) != 0) {
|
||||
BX_PANIC(("eth_tuntap: interface name (%s) must be tun", netif));
|
||||
}
|
||||
char filename[BX_PATHNAME_LEN];
|
||||
sprintf(filename, "/dev/net/%s", netif);
|
||||
|
||||
// check if the TUN/TAP devices is running, and turn on ARP. This is based
|
||||
// on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
BX_PANIC(("socket creation: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
BX_PANIC(("SIOCGIFFLAGS on %s: %s", netif, strerror (errno)));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
if (!(ifr.ifr_flags & IFF_RUNNING)) {
|
||||
BX_PANIC(("%s device is not running", netif));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
if ((ifr.ifr_flags & IFF_NOARP)) {
|
||||
BX_INFO(("turn on ARP for %s device", netif));
|
||||
ifr.ifr_flags &= ~IFF_NOARP;
|
||||
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
BX_PANIC(("SIOCSIFFLAGS: %s", strerror(errno)));
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
|
||||
fd = open (filename, O_RDWR);
|
||||
#endif
|
||||
char intname[DIFNAMSIZ];
|
||||
strncpy(intname,netif, DIFNAMSIZ);
|
||||
fd=tun_alloc(intname);
|
||||
if (fd < 0) {
|
||||
BX_PANIC(("open failed on %s: %s", netif, strerror (errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* set O_ASYNC flag so that we can poll with read() */
|
||||
if ((flags = fcntl(fd, F_GETFL)) < 0) {
|
||||
BX_PANIC(("getflags on tun device: %s", strerror (errno)));
|
||||
}
|
||||
flags |= O_NONBLOCK;
|
||||
if (fcntl(fd, F_SETFL, flags) < 0) {
|
||||
BX_PANIC(("set tun device flags: %s", strerror (errno)));
|
||||
}
|
||||
|
||||
BX_INFO(("tuntap network driver: opened %s device", netif));
|
||||
|
||||
/* Execute the configuration script */
|
||||
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
|
||||
{
|
||||
if (execute_script(this->netdev, script, intname) < 0)
|
||||
BX_ERROR(("execute script '%s' on %s failed", script, intname));
|
||||
}
|
||||
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
|
||||
1, 1, "eth_tuntap"); // continuous, active
|
||||
this->rxh = rxh;
|
||||
memcpy(&guest_macaddr[0], macaddr, 6);
|
||||
#if BX_ETH_TUNTAP_LOGGING
|
||||
// eventually Bryce wants txlog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
txlog = fopen("ne2k-tx.log", "wb");
|
||||
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
|
||||
txlog_txt = fopen("ne2k-txdump.txt", "wb");
|
||||
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
|
||||
fprintf(txlog_txt, "tuntap packetmover readable log file\n");
|
||||
fprintf(txlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(txlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(txlog_txt, "\n--\n");
|
||||
fflush(txlog_txt);
|
||||
|
||||
rxlog = fopen("ne2k-rx.log", "wb");
|
||||
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
|
||||
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
|
||||
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
|
||||
fprintf(rxlog_txt, "tuntap packetmover readable log file\n");
|
||||
fprintf(rxlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(rxlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(rxlog_txt, "\n--\n");
|
||||
fflush(rxlog_txt);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_tuntap_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
#ifdef __APPLE__ //FIXME
|
||||
unsigned int size = write (fd, (char*)buf+14, io_len-14);
|
||||
if (size != io_len-14) {
|
||||
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
|
||||
} else {
|
||||
BX_DEBUG(("wrote %d bytes on tuntap - 14 bytes Ethernet header", io_len));
|
||||
}
|
||||
#elif NEVERDEF
|
||||
Bit8u txbuf[BX_PACKET_BUFSIZE];
|
||||
txbuf[0] = 0;
|
||||
txbuf[1] = 0;
|
||||
memcpy (txbuf+2, buf, io_len);
|
||||
unsigned int size = write (fd, txbuf, io_len+2);
|
||||
if (size != io_len+2) {
|
||||
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
|
||||
} else {
|
||||
BX_DEBUG(("wrote %d bytes + 2 byte pad on tuntap", io_len));
|
||||
}
|
||||
#else
|
||||
unsigned int size = write (fd, buf, io_len);
|
||||
if (size != io_len) {
|
||||
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
|
||||
} else {
|
||||
BX_DEBUG(("wrote %d bytes on tuntap", io_len));
|
||||
}
|
||||
#endif
|
||||
#if BX_ETH_TUNTAP_LOGGING
|
||||
BX_DEBUG(("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(buf, io_len, 1, txlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to txlog failed"));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(txlog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_tuntap_pktmover_c::rx_timer_handler (void *this_ptr)
|
||||
{
|
||||
bx_tuntap_pktmover_c *class_ptr = (bx_tuntap_pktmover_c *) this_ptr;
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void bx_tuntap_pktmover_c::rx_timer()
|
||||
{
|
||||
int nbytes;
|
||||
Bit8u buf[BX_PACKET_BUFSIZE];
|
||||
Bit8u *rxbuf;
|
||||
if (fd<0) return;
|
||||
|
||||
#ifdef __APPLE__ //FIXME:hack
|
||||
nbytes = 14;
|
||||
bzero(buf, nbytes);
|
||||
buf[0] = buf[6] = 0xFE;
|
||||
buf[1] = buf[7] = 0xFD;
|
||||
buf[12] = 8;
|
||||
nbytes += read (fd, buf+nbytes, sizeof(buf)-nbytes);
|
||||
rxbuf=buf;
|
||||
#elif NEVERDEF
|
||||
nbytes = read (fd, buf, sizeof(buf));
|
||||
// hack: discard first two bytes
|
||||
rxbuf = buf+2;
|
||||
nbytes-=2;
|
||||
#else
|
||||
nbytes = read (fd, buf, sizeof(buf));
|
||||
rxbuf=buf;
|
||||
#endif
|
||||
|
||||
// hack: TUN/TAP device likes to create an ethernet header which has
|
||||
// the same source and destination address FE:FD:00:00:00:00.
|
||||
// Change the dest address to FE:FD:00:00:00:01.
|
||||
if (!memcmp(&rxbuf[0], &rxbuf[6], 6)) {
|
||||
rxbuf[5] = guest_macaddr[5];
|
||||
}
|
||||
|
||||
#ifdef __APPLE__ //FIXME:hack
|
||||
if (nbytes>14)
|
||||
#else
|
||||
if (nbytes>0)
|
||||
#endif
|
||||
BX_DEBUG(("tuntap read returned %d bytes", nbytes));
|
||||
#ifdef __APPLE__ //FIXME:hack
|
||||
if (nbytes<14) {
|
||||
#else
|
||||
if (nbytes<0) {
|
||||
#endif
|
||||
if (errno != EAGAIN)
|
||||
BX_ERROR(("tuntap read error: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
#if BX_ETH_TUNTAP_LOGGING
|
||||
if (nbytes > 0) {
|
||||
BX_DEBUG(("receive packet length %u", nbytes));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(rxbuf, nbytes, 1, rxlog);
|
||||
if (n != 1) BX_ERROR (("fwrite to rxlog failed"));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(rxlog);
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("eth_tuntap: got packet: %d bytes, dst=%02x:%02x:%02x:%02x:%02x:%02x, src=%02x:%02x:%02x:%02x:%02x:%02x", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
|
||||
if (nbytes < 60) {
|
||||
BX_INFO(("packet too short (%d), padding to 60", nbytes));
|
||||
nbytes = 60;
|
||||
}
|
||||
(*rxh)(this->netdev, rxbuf, nbytes);
|
||||
}
|
||||
|
||||
int tun_alloc(char *dev)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
char *ifname;
|
||||
int fd, err;
|
||||
|
||||
// split name into device:ifname if applicable, to allow for opening
|
||||
// persistent tuntap devices
|
||||
for (ifname = dev; *ifname; ifname++) {
|
||||
if (*ifname == ':') {
|
||||
*(ifname++) = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((fd = open(dev, O_RDWR)) < 0)
|
||||
return -1;
|
||||
#ifdef __linux__
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
|
||||
* IFF_TAP - TAP device
|
||||
*
|
||||
* IFF_NO_PI - Do not provide packet information
|
||||
*/
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
strncpy(dev, ifr.ifr_name, IFNAMSIZ);
|
||||
dev[IFNAMSIZ-1]=0;
|
||||
|
||||
ioctl(fd, TUNSETNOCSUM, 1);
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined HAVE_TUNTAP */
|
||||
327
bochs/iodev/eth_vde.cc
Normal file
327
bochs/iodev/eth_vde.cc
Normal file
@ -0,0 +1,327 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2003 Renzo Davoli
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// eth_vde.cc - Virtual Distributed Ethernet interface by Renzo Davoli <renzo@cs.unibo.it>
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(HAVE_VDE)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#if defined(__linux__)
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if.h>
|
||||
#elif BX_HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define SWITCH_MAGIC 0xfeedface
|
||||
|
||||
#define BX_ETH_VDE_LOGGING 0
|
||||
|
||||
int vde_alloc(char *dev,int *fdp,struct sockaddr_un *pdataout);
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_vde_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_vde_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
int fd;
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer();
|
||||
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
|
||||
int fddata;
|
||||
struct sockaddr_un dataout;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_vde_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_vde_locator_c(void) : eth_locator_c("vde") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_vde_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_vde_match;
|
||||
|
||||
|
||||
//
|
||||
// Define the methods for the bx_vde_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_vde_pktmover_c::bx_vde_pktmover_c(const char *netif,
|
||||
const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev,
|
||||
const char *script)
|
||||
{
|
||||
int flags;
|
||||
|
||||
this->netdev = dev;
|
||||
//if (strncmp (netif, "vde", 3) != 0) {
|
||||
// BX_PANIC (("eth_vde: interface name (%s) must be vde", netif));
|
||||
//}
|
||||
char intname[IFNAMSIZ];
|
||||
if (netif == NULL || strcmp(netif,"") == 0)
|
||||
strcpy(intname,"/tmp/vde.ctl");
|
||||
else
|
||||
strcpy(intname,netif);
|
||||
fd=vde_alloc(intname,&fddata,&dataout);
|
||||
if (fd < 0) {
|
||||
BX_PANIC(("open failed on %s: %s", netif, strerror (errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* set O_ASYNC flag so that we can poll with read() */
|
||||
if ((flags = fcntl(fd, F_GETFL)) < 0) {
|
||||
BX_PANIC(("getflags on vde device: %s", strerror (errno)));
|
||||
}
|
||||
flags |= O_NONBLOCK;
|
||||
if (fcntl(fd, F_SETFL, flags) < 0) {
|
||||
BX_PANIC(("set vde device flags: %s", strerror (errno)));
|
||||
}
|
||||
|
||||
BX_INFO(("eth_vde: opened %s device", netif));
|
||||
|
||||
/* Execute the configuration script */
|
||||
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
|
||||
{
|
||||
if (execute_script(this->netdev, script, intname) < 0)
|
||||
BX_ERROR(("execute script '%s' on %s failed", script, intname));
|
||||
}
|
||||
|
||||
// Start the rx poll
|
||||
this->rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
|
||||
1, 1, "eth_vde"); // continuous, active
|
||||
this->rxh = rxh;
|
||||
#if BX_ETH_VDE_LOGGING
|
||||
// eventually Bryce wants txlog to dump in pcap format so that
|
||||
// tcpdump -r FILE can read it and interpret packets.
|
||||
txlog = fopen("ne2k-tx.log", "wb");
|
||||
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
|
||||
txlog_txt = fopen("ne2k-txdump.txt", "wb");
|
||||
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
|
||||
fprintf(txlog_txt, "vde packetmover readable log file\n");
|
||||
fprintf(txlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(txlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(txlog_txt, "\n--\n");
|
||||
fflush(txlog_txt);
|
||||
|
||||
rxlog = fopen("ne2k-rx.log", "wb");
|
||||
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
|
||||
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
|
||||
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
|
||||
fprintf(rxlog_txt, "vde packetmover readable log file\n");
|
||||
fprintf(rxlog_txt, "net IF = %s\n", netif);
|
||||
fprintf(rxlog_txt, "MAC address = ");
|
||||
for (int i=0; i<6; i++)
|
||||
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
|
||||
fprintf(rxlog_txt, "\n--\n");
|
||||
fflush(rxlog_txt);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_vde_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
unsigned int size;
|
||||
//size = write (fd, buf, io_len);
|
||||
//size=send(fd,buf,io_len,0);
|
||||
size=sendto(fddata,buf,io_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un));
|
||||
if (size != io_len) {
|
||||
BX_PANIC(("write on vde device: %s", strerror (errno)));
|
||||
} else {
|
||||
BX_INFO(("wrote %d bytes on vde", io_len));
|
||||
}
|
||||
#if BX_ETH_VDE_LOGGING
|
||||
BX_DEBUG(("sendpkt length %u", io_len));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(buf, io_len, 1, txlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to txlog failed"));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(txlog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_vde_pktmover_c::rx_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_vde_pktmover_c *class_ptr = (bx_vde_pktmover_c *) this_ptr;
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void bx_vde_pktmover_c::rx_timer()
|
||||
{
|
||||
int nbytes;
|
||||
Bit8u buf[BX_PACKET_BUFSIZE];
|
||||
Bit8u *rxbuf;
|
||||
struct sockaddr_un datain;
|
||||
socklen_t datainsize;
|
||||
|
||||
if (fd<0) return;
|
||||
//nbytes = read (fd, buf, sizeof(buf));
|
||||
nbytes=recvfrom(fddata,buf,sizeof(buf),MSG_DONTWAIT|MSG_WAITALL,(struct sockaddr *) &datain, &datainsize);
|
||||
|
||||
rxbuf=buf;
|
||||
|
||||
if (nbytes>0)
|
||||
BX_INFO(("vde read returned %d bytes", nbytes));
|
||||
if (nbytes<0) {
|
||||
if (errno != EAGAIN)
|
||||
BX_ERROR(("vde read error: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
#if BX_ETH_VDE_LOGGING
|
||||
if (nbytes > 0) {
|
||||
BX_DEBUG(("receive packet length %u", nbytes));
|
||||
// dump raw bytes to a file, eventually dump in pcap format so that
|
||||
// tcpdump -r FILE can interpret them for us.
|
||||
int n = fwrite(rxbuf, nbytes, 1, rxlog);
|
||||
if (n != 1) BX_ERROR(("fwrite to rxlog failed"));
|
||||
// dump packet in hex into an ascii log file
|
||||
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
|
||||
|
||||
// flush log so that we see the packets as they arrive w/o buffering
|
||||
fflush(rxlog);
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("eth_vde: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
|
||||
if (nbytes < 60) {
|
||||
BX_INFO(("packet too short (%d), padding to 60", nbytes));
|
||||
nbytes = 60;
|
||||
}
|
||||
(*rxh)(this->netdev, rxbuf, nbytes);
|
||||
}
|
||||
|
||||
//enum request_type { REQ_NEW_CONTROL };
|
||||
#define REQ_NEW_CONTROL 0
|
||||
|
||||
struct request_v3 {
|
||||
Bit32u magic;
|
||||
Bit32u version;
|
||||
//enum request_type type;
|
||||
int type;
|
||||
struct sockaddr_un sock;
|
||||
};
|
||||
|
||||
static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int group)
|
||||
{
|
||||
int pid = getpid();
|
||||
struct request_v3 req;
|
||||
int fdctl;
|
||||
struct sockaddr_un sock;
|
||||
|
||||
if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
return(-1);
|
||||
}
|
||||
sock.sun_family = AF_UNIX;
|
||||
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
|
||||
if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))) {
|
||||
perror("connect");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
req.magic=SWITCH_MAGIC;
|
||||
req.version=3;
|
||||
req.type=((int)REQ_NEW_CONTROL)+((group > 0)?((geteuid()<<8) + group) << 8:0);
|
||||
req.sock.sun_family=AF_UNIX;
|
||||
memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
|
||||
sprintf(&req.sock.sun_path[1], "%5d", pid);
|
||||
|
||||
if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0) {
|
||||
perror("bind");
|
||||
return(-1);
|
||||
}
|
||||
if (send(fdctl,&req,sizeof(req),0) < 0) {
|
||||
perror("send");
|
||||
return(-1);
|
||||
}
|
||||
if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0) < 0) {
|
||||
perror("recv");
|
||||
return(-1);
|
||||
}
|
||||
return fdctl;
|
||||
}
|
||||
|
||||
int vde_alloc(char *dev, int *fdp, struct sockaddr_un *pdataout)
|
||||
{
|
||||
//struct ifreq ifr;
|
||||
//int err;
|
||||
int fd, fddata;
|
||||
|
||||
if ((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
if ((fd = send_fd(dev, fddata, pdataout, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
//memset(&ifr, 0, sizeof(ifr));
|
||||
*fdp=fddata;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif /* if BX_NETWORKING && defined HAVE_VDE */
|
||||
1422
bochs/iodev/eth_vnet.cc
Normal file
1422
bochs/iodev/eth_vnet.cc
Normal file
File diff suppressed because it is too large
Load Diff
386
bochs/iodev/eth_win32.cc
Normal file
386
bochs/iodev/eth_win32.cc
Normal file
@ -0,0 +1,386 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// eth_win32.cc - packet mover for win32
|
||||
// All win32 coding by Don Becker <x-odus@iname.com>
|
||||
// with patches from various sources
|
||||
//
|
||||
// Various networking docs:
|
||||
// http://www.graphcomp.com/info/rfc/
|
||||
// rfc0826: arp
|
||||
// rfc0903: rarp
|
||||
//
|
||||
// For ethernet support under win32 to work, you must install WinPCap.
|
||||
// Download it from http://netgroup-serv.polito.it/winpcap
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_NETWORKING && defined(ETH_WIN32)
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
// windows.h included by bochs.h
|
||||
#define LOG_THIS netdev->
|
||||
|
||||
#define BX_ETH_WIN32_LOGGING 0
|
||||
|
||||
#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
|
||||
#define Packet_ALIGNMENT sizeof(int)
|
||||
#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
|
||||
|
||||
typedef int bpf_int32;
|
||||
typedef u_int bpf_u_int32;
|
||||
|
||||
/*
|
||||
* The instruction encondings.
|
||||
*/
|
||||
|
||||
/* instruction classes */
|
||||
|
||||
#define BPF_CLASS(code) ((code) & 0x07)
|
||||
#define BPF_LD 0x00
|
||||
#define BPF_LDX 0x01
|
||||
#define BPF_ST 0x02
|
||||
#define BPF_STX 0x03
|
||||
#define BPF_ALU 0x04
|
||||
#define BPF_JMP 0x05
|
||||
#define BPF_RET 0x06
|
||||
#define BPF_MISC 0x07
|
||||
|
||||
/* ld/ldx fields */
|
||||
#define BPF_SIZE(code) ((code) & 0x18)
|
||||
#define BPF_W 0x00
|
||||
#define BPF_H 0x08
|
||||
#define BPF_B 0x10
|
||||
#define BPF_MODE(code) ((code) & 0xe0)
|
||||
#define BPF_IMM 0x00
|
||||
#define BPF_ABS 0x20
|
||||
#define BPF_IND 0x40
|
||||
#define BPF_MEM 0x60
|
||||
#define BPF_LEN 0x80
|
||||
#define BPF_MSH 0xa0
|
||||
|
||||
/* alu/jmp fields */
|
||||
#define BPF_OP(code) ((code) & 0xf0)
|
||||
#define BPF_ADD 0x00
|
||||
#define BPF_SUB 0x10
|
||||
#define BPF_MUL 0x20
|
||||
#define BPF_DIV 0x30
|
||||
#define BPF_OR 0x40
|
||||
#define BPF_AND 0x50
|
||||
#define BPF_LSH 0x60
|
||||
#define BPF_RSH 0x70
|
||||
#define BPF_NEG 0x80
|
||||
#define BPF_JA 0x00
|
||||
#define BPF_JEQ 0x10
|
||||
#define BPF_JGT 0x20
|
||||
#define BPF_JGE 0x30
|
||||
#define BPF_JSET 0x40
|
||||
#define BPF_SRC(code) ((code) & 0x08)
|
||||
#define BPF_K 0x00
|
||||
#define BPF_X 0x08
|
||||
|
||||
/* ret - BPF_K and BPF_X also apply */
|
||||
#define BPF_RVAL(code) ((code) & 0x18)
|
||||
#define BPF_A 0x10
|
||||
|
||||
/* misc */
|
||||
#define BPF_MISCOP(code) ((code) & 0xf8)
|
||||
#define BPF_TAX 0x00
|
||||
#define BPF_TXA 0x80
|
||||
|
||||
#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
|
||||
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
|
||||
|
||||
/*
|
||||
* The instruction data structure.
|
||||
*/
|
||||
struct bpf_insn {
|
||||
u_short code;
|
||||
u_char jt;
|
||||
u_char jf;
|
||||
bpf_int32 k;
|
||||
};
|
||||
|
||||
struct bpf_program {
|
||||
u_int bf_len;
|
||||
struct bpf_insn *bf_insns;
|
||||
};
|
||||
|
||||
struct bpf_hdr {
|
||||
struct timeval bh_tstamp; /* time stamp */
|
||||
UINT bh_caplen; /* length of captured portion */
|
||||
UINT bh_datalen; /* original length of packet */
|
||||
USHORT bh_hdrlen; /* length of bpf header (this struct
|
||||
plus alignment padding) */
|
||||
};
|
||||
|
||||
#define MAX_LINK_NAME_LENGTH 64
|
||||
|
||||
// Why don't these definitions come from including winpcap.h or something?
|
||||
// -Bryce
|
||||
typedef struct _ADAPTER {
|
||||
HANDLE hFile;
|
||||
TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
|
||||
int NumWrites;
|
||||
HANDLE ReadEvent;
|
||||
UINT ReadTimeOut; // WARNING: maybe invalid before winpcap 2.2
|
||||
} ADAPTER, *LPADAPTER;
|
||||
|
||||
typedef struct _PACKET {
|
||||
HANDLE hEvent;
|
||||
OVERLAPPED OverLapped;
|
||||
PVOID Buffer;
|
||||
UINT Length;
|
||||
UINT ulBytesReceived;
|
||||
BOOLEAN bIoComplete;
|
||||
} PACKET, *LPPACKET;
|
||||
|
||||
HINSTANCE hPacket;
|
||||
LPADAPTER lpAdapter = 0;
|
||||
LPPACKET pkSend;
|
||||
LPPACKET pkRecv;
|
||||
char buffer[256000];
|
||||
DWORD dwVersion, dwMajorVersion;
|
||||
char AdapterList[10][1024];
|
||||
char cMacAddr[6];
|
||||
char NetDev[512];
|
||||
BOOL IsNT = FALSE;
|
||||
|
||||
LPADAPTER (*PacketOpenAdapter) (LPTSTR);
|
||||
VOID (*PacketCloseAdapter) (LPADAPTER);
|
||||
BOOLEAN (*PacketSetHwFilter) (LPADAPTER, ULONG);
|
||||
BOOLEAN (*PacketSetBpf) (LPADAPTER, struct bpf_program *);
|
||||
BOOLEAN (*PacketGetAdapterNames) (PTSTR, PULONG);
|
||||
BOOLEAN (*PacketSendPacket) (LPADAPTER, LPPACKET, BOOLEAN);
|
||||
BOOLEAN (*PacketReceivePacket) (LPADAPTER, LPPACKET, BOOLEAN);
|
||||
BOOLEAN (*PacketSetBuff) (LPADAPTER, int);
|
||||
BOOLEAN (*PacketSetReadTimeout) (LPADAPTER, int);
|
||||
LPPACKET (*PacketAllocatePacket) (void);
|
||||
VOID (*PacketInitPacket) (LPPACKET, PVOID, UINT);
|
||||
VOID (*PacketFreePacket) (LPPACKET);
|
||||
|
||||
// template filter for a unicast mac address and all
|
||||
// multicast/broadcast frames
|
||||
static const struct bpf_insn macfilter[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
|
||||
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
|
||||
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
|
||||
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
|
||||
BPF_STMT(BPF_RET, 1514),
|
||||
BPF_STMT(BPF_RET, 0),
|
||||
};
|
||||
|
||||
//
|
||||
// Define the class. This is private to this module
|
||||
//
|
||||
class bx_win32_pktmover_c : public eth_pktmover_c {
|
||||
public:
|
||||
bx_win32_pktmover_c(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh, bx_devmodel_c *dev,
|
||||
const char *script);
|
||||
void sendpkt(void *buf, unsigned io_len);
|
||||
private:
|
||||
struct bpf_insn filter[8];
|
||||
int rx_timer_index;
|
||||
static void rx_timer_handler(void *);
|
||||
void rx_timer(void);
|
||||
#if BX_ETH_WIN32_LOGGING
|
||||
FILE *pktlog_txt;
|
||||
#endif
|
||||
};
|
||||
|
||||
//
|
||||
// Define the static class that registers the derived pktmover class,
|
||||
// and allocates one on request.
|
||||
//
|
||||
class bx_win32_locator_c : public eth_locator_c {
|
||||
public:
|
||||
bx_win32_locator_c(void) : eth_locator_c("win32") {}
|
||||
protected:
|
||||
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh,
|
||||
bx_devmodel_c *dev, const char *script) {
|
||||
return (new bx_win32_pktmover_c(netif, macaddr, rxh, dev, script));
|
||||
}
|
||||
} bx_win32_match;
|
||||
|
||||
//
|
||||
// Define the methods for the bx_win32_pktmover derived class
|
||||
//
|
||||
|
||||
// the constructor
|
||||
bx_win32_pktmover_c::bx_win32_pktmover_c(
|
||||
const char *netif, const char *macaddr,
|
||||
eth_rx_handler_t rxh, bx_devmodel_c *dev, const char *script)
|
||||
{
|
||||
this->netdev = dev;
|
||||
BX_INFO(("win32 network driver"));
|
||||
// Open Packet Driver Here.
|
||||
DWORD dwVersion;
|
||||
DWORD dwWindowsMajorVersion;
|
||||
|
||||
this->rxh = rxh;
|
||||
|
||||
hPacket = LoadLibrary("PACKET.DLL");
|
||||
memcpy(cMacAddr, macaddr, 6);
|
||||
if (hPacket) {
|
||||
PacketOpenAdapter = (LPADAPTER (*)(LPTSTR)) GetProcAddress(hPacket, "PacketOpenAdapter");
|
||||
PacketCloseAdapter = (VOID (*)(LPADAPTER)) GetProcAddress(hPacket, "PacketCloseAdapter");
|
||||
PacketSetHwFilter = (BOOLEAN (*)(LPADAPTER, ULONG)) GetProcAddress(hPacket, "PacketSetHwFilter");
|
||||
PacketSetBpf = (BOOLEAN (*)(LPADAPTER, struct bpf_program *)) GetProcAddress(hPacket, "PacketSetBpf");
|
||||
PacketGetAdapterNames = (BOOLEAN (*)(PTSTR, PULONG)) GetProcAddress(hPacket, "PacketGetAdapterNames");
|
||||
PacketSendPacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketSendPacket");
|
||||
PacketReceivePacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketReceivePacket");
|
||||
PacketSetBuff = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetBuff");
|
||||
PacketSetReadTimeout = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetReadTimeout");
|
||||
PacketAllocatePacket = (LPPACKET (*)(void)) GetProcAddress(hPacket, "PacketAllocatePacket");
|
||||
PacketInitPacket = (VOID (*)(LPPACKET, PVOID, UINT)) GetProcAddress(hPacket, "PacketInitPacket");
|
||||
PacketFreePacket = (VOID (*)(LPPACKET)) GetProcAddress(hPacket, "PacketFreePacket");
|
||||
} else {
|
||||
BX_PANIC(("Could not load WPCap Drivers for ethernet support!"));
|
||||
}
|
||||
|
||||
memset(&NetDev, 0, sizeof(NetDev));
|
||||
dwVersion=GetVersion();
|
||||
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
|
||||
if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4))
|
||||
{ // Windows NT/2k
|
||||
int nLen = MultiByteToWideChar(CP_ACP, 0, netif, -1, NULL, 0);
|
||||
MultiByteToWideChar(CP_ACP, 0, netif, -1, (WCHAR *)NetDev, nLen);
|
||||
IsNT = TRUE;
|
||||
} else { // Win9x
|
||||
strcpy(NetDev, netif);
|
||||
}
|
||||
|
||||
lpAdapter = PacketOpenAdapter(NetDev);
|
||||
if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) {
|
||||
BX_PANIC(("Could not open adapter for ethernet reception"));
|
||||
return;
|
||||
}
|
||||
PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS);
|
||||
|
||||
/* The code below sets a BPF mac address filter
|
||||
that seems to really kill performance, for now
|
||||
im just using code to filter, and it works
|
||||
better
|
||||
*/
|
||||
|
||||
// memcpy(&this->filter, macfilter, sizeof(macfilter));
|
||||
// this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 | (macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
|
||||
// this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
|
||||
// bp.bf_len = 8;
|
||||
// bp.bf_insns = &this->filter[0];
|
||||
// if (!PacketSetBpf(lpAdapter, &bp)) {
|
||||
// BX_PANIC(("Could not set mac address BPF filter"));
|
||||
// }
|
||||
|
||||
PacketSetBuff(lpAdapter, 512000);
|
||||
PacketSetReadTimeout(lpAdapter, -1);
|
||||
|
||||
if ((pkSend = PacketAllocatePacket()) == NULL) {
|
||||
BX_PANIC(("Could not allocate a send packet"));
|
||||
}
|
||||
|
||||
if ((pkRecv = PacketAllocatePacket()) == NULL) {
|
||||
BX_PANIC(("Could not allocate a recv packet"));
|
||||
}
|
||||
rx_timer_index =
|
||||
bx_pc_system.register_timer(this, this->rx_timer_handler, 10000, 1, 1, "eth_win32");
|
||||
|
||||
#if BX_ETH_WIN32_LOGGING
|
||||
pktlog_txt = fopen("ne2k-pktlog.txt", "wb");
|
||||
if (!pktlog_txt) BX_PANIC(("ne2k-pktlog.txt failed"));
|
||||
fprintf(pktlog_txt, "win32 packetmover readable log file\n");
|
||||
fprintf(pktlog_txt, "host adapter = %s\n", netif);
|
||||
fprintf(pktlog_txt, "guest MAC address = ");
|
||||
int i;
|
||||
for (i=0; i<6; i++)
|
||||
fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "\n");
|
||||
fprintf(pktlog_txt, "--\n");
|
||||
fflush(pktlog_txt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_win32_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
||||
{
|
||||
#if BX_ETH_WIN32_LOGGING
|
||||
write_pktlog_txt(pktlog_txt, (const Bit8u *)buf, io_len, 0);
|
||||
#endif
|
||||
|
||||
// SendPacket Here.
|
||||
PacketInitPacket(pkSend, (char *)buf, io_len);
|
||||
|
||||
if (!PacketSendPacket(lpAdapter, pkSend, TRUE)) {
|
||||
fprintf(stderr, "[ETH-WIN32] Error sending packet: %lu\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void bx_win32_pktmover_c::rx_timer_handler (void *this_ptr)
|
||||
{
|
||||
bx_win32_pktmover_c *class_ptr = (bx_win32_pktmover_c *) this_ptr;
|
||||
|
||||
class_ptr->rx_timer();
|
||||
}
|
||||
|
||||
void bx_win32_pktmover_c::rx_timer(void)
|
||||
{
|
||||
// Recieve Packet ????
|
||||
char *pBuf;
|
||||
unsigned char *pPacket;
|
||||
unsigned int iOffset = 0;
|
||||
struct bpf_hdr *hdr;
|
||||
int pktlen;
|
||||
|
||||
PacketInitPacket(pkRecv, (char *)buffer, 256000);
|
||||
if (WaitForSingleObject(lpAdapter->ReadEvent,0) == WAIT_OBJECT_0 || IsNT) {
|
||||
PacketReceivePacket(lpAdapter, pkRecv, TRUE);
|
||||
pBuf = (char *)pkRecv->Buffer;
|
||||
iOffset = 0;
|
||||
while(iOffset < pkRecv->ulBytesReceived)
|
||||
{
|
||||
hdr = (struct bpf_hdr *)(pBuf + iOffset);
|
||||
pPacket = (unsigned char *)(pBuf + iOffset + hdr->bh_hdrlen);
|
||||
if (memcmp(pPacket + 6, cMacAddr, 6) != 0) // src field != ours
|
||||
{
|
||||
if(memcmp(pPacket, cMacAddr, 6) == 0 || memcmp(pPacket, broadcast_macaddr, 6) == 0)
|
||||
{
|
||||
pktlen = hdr->bh_caplen;
|
||||
if (pktlen < 60) pktlen = 60;
|
||||
#if BX_ETH_WIN32_LOGGING
|
||||
write_pktlog_txt(pktlog_txt, pPacket, pktlen, 1);
|
||||
#endif
|
||||
(*this->rxh)(this->netdev, pPacket, pktlen);
|
||||
}
|
||||
}
|
||||
iOffset = Packet_WORDALIGN(iOffset + (hdr->bh_hdrlen + hdr->bh_caplen));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* if BX_NETWORKING && defined ETH_WIN32 */
|
||||
90
bochs/iodev/extfpuirq.cc
Normal file
90
bochs/iodev/extfpuirq.cc
Normal file
@ -0,0 +1,90 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// External circuit for MSDOS compatible FPU exceptions
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "extfpuirq.h"
|
||||
|
||||
#define LOG_THIS theExternalFpuIrq->
|
||||
|
||||
bx_extfpuirq_c *theExternalFpuIrq = NULL;
|
||||
|
||||
int libextfpuirq_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theExternalFpuIrq = new bx_extfpuirq_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theExternalFpuIrq, BX_PLUGIN_EXTFPUIRQ);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libextfpuirq_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theExternalFpuIrq;
|
||||
}
|
||||
|
||||
bx_extfpuirq_c::bx_extfpuirq_c(void)
|
||||
{
|
||||
put("EFIRQ");
|
||||
}
|
||||
|
||||
bx_extfpuirq_c::~bx_extfpuirq_c(void)
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_extfpuirq_c::init(void)
|
||||
{
|
||||
// called once when bochs initializes
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x00F0, "External FPU IRQ", 1);
|
||||
DEV_register_irq(13, "External FPU IRQ");
|
||||
}
|
||||
|
||||
void bx_extfpuirq_c::reset(unsigned type)
|
||||
{
|
||||
// We should handle IGNNE here
|
||||
DEV_pic_lower_irq(13);
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_extfpuirq_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_EFI_SMF
|
||||
bx_extfpuirq_c *class_ptr = (bx_extfpuirq_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_extfpuirq_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_EFI_SMF
|
||||
|
||||
// We should handle IGNNE here
|
||||
DEV_pic_lower_irq(13);
|
||||
}
|
||||
50
bochs/iodev/extfpuirq.h
Normal file
50
bochs/iodev/extfpuirq.h
Normal file
@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_EXTFPUIRQ_H
|
||||
#define BX_IODEV_EXTFPUIRQ_H
|
||||
|
||||
|
||||
#if BX_USE_EFI_SMF
|
||||
# define BX_EXTFPUIRQ_SMF static
|
||||
# define BX_EXTFPUIRQ_THIS theExternalFpuIrq->
|
||||
#else
|
||||
# define BX_EXTFPUIRQ_SMF
|
||||
# define BX_EXTFPUIRQ_THIS this->
|
||||
#endif
|
||||
|
||||
|
||||
class bx_extfpuirq_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_extfpuirq_c();
|
||||
virtual ~bx_extfpuirq_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
|
||||
private:
|
||||
|
||||
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
|
||||
#if !BX_USE_EFI_SMF
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
1983
bochs/iodev/floppy.cc
Normal file
1983
bochs/iodev/floppy.cc
Normal file
File diff suppressed because it is too large
Load Diff
201
bochs/iodev/floppy.h
Normal file
201
bochs/iodev/floppy.h
Normal file
@ -0,0 +1,201 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_FLOPPY_H
|
||||
#define BX_IODEV_FLOPPY_H
|
||||
|
||||
#define FROM_FLOPPY 10
|
||||
#define TO_FLOPPY 11
|
||||
|
||||
#if BX_USE_FD_SMF
|
||||
# define BX_FD_SMF static
|
||||
# define BX_FD_THIS theFloppyController->
|
||||
#else
|
||||
# define BX_FD_SMF
|
||||
# define BX_FD_THIS this->
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int fd; /* file descriptor of floppy image file */
|
||||
unsigned sectors_per_track; /* number of sectors/track */
|
||||
unsigned sectors; /* number of formatted sectors on diskette */
|
||||
unsigned tracks; /* number of tracks */
|
||||
unsigned heads; /* number of heads */
|
||||
unsigned type;
|
||||
unsigned write_protected;
|
||||
unsigned char raw_floppy_win95;
|
||||
#ifdef WIN32
|
||||
unsigned char raw_floppy_win95_drv;
|
||||
#endif
|
||||
bx_bool vvfat_floppy;
|
||||
device_image_t *vvfat;
|
||||
} floppy_t;
|
||||
|
||||
class bx_floppy_ctrl_c : public bx_floppy_stub_c {
|
||||
public:
|
||||
bx_floppy_ctrl_c();
|
||||
virtual ~bx_floppy_ctrl_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual unsigned set_media_status(unsigned drive, bx_bool status);
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
|
||||
struct {
|
||||
Bit8u data_rate;
|
||||
|
||||
Bit8u command[10]; /* largest command size ??? */
|
||||
Bit8u command_index;
|
||||
Bit8u command_size;
|
||||
bx_bool command_complete;
|
||||
Bit8u pending_command;
|
||||
|
||||
bx_bool multi_track;
|
||||
bx_bool pending_irq;
|
||||
Bit8u reset_sensei;
|
||||
Bit8u format_count;
|
||||
Bit8u format_fillbyte;
|
||||
|
||||
Bit8u result[10];
|
||||
Bit8u result_index;
|
||||
Bit8u result_size;
|
||||
|
||||
Bit8u DOR; // Digital Ouput Register
|
||||
Bit8u TDR; // Tape Drive Register
|
||||
Bit8u cylinder[4]; // really only using 2 drives
|
||||
Bit8u head[4]; // really only using 2 drives
|
||||
Bit8u sector[4]; // really only using 2 drives
|
||||
Bit8u eot[4]; // really only using 2 drives
|
||||
bx_bool TC; // Terminal Count status from DMA controller
|
||||
|
||||
/* MAIN STATUS REGISTER
|
||||
* b7: MRQ: main request 1=data register ready 0=data register not ready
|
||||
* b6: DIO: data input/output:
|
||||
* 1=controller->CPU (ready for data read)
|
||||
* 0=CPU->controller (ready for data write)
|
||||
* b5: NDMA: non-DMA mode: 1=controller not in DMA modes
|
||||
* 0=controller in DMA mode
|
||||
* b4: BUSY: instruction(device busy) 1=active 0=not active
|
||||
* b3-0: ACTD, ACTC, ACTB, ACTA:
|
||||
* drive D,C,B,A in positioning mode 1=active 0=not active
|
||||
*/
|
||||
Bit8u main_status_reg;
|
||||
|
||||
Bit8u status_reg0;
|
||||
Bit8u status_reg1;
|
||||
Bit8u status_reg2;
|
||||
Bit8u status_reg3;
|
||||
|
||||
// drive field allows up to 4 drives, even though probably only 2 will
|
||||
// ever be used.
|
||||
floppy_t media[4];
|
||||
unsigned num_supported_floppies;
|
||||
Bit8u floppy_buffer[512+2]; // 2 extra for good measure
|
||||
unsigned floppy_buffer_index;
|
||||
int floppy_timer_index;
|
||||
bx_bool media_present[4];
|
||||
Bit8u device_type[4];
|
||||
Bit8u DIR[4]; // Digital Input Register:
|
||||
// b7: 0=diskette is present and has not been changed
|
||||
// 1=diskette missing or changed
|
||||
bx_bool lock; // FDC lock status
|
||||
Bit8u SRT; // step rate time
|
||||
Bit8u HUT; // head unload time
|
||||
Bit8u HLT; // head load time
|
||||
Bit8u config; // configure byte #1
|
||||
Bit8u pretrk; // precompensation track
|
||||
Bit8u perp_mode; // perpendicular mode
|
||||
|
||||
int statusbar_id[2]; // IDs of the status LEDs
|
||||
} s; // state information
|
||||
|
||||
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_FD_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
BX_FD_SMF void dma_write(Bit8u *data_byte);
|
||||
BX_FD_SMF void dma_read(Bit8u *data_byte);
|
||||
BX_FD_SMF void floppy_command(void);
|
||||
BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
|
||||
BX_FD_SMF void raise_interrupt(void);
|
||||
BX_FD_SMF void lower_interrupt(void);
|
||||
BX_FD_SMF void enter_idle_phase(void);
|
||||
BX_FD_SMF void enter_result_phase(void);
|
||||
BX_FD_SMF Bit32u calculate_step_delay(Bit8u drive, Bit8u new_cylinder);
|
||||
BX_FD_SMF void reset_changeline(void);
|
||||
BX_FD_SMF bx_bool get_tc(void);
|
||||
static void timer_handler(void *);
|
||||
BX_FD_SMF void timer(void);
|
||||
BX_FD_SMF void increment_sector(void);
|
||||
BX_FD_SMF bx_bool evaluate_media(Bit8u devtype, Bit8u type, char *path, floppy_t *media);
|
||||
BX_FD_SMF void close_media(floppy_t *media);
|
||||
// runtime options
|
||||
static Bit64s floppy_param_handler(bx_param_c *param, int set, Bit64s val);
|
||||
static const char* floppy_param_string_handler(bx_param_string_c *param, int set, const char *oldval, const char *val, int maxlen);
|
||||
};
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
// used for direct floppy access in Win95
|
||||
#define VWIN32_DIOC_DOS_IOCTL 1
|
||||
#define VWIN32_DIOC_DOS_INT25 2
|
||||
#define VWIN32_DIOC_DOS_INT26 3
|
||||
|
||||
typedef struct _DIOC_REGISTERS {
|
||||
DWORD reg_EBX;
|
||||
DWORD reg_EDX;
|
||||
DWORD reg_ECX;
|
||||
DWORD reg_EAX;
|
||||
DWORD reg_EDI;
|
||||
DWORD reg_ESI;
|
||||
DWORD reg_Flags;
|
||||
} DIOC_REGISTERS, *PDIOC_REGISTERS;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct _BLOCK_DEV_PARAMS {
|
||||
BYTE features;
|
||||
BYTE dev_type;
|
||||
WORD attribs;
|
||||
WORD cylinders;
|
||||
BYTE media_type;
|
||||
// BPB
|
||||
WORD bytes_per_sector;
|
||||
BYTE sect_per_cluster;
|
||||
WORD reserved_sectors;
|
||||
BYTE fats;
|
||||
WORD root_entries;
|
||||
WORD tot_sectors;
|
||||
BYTE media_id;
|
||||
WORD sects_per_fat;
|
||||
WORD sects_per_track;
|
||||
WORD num_heads;
|
||||
WORD hidden_sectors;
|
||||
BYTE remainder[5];
|
||||
} BLOCK_DEV_PARAMS, *PBLOCK_DEV_PARAMS;
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#endif
|
||||
234
bochs/iodev/gameport.cc
Normal file
234
bochs/iodev/gameport.cc
Normal file
@ -0,0 +1,234 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2003-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// Standard PC gameport
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "gameport.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <linux/joystick.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
#ifndef JOY_BUTTON1
|
||||
#define JOY_BUTTON1 1
|
||||
#define JOY_BUTTON2 2
|
||||
UINT STDCALL joyGetPos(UINT, LPJOYINFO);
|
||||
#endif
|
||||
|
||||
#define JOYSTICKID1 0
|
||||
|
||||
#endif
|
||||
|
||||
#define LOG_THIS theGameport->
|
||||
|
||||
bx_gameport_c *theGameport = NULL;
|
||||
|
||||
int libgameport_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theGameport = new bx_gameport_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theGameport, BX_PLUGIN_GAMEPORT);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libgameport_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theGameport;
|
||||
}
|
||||
|
||||
bx_gameport_c::bx_gameport_c()
|
||||
{
|
||||
put("GAME");
|
||||
joyfd = -1;
|
||||
}
|
||||
|
||||
bx_gameport_c::~bx_gameport_c()
|
||||
{
|
||||
if (joyfd >= 0) close(joyfd);
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_gameport_c::init(void)
|
||||
{
|
||||
// Allocate the gameport IO address range 0x200..0x207
|
||||
for (unsigned addr=0x200; addr<0x208; addr++) {
|
||||
DEV_register_ioread_handler(this, read_handler, addr, "Gameport", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, addr, "Gameport", 1);
|
||||
}
|
||||
|
||||
BX_GAMEPORT_THIS port = 0xf0;
|
||||
BX_GAMEPORT_THIS write_usec = 0;
|
||||
BX_GAMEPORT_THIS timer_x = 0;
|
||||
BX_GAMEPORT_THIS timer_y = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
BX_GAMEPORT_THIS joyfd = open("/dev/input/js0", O_RDONLY);
|
||||
if (BX_GAMEPORT_THIS joyfd >= 0) {
|
||||
for (unsigned i=0; i<4; i++) poll_joydev();
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
JOYINFO joypos;
|
||||
if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
|
||||
BX_GAMEPORT_THIS joyfd = 1;
|
||||
} else {
|
||||
BX_GAMEPORT_THIS joyfd = -1;
|
||||
}
|
||||
#else
|
||||
BX_GAMEPORT_THIS joyfd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void bx_gameport_c::reset(unsigned type)
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
void bx_gameport_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "gameport", "Gameport State", 6);
|
||||
BXRS_HEX_PARAM_FIELD(list, port, BX_GAMEPORT_THIS port);
|
||||
BXRS_DEC_PARAM_FIELD(list, delay_x, BX_GAMEPORT_THIS delay_x);
|
||||
BXRS_DEC_PARAM_FIELD(list, delay_y, BX_GAMEPORT_THIS delay_y);
|
||||
BXRS_PARAM_BOOL(list, timer_x, BX_GAMEPORT_THIS timer_x);
|
||||
BXRS_PARAM_BOOL(list, timer_y, BX_GAMEPORT_THIS timer_y);
|
||||
BXRS_DEC_PARAM_FIELD(list, write_usec, BX_GAMEPORT_THIS write_usec);
|
||||
}
|
||||
|
||||
void bx_gameport_c::poll_joydev(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct js_event e;
|
||||
fd_set joyfds;
|
||||
struct timeval tv;
|
||||
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
FD_ZERO(&joyfds);
|
||||
FD_SET(BX_GAMEPORT_THIS joyfd, &joyfds);
|
||||
e.type = 0;
|
||||
if (select(BX_GAMEPORT_THIS joyfd+1, &joyfds, NULL, NULL, &tv)) {
|
||||
read(BX_GAMEPORT_THIS joyfd, &e, sizeof(struct js_event));
|
||||
if (e.type & JS_EVENT_BUTTON) {
|
||||
if (e.value == 1) {
|
||||
BX_GAMEPORT_THIS port &= ~(0x10 << e.number);
|
||||
} else {
|
||||
BX_GAMEPORT_THIS port |= (0x10 << e.number);
|
||||
}
|
||||
}
|
||||
if (e.type & JS_EVENT_AXIS) {
|
||||
if (e.number == 0) {
|
||||
BX_GAMEPORT_THIS delay_x = 25 + ((e.value + 0x8000) / 60);
|
||||
}
|
||||
if (e.number == 1) {
|
||||
BX_GAMEPORT_THIS delay_y = 25 + ((e.value + 0x8000) / 62);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
JOYINFO joypos;
|
||||
if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
|
||||
if (joypos.wButtons & JOY_BUTTON1) {
|
||||
BX_GAMEPORT_THIS port &= ~0x10;
|
||||
} else {
|
||||
BX_GAMEPORT_THIS port |= 0x10;
|
||||
}
|
||||
if (joypos.wButtons & JOY_BUTTON2) {
|
||||
BX_GAMEPORT_THIS port &= ~0x20;
|
||||
} else {
|
||||
BX_GAMEPORT_THIS port |= 0x20;
|
||||
}
|
||||
BX_GAMEPORT_THIS delay_x = 25 + (joypos.wXpos / 60);
|
||||
BX_GAMEPORT_THIS delay_y = 25 + (joypos.wYpos / 60);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_gameport_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_GAMEPORT_SMF
|
||||
bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_gameport_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_GAMEPORT_SMF
|
||||
Bit64u usec;
|
||||
|
||||
if (BX_GAMEPORT_THIS joyfd >= 0) {
|
||||
poll_joydev();
|
||||
usec = bx_pc_system.time_usec();
|
||||
if (BX_GAMEPORT_THIS timer_x) {
|
||||
if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_x) {
|
||||
BX_GAMEPORT_THIS port &= 0xfe;
|
||||
BX_GAMEPORT_THIS timer_x = 0;
|
||||
}
|
||||
}
|
||||
if (BX_GAMEPORT_THIS timer_y) {
|
||||
if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_y) {
|
||||
BX_GAMEPORT_THIS port &= 0xfd;
|
||||
BX_GAMEPORT_THIS timer_y = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BX_DEBUG(("read: joystick not present"));
|
||||
}
|
||||
return BX_GAMEPORT_THIS port;
|
||||
}
|
||||
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_gameport_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_GAMEPORT_SMF
|
||||
bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_gameport_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_GAMEPORT_SMF
|
||||
|
||||
BX_GAMEPORT_THIS write_usec = bx_pc_system.time_usec();
|
||||
BX_GAMEPORT_THIS timer_x = 1;
|
||||
BX_GAMEPORT_THIS timer_y = 1;
|
||||
BX_GAMEPORT_THIS port |= 0x0f;
|
||||
}
|
||||
62
bochs/iodev/gameport.h
Normal file
62
bochs/iodev/gameport.h
Normal file
@ -0,0 +1,62 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2003-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_GAMEPORT_H
|
||||
#define BX_IODEV_GAMEPORT_H
|
||||
|
||||
#if BX_USE_GAMEPORT_SMF
|
||||
# define BX_GAMEPORT_SMF static
|
||||
# define BX_GAMEPORT_THIS theGameport->
|
||||
#else
|
||||
# define BX_GAMEPORT_SMF
|
||||
# define BX_GAMEPORT_THIS this->
|
||||
#endif
|
||||
|
||||
|
||||
class bx_gameport_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_gameport_c();
|
||||
virtual ~bx_gameport_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
|
||||
int joyfd;
|
||||
Bit8u port;
|
||||
Bit16u delay_x;
|
||||
Bit16u delay_y;
|
||||
bx_bool timer_x;
|
||||
bx_bool timer_y;
|
||||
Bit64u write_usec;
|
||||
|
||||
BX_GAMEPORT_SMF void poll_joydev(void);
|
||||
|
||||
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_GAMEPORT_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
135
bochs/iodev/guest2host.cc
Normal file
135
bochs/iodev/guest2host.cc
Normal file
@ -0,0 +1,135 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "iodev.h"
|
||||
#include "guest2host.h"
|
||||
|
||||
#define LOG_THIS bx_g2h.
|
||||
|
||||
bx_g2h_c bx_g2h;
|
||||
|
||||
bx_g2h_c::bx_g2h_c()
|
||||
{
|
||||
put("G2H");
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<BX_MAX_G2H_CHANNELS; i++) {
|
||||
s.callback[i].f = NULL;
|
||||
s.callback[i].used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bx_g2h_c::~bx_g2h_c()
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
void bx_g2h_c::init(void)
|
||||
{
|
||||
BX_DEBUG(("Init $Id$"));
|
||||
// Reserve a dword port for this interface
|
||||
for (Bit32u addr=BX_G2H_PORT; addr<=(BX_G2H_PORT+3); addr++) {
|
||||
bx_devices.register_io_read_handler(&bx_g2h,
|
||||
inp_handler, addr, "g2h");
|
||||
bx_devices.register_io_write_handler(&bx_g2h,
|
||||
outp_handler, addr, "g2h");
|
||||
}
|
||||
memset(&bx_g2h.s, 0, sizeof(bx_g2h.s));
|
||||
}
|
||||
|
||||
void bx_g2h_c::reset(unsigned type)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned bx_g2h_c::acquire_channel(bx_g2h_callback_t f)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<BX_MAX_G2H_CHANNELS; i++) {
|
||||
if (bx_g2h.s.callback[i].used==0) {
|
||||
bx_g2h.s.callback[i].f = f;
|
||||
bx_g2h.s.callback[i].used = 1;
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
BX_INFO(("g2h: attempt to acquire channel: maxed out"));
|
||||
return BX_G2H_ERROR; // No more free channels
|
||||
}
|
||||
|
||||
unsigned bx_g2h_c::deacquire_channel(unsigned channel)
|
||||
{
|
||||
if ((channel >= BX_MAX_G2H_CHANNELS) ||
|
||||
(bx_g2h.s.callback[channel].used==0))
|
||||
{
|
||||
BX_PANIC(("g2h: attempt to deacquire channel %u: not acquired", channel));
|
||||
}
|
||||
bx_g2h.s.callback[channel].used = 0;
|
||||
bx_g2h.s.callback[channel].f = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_g2h_c::inp_handler(void *this_ptr, Bit32u addr, unsigned io_len)
|
||||
{
|
||||
UNUSED(this_ptr);
|
||||
|
||||
if (addr != BX_G2H_PORT)
|
||||
BX_PANIC(("g2h: IO read not aligned on dword boundary."));
|
||||
if (io_len != 4)
|
||||
BX_PANIC(("g2h: IO read not dword."));
|
||||
|
||||
BX_PANIC(("g2h: IO read not complete."));
|
||||
return(0);
|
||||
}
|
||||
|
||||
void bx_g2h_c::outp_handler(void *this_ptr, Bit32u addr, Bit32u val32, unsigned io_len)
|
||||
{
|
||||
UNUSED(this_ptr);
|
||||
|
||||
if (addr != BX_G2H_PORT)
|
||||
BX_PANIC(("g2h: IO write not aligned on dword boundary."));
|
||||
if (io_len != 4)
|
||||
BX_PANIC(("g2h: IO write not dword."));
|
||||
|
||||
if ((bx_g2h.s.packet_count==0) && (val32!=BX_G2H_MAGIC)) {
|
||||
BX_INFO(("g2h: IO W: Not magic header."));
|
||||
return;
|
||||
}
|
||||
bx_g2h.s.guest_packet[bx_g2h.s.packet_count++] = val32;
|
||||
if (bx_g2h.s.packet_count >= BX_G2H_PACKET_SIZE) {
|
||||
unsigned channel;
|
||||
|
||||
// Full packet received from guest. Pass on to the host code.
|
||||
channel = bx_g2h.s.guest_packet[1];
|
||||
if (channel >= BX_MAX_G2H_CHANNELS) {
|
||||
BX_PANIC(("g2h: channel (%u) out of bounds", channel));
|
||||
}
|
||||
if (bx_g2h.s.callback[channel].used==0) {
|
||||
BX_PANIC(("g2h: channel (%u) not active", channel));
|
||||
}
|
||||
bx_g2h.s.callback[channel].f(&bx_g2h.s.guest_packet);
|
||||
bx_g2h.s.packet_count = 0; // Ready for next packet
|
||||
}
|
||||
}
|
||||
68
bochs/iodev/guest2host.h
Normal file
68
bochs/iodev/guest2host.h
Normal file
@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#define BX_MAX_G2H_CHANNELS 8
|
||||
#define BX_G2H_ERROR ((unsigned) -1)
|
||||
// IO port number for this interface. Align on dword boundary.
|
||||
#define BX_G2H_PORT 0x2000
|
||||
// Magic number which is first dword passed by guest
|
||||
#define BX_G2H_MAGIC 0xffeeddcc
|
||||
// Number of dwords in packet from guest
|
||||
#define BX_G2H_PACKET_SIZE 5
|
||||
|
||||
|
||||
typedef Bit32u bx_guest_packet_t[BX_G2H_PACKET_SIZE];
|
||||
typedef void (*bx_g2h_callback_t)(bx_guest_packet_t *);
|
||||
|
||||
|
||||
class bx_g2h_c : public logfunctions {
|
||||
public:
|
||||
bx_g2h_c();
|
||||
virtual ~bx_g2h_c();
|
||||
static void init(void);
|
||||
void reset(unsigned type);
|
||||
unsigned acquire_channel(bx_g2h_callback_t);
|
||||
unsigned deacquire_channel(unsigned channel);
|
||||
|
||||
private:
|
||||
|
||||
static Bit32u inp_handler(void *this_ptr, Bit32u addr, unsigned io_len);
|
||||
static void outp_handler(void *this_ptr, Bit32u addr,
|
||||
Bit32u value, unsigned io_len);
|
||||
// state info
|
||||
struct {
|
||||
struct {
|
||||
bx_g2h_callback_t f;
|
||||
bx_bool used;
|
||||
} callback[BX_MAX_G2H_CHANNELS];
|
||||
|
||||
// Define the data received from the guest OS.
|
||||
// dword0: magic number, should be BX_G2H_MAGIC
|
||||
// dword1: channel ID
|
||||
// dword2: address of data structure in guest physical memory
|
||||
// dword3: size of data structure in guest physical memory
|
||||
// dword4: address of return data structure in guest physical memory
|
||||
unsigned packet_count;
|
||||
bx_guest_packet_t guest_packet;
|
||||
} s;
|
||||
};
|
||||
|
||||
extern bx_g2h_c bx_g2h;
|
||||
3462
bochs/iodev/harddrv.cc
Normal file
3462
bochs/iodev/harddrv.cc
Normal file
File diff suppressed because it is too large
Load Diff
258
bochs/iodev/harddrv.h
Normal file
258
bochs/iodev/harddrv.h
Normal file
@ -0,0 +1,258 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2010 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_HDDRIVE_H
|
||||
#define BX_IODEV_HDDRIVE_H
|
||||
|
||||
#define MAX_MULTIPLE_SECTORS 16
|
||||
|
||||
typedef enum _sense {
|
||||
SENSE_NONE = 0, SENSE_NOT_READY = 2, SENSE_ILLEGAL_REQUEST = 5,
|
||||
SENSE_UNIT_ATTENTION = 6
|
||||
} sense_t;
|
||||
|
||||
typedef enum _asc {
|
||||
ASC_ILLEGAL_OPCODE = 0x20,
|
||||
ASC_LOGICAL_BLOCK_OOR = 0x21,
|
||||
ASC_INV_FIELD_IN_CMD_PACKET = 0x24,
|
||||
ASC_MEDIUM_MAY_HAVE_CHANGED = 0x28,
|
||||
ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
|
||||
ASC_MEDIUM_NOT_PRESENT = 0x3a
|
||||
} asc_t;
|
||||
|
||||
class device_image_t;
|
||||
class LOWLEVEL_CDROM;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
bx_bool busy;
|
||||
bx_bool drive_ready;
|
||||
bx_bool write_fault;
|
||||
bx_bool seek_complete;
|
||||
bx_bool drq;
|
||||
bx_bool corrected_data;
|
||||
bx_bool index_pulse;
|
||||
unsigned index_pulse_count;
|
||||
bx_bool err;
|
||||
} status;
|
||||
Bit8u error_register;
|
||||
Bit8u head_no;
|
||||
union {
|
||||
Bit8u sector_count;
|
||||
struct {
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
unsigned c_d : 1;
|
||||
unsigned i_o : 1;
|
||||
unsigned rel : 1;
|
||||
unsigned tag : 5;
|
||||
#else /* BX_BIG_ENDIAN */
|
||||
unsigned tag : 5;
|
||||
unsigned rel : 1;
|
||||
unsigned i_o : 1;
|
||||
unsigned c_d : 1;
|
||||
#endif
|
||||
} interrupt_reason;
|
||||
};
|
||||
Bit8u sector_no;
|
||||
union {
|
||||
Bit16u cylinder_no;
|
||||
Bit16u byte_count;
|
||||
};
|
||||
Bit8u buffer[MAX_MULTIPLE_SECTORS*512 + 4];
|
||||
Bit32u buffer_size;
|
||||
Bit32u buffer_index;
|
||||
Bit32u drq_index;
|
||||
Bit8u current_command;
|
||||
Bit8u multiple_sectors;
|
||||
Bit8u lba_mode;
|
||||
bx_bool packet_dma;
|
||||
Bit8u mdma_mode;
|
||||
Bit8u udma_mode;
|
||||
struct {
|
||||
bx_bool reset; // 0=normal, 1=reset controller
|
||||
bx_bool disable_irq; // 0=allow irq, 1=disable irq
|
||||
} control;
|
||||
Bit8u reset_in_progress;
|
||||
Bit8u features;
|
||||
struct {
|
||||
Bit8u feature;
|
||||
Bit8u nsector;
|
||||
Bit8u sector;
|
||||
Bit8u lcyl;
|
||||
Bit8u hcyl;
|
||||
} hob;
|
||||
Bit32u num_sectors;
|
||||
bx_bool lba48;
|
||||
} controller_t;
|
||||
|
||||
struct sense_info_t {
|
||||
sense_t sense_key;
|
||||
struct {
|
||||
Bit8u arr[4];
|
||||
} information;
|
||||
struct {
|
||||
Bit8u arr[4];
|
||||
} specific_inf;
|
||||
struct {
|
||||
Bit8u arr[3];
|
||||
} key_spec;
|
||||
Bit8u fruc;
|
||||
Bit8u asc;
|
||||
Bit8u ascq;
|
||||
};
|
||||
|
||||
struct error_recovery_t {
|
||||
unsigned char data[8];
|
||||
|
||||
error_recovery_t ();
|
||||
};
|
||||
|
||||
Bit16u read_16bit(const Bit8u* buf) BX_CPP_AttrRegparmN(1);
|
||||
Bit32u read_32bit(const Bit8u* buf) BX_CPP_AttrRegparmN(1);
|
||||
|
||||
|
||||
struct cdrom_t
|
||||
{
|
||||
bx_bool ready;
|
||||
bx_bool locked;
|
||||
#ifdef LOWLEVEL_CDROM
|
||||
LOWLEVEL_CDROM* cd;
|
||||
#endif
|
||||
Bit32u capacity;
|
||||
int next_lba;
|
||||
int remaining_blocks;
|
||||
struct currentStruct {
|
||||
error_recovery_t error_recovery;
|
||||
} current;
|
||||
};
|
||||
|
||||
struct atapi_t
|
||||
{
|
||||
Bit8u command;
|
||||
int drq_bytes;
|
||||
int total_bytes_remaining;
|
||||
};
|
||||
|
||||
#if BX_USE_HD_SMF
|
||||
# define BX_HD_SMF static
|
||||
# define BX_HD_THIS theHardDrive->
|
||||
#else
|
||||
# define BX_HD_SMF
|
||||
# define BX_HD_THIS this->
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
IDE_NONE, IDE_DISK, IDE_CDROM
|
||||
} device_type_t;
|
||||
|
||||
class bx_hard_drive_c : public bx_hard_drive_stub_c {
|
||||
public:
|
||||
bx_hard_drive_c();
|
||||
virtual ~bx_hard_drive_c();
|
||||
virtual void init();
|
||||
virtual void reset(unsigned type);
|
||||
virtual Bit32u get_device_handle(Bit8u channel, Bit8u device);
|
||||
virtual Bit32u get_first_cd_handle(void);
|
||||
virtual unsigned get_cd_media_status(Bit32u handle);
|
||||
virtual unsigned set_cd_media_status(Bit32u handle, unsigned status);
|
||||
#if BX_SUPPORT_PCI
|
||||
virtual bx_bool bmdma_read_sector(Bit8u channel, Bit8u *buffer, Bit32u *sector_size);
|
||||
virtual bx_bool bmdma_write_sector(Bit8u channel, Bit8u *buffer);
|
||||
virtual void bmdma_complete(Bit8u channel);
|
||||
#endif
|
||||
virtual void register_state(void);
|
||||
|
||||
virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len)
|
||||
{
|
||||
return read_handler(this, address, io_len);
|
||||
}
|
||||
virtual void virt_write_handler(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
write_handler(this, address, value, io_len);
|
||||
}
|
||||
|
||||
#if !BX_USE_HD_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
static void iolight_timer_handler(void *);
|
||||
BX_HD_SMF void iolight_timer(void);
|
||||
|
||||
private:
|
||||
|
||||
BX_HD_SMF bx_bool calculate_logical_address(Bit8u channel, Bit64s *sector) BX_CPP_AttrRegparmN(2);
|
||||
BX_HD_SMF void increment_address(Bit8u channel) BX_CPP_AttrRegparmN(1);
|
||||
BX_HD_SMF void identify_drive(Bit8u channel);
|
||||
BX_HD_SMF void identify_ATAPI_drive(Bit8u channel);
|
||||
BX_HD_SMF void command_aborted(Bit8u channel, unsigned command);
|
||||
|
||||
BX_HD_SMF void init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bx_bool lazy = 0);
|
||||
BX_HD_SMF void ready_to_send_atapi(Bit8u channel) BX_CPP_AttrRegparmN(1);
|
||||
BX_HD_SMF void raise_interrupt(Bit8u channel) BX_CPP_AttrRegparmN(1);
|
||||
BX_HD_SMF void atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc, bx_bool show);
|
||||
BX_HD_SMF void init_mode_sense_single(Bit8u channel, const void* src, int size);
|
||||
BX_HD_SMF void atapi_cmd_nop(Bit8u channel) BX_CPP_AttrRegparmN(1);
|
||||
BX_HD_SMF bx_bool bmdma_present(void);
|
||||
BX_HD_SMF void set_signature(Bit8u channel, Bit8u id);
|
||||
BX_HD_SMF bx_bool ide_read_sector(Bit8u channel, Bit8u *buffer, Bit32u buffer_size);
|
||||
BX_HD_SMF bx_bool ide_write_sector(Bit8u channel, Bit8u *buffer, Bit32u buffer_size);
|
||||
BX_HD_SMF void lba48_transform(Bit8u channel, bx_bool lba48);
|
||||
|
||||
// FIXME:
|
||||
// For each ATA channel we should have one controller struct
|
||||
// and an array of two drive structs
|
||||
struct channel_t {
|
||||
struct drive_t {
|
||||
device_image_t* hdimage;
|
||||
device_type_t device_type;
|
||||
// 512 byte buffer for ID drive command
|
||||
// These words are stored in native word endian format, as
|
||||
// they are fetched and returned via a return(), so
|
||||
// there's no need to keep them in x86 endian format.
|
||||
Bit16u id_drive[256];
|
||||
bx_bool identify_set;
|
||||
|
||||
controller_t controller;
|
||||
cdrom_t cdrom;
|
||||
sense_info_t sense;
|
||||
atapi_t atapi;
|
||||
|
||||
Bit8u model_no[41];
|
||||
int statusbar_id;
|
||||
int iolight_counter;
|
||||
Bit8u device_num; // for ATAPI identify & inquiry
|
||||
} drives[2];
|
||||
unsigned drive_select;
|
||||
|
||||
Bit16u ioaddr1;
|
||||
Bit16u ioaddr2;
|
||||
Bit8u irq;
|
||||
|
||||
} channels[BX_MAX_ATA_CHANNEL];
|
||||
|
||||
int iolight_timer_index;
|
||||
Bit8u cdrom_count;
|
||||
};
|
||||
|
||||
#endif
|
||||
1897
bochs/iodev/hdimage.cc
Normal file
1897
bochs/iodev/hdimage.cc
Normal file
File diff suppressed because it is too large
Load Diff
590
bochs/iodev/hdimage.h
Normal file
590
bochs/iodev/hdimage.h
Normal file
@ -0,0 +1,590 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2005-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_HDIMAGE_H
|
||||
#define BX_HDIMAGE_H
|
||||
|
||||
// hdimage capabilities
|
||||
#define HDIMAGE_READONLY 1
|
||||
#define HDIMAGE_HAS_GEOMETRY 2
|
||||
#define HDIMAGE_AUTO_GEOMETRY 4
|
||||
|
||||
// SPARSE IMAGES HEADER
|
||||
#define SPARSE_HEADER_MAGIC (0x02468ace)
|
||||
#define SPARSE_HEADER_VERSION 2
|
||||
#define SPARSE_HEADER_V1 1
|
||||
#define SPARSE_HEADER_SIZE (256) // Plenty of room for later
|
||||
#define SPARSE_PAGE_NOT_ALLOCATED (0xffffffff)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Bit32u magic;
|
||||
Bit32u version;
|
||||
Bit32u pagesize;
|
||||
Bit32u numpages;
|
||||
Bit64u disk;
|
||||
|
||||
Bit32u padding[58];
|
||||
} sparse_header_t;
|
||||
|
||||
#define STANDARD_HEADER_MAGIC "Bochs Virtual HD Image"
|
||||
#define STANDARD_HEADER_V1 (0x00010000)
|
||||
#define STANDARD_HEADER_VERSION (0x00020000)
|
||||
#define STANDARD_HEADER_SIZE (512)
|
||||
|
||||
|
||||
// WARNING : headers are kept in x86 (little) endianness
|
||||
typedef struct
|
||||
{
|
||||
Bit8u magic[32];
|
||||
Bit8u type[16];
|
||||
Bit8u subtype[16];
|
||||
Bit32u version;
|
||||
Bit32u header;
|
||||
} standard_header_t;
|
||||
|
||||
#define REDOLOG_TYPE "Redolog"
|
||||
#define REDOLOG_SUBTYPE_UNDOABLE "Undoable"
|
||||
#define REDOLOG_SUBTYPE_VOLATILE "Volatile"
|
||||
#define REDOLOG_SUBTYPE_GROWING "Growing"
|
||||
// #define REDOLOG_SUBTYPE_Z_UNDOABLE "z-Undoable"
|
||||
// #define REDOLOG_SUBTYPE_Z_VOLATILE "z-Volatile"
|
||||
|
||||
#define REDOLOG_PAGE_NOT_ALLOCATED (0xffffffff)
|
||||
|
||||
#define UNDOABLE_REDOLOG_EXTENSION ".redolog"
|
||||
#define UNDOABLE_REDOLOG_EXTENSION_LENGTH (strlen(UNDOABLE_REDOLOG_EXTENSION))
|
||||
#define VOLATILE_REDOLOG_EXTENSION ".XXXXXX"
|
||||
#define VOLATILE_REDOLOG_EXTENSION_LENGTH (strlen(VOLATILE_REDOLOG_EXTENSION))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// the fields in the header are kept in little endian
|
||||
Bit32u catalog; // #entries in the catalog
|
||||
Bit32u bitmap; // bitmap size in bytes
|
||||
Bit32u extent; // extent size in bytes
|
||||
Bit32u reserved; // for data alignment
|
||||
Bit64u disk; // disk size in bytes
|
||||
} redolog_specific_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// the fields in the header are kept in little endian
|
||||
Bit32u catalog; // #entries in the catalog
|
||||
Bit32u bitmap; // bitmap size in bytes
|
||||
Bit32u extent; // extent size in bytes
|
||||
Bit64u disk; // disk size in bytes
|
||||
} redolog_specific_header_v1_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
standard_header_t standard;
|
||||
redolog_specific_header_t specific;
|
||||
|
||||
Bit8u padding[STANDARD_HEADER_SIZE - (sizeof (standard_header_t) + sizeof (redolog_specific_header_t))];
|
||||
} redolog_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
standard_header_t standard;
|
||||
redolog_specific_header_v1_t specific;
|
||||
|
||||
Bit8u padding[STANDARD_HEADER_SIZE - (sizeof (standard_header_t) + sizeof (redolog_specific_header_v1_t))];
|
||||
} redolog_header_v1_t;
|
||||
|
||||
// htod : convert host to disk (little) endianness
|
||||
// dtoh : convert disk (little) to host endianness
|
||||
#if defined (BX_LITTLE_ENDIAN)
|
||||
#define htod32(val) (val)
|
||||
#define dtoh32(val) (val)
|
||||
#define htod64(val) (val)
|
||||
#define dtoh64(val) (val)
|
||||
#else
|
||||
#define htod32(val) ( (((val)&0xff000000)>>24) | (((val)&0xff0000)>>8) | (((val)&0xff00)<<8) | (((val)&0xff)<<24) )
|
||||
#define dtoh32(val) htod32(val)
|
||||
#define htod64(val) ( (((val)&0xff00000000000000LL)>>56) | (((val)&0xff000000000000LL)>>40) | (((val)&0xff0000000000LL)>>24) | (((val)&0xff00000000LL)>>8) | (((val)&0xff000000LL)<<8) | (((val)&0xff0000LL)<<24) | (((val)&0xff00LL)<<40) | (((val)&0xffLL)<<56) )
|
||||
#define dtoh64(val) htod64(val)
|
||||
#endif
|
||||
|
||||
#ifndef HDIMAGE_HEADERS_ONLY
|
||||
|
||||
class device_image_t
|
||||
{
|
||||
public:
|
||||
// Default constructor
|
||||
device_image_t();
|
||||
virtual ~device_image_t() {}
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
virtual int open(const char* pathname) = 0;
|
||||
|
||||
// Close the image.
|
||||
virtual void close() = 0;
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
virtual Bit64s lseek(Bit64s offset, int whence) = 0;
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
virtual ssize_t read(void* buf, size_t count) = 0;
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
virtual ssize_t write(const void* buf, size_t count) = 0;
|
||||
|
||||
// Get image capabilities
|
||||
virtual Bit32u get_capabilities();
|
||||
|
||||
unsigned cylinders;
|
||||
unsigned heads;
|
||||
unsigned sectors;
|
||||
Bit64u hd_size;
|
||||
};
|
||||
|
||||
// FLAT MODE
|
||||
class default_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Open an image with specific flags. Returns non-negative if successful.
|
||||
int open(const char* pathname, int flags);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
int fd;
|
||||
|
||||
};
|
||||
|
||||
// CONCAT MODE
|
||||
class concat_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Default constructor
|
||||
concat_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
#define BX_CONCAT_MAX_IMAGES 8
|
||||
int fd_table[BX_CONCAT_MAX_IMAGES];
|
||||
Bit64s start_offset_table[BX_CONCAT_MAX_IMAGES];
|
||||
Bit64s length_table[BX_CONCAT_MAX_IMAGES];
|
||||
void increment_string(char *str);
|
||||
int maxfd; // number of entries in tables that are valid
|
||||
|
||||
// notice if anyone does sequential read or write without seek in between.
|
||||
// This can be supported pretty easily, but needs additional checks.
|
||||
// 0=something other than seek was last operation
|
||||
// 1=seek was last operation
|
||||
int seek_was_last_op;
|
||||
|
||||
// the following variables tell which partial image file to use for
|
||||
// the next read and write.
|
||||
int index; // index into table
|
||||
int fd; // fd to use for reads and writes
|
||||
Bit64s thismin, thismax; // byte offset boundary of this image
|
||||
};
|
||||
|
||||
// SPARSE MODE
|
||||
class sparse_image_t : public device_image_t
|
||||
{
|
||||
|
||||
// Format of a sparse file:
|
||||
// 256 byte header, containing details such as page size and number of pages
|
||||
// Page indirection table, mapping virtual pages to physical pages within file
|
||||
// Physical pages till end of file
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
sparse_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
int fd;
|
||||
|
||||
#ifdef _POSIX_MAPPED_FILES
|
||||
void * mmap_header;
|
||||
size_t mmap_length;
|
||||
size_t system_pagesize_mask;
|
||||
#endif
|
||||
Bit32u * pagetable;
|
||||
|
||||
// Header is written to disk in little-endian (x86) format
|
||||
// Thus needs to be converted on big-endian systems before read
|
||||
// The pagetable is also kept little endian
|
||||
|
||||
sparse_header_t header;
|
||||
|
||||
Bit32u pagesize;
|
||||
int pagesize_shift;
|
||||
Bit32u pagesize_mask;
|
||||
|
||||
Bit64s data_start;
|
||||
Bit64s underlying_filesize;
|
||||
|
||||
char * pathname;
|
||||
|
||||
Bit64s position;
|
||||
|
||||
Bit32u position_virtual_page;
|
||||
Bit32u position_physical_page;
|
||||
Bit32u position_page_offset;
|
||||
|
||||
Bit64s underlying_current_filepos;
|
||||
|
||||
Bit64s total_size;
|
||||
|
||||
void panic(const char * message);
|
||||
Bit64s get_physical_offset();
|
||||
void set_virtual_page(Bit32u new_virtual_page);
|
||||
void read_header();
|
||||
ssize_t read_page_fragment(Bit32u read_virtual_page, Bit32u read_page_offset, size_t read_size, void * buf);
|
||||
|
||||
sparse_image_t * parent_image;
|
||||
};
|
||||
|
||||
#if EXTERNAL_DISK_SIMULATOR
|
||||
#include "external-disk-simulator.h"
|
||||
#endif
|
||||
|
||||
#if DLL_HD_SUPPORT
|
||||
class dll_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
int vunit,vblk;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
// REDOLOG class
|
||||
class redolog_t
|
||||
{
|
||||
public:
|
||||
redolog_t();
|
||||
int make_header(const char* type, Bit64u size);
|
||||
int create(const char* filename, const char* type, Bit64u size);
|
||||
int create(int filedes, const char* type, Bit64u size);
|
||||
int open(const char* filename, const char* type);
|
||||
void close();
|
||||
Bit64u get_size();
|
||||
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
ssize_t read(void* buf, size_t count);
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
void print_header();
|
||||
int fd;
|
||||
redolog_header_t header; // Header is kept in x86 (little) endianness
|
||||
Bit32u *catalog;
|
||||
Bit8u *bitmap;
|
||||
Bit32u extent_index;
|
||||
Bit32u extent_offset;
|
||||
Bit32u extent_next;
|
||||
|
||||
Bit32u bitmap_blocks;
|
||||
Bit32u extent_blocks;
|
||||
|
||||
Bit64s imagepos;
|
||||
};
|
||||
|
||||
// GROWING MODE
|
||||
class growing_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
growing_image_t();
|
||||
virtual ~growing_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
redolog_t *redolog;
|
||||
};
|
||||
|
||||
// UNDOABLE MODE
|
||||
class undoable_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
undoable_image_t(const char* redolog_name);
|
||||
virtual ~undoable_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
redolog_t *redolog; // Redolog instance
|
||||
default_image_t *ro_disk; // Read-only flat disk instance
|
||||
char *redolog_name; // Redolog name
|
||||
};
|
||||
|
||||
|
||||
// VOLATILE MODE
|
||||
class volatile_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
volatile_image_t(const char* redolog_name);
|
||||
virtual ~volatile_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
redolog_t *redolog; // Redolog instance
|
||||
default_image_t *ro_disk; // Read-only flat disk instance
|
||||
char *redolog_name; // Redolog name
|
||||
char *redolog_temp; // Redolog temporary file name
|
||||
};
|
||||
|
||||
|
||||
#if BX_COMPRESSED_HD_SUPPORT
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
// Default compressed READ-ONLY image class
|
||||
class z_ro_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
z_ro_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
Bit64s offset;
|
||||
int fd;
|
||||
gzFile gzfile;
|
||||
|
||||
};
|
||||
|
||||
// Z-UNDOABLE MODE
|
||||
class z_undoable_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
z_undoable_image_t(Bit64u size, const char* redolog_name);
|
||||
virtual ~z_undoable_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
redolog_t *redolog; // Redolog instance
|
||||
z_ro_image_t *ro_disk; // Read-only compressed flat disk instance
|
||||
Bit64u size;
|
||||
char *redolog_name; // Redolog name
|
||||
};
|
||||
|
||||
// Z-VOLATILE MODE
|
||||
class z_volatile_image_t : public device_image_t
|
||||
{
|
||||
public:
|
||||
// Contructor
|
||||
z_volatile_image_t(Bit64u size, const char* redolog_name);
|
||||
virtual ~z_volatile_image_t();
|
||||
|
||||
// Open a image. Returns non-negative if successful.
|
||||
int open(const char* pathname);
|
||||
|
||||
// Close the image.
|
||||
void close();
|
||||
|
||||
// Position ourselves. Return the resulting offset from the
|
||||
// beginning of the file.
|
||||
Bit64s lseek(Bit64s offset, int whence);
|
||||
|
||||
// Read count bytes to the buffer buf. Return the number of
|
||||
// bytes read (count).
|
||||
ssize_t read(void* buf, size_t count);
|
||||
|
||||
// Write count bytes from buf. Return the number of bytes
|
||||
// written (count).
|
||||
ssize_t write(const void* buf, size_t count);
|
||||
|
||||
private:
|
||||
redolog_t *redolog; // Redolog instance
|
||||
z_ro_image_t *ro_disk; // Read-only compressed flat disk instance
|
||||
Bit64u size;
|
||||
char *redolog_name; // Redolog name
|
||||
char *redolog_temp; // Redolog temporary file name
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class bx_hdimage_ctl_c : public bx_hdimage_ctl_stub_c {
|
||||
public:
|
||||
bx_hdimage_ctl_c();
|
||||
virtual ~bx_hdimage_ctl_c() {}
|
||||
virtual device_image_t *init_image(Bit8u image_mode, Bit64u disk_size, const char *journal);
|
||||
};
|
||||
|
||||
|
||||
#endif // HDIMAGE_HEADERS_ONLY
|
||||
|
||||
#endif
|
||||
308
bochs/iodev/ioapic.cc
Normal file
308
bochs/iodev/ioapic.cc
Normal file
@ -0,0 +1,308 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
|
||||
#include "ioapic.h"
|
||||
|
||||
#define LOG_THIS theIOAPIC->
|
||||
|
||||
bx_ioapic_c *theIOAPIC = NULL;
|
||||
|
||||
int libioapic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theIOAPIC = new bx_ioapic_c();
|
||||
bx_devices.pluginIOAPIC = theIOAPIC;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIOAPIC, BX_PLUGIN_IOAPIC);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libioapic_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theIOAPIC;
|
||||
}
|
||||
|
||||
static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
|
||||
{
|
||||
if((a20addr & ~0x3) != ((a20addr+len-1) & ~0x3)) {
|
||||
BX_PANIC(("I/O APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", a20addr));
|
||||
return 1;
|
||||
}
|
||||
Bit32u value = theIOAPIC->read_aligned(a20addr & ~0x3);
|
||||
if(len == 4) { // must be 32-bit aligned
|
||||
*((Bit32u *)data) = value;
|
||||
return 1;
|
||||
}
|
||||
// handle partial read, independent of endian-ness
|
||||
value >>= (a20addr&3)*8;
|
||||
if (len == 1)
|
||||
*((Bit8u *) data) = value & 0xff;
|
||||
else if (len == 2)
|
||||
*((Bit16u *)data) = value & 0xffff;
|
||||
else
|
||||
BX_PANIC(("Unsupported I/O APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", a20addr, len));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
|
||||
{
|
||||
if (len != 4) {
|
||||
BX_PANIC(("I/O apic write with len=%d (should be 4)", len));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(a20addr & 0xf) {
|
||||
BX_PANIC(("I/O apic write at unaligned address 0x" FMT_PHY_ADDRX, a20addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
theIOAPIC->write_aligned(a20addr, *((Bit32u*) data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bx_io_redirect_entry_t::sprintf_self(char *buf)
|
||||
{
|
||||
sprintf(buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x",
|
||||
(unsigned) destination(),
|
||||
(unsigned) is_masked(),
|
||||
(unsigned) trigger_mode(),
|
||||
(unsigned) remote_irr(),
|
||||
(unsigned) pin_polarity(),
|
||||
(unsigned) delivery_status(),
|
||||
(unsigned) destination_mode(),
|
||||
(unsigned) delivery_mode(),
|
||||
(unsigned) vector());
|
||||
}
|
||||
|
||||
void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
|
||||
{
|
||||
BXRS_HEX_PARAM_SIMPLE(parent, lo);
|
||||
BXRS_HEX_PARAM_SIMPLE(parent, hi);
|
||||
}
|
||||
|
||||
#define BX_IOAPIC_BASE_ADDR (0xfec00000)
|
||||
#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)
|
||||
|
||||
bx_ioapic_c::bx_ioapic_c(): base_addr(BX_IOAPIC_BASE_ADDR)
|
||||
{
|
||||
set_id(BX_IOAPIC_DEFAULT_ID);
|
||||
put("IOAP");
|
||||
}
|
||||
|
||||
void bx_ioapic_c::init(void)
|
||||
{
|
||||
BX_INFO(("initializing I/O APIC"));
|
||||
DEV_register_memory_handlers(theIOAPIC,
|
||||
ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
|
||||
reset(BX_RESET_HARDWARE);
|
||||
}
|
||||
|
||||
void bx_ioapic_c::reset(unsigned type)
|
||||
{
|
||||
// all interrupts masked
|
||||
for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
|
||||
ioredtbl[i].set_lo_part(0x00010000);
|
||||
ioredtbl[i].set_hi_part(0x00000000);
|
||||
}
|
||||
intin = 0;
|
||||
irr = 0;
|
||||
ioregsel = 0;
|
||||
}
|
||||
|
||||
Bit32u bx_ioapic_c::read_aligned(bx_phy_address address)
|
||||
{
|
||||
BX_DEBUG(("IOAPIC: read aligned addr=0x" FMT_PHY_ADDRX, address));
|
||||
address &= 0xff;
|
||||
if (address == 0x00) {
|
||||
// select register
|
||||
return ioregsel;
|
||||
} else {
|
||||
if (address != 0x10)
|
||||
BX_PANIC(("IOAPIC: read from unsupported address"));
|
||||
}
|
||||
|
||||
Bit32u data = 0;
|
||||
|
||||
// only reached when reading data register
|
||||
switch (ioregsel) {
|
||||
case 0x00: // APIC ID, note this is 4bits, the upper 4 are reserved
|
||||
data = ((id & apic_id_mask) << 24);
|
||||
break;
|
||||
case 0x01: // version
|
||||
data = BX_IOAPIC_VERSION_ID;
|
||||
break;
|
||||
case 0x02:
|
||||
BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
|
||||
break;
|
||||
default:
|
||||
int index = (ioregsel - 0x10) >> 1;
|
||||
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + index;
|
||||
data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
|
||||
break;
|
||||
}
|
||||
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u value)
|
||||
{
|
||||
BX_DEBUG(("IOAPIC: write aligned addr=%08x, data=%08x", (unsigned) address, value));
|
||||
address &= 0xff;
|
||||
if (address == 0x00) {
|
||||
ioregsel = value;
|
||||
return;
|
||||
} else {
|
||||
if (address != 0x10)
|
||||
BX_PANIC(("IOAPIC: write to unsupported address"));
|
||||
}
|
||||
// only reached when writing data register
|
||||
switch (ioregsel) {
|
||||
case 0x00: // set APIC ID
|
||||
{
|
||||
Bit8u newid = (value >> 24) & apic_id_mask;
|
||||
BX_INFO(("IOAPIC: setting id to 0x%x", newid));
|
||||
set_id (newid);
|
||||
return;
|
||||
}
|
||||
case 0x01: // version
|
||||
case 0x02: // arbitration id
|
||||
BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
|
||||
return;
|
||||
default:
|
||||
int index = (ioregsel - 0x10) >> 1;
|
||||
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + index;
|
||||
if (ioregsel&1)
|
||||
entry->set_hi_part(value);
|
||||
else
|
||||
entry->set_lo_part(value);
|
||||
char buf[1024];
|
||||
entry->sprintf_self(buf);
|
||||
BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
|
||||
service_ioapic();
|
||||
return;
|
||||
}
|
||||
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_ioapic_c::set_irq_level(Bit8u int_in, bx_bool level)
|
||||
{
|
||||
BX_DEBUG(("set_irq_level(): INTIN%d: level=%d", int_in, level));
|
||||
if (int_in < BX_IOAPIC_NUM_PINS) {
|
||||
Bit32u bit = 1<<int_in;
|
||||
if ((level<<int_in) != (intin & bit)) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + int_in;
|
||||
if (entry->trigger_mode()) {
|
||||
// level triggered
|
||||
if (level) {
|
||||
intin |= bit;
|
||||
irr |= bit;
|
||||
service_ioapic();
|
||||
} else {
|
||||
intin &= ~bit;
|
||||
irr &= ~bit;
|
||||
}
|
||||
} else {
|
||||
// edge triggered
|
||||
if (level) {
|
||||
intin |= bit;
|
||||
irr |= bit;
|
||||
service_ioapic();
|
||||
} else {
|
||||
intin &= ~bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_ioapic_c::receive_eoi(Bit8u vector)
|
||||
{
|
||||
BX_DEBUG(("IOAPIC: received EOI for vector %d", vector));
|
||||
}
|
||||
|
||||
void bx_ioapic_c::service_ioapic()
|
||||
{
|
||||
static unsigned int stuck = 0;
|
||||
Bit8u vector = 0;
|
||||
// look in IRR and deliver any interrupts that are not masked.
|
||||
BX_DEBUG(("IOAPIC: servicing"));
|
||||
for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
|
||||
Bit32u mask = 1<<bit;
|
||||
if (irr & mask) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + bit;
|
||||
if (! entry->is_masked()) {
|
||||
// clear irr bit and deliver
|
||||
if (entry->delivery_mode() == 7) {
|
||||
vector = DEV_pic_iac();
|
||||
} else {
|
||||
vector = entry->vector();
|
||||
}
|
||||
bx_bool done = apic_bus_deliver_interrupt(vector, entry->destination(), entry->delivery_mode(), entry->destination_mode(), entry->pin_polarity(), entry->trigger_mode());
|
||||
if (done) {
|
||||
if (! entry->trigger_mode())
|
||||
irr &= ~mask;
|
||||
entry->clear_delivery_status();
|
||||
stuck = 0;
|
||||
} else {
|
||||
entry->set_delivery_status();
|
||||
stuck++;
|
||||
if (stuck > 5)
|
||||
BX_INFO(("vector %#x stuck?", vector));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("service_ioapic(): INTIN%d is masked", bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_ioapic_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
|
||||
|
||||
BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
|
||||
BXRS_HEX_PARAM_SIMPLE(list, intin);
|
||||
BXRS_HEX_PARAM_SIMPLE(list, irr);
|
||||
|
||||
bx_list_c *table = new bx_list_c(list, "ioredtbl", BX_IOAPIC_NUM_PINS);
|
||||
for (unsigned i=0; i<BX_IOAPIC_NUM_PINS; i++) {
|
||||
char name[6];
|
||||
sprintf(name, "0x%02x", i);
|
||||
bx_list_c *entry = new bx_list_c(table, name, 2);
|
||||
ioredtbl[i].register_state(entry);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_APIC */
|
||||
112
bochs/iodev/ioapic.h
Normal file
112
bochs/iodev/ioapic.h
Normal file
@ -0,0 +1,112 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_DEVICES_IOAPIC_H
|
||||
#define BX_DEVICES_IOAPIC_H
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
|
||||
typedef Bit32u apic_dest_t; /* same definition in apic.h */
|
||||
|
||||
extern int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast);
|
||||
extern int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bx_bool logical_dest, bx_bool level, bx_bool trig_mode);
|
||||
extern int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bx_bool trig_mode, int exclude_cpu);
|
||||
|
||||
#define BX_IOAPIC_NUM_PINS (0x18)
|
||||
|
||||
// use the same version as 82093 IOAPIC (0x00170011)
|
||||
#define BX_IOAPIC_VERSION_ID (((BX_IOAPIC_NUM_PINS - 1) << 16) | 0x11)
|
||||
|
||||
class bx_io_redirect_entry_t {
|
||||
Bit32u hi, lo;
|
||||
|
||||
public:
|
||||
bx_io_redirect_entry_t(): hi(0), lo(0x10000) {}
|
||||
|
||||
Bit8u destination() const { return (Bit8u)(hi >> 24); }
|
||||
bx_bool is_masked() const { return (bx_bool)((lo >> 16) & 1); }
|
||||
Bit8u trigger_mode() const { return (Bit8u)((lo >> 15) & 1); }
|
||||
bx_bool remote_irr() const { return (bx_bool)((lo >> 14) & 1); }
|
||||
Bit8u pin_polarity() const { return (Bit8u)((lo >> 13) & 1); }
|
||||
bx_bool delivery_status() const { return (bx_bool)((lo >> 12) & 1); }
|
||||
Bit8u destination_mode() const { return (Bit8u)((lo >> 11) & 1); }
|
||||
Bit8u delivery_mode() const { return (Bit8u)((lo >> 8) & 7); }
|
||||
Bit8u vector() const { return (Bit8u)(lo & 0xff); }
|
||||
|
||||
void set_delivery_status() { lo |= (1<<12); }
|
||||
void clear_delivery_status() { lo &= ~(1<<12); }
|
||||
void set_remote_irr() { lo |= (1<<14); }
|
||||
void clear_remote_irr() { lo &= ~(1<<14); }
|
||||
|
||||
Bit32u get_lo_part () const { return lo; }
|
||||
Bit32u get_hi_part () const { return hi; }
|
||||
void set_lo_part (Bit32u val_lo_part) {
|
||||
// keep high 32 bits of value, replace low 32, ignore R/O bits
|
||||
lo = val_lo_part & 0xffffafff;
|
||||
}
|
||||
void set_hi_part (Bit32u val_hi_part) {
|
||||
// keep low 32 bits of value, replace high 32
|
||||
hi = val_hi_part;
|
||||
}
|
||||
void sprintf_self(char *buf);
|
||||
void register_state(bx_param_c *parent);
|
||||
};
|
||||
|
||||
class bx_ioapic_c : public bx_ioapic_stub_c {
|
||||
public:
|
||||
bx_ioapic_c();
|
||||
virtual ~bx_ioapic_c() {}
|
||||
virtual void init();
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
|
||||
virtual void receive_eoi(Bit8u vector);
|
||||
virtual void set_irq_level(Bit8u int_in, bx_bool level);
|
||||
|
||||
Bit32u read_aligned(bx_phy_address address);
|
||||
void write_aligned(bx_phy_address address, Bit32u data);
|
||||
|
||||
private:
|
||||
bx_phy_address get_base(void) const { return base_addr; }
|
||||
void set_id(Bit32u new_id) { id = new_id; }
|
||||
Bit32u get_id() const { return id; }
|
||||
|
||||
void service_ioapic(void);
|
||||
|
||||
bx_phy_address base_addr;
|
||||
Bit32u id;
|
||||
|
||||
Bit32u ioregsel; // selects between various registers
|
||||
Bit32u intin;
|
||||
// interrupt request bitmask, not visible from the outside. Bits in the
|
||||
// irr are set when trigger_irq is called, and cleared when the interrupt
|
||||
// is delivered to the processor. If an interrupt is masked, the irr
|
||||
// will still be set but delivery will not occur until it is unmasked.
|
||||
// It's not clear if this is how the real device works.
|
||||
Bit32u irr;
|
||||
|
||||
bx_io_redirect_entry_t ioredtbl[BX_IOAPIC_NUM_PINS]; // table of redirections
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
343
bochs/iodev/iodebug.cc
Normal file
343
bochs/iodev/iodebug.cc
Normal file
@ -0,0 +1,343 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_IODEBUG
|
||||
|
||||
#include "cpu/cpu.h"
|
||||
#include "iodebug.h"
|
||||
|
||||
#define BX_IODEBUG_THIS this->
|
||||
|
||||
bx_iodebug_c *theIODebugDevice = NULL;
|
||||
|
||||
int libiodebug_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theIODebugDevice = new bx_iodebug_c();
|
||||
bx_devices.pluginIODebug = theIODebugDevice;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIODebugDevice, BX_PLUGIN_IODEBUG);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libiodebug_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theIODebugDevice;
|
||||
}
|
||||
|
||||
struct bx_iodebug_s_type {
|
||||
bx_bool enabled;
|
||||
unsigned register_select;
|
||||
Bit32u registers[2];
|
||||
bx_phy_address monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
|
||||
bx_phy_address monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
|
||||
} bx_iodebug_s;
|
||||
|
||||
|
||||
bx_iodebug_c::bx_iodebug_c()
|
||||
{
|
||||
put("IODBG");
|
||||
}
|
||||
|
||||
void bx_iodebug_c::init(void)
|
||||
{
|
||||
DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 2);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 2);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 2);
|
||||
|
||||
bx_iodebug_s.enabled = 0;
|
||||
bx_iodebug_s.register_select = 0;
|
||||
|
||||
for(int i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
|
||||
bx_iodebug_s.monitored_mem_areas_start[i] = 0;
|
||||
bx_iodebug_s.monitored_mem_areas_end[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
|
||||
{
|
||||
bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
|
||||
return bx_iodebug_ptr->read(addr, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_iodebug_c::read(Bit32u addr, unsigned io_len)
|
||||
{
|
||||
if (bx_iodebug_s.enabled) return 0x8A00;
|
||||
return(0);
|
||||
}
|
||||
|
||||
void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
|
||||
{
|
||||
bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
|
||||
bx_iodebug_ptr->write(addr, dvalue, io_len);
|
||||
}
|
||||
|
||||
void bx_iodebug_c::write(Bit32u addr, Bit32u dvalue, unsigned io_len)
|
||||
{
|
||||
//fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned) addr, (unsigned) dvalue, io_len);
|
||||
|
||||
if (addr == 0x8A01)
|
||||
{
|
||||
bx_iodebug_s.registers[bx_iodebug_s.register_select] =
|
||||
(bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
|
||||
(dvalue & 0xFFFF);
|
||||
}
|
||||
|
||||
if (addr != 0x8A00) return;
|
||||
|
||||
if (!bx_iodebug_s.enabled)
|
||||
{
|
||||
if(dvalue == 0x8A00)
|
||||
{
|
||||
bx_iodebug_s.enabled = 1;
|
||||
// fprintf(stderr, "IODEBUG enabled\n");
|
||||
bx_iodebug_s.registers[0] = 0;
|
||||
bx_iodebug_s.registers[1] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch(dvalue)
|
||||
{
|
||||
case 0x8A01:
|
||||
bx_iodebug_s.register_select = 0;
|
||||
// fprintf(stderr, "IODEBUG register 0 selected\n");
|
||||
break;
|
||||
|
||||
case 0x8A02:
|
||||
bx_iodebug_s.register_select = 1;
|
||||
// fprintf(stderr, "IODEBUG register 1 selected\n");
|
||||
break;
|
||||
|
||||
case 0x8A80:
|
||||
bx_iodebug_s.register_select = 0;
|
||||
bx_iodebug_c::add_range(bx_iodebug_s.registers[0],
|
||||
bx_iodebug_s.registers[1]);
|
||||
bx_iodebug_s.registers[0] = 0;
|
||||
bx_iodebug_s.registers[1] = 0;
|
||||
break;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
case 0x8AE0:
|
||||
fprintf(stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
|
||||
bx_guard.interrupt_requested=1;
|
||||
break;
|
||||
|
||||
case 0x8AE2:
|
||||
fprintf(stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
|
||||
BX_CPU(dbg_cpu)->trace = 0;
|
||||
break;
|
||||
|
||||
case 0x8AE3:
|
||||
fprintf(stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
|
||||
BX_CPU(dbg_cpu)->trace = 1;
|
||||
break;
|
||||
|
||||
case 0x8AE4:
|
||||
fprintf(stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
|
||||
BX_CPU(dbg_cpu)->trace_reg = 0;
|
||||
break;
|
||||
|
||||
case 0x8AE5:
|
||||
fprintf(stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
|
||||
BX_CPU(dbg_cpu)->trace_reg = 1;
|
||||
break;
|
||||
#endif
|
||||
case 0x8AFF:
|
||||
bx_iodebug_s.enabled = 0;
|
||||
// fprintf(stderr, "IODEBUG device deactivated\n");
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// fprintf(stderr,"IODEBUG unsupported register code\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Static function
|
||||
void bx_iodebug_c::mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
|
||||
{
|
||||
if(! bx_iodebug_s.enabled) return;
|
||||
|
||||
unsigned area = bx_iodebug_c::range_test(addr, len);
|
||||
// Device is enabled, testing address ranges
|
||||
if(area)
|
||||
{
|
||||
area--;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
if (cpu != NULL) {
|
||||
fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " write at monitored memory location %8X\n",
|
||||
cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "IODEBUG write at monitored memory location %8X\n", addr);
|
||||
}
|
||||
bx_guard.interrupt_requested=1;
|
||||
#else
|
||||
fprintf(stderr, "IODEBUG write to monitored memory area: %2i\t", area);
|
||||
|
||||
if (cpu != NULL)
|
||||
fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
|
||||
else
|
||||
fprintf(stderr, "(device origin)\t");
|
||||
|
||||
fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
|
||||
bx_iodebug_s.monitored_mem_areas_start[area],
|
||||
bx_iodebug_s.monitored_mem_areas_end[area],
|
||||
(unsigned) addr);
|
||||
|
||||
switch(len)
|
||||
{
|
||||
case 1: {
|
||||
Bit8u data8 = * ((Bit8u *) data);
|
||||
fprintf(stderr,"%02X\n", (unsigned) data8);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
Bit16u data16 = * ((Bit16u *) data);
|
||||
fprintf(stderr,"%04X\n", (unsigned) data16);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
Bit32u data32 = * ((Bit32u *) data);
|
||||
fprintf(stderr,"%08X\n", (unsigned) data32);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
Bit64u data64 = * ((Bit64u *) data);
|
||||
fprintf(stderr,"%08X%08x\n",
|
||||
(unsigned) (data64 >> 32),
|
||||
(unsigned) (data64 & 0xffffffff));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "unsupported write size\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void bx_iodebug_c::mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
|
||||
{
|
||||
if(! bx_iodebug_s.enabled) return;
|
||||
|
||||
unsigned area = bx_iodebug_c::range_test(addr, len);
|
||||
// Device is enabled, testing address ranges
|
||||
if(area)
|
||||
{
|
||||
area--;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
if (cpu != NULL) {
|
||||
fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " read at monitored memory location %8X\n",
|
||||
cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "IODEBUG read at monitored memory location %8X\n", addr);
|
||||
}
|
||||
bx_guard.interrupt_requested=1;
|
||||
#else
|
||||
fprintf(stderr, "IODEBUG read at monitored memory area: %2i\t", area);
|
||||
|
||||
if (cpu != NULL)
|
||||
fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
|
||||
else
|
||||
fprintf(stderr, "(device origin)\t");
|
||||
|
||||
fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
|
||||
bx_iodebug_s.monitored_mem_areas_start[area],
|
||||
bx_iodebug_s.monitored_mem_areas_end[area],
|
||||
(unsigned) addr);
|
||||
|
||||
switch(len)
|
||||
{
|
||||
case 1: {
|
||||
Bit8u data8 = * ((Bit8u *) data);
|
||||
fprintf(stderr,"%02X\n", (unsigned) data8);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
Bit16u data16 = * ((Bit16u *) data);
|
||||
fprintf(stderr,"%04X\n", (unsigned) data16);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
Bit32u data32 = * ((Bit32u *) data);
|
||||
fprintf(stderr,"%08X\n", (unsigned) data32);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
Bit64u data64 = * ((Bit64u *) data);
|
||||
fprintf(stderr,"%08X%08x\n",
|
||||
(unsigned) (data64 >> 32),
|
||||
(unsigned) (data64 & 0xffffffff));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "unsupported read size\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
unsigned bx_iodebug_c::range_test(bx_phy_address addr, unsigned len)
|
||||
{
|
||||
for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
|
||||
{
|
||||
if(bx_iodebug_s.monitored_mem_areas_start[i] != 0 ||
|
||||
bx_iodebug_s.monitored_mem_areas_end[i] != 0)
|
||||
{
|
||||
if((Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i])
|
||||
continue;
|
||||
|
||||
if(addr < bx_iodebug_s.monitored_mem_areas_end[i])
|
||||
{
|
||||
return(++i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void bx_iodebug_c::add_range(bx_phy_address addr_start, bx_phy_address addr_end)
|
||||
{
|
||||
for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
|
||||
{
|
||||
if(!bx_iodebug_s.monitored_mem_areas_start[i] &&
|
||||
!bx_iodebug_s.monitored_mem_areas_end[i])
|
||||
{
|
||||
bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
|
||||
bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
|
||||
// fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_IODEBUG */
|
||||
49
bochs/iodev/iodebug.h
Normal file
49
bochs/iodev/iodebug.h
Normal file
@ -0,0 +1,49 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _BX_IODEBUG_H
|
||||
#define _BX_IODEBUG_H
|
||||
|
||||
#if BX_SUPPORT_IODEBUG
|
||||
|
||||
#define BX_IODEBUG_MAX_AREAS 30
|
||||
|
||||
class bx_iodebug_c : public bx_iodebug_stub_c {
|
||||
public:
|
||||
bx_iodebug_c();
|
||||
virtual ~bx_iodebug_c() {}
|
||||
virtual void init(void);
|
||||
virtual void reset (unsigned type) {}
|
||||
virtual void mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data);
|
||||
virtual void mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data);
|
||||
|
||||
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);
|
||||
Bit32u read(Bit32u addr, unsigned io_len);
|
||||
void write(Bit32u addr, Bit32u dvalue, unsigned io_len);
|
||||
static unsigned range_test(bx_phy_address addr, unsigned len);
|
||||
static void add_range(bx_phy_address addr_start, bx_phy_address addr_end);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
619
bochs/iodev/iodev.h
Normal file
619
bochs/iodev/iodev.h
Normal file
@ -0,0 +1,619 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2011 The Bochs Project
|
||||
//
|
||||
// I/O port handlers API Copyright (C) 2003 by Frank Cornelis
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef IODEV_H
|
||||
#define IODEV_H
|
||||
|
||||
#include "bochs.h"
|
||||
#include "param_names.h"
|
||||
|
||||
/* number of IRQ lines supported. In an ISA PC there are two
|
||||
PIC chips cascaded together. each has 8 IRQ lines, so there
|
||||
should be 16 IRQ's total */
|
||||
#define BX_MAX_IRQS 16
|
||||
|
||||
/* size of internal buffer for mouse devices */
|
||||
#define BX_MOUSE_BUFF_SIZE 48
|
||||
|
||||
#if 0
|
||||
class bx_g2h_c;
|
||||
#endif
|
||||
|
||||
typedef Bit32u (*bx_read_handler_t)(void *, Bit32u, unsigned);
|
||||
typedef void (*bx_write_handler_t)(void *, Bit32u, Bit32u, unsigned);
|
||||
|
||||
typedef bx_bool (*bx_keyb_enq_t)(void *, Bit8u *);
|
||||
typedef void (*bx_mouse_enq_t)(void *, int, int, int, unsigned);
|
||||
typedef void (*bx_mouse_enabled_changed_t)(void *, bx_bool);
|
||||
|
||||
#if BX_USE_DEV_SMF
|
||||
# define BX_DEV_SMF static
|
||||
# define BX_DEV_THIS bx_devices.
|
||||
#else
|
||||
# define BX_DEV_SMF
|
||||
# define BX_DEV_THIS this->
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// bx_devmodel_c declaration
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This class defines virtual methods that are common to all devices.
|
||||
// Child classes do not need to implement all of them, because in this
|
||||
// definition they are defined as empty, as opposed to being pure
|
||||
// virtual (= 0).
|
||||
class BOCHSAPI bx_devmodel_c : public logfunctions {
|
||||
public:
|
||||
virtual ~bx_devmodel_c() {}
|
||||
virtual void init(void) {}
|
||||
virtual void reset(unsigned type) {}
|
||||
virtual void register_state(void) {}
|
||||
virtual void after_restore_state(void) {}
|
||||
#if BX_DEBUGGER
|
||||
virtual void debug_dump(void) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// declare stubs for PCI devices
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class bx_list_c;
|
||||
class device_image_t;
|
||||
|
||||
// the best should be deriving of bx_pci_device_stub_c from bx_devmodel_c
|
||||
// but it make serious problems for cirrus_svga device
|
||||
class BOCHSAPI bx_pci_device_stub_c {
|
||||
public:
|
||||
virtual ~bx_pci_device_stub_c() {}
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len) {}
|
||||
|
||||
void register_pci_state(bx_list_c *list, Bit8u *pci_conf);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// declare stubs for devices
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#define STUBFUNC(dev,method) \
|
||||
pluginlog->panic("%s called in %s stub. you must not have loaded the %s plugin", #dev, #method, #dev)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BOCHSAPI bx_keyb_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual ~bx_keyb_stub_c() {}
|
||||
// stubs for bx_keyb_c methods
|
||||
virtual void gen_scancode(Bit32u key) {
|
||||
STUBFUNC(keyboard, gen_scancode);
|
||||
}
|
||||
virtual void paste_bytes(Bit8u *data, Bit32s length) {
|
||||
STUBFUNC(keyboard, paste_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_hard_drive_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void init() {
|
||||
STUBFUNC(HD, init);
|
||||
}
|
||||
virtual void reset(unsigned type) {
|
||||
STUBFUNC(HD, reset);
|
||||
}
|
||||
virtual Bit32u get_device_handle(Bit8u channel, Bit8u device) {
|
||||
STUBFUNC(HD, get_device_handle); return 0;
|
||||
}
|
||||
virtual Bit32u get_first_cd_handle(void) {
|
||||
STUBFUNC(HD, get_first_cd_handle); return 0;
|
||||
}
|
||||
virtual unsigned get_cd_media_status(Bit32u handle) {
|
||||
STUBFUNC(HD, get_cd_media_status); return 0;
|
||||
}
|
||||
virtual unsigned set_cd_media_status(Bit32u handle, unsigned status) {
|
||||
STUBFUNC(HD, set_cd_media_status); return 0;
|
||||
}
|
||||
virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len)
|
||||
{
|
||||
STUBFUNC(HD, virt_read_handler); return 0;
|
||||
}
|
||||
virtual void virt_write_handler(Bit32u address,
|
||||
Bit32u value, unsigned io_len)
|
||||
{
|
||||
STUBFUNC(HD, virt_write_handler);
|
||||
}
|
||||
virtual bx_bool bmdma_read_sector(Bit8u channel, Bit8u *buffer, Bit32u *sector_size) {
|
||||
STUBFUNC(HD, bmdma_read_sector); return 0;
|
||||
}
|
||||
virtual bx_bool bmdma_write_sector(Bit8u channel, Bit8u *buffer) {
|
||||
STUBFUNC(HD, bmdma_write_sector); return 0;
|
||||
}
|
||||
virtual void bmdma_complete(Bit8u channel) {
|
||||
STUBFUNC(HD, bmdma_complete);
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_floppy_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual unsigned set_media_status(unsigned drive, unsigned status) {
|
||||
STUBFUNC(floppy, set_media_status); return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_cmos_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual Bit32u get_reg(unsigned reg) {
|
||||
STUBFUNC(cmos, get_reg); return 0;
|
||||
}
|
||||
virtual void set_reg(unsigned reg, Bit32u val) {
|
||||
STUBFUNC(cmos, set_reg);
|
||||
}
|
||||
virtual time_t get_timeval() {
|
||||
return 0;
|
||||
}
|
||||
virtual void checksum_cmos(void) {
|
||||
STUBFUNC(cmos, checksum);
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_dma_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual unsigned registerDMA8Channel(
|
||||
unsigned channel,
|
||||
void (* dmaRead)(Bit8u *data_byte),
|
||||
void (* dmaWrite)(Bit8u *data_byte),
|
||||
const char *name)
|
||||
{
|
||||
STUBFUNC(dma, registerDMA8Channel); return 0;
|
||||
}
|
||||
virtual unsigned registerDMA16Channel(
|
||||
unsigned channel,
|
||||
void (* dmaRead)(Bit16u *data_word),
|
||||
void (* dmaWrite)(Bit16u *data_word),
|
||||
const char *name)
|
||||
{
|
||||
STUBFUNC(dma, registerDMA16Channel); return 0;
|
||||
}
|
||||
virtual unsigned unregisterDMAChannel(unsigned channel) {
|
||||
STUBFUNC(dma, unregisterDMAChannel); return 0;
|
||||
}
|
||||
virtual unsigned get_TC(void) {
|
||||
STUBFUNC(dma, get_TC); return 0;
|
||||
}
|
||||
virtual void set_DRQ(unsigned channel, bx_bool val) {
|
||||
STUBFUNC(dma, set_DRQ);
|
||||
}
|
||||
virtual void raise_HLDA(void) {
|
||||
STUBFUNC(dma, raise_HLDA);
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_pic_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void raise_irq(unsigned irq_no) {
|
||||
STUBFUNC(pic, raise_irq);
|
||||
}
|
||||
virtual void lower_irq(unsigned irq_no) {
|
||||
STUBFUNC(pic, lower_irq);
|
||||
}
|
||||
virtual void set_mode(bx_bool ma_sl, Bit8u mode) {
|
||||
STUBFUNC(pic, set_mode);
|
||||
}
|
||||
virtual Bit8u IAC(void) {
|
||||
STUBFUNC(pic, IAC); return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_vga_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void redraw_area(unsigned x0, unsigned y0,
|
||||
unsigned width, unsigned height) {
|
||||
STUBFUNC(vga, redraw_area);
|
||||
}
|
||||
virtual Bit8u mem_read(bx_phy_address addr) {
|
||||
STUBFUNC(vga, mem_read); return 0;
|
||||
}
|
||||
virtual void mem_write(bx_phy_address addr, Bit8u value) {
|
||||
STUBFUNC(vga, mem_write);
|
||||
}
|
||||
virtual void get_text_snapshot(Bit8u **text_snapshot,
|
||||
unsigned *txHeight, unsigned *txWidth) {
|
||||
STUBFUNC(vga, get_text_snapshot);
|
||||
}
|
||||
virtual void trigger_timer(void *this_ptr) {
|
||||
STUBFUNC(vga, trigger_timer);
|
||||
}
|
||||
virtual Bit8u get_actl_palette_idx(Bit8u index) {
|
||||
return 0;
|
||||
}
|
||||
virtual bx_bool vbe_set_base_addr(Bit32u *addr, Bit8u *pci_conf) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_pci_bridge_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
virtual bx_bool register_pci_handlers(bx_pci_device_stub_c *device,
|
||||
Bit8u *devfunc, const char *name,
|
||||
const char *descr)
|
||||
{
|
||||
STUBFUNC(pci, register_pci_handlers); return 0;
|
||||
}
|
||||
virtual bx_bool is_pci_device(const char *name) {
|
||||
return 0;
|
||||
}
|
||||
virtual bx_bool pci_set_base_mem(void *this_ptr, memory_handler_t f1, memory_handler_t f2,
|
||||
Bit32u *addr, Bit8u *pci_conf, unsigned size) {
|
||||
STUBFUNC(pci, pci_set_base_mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual bx_bool pci_set_base_io(void *this_ptr, bx_read_handler_t f1, bx_write_handler_t f2,
|
||||
Bit32u *addr, Bit8u *pci_conf, unsigned size,
|
||||
const Bit8u *iomask, const char *name) {
|
||||
STUBFUNC(pci, pci_set_base_io);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Bit8u rd_memType(Bit32u addr) { return 0; }
|
||||
virtual Bit8u wr_memType(Bit32u addr) { return 0; }
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_pci2isa_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
virtual void pci_set_irq (Bit8u devfunc, unsigned line, bx_bool level) {
|
||||
STUBFUNC(pci2isa, pci_set_irq);
|
||||
}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_pci_ide_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
virtual bx_bool bmdma_present(void) {
|
||||
return 0;
|
||||
}
|
||||
virtual void bmdma_set_irq(Bit8u channel) {}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_ne2k_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void print_info(FILE *file, int page, int reg, int nodups) {}
|
||||
};
|
||||
|
||||
class BOCHSAPI bx_speaker_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void beep_on(float frequency) {
|
||||
bx_gui->beep_on(frequency);
|
||||
}
|
||||
virtual void beep_off() {
|
||||
bx_gui->beep_off();
|
||||
}
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_ACPI
|
||||
class BOCHSAPI bx_acpi_ctrl_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
virtual void generate_smi(Bit8u value) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_IODEBUG
|
||||
class BOCHSAPI bx_iodebug_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data) {
|
||||
STUBFUNC(iodebug, mem_write);
|
||||
}
|
||||
virtual void mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data) {
|
||||
STUBFUNC(iodebug, mem_read);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
class BOCHSAPI bx_ioapic_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void receive_eoi(Bit8u vector) {}
|
||||
virtual void set_irq_level(Bit8u int_in, bx_bool level) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_PCIUSB
|
||||
class BOCHSAPI bx_usb_devctl_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual int init_device(bx_list_c *portconf, logfunctions *hub, void **dev, bx_list_c *sr_list) {
|
||||
STUBFUNC(usb_devctl, init_device); return 0;
|
||||
}
|
||||
virtual void usb_send_msg(void *dev, int msg) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
class BOCHSAPI bx_hdimage_ctl_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual device_image_t* init_image(Bit8u image_mode, Bit64u disk_size, const char *journal) {
|
||||
STUBFUNC(hdimage_ctl, init_image); return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_SB16
|
||||
class BOCHSAPI bx_soundmod_ctl_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual int init_module(const char *type, void **module, logfunctions *dev) {
|
||||
STUBFUNC(soundmod_ctl, init_module); return 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class BOCHSAPI bx_devices_c : public logfunctions {
|
||||
public:
|
||||
bx_devices_c();
|
||||
~bx_devices_c();
|
||||
|
||||
// Initialize the device stubs (in constructur and exit())
|
||||
void init_stubs(void);
|
||||
// Register I/O addresses and IRQ lines. Initialize any internal
|
||||
// structures. init() is called only once, even if the simulator
|
||||
// reboots or is restarted.
|
||||
void init(BX_MEM_C *);
|
||||
// Enter reset state in response to a reset condition.
|
||||
// The types of reset conditions are defined in bochs.h:
|
||||
// power-on, hardware, or software.
|
||||
void reset(unsigned type);
|
||||
// Cleanup the devices when the simulation quits.
|
||||
void exit(void);
|
||||
void register_state(void);
|
||||
void after_restore_state(void);
|
||||
BX_MEM_C *mem; // address space associated with these devices
|
||||
bx_bool register_io_read_handler(void *this_ptr, bx_read_handler_t f,
|
||||
Bit32u addr, const char *name, Bit8u mask);
|
||||
bx_bool unregister_io_read_handler(void *this_ptr, bx_read_handler_t f,
|
||||
Bit32u addr, Bit8u mask);
|
||||
bx_bool register_io_write_handler(void *this_ptr, bx_write_handler_t f,
|
||||
Bit32u addr, const char *name, Bit8u mask);
|
||||
bx_bool unregister_io_write_handler(void *this_ptr, bx_write_handler_t f,
|
||||
Bit32u addr, Bit8u mask);
|
||||
bx_bool register_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
|
||||
Bit32u begin_addr, Bit32u end_addr,
|
||||
const char *name, Bit8u mask);
|
||||
bx_bool register_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
|
||||
Bit32u begin_addr, Bit32u end_addr,
|
||||
const char *name, Bit8u mask);
|
||||
bx_bool unregister_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
|
||||
Bit32u begin, Bit32u end, Bit8u mask);
|
||||
bx_bool unregister_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
|
||||
Bit32u begin, Bit32u end, Bit8u mask);
|
||||
bx_bool register_default_io_read_handler(void *this_ptr, bx_read_handler_t f, const char *name, Bit8u mask);
|
||||
bx_bool register_default_io_write_handler(void *this_ptr, bx_write_handler_t f, const char *name, Bit8u mask);
|
||||
bx_bool register_irq(unsigned irq, const char *name);
|
||||
bx_bool unregister_irq(unsigned irq, const char *name);
|
||||
Bit32u inp(Bit16u addr, unsigned io_len) BX_CPP_AttrRegparmN(2);
|
||||
void outp(Bit16u addr, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
|
||||
|
||||
void register_removable_keyboard(void *dev, bx_keyb_enq_t keyb_enq);
|
||||
void unregister_removable_keyboard(void *dev);
|
||||
void register_default_mouse(void *dev, bx_mouse_enq_t mouse_enq, bx_mouse_enabled_changed_t mouse_enabled_changed);
|
||||
void register_removable_mouse(void *dev, bx_mouse_enq_t mouse_enq, bx_mouse_enabled_changed_t mouse_enabled_changed);
|
||||
void unregister_removable_mouse(void *dev);
|
||||
bx_bool optional_key_enq(Bit8u *scan_code);
|
||||
void mouse_enabled_changed(bx_bool enabled);
|
||||
void mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
|
||||
static void timer_handler(void *);
|
||||
void timer(void);
|
||||
|
||||
bx_pci_bridge_stub_c *pluginPciBridge;
|
||||
bx_pci2isa_stub_c *pluginPci2IsaBridge;
|
||||
bx_pci_ide_stub_c *pluginPciIdeController;
|
||||
#if BX_SUPPORT_ACPI
|
||||
bx_acpi_ctrl_stub_c *pluginACPIController;
|
||||
#endif
|
||||
bx_devmodel_c *pluginPitDevice;
|
||||
bx_keyb_stub_c *pluginKeyboard;
|
||||
bx_dma_stub_c *pluginDmaDevice;
|
||||
bx_floppy_stub_c *pluginFloppyDevice;
|
||||
bx_cmos_stub_c *pluginCmosDevice;
|
||||
bx_vga_stub_c *pluginVgaDevice;
|
||||
bx_pic_stub_c *pluginPicDevice;
|
||||
bx_hard_drive_stub_c *pluginHardDrive;
|
||||
bx_hdimage_ctl_stub_c *pluginHDImageCtl;
|
||||
bx_ne2k_stub_c *pluginNE2kDevice[4];
|
||||
bx_speaker_stub_c *pluginSpeaker;
|
||||
#if BX_SUPPORT_IODEBUG
|
||||
bx_iodebug_stub_c *pluginIODebug;
|
||||
#endif
|
||||
#if BX_SUPPORT_APIC
|
||||
bx_ioapic_stub_c *pluginIOAPIC;
|
||||
#endif
|
||||
#if BX_SUPPORT_PCIUSB
|
||||
bx_usb_devctl_stub_c *pluginUsbDevCtl;
|
||||
#endif
|
||||
#if BX_SUPPORT_SB16
|
||||
bx_soundmod_ctl_stub_c *pluginSoundModCtl;
|
||||
#endif
|
||||
#if 0
|
||||
bx_g2h_c *g2h;
|
||||
#endif
|
||||
|
||||
// stub classes that the pointers (above) can point to until a plugin is
|
||||
// loaded
|
||||
bx_cmos_stub_c stubCmos;
|
||||
bx_keyb_stub_c stubKeyboard;
|
||||
bx_hard_drive_stub_c stubHardDrive;
|
||||
bx_hdimage_ctl_stub_c stubHDImage;
|
||||
bx_dma_stub_c stubDma;
|
||||
bx_pic_stub_c stubPic;
|
||||
bx_floppy_stub_c stubFloppy;
|
||||
bx_vga_stub_c stubVga;
|
||||
bx_pci_bridge_stub_c stubPci;
|
||||
bx_pci2isa_stub_c stubPci2Isa;
|
||||
bx_pci_ide_stub_c stubPciIde;
|
||||
bx_ne2k_stub_c stubNE2k;
|
||||
bx_speaker_stub_c stubSpeaker;
|
||||
#if BX_SUPPORT_ACPI
|
||||
bx_acpi_ctrl_stub_c stubACPIController;
|
||||
#endif
|
||||
#if BX_SUPPORT_IODEBUG
|
||||
bx_iodebug_stub_c stubIODebug;
|
||||
#endif
|
||||
#if BX_SUPPORT_APIC
|
||||
bx_ioapic_stub_c stubIOAPIC;
|
||||
#endif
|
||||
#if BX_SUPPORT_PCIUSB
|
||||
bx_usb_devctl_stub_c stubUsbDevCtl;
|
||||
#endif
|
||||
#if BX_SUPPORT_SB16
|
||||
bx_soundmod_ctl_stub_c stubSoundModCtl;
|
||||
#endif
|
||||
|
||||
// Some info to pass to devices which can handled bulk IO. This allows
|
||||
// the interface to remain the same for IO devices which can't handle
|
||||
// bulk IO. We should probably implement special INPBulk() and OUTBulk()
|
||||
// functions which stick these values in the bx_devices_c class, and
|
||||
// then call the normal functions rather than having gross globals
|
||||
// variables.
|
||||
Bit8u* bulkIOHostAddr;
|
||||
unsigned bulkIOQuantumsRequested;
|
||||
unsigned bulkIOQuantumsTransferred;
|
||||
|
||||
private:
|
||||
|
||||
struct io_handler_struct {
|
||||
struct io_handler_struct *next;
|
||||
struct io_handler_struct *prev;
|
||||
void *funct; // C++ type checking is great, but annoying
|
||||
void *this_ptr;
|
||||
char *handler_name; // name of device
|
||||
int usage_count;
|
||||
Bit8u mask; // io_len mask
|
||||
};
|
||||
struct io_handler_struct io_read_handlers;
|
||||
struct io_handler_struct io_write_handlers;
|
||||
#define PORTS 0x10000
|
||||
struct io_handler_struct **read_port_to_handler;
|
||||
struct io_handler_struct **write_port_to_handler;
|
||||
|
||||
// more for informative purposes, the names of the devices which
|
||||
// are use each of the IRQ 0..15 lines are stored here
|
||||
char *irq_handler_name[BX_MAX_IRQS];
|
||||
|
||||
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);
|
||||
BX_DEV_SMF Bit32u port92_read(Bit32u address, unsigned io_len);
|
||||
BX_DEV_SMF void port92_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
|
||||
static Bit32u default_read_handler(void *this_ptr, Bit32u address, unsigned io_len);
|
||||
static void default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
|
||||
|
||||
bx_bool mouse_captured; // host mouse capture enabled
|
||||
Bit8u mouse_type;
|
||||
struct {
|
||||
void *dev;
|
||||
bx_mouse_enq_t enq_event;
|
||||
bx_mouse_enabled_changed_t enabled_changed;
|
||||
} bx_mouse[2];
|
||||
struct {
|
||||
void *dev;
|
||||
bx_keyb_enq_t enq_event;
|
||||
} bx_keyboard;
|
||||
|
||||
int timer_handle;
|
||||
|
||||
bx_bool is_harddrv_enabled();
|
||||
bx_bool is_serial_enabled();
|
||||
bx_bool is_parallel_enabled();
|
||||
bx_bool is_usb_ohci_enabled();
|
||||
bx_bool is_usb_uhci_enabled();
|
||||
};
|
||||
|
||||
// memory stub has an assumption that there are no memory accesses splitting 4K page
|
||||
BX_CPP_INLINE void DEV_MEM_READ_PHYSICAL(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
|
||||
{
|
||||
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
|
||||
if (len <= remainingInPage) {
|
||||
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, len, ptr);
|
||||
}
|
||||
else {
|
||||
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, remainingInPage, ptr);
|
||||
ptr += remainingInPage;
|
||||
phy_addr += remainingInPage;
|
||||
len -= remainingInPage;
|
||||
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, len, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void DEV_MEM_READ_PHYSICAL_BLOCK(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
|
||||
{
|
||||
Bit8u *memptr;
|
||||
|
||||
while(len > 0) {
|
||||
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
|
||||
if (len < remainingInPage) remainingInPage = len;
|
||||
memptr = BX_MEM(0)->getHostMemAddr(NULL, phy_addr, BX_READ);
|
||||
if (memptr != NULL) {
|
||||
memcpy(ptr, memptr, remainingInPage);
|
||||
}
|
||||
ptr += remainingInPage;
|
||||
phy_addr += remainingInPage;
|
||||
len -= remainingInPage;
|
||||
}
|
||||
}
|
||||
|
||||
// memory stub has an assumption that there are no memory accesses splitting 4K page
|
||||
BX_CPP_INLINE void DEV_MEM_WRITE_PHYSICAL(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
|
||||
{
|
||||
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
|
||||
if (len <= remainingInPage) {
|
||||
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, len, ptr);
|
||||
}
|
||||
else {
|
||||
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, remainingInPage, ptr);
|
||||
ptr += remainingInPage;
|
||||
phy_addr += remainingInPage;
|
||||
len -= remainingInPage;
|
||||
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, len, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void DEV_MEM_WRITE_PHYSICAL_BLOCK(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
|
||||
{
|
||||
Bit8u *memptr;
|
||||
|
||||
while(len > 0) {
|
||||
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
|
||||
if (len < remainingInPage) remainingInPage = len;
|
||||
memptr = BX_MEM(0)->getHostMemAddr(NULL, phy_addr, BX_WRITE);
|
||||
if (memptr != NULL) {
|
||||
memcpy(memptr, ptr, remainingInPage);
|
||||
}
|
||||
ptr += remainingInPage;
|
||||
phy_addr += remainingInPage;
|
||||
len -= remainingInPage;
|
||||
}
|
||||
}
|
||||
|
||||
BOCHSAPI extern bx_devices_c bx_devices;
|
||||
|
||||
#endif /* IODEV_H */
|
||||
1685
bochs/iodev/keyboard.cc
Normal file
1685
bochs/iodev/keyboard.cc
Normal file
File diff suppressed because it is too large
Load Diff
234
bochs/iodev/keyboard.h
Normal file
234
bochs/iodev/keyboard.h
Normal file
@ -0,0 +1,234 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef _PCKEY_H
|
||||
#define _PCKEY_H
|
||||
|
||||
#define BX_KBD_ELEMENTS 16
|
||||
|
||||
// these keywords should only be used in keyboard.cc
|
||||
#if BX_USE_KEY_SMF
|
||||
# define BX_KEY_SMF static
|
||||
# define BX_KEY_THIS theKeyboard->
|
||||
#else
|
||||
# define BX_KEY_SMF
|
||||
# define BX_KEY_THIS this->
|
||||
#endif
|
||||
|
||||
#define MOUSE_MODE_RESET 10
|
||||
#define MOUSE_MODE_STREAM 11
|
||||
#define MOUSE_MODE_REMOTE 12
|
||||
#define MOUSE_MODE_WRAP 13
|
||||
|
||||
class bx_keyb_c : public bx_keyb_stub_c {
|
||||
public:
|
||||
bx_keyb_c();
|
||||
virtual ~bx_keyb_c();
|
||||
// implement bx_devmodel_c interface
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
// override stubs from bx_keyb_stub_c
|
||||
virtual void gen_scancode(Bit32u key);
|
||||
virtual void paste_bytes(Bit8u *data, Bit32s length);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
// runtime options
|
||||
static Bit64s kbd_param_handler(bx_param_c *param, int set, Bit64s val);
|
||||
BX_KEY_SMF void paste_delay_changed(Bit32u value);
|
||||
|
||||
private:
|
||||
BX_KEY_SMF Bit8u get_kbd_enable(void);
|
||||
BX_KEY_SMF void service_paste_buf ();
|
||||
BX_KEY_SMF void create_mouse_packet(bx_bool force_enq);
|
||||
BX_KEY_SMF unsigned periodic(Bit32u usec_delta);
|
||||
|
||||
|
||||
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 matching the status port*/
|
||||
bx_bool pare; // Bit7, 1= parity error from keyboard/mouse - ignored.
|
||||
bx_bool tim; // Bit6, 1= timeout from keyboard - ignored.
|
||||
bx_bool auxb; // Bit5, 1= mouse data waiting for CPU to read.
|
||||
bx_bool keyl; // Bit4, 1= keyswitch in lock position - ignored.
|
||||
bx_bool c_d; /* Bit3, 1=command to port 64h, 0=data to port 60h */
|
||||
bx_bool sysf; // Bit2,
|
||||
bx_bool inpb; // Bit1,
|
||||
bx_bool outb; // Bit0, 1= keyboard data or mouse data ready for CPU
|
||||
// check aux to see which. Or just keyboard
|
||||
// data before AT style machines
|
||||
|
||||
/* internal to our version of the keyboard controller */
|
||||
bx_bool kbd_clock_enabled;
|
||||
bx_bool aux_clock_enabled;
|
||||
bx_bool allow_irq1;
|
||||
bx_bool allow_irq12;
|
||||
Bit8u kbd_output_buffer;
|
||||
Bit8u aux_output_buffer;
|
||||
Bit8u last_comm;
|
||||
Bit8u expecting_port60h;
|
||||
Bit8u expecting_mouse_parameter;
|
||||
Bit8u last_mouse_command;
|
||||
Bit32u timer_pending;
|
||||
bx_bool irq1_requested;
|
||||
bx_bool irq12_requested;
|
||||
bx_bool scancodes_translate;
|
||||
bx_bool expecting_scancodes_set;
|
||||
Bit8u current_scancodes_set;
|
||||
bx_bool bat_in_progress;
|
||||
} kbd_controller;
|
||||
|
||||
struct mouseStruct {
|
||||
Bit8u type;
|
||||
Bit8u sample_rate;
|
||||
Bit8u resolution_cpmm; // resolution in counts per mm
|
||||
Bit8u scaling;
|
||||
Bit8u mode;
|
||||
Bit8u saved_mode; // the mode prior to entering wrap mode
|
||||
bx_bool enable;
|
||||
|
||||
Bit8u get_status_byte ()
|
||||
{
|
||||
// top bit is 0 , bit 6 is 1 if remote mode.
|
||||
Bit8u ret = (Bit8u) ((mode == MOUSE_MODE_REMOTE) ? 0x40 : 0);
|
||||
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:
|
||||
genlog->panic("mouse: invalid resolution_cpmm");
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bit8u button_status;
|
||||
Bit16s delayed_dx;
|
||||
Bit16s delayed_dy;
|
||||
Bit16s delayed_dz;
|
||||
Bit8u im_request;
|
||||
bx_bool im_mode;
|
||||
} mouse;
|
||||
|
||||
struct {
|
||||
int num_elements;
|
||||
Bit8u buffer[BX_KBD_ELEMENTS];
|
||||
int head;
|
||||
bx_bool expecting_typematic;
|
||||
bx_bool expecting_led_write;
|
||||
Bit8u delay;
|
||||
Bit8u repeat_rate;
|
||||
Bit8u led_status;
|
||||
bx_bool 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
|
||||
} s; // State information for saving/loading
|
||||
|
||||
// The paste buffer does NOT exist in the hardware. It is a bochs
|
||||
// construction that allows the user to "paste" arbitrary length sequences of
|
||||
// keystrokes into the emulated machine. Since the hardware buffer is only
|
||||
// 16 bytes, a very small amount of data can be added to the hardware buffer
|
||||
// at a time. The paste buffer keeps track of the bytes that have not yet
|
||||
// been pasted.
|
||||
//
|
||||
// Lifetime of a paste buffer: The paste data comes from the system
|
||||
// clipboard, which must be accessed using platform independent code in the
|
||||
// gui. Because every gui has its own way of managing the clipboard memory
|
||||
// (in X windows, you're supposed to call Xfree for example), in the platform
|
||||
// specific code we make a copy of the clipboard buffer with
|
||||
// "new Bit8u[length]". Then the pointer is passed into
|
||||
// bx_keyb_c::paste_bytes, along with the length. The gui code never touches
|
||||
// the pastebuf again, and does not free it. The keyboard code is
|
||||
// responsible for deallocating the paste buffer using delete [] buf. The
|
||||
// paste buffer is binary data, and it is probably NOT null terminated.
|
||||
//
|
||||
// Summary: A paste buffer is allocated (new) in the platform-specific gui
|
||||
// code, passed to the keyboard model, and is freed (delete[]) when it is no
|
||||
// longer needed.
|
||||
Bit8u *pastebuf; // ptr to bytes to be pasted, or NULL if none in progress
|
||||
Bit32u pastebuf_len; // length of pastebuf
|
||||
Bit32u pastebuf_ptr; // ptr to next byte to be added to hw buffer
|
||||
Bit32u pastedelay; // count before paste
|
||||
bx_bool paste_service; // set to 1 when gen_scancode() is called from paste service
|
||||
bx_bool stop_paste; // stop the current paste operation on keypress or hardware reset
|
||||
|
||||
BX_KEY_SMF void resetinternals(bx_bool powerup);
|
||||
BX_KEY_SMF void set_kbd_clock_enable(Bit8u value) BX_CPP_AttrRegparmN(1);
|
||||
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 bx_bool mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3, Bit8u b4);
|
||||
BX_KEY_SMF void mouse_enQ(Bit8u mouse_data);
|
||||
|
||||
static void mouse_enabled_changed_static(void *dev, bx_bool enabled);
|
||||
void mouse_enabled_changed(bx_bool enabled);
|
||||
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
void mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
|
||||
static void timer_handler(void *);
|
||||
void timer(void);
|
||||
int timer_handle;
|
||||
int statusbar_id[3];
|
||||
};
|
||||
|
||||
#endif // #ifndef _PCKEY_H
|
||||
1931
bochs/iodev/ne2k.cc
Normal file
1931
bochs/iodev/ne2k.cc
Normal file
File diff suppressed because it is too large
Load Diff
263
bochs/iodev/ne2k.h
Normal file
263
bochs/iodev/ne2k.h
Normal file
@ -0,0 +1,263 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
|
||||
// NE2000/ether stuff.
|
||||
|
||||
//
|
||||
// An implementation of an ne2000 ISA ethernet adapter. This part uses
|
||||
// a National Semiconductor DS-8390 ethernet MAC chip, with some h/w
|
||||
// to provide a windowed memory region for the chip and a MAC address.
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_NE2K
|
||||
#define BX_IODEV_NE2K
|
||||
|
||||
#if BX_USE_NE2K_SMF
|
||||
#error Ne2K cannot user Static functions with multiple NICS
|
||||
#error Change BX USER NE2K SMF in config.h to 0
|
||||
# define BX_NE2K_SMF static
|
||||
# define BX_NE2K_THIS theNE2kDevice->
|
||||
# define BX_NE2K_THIS_PTR theNE2kDevice
|
||||
#else
|
||||
# define BX_NE2K_SMF
|
||||
# define BX_NE2K_THIS this->
|
||||
# define BX_NE2K_THIS_PTR this
|
||||
#endif
|
||||
|
||||
#define BX_NE2K_MEMSIZ (32*1024)
|
||||
#define BX_NE2K_MEMSTART (16*1024)
|
||||
#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
|
||||
|
||||
#define BX_NE2K_MAXDEV 4
|
||||
|
||||
class eth_pktmover_c;
|
||||
|
||||
typedef struct {
|
||||
//
|
||||
// ne2k register state
|
||||
|
||||
//
|
||||
// Page 0
|
||||
//
|
||||
// Command Register - 00h read/write
|
||||
struct {
|
||||
bx_bool stop; // STP - Software Reset command
|
||||
bx_bool start; // START - start the NIC
|
||||
bx_bool tx_packet; // TXP - initiate packet transmission
|
||||
Bit8u rdma_cmd; // RD0,RD1,RD2 - Remote DMA command
|
||||
Bit8u pgsel; // PS0,PS1 - Page select
|
||||
} CR;
|
||||
// Interrupt Status Register - 07h read/write
|
||||
struct {
|
||||
bx_bool pkt_rx; // PRX - packet received with no errors
|
||||
bx_bool pkt_tx; // PTX - packet transmitted with no errors
|
||||
bx_bool rx_err; // RXE - packet received with 1 or more errors
|
||||
bx_bool tx_err; // TXE - packet tx'd " " " " "
|
||||
bx_bool overwrite; // OVW - rx buffer resources exhausted
|
||||
bx_bool cnt_oflow; // CNT - network tally counter MSB's set
|
||||
bx_bool rdma_done; // RDC - remote DMA complete
|
||||
bx_bool reset; // RST - reset status
|
||||
} ISR;
|
||||
// Interrupt Mask Register - 0fh write
|
||||
struct {
|
||||
bx_bool rx_inte; // PRXE - packet rx interrupt enable
|
||||
bx_bool tx_inte; // PTXE - packet tx interrput enable
|
||||
bx_bool rxerr_inte; // RXEE - rx error interrupt enable
|
||||
bx_bool txerr_inte; // TXEE - tx error interrupt enable
|
||||
bx_bool overw_inte; // OVWE - overwrite warn int enable
|
||||
bx_bool cofl_inte; // CNTE - counter o'flow int enable
|
||||
bx_bool rdma_inte; // RDCE - remote DMA complete int enable
|
||||
bx_bool reserved; // D7 - reserved
|
||||
} IMR;
|
||||
// Data Configuration Register - 0eh write
|
||||
struct {
|
||||
bx_bool wdsize; // WTS - 8/16-bit select
|
||||
bx_bool endian; // BOS - byte-order select
|
||||
bx_bool longaddr; // LAS - long-address select
|
||||
bx_bool loop; // LS - loopback select
|
||||
bx_bool auto_rx; // AR - auto-remove rx packets with remote DMA
|
||||
Bit8u fifo_size; // FT0,FT1 - fifo threshold
|
||||
} DCR;
|
||||
// Transmit Configuration Register - 0dh write
|
||||
struct {
|
||||
bx_bool crc_disable; // CRC - inhibit tx CRC
|
||||
Bit8u loop_cntl; // LB0,LB1 - loopback control
|
||||
bx_bool ext_stoptx; // ATD - allow tx disable by external mcast
|
||||
bx_bool coll_prio; // OFST - backoff algorithm select
|
||||
Bit8u reserved; // D5,D6,D7 - reserved
|
||||
} TCR;
|
||||
// Transmit Status Register - 04h read
|
||||
struct {
|
||||
bx_bool tx_ok; // PTX - tx complete without error
|
||||
bx_bool reserved; // D1 - reserved
|
||||
bx_bool collided; // COL - tx collided >= 1 times
|
||||
bx_bool aborted; // ABT - aborted due to excessive collisions
|
||||
bx_bool no_carrier; // CRS - carrier-sense lost
|
||||
bx_bool fifo_ur; // FU - FIFO underrun
|
||||
bx_bool cd_hbeat; // CDH - no tx cd-heartbeat from transceiver
|
||||
bx_bool ow_coll; // OWC - out-of-window collision
|
||||
} TSR;
|
||||
// Receive Configuration Register - 0ch write
|
||||
struct {
|
||||
bx_bool errors_ok; // SEP - accept pkts with rx errors
|
||||
bx_bool runts_ok; // AR - accept < 64-byte runts
|
||||
bx_bool broadcast; // AB - accept eth broadcast address
|
||||
bx_bool multicast; // AM - check mcast hash array
|
||||
bx_bool promisc; // PRO - accept all packets
|
||||
bx_bool monitor; // MON - check pkts, but don't rx
|
||||
Bit8u reserved; // D6,D7 - reserved
|
||||
} RCR;
|
||||
// Receive Status Register - 0ch read
|
||||
struct {
|
||||
bx_bool rx_ok; // PRX - rx complete without error
|
||||
bx_bool bad_crc; // CRC - Bad CRC detected
|
||||
bx_bool bad_falign; // FAE - frame alignment error
|
||||
bx_bool fifo_or; // FO - FIFO overrun
|
||||
bx_bool rx_missed; // MPA - missed packet error
|
||||
bx_bool rx_mbit; // PHY - unicast or mcast/bcast address match
|
||||
bx_bool rx_disabled; // DIS - set when in monitor mode
|
||||
bx_bool deferred; // DFR - collision active
|
||||
} RSR;
|
||||
|
||||
Bit16u local_dma; // 01,02h read ; current local DMA addr
|
||||
Bit8u page_start; // 01h write ; page start register
|
||||
Bit8u page_stop; // 02h write ; page stop register
|
||||
Bit8u bound_ptr; // 03h read/write ; boundary pointer
|
||||
Bit8u tx_page_start; // 04h write ; transmit page start register
|
||||
Bit8u num_coll; // 05h read ; number-of-collisions register
|
||||
Bit16u tx_bytes; // 05,06h write ; transmit byte-count register
|
||||
Bit8u fifo; // 06h read ; FIFO
|
||||
Bit16u remote_dma; // 08,09h read ; current remote DMA addr
|
||||
Bit16u remote_start; // 08,09h write ; remote start address register
|
||||
Bit16u remote_bytes; // 0a,0bh write ; remote byte-count register
|
||||
Bit8u tallycnt_0; // 0dh read ; tally counter 0 (frame align errors)
|
||||
Bit8u tallycnt_1; // 0eh read ; tally counter 1 (CRC errors)
|
||||
Bit8u tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors)
|
||||
|
||||
//
|
||||
// Page 1
|
||||
//
|
||||
// Command Register 00h (repeated)
|
||||
//
|
||||
Bit8u physaddr[6]; // 01-06h read/write ; MAC address
|
||||
Bit8u curr_page; // 07h read/write ; current page register
|
||||
Bit8u mchash[8]; // 08-0fh read/write ; multicast hash array
|
||||
|
||||
//
|
||||
// Page 2 - diagnostic use only
|
||||
//
|
||||
// Command Register 00h (repeated)
|
||||
//
|
||||
// Page Start Register 01h read (repeated)
|
||||
// Page Stop Register 02h read (repeated)
|
||||
// Current Local DMA Address 01,02h write (repeated)
|
||||
// Transmit Page start address 04h read (repeated)
|
||||
// Receive Configuration Register 0ch read (repeated)
|
||||
// Transmit Configuration Register 0dh read (repeated)
|
||||
// Data Configuration Register 0eh read (repeated)
|
||||
// Interrupt Mask Register 0fh read (repeated)
|
||||
//
|
||||
Bit8u rempkt_ptr; // 03h read/write ; remote next-packet pointer
|
||||
Bit8u localpkt_ptr; // 05h read/write ; local next-packet pointer
|
||||
Bit16u address_cnt; // 06,07h read/write ; address counter
|
||||
|
||||
//
|
||||
// Page 3 - should never be modified.
|
||||
//
|
||||
|
||||
// Novell ASIC state
|
||||
Bit8u macaddr[32]; // ASIC ROM'd MAC address, even bytes
|
||||
Bit8u mem[BX_NE2K_MEMSIZ]; // on-chip packet memory
|
||||
|
||||
// ne2k internal state
|
||||
Bit32u base_address;
|
||||
int base_irq;
|
||||
int tx_timer_index;
|
||||
bx_bool tx_timer_active;
|
||||
|
||||
// pci stuff
|
||||
bx_bool pci_enabled;
|
||||
#if BX_SUPPORT_PCI
|
||||
Bit8u devfunc;
|
||||
Bit8u pci_conf[256];
|
||||
#endif
|
||||
} bx_ne2k_t;
|
||||
|
||||
class bx_ne2k_c : public bx_ne2k_stub_c
|
||||
#if BX_SUPPORT_PCI
|
||||
, public bx_pci_device_stub_c
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
bx_ne2k_c();
|
||||
virtual ~bx_ne2k_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void print_info (FILE *file, int page, int reg, int nodups);
|
||||
virtual void register_state(void);
|
||||
#if BX_SUPPORT_PCI
|
||||
virtual void after_restore_state(void);
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_PCI
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
int interfaceNo;
|
||||
private:
|
||||
bx_ne2k_t s;
|
||||
|
||||
eth_pktmover_c *ethdev;
|
||||
|
||||
BX_NE2K_SMF Bit32u read_cr(void);
|
||||
BX_NE2K_SMF void write_cr(Bit32u value);
|
||||
BX_NE2K_SMF void set_irq_level(bx_bool level);
|
||||
|
||||
BX_NE2K_SMF Bit32u chipmem_read(Bit32u address, unsigned io_len) BX_CPP_AttrRegparmN(2);
|
||||
BX_NE2K_SMF Bit32u asic_read(Bit32u offset, unsigned io_len) BX_CPP_AttrRegparmN(2);
|
||||
BX_NE2K_SMF Bit32u page0_read(Bit32u offset, unsigned io_len);
|
||||
BX_NE2K_SMF Bit32u page1_read(Bit32u offset, unsigned io_len);
|
||||
BX_NE2K_SMF Bit32u page2_read(Bit32u offset, unsigned io_len);
|
||||
BX_NE2K_SMF Bit32u page3_read(Bit32u offset, unsigned io_len);
|
||||
|
||||
BX_NE2K_SMF void chipmem_write(Bit32u address, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
|
||||
BX_NE2K_SMF void asic_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
BX_NE2K_SMF void page0_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
BX_NE2K_SMF void page1_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
BX_NE2K_SMF void page2_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
BX_NE2K_SMF void page3_write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
|
||||
static void tx_timer_handler(void *);
|
||||
BX_NE2K_SMF void tx_timer(void);
|
||||
|
||||
static void rx_handler(void *arg, const void *buf, unsigned len);
|
||||
BX_NE2K_SMF unsigned mcast_index(const void *dst);
|
||||
BX_NE2K_SMF void rx_frame(const void *buf, unsigned io_len);
|
||||
|
||||
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_NE2K_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
343
bochs/iodev/parallel.cc
Normal file
343
bochs/iodev/parallel.cc
Normal file
@ -0,0 +1,343 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
// This code was just a few stubs until Volker.Ruppert@t-online.de
|
||||
// fixed it up in November 2001.
|
||||
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "parallel.h"
|
||||
|
||||
#define LOG_THIS theParallelDevice->
|
||||
|
||||
bx_parallel_c *theParallelDevice = NULL;
|
||||
|
||||
int libparallel_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theParallelDevice = new bx_parallel_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theParallelDevice, BX_PLUGIN_PARALLEL);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libparallel_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theParallelDevice;
|
||||
}
|
||||
|
||||
bx_parallel_c::bx_parallel_c()
|
||||
{
|
||||
put("PAR");
|
||||
for (int i=0; i<BX_PARPORT_MAXDEV; i++) {
|
||||
s[i].output = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bx_parallel_c::~bx_parallel_c()
|
||||
{
|
||||
for (int i=0; i<BX_PARPORT_MAXDEV; i++) {
|
||||
if (s[i].output != NULL)
|
||||
fclose(s[i].output);
|
||||
}
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_parallel_c::init(void)
|
||||
{
|
||||
Bit16u ports[BX_PARPORT_MAXDEV] = {0x0378, 0x0278};
|
||||
Bit8u irqs[BX_PARPORT_MAXDEV] = {7, 5};
|
||||
char name[16], pname[20];
|
||||
bx_list_c *base;
|
||||
|
||||
BX_DEBUG(("Init $Id$"));
|
||||
|
||||
for (unsigned i=0; i<BX_N_PARALLEL_PORTS; i++) {
|
||||
sprintf(pname, "ports.parallel.%d", i+1);
|
||||
base = (bx_list_c*) SIM->get_param(pname);
|
||||
if (SIM->get_param_bool("enabled", base)->get()) {
|
||||
sprintf(name, "Parallel Port %d", i + 1);
|
||||
/* parallel interrupt and i/o ports */
|
||||
BX_PAR_THIS s[i].IRQ = irqs[i];
|
||||
for (unsigned addr=ports[i]; addr<=(unsigned)(ports[i]+2); addr++) {
|
||||
DEV_register_ioread_handler(this, read_handler, addr, name, 1);
|
||||
}
|
||||
DEV_register_iowrite_handler(this, write_handler, ports[i], name, 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, ports[i]+2, name, 1);
|
||||
BX_INFO (("parallel port %d at 0x%04x irq %d", i+1, ports[i], irqs[i]));
|
||||
/* internal state */
|
||||
BX_PAR_THIS s[i].STATUS.error = 1;
|
||||
BX_PAR_THIS s[i].STATUS.slct = 1;
|
||||
BX_PAR_THIS s[i].STATUS.pe = 0;
|
||||
BX_PAR_THIS s[i].STATUS.ack = 1;
|
||||
BX_PAR_THIS s[i].STATUS.busy = 1;
|
||||
|
||||
BX_PAR_THIS s[i].CONTROL.strobe = 0;
|
||||
BX_PAR_THIS s[i].CONTROL.autofeed = 0;
|
||||
BX_PAR_THIS s[i].CONTROL.init = 1;
|
||||
BX_PAR_THIS s[i].CONTROL.slct_in = 1;
|
||||
BX_PAR_THIS s[i].CONTROL.irq = 0;
|
||||
BX_PAR_THIS s[i].CONTROL.input = 0;
|
||||
|
||||
BX_PAR_THIS s[i].initmode = 0;
|
||||
/* output file */
|
||||
char *outfile = SIM->get_param_string("outfile", base)->getptr();
|
||||
if (strlen(outfile) > 0) {
|
||||
s[i].output = fopen(outfile, "wb");
|
||||
if (!s[i].output)
|
||||
BX_PANIC(("Could not open '%s' to write parport%d output",
|
||||
outfile, i+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_parallel_c::reset(unsigned type)
|
||||
{
|
||||
}
|
||||
|
||||
void bx_parallel_c::register_state(void)
|
||||
{
|
||||
unsigned i;
|
||||
char name[4], pname[20];
|
||||
bx_list_c *base, *port;
|
||||
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "parallel", "Parallel Port State", BX_N_PARALLEL_PORTS);
|
||||
for (i=0; i<BX_N_PARALLEL_PORTS; i++) {
|
||||
sprintf(pname, "ports.parallel.%d", i+1);
|
||||
base = (bx_list_c*) SIM->get_param(pname);
|
||||
if (SIM->get_param_bool("enabled", base)->get()) {
|
||||
sprintf(name, "%d", i);
|
||||
port = new bx_list_c(list, name, 11);
|
||||
new bx_shadow_num_c(port, "data", &BX_PAR_THIS s[i].data, BASE_HEX);
|
||||
new bx_shadow_bool_c(port, "slct", &BX_PAR_THIS s[i].STATUS.slct);
|
||||
new bx_shadow_bool_c(port, "ack", &BX_PAR_THIS s[i].STATUS.ack);
|
||||
new bx_shadow_bool_c(port, "busy", &BX_PAR_THIS s[i].STATUS.busy);
|
||||
new bx_shadow_bool_c(port, "strobe", &BX_PAR_THIS s[i].CONTROL.strobe);
|
||||
new bx_shadow_bool_c(port, "autofeed", &BX_PAR_THIS s[i].CONTROL.autofeed);
|
||||
new bx_shadow_bool_c(port, "init", &BX_PAR_THIS s[i].CONTROL.init);
|
||||
new bx_shadow_bool_c(port, "slct_in", &BX_PAR_THIS s[i].CONTROL.slct_in);
|
||||
new bx_shadow_bool_c(port, "irq", &BX_PAR_THIS s[i].CONTROL.irq);
|
||||
new bx_shadow_bool_c(port, "input", &BX_PAR_THIS s[i].CONTROL.input);
|
||||
new bx_shadow_bool_c(port, "initmode", &BX_PAR_THIS s[i].initmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_parallel_c::virtual_printer(Bit8u port)
|
||||
{
|
||||
if (BX_PAR_THIS s[port].STATUS.slct) {
|
||||
if (BX_PAR_THIS s[port].output != NULL) {
|
||||
fputc(BX_PAR_THIS s[port].data, BX_PAR_THIS s[port].output);
|
||||
fflush (BX_PAR_THIS s[port].output);
|
||||
}
|
||||
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
|
||||
DEV_pic_raise_irq(BX_PAR_THIS s[port].IRQ);
|
||||
}
|
||||
BX_PAR_THIS s[port].STATUS.ack = 0;
|
||||
BX_PAR_THIS s[port].STATUS.busy = 1;
|
||||
}
|
||||
else {
|
||||
BX_ERROR(("data is valid, but printer is offline"));
|
||||
}
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_parallel_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PAR_SMF
|
||||
bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_parallel_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PAR_SMF
|
||||
Bit8u offset;
|
||||
Bit8u port = 0;
|
||||
Bit32u retval;
|
||||
|
||||
offset = address & 0x07;
|
||||
switch (address & 0x03f8) {
|
||||
case 0x0378: port = 0; break;
|
||||
case 0x0278: port = 1; break;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case BX_PAR_DATA:
|
||||
if (!BX_PAR_THIS s[port].CONTROL.input) {
|
||||
return (Bit32u)BX_PAR_THIS s[port].data;
|
||||
} else {
|
||||
BX_ERROR(("read: input mode not supported"));
|
||||
return (0xFF);
|
||||
}
|
||||
break;
|
||||
case BX_PAR_STAT:
|
||||
{
|
||||
retval = ((BX_PAR_THIS s[port].STATUS.busy << 7) |
|
||||
(BX_PAR_THIS s[port].STATUS.ack << 6) |
|
||||
(BX_PAR_THIS s[port].STATUS.pe << 5) |
|
||||
(BX_PAR_THIS s[port].STATUS.slct << 4) |
|
||||
(BX_PAR_THIS s[port].STATUS.error << 3));
|
||||
if (BX_PAR_THIS s[port].STATUS.ack == 0) {
|
||||
BX_PAR_THIS s[port].STATUS.ack = 1;
|
||||
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
|
||||
DEV_pic_lower_irq(BX_PAR_THIS s[port].IRQ);
|
||||
}
|
||||
}
|
||||
if (BX_PAR_THIS s[port].initmode == 1) {
|
||||
BX_PAR_THIS s[port].STATUS.busy = 1;
|
||||
BX_PAR_THIS s[port].STATUS.slct = 1;
|
||||
BX_PAR_THIS s[port].STATUS.ack = 0;
|
||||
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
|
||||
DEV_pic_raise_irq(BX_PAR_THIS s[port].IRQ);
|
||||
}
|
||||
BX_PAR_THIS s[port].initmode = 0;
|
||||
}
|
||||
BX_DEBUG(("read: parport%d status register returns 0x%02x", port+1, retval));
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
case BX_PAR_CTRL:
|
||||
{
|
||||
retval = ((BX_PAR_THIS s[port].CONTROL.input << 5) |
|
||||
(BX_PAR_THIS s[port].CONTROL.irq << 4) |
|
||||
(BX_PAR_THIS s[port].CONTROL.slct_in << 3) |
|
||||
(BX_PAR_THIS s[port].CONTROL.init << 2) |
|
||||
(BX_PAR_THIS s[port].CONTROL.autofeed << 1) |
|
||||
(BX_PAR_THIS s[port].CONTROL.strobe));
|
||||
BX_DEBUG(("read: parport%d control register returns 0x%02x", port+1, retval));
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_parallel_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PAR_SMF
|
||||
bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
|
||||
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_parallel_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PAR_SMF
|
||||
Bit8u offset;
|
||||
Bit8u port = 0;
|
||||
char name[16];
|
||||
|
||||
offset = address & 0x07;
|
||||
switch (address & 0x03f8) {
|
||||
case 0x0378: port = 0; break;
|
||||
case 0x0278: port = 1; break;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case BX_PAR_DATA:
|
||||
BX_PAR_THIS s[port].data = (Bit8u)value;
|
||||
BX_DEBUG(("write: parport%d data output register = 0x%02x", port+1, (Bit8u)value));
|
||||
break;
|
||||
case BX_PAR_CTRL:
|
||||
{
|
||||
if ((value & 0x01) == 0x01) {
|
||||
if (BX_PAR_THIS s[port].CONTROL.strobe == 0) {
|
||||
BX_PAR_THIS s[port].CONTROL.strobe = 1;
|
||||
virtual_printer(port); // data is valid now
|
||||
}
|
||||
} else {
|
||||
if (BX_PAR_THIS s[port].CONTROL.strobe == 1) {
|
||||
BX_PAR_THIS s[port].CONTROL.strobe = 0;
|
||||
}
|
||||
}
|
||||
BX_PAR_THIS s[port].CONTROL.autofeed = ((value & 0x02) == 0x02);
|
||||
if ((value & 0x04) == 0x04) {
|
||||
if (BX_PAR_THIS s[port].CONTROL.init == 0) {
|
||||
BX_PAR_THIS s[port].CONTROL.init = 1;
|
||||
BX_PAR_THIS s[port].STATUS.busy = 0;
|
||||
BX_PAR_THIS s[port].STATUS.slct = 0;
|
||||
BX_PAR_THIS s[port].initmode = 1;
|
||||
BX_DEBUG(("parport%d: printer init requested", port+1));
|
||||
}
|
||||
} else {
|
||||
if (BX_PAR_THIS s[port].CONTROL.init == 1) {
|
||||
BX_PAR_THIS s[port].CONTROL.init = 0;
|
||||
}
|
||||
}
|
||||
if ((value & 0x08) == 0x08) {
|
||||
if (BX_PAR_THIS s[port].CONTROL.slct_in == 0) {
|
||||
BX_PAR_THIS s[port].CONTROL.slct_in = 1;
|
||||
BX_DEBUG(("parport%d: printer now online", port+1));
|
||||
}
|
||||
} else {
|
||||
if (BX_PAR_THIS s[port].CONTROL.slct_in == 1) {
|
||||
BX_PAR_THIS s[port].CONTROL.slct_in = 0;
|
||||
BX_DEBUG(("parport%d: printer now offline", port+1));
|
||||
}
|
||||
}
|
||||
BX_PAR_THIS s[port].STATUS.slct = BX_PAR_THIS s[port].CONTROL.slct_in;
|
||||
if ((value & 0x10) == 0x10) {
|
||||
if (BX_PAR_THIS s[port].CONTROL.irq == 0) {
|
||||
BX_PAR_THIS s[port].CONTROL.irq = 1;
|
||||
sprintf(name, "Parallel Port %d", port+1);
|
||||
DEV_register_irq(BX_PAR_THIS s[port].IRQ, name);
|
||||
BX_DEBUG(("parport%d: irq mode selected", port+1));
|
||||
}
|
||||
} else {
|
||||
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
|
||||
BX_PAR_THIS s[port].CONTROL.irq = 0;
|
||||
sprintf(name, "Parallel Port %d", port+1);
|
||||
DEV_unregister_irq(BX_PAR_THIS s[port].IRQ, name);
|
||||
BX_DEBUG(("parport%d: polling mode selected", port+1));
|
||||
}
|
||||
}
|
||||
if ((value & 0x20) == 0x20) {
|
||||
if (BX_PAR_THIS s[port].CONTROL.input == 0) {
|
||||
BX_PAR_THIS s[port].CONTROL.input = 1;
|
||||
BX_DEBUG(("parport%d: data input mode selected", port+1));
|
||||
}
|
||||
} else {
|
||||
if (BX_PAR_THIS s[port].CONTROL.input == 1) {
|
||||
BX_PAR_THIS s[port].CONTROL.input = 0;
|
||||
BX_DEBUG(("parport%d: data output mode selected", port+1));
|
||||
}
|
||||
}
|
||||
if ((value & 0xC0) > 0) {
|
||||
BX_ERROR(("write: parport%d: unsupported control bit ignored", port+1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
81
bochs/iodev/parallel.h
Normal file
81
bochs/iodev/parallel.h
Normal file
@ -0,0 +1,81 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PARPORT_H
|
||||
#define BX_IODEV_PARPORT_H
|
||||
|
||||
#if BX_USE_PAR_SMF
|
||||
# define BX_PAR_SMF static
|
||||
# define BX_PAR_THIS theParallelDevice->
|
||||
#else
|
||||
# define BX_PAR_SMF
|
||||
# define BX_PAR_THIS this->
|
||||
#endif
|
||||
|
||||
#define BX_PARPORT_MAXDEV 2
|
||||
|
||||
#define BX_PAR_DATA 0
|
||||
#define BX_PAR_STAT 1
|
||||
#define BX_PAR_CTRL 2
|
||||
|
||||
typedef struct {
|
||||
Bit8u data;
|
||||
struct {
|
||||
bx_bool error;
|
||||
bx_bool slct;
|
||||
bx_bool pe;
|
||||
bx_bool ack;
|
||||
bx_bool busy;
|
||||
} STATUS;
|
||||
struct {
|
||||
bx_bool strobe;
|
||||
bx_bool autofeed;
|
||||
bx_bool init;
|
||||
bx_bool slct_in;
|
||||
bx_bool irq;
|
||||
bx_bool input;
|
||||
} CONTROL;
|
||||
Bit8u IRQ;
|
||||
FILE *output;
|
||||
bx_bool initmode;
|
||||
} bx_par_t;
|
||||
|
||||
class bx_parallel_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_parallel_c();
|
||||
virtual ~bx_parallel_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
bx_par_t s[BX_PARPORT_MAXDEV];
|
||||
|
||||
static void virtual_printer(Bit8u port);
|
||||
|
||||
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_PAR_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
603
bochs/iodev/pci.cc
Normal file
603
bochs/iodev/pci.cc
Normal file
@ -0,0 +1,603 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// i440FX Support - PMC/DBX
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI
|
||||
|
||||
#include "pci.h"
|
||||
|
||||
#define LOG_THIS thePciBridge->
|
||||
|
||||
bx_pci_bridge_c *thePciBridge = NULL;
|
||||
|
||||
int libpci_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePciBridge = new bx_pci_bridge_c();
|
||||
bx_devices.pluginPciBridge = thePciBridge;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciBridge, BX_PLUGIN_PCI);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libpci_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePciBridge;
|
||||
}
|
||||
|
||||
bx_pci_bridge_c::bx_pci_bridge_c()
|
||||
{
|
||||
put("PCI");
|
||||
}
|
||||
|
||||
bx_pci_bridge_c::~bx_pci_bridge_c()
|
||||
{
|
||||
debug_dump();
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::init(void)
|
||||
{
|
||||
// called once when bochs initializes
|
||||
unsigned i;
|
||||
BX_PCI_THIS num_pci_handlers = 0;
|
||||
|
||||
/* set unused elements to appropriate values */
|
||||
for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
|
||||
BX_PCI_THIS pci_handler[i].handler = NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < 0x100; i++) {
|
||||
BX_PCI_THIS pci_handler_id[i] = BX_MAX_PCI_DEVICES; // not assigned
|
||||
}
|
||||
|
||||
for (i=0; i < BX_N_PCI_SLOTS; i++) {
|
||||
BX_PCI_THIS slot_used[i] = 0; // no device connected
|
||||
}
|
||||
BX_PCI_THIS slots_checked = 0;
|
||||
|
||||
// confAddr accepts dword i/o only
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0CF8, "i440FX", 4);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0CF8, "i440FX", 4);
|
||||
|
||||
for (i=0x0CFC; i<=0x0CFF; i++) {
|
||||
DEV_register_ioread_handler(this, read_handler, i, "i440FX", 7);
|
||||
}
|
||||
for (i=0x0CFC; i<=0x0CFF; i++) {
|
||||
DEV_register_iowrite_handler(this, write_handler, i, "i440FX", 7);
|
||||
}
|
||||
|
||||
Bit8u devfunc = BX_PCI_DEVICE(0,0);
|
||||
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI, "440FX Host bridge");
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
BX_PCI_THIS s.i440fx.pci_conf[i] = 0x0;
|
||||
// readonly registers
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x00] = 0x86;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x01] = 0x80;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x02] = 0x37;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x03] = 0x12;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x0b] = 0x06;
|
||||
}
|
||||
|
||||
void
|
||||
bx_pci_bridge_c::reset(unsigned type)
|
||||
{
|
||||
unsigned i;
|
||||
char devname[80];
|
||||
char *device;
|
||||
|
||||
if (!BX_PCI_THIS slots_checked) {
|
||||
for (i=0; i<BX_N_PCI_SLOTS; i++) {
|
||||
sprintf(devname, "pci.slot.%d", i+1);
|
||||
device = SIM->get_param_string(devname)->getptr();
|
||||
if ((strlen(device) > 0) && !BX_PCI_THIS slot_used[i]) {
|
||||
BX_PANIC(("Unknown plugin '%s' at PCI slot #%d", device, i+1));
|
||||
}
|
||||
}
|
||||
BX_PCI_THIS slots_checked = 1;
|
||||
}
|
||||
|
||||
BX_PCI_THIS s.i440fx.confAddr = 0;
|
||||
BX_PCI_THIS s.i440fx.confData = 0;
|
||||
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x04] = 0x06;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x05] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x06] = 0x80;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x07] = 0x02;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x0d] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x0f] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x50] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x51] = 0x01;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x52] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x53] = 0x80;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x54] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x55] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x56] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x57] = 0x01;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x58] = 0x10;
|
||||
for (i=0x59; i<0x60; i++)
|
||||
BX_PCI_THIS s.i440fx.pci_conf[i] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x72] = 0x02;
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_bridge", "PCI Bridge State", 3);
|
||||
BXRS_HEX_PARAM_FIELD(list, confAddr, BX_PCI_THIS s.i440fx.confAddr);
|
||||
BXRS_HEX_PARAM_FIELD(list, confData, BX_PCI_THIS s.i440fx.confData);
|
||||
bx_list_c *pci_conf = new bx_list_c(list, "pci_conf", 256);
|
||||
for (unsigned i=0; i<256; i++) {
|
||||
char name[6];
|
||||
sprintf(name, "0x%02x", i);
|
||||
new bx_shadow_num_c(pci_conf, name, &BX_PCI_THIS s.i440fx.pci_conf[i], BASE_HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::after_restore_state(void)
|
||||
{
|
||||
BX_PCI_THIS smram_control(BX_PCI_THIS s.i440fx.pci_conf[0x72]);
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_pci_bridge_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCI_SMF
|
||||
bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pci_bridge_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCI_SMF
|
||||
|
||||
switch (address) {
|
||||
case 0x0CF8:
|
||||
return BX_PCI_THIS s.i440fx.confAddr;
|
||||
case 0x0CFC:
|
||||
case 0x0CFD:
|
||||
case 0x0CFE:
|
||||
case 0x0CFF:
|
||||
{
|
||||
Bit32u handle, retval;
|
||||
Bit8u devfunc, regnum;
|
||||
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
|
||||
devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
|
||||
regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
|
||||
handle = BX_PCI_THIS pci_handler_id[devfunc];
|
||||
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES))
|
||||
retval = BX_PCI_THIS pci_handler[handle].handler->pci_read_handler(regnum, io_len);
|
||||
else
|
||||
retval = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
retval = 0xFFFFFFFF;
|
||||
BX_PCI_THIS s.i440fx.confData = retval;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
BX_PANIC(("unsupported IO read to port 0x%x", (unsigned) address));
|
||||
return(0xffffffff);
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_pci_bridge_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCI_SMF
|
||||
bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCI_SMF
|
||||
|
||||
switch (address) {
|
||||
case 0xCF8:
|
||||
BX_PCI_THIS s.i440fx.confAddr = value;
|
||||
if ((value & 0x80FFFF00) == 0x80000000) {
|
||||
BX_DEBUG(("440FX PMC register 0x%02x selected", value & 0xfc));
|
||||
} else if ((value & 0x80000000) == 0x80000000) {
|
||||
BX_DEBUG(("440FX request for bus 0x%02x device 0x%02x function 0x%02x",
|
||||
(value >> 16) & 0xFF, (value >> 11) & 0x1F, (value >> 8) & 0x07));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xCFC:
|
||||
case 0xCFD:
|
||||
case 0xCFE:
|
||||
case 0xCFF:
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
|
||||
Bit8u devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
|
||||
Bit8u regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
|
||||
Bit32u handle = BX_PCI_THIS pci_handler_id[devfunc];
|
||||
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
|
||||
if (((regnum>=4) && (regnum<=7)) || (regnum==12) || (regnum==13) || (regnum>14)) {
|
||||
BX_PCI_THIS pci_handler[handle].handler->pci_write_handler(regnum, value, io_len);
|
||||
BX_PCI_THIS s.i440fx.confData = value << (8 * (address & 0x03));
|
||||
}
|
||||
else
|
||||
BX_DEBUG(("read only register, write ignored"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("IO write to port 0x%x", (unsigned) address));
|
||||
}
|
||||
}
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_pci_bridge_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_PCI_THIS s.i440fx.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x", address, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
// pci configuration space write callback handler
|
||||
void bx_pci_bridge_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
Bit8u value8;
|
||||
|
||||
if ((address >= 0x10) && (address < 0x34))
|
||||
return;
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value8 = (value >> (i*8)) & 0xFF;
|
||||
switch (address+i) {
|
||||
case 0x04:
|
||||
BX_PCI_THIS s.i440fx.pci_conf[address+i] = (value8 & 0x40) | 0x06;
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x0c:
|
||||
break;
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
BX_INFO(("440FX PMC write to PAM register %x (TLB Flush)", address+i));
|
||||
BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
|
||||
bx_pc_system.MemoryMappingChanged();
|
||||
break;
|
||||
case 0x72:
|
||||
smram_control(value); // SMRAM conrol register
|
||||
break;
|
||||
default:
|
||||
BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
|
||||
BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x", address+i, value8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::smram_control(Bit8u value8)
|
||||
{
|
||||
//
|
||||
// From i440FX chipset manual:
|
||||
//
|
||||
// [7:7] Reserved.
|
||||
// [6:6] SMM Space Open (DOPEN), when DOPEN=1 and DLCK=0, SMM space DRAM
|
||||
// became visible even CPU not indicte SMM mode access. This is
|
||||
// indended to help BIOS to initialize SMM space.
|
||||
// [5:5] SMM Space Closed (DCLS), when DCLS=1, SMM space is not accessible
|
||||
// for data references, even if CPU indicates SMM mode access. Code
|
||||
// references may still access SMM space DRAM.
|
||||
// [4:4] SMM Space Locked (DLCK), when DLCK=1, DOPEN is set to 0 and
|
||||
// both DLCK and DOPEN became R/O. DLCK can only be cleared by
|
||||
// a power-on reset.
|
||||
// [3:3] SMRAM Enable (SMRAME)
|
||||
// [2:0] SMM space base segment, program the location of SMM space
|
||||
// reserved.
|
||||
//
|
||||
|
||||
// SMRAM space access cycles:
|
||||
|
||||
// | SMRAME | DLCK | DCLS | DOPEN | CPU_SMM | | Code | Data |
|
||||
// ------------------------------------------ ---------------
|
||||
// | 0 | X | X | X | X | -> | PCI | PCI |
|
||||
// | 1 | 0 | X | 0 | 0 | -> | PCI | PCI |
|
||||
// | 1 | 0 | 0 | 0 | 1 | -> | DRAM | DRAM |
|
||||
// | 1 | 0 | 0 | 1 | X | -> | DRAM | DRAM |
|
||||
// | 1 | 1 | 0 | X | 1 | -> | DRAM | DRAM |
|
||||
// | 1 | 0 | 1 | 0 | 1 | -> | DRAM | PCI |
|
||||
// | 1 | 0 | 1 | 1 | X | -> | ---- | ---- |
|
||||
// | 1 | 1 | X | X | 0 | -> | PCI | PCI |
|
||||
// | 1 | 1 | 1 | X | 1 | -> | DRAM | PCI |
|
||||
// ------------------------------------------ ---------------
|
||||
|
||||
value8 = (value8 & 0x78) | 0x2; // ignore reserved bits
|
||||
|
||||
if (BX_PCI_THIS s.i440fx.pci_conf[0x72] & 0x10)
|
||||
{
|
||||
value8 &= 0xbf; // set DOPEN=0, DLCK=1
|
||||
value8 |= 0x10;
|
||||
}
|
||||
|
||||
if ((value8 & 0x08) == 0) {
|
||||
bx_devices.mem->disable_smram();
|
||||
}
|
||||
else {
|
||||
bx_bool DOPEN = (value8 & 0x40) > 0, DCLS = (value8 & 0x20) > 0;
|
||||
if(DOPEN && DCLS) BX_PANIC(("SMRAM control: DOPEN not mutually exclusive with DCLS !"));
|
||||
bx_devices.mem->enable_smram(DOPEN, DCLS);
|
||||
}
|
||||
|
||||
BX_INFO(("setting SMRAM control register to 0x%02x", value8));
|
||||
BX_PCI_THIS s.i440fx.pci_conf[0x72] = value8;
|
||||
}
|
||||
|
||||
Bit8u bx_pci_bridge_c::rd_memType(Bit32u addr)
|
||||
{
|
||||
switch ((addr & 0xFC000) >> 12) {
|
||||
case 0xC0:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5A] & 0x1);
|
||||
case 0xC4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 4) & 0x1);
|
||||
case 0xC8:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5B] & 0x1);
|
||||
case 0xCC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 4) & 0x1);
|
||||
|
||||
case 0xD0:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5C] & 0x1);
|
||||
case 0xD4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 4) & 0x1);
|
||||
case 0xD8:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5D] & 0x1);
|
||||
case 0xDC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 4) & 0x1);
|
||||
|
||||
case 0xE0:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5E] & 0x1);
|
||||
case 0xE4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 4) & 0x1);
|
||||
case 0xE8:
|
||||
return (BX_PCI_THIS s.i440fx.pci_conf[0x5F] & 0x1);
|
||||
case 0xEC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 4) & 0x1);
|
||||
|
||||
case 0xF0:
|
||||
case 0xF4:
|
||||
case 0xF8:
|
||||
case 0xFC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 4) & 0x1);
|
||||
|
||||
default:
|
||||
BX_PANIC(("rd_memType () Error: Memory Type not known !"));
|
||||
break;
|
||||
}
|
||||
|
||||
return(0); // keep compiler happy
|
||||
}
|
||||
|
||||
Bit8u bx_pci_bridge_c::wr_memType(Bit32u addr)
|
||||
{
|
||||
switch ((addr & 0xFC000) >> 12) {
|
||||
case 0xC0:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 1) & 0x1);
|
||||
case 0xC4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 5) & 0x1);
|
||||
case 0xC8:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 1) & 0x1);
|
||||
case 0xCC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 5) & 0x1);
|
||||
|
||||
case 0xD0:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 1) & 0x1);
|
||||
case 0xD4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 5) & 0x1);
|
||||
case 0xD8:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 1) & 0x1);
|
||||
case 0xDC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 5) & 0x1);
|
||||
|
||||
case 0xE0:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 1) & 0x1);
|
||||
case 0xE4:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 5) & 0x1);
|
||||
case 0xE8:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 1) & 0x1);
|
||||
case 0xEC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 5) & 0x1);
|
||||
|
||||
case 0xF0:
|
||||
case 0xF4:
|
||||
case 0xF8:
|
||||
case 0xFC:
|
||||
return ((BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 5) & 0x1);
|
||||
|
||||
default:
|
||||
BX_PANIC(("wr_memType () Error: Memory Type not known !"));
|
||||
break;
|
||||
}
|
||||
|
||||
return(0); // keep compiler happy
|
||||
}
|
||||
|
||||
void bx_pci_bridge_c::debug_dump()
|
||||
{
|
||||
int i;
|
||||
|
||||
BX_DEBUG(("i440fxConfAddr:0x%08x", BX_PCI_THIS s.i440fx.confAddr));
|
||||
BX_DEBUG(("i440fxConfData:0x%08x", BX_PCI_THIS s.i440fx.confData));
|
||||
|
||||
#ifdef DUMP_FULL_I440FX
|
||||
for (i=0; i<256; i++) {
|
||||
BX_DEBUG(("i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i]));
|
||||
}
|
||||
#else /* DUMP_FULL_I440FX */
|
||||
for (i=0x59; i<0x60; i++) {
|
||||
BX_DEBUG(("i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i]));
|
||||
}
|
||||
#endif /* DUMP_FULL_I440FX */
|
||||
}
|
||||
|
||||
bx_bool bx_pci_bridge_c::register_pci_handlers(bx_pci_device_stub_c *dev,
|
||||
Bit8u *devfunc, const char *name,
|
||||
const char *descr)
|
||||
{
|
||||
unsigned i, handle;
|
||||
char devname[80];
|
||||
char *device;
|
||||
|
||||
if (strcmp(name, "pci") && strcmp(name, "pci2isa") && strcmp(name, "pci_ide")
|
||||
&& (*devfunc == 0x00)) {
|
||||
for (i = 0; i < BX_N_PCI_SLOTS; i++) {
|
||||
sprintf(devname, "pci.slot.%d", i+1);
|
||||
device = SIM->get_param_string(devname)->getptr();
|
||||
if ((strlen(device) > 0) && (!strcmp(name, device))) {
|
||||
*devfunc = (i + 2) << 3;
|
||||
BX_PCI_THIS slot_used[i] = 1;
|
||||
BX_INFO(("PCI slot #%d used by plugin '%s'", i+1, name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*devfunc == 0x00) {
|
||||
BX_ERROR(("Plugin '%s' not connected to a PCI slot", name));
|
||||
}
|
||||
}
|
||||
/* check if device/function is available */
|
||||
if (BX_PCI_THIS pci_handler_id[*devfunc] == BX_MAX_PCI_DEVICES) {
|
||||
if (BX_PCI_THIS num_pci_handlers >= BX_MAX_PCI_DEVICES) {
|
||||
BX_INFO(("too many PCI devices installed."));
|
||||
BX_PANIC((" try increasing BX_MAX_PCI_DEVICES"));
|
||||
return false;
|
||||
}
|
||||
handle = BX_PCI_THIS num_pci_handlers++;
|
||||
BX_PCI_THIS pci_handler[handle].handler = dev;
|
||||
BX_PCI_THIS pci_handler_id[*devfunc] = handle;
|
||||
BX_INFO(("%s present at device %d, function %d", descr, *devfunc >> 3,
|
||||
*devfunc & 0x07));
|
||||
return true; // device/function mapped successfully
|
||||
}
|
||||
else {
|
||||
return false; // device/function not available, return false.
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool bx_pci_bridge_c::is_pci_device(const char *name)
|
||||
{
|
||||
unsigned i;
|
||||
char devname[80];
|
||||
char *device;
|
||||
|
||||
for (i = 0; i < BX_N_PCI_SLOTS; i++) {
|
||||
sprintf(devname, "pci.slot.%d", i+1);
|
||||
device = SIM->get_param_string(devname)->getptr();
|
||||
if ((strlen(device) > 0) && (!strcmp(name, device))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool bx_pci_bridge_c::pci_set_base_mem(void *this_ptr, memory_handler_t f1, memory_handler_t f2,
|
||||
Bit32u *addr, Bit8u *pci_conf, unsigned size)
|
||||
{
|
||||
Bit32u newbase;
|
||||
|
||||
Bit32u oldbase = *addr;
|
||||
Bit32u mask = ~(size - 1);
|
||||
Bit8u pci_flags = pci_conf[0x00] & 0x0f;
|
||||
if ((pci_flags & 0x06) > 0) {
|
||||
BX_PANIC(("PCI base memory flag 0x%02x not supported", pci_flags));
|
||||
return 0;
|
||||
}
|
||||
pci_conf[0x00] &= (mask & 0xf0);
|
||||
pci_conf[0x01] &= (mask >> 8) & 0xff;
|
||||
pci_conf[0x02] &= (mask >> 16) & 0xff;
|
||||
pci_conf[0x03] &= (mask >> 24) & 0xff;
|
||||
ReadHostDWordFromLittleEndian(pci_conf, newbase);
|
||||
pci_conf[0x00] |= pci_flags;
|
||||
if ((newbase != mask) && (newbase != oldbase)) { // skip PCI probe
|
||||
if (oldbase > 0) {
|
||||
DEV_unregister_memory_handlers(f1, f2, oldbase, oldbase + size - 1);
|
||||
}
|
||||
if (newbase > 0) {
|
||||
DEV_register_memory_handlers(this_ptr, f1, f2, newbase, newbase + size - 1);
|
||||
}
|
||||
*addr = newbase;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool bx_pci_bridge_c::pci_set_base_io(void *this_ptr, bx_read_handler_t f1, bx_write_handler_t f2,
|
||||
Bit32u *addr, Bit8u *pci_conf, unsigned size,
|
||||
const Bit8u *iomask, const char *name)
|
||||
{
|
||||
unsigned i;
|
||||
Bit32u newbase;
|
||||
|
||||
Bit32u oldbase = *addr;
|
||||
Bit16u mask = ~(size - 1);
|
||||
Bit8u pci_flags = pci_conf[0x00] & 0x03;
|
||||
pci_conf[0x00] &= (mask & 0xfc);
|
||||
pci_conf[0x01] &= (mask >> 8);
|
||||
ReadHostDWordFromLittleEndian(pci_conf, newbase);
|
||||
pci_conf[0x00] |= pci_flags;
|
||||
if (((newbase & 0xfffc) != mask) && (newbase != oldbase)) { // skip PCI probe
|
||||
if (oldbase > 0) {
|
||||
for (i=0; i<size; i++) {
|
||||
if (iomask[i] > 0) {
|
||||
DEV_unregister_ioread_handler(this_ptr, f1, oldbase + i, iomask[i]);
|
||||
DEV_unregister_iowrite_handler(this_ptr, f2, oldbase + i, iomask[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newbase > 0) {
|
||||
for (i=0; i<size; i++) {
|
||||
if (iomask[i] > 0) {
|
||||
DEV_register_ioread_handler(this_ptr, f1, newbase + i, name, iomask[i]);
|
||||
DEV_register_iowrite_handler(this_ptr, f2, newbase + i, name, iomask[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*addr = newbase;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* BX_SUPPORT_PCI */
|
||||
100
bochs/iodev/pci.h
Normal file
100
bochs/iodev/pci.h
Normal file
@ -0,0 +1,100 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PCI_BRIDGE_H
|
||||
#define BX_IODEV_PCI_BRIDGE_H
|
||||
|
||||
#define BX_MAX_PCI_DEVICES 20
|
||||
|
||||
#define BX_PCI_DEVICE(device, function) ((device)<<3 | (function))
|
||||
|
||||
#if BX_USE_PCI_SMF
|
||||
# define BX_PCI_SMF static
|
||||
# define BX_PCI_THIS thePciBridge->
|
||||
#else
|
||||
# define BX_PCI_SMF
|
||||
# define BX_PCI_THIS this->
|
||||
#endif
|
||||
|
||||
#define BX_PCI_INTA 1
|
||||
#define BX_PCI_INTB 2
|
||||
#define BX_PCI_INTC 3
|
||||
#define BX_PCI_INTD 4
|
||||
|
||||
typedef struct {
|
||||
Bit32u confAddr;
|
||||
Bit32u confData;
|
||||
Bit8u pci_conf[256];
|
||||
} bx_def440fx_t;
|
||||
|
||||
class bx_pci_device_stub_c;
|
||||
|
||||
class bx_pci_bridge_c : public bx_pci_bridge_stub_c {
|
||||
public:
|
||||
bx_pci_bridge_c();
|
||||
virtual ~bx_pci_bridge_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
virtual bx_bool register_pci_handlers(bx_pci_device_stub_c *device,
|
||||
Bit8u *devfunc, const char *name,
|
||||
const char *descr);
|
||||
virtual bx_bool is_pci_device(const char *name);
|
||||
virtual bx_bool pci_set_base_mem(void *this_ptr, memory_handler_t f1,
|
||||
memory_handler_t f2, Bit32u *addr,
|
||||
Bit8u *pci_conf, unsigned size);
|
||||
virtual bx_bool pci_set_base_io(void *this_ptr, bx_read_handler_t f1,
|
||||
bx_write_handler_t f2, Bit32u *addr,
|
||||
Bit8u *pci_conf, unsigned size,
|
||||
const Bit8u *iomask, const char *name);
|
||||
virtual Bit8u rd_memType(Bit32u addr);
|
||||
virtual Bit8u wr_memType(Bit32u addr);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
virtual void debug_dump(void);
|
||||
|
||||
private:
|
||||
Bit8u pci_handler_id[0x100]; // 256 devices/functions
|
||||
struct {
|
||||
bx_pci_device_stub_c *handler;
|
||||
} pci_handler[BX_MAX_PCI_DEVICES];
|
||||
unsigned num_pci_handlers;
|
||||
|
||||
bx_bool slot_used[BX_N_PCI_SLOTS];
|
||||
bx_bool slots_checked;
|
||||
|
||||
struct {
|
||||
bx_def440fx_t i440fx;
|
||||
} s;
|
||||
|
||||
void smram_control(Bit8u value);
|
||||
|
||||
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_PCI_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
377
bochs/iodev/pci2isa.cc
Normal file
377
bochs/iodev/pci2isa.cc
Normal file
@ -0,0 +1,377 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// i440FX Support - PCI-to-ISA bridge (PIIX3)
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI
|
||||
|
||||
#include "pci.h"
|
||||
#include "pci2isa.h"
|
||||
|
||||
#define LOG_THIS thePci2IsaBridge->
|
||||
|
||||
bx_piix3_c *thePci2IsaBridge = NULL;
|
||||
|
||||
int libpci2isa_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePci2IsaBridge = new bx_piix3_c();
|
||||
bx_devices.pluginPci2IsaBridge = thePci2IsaBridge;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePci2IsaBridge, BX_PLUGIN_PCI2ISA);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libpci2isa_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePci2IsaBridge;
|
||||
}
|
||||
|
||||
bx_piix3_c::bx_piix3_c()
|
||||
{
|
||||
put("P2I");
|
||||
}
|
||||
|
||||
bx_piix3_c::~bx_piix3_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_piix3_c::init(void)
|
||||
{
|
||||
unsigned i;
|
||||
// called once when bochs initializes
|
||||
|
||||
Bit8u devfunc = BX_PCI_DEVICE(1,0);
|
||||
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI2ISA,
|
||||
"PIIX3 PCI-to-ISA bridge");
|
||||
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
|
||||
DEV_register_ioread_handler(this, read_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
BX_P2I_THIS s.pci_conf[i] = 0x0;
|
||||
for (i=0; i<16; i++)
|
||||
BX_P2I_THIS s.irq_registry[i] = 0x0;
|
||||
for (i=0; i<16; i++)
|
||||
BX_P2I_THIS s.irq_level[i] = 0x0;
|
||||
// readonly registers
|
||||
BX_P2I_THIS s.pci_conf[0x00] = 0x86;
|
||||
BX_P2I_THIS s.pci_conf[0x01] = 0x80;
|
||||
BX_P2I_THIS s.pci_conf[0x02] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x03] = 0x70;
|
||||
BX_P2I_THIS s.pci_conf[0x04] = 0x07;
|
||||
BX_P2I_THIS s.pci_conf[0x0a] = 0x01;
|
||||
BX_P2I_THIS s.pci_conf[0x0b] = 0x06;
|
||||
BX_P2I_THIS s.pci_conf[0x0e] = 0x80;
|
||||
// irq routing registers
|
||||
BX_P2I_THIS s.pci_conf[0x60] = 0x80;
|
||||
BX_P2I_THIS s.pci_conf[0x61] = 0x80;
|
||||
BX_P2I_THIS s.pci_conf[0x62] = 0x80;
|
||||
BX_P2I_THIS s.pci_conf[0x63] = 0x80;
|
||||
}
|
||||
|
||||
void bx_piix3_c::reset(unsigned type)
|
||||
{
|
||||
BX_P2I_THIS s.pci_conf[0x05] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x06] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x07] = 0x02;
|
||||
BX_P2I_THIS s.pci_conf[0x4c] = 0x4d;
|
||||
BX_P2I_THIS s.pci_conf[0x4e] = 0x03;
|
||||
BX_P2I_THIS s.pci_conf[0x4f] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x69] = 0x02;
|
||||
BX_P2I_THIS s.pci_conf[0x70] = 0x80;
|
||||
BX_P2I_THIS s.pci_conf[0x76] = 0x0c;
|
||||
BX_P2I_THIS s.pci_conf[0x77] = 0x0c;
|
||||
BX_P2I_THIS s.pci_conf[0x78] = 0x02;
|
||||
BX_P2I_THIS s.pci_conf[0x79] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x80] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0x82] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa0] = 0x08;
|
||||
BX_P2I_THIS s.pci_conf[0xa2] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa3] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa4] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa5] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa6] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa7] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xa8] = 0x0f;
|
||||
BX_P2I_THIS s.pci_conf[0xaa] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xab] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xac] = 0x00;
|
||||
BX_P2I_THIS s.pci_conf[0xae] = 0x00;
|
||||
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
pci_set_irq(0x08, i+1, 0);
|
||||
pci_unregister_irq(i);
|
||||
}
|
||||
|
||||
BX_P2I_THIS s.elcr1 = 0x00;
|
||||
BX_P2I_THIS s.elcr2 = 0x00;
|
||||
BX_P2I_THIS s.pci_reset = 0x00;
|
||||
BX_P2I_THIS s.apms = 0x00;
|
||||
BX_P2I_THIS s.apmc = 0x00;
|
||||
}
|
||||
|
||||
void bx_piix3_c::register_state(void)
|
||||
{
|
||||
unsigned i;
|
||||
char name[6];
|
||||
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci2isa", "PCI-to-ISA Bridge State", 8);
|
||||
|
||||
register_pci_state(list, BX_P2I_THIS s.pci_conf);
|
||||
|
||||
BXRS_HEX_PARAM_FIELD(list, elcr1, BX_P2I_THIS s.elcr1);
|
||||
BXRS_HEX_PARAM_FIELD(list, elcr2, BX_P2I_THIS s.elcr2);
|
||||
BXRS_HEX_PARAM_FIELD(list, apmc, BX_P2I_THIS s.apmc);
|
||||
BXRS_HEX_PARAM_FIELD(list, apms, BX_P2I_THIS s.apms);
|
||||
BXRS_HEX_PARAM_FIELD(list, pci_reset, BX_P2I_THIS s.pci_reset);
|
||||
|
||||
bx_list_c *irqr = new bx_list_c(list, "irq_registry", 16);
|
||||
for (i=0; i<16; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
new bx_shadow_num_c(irqr, name, &BX_P2I_THIS s.irq_registry[i]);
|
||||
}
|
||||
bx_list_c *irql = new bx_list_c(list, "irq_level", 16);
|
||||
for (i=0; i<16; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
new bx_shadow_num_c(irql, name, &BX_P2I_THIS s.irq_level[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_piix3_c::after_restore_state(void)
|
||||
{
|
||||
for (unsigned i=0; i<16; i++) {
|
||||
if (BX_P2I_THIS s.irq_registry[i]) {
|
||||
DEV_register_irq(i, "PIIX3 IRQ routing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bx_piix3_c::pci_register_irq(unsigned pirq, unsigned irq)
|
||||
{
|
||||
if ((irq < 16) && (((1 << irq) & 0xdef8) > 0)) {
|
||||
if (BX_P2I_THIS s.pci_conf[0x60 + pirq] < 16) {
|
||||
pci_unregister_irq(pirq);
|
||||
}
|
||||
BX_P2I_THIS s.pci_conf[0x60 + pirq] = irq;
|
||||
if (!BX_P2I_THIS s.irq_registry[irq]) {
|
||||
DEV_register_irq(irq, "PIIX3 IRQ routing");
|
||||
}
|
||||
BX_P2I_THIS s.irq_registry[irq] |= (1 << pirq);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_piix3_c::pci_unregister_irq(unsigned pirq)
|
||||
{
|
||||
Bit8u irq = BX_P2I_THIS s.pci_conf[0x60 + pirq];
|
||||
if (irq < 16) {
|
||||
BX_P2I_THIS s.irq_registry[irq] &= ~(1 << pirq);
|
||||
if (!BX_P2I_THIS s.irq_registry[irq]) {
|
||||
BX_P2I_THIS pci_set_irq(0x08, pirq+1, 0);
|
||||
DEV_unregister_irq(irq, "PIIX3 IRQ routing");
|
||||
}
|
||||
BX_P2I_THIS s.pci_conf[0x60 + pirq] = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_piix3_c::pci_set_irq(Bit8u devfunc, unsigned line, bx_bool level)
|
||||
{
|
||||
Bit8u pirq = ((devfunc >> 3) + line - 2) & 0x03;
|
||||
#if BX_SUPPORT_APIC
|
||||
// forward this function call to the ioapic too
|
||||
if (DEV_ioapic_present()) {
|
||||
DEV_ioapic_set_irq_level(pirq + 16, level);
|
||||
}
|
||||
#endif
|
||||
Bit8u irq = BX_P2I_THIS s.pci_conf[0x60 + pirq];
|
||||
if ((irq < 16) && (((1 << irq) & 0xdef8) > 0)) {
|
||||
if (level == 1) {
|
||||
if (!BX_P2I_THIS s.irq_level[irq]) {
|
||||
DEV_pic_raise_irq(irq);
|
||||
BX_DEBUG(("PIRQ%c -> IRQ %d = 1", pirq+65, irq));
|
||||
}
|
||||
BX_P2I_THIS s.irq_level[irq] |= (1 << (devfunc >> 3));
|
||||
} else {
|
||||
BX_P2I_THIS s.irq_level[irq] &= ~(1 << (devfunc >> 3));
|
||||
if (!BX_P2I_THIS s.irq_level[irq]) {
|
||||
DEV_pic_lower_irq(irq);
|
||||
BX_DEBUG(("PIRQ%c -> IRQ %d = 0", pirq+65, irq));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_piix3_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_P2I_SMF
|
||||
bx_piix3_c *class_ptr = (bx_piix3_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_piix3_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_P2I_SMF
|
||||
|
||||
switch (address) {
|
||||
case 0x00b2:
|
||||
return(BX_P2I_THIS s.apmc);
|
||||
|
||||
case 0x00b3:
|
||||
return(BX_P2I_THIS s.apms);
|
||||
|
||||
case 0x04d0:
|
||||
return(BX_P2I_THIS s.elcr1);
|
||||
|
||||
case 0x04d1:
|
||||
return(BX_P2I_THIS s.elcr2);
|
||||
|
||||
case 0x0cf9:
|
||||
return(BX_P2I_THIS s.pci_reset);
|
||||
}
|
||||
|
||||
return(0xffffffff);
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_piix3_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_P2I_SMF
|
||||
bx_piix3_c *class_ptr = (bx_piix3_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_piix3_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_P2I_SMF
|
||||
|
||||
switch (address) {
|
||||
case 0x00b2:
|
||||
#if BX_SUPPORT_ACPI
|
||||
DEV_acpi_generate_smi((Bit8u)value);
|
||||
#else
|
||||
BX_ERROR(("write %08x: APM command register not supported yet", value));
|
||||
#endif
|
||||
BX_P2I_THIS s.apmc = value & 0xff;
|
||||
break;
|
||||
case 0x00b3:
|
||||
BX_P2I_THIS s.apms = value & 0xff;
|
||||
break;
|
||||
case 0x04d0:
|
||||
value &= 0xf8;
|
||||
if (value != BX_P2I_THIS s.elcr1) {
|
||||
BX_P2I_THIS s.elcr1 = value;
|
||||
BX_INFO(("write: ELCR1 = 0x%02x", BX_P2I_THIS s.elcr1));
|
||||
DEV_pic_set_mode(1, BX_P2I_THIS s.elcr1); // master PIC
|
||||
}
|
||||
break;
|
||||
case 0x04d1:
|
||||
value &= 0xde;
|
||||
if (value != BX_P2I_THIS s.elcr2) {
|
||||
BX_P2I_THIS s.elcr2 = value;
|
||||
BX_INFO(("write: ELCR2 = 0x%02x", BX_P2I_THIS s.elcr2));
|
||||
DEV_pic_set_mode(0, BX_P2I_THIS s.elcr2); // slave PIC
|
||||
}
|
||||
break;
|
||||
case 0x0cf9:
|
||||
BX_INFO(("write: CPU reset register = 0x%02x", value));
|
||||
BX_P2I_THIS s.pci_reset = value & 0x02;
|
||||
if (value & 0x04) {
|
||||
if (BX_P2I_THIS s.pci_reset) {
|
||||
bx_pc_system.Reset(BX_RESET_HARDWARE);
|
||||
} else {
|
||||
bx_pc_system.Reset(BX_RESET_SOFTWARE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_piix3_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_P2I_THIS s.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
BX_DEBUG(("PIIX3 PCI-to-ISA read register 0x%02x value 0x%08x", address, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
// pci configuration space write callback handler
|
||||
void bx_piix3_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
if ((address >= 0x10) && (address < 0x34))
|
||||
return;
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
Bit8u value8 = (value >> (i*8)) & 0xFF;
|
||||
switch (address+i) {
|
||||
case 0x04:
|
||||
case 0x06:
|
||||
break;
|
||||
case 0x60:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
case 0x63:
|
||||
if (value8 != BX_P2I_THIS s.pci_conf[address+i]) {
|
||||
if (value8 >= 0x80) {
|
||||
pci_unregister_irq((address+i) & 0x03);
|
||||
} else {
|
||||
pci_register_irq((address+i) & 0x03, value8);
|
||||
}
|
||||
BX_INFO(("PCI IRQ routing: PIRQ%c# set to 0x%02x", address+i-31,
|
||||
value8));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_P2I_THIS s.pci_conf[address+i] = value8;
|
||||
BX_DEBUG(("PIIX3 PCI-to-ISA write register 0x%02x value 0x%02x", address+i,
|
||||
value8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BX_SUPPORT_PCI */
|
||||
70
bochs/iodev/pci2isa.h
Normal file
70
bochs/iodev/pci2isa.h
Normal file
@ -0,0 +1,70 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PIC2ISA_H
|
||||
#define BX_IODEV_PIC2ISA_H
|
||||
|
||||
#if BX_USE_P2I_SMF
|
||||
# define BX_P2I_SMF static
|
||||
# define BX_P2I_THIS thePci2IsaBridge->
|
||||
#else
|
||||
# define BX_P2I_SMF
|
||||
# define BX_P2I_THIS this->
|
||||
#endif
|
||||
|
||||
|
||||
class bx_piix3_c : public bx_pci2isa_stub_c {
|
||||
public:
|
||||
bx_piix3_c();
|
||||
virtual ~bx_piix3_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void pci_set_irq(Bit8u devfunc, unsigned line, bx_bool level);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
private:
|
||||
|
||||
struct {
|
||||
Bit8u pci_conf[256];
|
||||
Bit8u elcr1;
|
||||
Bit8u elcr2;
|
||||
Bit8u apmc;
|
||||
Bit8u apms;
|
||||
Bit8u irq_registry[16];
|
||||
Bit32u irq_level[16];
|
||||
Bit8u pci_reset;
|
||||
} s;
|
||||
|
||||
static void pci_register_irq(unsigned pirq, unsigned irq);
|
||||
static void pci_unregister_irq(unsigned pirq);
|
||||
|
||||
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_P2I_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
460
bochs/iodev/pci_ide.cc
Normal file
460
bochs/iodev/pci_ide.cc
Normal file
@ -0,0 +1,460 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// i440FX Support - PCI IDE controller (PIIX3)
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI
|
||||
|
||||
#include "pci.h"
|
||||
#include "pci_ide.h"
|
||||
|
||||
#define LOG_THIS thePciIdeController->
|
||||
|
||||
bx_pci_ide_c *thePciIdeController = NULL;
|
||||
|
||||
const Bit8u bmdma_iomask[16] = {1, 0, 1, 0, 4, 0, 0, 0, 1, 0, 1, 0, 4, 0, 0, 0};
|
||||
|
||||
int libpci_ide_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePciIdeController = new bx_pci_ide_c();
|
||||
bx_devices.pluginPciIdeController = thePciIdeController;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciIdeController, BX_PLUGIN_PCI_IDE);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libpci_ide_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePciIdeController;
|
||||
}
|
||||
|
||||
bx_pci_ide_c::bx_pci_ide_c()
|
||||
{
|
||||
put("PIDE");
|
||||
s.bmdma[0].timer_index = BX_NULL_TIMER_HANDLE;
|
||||
s.bmdma[1].timer_index = BX_NULL_TIMER_HANDLE;
|
||||
s.bmdma[0].buffer = NULL;
|
||||
s.bmdma[1].buffer = NULL;
|
||||
}
|
||||
|
||||
bx_pci_ide_c::~bx_pci_ide_c()
|
||||
{
|
||||
if (s.bmdma[0].buffer != NULL) {
|
||||
delete [] s.bmdma[0].buffer;
|
||||
}
|
||||
if (s.bmdma[1].buffer != NULL) {
|
||||
delete [] s.bmdma[1].buffer;
|
||||
}
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
Bit8u devfunc = BX_PCI_DEVICE(1,1);
|
||||
DEV_register_pci_handlers(this, &devfunc,
|
||||
BX_PLUGIN_PCI_IDE, "PIIX3 PCI IDE controller");
|
||||
|
||||
// register BM-DMA timer
|
||||
for (i=0; i<2; i++) {
|
||||
if (BX_PIDE_THIS s.bmdma[i].timer_index == BX_NULL_TIMER_HANDLE) {
|
||||
BX_PIDE_THIS s.bmdma[i].timer_index =
|
||||
DEV_register_timer(this, timer_handler, 1000, 0,0, "PIIX3 BM-DMA timer");
|
||||
}
|
||||
}
|
||||
|
||||
BX_PIDE_THIS s.bmdma[0].buffer = new Bit8u[0x20000];
|
||||
BX_PIDE_THIS s.bmdma[1].buffer = new Bit8u[0x20000];
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
BX_PIDE_THIS s.pci_conf[i] = 0x0;
|
||||
// readonly registers
|
||||
BX_PIDE_THIS s.pci_conf[0x00] = 0x86;
|
||||
BX_PIDE_THIS s.pci_conf[0x01] = 0x80;
|
||||
BX_PIDE_THIS s.pci_conf[0x02] = 0x10;
|
||||
BX_PIDE_THIS s.pci_conf[0x03] = 0x70;
|
||||
BX_PIDE_THIS s.pci_conf[0x09] = 0x80;
|
||||
BX_PIDE_THIS s.pci_conf[0x0a] = 0x01;
|
||||
BX_PIDE_THIS s.pci_conf[0x0b] = 0x01;
|
||||
BX_PIDE_THIS s.pci_conf[0x0e] = 0x00;
|
||||
BX_PIDE_THIS s.pci_conf[0x20] = 0x01;
|
||||
BX_PIDE_THIS s.bmdma_addr = 0;
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::reset(unsigned type)
|
||||
{
|
||||
BX_PIDE_THIS s.pci_conf[0x04] = 0x01;
|
||||
BX_PIDE_THIS s.pci_conf[0x06] = 0x80;
|
||||
BX_PIDE_THIS s.pci_conf[0x07] = 0x02;
|
||||
if (SIM->get_param_bool(BXPN_ATA0_ENABLED)->get()) {
|
||||
BX_PIDE_THIS s.pci_conf[0x40] = 0x00;
|
||||
BX_PIDE_THIS s.pci_conf[0x41] = 0x80;
|
||||
}
|
||||
if (SIM->get_param_bool(BXPN_ATA1_ENABLED)->get()) {
|
||||
BX_PIDE_THIS s.pci_conf[0x42] = 0x00;
|
||||
BX_PIDE_THIS s.pci_conf[0x43] = 0x80;
|
||||
}
|
||||
BX_PIDE_THIS s.pci_conf[0x44] = 0x00;
|
||||
for (unsigned i=0; i<2; i++) {
|
||||
BX_PIDE_THIS s.bmdma[i].cmd_ssbm = 0;
|
||||
BX_PIDE_THIS s.bmdma[i].cmd_rwcon = 0;
|
||||
BX_PIDE_THIS s.bmdma[i].status = 0;
|
||||
BX_PIDE_THIS s.bmdma[i].dtpr = 0;
|
||||
BX_PIDE_THIS s.bmdma[i].prd_current = 0;
|
||||
BX_PIDE_THIS s.bmdma[i].buffer_top = BX_PIDE_THIS s.bmdma[i].buffer;
|
||||
BX_PIDE_THIS s.bmdma[i].buffer_idx = BX_PIDE_THIS s.bmdma[i].buffer;
|
||||
}
|
||||
}
|
||||
|
||||
// save/restore code begin
|
||||
void bx_pci_ide_c::register_state(void)
|
||||
{
|
||||
char name[6];
|
||||
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_ide", "PCI IDE Controller State", 5);
|
||||
|
||||
register_pci_state(list, BX_PIDE_THIS s.pci_conf);
|
||||
|
||||
new bx_shadow_data_c(list, "buffer0", BX_PIDE_THIS s.bmdma[0].buffer, 0x20000);
|
||||
new bx_shadow_data_c(list, "buffer1", BX_PIDE_THIS s.bmdma[1].buffer, 0x20000);
|
||||
|
||||
for (unsigned i=0; i<2; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
bx_list_c *ctrl = new bx_list_c(list, name, 7);
|
||||
BXRS_PARAM_BOOL(ctrl, cmd_ssbm, BX_PIDE_THIS s.bmdma[i].cmd_ssbm);
|
||||
BXRS_PARAM_BOOL(ctrl, cmd_rwcon, BX_PIDE_THIS s.bmdma[i].cmd_rwcon);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, status, BX_PIDE_THIS s.bmdma[i].status);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, dtpr, BX_PIDE_THIS s.bmdma[i].dtpr);
|
||||
BXRS_HEX_PARAM_FIELD(ctrl, prd_current, BX_PIDE_THIS s.bmdma[i].prd_current);
|
||||
BXRS_PARAM_SPECIAL32(ctrl, buffer_top,
|
||||
BX_PIDE_THIS param_save_handler, BX_PIDE_THIS param_restore_handler);
|
||||
BXRS_PARAM_SPECIAL32(ctrl, buffer_idx,
|
||||
BX_PIDE_THIS param_save_handler, BX_PIDE_THIS param_restore_handler);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::after_restore_state(void)
|
||||
{
|
||||
if (DEV_pci_set_base_io(BX_PIDE_THIS_PTR, read_handler, write_handler,
|
||||
&BX_PIDE_THIS s.bmdma_addr, &BX_PIDE_THIS s.pci_conf[0x20],
|
||||
16, &bmdma_iomask[0], "PIIX3 PCI IDE controller"))
|
||||
{
|
||||
BX_INFO(("new BM-DMA address: 0x%04x", BX_PIDE_THIS s.bmdma_addr));
|
||||
}
|
||||
}
|
||||
|
||||
Bit64s bx_pci_ide_c::param_save_handler(void *devptr, bx_param_c *param)
|
||||
{
|
||||
#if !BX_USE_PIDE_SMF
|
||||
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) devptr;
|
||||
return class_ptr->param_save(param, val);
|
||||
}
|
||||
|
||||
Bit64s bx_pci_ide_c::param_save(bx_param_c *param)
|
||||
{
|
||||
#else
|
||||
UNUSED(devptr);
|
||||
#endif // !BX_USE_PIDE_SMF
|
||||
int chan = atoi(param->get_parent()->get_name());
|
||||
Bit64s val = 0;
|
||||
if (!strcmp(param->get_name(), "buffer_top")) {
|
||||
val = (Bit32u)(BX_PIDE_THIS s.bmdma[chan].buffer_top - BX_PIDE_THIS s.bmdma[chan].buffer);
|
||||
} else if (!strcmp(param->get_name(), "buffer_idx")) {
|
||||
val = (Bit32u)(BX_PIDE_THIS s.bmdma[chan].buffer_idx - BX_PIDE_THIS s.bmdma[chan].buffer);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::param_restore_handler(void *devptr, bx_param_c *param, Bit64s val)
|
||||
{
|
||||
#if !BX_USE_PIDE_SMF
|
||||
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) devptr;
|
||||
class_ptr->param_restore(param, val);
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::param_restore(bx_param_c *param, Bit64s val)
|
||||
{
|
||||
#else
|
||||
UNUSED(devptr);
|
||||
#endif // !BX_USE_PIDE_SMF
|
||||
int chan = atoi(param->get_parent()->get_name());
|
||||
if (!strcmp(param->get_name(), "buffer_top")) {
|
||||
BX_PIDE_THIS s.bmdma[chan].buffer_top = BX_PIDE_THIS s.bmdma[chan].buffer + val;
|
||||
} else if (!strcmp(param->get_name(), "buffer_idx")) {
|
||||
BX_PIDE_THIS s.bmdma[chan].buffer_idx = BX_PIDE_THIS s.bmdma[chan].buffer + val;
|
||||
}
|
||||
}
|
||||
// save/restore code end
|
||||
|
||||
bx_bool bx_pci_ide_c::bmdma_present(void)
|
||||
{
|
||||
return (BX_PIDE_THIS s.bmdma_addr > 0);
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::bmdma_set_irq(Bit8u channel)
|
||||
{
|
||||
if (channel < 2) {
|
||||
BX_PIDE_THIS s.bmdma[channel].status |= 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
|
||||
class_ptr->timer();
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::timer()
|
||||
{
|
||||
int timer_id, count;
|
||||
Bit8u channel;
|
||||
Bit32u size, sector_size;
|
||||
struct {
|
||||
Bit32u addr;
|
||||
Bit32u size;
|
||||
} prd;
|
||||
|
||||
timer_id = bx_pc_system.triggeredTimerID();
|
||||
if (timer_id == BX_PIDE_THIS s.bmdma[0].timer_index) {
|
||||
channel = 0;
|
||||
} else {
|
||||
channel = 1;
|
||||
}
|
||||
if (((BX_PIDE_THIS s.bmdma[channel].status & 0x01) == 0) ||
|
||||
(BX_PIDE_THIS s.bmdma[channel].prd_current == 0)) {
|
||||
return;
|
||||
}
|
||||
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current, 4, (Bit8u *)&prd.addr);
|
||||
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current+4, 4, (Bit8u *)&prd.size);
|
||||
size = prd.size & 0xfffe;
|
||||
if (size == 0) {
|
||||
size = 0x10000;
|
||||
}
|
||||
if (BX_PIDE_THIS s.bmdma[channel].cmd_rwcon) {
|
||||
BX_DEBUG(("READ DMA to addr=0x%08x, size=0x%08x", prd.addr, size));
|
||||
count = size - (BX_PIDE_THIS s.bmdma[channel].buffer_top - BX_PIDE_THIS s.bmdma[channel].buffer_idx);
|
||||
while (count > 0) {
|
||||
sector_size = count;
|
||||
if (DEV_hd_bmdma_read_sector(channel, BX_PIDE_THIS s.bmdma[channel].buffer_top, §or_size)) {
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_top += sector_size;
|
||||
count -= sector_size;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (count > 0) {
|
||||
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
|
||||
BX_PIDE_THIS s.bmdma[channel].status |= 0x06;
|
||||
return;
|
||||
} else {
|
||||
DEV_MEM_WRITE_PHYSICAL_BLOCK(prd.addr, size, BX_PIDE_THIS s.bmdma[channel].buffer_idx);
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_idx += size;
|
||||
}
|
||||
} else {
|
||||
BX_DEBUG(("WRITE DMA from addr=0x%08x, size=0x%08x", prd.addr, size));
|
||||
DEV_MEM_READ_PHYSICAL_BLOCK(prd.addr, size, BX_PIDE_THIS s.bmdma[channel].buffer_top);
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_top += size;
|
||||
count = BX_PIDE_THIS s.bmdma[channel].buffer_top - BX_PIDE_THIS s.bmdma[channel].buffer_idx;
|
||||
while (count > 511) {
|
||||
if (DEV_hd_bmdma_write_sector(channel, BX_PIDE_THIS s.bmdma[channel].buffer_idx)) {
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_idx += 512;
|
||||
count -= 512;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (count > 511) {
|
||||
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
|
||||
BX_PIDE_THIS s.bmdma[channel].status |= 0x06;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (prd.size & 0x80000000) {
|
||||
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
|
||||
BX_PIDE_THIS s.bmdma[channel].status |= 0x04;
|
||||
BX_PIDE_THIS s.bmdma[channel].prd_current = 0;
|
||||
DEV_hd_bmdma_complete(channel);
|
||||
} else {
|
||||
BX_PIDE_THIS s.bmdma[channel].prd_current += 8;
|
||||
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current, 4, (Bit8u *)&prd.addr);
|
||||
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current+4, 4, (Bit8u *)&prd.size);
|
||||
size = prd.size & 0xfffe;
|
||||
if (size == 0) {
|
||||
size = 0x10000;
|
||||
}
|
||||
bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, (size >> 4) | 0x10, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_pci_ide_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIDE_SMF
|
||||
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pci_ide_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIDE_SMF
|
||||
Bit8u offset, channel;
|
||||
Bit32u value = 0xffffffff;
|
||||
|
||||
offset = address - BX_PIDE_THIS s.bmdma_addr;
|
||||
channel = (offset >> 3);
|
||||
offset &= 0x07;
|
||||
switch (offset) {
|
||||
case 0x00:
|
||||
value = BX_PIDE_THIS s.bmdma[channel].cmd_ssbm |
|
||||
(BX_PIDE_THIS s.bmdma[channel].cmd_rwcon << 3);
|
||||
BX_DEBUG(("BM-DMA read command register, channel %d, value = 0x%02x", channel, value));
|
||||
break;
|
||||
case 0x02:
|
||||
value = BX_PIDE_THIS s.bmdma[channel].status;
|
||||
BX_DEBUG(("BM-DMA read status register, channel %d, value = 0x%02x", channel, value));
|
||||
break;
|
||||
case 0x04:
|
||||
value = BX_PIDE_THIS s.bmdma[channel].dtpr;
|
||||
BX_DEBUG(("BM-DMA read DTP register, channel %d, value = 0x%04x", channel, value));
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_pci_ide_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIDE_SMF
|
||||
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
|
||||
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_pci_ide_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIDE_SMF
|
||||
Bit8u offset, channel;
|
||||
|
||||
offset = address - BX_PIDE_THIS s.bmdma_addr;
|
||||
channel = (offset >> 3);
|
||||
offset &= 0x07;
|
||||
switch (offset) {
|
||||
case 0x00:
|
||||
BX_DEBUG(("BM-DMA write command register, channel %d, value = 0x%02x", channel, value));
|
||||
BX_PIDE_THIS s.bmdma[channel].cmd_rwcon = (value >> 3) & 1;
|
||||
if ((value & 0x01) && !BX_PIDE_THIS s.bmdma[channel].cmd_ssbm) {
|
||||
BX_PIDE_THIS s.bmdma[channel].cmd_ssbm = 1;
|
||||
BX_PIDE_THIS s.bmdma[channel].status |= 0x01;
|
||||
BX_PIDE_THIS s.bmdma[channel].prd_current = BX_PIDE_THIS s.bmdma[channel].dtpr;
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_top = BX_PIDE_THIS s.bmdma[channel].buffer;
|
||||
BX_PIDE_THIS s.bmdma[channel].buffer_idx = BX_PIDE_THIS s.bmdma[channel].buffer;
|
||||
bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, 1000, 0);
|
||||
} else if (!(value & 0x01) && BX_PIDE_THIS s.bmdma[channel].cmd_ssbm) {
|
||||
BX_PIDE_THIS s.bmdma[channel].cmd_ssbm = 0;
|
||||
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
BX_PIDE_THIS s.bmdma[channel].status = (value & 0x60)
|
||||
| (BX_PIDE_THIS s.bmdma[channel].status & 0x01)
|
||||
| (BX_PIDE_THIS s.bmdma[channel].status & (~value & 0x06));
|
||||
BX_DEBUG(("BM-DMA write status register, channel %d, value = 0x%02x", channel, value));
|
||||
break;
|
||||
case 0x04:
|
||||
BX_PIDE_THIS s.bmdma[channel].dtpr = value & 0xfffffffc;
|
||||
BX_DEBUG(("BM-DMA write DTP register, channel %d, value = 0x%04x", channel, value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_pci_ide_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_PIDE_THIS s.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
BX_DEBUG(("PIIX3 PCI IDE read register 0x%02x value 0x%08x", address, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
// pci configuration space write callback handler
|
||||
void bx_pci_ide_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
Bit8u value8, oldval;
|
||||
bx_bool bmdma_change = 0;
|
||||
|
||||
if (((address >= 0x10) && (address < 0x20)) ||
|
||||
((address > 0x23) && (address < 0x40)))
|
||||
return;
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
oldval = BX_PIDE_THIS s.pci_conf[address+i];
|
||||
value8 = (value >> (i*8)) & 0xFF;
|
||||
switch (address+i) {
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
break;
|
||||
case 0x04:
|
||||
BX_PIDE_THIS s.pci_conf[address+i] = value8 & 0x05;
|
||||
break;
|
||||
case 0x20:
|
||||
value8 = (value8 & 0xfc) | 0x01;
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
bmdma_change |= (value8 != oldval);
|
||||
default:
|
||||
BX_PIDE_THIS s.pci_conf[address+i] = value8;
|
||||
BX_DEBUG(("PIIX3 PCI IDE write register 0x%02x value 0x%02x", address+i,
|
||||
value8));
|
||||
}
|
||||
}
|
||||
if (bmdma_change) {
|
||||
if (DEV_pci_set_base_io(BX_PIDE_THIS_PTR, read_handler, write_handler,
|
||||
&BX_PIDE_THIS s.bmdma_addr, &BX_PIDE_THIS s.pci_conf[0x20],
|
||||
16, &bmdma_iomask[0], "PIIX3 PCI IDE controller")) {
|
||||
BX_INFO(("new BM-DMA address: 0x%04x", BX_PIDE_THIS s.bmdma_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BX_SUPPORT_PCI */
|
||||
83
bochs/iodev/pci_ide.h
Normal file
83
bochs/iodev/pci_ide.h
Normal file
@ -0,0 +1,83 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PCIIDE_H
|
||||
#define BX_IODEV_PCIIDE_H
|
||||
|
||||
#if BX_USE_PIDE_SMF
|
||||
# define BX_PIDE_SMF static
|
||||
# define BX_PIDE_THIS thePciIdeController->
|
||||
# define BX_PIDE_THIS_PTR thePciIdeController
|
||||
#else
|
||||
# define BX_PIDE_SMF
|
||||
# define BX_PIDE_THIS this->
|
||||
# define BX_PIDE_THIS_PTR this
|
||||
#endif
|
||||
|
||||
class bx_pci_ide_c : public bx_pci_ide_stub_c {
|
||||
public:
|
||||
bx_pci_ide_c();
|
||||
virtual ~bx_pci_ide_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual bx_bool bmdma_present(void);
|
||||
virtual void bmdma_set_irq(Bit8u channel);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
static Bit64s param_save_handler(void *devptr, bx_param_c *param);
|
||||
static void param_restore_handler(void *devptr, bx_param_c *param, Bit64s val);
|
||||
#if !BX_USE_PIDE_SMF
|
||||
Bit64s param_save(bx_param_c *param);
|
||||
void param_restore(bx_param_c *param, Bit64s val);
|
||||
#endif
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
static void timer_handler(void *);
|
||||
BX_PIDE_SMF void timer(void);
|
||||
|
||||
private:
|
||||
|
||||
struct {
|
||||
Bit8u pci_conf[256];
|
||||
Bit32u bmdma_addr;
|
||||
struct {
|
||||
bx_bool cmd_ssbm;
|
||||
bx_bool cmd_rwcon;
|
||||
Bit8u status;
|
||||
Bit32u dtpr;
|
||||
Bit32u prd_current;
|
||||
int timer_index;
|
||||
Bit8u *buffer;
|
||||
Bit8u *buffer_top;
|
||||
Bit8u *buffer_idx;
|
||||
} bmdma[2];
|
||||
} s;
|
||||
|
||||
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_PIDE_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
464
bochs/iodev/pcidev.cc
Normal file
464
bochs/iodev/pcidev.cc
Normal file
@ -0,0 +1,464 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* PCIDEV: PCI host device mapping
|
||||
* Copyright (C) 2003 - Frank Cornelis
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on pcivga code:
|
||||
* Copyright (C) 2002,2003 Mike Nordell
|
||||
*/
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIDEV
|
||||
|
||||
#include "pcidev.h"
|
||||
#include "kernel_pcidev.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define LOG_THIS thePciDevAdapter->
|
||||
|
||||
bx_pcidev_c* thePciDevAdapter = NULL;
|
||||
|
||||
int libpcidev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePciDevAdapter = new bx_pcidev_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciDevAdapter, BX_PLUGIN_PCIDEV);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void libpcidev_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePciDevAdapter;
|
||||
}
|
||||
|
||||
bx_pcidev_c::bx_pcidev_c()
|
||||
{
|
||||
put("PCI2H");
|
||||
}
|
||||
|
||||
bx_pcidev_c::~bx_pcidev_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
static void pcidev_sighandler(int param)
|
||||
{
|
||||
bx_pcidev_c *pcidev = thePciDevAdapter;
|
||||
BX_INFO(("Interrupt received."));
|
||||
DEV_pci_set_irq(pcidev->devfunc, pcidev->intpin, 0);
|
||||
/*
|
||||
* We need to first lower the IRQ line or else we don't
|
||||
* get any IRQs through
|
||||
*/
|
||||
DEV_pci_set_irq(pcidev->devfunc, pcidev->intpin, 1);
|
||||
}
|
||||
|
||||
static bx_bool pcidev_mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
|
||||
{
|
||||
struct region_struct *region = (struct region_struct *)param;
|
||||
bx_pcidev_c *pcidev = region->pcidev;
|
||||
int fd = pcidev->pcidev_fd;
|
||||
int ret = -1;
|
||||
|
||||
if (fd == -1)
|
||||
return false; /* we failed to handle the request, so let a default handler do it for us */
|
||||
|
||||
BX_INFO(("Reading I/O memory at 0x%08x", (unsigned)addr));
|
||||
struct pcidev_io_struct io;
|
||||
io.address = addr + region->host_start - region->start;
|
||||
switch(len) {
|
||||
case 1:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_BYTE, &io);
|
||||
*(Bit8u *)data = io.value;
|
||||
break;
|
||||
case 2:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_WORD, &io);
|
||||
*(Bit16u *)data = io.value;
|
||||
break;
|
||||
case 4:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_DWORD, &io);
|
||||
*(Bit32u *)data = io.value;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unsupported pcidev read mem operation"));
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
BX_ERROR(("pcidev read mem error"));
|
||||
}
|
||||
return true; // ok, we handled the request
|
||||
}
|
||||
|
||||
|
||||
static bx_bool pcidev_mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
|
||||
{
|
||||
struct region_struct *region = (struct region_struct *)param;
|
||||
bx_pcidev_c *pcidev = region->pcidev;
|
||||
int fd = pcidev->pcidev_fd;
|
||||
int ret = -1;
|
||||
|
||||
if (fd == -1)
|
||||
return false; /* we failed to handle the request, so let a default handler do it for us */
|
||||
|
||||
BX_INFO(("Writing I/O memory at 0x%08x", (unsigned)addr));
|
||||
struct pcidev_io_struct io;
|
||||
io.address = addr + region->host_start - region->start;
|
||||
switch(len) {
|
||||
case 1:
|
||||
io.value = *(Bit8u *)data;
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_BYTE, &io);
|
||||
break;
|
||||
case 2:
|
||||
io.value = *(Bit16u *)data;
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_WORD, &io);
|
||||
break;
|
||||
case 4:
|
||||
io.value = *(Bit32u *)data;
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_DWORD, &io);
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unsupported pcidev write mem operation"));
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
BX_ERROR(("pcidev write mem error"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const char * const pcidev_name = "Experimental PCI 2 host PCI";
|
||||
|
||||
void bx_pcidev_c::init(void)
|
||||
{
|
||||
// called once when bochs initializes
|
||||
BX_PCIDEV_THIS pcidev_fd = -1;
|
||||
int fd;
|
||||
fd = open("/dev/pcidev", O_RDWR);
|
||||
if (fd == -1) {
|
||||
switch(errno) {
|
||||
case ENODEV:
|
||||
BX_PANIC(("The pcidev kernel module is not loaded!"));
|
||||
break;
|
||||
default:
|
||||
BX_PANIC(("open /dev/pcidev: %s", strerror(errno)));
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
BX_PCIDEV_THIS pcidev_fd = fd;
|
||||
struct pcidev_find_struct find;
|
||||
unsigned short vendor = SIM->get_param_num(BXPN_PCIDEV_VENDOR)->get();
|
||||
unsigned short device = SIM->get_param_num(BXPN_PCIDEV_DEVICE)->get();
|
||||
find.deviceID = device;
|
||||
find.vendorID = vendor;
|
||||
if (ioctl(fd, PCIDEV_IOCTL_FIND, &find) == -1) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
BX_PANIC(("PCI device not found on host system."));
|
||||
break;
|
||||
case EBUSY:
|
||||
BX_PANIC(("PCI device already used by another kernel module."));
|
||||
break;
|
||||
default:
|
||||
perror("ioctl");
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
BX_PCIDEV_THIS pcidev_fd = -1;
|
||||
return;
|
||||
}
|
||||
BX_INFO(("vendor: %04x; device: %04x @ host %04x:%04x.%d", vendor, device,
|
||||
(unsigned)find.bus, (unsigned)find.device, (unsigned)find.func));
|
||||
|
||||
BX_PCIDEV_THIS devfunc = 0x00;
|
||||
DEV_register_pci_handlers(this, &BX_PCIDEV_THIS devfunc, BX_PLUGIN_PCIDEV,
|
||||
pcidev_name);
|
||||
|
||||
BX_PCIDEV_THIS irq = 0;
|
||||
struct pcidev_io_struct io;
|
||||
io.address = 0x3d;
|
||||
int ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_BYTE, &io);
|
||||
if (ret != -1) {
|
||||
BX_PCIDEV_THIS intpin = io.value;
|
||||
} else {
|
||||
BX_PCIDEV_THIS intpin = 0;
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++) {
|
||||
BX_PCIDEV_THIS regions[idx].start = 0; // emulated device not yet initialized
|
||||
if (!find.resources[idx].start)
|
||||
continue;
|
||||
BX_INFO(("PCI resource @ %x-%x (%s)", (unsigned)find.resources[idx].start,
|
||||
(unsigned)find.resources[idx].end,
|
||||
(find.resources[idx].flags & PCIDEV_RESOURCE_IO ? "I/O" : "Mem")));
|
||||
BX_PCIDEV_THIS regions[idx].size = find.resources[idx].end - find.resources[idx].start + 1;
|
||||
BX_PCIDEV_THIS regions[idx].host_start = find.resources[idx].start;
|
||||
struct pcidev_io_struct io;
|
||||
io.address = PCI_BASE_ADDRESS_0 + idx * 4;
|
||||
if (ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io) == -1)
|
||||
BX_ERROR(("Error reading a base address config reg"));
|
||||
BX_PCIDEV_THIS regions[idx].config_value = io.value;
|
||||
/*
|
||||
* We will use ®ion[idx] as parameter for our I/O or memory
|
||||
* handler. So we provide a pcidev pointer to the pcidev object
|
||||
* in order for the handle to be able to use its pcidev object
|
||||
*/
|
||||
BX_PCIDEV_THIS regions[idx].pcidev = this;
|
||||
}
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = pcidev_sighandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
|
||||
/*
|
||||
* The kernel pcidev will fire SIGUSR1 signals when it receives
|
||||
* interrupts from the host PCI device.
|
||||
*/
|
||||
ioctl(fd, PCIDEV_IOCTL_INTERRUPT, 1);
|
||||
}
|
||||
|
||||
void bx_pcidev_c::reset(unsigned type) { }
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_pcidev_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
int fd = BX_PCIDEV_THIS pcidev_fd;
|
||||
if (fd == -1)
|
||||
return 0xffffffff;
|
||||
|
||||
struct pcidev_io_struct io;
|
||||
io.address = address;
|
||||
switch(io_len) {
|
||||
case 1:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_BYTE, &io);
|
||||
break;
|
||||
case 2:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_WORD, &io);
|
||||
break;
|
||||
case 4:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io);
|
||||
break;
|
||||
}
|
||||
if (ret == -1)
|
||||
BX_ERROR(("pcidev config read error"));
|
||||
|
||||
// we don't use the host irq line but our own bochs irq line
|
||||
if (address == PCI_INTERRUPT_LINE) {
|
||||
io.value = (io.value & 0xffffff00) | (BX_PCIDEV_THIS irq & 0xff);
|
||||
}
|
||||
if (PCI_BASE_ADDRESS_0 <= address && address <= PCI_BASE_ADDRESS_5) {
|
||||
BX_INFO(("Reading pcidev base address #%d", (address - PCI_BASE_ADDRESS_0) / 4));
|
||||
io.value = BX_PCIDEV_THIS regions[(address - PCI_BASE_ADDRESS_0) >> 2].config_value;
|
||||
if (address & 3) {
|
||||
io.value >>= (8 * (address & 3));
|
||||
}
|
||||
}
|
||||
|
||||
return io.value;
|
||||
}
|
||||
|
||||
// pci configuration space write callback handler
|
||||
void bx_pcidev_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
int ret = -1;
|
||||
Bit8u *iomask;
|
||||
Bit32u bitmask;
|
||||
|
||||
int fd = BX_PCIDEV_THIS pcidev_fd;
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
// we do a host 2 guest irq line mapping
|
||||
if (address == PCI_INTERRUPT_LINE) {
|
||||
value &= 0xff;
|
||||
BX_INFO(("Changing the pcidev irq line from %d to %d", BX_PCIDEV_THIS irq, value));
|
||||
BX_PCIDEV_THIS irq = value;
|
||||
return;
|
||||
}
|
||||
if ((PCI_BASE_ADDRESS_0 <= address) && (address <= PCI_BASE_ADDRESS_5)) {
|
||||
/*
|
||||
* Two things to do here:
|
||||
* - update the cached config space value via a probe
|
||||
* - remap the I/O or memory handler if required
|
||||
*/
|
||||
int io_reg_idx = (address - PCI_BASE_ADDRESS_0) >> 2;
|
||||
switch (io_len) {
|
||||
case 1: bitmask = 0xff; break;
|
||||
case 2: bitmask = 0xffff; break;
|
||||
default: bitmask = 0xffffffff;
|
||||
}
|
||||
bitmask <<= (8 * (address & 3));
|
||||
value <<= (8 * (address & 3));
|
||||
value |= BX_PCIDEV_THIS regions[io_reg_idx].config_value & ~bitmask;
|
||||
BX_INFO(("Changing pcidev base address #%d - New value: %#x",
|
||||
(address - PCI_BASE_ADDRESS_0) / 4, value));
|
||||
struct pcidev_io_struct io;
|
||||
io.address = address;
|
||||
io.value = value;
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_PROBE_CONFIG_DWORD, &io);
|
||||
if (ret == -1) {
|
||||
BX_ERROR(("Error probing a base address reg!"));
|
||||
return;
|
||||
}
|
||||
unsigned long base = io.value;
|
||||
BX_PCIDEV_THIS regions[io_reg_idx].config_value = base;
|
||||
/* remap the I/O or memory handler if required using io.value
|
||||
* We assume that an I/O memory region will stay and I/O memory
|
||||
* region. And that an I/O port region also will stay an I/O port
|
||||
* region.
|
||||
*/
|
||||
if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
|
||||
if (DEV_pci_set_base_mem(&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
||||
pcidev_mem_read_handler,
|
||||
pcidev_mem_write_handler,
|
||||
&BX_PCIDEV_THIS regions[io_reg_idx].start,
|
||||
(Bit8u*)&BX_PCIDEV_THIS regions[io_reg_idx].config_value,
|
||||
BX_PCIDEV_THIS regions[io_reg_idx].size)) {
|
||||
BX_INFO(("new base #%d memory address: 0x%08x", io_reg_idx,
|
||||
BX_PCIDEV_THIS regions[io_reg_idx].start));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Remap our I/O port handlers here.
|
||||
*/
|
||||
iomask = (Bit8u*)malloc(BX_PCIDEV_THIS regions[io_reg_idx].size);
|
||||
memset(iomask, 7, BX_PCIDEV_THIS regions[io_reg_idx].size);
|
||||
if (DEV_pci_set_base_io(&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
||||
read_handler, write_handler,
|
||||
&BX_PCIDEV_THIS regions[io_reg_idx].start,
|
||||
(Bit8u*)&BX_PCIDEV_THIS regions[io_reg_idx].config_value,
|
||||
BX_PCIDEV_THIS regions[io_reg_idx].size, iomask, "pcidev")) {
|
||||
BX_INFO(("new base #%d i/o address: 0x%04x", io_reg_idx,
|
||||
(Bit16u)BX_PCIDEV_THIS regions[io_reg_idx].start));
|
||||
}
|
||||
free(iomask);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct pcidev_io_struct io;
|
||||
io.address = address;
|
||||
io.value = value;
|
||||
|
||||
switch(io_len) {
|
||||
case 1:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_BYTE, &io);
|
||||
break;
|
||||
case 2:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_WORD, &io);
|
||||
break;
|
||||
case 4:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_DWORD, &io);
|
||||
break;
|
||||
}
|
||||
if (ret == -1)
|
||||
BX_ERROR(("pcidev config write error"));
|
||||
}
|
||||
|
||||
Bit32u bx_pcidev_c::read_handler(void *param, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCIDEV_SMF
|
||||
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
|
||||
return class_ptr->read(param, address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pcidev_c::read(void *param, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#endif
|
||||
struct region_struct *region = (struct region_struct *)param;
|
||||
int ret = -1;
|
||||
|
||||
int fd = BX_PCIDEV_THIS pcidev_fd;
|
||||
if (fd == -1)
|
||||
return 0xffffffff;
|
||||
|
||||
struct pcidev_io_struct io;
|
||||
// here we map the io address
|
||||
io.address = address + region->host_start - region->start;
|
||||
switch(io_len) {
|
||||
case 1:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_BYTE, &io);
|
||||
break;
|
||||
case 2:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_WORD, &io);
|
||||
break;
|
||||
case 4:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_DWORD, &io);
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
BX_ERROR(("pcidev read I/O error"));
|
||||
io.value = 0xffffffff;
|
||||
}
|
||||
|
||||
return io.value;
|
||||
}
|
||||
|
||||
void bx_pcidev_c::write_handler(void *param, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCIDEV_SMF
|
||||
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
|
||||
class_ptr->write(param, address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_pcidev_c::write(void *param, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#endif
|
||||
struct region_struct *region = (struct region_struct *)param;
|
||||
int ret = -1;
|
||||
|
||||
int fd = BX_PCIDEV_THIS pcidev_fd;
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
struct pcidev_io_struct io;
|
||||
// here we map the I/O address
|
||||
io.address = address + region->host_start - region->start;
|
||||
io.value = value;
|
||||
|
||||
switch(io_len) {
|
||||
case 1:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_BYTE, &io);
|
||||
break;
|
||||
case 2:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_WORD, &io);
|
||||
break;
|
||||
case 4:
|
||||
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_DWORD, &io);
|
||||
break;
|
||||
}
|
||||
if (ret == -1)
|
||||
BX_ERROR(("pcidev I/O write error"));
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIDEV
|
||||
69
bochs/iodev/pcidev.h
Normal file
69
bochs/iodev/pcidev.h
Normal file
@ -0,0 +1,69 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* PCIDEV: PCI host device mapping
|
||||
* Copyright (C) 2003 - Frank Cornelis
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef BX_IODEV_PCIDEV_H
|
||||
#define BX_IODEV_PCIDEV_H
|
||||
|
||||
#if BX_USE_PCIDEV_SMF
|
||||
# define BX_PCIDEV_THIS thePciDevAdapter->
|
||||
# define BX_PCIDEV_THIS_ thePciDevAdapter
|
||||
#else
|
||||
# define BX_PCIDEV_THIS this->
|
||||
# define BX_PCIDEV_THIS_ this
|
||||
#endif
|
||||
|
||||
struct region_struct {
|
||||
Bit32u config_value;
|
||||
Bit32u start; // can change
|
||||
Bit32u size;
|
||||
Bit32u host_start; // never changes!!!
|
||||
class bx_pcidev_c *pcidev;
|
||||
};
|
||||
|
||||
class bx_pcidev_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
bx_pcidev_c();
|
||||
virtual ~bx_pcidev_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
int pcidev_fd; // to access the pcidev
|
||||
|
||||
// resource mapping
|
||||
struct region_struct regions[6];
|
||||
Bit8u devfunc;
|
||||
Bit8u intpin;
|
||||
Bit8u irq;
|
||||
|
||||
private:
|
||||
static Bit32u read_handler(void *param, Bit32u address, unsigned io_len);
|
||||
static void write_handler(void *param, Bit32u address, Bit32u value, unsigned io_len);
|
||||
#if !BX_USE_PCIDEV_SMF
|
||||
Bit32u read(void *param, Bit32u address, unsigned io_len);
|
||||
void write(void *param, Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
522
bochs/iodev/pcipnic.cc
Normal file
522
bochs/iodev/pcipnic.cc
Normal file
@ -0,0 +1,522 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2003 Fen Systems Ltd.
|
||||
// http://www.fensystems.co.uk/
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIPNIC
|
||||
|
||||
#include "pci.h"
|
||||
#include "eth.h"
|
||||
#include "pcipnic.h"
|
||||
|
||||
#define LOG_THIS thePNICDevice->
|
||||
|
||||
bx_pcipnic_c* thePNICDevice = NULL;
|
||||
|
||||
const Bit8u pnic_iomask[16] = {2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
int libpcipnic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePNICDevice = new bx_pcipnic_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePNICDevice, BX_PLUGIN_PCIPNIC);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void libpcipnic_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePNICDevice;
|
||||
}
|
||||
|
||||
bx_pcipnic_c::bx_pcipnic_c()
|
||||
{
|
||||
put("PNIC");
|
||||
}
|
||||
|
||||
bx_pcipnic_c::~bx_pcipnic_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::init(void)
|
||||
{
|
||||
bx_list_c *base;
|
||||
|
||||
// Read in values from config interface
|
||||
base = (bx_list_c*) SIM->get_param(BXPN_PNIC);
|
||||
memcpy(BX_PNIC_THIS s.macaddr, SIM->get_param_string("macaddr", base)->getptr(), 6);
|
||||
|
||||
BX_PNIC_THIS s.devfunc = 0x00;
|
||||
DEV_register_pci_handlers(this, &BX_PNIC_THIS s.devfunc, BX_PLUGIN_PCIPNIC,
|
||||
"Experimental PCI Pseudo NIC");
|
||||
|
||||
for (unsigned i=0; i<256; i++) {
|
||||
BX_PNIC_THIS s.pci_conf[i] = 0x0;
|
||||
}
|
||||
|
||||
// This code ripped wholesale from ne2k.cc:
|
||||
// Attach to the simulated ethernet dev
|
||||
const char *ethmod = SIM->get_param_enum("ethmod", base)->get_selected();
|
||||
BX_PNIC_THIS ethdev = eth_locator_c::create(ethmod,
|
||||
SIM->get_param_string("ethdev", base)->getptr(),
|
||||
(const char *) SIM->get_param_string("macaddr", base)->getptr(),
|
||||
rx_handler,
|
||||
this,
|
||||
SIM->get_param_string("script", base)->getptr());
|
||||
|
||||
if (BX_PNIC_THIS ethdev == NULL) {
|
||||
BX_PANIC(("could not find eth module %s", ethmod));
|
||||
// if they continue, use null.
|
||||
BX_INFO(("could not find eth module %s - using null instead", ethmod));
|
||||
|
||||
BX_PNIC_THIS ethdev = eth_locator_c::create("null", NULL,
|
||||
(const char *) SIM->get_param_string("macaddr", base)->getptr(),
|
||||
rx_handler,
|
||||
this, "");
|
||||
if (BX_PNIC_THIS ethdev == NULL)
|
||||
BX_PANIC(("could not locate null module"));
|
||||
}
|
||||
|
||||
BX_PNIC_THIS s.base_ioaddr = 0;
|
||||
|
||||
BX_INFO(("PCI Pseudo NIC initialized - I/O base and IRQ assigned by PCI BIOS"));
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::reset(unsigned type)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
static const struct reset_vals_t {
|
||||
unsigned addr;
|
||||
unsigned char val;
|
||||
} reset_vals[] = {
|
||||
{ 0x00, PNIC_PCI_VENDOR & 0xff },
|
||||
{ 0x01, PNIC_PCI_VENDOR >> 8 },
|
||||
{ 0x02, PNIC_PCI_DEVICE & 0xff },
|
||||
{ 0x03, PNIC_PCI_DEVICE >> 8 },
|
||||
{ 0x04, 0x05 }, { 0x05, 0x00 }, // command_io
|
||||
{ 0x06, 0x80 }, { 0x07, 0x02 }, // status
|
||||
{ 0x08, 0x01 }, // revision number
|
||||
{ 0x09, 0x00 }, // interface
|
||||
{ 0x0a, 0x00 }, // class_sub
|
||||
{ 0x0b, 0x02 }, // class_base Network Controller
|
||||
{ 0x0D, 0x20 }, // bus latency
|
||||
{ 0x0e, 0x00 }, // header_type_generic
|
||||
// address space 0x20 - 0x23
|
||||
{ 0x20, 0x01 }, { 0x21, 0x00 },
|
||||
{ 0x22, 0x00 }, { 0x23, 0x00 },
|
||||
{ 0x3c, 0x00, }, // IRQ
|
||||
{ 0x3d, BX_PCI_INTA }, // INT
|
||||
{ 0x6a, 0x01 }, // PNIC clock
|
||||
{ 0xc1, 0x20 } // PIRQ enable
|
||||
|
||||
};
|
||||
for (i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
|
||||
BX_PNIC_THIS s.pci_conf[reset_vals[i].addr] = reset_vals[i].val;
|
||||
}
|
||||
|
||||
// Set up initial register values
|
||||
BX_PNIC_THIS s.rCmd = PNIC_CMD_NOOP;
|
||||
BX_PNIC_THIS s.rStatus = PNIC_STATUS_OK;
|
||||
BX_PNIC_THIS s.rLength = 0;
|
||||
BX_PNIC_THIS s.rDataCursor = 0;
|
||||
BX_PNIC_THIS s.recvIndex = 0;
|
||||
BX_PNIC_THIS s.recvQueueLength = 0;
|
||||
BX_PNIC_THIS s.irqEnabled = 0;
|
||||
|
||||
// Deassert IRQ
|
||||
set_irq_level(0);
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::register_state(void)
|
||||
{
|
||||
unsigned i;
|
||||
char name[6];
|
||||
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pcipnic", "PCI Pseudo NIC State", 11);
|
||||
new bx_shadow_num_c(list, "irqEnabled", &BX_PNIC_THIS s.irqEnabled);
|
||||
new bx_shadow_num_c(list, "rCmd", &BX_PNIC_THIS s.rCmd);
|
||||
new bx_shadow_num_c(list, "rStatus", &BX_PNIC_THIS s.rStatus);
|
||||
new bx_shadow_num_c(list, "rLength", &BX_PNIC_THIS s.rLength);
|
||||
new bx_shadow_num_c(list, "rDataCursor", &BX_PNIC_THIS s.rDataCursor);
|
||||
new bx_shadow_num_c(list, "recvIndex", &BX_PNIC_THIS s.recvIndex);
|
||||
new bx_shadow_num_c(list, "recvQueueLength", &BX_PNIC_THIS s.recvQueueLength);
|
||||
bx_list_c *recvRL = new bx_list_c(list, "recvRingLength", PNIC_RECV_RINGS);
|
||||
for (i=0; i<PNIC_RECV_RINGS; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
new bx_shadow_num_c(recvRL, name, &BX_PNIC_THIS s.recvRingLength[i]);
|
||||
}
|
||||
new bx_shadow_data_c(list, "rData", BX_PNIC_THIS s.rData, PNIC_DATA_SIZE);
|
||||
new bx_shadow_data_c(list, "recvRing", (Bit8u*)BX_PNIC_THIS s.recvRing, PNIC_RECV_RINGS*PNIC_DATA_SIZE);
|
||||
register_pci_state(list, BX_PNIC_THIS s.pci_conf);
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::after_restore_state(void)
|
||||
{
|
||||
if (DEV_pci_set_base_io(BX_PNIC_THIS_PTR, read_handler, write_handler,
|
||||
&BX_PNIC_THIS s.base_ioaddr,
|
||||
&BX_PNIC_THIS s.pci_conf[0x10],
|
||||
16, &pnic_iomask[0], "PNIC")) {
|
||||
BX_INFO(("new base address: 0x%04x", BX_PNIC_THIS s.base_ioaddr));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::set_irq_level(bx_bool level)
|
||||
{
|
||||
DEV_pci_set_irq(BX_PNIC_THIS s.devfunc, BX_PNIC_THIS s.pci_conf[0x3d], level);
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_pcipnic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCIPNIC_SMF
|
||||
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pcipnic_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCIPNIC_SMF
|
||||
Bit32u val = 0x0;
|
||||
Bit8u offset;
|
||||
|
||||
BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
|
||||
|
||||
offset = address - BX_PNIC_THIS s.base_ioaddr;
|
||||
|
||||
switch (offset) {
|
||||
case PNIC_REG_STAT:
|
||||
val = BX_PNIC_THIS s.rStatus;
|
||||
break;
|
||||
|
||||
case PNIC_REG_LEN:
|
||||
val = BX_PNIC_THIS s.rLength;
|
||||
break;
|
||||
|
||||
case PNIC_REG_DATA:
|
||||
if (BX_PNIC_THIS s.rDataCursor >= BX_PNIC_THIS s.rLength)
|
||||
BX_PANIC(("PNIC read at %u, beyond end of data register array",
|
||||
BX_PNIC_THIS s.rDataCursor));
|
||||
val = BX_PNIC_THIS s.rData[BX_PNIC_THIS s.rDataCursor++];
|
||||
break;
|
||||
|
||||
default :
|
||||
val = 0; // keep compiler happy
|
||||
BX_PANIC(("unsupported io read from address=0x%04x!", (unsigned) address));
|
||||
break;
|
||||
}
|
||||
|
||||
BX_DEBUG(("val = 0x%04x", (Bit16u) val));
|
||||
|
||||
return(val);
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_pcipnic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCIPNIC_SMF
|
||||
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
|
||||
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCIPNIC_SMF
|
||||
Bit8u offset;
|
||||
|
||||
BX_DEBUG(("register write to address 0x%04x - ", (unsigned) address));
|
||||
|
||||
offset = address - BX_PNIC_THIS s.base_ioaddr;
|
||||
|
||||
switch (offset) {
|
||||
case PNIC_REG_CMD:
|
||||
BX_PNIC_THIS s.rCmd = value;
|
||||
BX_PNIC_THIS exec_command();
|
||||
break;
|
||||
|
||||
case PNIC_REG_LEN:
|
||||
if (value > PNIC_DATA_SIZE)
|
||||
BX_PANIC(("PNIC bad length %u written to length register, max is %u",
|
||||
value, PNIC_DATA_SIZE));
|
||||
BX_PNIC_THIS s.rLength = value;
|
||||
BX_PNIC_THIS s.rDataCursor = 0;
|
||||
break;
|
||||
|
||||
case PNIC_REG_DATA:
|
||||
if (BX_PNIC_THIS s.rDataCursor >= BX_PNIC_THIS s.rLength)
|
||||
BX_PANIC(("PNIC write at %u, beyond end of data register array",
|
||||
BX_PNIC_THIS s.rDataCursor));
|
||||
BX_PNIC_THIS s.rData[BX_PNIC_THIS s.rDataCursor++] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("unsupported io write to address=0x%04x!", (unsigned) address));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pcipnic_c::pnic_timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
|
||||
class_ptr->pnic_timer();
|
||||
}
|
||||
|
||||
// Called once every 1ms
|
||||
void bx_pcipnic_c::pnic_timer(void)
|
||||
{
|
||||
// Do nothing atm
|
||||
|
||||
}
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_pcipnic_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_PNIC_THIS s.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// pci configuration space write callback handler
|
||||
void bx_pcipnic_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
Bit8u value8, oldval;
|
||||
bx_bool baseaddr_change = 0;
|
||||
|
||||
if (((address >= 0x10) && (address < 0x20)) ||
|
||||
((address > 0x23) && (address < 0x34)))
|
||||
return;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value8 = (value >> (i*8)) & 0xFF;
|
||||
oldval = BX_PNIC_THIS s.pci_conf[address+i];
|
||||
switch (address+i) {
|
||||
case 0x3d: //
|
||||
case 0x05: // disallowing write to command hi-byte
|
||||
case 0x06: // disallowing write to status lo-byte (is that expected?)
|
||||
break;
|
||||
case 0x3c:
|
||||
if (value8 != oldval) {
|
||||
BX_INFO(("new irq line = %d", value8));
|
||||
BX_PNIC_THIS s.pci_conf[address+i] = value8;
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
value8 = (value8 & 0xfc) | 0x01;
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
baseaddr_change = (value8 != oldval);
|
||||
default:
|
||||
BX_PNIC_THIS s.pci_conf[address+i] = value8;
|
||||
}
|
||||
}
|
||||
if (baseaddr_change) {
|
||||
if (DEV_pci_set_base_io(BX_PNIC_THIS_PTR, read_handler, write_handler,
|
||||
&BX_PNIC_THIS s.base_ioaddr,
|
||||
&BX_PNIC_THIS s.pci_conf[0x20],
|
||||
16, &pnic_iomask[0], "PNIC")) {
|
||||
BX_INFO(("new base address: 0x%04x", BX_PNIC_THIS s.base_ioaddr));
|
||||
}
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute a hardware command.
|
||||
*/
|
||||
void bx_pcipnic_c::exec_command(void)
|
||||
{
|
||||
Bit16u command = BX_PNIC_THIS s.rCmd;
|
||||
Bit16u ilength = BX_PNIC_THIS s.rLength;
|
||||
Bit8u *data = BX_PNIC_THIS s.rData;
|
||||
// Default return values
|
||||
Bit16u status = PNIC_STATUS_UNKNOWN_CMD;
|
||||
Bit16u olength = 0;
|
||||
|
||||
if (ilength != BX_PNIC_THIS s.rDataCursor)
|
||||
BX_PANIC(("PNIC command issued with incomplete data (should be %u, is %u)",
|
||||
ilength, BX_PNIC_THIS s.rDataCursor));
|
||||
|
||||
switch (command) {
|
||||
case PNIC_CMD_NOOP:
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_API_VER:
|
||||
Bit16u api_version;
|
||||
|
||||
api_version = PNIC_API_VERSION;
|
||||
olength = sizeof(api_version);
|
||||
memcpy (data, &api_version, sizeof(api_version));
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_READ_MAC:
|
||||
olength = sizeof (BX_PNIC_THIS s.macaddr);
|
||||
memcpy (data, BX_PNIC_THIS s.macaddr, olength);
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_RESET:
|
||||
/* Flush the receive queue */
|
||||
BX_PNIC_THIS s.recvQueueLength = 0;
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_XMIT:
|
||||
BX_PNIC_THIS ethdev->sendpkt(data, ilength);
|
||||
if (BX_PNIC_THIS s.irqEnabled) {
|
||||
set_irq_level(1);
|
||||
}
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_RECV:
|
||||
if (BX_PNIC_THIS s.recvQueueLength > 0) {
|
||||
int idx = (BX_PNIC_THIS s.recvIndex - BX_PNIC_THIS s.recvQueueLength
|
||||
+ PNIC_RECV_RINGS) % PNIC_RECV_RINGS;
|
||||
olength = BX_PNIC_THIS s.recvRingLength[idx];
|
||||
memcpy (data, BX_PNIC_THIS s.recvRing[idx], olength);
|
||||
BX_PNIC_THIS s.recvQueueLength--;
|
||||
}
|
||||
if (! BX_PNIC_THIS s.recvQueueLength) {
|
||||
set_irq_level(0);
|
||||
}
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_RECV_QLEN:
|
||||
Bit16u qlen;
|
||||
|
||||
qlen = BX_PNIC_THIS s.recvQueueLength;
|
||||
olength = sizeof(qlen);
|
||||
memcpy (data, &qlen, sizeof(qlen));
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_MASK_IRQ:
|
||||
Bit8u enabled;
|
||||
|
||||
enabled = *((Bit8u*)data);
|
||||
BX_PNIC_THIS s.irqEnabled = enabled;
|
||||
if (enabled && BX_PNIC_THIS s.recvQueueLength) {
|
||||
set_irq_level(1);
|
||||
} else {
|
||||
set_irq_level(0);
|
||||
}
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
case PNIC_CMD_FORCE_IRQ:
|
||||
set_irq_level(1);
|
||||
status = PNIC_STATUS_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("Unknown PNIC command %x (data length %u)", command, ilength));
|
||||
status = PNIC_STATUS_UNKNOWN_CMD;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set registers
|
||||
BX_PNIC_THIS s.rStatus = status;
|
||||
BX_PNIC_THIS s.rLength = olength;
|
||||
BX_PNIC_THIS s.rDataCursor = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback from the eth system driver when a frame has arrived
|
||||
*/
|
||||
void bx_pcipnic_c::rx_handler(void *arg, const void *buf, unsigned len)
|
||||
{
|
||||
// BX_DEBUG(("rx_handler with length %d", len));
|
||||
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) arg;
|
||||
class_ptr->rx_frame(buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* rx_frame() - called by the platform-specific code when an
|
||||
* ethernet frame has been received. The destination address
|
||||
* is tested to see if it should be accepted, and if the
|
||||
* rx ring has enough room, it is copied into it and
|
||||
* the receive process is updated
|
||||
*/
|
||||
void bx_pcipnic_c::rx_frame(const void *buf, unsigned io_len)
|
||||
{
|
||||
// Check packet length
|
||||
if (io_len > PNIC_DATA_SIZE) {
|
||||
BX_PANIC(("PNIC receive: data size %u exceeded buffer size %u",
|
||||
io_len, PNIC_DATA_SIZE));
|
||||
// Truncate if user continues
|
||||
io_len = PNIC_DATA_SIZE;
|
||||
}
|
||||
// Check receive ring is not full
|
||||
if (BX_PNIC_THIS s.recvQueueLength == PNIC_RECV_RINGS) {
|
||||
BX_ERROR(("PNIC receive: receive ring full, discarding packet"));
|
||||
return;
|
||||
}
|
||||
// Copy data to receive ring and record length
|
||||
memcpy (BX_PNIC_THIS s.recvRing[BX_PNIC_THIS s.recvIndex], buf, io_len);
|
||||
BX_PNIC_THIS s.recvRingLength[BX_PNIC_THIS s.recvIndex] = io_len;
|
||||
// Move to next ring entry
|
||||
BX_PNIC_THIS s.recvIndex = (BX_PNIC_THIS s.recvIndex + 1) % PNIC_RECV_RINGS;
|
||||
BX_PNIC_THIS s.recvQueueLength++;
|
||||
|
||||
// Generate interrupt if enabled
|
||||
if (BX_PNIC_THIS s.irqEnabled) {
|
||||
set_irq_level(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIPNIC
|
||||
96
bochs/iodev/pcipnic.h
Normal file
96
bochs/iodev/pcipnic.h
Normal file
@ -0,0 +1,96 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2003 Fen Systems Ltd.
|
||||
// http://www.fensystems.co.uk/
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PCIPNIC_H
|
||||
#define BX_IODEV_PCIPNIC_H
|
||||
|
||||
#include "pnic_api.h"
|
||||
|
||||
#if BX_USE_PCIPNIC_SMF
|
||||
# define BX_PNIC_SMF static
|
||||
# define BX_PNIC_THIS thePNICDevice->
|
||||
# define BX_PNIC_THIS_PTR thePNICDevice
|
||||
#else
|
||||
# define BX_PNIC_SMF
|
||||
# define BX_PNIC_THIS this->
|
||||
# define BX_PNIC_THIS_PTR this
|
||||
#endif
|
||||
|
||||
#define PNIC_DATA_SIZE 4096
|
||||
#define PNIC_RECV_RINGS 4
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bit32u base_ioaddr;
|
||||
Bit8u macaddr[6];
|
||||
Bit8u irqEnabled;
|
||||
|
||||
Bit16u rCmd; // Command register
|
||||
Bit16u rStatus; // Status register
|
||||
Bit16u rLength; // Length register
|
||||
Bit8u rData[PNIC_DATA_SIZE]; // Data register array
|
||||
Bit16u rDataCursor;
|
||||
|
||||
int recvIndex;
|
||||
int recvQueueLength;
|
||||
Bit8u recvRing[PNIC_RECV_RINGS][PNIC_DATA_SIZE]; // Receive buffer
|
||||
Bit16u recvRingLength[PNIC_RECV_RINGS];
|
||||
|
||||
Bit8u devfunc;
|
||||
Bit8u pci_conf[256];
|
||||
|
||||
} bx_pnic_t;
|
||||
|
||||
|
||||
class bx_pcipnic_c : public bx_ne2k_stub_c, bx_pci_device_stub_c {
|
||||
public:
|
||||
bx_pcipnic_c();
|
||||
virtual ~bx_pcipnic_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
private:
|
||||
bx_pnic_t s;
|
||||
|
||||
static void set_irq_level(bx_bool level);
|
||||
|
||||
static void pnic_timer_handler(void *);
|
||||
void pnic_timer(void);
|
||||
|
||||
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_PCIPNIC_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
|
||||
eth_pktmover_c *ethdev;
|
||||
static void exec_command(void);
|
||||
static void rx_handler(void *arg, const void *buf, unsigned len);
|
||||
BX_PNIC_SMF void rx_frame(const void *buf, unsigned io_len);
|
||||
};
|
||||
|
||||
#endif
|
||||
195
bochs/iodev/pcivga.cc
Normal file
195
bochs/iodev/pcivga.cc
Normal file
@ -0,0 +1,195 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002,2003 Mike Nordell
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
//
|
||||
// Experimental PCI VGA adapter
|
||||
//
|
||||
|
||||
// Note: This "driver" was created for the SOLE PURPOSE of getting BeOS
|
||||
// to boot. It currently does NOTHING more than presenting a generic VGA
|
||||
// device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
|
||||
// Furthermore, almost all of the PCI registers are currently acting like RAM.
|
||||
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIVGA
|
||||
|
||||
#include "pci.h"
|
||||
#include "pcivga.h"
|
||||
|
||||
#define LOG_THIS thePciVgaAdapter->
|
||||
|
||||
bx_pcivga_c* thePciVgaAdapter = 0;
|
||||
|
||||
int libpcivga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePciVgaAdapter = new bx_pcivga_c();
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciVgaAdapter, BX_PLUGIN_PCIVGA);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
void libpcivga_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePciVgaAdapter;
|
||||
}
|
||||
|
||||
bx_pcivga_c::bx_pcivga_c()
|
||||
{
|
||||
put("PCIVGA");
|
||||
}
|
||||
|
||||
bx_pcivga_c::~bx_pcivga_c()
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_pcivga_c::init(void)
|
||||
{
|
||||
// called once when bochs initializes
|
||||
|
||||
Bit8u devfunc = 0x00;
|
||||
unsigned i;
|
||||
|
||||
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCIVGA,
|
||||
"Experimental PCI VGA");
|
||||
|
||||
for (i=0; i<256; i++) {
|
||||
BX_PCIVGA_THIS s.pci_conf[i] = 0x0;
|
||||
}
|
||||
|
||||
// readonly registers
|
||||
static const struct init_vals_t {
|
||||
unsigned addr;
|
||||
unsigned char val;
|
||||
} init_vals[] = {
|
||||
// Note that the values for vendor and device id are selected at random!
|
||||
// There might actually be "real" values for "experimental" vendor and
|
||||
// device that should be used!
|
||||
{ 0x00, 0x34 }, { 0x01, 0x12 }, // 0x1234 - experimental vendor
|
||||
{ 0x02, 0x11 }, { 0x03, 0x11 }, // 0x1111 - experimental device
|
||||
{ 0x0a, 0x00 }, // class_sub VGA controller
|
||||
{ 0x0b, 0x03 }, // class_base display
|
||||
{ 0x0e, 0x00 } // header_type_generic
|
||||
};
|
||||
for (i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
|
||||
BX_PCIVGA_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
|
||||
}
|
||||
WriteHostDWordToLittleEndian(&BX_PCIVGA_THIS s.pci_conf[0x10], 0x08);
|
||||
BX_PCIVGA_THIS s.base_address = 0;
|
||||
}
|
||||
|
||||
void bx_pcivga_c::reset(unsigned type)
|
||||
{
|
||||
static const struct reset_vals_t {
|
||||
unsigned addr;
|
||||
unsigned char val;
|
||||
} reset_vals[] = {
|
||||
{ 0x04, 0x03 }, { 0x05, 0x00 }, // command_io + command_mem
|
||||
{ 0x06, 0x00 }, { 0x07, 0x02 } // status_devsel_medium
|
||||
};
|
||||
for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
|
||||
BX_PCIVGA_THIS s.pci_conf[reset_vals[i].addr] = reset_vals[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pcivga_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pcivga", "PCI VGA Adapter State", 1);
|
||||
register_pci_state(list, BX_PCIVGA_THIS s.pci_conf);
|
||||
}
|
||||
|
||||
void bx_pcivga_c::after_restore_state(void)
|
||||
{
|
||||
if (DEV_vbe_set_base_addr(&BX_PCIVGA_THIS s.base_address,
|
||||
&BX_PCIVGA_THIS s.pci_conf[0x10])) {
|
||||
BX_INFO(("new base address: 0x%08x", BX_PCIVGA_THIS s.base_address));
|
||||
}
|
||||
}
|
||||
|
||||
// pci configuration space read callback handler
|
||||
Bit32u bx_pcivga_c::pci_read_handler(Bit8u address, unsigned io_len)
|
||||
{
|
||||
Bit32u value = 0;
|
||||
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value |= (BX_PCIVGA_THIS s.pci_conf[address+i] << (i*8));
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// static pci configuration space write callback handler
|
||||
void bx_pcivga_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned write_addr;
|
||||
Bit8u new_value, old_value;
|
||||
bx_bool baseaddr_change = 0;
|
||||
|
||||
if ((address >= 0x14) && (address < 0x34))
|
||||
return;
|
||||
|
||||
for (i = 0; i < io_len; i++) {
|
||||
write_addr = address + i;
|
||||
old_value = BX_PCIVGA_THIS s.pci_conf[write_addr];
|
||||
new_value = (Bit8u)(value & 0xff);
|
||||
switch (write_addr) {
|
||||
case 0x04: // disallowing write to command
|
||||
case 0x06: // disallowing write to status lo-byte (is that expected?)
|
||||
break;
|
||||
case 0x10: // base address #0
|
||||
new_value = (new_value & 0xf0) | (old_value & 0x0f);
|
||||
case 0x11: case 0x12: case 0x13:
|
||||
baseaddr_change |= (old_value != new_value);
|
||||
default:
|
||||
BX_PCIVGA_THIS s.pci_conf[write_addr] = new_value;
|
||||
}
|
||||
value >>= 8;
|
||||
}
|
||||
if (baseaddr_change) {
|
||||
if (DEV_vbe_set_base_addr(&BX_PCIVGA_THIS s.base_address,
|
||||
&BX_PCIVGA_THIS s.pci_conf[0x10])) {
|
||||
BX_INFO(("new base address: 0x%08x", BX_PCIVGA_THIS s.base_address));
|
||||
}
|
||||
}
|
||||
|
||||
if (io_len == 1)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
|
||||
else if (io_len == 2)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
|
||||
else if (io_len == 4)
|
||||
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIVGA
|
||||
49
bochs/iodev/pcivga.h
Normal file
49
bochs/iodev/pcivga.h
Normal file
@ -0,0 +1,49 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002,2003 Mike Nordell
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PCIVGA_H
|
||||
#define BX_IODEV_PCIVGA_H
|
||||
|
||||
#if BX_USE_PCIVGA_SMF
|
||||
# define BX_PCIVGA_THIS thePciVgaAdapter->
|
||||
#else
|
||||
# define BX_PCIVGA_THIS this->
|
||||
#endif
|
||||
|
||||
class bx_pcivga_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
bx_pcivga_c();
|
||||
virtual ~bx_pcivga_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
||||
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
||||
|
||||
private:
|
||||
struct {
|
||||
Bit32u base_address;
|
||||
Bit8u pci_conf[256];
|
||||
} s;
|
||||
};
|
||||
|
||||
#endif
|
||||
889
bochs/iodev/pic.cc
Normal file
889
bochs/iodev/pic.cc
Normal file
@ -0,0 +1,889 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "pic.h"
|
||||
|
||||
#define LOG_THIS thePic->
|
||||
|
||||
bx_pic_c *thePic = NULL;
|
||||
|
||||
int libpic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePic = new bx_pic_c();
|
||||
bx_devices.pluginPicDevice = thePic;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePic, BX_PLUGIN_PIC);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libpic_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePic;
|
||||
}
|
||||
|
||||
bx_pic_c::bx_pic_c(void)
|
||||
{
|
||||
put("PIC");
|
||||
}
|
||||
|
||||
bx_pic_c::~bx_pic_c(void)
|
||||
{
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_pic_c::init(void)
|
||||
{
|
||||
/* 8259 PIC (Programmable Interrupt Controller) */
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0020, "8259 PIC", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0021, "8259 PIC", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x00A0, "8259 PIC", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x00A1, "8259 PIC", 1);
|
||||
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0020, "8259 PIC", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0021, "8259 PIC", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x00A0, "8259 PIC", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x00A1, "8259 PIC", 1);
|
||||
|
||||
|
||||
BX_PIC_THIS s.master_pic.single_PIC = 0;
|
||||
BX_PIC_THIS s.master_pic.interrupt_offset = 0x08; /* IRQ0 = INT 0x08 */
|
||||
/* slave PIC connected to IRQ2 of master */
|
||||
BX_PIC_THIS s.master_pic.u.slave_connect_mask = 0x04;
|
||||
BX_PIC_THIS s.master_pic.sfnm = 0; /* normal nested mode */
|
||||
BX_PIC_THIS s.master_pic.buffered_mode = 0; /* unbuffered mode */
|
||||
BX_PIC_THIS s.master_pic.master_slave = 1; /* master PIC */
|
||||
BX_PIC_THIS s.master_pic.auto_eoi = 0; /* manual EOI from CPU */
|
||||
BX_PIC_THIS s.master_pic.imr = 0xFF; /* all IRQ's initially masked */
|
||||
BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
|
||||
BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
|
||||
BX_PIC_THIS s.master_pic.read_reg_select = 0; /* IRR */
|
||||
BX_PIC_THIS s.master_pic.irq = 0;
|
||||
BX_PIC_THIS s.master_pic.INT = 0;
|
||||
BX_PIC_THIS s.master_pic.init.in_init = 0;
|
||||
BX_PIC_THIS s.master_pic.init.requires_4 = 0;
|
||||
BX_PIC_THIS s.master_pic.init.byte_expected = 0;
|
||||
BX_PIC_THIS s.master_pic.special_mask = 0;
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = 7;
|
||||
BX_PIC_THIS s.master_pic.polled = 0;
|
||||
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
|
||||
BX_PIC_THIS s.master_pic.edge_level = 0;
|
||||
BX_PIC_THIS s.master_pic.IRQ_in = 0;
|
||||
|
||||
BX_PIC_THIS s.slave_pic.single_PIC = 0;
|
||||
BX_PIC_THIS s.slave_pic.interrupt_offset = 0x70; /* IRQ8 = INT 0x70 */
|
||||
BX_PIC_THIS s.slave_pic.u.slave_id = 0x02; /* slave PIC connected to IRQ2 of master */
|
||||
BX_PIC_THIS s.slave_pic.sfnm = 0; /* normal nested mode */
|
||||
BX_PIC_THIS s.slave_pic.buffered_mode = 0; /* unbuffered mode */
|
||||
BX_PIC_THIS s.slave_pic.master_slave = 0; /* slave PIC */
|
||||
BX_PIC_THIS s.slave_pic.auto_eoi = 0; /* manual EOI from CPU */
|
||||
BX_PIC_THIS s.slave_pic.imr = 0xFF; /* all IRQ's initially masked */
|
||||
BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
|
||||
BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
|
||||
BX_PIC_THIS s.slave_pic.read_reg_select = 0; /* IRR */
|
||||
BX_PIC_THIS s.slave_pic.irq = 0;
|
||||
BX_PIC_THIS s.slave_pic.INT = 0;
|
||||
BX_PIC_THIS s.slave_pic.init.in_init = 0;
|
||||
BX_PIC_THIS s.slave_pic.init.requires_4 = 0;
|
||||
BX_PIC_THIS s.slave_pic.init.byte_expected = 0;
|
||||
BX_PIC_THIS s.slave_pic.special_mask = 0;
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = 7;
|
||||
BX_PIC_THIS s.slave_pic.polled = 0;
|
||||
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
|
||||
BX_PIC_THIS s.slave_pic.edge_level = 0;
|
||||
BX_PIC_THIS s.slave_pic.IRQ_in = 0;
|
||||
}
|
||||
|
||||
void bx_pic_c::reset(unsigned type) {}
|
||||
|
||||
void bx_pic_c::register_state(void)
|
||||
{
|
||||
bx_list_c *ctrl;
|
||||
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pic", "PIC State", 2);
|
||||
ctrl = new bx_list_c(list, "master", 17);
|
||||
new bx_shadow_num_c(ctrl, "interrupt_offset", &BX_PIC_THIS s.master_pic.interrupt_offset, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "auto_eoi", &BX_PIC_THIS s.master_pic.auto_eoi, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "imr", &BX_PIC_THIS s.master_pic.imr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "isr", &BX_PIC_THIS s.master_pic.isr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "irr", &BX_PIC_THIS s.master_pic.irr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "read_reg_select", &BX_PIC_THIS s.master_pic.read_reg_select);
|
||||
new bx_shadow_num_c(ctrl, "irq", &BX_PIC_THIS s.master_pic.irq, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "lowest_priority", &BX_PIC_THIS s.master_pic.lowest_priority, BASE_HEX);
|
||||
new bx_shadow_bool_c(ctrl, "INT", &BX_PIC_THIS s.master_pic.INT);
|
||||
new bx_shadow_num_c(ctrl, "IRQ_in", &BX_PIC_THIS s.master_pic.IRQ_in, BASE_HEX);
|
||||
new bx_shadow_bool_c(ctrl, "in_init", &BX_PIC_THIS s.master_pic.init.in_init);
|
||||
new bx_shadow_bool_c(ctrl, "requires_4", &BX_PIC_THIS s.master_pic.init.requires_4);
|
||||
new bx_shadow_num_c(ctrl, "byte_expected", &BX_PIC_THIS s.master_pic.init.byte_expected);
|
||||
new bx_shadow_bool_c(ctrl, "special_mask", &BX_PIC_THIS s.master_pic.special_mask);
|
||||
new bx_shadow_bool_c(ctrl, "polled", &BX_PIC_THIS s.master_pic.polled);
|
||||
new bx_shadow_bool_c(ctrl, "rotate_on_autoeoi", &BX_PIC_THIS s.master_pic.rotate_on_autoeoi);
|
||||
new bx_shadow_num_c(ctrl, "edge_level", &BX_PIC_THIS s.master_pic.edge_level, BASE_HEX);
|
||||
ctrl = new bx_list_c(list, "slave", 17);
|
||||
new bx_shadow_num_c(ctrl, "interrupt_offset", &BX_PIC_THIS s.slave_pic.interrupt_offset, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "auto_eoi", &BX_PIC_THIS s.slave_pic.auto_eoi, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "imr", &BX_PIC_THIS s.slave_pic.imr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "isr", &BX_PIC_THIS s.slave_pic.isr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "irr", &BX_PIC_THIS s.slave_pic.irr, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "read_reg_select", &BX_PIC_THIS s.slave_pic.read_reg_select);
|
||||
new bx_shadow_num_c(ctrl, "irq", &BX_PIC_THIS s.slave_pic.irq, BASE_HEX);
|
||||
new bx_shadow_num_c(ctrl, "lowest_priority", &BX_PIC_THIS s.slave_pic.lowest_priority, BASE_HEX);
|
||||
new bx_shadow_bool_c(ctrl, "INT", &BX_PIC_THIS s.slave_pic.INT);
|
||||
new bx_shadow_num_c(ctrl, "IRQ_in", &BX_PIC_THIS s.slave_pic.IRQ_in, BASE_HEX);
|
||||
new bx_shadow_bool_c(ctrl, "in_init", &BX_PIC_THIS s.slave_pic.init.in_init);
|
||||
new bx_shadow_bool_c(ctrl, "requires_4", &BX_PIC_THIS s.slave_pic.init.requires_4);
|
||||
new bx_shadow_num_c(ctrl, "byte_expected", &BX_PIC_THIS s.slave_pic.init.byte_expected);
|
||||
new bx_shadow_bool_c(ctrl, "special_mask", &BX_PIC_THIS s.slave_pic.special_mask);
|
||||
new bx_shadow_bool_c(ctrl, "polled", &BX_PIC_THIS s.slave_pic.polled);
|
||||
new bx_shadow_bool_c(ctrl, "rotate_on_autoeoi", &BX_PIC_THIS s.slave_pic.rotate_on_autoeoi);
|
||||
new bx_shadow_num_c(ctrl, "edge_level", &BX_PIC_THIS s.slave_pic.edge_level, BASE_HEX);
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
Bit32u bx_pic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIC_SMF
|
||||
bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pic_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIC_SMF
|
||||
|
||||
BX_DEBUG(("IO read from %04x", (unsigned) address));
|
||||
|
||||
/*
|
||||
8259A PIC
|
||||
*/
|
||||
|
||||
if((address == 0x20 || address == 0x21) && BX_PIC_THIS s.master_pic.polled) {
|
||||
// In polled mode. Treat this as an interrupt acknowledge
|
||||
clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
|
||||
BX_PIC_THIS s.master_pic.polled = 0;
|
||||
service_master_pic();
|
||||
return io_len==1?BX_PIC_THIS s.master_pic.irq:(BX_PIC_THIS s.master_pic.irq)<<8|(BX_PIC_THIS s.master_pic.irq); // Return the current irq requested
|
||||
}
|
||||
|
||||
if((address == 0xa0 || address == 0xa1) && BX_PIC_THIS s.slave_pic.polled) {
|
||||
// In polled mode. Treat this as an interrupt acknowledge
|
||||
clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
|
||||
BX_PIC_THIS s.slave_pic.polled = 0;
|
||||
service_slave_pic();
|
||||
return io_len==1?BX_PIC_THIS s.slave_pic.irq:(BX_PIC_THIS s.slave_pic.irq)<<8|(BX_PIC_THIS s.slave_pic.irq); // Return the current irq requested
|
||||
}
|
||||
|
||||
switch (address) {
|
||||
case 0x20:
|
||||
if (BX_PIC_THIS s.master_pic.read_reg_select) { /* ISR */
|
||||
BX_DEBUG(("read master ISR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.master_pic.isr));
|
||||
return(BX_PIC_THIS s.master_pic.isr);
|
||||
}
|
||||
else { /* IRR */
|
||||
BX_DEBUG(("read master IRR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.master_pic.irr));
|
||||
return(BX_PIC_THIS s.master_pic.irr);
|
||||
}
|
||||
break;
|
||||
case 0x21:
|
||||
BX_DEBUG(("read master IMR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.master_pic.imr));
|
||||
return(BX_PIC_THIS s.master_pic.imr);
|
||||
case 0xA0:
|
||||
if (BX_PIC_THIS s.slave_pic.read_reg_select) { /* ISR */
|
||||
BX_DEBUG(("read slave ISR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.slave_pic.isr));
|
||||
return(BX_PIC_THIS s.slave_pic.isr);
|
||||
}
|
||||
else { /* IRR */
|
||||
BX_DEBUG(("read slave IRR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.slave_pic.irr));
|
||||
return(BX_PIC_THIS s.slave_pic.irr);
|
||||
}
|
||||
break;
|
||||
case 0xA1:
|
||||
BX_DEBUG(("read slave IMR = %02x",
|
||||
(unsigned) BX_PIC_THIS s.slave_pic.imr));
|
||||
return(BX_PIC_THIS s.slave_pic.imr);
|
||||
}
|
||||
|
||||
BX_PANIC(("io read to address %04x", (unsigned) address));
|
||||
return(0); /* default if not found above */
|
||||
}
|
||||
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_pic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIC_SMF
|
||||
bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
|
||||
class_ptr->write(address, value, io_len);
|
||||
}
|
||||
|
||||
void bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIC_SMF
|
||||
|
||||
BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value));
|
||||
|
||||
/*
|
||||
8259A PIC
|
||||
*/
|
||||
|
||||
switch (address) {
|
||||
case 0x20:
|
||||
if (value & 0x10) { /* initialization command 1 */
|
||||
BX_DEBUG(("master: init command 1 found"));
|
||||
BX_DEBUG((" requires 4 = %u", (unsigned) (value & 0x01)));
|
||||
BX_DEBUG((" cascade mode: [0=cascade,1=single] %u",
|
||||
(unsigned) ((value & 0x02) >> 1)));
|
||||
BX_PIC_THIS s.master_pic.init.in_init = 1;
|
||||
BX_PIC_THIS s.master_pic.init.requires_4 = (value & 0x01);
|
||||
BX_PIC_THIS s.master_pic.init.byte_expected = 2; /* operation command 2 */
|
||||
BX_PIC_THIS s.master_pic.imr = 0x00; /* clear the irq mask register */
|
||||
BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
|
||||
BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = 7;
|
||||
BX_PIC_THIS s.master_pic.INT = 0; /* reprogramming clears previous INTR request */
|
||||
BX_PIC_THIS s.master_pic.auto_eoi = 0;
|
||||
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
|
||||
if (value & 0x02)
|
||||
BX_PANIC(("master: ICW1: single mode not supported"));
|
||||
if (value & 0x08) {
|
||||
BX_PANIC(("master: ICW1: level sensitive mode not supported"));
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("master: ICW1: edge triggered mode selected"));
|
||||
}
|
||||
BX_SET_INTR(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((value & 0x18) == 0x08) { /* OCW3 */
|
||||
Bit8u special_mask, poll, read_op;
|
||||
|
||||
special_mask = (value & 0x60) >> 5;
|
||||
poll = (value & 0x04) >> 2;
|
||||
read_op = (value & 0x03);
|
||||
if (poll) {
|
||||
BX_PIC_THIS s.master_pic.polled = 1;
|
||||
return;
|
||||
}
|
||||
if (read_op == 0x02) /* read IRR */
|
||||
BX_PIC_THIS s.master_pic.read_reg_select = 0;
|
||||
else if (read_op == 0x03) /* read ISR */
|
||||
BX_PIC_THIS s.master_pic.read_reg_select = 1;
|
||||
if (special_mask == 0x02) { /* cancel special mask */
|
||||
BX_PIC_THIS s.master_pic.special_mask = 0;
|
||||
}
|
||||
else if (special_mask == 0x03) { /* set specific mask */
|
||||
BX_PIC_THIS s.master_pic.special_mask = 1;
|
||||
service_master_pic();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* OCW2 */
|
||||
switch (value) {
|
||||
case 0x00: // Rotate in auto eoi mode clear
|
||||
case 0x80: // Rotate in auto eoi mode set
|
||||
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = (value != 0);
|
||||
break;
|
||||
case 0x0A: /* select read interrupt request register */
|
||||
BX_PIC_THIS s.master_pic.read_reg_select = 0;
|
||||
break;
|
||||
case 0x0B: /* select read interrupt in-service register */
|
||||
BX_PIC_THIS s.master_pic.read_reg_select = 1;
|
||||
break;
|
||||
|
||||
case 0xA0: // Rotate on non-specific end of interrupt
|
||||
case 0x20: /* end of interrupt command */
|
||||
clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
|
||||
|
||||
if(value == 0xA0) {// Rotate in Auto-EOI mode
|
||||
BX_PIC_THIS s.master_pic.lowest_priority ++;
|
||||
if(BX_PIC_THIS s.master_pic.lowest_priority > 7)
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = 0;
|
||||
}
|
||||
|
||||
service_master_pic();
|
||||
break;
|
||||
|
||||
case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
|
||||
BX_INFO(("IRQ no-op"));
|
||||
break;
|
||||
|
||||
case 0x60: /* specific EOI 0 */
|
||||
case 0x61: /* specific EOI 1 */
|
||||
case 0x62: /* specific EOI 2 */
|
||||
case 0x63: /* specific EOI 3 */
|
||||
case 0x64: /* specific EOI 4 */
|
||||
case 0x65: /* specific EOI 5 */
|
||||
case 0x66: /* specific EOI 6 */
|
||||
case 0x67: /* specific EOI 7 */
|
||||
BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0x60));
|
||||
service_master_pic();
|
||||
break;
|
||||
|
||||
// IRQ lowest priority commands
|
||||
case 0xC0: // 0 7 6 5 4 3 2 1
|
||||
case 0xC1: // 1 0 7 6 5 4 3 2
|
||||
case 0xC2: // 2 1 0 7 6 5 4 3
|
||||
case 0xC3: // 3 2 1 0 7 6 5 4
|
||||
case 0xC4: // 4 3 2 1 0 7 6 5
|
||||
case 0xC5: // 5 4 3 2 1 0 7 6
|
||||
case 0xC6: // 6 5 4 3 2 1 0 7
|
||||
case 0xC7: // 7 6 5 4 3 2 1 0
|
||||
BX_INFO(("IRQ lowest command 0x%x", value));
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = value - 0xC0;
|
||||
break;
|
||||
|
||||
case 0xE0: // specific EOI and rotate 0
|
||||
case 0xE1: // specific EOI and rotate 1
|
||||
case 0xE2: // specific EOI and rotate 2
|
||||
case 0xE3: // specific EOI and rotate 3
|
||||
case 0xE4: // specific EOI and rotate 4
|
||||
case 0xE5: // specific EOI and rotate 5
|
||||
case 0xE6: // specific EOI and rotate 6
|
||||
case 0xE7: // specific EOI and rotate 7
|
||||
BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0xE0));
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = (value - 0xE0);
|
||||
service_master_pic();
|
||||
break;
|
||||
|
||||
case 0x02: // single mode bit: 1 = single, 0 = cascade
|
||||
// ignore. 386BSD writes this value but works with it ignored.
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("write to port 20h = %02x", value));
|
||||
} /* switch (value) */
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
/* initialization mode operation */
|
||||
if (BX_PIC_THIS s.master_pic.init.in_init) {
|
||||
switch (BX_PIC_THIS s.master_pic.init.byte_expected) {
|
||||
case 2:
|
||||
BX_PIC_THIS s.master_pic.interrupt_offset = value & 0xf8;
|
||||
BX_PIC_THIS s.master_pic.init.byte_expected = 3;
|
||||
BX_DEBUG(("master: init command 2 = %02x", (unsigned) value));
|
||||
BX_DEBUG((" offset = INT %02x",
|
||||
BX_PIC_THIS s.master_pic.interrupt_offset));
|
||||
return;
|
||||
break;
|
||||
case 3:
|
||||
BX_DEBUG(("master: init command 3 = %02x", (unsigned) value));
|
||||
if (BX_PIC_THIS s.master_pic.init.requires_4) {
|
||||
BX_PIC_THIS s.master_pic.init.byte_expected = 4;
|
||||
}
|
||||
else {
|
||||
BX_PIC_THIS s.master_pic.init.in_init = 0;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case 4:
|
||||
BX_DEBUG(("master: init command 4 = %02x", (unsigned) value));
|
||||
if (value & 0x02) {
|
||||
BX_DEBUG((" auto EOI"));
|
||||
BX_PIC_THIS s.master_pic.auto_eoi = 1;
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("normal EOI interrupt"));
|
||||
BX_PIC_THIS s.master_pic.auto_eoi = 0;
|
||||
}
|
||||
if (value & 0x01) {
|
||||
BX_DEBUG((" 80x86 mode"));
|
||||
} else
|
||||
BX_PANIC((" not 80x86 mode"));
|
||||
BX_PIC_THIS s.master_pic.init.in_init = 0;
|
||||
return;
|
||||
default:
|
||||
BX_PANIC(("master expecting bad init command"));
|
||||
}
|
||||
}
|
||||
|
||||
/* normal operation */
|
||||
BX_DEBUG(("setting master pic IMR to %02x", value));
|
||||
BX_PIC_THIS s.master_pic.imr = value;
|
||||
service_master_pic();
|
||||
return;
|
||||
|
||||
case 0xA0:
|
||||
if (value & 0x10) { /* initialization command 1 */
|
||||
BX_DEBUG(("slave: init command 1 found"));
|
||||
BX_DEBUG((" requires 4 = %u",
|
||||
(unsigned) (value & 0x01)));
|
||||
BX_DEBUG((" cascade mode: [0=cascade,1=single] %u",
|
||||
(unsigned) ((value & 0x02) >> 1)));
|
||||
BX_PIC_THIS s.slave_pic.init.in_init = 1;
|
||||
BX_PIC_THIS s.slave_pic.init.requires_4 = (value & 0x01);
|
||||
BX_PIC_THIS s.slave_pic.init.byte_expected = 2; /* operation command 2 */
|
||||
BX_PIC_THIS s.slave_pic.imr = 0x00; /* clear irq mask */
|
||||
BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
|
||||
BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = 7;
|
||||
BX_PIC_THIS s.slave_pic.INT = 0; /* reprogramming clears previous INTR request */
|
||||
BX_PIC_THIS s.master_pic.IRQ_in &= ~(1 << 2);
|
||||
BX_PIC_THIS s.slave_pic.auto_eoi = 0;
|
||||
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
|
||||
if (value & 0x02)
|
||||
BX_PANIC(("slave: ICW1: single mode not supported"));
|
||||
if (value & 0x08) {
|
||||
BX_PANIC(("slave: ICW1: level sensitive mode not supported"));
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("slave: ICW1: edge triggered mode selected"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((value & 0x18) == 0x08) { /* OCW3 */
|
||||
Bit8u special_mask, poll, read_op;
|
||||
|
||||
special_mask = (value & 0x60) >> 5;
|
||||
poll = (value & 0x04) >> 2;
|
||||
read_op = (value & 0x03);
|
||||
if (poll) {
|
||||
BX_PIC_THIS s.slave_pic.polled = 1;
|
||||
return;
|
||||
}
|
||||
if (read_op == 0x02) /* read IRR */
|
||||
BX_PIC_THIS s.slave_pic.read_reg_select = 0;
|
||||
else if (read_op == 0x03) /* read ISR */
|
||||
BX_PIC_THIS s.slave_pic.read_reg_select = 1;
|
||||
if (special_mask == 0x02) { /* cancel special mask */
|
||||
BX_PIC_THIS s.slave_pic.special_mask = 0;
|
||||
}
|
||||
else if (special_mask == 0x03) { /* set specific mask */
|
||||
BX_PIC_THIS s.slave_pic.special_mask = 1;
|
||||
service_slave_pic();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 0x00: // Rotate in auto eoi mode clear
|
||||
case 0x80: // Rotate in auto eoi mode set
|
||||
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = (value != 0);
|
||||
break;
|
||||
|
||||
case 0x0A: /* select read interrupt request register */
|
||||
BX_PIC_THIS s.slave_pic.read_reg_select = 0;
|
||||
break;
|
||||
case 0x0B: /* select read interrupt in-service register */
|
||||
BX_PIC_THIS s.slave_pic.read_reg_select = 1;
|
||||
break;
|
||||
|
||||
case 0xA0: // Rotate on non-specific end of interrupt
|
||||
case 0x20: /* end of interrupt command */
|
||||
clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
|
||||
|
||||
if(value == 0xA0) {// Rotate in Auto-EOI mode
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority ++;
|
||||
if(BX_PIC_THIS s.slave_pic.lowest_priority > 7)
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = 0;
|
||||
}
|
||||
|
||||
service_slave_pic();
|
||||
break;
|
||||
|
||||
case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
|
||||
BX_INFO(("IRQ no-op"));
|
||||
break;
|
||||
|
||||
case 0x60: /* specific EOI 0 */
|
||||
case 0x61: /* specific EOI 1 */
|
||||
case 0x62: /* specific EOI 2 */
|
||||
case 0x63: /* specific EOI 3 */
|
||||
case 0x64: /* specific EOI 4 */
|
||||
case 0x65: /* specific EOI 5 */
|
||||
case 0x66: /* specific EOI 6 */
|
||||
case 0x67: /* specific EOI 7 */
|
||||
BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0x60));
|
||||
service_slave_pic();
|
||||
break;
|
||||
|
||||
// IRQ lowest priority commands
|
||||
case 0xC0: // 0 7 6 5 4 3 2 1
|
||||
case 0xC1: // 1 0 7 6 5 4 3 2
|
||||
case 0xC2: // 2 1 0 7 6 5 4 3
|
||||
case 0xC3: // 3 2 1 0 7 6 5 4
|
||||
case 0xC4: // 4 3 2 1 0 7 6 5
|
||||
case 0xC5: // 5 4 3 2 1 0 7 6
|
||||
case 0xC6: // 6 5 4 3 2 1 0 7
|
||||
case 0xC7: // 7 6 5 4 3 2 1 0
|
||||
BX_INFO(("IRQ lowest command 0x%x", value));
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = value - 0xC0;
|
||||
break;
|
||||
|
||||
case 0xE0: // specific EOI and rotate 0
|
||||
case 0xE1: // specific EOI and rotate 1
|
||||
case 0xE2: // specific EOI and rotate 2
|
||||
case 0xE3: // specific EOI and rotate 3
|
||||
case 0xE4: // specific EOI and rotate 4
|
||||
case 0xE5: // specific EOI and rotate 5
|
||||
case 0xE6: // specific EOI and rotate 6
|
||||
case 0xE7: // specific EOI and rotate 7
|
||||
BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0xE0));
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = (value - 0xE0);
|
||||
service_slave_pic();
|
||||
break;
|
||||
|
||||
case 0x02: // single mode bit: 1 = single, 0 = cascade
|
||||
// ignore. 386BSD writes this value but works with it ignored.
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("write to port A0h = %02x", value));
|
||||
} /* switch (value) */
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
/* initialization mode operation */
|
||||
if (BX_PIC_THIS s.slave_pic.init.in_init) {
|
||||
switch (BX_PIC_THIS s.slave_pic.init.byte_expected) {
|
||||
case 2:
|
||||
BX_PIC_THIS s.slave_pic.interrupt_offset = value & 0xf8;
|
||||
BX_PIC_THIS s.slave_pic.init.byte_expected = 3;
|
||||
BX_DEBUG(("slave: init command 2 = %02x", (unsigned) value));
|
||||
BX_DEBUG((" offset = INT %02x",
|
||||
BX_PIC_THIS s.slave_pic.interrupt_offset));
|
||||
return;
|
||||
case 3:
|
||||
BX_DEBUG(("slave: init command 3 = %02x", (unsigned) value));
|
||||
if (BX_PIC_THIS s.slave_pic.init.requires_4) {
|
||||
BX_PIC_THIS s.slave_pic.init.byte_expected = 4;
|
||||
} else {
|
||||
BX_PIC_THIS s.slave_pic.init.in_init = 0;
|
||||
}
|
||||
return;
|
||||
case 4:
|
||||
BX_DEBUG(("slave: init command 4 = %02x", (unsigned) value));
|
||||
if (value & 0x02) {
|
||||
BX_DEBUG((" auto EOI"));
|
||||
BX_PIC_THIS s.slave_pic.auto_eoi = 1;
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("normal EOI interrupt"));
|
||||
BX_PIC_THIS s.slave_pic.auto_eoi = 0;
|
||||
}
|
||||
if (value & 0x01) {
|
||||
BX_DEBUG((" 80x86 mode"));
|
||||
} else
|
||||
BX_PANIC((" not 80x86 mode"));
|
||||
BX_PIC_THIS s.slave_pic.init.in_init = 0;
|
||||
return;
|
||||
default:
|
||||
BX_PANIC(("slave: expecting bad init command"));
|
||||
}
|
||||
}
|
||||
|
||||
/* normal operation */
|
||||
BX_DEBUG(("setting slave pic IMR to %02x", value));
|
||||
BX_PIC_THIS s.slave_pic.imr = value;
|
||||
service_slave_pic();
|
||||
return;
|
||||
} /* switch (address) */
|
||||
}
|
||||
|
||||
// new IRQ signal handling routines
|
||||
|
||||
void bx_pic_c::lower_irq(unsigned irq_no)
|
||||
{
|
||||
#if BX_SUPPORT_APIC
|
||||
// forward this function call to the ioapic too
|
||||
if (DEV_ioapic_present() && (irq_no != 2)) {
|
||||
DEV_ioapic_set_irq_level(irq_no, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
Bit8u mask = (1 << (irq_no & 7));
|
||||
if ((irq_no <= 7) && (BX_PIC_THIS s.master_pic.IRQ_in & mask)) {
|
||||
BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
|
||||
BX_PIC_THIS s.master_pic.IRQ_in &= ~(mask);
|
||||
BX_PIC_THIS s.master_pic.irr &= ~(mask);
|
||||
} else if ((irq_no > 7) && (irq_no <= 15) &&
|
||||
(BX_PIC_THIS s.slave_pic.IRQ_in & mask)) {
|
||||
BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
|
||||
BX_PIC_THIS s.slave_pic.IRQ_in &= ~(mask);
|
||||
BX_PIC_THIS s.slave_pic.irr &= ~(mask);
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pic_c::raise_irq(unsigned irq_no)
|
||||
{
|
||||
#if BX_SUPPORT_APIC
|
||||
// forward this function call to the ioapic too
|
||||
if (DEV_ioapic_present() && (irq_no != 2)) {
|
||||
DEV_ioapic_set_irq_level(irq_no, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
Bit8u mask = (1 << (irq_no & 7));
|
||||
if ((irq_no <= 7) && !(BX_PIC_THIS s.master_pic.IRQ_in & mask)) {
|
||||
BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
|
||||
BX_PIC_THIS s.master_pic.IRQ_in |= mask;
|
||||
BX_PIC_THIS s.master_pic.irr |= mask;
|
||||
service_master_pic();
|
||||
} else if ((irq_no > 7) && (irq_no <= 15) &&
|
||||
!(BX_PIC_THIS s.slave_pic.IRQ_in & mask)) {
|
||||
BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
|
||||
BX_PIC_THIS s.slave_pic.IRQ_in |= mask;
|
||||
BX_PIC_THIS s.slave_pic.irr |= mask;
|
||||
service_slave_pic();
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pic_c::set_mode(bx_bool ma_sl, Bit8u mode)
|
||||
{
|
||||
if (ma_sl) {
|
||||
BX_PIC_THIS s.master_pic.edge_level = mode;
|
||||
} else {
|
||||
BX_PIC_THIS s.slave_pic.edge_level = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_pic_c::clear_highest_interrupt(bx_pic_t *pic)
|
||||
{
|
||||
int irq;
|
||||
int lowest_priority;
|
||||
int highest_priority;
|
||||
|
||||
/* clear highest current in service bit */
|
||||
lowest_priority = pic->lowest_priority;
|
||||
highest_priority = lowest_priority + 1;
|
||||
if(highest_priority > 7)
|
||||
highest_priority = 0;
|
||||
|
||||
irq = highest_priority;
|
||||
do {
|
||||
if (pic->isr & (1 << irq)) {
|
||||
pic->isr &= ~(1 << irq);
|
||||
break; /* Return mask of bit cleared. */
|
||||
}
|
||||
|
||||
irq ++;
|
||||
if(irq > 7)
|
||||
irq = 0;
|
||||
} while(irq != highest_priority);
|
||||
}
|
||||
|
||||
void bx_pic_c::service_master_pic(void)
|
||||
{
|
||||
Bit8u unmasked_requests;
|
||||
int irq;
|
||||
Bit8u isr, max_irq;
|
||||
Bit8u highest_priority = BX_PIC_THIS s.master_pic.lowest_priority + 1;
|
||||
if(highest_priority > 7)
|
||||
highest_priority = 0;
|
||||
|
||||
if (BX_PIC_THIS s.master_pic.INT) { /* last interrupt still not acknowleged */
|
||||
return;
|
||||
}
|
||||
|
||||
if (BX_PIC_THIS s.master_pic.special_mask) {
|
||||
/* all priorities may be enabled. check all IRR bits except ones
|
||||
* which have corresponding ISR bits set
|
||||
*/
|
||||
max_irq = highest_priority;
|
||||
}
|
||||
else { /* normal mode */
|
||||
/* Find the highest priority IRQ that is enabled due to current ISR */
|
||||
isr = BX_PIC_THIS s.master_pic.isr;
|
||||
if (isr) {
|
||||
max_irq = highest_priority;
|
||||
while ((isr & (1 << max_irq)) == 0) {
|
||||
max_irq++;
|
||||
if(max_irq > 7)
|
||||
max_irq = 0;
|
||||
}
|
||||
if (max_irq == highest_priority) return; /* Highest priority interrupt in-service,
|
||||
* no other priorities allowed */
|
||||
if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
|
||||
}
|
||||
else
|
||||
max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
|
||||
}
|
||||
|
||||
/* now, see if there are any higher priority requests */
|
||||
if ((unmasked_requests = (BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr))) {
|
||||
irq = highest_priority;
|
||||
do {
|
||||
/* for special mode, since we're looking at all IRQ's, skip if
|
||||
* current IRQ is already in-service
|
||||
*/
|
||||
if (! (BX_PIC_THIS s.master_pic.special_mask && ((BX_PIC_THIS s.master_pic.isr >> irq) & 0x01))) {
|
||||
if (unmasked_requests & (1 << irq)) {
|
||||
BX_DEBUG(("signalling IRQ(%u)", (unsigned) irq));
|
||||
BX_PIC_THIS s.master_pic.INT = 1;
|
||||
BX_PIC_THIS s.master_pic.irq = irq;
|
||||
BX_SET_INTR(1);
|
||||
return;
|
||||
} /* if (unmasked_requests & ... */
|
||||
}
|
||||
|
||||
irq ++;
|
||||
if(irq > 7)
|
||||
irq = 0;
|
||||
} while(irq != max_irq); /* do ... */
|
||||
} /* if (unmasked_requests = ... */
|
||||
}
|
||||
|
||||
void bx_pic_c::service_slave_pic(void)
|
||||
{
|
||||
Bit8u unmasked_requests;
|
||||
int irq;
|
||||
Bit8u isr, max_irq;
|
||||
Bit8u highest_priority = BX_PIC_THIS s.slave_pic.lowest_priority + 1;
|
||||
if(highest_priority > 7)
|
||||
highest_priority = 0;
|
||||
|
||||
if (BX_PIC_THIS s.slave_pic.INT) { /* last interrupt still not acknowleged */
|
||||
return;
|
||||
}
|
||||
|
||||
if (BX_PIC_THIS s.slave_pic.special_mask) {
|
||||
/* all priorities may be enabled. check all IRR bits except ones
|
||||
* which have corresponding ISR bits set
|
||||
*/
|
||||
max_irq = highest_priority;
|
||||
}
|
||||
else { /* normal mode */
|
||||
/* Find the highest priority IRQ that is enabled due to current ISR */
|
||||
isr = BX_PIC_THIS s.slave_pic.isr;
|
||||
if (isr) {
|
||||
max_irq = highest_priority;
|
||||
while ((isr & (1 << max_irq)) == 0) {
|
||||
max_irq++;
|
||||
if(max_irq > 7)
|
||||
max_irq = 0;
|
||||
}
|
||||
if (max_irq == highest_priority) return; /* Highest priority interrupt in-service,
|
||||
* no other priorities allowed */
|
||||
if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
|
||||
}
|
||||
else
|
||||
max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
|
||||
}
|
||||
|
||||
/* now, see if there are any higher priority requests */
|
||||
if ((unmasked_requests = (BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr))) {
|
||||
irq = highest_priority;
|
||||
do {
|
||||
/* for special mode, since we're looking at all IRQ's, skip if
|
||||
* current IRQ is already in-service
|
||||
*/
|
||||
if (! (BX_PIC_THIS s.slave_pic.special_mask && ((BX_PIC_THIS s.slave_pic.isr >> irq) & 0x01))) {
|
||||
if (unmasked_requests & (1 << irq)) {
|
||||
BX_DEBUG(("slave: signalling IRQ(%u)", (unsigned) 8 + irq));
|
||||
|
||||
BX_PIC_THIS s.slave_pic.INT = 1;
|
||||
BX_PIC_THIS s.slave_pic.irq = irq;
|
||||
BX_PIC_THIS raise_irq(2); /* request IRQ 2 on master pic */
|
||||
return;
|
||||
} /* if (unmasked_requests & ... */
|
||||
}
|
||||
|
||||
irq ++;
|
||||
if(irq > 7)
|
||||
irq = 0;
|
||||
|
||||
} while(irq != max_irq); /* do ... */
|
||||
} /* if (unmasked_requests = ... */
|
||||
}
|
||||
|
||||
/* CPU handshakes with PIC after acknowledging interrupt */
|
||||
Bit8u bx_pic_c::IAC(void)
|
||||
{
|
||||
Bit8u vector;
|
||||
Bit8u irq;
|
||||
|
||||
BX_SET_INTR(0);
|
||||
BX_PIC_THIS s.master_pic.INT = 0;
|
||||
// Check for spurious interrupt
|
||||
if (BX_PIC_THIS s.master_pic.irr == 0) {
|
||||
return (BX_PIC_THIS s.master_pic.interrupt_offset + 7);
|
||||
}
|
||||
// In level sensitive mode don't clear the irr bit.
|
||||
if (!(BX_PIC_THIS s.master_pic.edge_level & (1 << BX_PIC_THIS s.master_pic.irq)))
|
||||
BX_PIC_THIS s.master_pic.irr &= ~(1 << BX_PIC_THIS s.master_pic.irq);
|
||||
// In autoeoi mode don't set the isr bit.
|
||||
if (!BX_PIC_THIS s.master_pic.auto_eoi)
|
||||
BX_PIC_THIS s.master_pic.isr |= (1 << BX_PIC_THIS s.master_pic.irq);
|
||||
else if (BX_PIC_THIS s.master_pic.rotate_on_autoeoi)
|
||||
BX_PIC_THIS s.master_pic.lowest_priority = BX_PIC_THIS s.master_pic.irq;
|
||||
|
||||
if (BX_PIC_THIS s.master_pic.irq != 2) {
|
||||
irq = BX_PIC_THIS s.master_pic.irq;
|
||||
vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
|
||||
} else { /* IRQ2 = slave pic IRQ8..15 */
|
||||
BX_PIC_THIS s.slave_pic.INT = 0;
|
||||
BX_PIC_THIS s.master_pic.IRQ_in &= ~(1 << 2);
|
||||
// Check for spurious interrupt
|
||||
if (BX_PIC_THIS s.slave_pic.irr == 0) {
|
||||
return (BX_PIC_THIS s.slave_pic.interrupt_offset + 7);
|
||||
}
|
||||
irq = BX_PIC_THIS s.slave_pic.irq;
|
||||
vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
|
||||
// In level sensitive mode don't clear the irr bit.
|
||||
if (!(BX_PIC_THIS s.slave_pic.edge_level & (1 << BX_PIC_THIS s.slave_pic.irq)))
|
||||
BX_PIC_THIS s.slave_pic.irr &= ~(1 << BX_PIC_THIS s.slave_pic.irq);
|
||||
// In autoeoi mode don't set the isr bit.
|
||||
if (!BX_PIC_THIS s.slave_pic.auto_eoi)
|
||||
BX_PIC_THIS s.slave_pic.isr |= (1 << BX_PIC_THIS s.slave_pic.irq);
|
||||
else if (BX_PIC_THIS s.slave_pic.rotate_on_autoeoi)
|
||||
BX_PIC_THIS s.slave_pic.lowest_priority = BX_PIC_THIS s.slave_pic.irq;
|
||||
service_slave_pic();
|
||||
irq += 8; // for debug printing purposes
|
||||
}
|
||||
|
||||
service_master_pic();
|
||||
|
||||
BX_DBG_IAC_REPORT(vector, irq);
|
||||
return(vector);
|
||||
}
|
||||
|
||||
#if BX_DEBUGGER
|
||||
void bx_pic_c::debug_dump(void)
|
||||
{
|
||||
dbg_printf("s.master_pic.imr = %02x\n", BX_PIC_THIS s.master_pic.imr);
|
||||
dbg_printf("s.master_pic.isr = %02x\n", BX_PIC_THIS s.master_pic.isr);
|
||||
dbg_printf("s.master_pic.irr = %02x\n", BX_PIC_THIS s.master_pic.irr);
|
||||
dbg_printf("s.master_pic.irq = %02x\n", BX_PIC_THIS s.master_pic.irq);
|
||||
dbg_printf("s.slave_pic.imr = %02x\n", BX_PIC_THIS s.slave_pic.imr);
|
||||
dbg_printf("s.slave_pic.isr = %02x\n", BX_PIC_THIS s.slave_pic.isr);
|
||||
dbg_printf("s.slave_pic.irr = %02x\n", BX_PIC_THIS s.slave_pic.irr);
|
||||
dbg_printf("s.slave_pic.irq = %02x\n", BX_PIC_THIS s.slave_pic.irq);
|
||||
}
|
||||
#endif
|
||||
97
bochs/iodev/pic.h
Normal file
97
bochs/iodev/pic.h
Normal file
@ -0,0 +1,97 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_IODEV_PIC_H
|
||||
#define BX_IODEV_PIC_H
|
||||
|
||||
#if BX_USE_PIC_SMF
|
||||
# define BX_PIC_SMF static
|
||||
# define BX_PIC_THIS thePic->
|
||||
#else
|
||||
# define BX_PIC_SMF
|
||||
# define BX_PIC_THIS this->
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
Bit8u single_PIC; /* 0=cascaded PIC, 1=master only */
|
||||
Bit8u interrupt_offset; /* programmable interrupt vector offset */
|
||||
union {
|
||||
Bit8u slave_connect_mask; /* for master, a bit for each interrupt line
|
||||
0=not connect to a slave, 1=connected */
|
||||
Bit8u slave_id; /* for slave, id number of slave PIC */
|
||||
} u;
|
||||
Bit8u sfnm; /* specially fully nested mode: 0=no, 1=yes*/
|
||||
Bit8u buffered_mode; /* 0=no buffered mode, 1=buffered mode */
|
||||
Bit8u master_slave; /* master/slave: 0=slave PIC, 1=master PIC */
|
||||
Bit8u auto_eoi; /* 0=manual EOI, 1=automatic EOI */
|
||||
Bit8u imr; /* interrupt mask register, 1=masked */
|
||||
Bit8u isr; /* in service register */
|
||||
Bit8u irr; /* interrupt request register */
|
||||
Bit8u read_reg_select; /* 0=IRR, 1=ISR */
|
||||
Bit8u irq; /* current IRQ number */
|
||||
Bit8u lowest_priority; /* current lowest priority irq */
|
||||
bx_bool INT; /* INT request pin of PIC */
|
||||
Bit8u IRQ_in; /* IRQ pins of PIC */
|
||||
struct {
|
||||
bx_bool in_init;
|
||||
bx_bool requires_4;
|
||||
Bit8u byte_expected;
|
||||
} init;
|
||||
bx_bool special_mask;
|
||||
bx_bool polled; /* Set when poll command is issued. */
|
||||
bx_bool rotate_on_autoeoi; /* Set when should rotate in auto-eoi mode. */
|
||||
Bit8u edge_level; /* bitmap for irq mode (0=edge, 1=level) */
|
||||
} bx_pic_t;
|
||||
|
||||
|
||||
class bx_pic_c : public bx_pic_stub_c {
|
||||
public:
|
||||
bx_pic_c();
|
||||
virtual ~bx_pic_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void lower_irq(unsigned irq_no);
|
||||
virtual void raise_irq(unsigned irq_no);
|
||||
virtual void set_mode(bx_bool ma_sl, Bit8u mode);
|
||||
virtual Bit8u IAC(void);
|
||||
#if BX_DEBUGGER
|
||||
virtual void debug_dump(void);
|
||||
#endif
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
struct {
|
||||
bx_pic_t master_pic;
|
||||
bx_pic_t slave_pic;
|
||||
} s;
|
||||
|
||||
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_PIC_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
|
||||
BX_PIC_SMF void service_master_pic(void);
|
||||
BX_PIC_SMF void service_slave_pic(void);
|
||||
BX_PIC_SMF void clear_highest_interrupt(bx_pic_t *pic);
|
||||
};
|
||||
|
||||
#endif
|
||||
972
bochs/iodev/pit82c54.cc
Normal file
972
bochs/iodev/pit82c54.cc
Normal file
@ -0,0 +1,972 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/*
|
||||
* Emulator of an Intel 8254/82C54 Programmable Interval Timer.
|
||||
* Greg Alexander <yakovlev@usa.com>
|
||||
*
|
||||
*
|
||||
* Things I am unclear on (greg):
|
||||
* 1.)What happens if both the status and count registers are latched,
|
||||
* but the first of the two count registers has already been read?
|
||||
* I.E.:
|
||||
* latch count 0 (16-bit)
|
||||
* Read count 0 (read LSByte)
|
||||
* READ_BACK status of count 0
|
||||
* Read count 0 - do you get MSByte or status?
|
||||
* This will be flagged as an error.
|
||||
* 2.)What happens when we latch the output in the middle of a 2-part
|
||||
* unlatched read?
|
||||
* 3.)I assumed that programming a counter removes a latched status.
|
||||
* 4.)I implemented the 8254 description of mode 0, not the 82C54 one.
|
||||
* 5.)clock() calls represent a rising clock edge followed by a falling
|
||||
* clock edge.
|
||||
* 6.)What happens when we trigger mode 1 in the middle of a 2-part
|
||||
* write?
|
||||
*/
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "pit82c54.h"
|
||||
#define LOG_THIS this->
|
||||
|
||||
|
||||
void pit_82C54::print_counter(counter_type &thisctr)
|
||||
{
|
||||
BX_INFO(("Printing Counter"));
|
||||
BX_INFO(("count: %d",thisctr.count));
|
||||
BX_INFO(("count_binary: %x",thisctr.count_binary));
|
||||
BX_INFO(("counter gate: %x",thisctr.GATE));
|
||||
BX_INFO(("counter OUT: %x",thisctr.OUTpin));
|
||||
BX_INFO(("next_change_time: %d",thisctr.next_change_time));
|
||||
BX_INFO(("End Counter Printout"));
|
||||
}
|
||||
|
||||
void pit_82C54::print_cnum(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Bad counter index to print_cnum"));
|
||||
} else {
|
||||
print_counter(counter[cnum]);
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::latch_counter(counter_type &thisctr)
|
||||
{
|
||||
if (thisctr.count_LSB_latched || thisctr.count_MSB_latched) {
|
||||
//Do nothing because previous latch has not been read.;
|
||||
} else {
|
||||
switch(thisctr.read_state) {
|
||||
case MSByte:
|
||||
thisctr.outlatch=thisctr.count & 0xFFFF;
|
||||
thisctr.count_MSB_latched=1;
|
||||
break;
|
||||
case LSByte:
|
||||
thisctr.outlatch=thisctr.count & 0xFFFF;
|
||||
thisctr.count_LSB_latched=1;
|
||||
break;
|
||||
case LSByte_multiple:
|
||||
thisctr.outlatch=thisctr.count & 0xFFFF;
|
||||
thisctr.count_LSB_latched=1;
|
||||
thisctr.count_MSB_latched=1;
|
||||
break;
|
||||
case MSByte_multiple:
|
||||
if (!(seen_problems & UNL_2P_READ)) {
|
||||
// seen_problems|=UNL_2P_READ;
|
||||
BX_ERROR(("Unknown behavior when latching during 2-part read."));
|
||||
BX_ERROR((" This message will not be repeated."));
|
||||
}
|
||||
//I guess latching and resetting to LSB first makes sense;
|
||||
BX_DEBUG(("Setting read_state to LSB_mult"));
|
||||
thisctr.read_state=LSByte_multiple;
|
||||
thisctr.outlatch=thisctr.count & 0xFFFF;
|
||||
thisctr.count_LSB_latched=1;
|
||||
thisctr.count_MSB_latched=1;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unknown read mode found during latch command."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::set_OUT(counter_type &thisctr, bx_bool data)
|
||||
{
|
||||
if (thisctr.OUTpin != data) {
|
||||
thisctr.OUTpin = data;
|
||||
if (thisctr.out_handler != NULL) {
|
||||
thisctr.out_handler(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) pit_82C54::set_count(counter_type &thisctr, Bit32u data)
|
||||
{
|
||||
thisctr.count=data & 0xFFFF;
|
||||
set_binary_to_count(thisctr);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) pit_82C54::set_count_to_binary(counter_type &thisctr)
|
||||
{
|
||||
if (thisctr.bcd_mode) {
|
||||
thisctr.count=
|
||||
(((thisctr.count_binary/1)%10)<<0) |
|
||||
(((thisctr.count_binary/10)%10)<<4) |
|
||||
(((thisctr.count_binary/100)%10)<<8) |
|
||||
(((thisctr.count_binary/1000)%10)<<12);
|
||||
} else {
|
||||
thisctr.count=thisctr.count_binary;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) pit_82C54::set_binary_to_count(counter_type &thisctr)
|
||||
{
|
||||
if (thisctr.bcd_mode) {
|
||||
thisctr.count_binary=
|
||||
(1*((thisctr.count>>0)&0xF)) +
|
||||
(10*((thisctr.count>>4)&0xF)) +
|
||||
(100*((thisctr.count>>8)&0xF)) +
|
||||
(1000*((thisctr.count>>12)&0xF));
|
||||
} else {
|
||||
thisctr.count_binary=thisctr.count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) pit_82C54::decrement (counter_type &thisctr)
|
||||
{
|
||||
if (!thisctr.count) {
|
||||
if (thisctr.bcd_mode) {
|
||||
thisctr.count=0x9999;
|
||||
thisctr.count_binary=9999;
|
||||
} else {
|
||||
thisctr.count=0xFFFF;
|
||||
thisctr.count_binary=0xFFFF;
|
||||
}
|
||||
} else {
|
||||
thisctr.count_binary--;
|
||||
set_count_to_binary(thisctr);
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::init(void)
|
||||
{
|
||||
put("PIT81");
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
BX_DEBUG(("Setting read_state to LSB"));
|
||||
counter[i].read_state=LSByte;
|
||||
counter[i].write_state=LSByte;
|
||||
counter[i].GATE=1;
|
||||
counter[i].OUTpin=1;
|
||||
counter[i].triggerGATE=0;
|
||||
counter[i].mode=4;
|
||||
counter[i].first_pass=0;
|
||||
counter[i].bcd_mode=0;
|
||||
counter[i].count=0;
|
||||
counter[i].count_binary=0;
|
||||
counter[i].state_bit_1=0;
|
||||
counter[i].state_bit_2=0;
|
||||
counter[i].null_count=0;
|
||||
counter[i].rw_mode=1;
|
||||
counter[i].count_written=1;
|
||||
counter[i].count_LSB_latched=0;
|
||||
counter[i].count_MSB_latched=0;
|
||||
counter[i].status_latched=0;
|
||||
counter[i].next_change_time=0;
|
||||
counter[i].out_handler=NULL;
|
||||
}
|
||||
seen_problems=0;
|
||||
}
|
||||
|
||||
pit_82C54::pit_82C54(void)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void pit_82C54::reset(unsigned type) {}
|
||||
|
||||
void pit_82C54::register_state(bx_param_c *parent)
|
||||
{
|
||||
char name[4];
|
||||
|
||||
for (unsigned i=0; i<3; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
bx_list_c *tim = new bx_list_c(parent, name, 22);
|
||||
new bx_shadow_bool_c(tim, "GATE", &counter[i].GATE);
|
||||
new bx_shadow_bool_c(tim, "OUTpin", &counter[i].OUTpin);
|
||||
new bx_shadow_num_c(tim, "count", &counter[i].count);
|
||||
new bx_shadow_num_c(tim, "outlatch", &counter[i].outlatch);
|
||||
new bx_shadow_num_c(tim, "inlatch", &counter[i].inlatch);
|
||||
new bx_shadow_num_c(tim, "status_latch", &counter[i].status_latch);
|
||||
new bx_shadow_num_c(tim, "rw_mode", &counter[i].rw_mode);
|
||||
new bx_shadow_num_c(tim, "mode", &counter[i].mode);
|
||||
new bx_shadow_bool_c(tim, "bcd_mode", &counter[i].bcd_mode);
|
||||
new bx_shadow_bool_c(tim, "null_count", &counter[i].null_count);
|
||||
new bx_shadow_bool_c(tim, "count_LSB_latched", &counter[i].count_LSB_latched);
|
||||
new bx_shadow_bool_c(tim, "count_MSB_latched", &counter[i].count_MSB_latched);
|
||||
new bx_shadow_bool_c(tim, "status_latched", &counter[i].status_latched);
|
||||
new bx_shadow_num_c(tim, "count_binary", &counter[i].count_binary);
|
||||
new bx_shadow_bool_c(tim, "triggerGATE", &counter[i].triggerGATE);
|
||||
new bx_shadow_num_c(tim, "write_state", (Bit8u*)&counter[i].write_state);
|
||||
new bx_shadow_num_c(tim, "read_state", (Bit8u*)&counter[i].read_state);
|
||||
new bx_shadow_bool_c(tim, "count_written", &counter[i].count_written);
|
||||
new bx_shadow_bool_c(tim, "first_pass", &counter[i].first_pass);
|
||||
new bx_shadow_bool_c(tim, "state_bit_1", &counter[i].state_bit_1);
|
||||
new bx_shadow_bool_c(tim, "state_bit_2", &counter[i].state_bit_2);
|
||||
new bx_shadow_num_c(tim, "next_change_time", &counter[i].next_change_time);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) pit_82C54::decrement_multiple(counter_type &thisctr, Bit32u cycles)
|
||||
{
|
||||
while(cycles>0) {
|
||||
if (cycles<=thisctr.count_binary) {
|
||||
thisctr.count_binary-=cycles;
|
||||
cycles-=cycles;
|
||||
set_count_to_binary(thisctr);
|
||||
} else {
|
||||
cycles-=(thisctr.count_binary+1);
|
||||
thisctr.count_binary-=thisctr.count_binary;
|
||||
set_count_to_binary(thisctr);
|
||||
decrement(thisctr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::clock_multiple(Bit8u cnum, Bit32u cycles)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number too high in clock"));
|
||||
} else {
|
||||
counter_type &thisctr = counter[cnum];
|
||||
while(cycles>0) {
|
||||
if (thisctr.next_change_time==0) {
|
||||
if (thisctr.count_written) {
|
||||
switch(thisctr.mode) {
|
||||
case 0:
|
||||
if (thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
|
||||
decrement_multiple(thisctr, cycles);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
decrement_multiple(thisctr, cycles);
|
||||
break;
|
||||
case 2:
|
||||
if (!thisctr.first_pass && thisctr.GATE) {
|
||||
decrement_multiple(thisctr, cycles);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!thisctr.first_pass && thisctr.GATE) {
|
||||
decrement_multiple(thisctr, 2*cycles);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (thisctr.GATE) {
|
||||
decrement_multiple(thisctr, cycles);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
decrement_multiple(thisctr, cycles);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
cycles-=cycles;
|
||||
} else {
|
||||
switch(thisctr.mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 5:
|
||||
if (thisctr.next_change_time > cycles) {
|
||||
decrement_multiple(thisctr,cycles);
|
||||
thisctr.next_change_time-=cycles;
|
||||
cycles-=cycles;
|
||||
} else {
|
||||
decrement_multiple(thisctr,(thisctr.next_change_time-1));
|
||||
cycles-=thisctr.next_change_time;
|
||||
clock(cnum);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (thisctr.next_change_time > cycles) {
|
||||
decrement_multiple(thisctr,cycles*2);
|
||||
thisctr.next_change_time-=cycles;
|
||||
cycles-=cycles;
|
||||
} else {
|
||||
decrement_multiple(thisctr,(thisctr.next_change_time-1)*2);
|
||||
cycles-=thisctr.next_change_time;
|
||||
clock(cnum);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cycles-=cycles;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
print_counter(thisctr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) pit_82C54::clock(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number too high in clock"));
|
||||
} else {
|
||||
counter_type &thisctr = counter[cnum];
|
||||
switch(thisctr.mode) {
|
||||
case 0:
|
||||
if (thisctr.count_written) {
|
||||
if (thisctr.null_count) {
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
if (thisctr.GATE) {
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.null_count=0;
|
||||
} else {
|
||||
if (thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
|
||||
decrement(thisctr);
|
||||
if (!thisctr.OUTpin) {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
if (!thisctr.count) {
|
||||
set_OUT(thisctr,1);
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0; //if the clock isn't moving.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0; //default to 0.
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
case 1:
|
||||
if (thisctr.count_written) {
|
||||
if (thisctr.triggerGATE) {
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
thisctr.null_count=0;
|
||||
set_OUT(thisctr,0);
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
BX_ERROR(("Undefined behavior when loading a half loaded count."));
|
||||
}
|
||||
} else {
|
||||
decrement(thisctr);
|
||||
if (!thisctr.OUTpin) {
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
if (thisctr.count==0) {
|
||||
set_OUT(thisctr,1);
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0; //default to 0.
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
case 2:
|
||||
if (thisctr.count_written) {
|
||||
if (thisctr.triggerGATE || thisctr.first_pass) {
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
|
||||
thisctr.null_count=0;
|
||||
if (thisctr.inlatch==1) {
|
||||
BX_ERROR(("ERROR: count of 1 is invalid in pit mode 2."));
|
||||
}
|
||||
if (!thisctr.OUTpin) {
|
||||
set_OUT(thisctr,1);
|
||||
}
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
BX_ERROR(("Undefined behavior when loading a half loaded count."));
|
||||
}
|
||||
thisctr.first_pass=0;
|
||||
} else {
|
||||
if (thisctr.GATE) {
|
||||
decrement(thisctr);
|
||||
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
|
||||
if (thisctr.count==1) {
|
||||
thisctr.next_change_time=1;
|
||||
set_OUT(thisctr,0);
|
||||
thisctr.first_pass=1;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
case 3:
|
||||
if (thisctr.count_written) {
|
||||
if ((thisctr.triggerGATE || thisctr.first_pass
|
||||
|| thisctr.state_bit_2) && thisctr.GATE) {
|
||||
set_count(thisctr, thisctr.inlatch & 0xFFFE);
|
||||
thisctr.state_bit_1=thisctr.inlatch & 0x1;
|
||||
if (!thisctr.OUTpin || !thisctr.state_bit_1) {
|
||||
if (((thisctr.count_binary/2)-1)==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
|
||||
}
|
||||
} else {
|
||||
if ((thisctr.count_binary/2)==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
thisctr.null_count=0;
|
||||
if (thisctr.inlatch==1) {
|
||||
BX_ERROR(("Count of 1 is invalid in pit mode 3."));
|
||||
}
|
||||
if (!thisctr.OUTpin) {
|
||||
set_OUT(thisctr,1);
|
||||
} else if (thisctr.OUTpin && !thisctr.first_pass) {
|
||||
set_OUT(thisctr,0);
|
||||
}
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
BX_ERROR(("Undefined behavior when loading a half loaded count."));
|
||||
}
|
||||
thisctr.state_bit_2=0;
|
||||
thisctr.first_pass=0;
|
||||
} else {
|
||||
if (thisctr.GATE) {
|
||||
decrement(thisctr);
|
||||
decrement(thisctr);
|
||||
if (!thisctr.OUTpin || !thisctr.state_bit_1) {
|
||||
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
|
||||
} else {
|
||||
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
|
||||
}
|
||||
if (thisctr.count==0) {
|
||||
thisctr.state_bit_2=1;
|
||||
thisctr.next_change_time=1;
|
||||
}
|
||||
if ((thisctr.count==2) &&
|
||||
(!thisctr.OUTpin || !thisctr.state_bit_1))
|
||||
{
|
||||
thisctr.state_bit_2=1;
|
||||
thisctr.next_change_time=1;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
case 4:
|
||||
if (thisctr.count_written) {
|
||||
if (!thisctr.OUTpin) {
|
||||
set_OUT(thisctr,1);
|
||||
}
|
||||
if (thisctr.null_count) {
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
if (thisctr.GATE) {
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.null_count=0;
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
BX_ERROR(("Undefined behavior when loading a half loaded count."));
|
||||
}
|
||||
thisctr.first_pass=1;
|
||||
} else {
|
||||
if (thisctr.GATE) {
|
||||
decrement(thisctr);
|
||||
if (thisctr.first_pass) {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
if (!thisctr.count) {
|
||||
set_OUT(thisctr,0);
|
||||
thisctr.next_change_time=1;
|
||||
thisctr.first_pass=0;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
case 5:
|
||||
if (thisctr.count_written) {
|
||||
if (!thisctr.OUTpin) {
|
||||
set_OUT(thisctr,1);
|
||||
}
|
||||
if (thisctr.triggerGATE) {
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
thisctr.null_count=0;
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
BX_ERROR(("Undefined behavior when loading a half loaded count."));
|
||||
}
|
||||
thisctr.first_pass=1;
|
||||
} else {
|
||||
decrement(thisctr);
|
||||
if (thisctr.first_pass) {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
if (!thisctr.count) {
|
||||
set_OUT(thisctr,0);
|
||||
thisctr.next_change_time=1;
|
||||
thisctr.first_pass=0;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Mode not implemented."));
|
||||
thisctr.next_change_time=0;
|
||||
thisctr.triggerGATE=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::clock_all(Bit32u cycles)
|
||||
{
|
||||
BX_DEBUG(("clock_all: cycles=%d",cycles));
|
||||
clock_multiple(0,cycles);
|
||||
clock_multiple(1,cycles);
|
||||
clock_multiple(2,cycles);
|
||||
}
|
||||
|
||||
Bit8u pit_82C54::read(Bit8u address)
|
||||
{
|
||||
if (address>MAX_ADDRESS) {
|
||||
BX_ERROR(("Counter address incorrect in data read."));
|
||||
} else if (address==CONTROL_ADDRESS) {
|
||||
BX_DEBUG(("PIT Read: Control Word Register."));
|
||||
//Read from control word register;
|
||||
/* This might be okay. If so, 0 seems the most logical
|
||||
* return value from looking at the docs.
|
||||
*/
|
||||
BX_ERROR(("Read from control word register not defined."));
|
||||
return 0;
|
||||
} else {
|
||||
//Read from a counter;
|
||||
BX_DEBUG(("PIT Read: Counter %d.",address));
|
||||
counter_type &thisctr=counter[address];
|
||||
if (thisctr.status_latched) {
|
||||
//Latched Status Read;
|
||||
if (thisctr.count_MSB_latched &&
|
||||
(thisctr.read_state==MSByte_multiple)) {
|
||||
BX_ERROR(("Undefined output when status latched and count half read."));
|
||||
} else {
|
||||
thisctr.status_latched=0;
|
||||
return thisctr.status_latch;
|
||||
}
|
||||
} else {
|
||||
//Latched Count Read;
|
||||
if (thisctr.count_LSB_latched) {
|
||||
//Read Least Significant Byte;
|
||||
if (thisctr.read_state==LSByte_multiple) {
|
||||
BX_DEBUG(("Setting read_state to MSB_mult"));
|
||||
thisctr.read_state=MSByte_multiple;
|
||||
}
|
||||
thisctr.count_LSB_latched=0;
|
||||
return (thisctr.outlatch & 0xFF);
|
||||
} else if (thisctr.count_MSB_latched) {
|
||||
//Read Most Significant Byte;
|
||||
if (thisctr.read_state==MSByte_multiple) {
|
||||
BX_DEBUG(("Setting read_state to LSB_mult"));
|
||||
thisctr.read_state=LSByte_multiple;
|
||||
}
|
||||
thisctr.count_MSB_latched=0;
|
||||
return ((thisctr.outlatch>>8) & 0xFF);
|
||||
} else {
|
||||
//Unlatched Count Read;
|
||||
if (!(thisctr.read_state & 0x1)) {
|
||||
//Read Least Significant Byte;
|
||||
if (thisctr.read_state==LSByte_multiple) {
|
||||
thisctr.read_state=MSByte_multiple;
|
||||
BX_DEBUG(("Setting read_state to MSB_mult"));
|
||||
}
|
||||
return (thisctr.count & 0xFF);
|
||||
} else {
|
||||
//Read Most Significant Byte;
|
||||
if (thisctr.read_state==MSByte_multiple) {
|
||||
BX_DEBUG(("Setting read_state to LSB_mult"));
|
||||
thisctr.read_state=LSByte_multiple;
|
||||
}
|
||||
return ((thisctr.count>>8) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Should only get here on errors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pit_82C54::write(Bit8u address, Bit8u data)
|
||||
{
|
||||
if (address>MAX_ADDRESS) {
|
||||
BX_ERROR(("Counter address incorrect in data write."));
|
||||
} else if (address==CONTROL_ADDRESS) {
|
||||
Bit8u SC, RW, M, BCD;
|
||||
controlword=data;
|
||||
BX_DEBUG(("Control Word Write."));
|
||||
SC = (controlword>>6) & 0x3;
|
||||
RW = (controlword>>4) & 0x3;
|
||||
M = (controlword>>1) & 0x7;
|
||||
BCD = controlword & 0x1;
|
||||
if (SC == 3) {
|
||||
//READ_BACK command;
|
||||
int i;
|
||||
BX_DEBUG(("READ_BACK command."));
|
||||
for(i=0;i<=MAX_COUNTER;i++) {
|
||||
if ((M>>i) & 0x1) {
|
||||
//If we are using this counter;
|
||||
counter_type &thisctr=counter[i];
|
||||
if (!((controlword>>5) & 1)) {
|
||||
//Latch Count;
|
||||
latch_counter(thisctr);
|
||||
}
|
||||
if (!((controlword>>4) & 1)) {
|
||||
//Latch Status;
|
||||
if (thisctr.status_latched) {
|
||||
//Do nothing because latched status has not been read.;
|
||||
} else {
|
||||
thisctr.status_latch=
|
||||
((thisctr.OUTpin & 0x1) << 7) |
|
||||
((thisctr.null_count & 0x1) << 6) |
|
||||
((thisctr.rw_mode & 0x3) << 4) |
|
||||
((thisctr.mode & 0x7) << 1) |
|
||||
(thisctr.bcd_mode&0x1);
|
||||
thisctr.status_latched=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
counter_type &thisctr = counter[SC];
|
||||
if (!RW) {
|
||||
//Counter Latch command;
|
||||
BX_DEBUG(("Counter Latch command. SC=%d",SC));
|
||||
latch_counter(thisctr);
|
||||
} else {
|
||||
//Counter Program Command;
|
||||
BX_DEBUG(("Counter Program command. SC=%d, RW=%d, M=%d, BCD=%d",SC,RW,M,BCD));
|
||||
thisctr.null_count=1;
|
||||
thisctr.count_LSB_latched=0;
|
||||
thisctr.count_MSB_latched=0;
|
||||
thisctr.status_latched=0;
|
||||
thisctr.inlatch=0;
|
||||
thisctr.count_written=0;
|
||||
thisctr.first_pass=1;
|
||||
thisctr.rw_mode=RW;
|
||||
thisctr.bcd_mode=(BCD > 0);
|
||||
thisctr.mode=M;
|
||||
switch(RW) {
|
||||
case 0x1:
|
||||
BX_DEBUG(("Setting read_state to LSB"));
|
||||
thisctr.read_state=LSByte;
|
||||
thisctr.write_state=LSByte;
|
||||
break;
|
||||
case 0x2:
|
||||
BX_DEBUG(("Setting read_state to MSB"));
|
||||
thisctr.read_state=MSByte;
|
||||
thisctr.write_state=MSByte;
|
||||
break;
|
||||
case 0x3:
|
||||
BX_DEBUG(("Setting read_state to LSB_mult"));
|
||||
thisctr.read_state=LSByte_multiple;
|
||||
thisctr.write_state=LSByte_multiple;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("RW field invalid in control word write."));
|
||||
break;
|
||||
}
|
||||
//All modes except mode 0 have initial output of 1.;
|
||||
if (M) {
|
||||
set_OUT(thisctr, 1);
|
||||
} else {
|
||||
set_OUT(thisctr, 0);
|
||||
}
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Write to counter initial value.
|
||||
counter_type &thisctr = counter[address];
|
||||
BX_DEBUG(("Write Initial Count: counter=%d, count=%d",address,data));
|
||||
switch(thisctr.write_state) {
|
||||
case LSByte_multiple:
|
||||
thisctr.inlatch = data;
|
||||
thisctr.write_state = MSByte_multiple;
|
||||
break;
|
||||
case LSByte:
|
||||
thisctr.inlatch = data;
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
case MSByte_multiple:
|
||||
thisctr.write_state = LSByte_multiple;
|
||||
thisctr.inlatch |= (data << 8);
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
case MSByte:
|
||||
thisctr.inlatch = (data << 8);
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("write counter in invalid write state."));
|
||||
break;
|
||||
}
|
||||
if (thisctr.count_written && thisctr.write_state != MSByte_multiple) {
|
||||
thisctr.null_count = 1;
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
}
|
||||
switch(thisctr.mode) {
|
||||
case 0:
|
||||
if (thisctr.write_state==MSByte_multiple) {
|
||||
set_OUT(thisctr,0);
|
||||
}
|
||||
thisctr.next_change_time=1;
|
||||
break;
|
||||
case 1:
|
||||
if (thisctr.triggerGATE) { //for initial writes, if already saw trigger.
|
||||
thisctr.next_change_time=1;
|
||||
} //Otherwise, no change.
|
||||
break;
|
||||
case 6:
|
||||
case 2:
|
||||
thisctr.next_change_time=1; //FIXME: this could be loosened.
|
||||
break;
|
||||
case 7:
|
||||
case 3:
|
||||
thisctr.next_change_time=1; //FIXME: this could be loosened.
|
||||
break;
|
||||
case 4:
|
||||
thisctr.next_change_time=1;
|
||||
break;
|
||||
case 5:
|
||||
if (thisctr.triggerGATE) { //for initial writes, if already saw trigger.
|
||||
thisctr.next_change_time=1;
|
||||
} //Otherwise, no change.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_82C54::set_GATE(Bit8u cnum, bx_bool data)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 set_GATE"));
|
||||
} else {
|
||||
counter_type &thisctr = counter[cnum];
|
||||
if (!((thisctr.GATE&&data) || (!(thisctr.GATE||data)))) {
|
||||
BX_INFO(("Changing GATE %d to: %d",cnum,data));
|
||||
thisctr.GATE=data;
|
||||
if (thisctr.GATE) {
|
||||
thisctr.triggerGATE=1;
|
||||
}
|
||||
switch(thisctr.mode) {
|
||||
case 0:
|
||||
if (data && thisctr.count_written) {
|
||||
if (thisctr.null_count) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
if ((!thisctr.OUTpin) &&
|
||||
(thisctr.write_state!=MSByte_multiple))
|
||||
{
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (thisctr.null_count) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (data && thisctr.count_written) { //only triggers cause a change.
|
||||
thisctr.next_change_time=1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!data) {
|
||||
set_OUT(thisctr,1);
|
||||
thisctr.next_change_time=0;
|
||||
} else {
|
||||
if (thisctr.count_written) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!data) {
|
||||
set_OUT(thisctr,1);
|
||||
thisctr.first_pass=1;
|
||||
thisctr.next_change_time=0;
|
||||
} else {
|
||||
if (thisctr.count_written) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (!thisctr.OUTpin || thisctr.null_count) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
if (data && thisctr.count_written) {
|
||||
if (thisctr.first_pass) {
|
||||
if (thisctr.count_binary==0) {
|
||||
thisctr.next_change_time=1;
|
||||
} else {
|
||||
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
} else {
|
||||
thisctr.next_change_time=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (data && thisctr.count_written) { //only triggers cause a change.
|
||||
thisctr.next_change_time=1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool pit_82C54::read_OUT(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return counter[cnum].OUTpin;
|
||||
}
|
||||
|
||||
bx_bool pit_82C54::read_GATE(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return counter[cnum].GATE;
|
||||
}
|
||||
|
||||
Bit32u pit_82C54::get_clock_event_time(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return counter[cnum].next_change_time;
|
||||
}
|
||||
|
||||
Bit32u pit_82C54::get_next_event_time(void)
|
||||
{
|
||||
Bit32u time0=get_clock_event_time(0);
|
||||
Bit32u time1=get_clock_event_time(1);
|
||||
Bit32u time2=get_clock_event_time(2);
|
||||
|
||||
Bit32u out=time0;
|
||||
if (time1 && (time1<out))
|
||||
out=time1;
|
||||
if (time2 && (time2<out))
|
||||
out=time2;
|
||||
return out;
|
||||
}
|
||||
|
||||
Bit16u pit_82C54::get_inlatch(int counternum)
|
||||
{
|
||||
return counter[counternum].inlatch;
|
||||
}
|
||||
|
||||
void pit_82C54::set_OUT_handler(Bit8u counternum, out_handler_t outh)
|
||||
{
|
||||
counter[counternum].out_handler = outh;
|
||||
}
|
||||
148
bochs/iodev/pit82c54.h
Normal file
148
bochs/iodev/pit82c54.h
Normal file
@ -0,0 +1,148 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/*
|
||||
* Emulator of an Intel 8254/82C54 Programmable Interval Timer.
|
||||
* Greg Alexander <yakovlev@usa.com>
|
||||
*/
|
||||
|
||||
#ifndef _PIT_82C54_H_
|
||||
#define _PIT_82C54_H_ 1
|
||||
|
||||
typedef void (*out_handler_t)(bx_bool value);
|
||||
|
||||
class pit_82C54 : public logfunctions {
|
||||
public:
|
||||
//Please do not use these. They are public because they have to be
|
||||
// to compile on some platforms. They are not to be used by other
|
||||
// classes.
|
||||
|
||||
enum rw_status {
|
||||
LSByte=0,
|
||||
MSByte=1,
|
||||
LSByte_multiple=2,
|
||||
MSByte_multiple=3
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
MAX_COUNTER=2,
|
||||
MAX_ADDRESS=3,
|
||||
CONTROL_ADDRESS=3,
|
||||
MAX_MODE=5
|
||||
};
|
||||
|
||||
enum real_RW_status {
|
||||
LSB_real=1,
|
||||
MSB_real=2,
|
||||
BOTH_real=3
|
||||
};
|
||||
|
||||
enum problem_type {
|
||||
UNL_2P_READ=1
|
||||
};
|
||||
|
||||
struct counter_type {
|
||||
//Chip IOs;
|
||||
bx_bool GATE; //GATE Input value at end of cycle
|
||||
bx_bool OUTpin; //OUT output this cycle
|
||||
|
||||
//Architected state;
|
||||
Bit32u count; //Counter value this cycle
|
||||
Bit16u outlatch; //Output latch this cycle
|
||||
Bit16u inlatch; //Input latch this cycle
|
||||
Bit8u status_latch;
|
||||
|
||||
//Status Register data;
|
||||
Bit8u rw_mode; //2-bit R/W mode from command word register.
|
||||
Bit8u mode; //3-bit mode from command word register.
|
||||
bx_bool bcd_mode; //1-bit BCD vs. Binary setting.
|
||||
bx_bool null_count; //Null count bit of status register.
|
||||
|
||||
//Latch status data;
|
||||
bx_bool count_LSB_latched;
|
||||
bx_bool count_MSB_latched;
|
||||
bx_bool status_latched;
|
||||
|
||||
//Miscelaneous State;
|
||||
Bit32u count_binary; //Value of the count in binary.
|
||||
bx_bool triggerGATE; //Whether we saw GATE rise this cycle.
|
||||
rw_status write_state; //Read state this cycle
|
||||
rw_status read_state; //Read state this cycle
|
||||
bx_bool count_written; //Whether a count written since programmed
|
||||
bx_bool first_pass; //Whether or not this is the first loaded count.
|
||||
bx_bool state_bit_1; //Miscelaneous state bits.
|
||||
bx_bool state_bit_2;
|
||||
Bit32u next_change_time; //Next time something besides count changes.
|
||||
//0 means never.
|
||||
out_handler_t out_handler; // OUT pin callback (for IRQ0)
|
||||
};
|
||||
|
||||
counter_type counter[3];
|
||||
|
||||
Bit8u controlword;
|
||||
|
||||
int seen_problems;
|
||||
|
||||
void latch_counter(counter_type & thisctr);
|
||||
|
||||
void set_OUT (counter_type & thisctr, bx_bool data);
|
||||
|
||||
void set_count (counter_type & thisctr, Bit32u data) BX_CPP_AttrRegparmN(2);
|
||||
|
||||
void set_count_to_binary (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
|
||||
|
||||
void set_binary_to_count (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
|
||||
|
||||
void decrement (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
|
||||
|
||||
void decrement_multiple(counter_type & thisctr, Bit32u cycles) BX_CPP_AttrRegparmN(2);
|
||||
|
||||
void clock(Bit8u cnum) BX_CPP_AttrRegparmN(1);
|
||||
|
||||
void print_counter(counter_type & thisctr);
|
||||
|
||||
public:
|
||||
pit_82C54 (void);
|
||||
void init (void);
|
||||
void reset (unsigned type);
|
||||
void register_state(bx_param_c *parent);
|
||||
|
||||
void clock_all(Bit32u cycles);
|
||||
void clock_multiple(Bit8u cnum, Bit32u cycles);
|
||||
|
||||
Bit8u read(Bit8u address);
|
||||
void write(Bit8u address, Bit8u data);
|
||||
|
||||
void set_GATE(Bit8u cnum, bx_bool data);
|
||||
bx_bool read_GATE(Bit8u cnum);
|
||||
|
||||
bx_bool read_OUT(Bit8u cnum);
|
||||
void set_OUT_handler(Bit8u cnum, out_handler_t outh);
|
||||
|
||||
Bit32u get_clock_event_time(Bit8u cnum);
|
||||
Bit32u get_next_event_time(void);
|
||||
Bit16u get_inlatch(int countnum);
|
||||
|
||||
void print_cnum(Bit8u cnum);
|
||||
};
|
||||
|
||||
#endif
|
||||
372
bochs/iodev/pit_wrap.cc
Normal file
372
bochs/iodev/pit_wrap.cc
Normal file
@ -0,0 +1,372 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "pit_wrap.h"
|
||||
#include "virt_timer.h"
|
||||
#include "speaker.h"
|
||||
|
||||
|
||||
#define LOG_THIS thePit->
|
||||
|
||||
bx_pit_c *thePit = NULL;
|
||||
|
||||
int libpit_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
thePit = new bx_pit_c();
|
||||
bx_devices.pluginPitDevice = thePit;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePit, BX_PLUGIN_PIT);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libpit_LTX_plugin_fini(void)
|
||||
{
|
||||
delete thePit;
|
||||
}
|
||||
|
||||
//Important constant #defines:
|
||||
#define USEC_PER_SECOND (1000000)
|
||||
//1.193181MHz Clock
|
||||
#define TICKS_PER_SECOND (1193181)
|
||||
|
||||
|
||||
// define a macro to convert floating point numbers into 64-bit integers.
|
||||
// In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
|
||||
// but it will not convert a 64-bit float into a 64-bit unsigned integer.
|
||||
// This macro works around that.
|
||||
#define F2I(x) ((Bit64u)(Bit64s) (x))
|
||||
#define I2F(x) ((double)(Bit64s) (x))
|
||||
|
||||
|
||||
//Generic MAX and MIN Functions
|
||||
#define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
|
||||
#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
|
||||
|
||||
|
||||
//USEC_ALPHA is multiplier for the past.
|
||||
//USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
|
||||
#define USEC_ALPHA ((double)(.8))
|
||||
#define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
|
||||
#define USEC_ALPHA2 ((double)(.5))
|
||||
#define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
|
||||
#define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
|
||||
|
||||
|
||||
//PIT tick to usec conversion functions:
|
||||
//Direct conversions:
|
||||
#define TICKS_TO_USEC(a) (((a)*USEC_PER_SECOND)/TICKS_PER_SECOND)
|
||||
#define USEC_TO_TICKS(a) (((a)*TICKS_PER_SECOND)/USEC_PER_SECOND)
|
||||
|
||||
bx_pit_c::bx_pit_c()
|
||||
{
|
||||
put("PIT");
|
||||
s.speaker_data_on=0;
|
||||
|
||||
/* 8254 PIT (Programmable Interval Timer) */
|
||||
|
||||
s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
|
||||
s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
|
||||
s.timer_handle[0] = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
void bx_pit_c::init(void)
|
||||
{
|
||||
DEV_register_irq(0, "8254 PIT");
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1);
|
||||
DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1);
|
||||
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1);
|
||||
DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1);
|
||||
|
||||
BX_DEBUG(("starting init"));
|
||||
|
||||
BX_PIT_THIS s.speaker_data_on = 0;
|
||||
BX_PIT_THIS s.refresh_clock_div2 = 0;
|
||||
|
||||
BX_PIT_THIS s.timer.init();
|
||||
BX_PIT_THIS s.timer.set_OUT_handler(0, irq_handler);
|
||||
|
||||
Bit64u my_time_usec = bx_virt_timer.time_usec();
|
||||
|
||||
if (BX_PIT_THIS s.timer_handle[0] == BX_NULL_TIMER_HANDLE) {
|
||||
BX_PIT_THIS s.timer_handle[0] = bx_virt_timer.register_timer(this, timer_handler, (unsigned) 100 , 1, 1, "pit_wrap");
|
||||
}
|
||||
BX_DEBUG(("RESETting timer."));
|
||||
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
|
||||
BX_DEBUG(("deactivated timer."));
|
||||
if (BX_PIT_THIS s.timer.get_next_event_time()) {
|
||||
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
|
||||
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
|
||||
0);
|
||||
BX_DEBUG(("activated timer."));
|
||||
}
|
||||
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
|
||||
BX_PIT_THIS s.last_usec=my_time_usec;
|
||||
|
||||
BX_PIT_THIS s.total_ticks=0;
|
||||
BX_PIT_THIS s.total_usec=0;
|
||||
|
||||
BX_DEBUG(("finished init"));
|
||||
|
||||
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
|
||||
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
|
||||
BX_DEBUG(("s.timer.get_next_event_time=%d",BX_PIT_THIS s.timer.get_next_event_time()));
|
||||
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
|
||||
}
|
||||
|
||||
void bx_pit_c::reset(unsigned type)
|
||||
{
|
||||
BX_PIT_THIS s.timer.reset(type);
|
||||
}
|
||||
|
||||
void bx_pit_c::register_state(void)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pit", "8254 PIT State", 7);
|
||||
new bx_shadow_num_c(list, "speaker_data_on", &BX_PIT_THIS s.speaker_data_on, BASE_HEX);
|
||||
new bx_shadow_bool_c(list, "refresh_clock_div2", &BX_PIT_THIS s.refresh_clock_div2);
|
||||
new bx_shadow_num_c(list, "last_usec", &BX_PIT_THIS s.last_usec);
|
||||
new bx_shadow_num_c(list, "last_next_event_time", &BX_PIT_THIS s.last_next_event_time);
|
||||
new bx_shadow_num_c(list, "total_ticks", &BX_PIT_THIS s.total_ticks);
|
||||
new bx_shadow_num_c(list, "total_usec", &BX_PIT_THIS s.total_usec);
|
||||
bx_list_c *counter = new bx_list_c(list, "counter", 4);
|
||||
BX_PIT_THIS s.timer.register_state(counter);
|
||||
}
|
||||
|
||||
void bx_pit_c::timer_handler(void *this_ptr)
|
||||
{
|
||||
bx_pit_c * class_ptr = (bx_pit_c *) this_ptr;
|
||||
class_ptr->handle_timer();
|
||||
}
|
||||
|
||||
void bx_pit_c::handle_timer()
|
||||
{
|
||||
Bit64u my_time_usec = bx_virt_timer.time_usec();
|
||||
Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
|
||||
Bit32u time_passed32 = (Bit32u)time_passed;
|
||||
|
||||
BX_DEBUG(("entering timer handler"));
|
||||
|
||||
if(time_passed32) {
|
||||
periodic(time_passed32);
|
||||
}
|
||||
BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
|
||||
if(time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time()))
|
||||
{
|
||||
BX_DEBUG(("RESETting timer"));
|
||||
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
|
||||
BX_DEBUG(("deactivated timer"));
|
||||
if(BX_PIT_THIS s.timer.get_next_event_time()) {
|
||||
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
|
||||
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
|
||||
0);
|
||||
BX_DEBUG(("activated timer"));
|
||||
}
|
||||
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
|
||||
}
|
||||
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
|
||||
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
|
||||
BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
|
||||
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
|
||||
}
|
||||
|
||||
// static IO port read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIT_SMF
|
||||
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
|
||||
return class_ptr->read(address, io_len);
|
||||
}
|
||||
|
||||
Bit32u bx_pit_c::read(Bit32u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIT_SMF
|
||||
|
||||
Bit8u value = 0;
|
||||
|
||||
handle_timer();
|
||||
|
||||
Bit64u my_time_usec = bx_virt_timer.time_usec();
|
||||
|
||||
switch (address) {
|
||||
|
||||
case 0x40: /* timer 0 - system ticks */
|
||||
value = BX_PIT_THIS s.timer.read(0);
|
||||
break;
|
||||
case 0x41: /* timer 1 read */
|
||||
value = BX_PIT_THIS s.timer.read(1);
|
||||
break;
|
||||
case 0x42: /* timer 2 read */
|
||||
value = BX_PIT_THIS s.timer.read(2);
|
||||
break;
|
||||
case 0x43: /* timer 1 read */
|
||||
value = BX_PIT_THIS s.timer.read(3);
|
||||
break;
|
||||
|
||||
case 0x61:
|
||||
/* AT, port 61h */
|
||||
BX_PIT_THIS s.refresh_clock_div2 = (bx_bool)((my_time_usec / 15) & 1);
|
||||
value = (BX_PIT_THIS s.timer.read_OUT(2)<<5) |
|
||||
(BX_PIT_THIS s.refresh_clock_div2<<4) |
|
||||
(BX_PIT_THIS s.speaker_data_on<<1) |
|
||||
(BX_PIT_THIS s.timer.read_GATE(2)?1:0);
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("unsupported io read from port 0x%04x", address));
|
||||
}
|
||||
|
||||
BX_DEBUG(("read from port 0x%04x, value = 0x%02x", address, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
// static IO port write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PIT_SMF
|
||||
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
|
||||
class_ptr->write(address, dvalue, io_len);
|
||||
}
|
||||
|
||||
void bx_pit_c::write(Bit32u address, Bit32u dvalue, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PIT_SMF
|
||||
Bit8u value;
|
||||
Bit64u my_time_usec = bx_virt_timer.time_usec();
|
||||
Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
|
||||
Bit32u time_passed32 = (Bit32u)time_passed;
|
||||
|
||||
if(time_passed32) {
|
||||
periodic(time_passed32);
|
||||
}
|
||||
BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
|
||||
|
||||
value = (Bit8u) dvalue;
|
||||
|
||||
BX_DEBUG(("write to port 0x%04x, value = 0x%02x", address, value));
|
||||
|
||||
switch (address) {
|
||||
case 0x40: /* timer 0: write count register */
|
||||
BX_PIT_THIS s.timer.write(0, value);
|
||||
break;
|
||||
|
||||
case 0x41: /* timer 1: write count register */
|
||||
BX_PIT_THIS s.timer.write(1, value);
|
||||
break;
|
||||
|
||||
case 0x42: /* timer 2: write count register */
|
||||
BX_PIT_THIS s.timer.write(2, value);
|
||||
break;
|
||||
|
||||
case 0x43: /* timer 0-2 mode control */
|
||||
BX_PIT_THIS s.timer.write(3, value);
|
||||
break;
|
||||
|
||||
case 0x61:
|
||||
BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
|
||||
if (BX_PIT_THIS s.speaker_data_on) {
|
||||
DEV_speaker_beep_on((float)(1193180.0 / BX_PIT_THIS get_timer(2)));
|
||||
} else {
|
||||
DEV_speaker_beep_off();
|
||||
}
|
||||
/* ??? only on AT+ */
|
||||
BX_PIT_THIS s.timer.set_GATE(2, value & 0x01);
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("unsupported io write to port 0x%04x = 0x%02x", address, value));
|
||||
}
|
||||
|
||||
if(time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time()))
|
||||
{
|
||||
BX_DEBUG(("RESETting timer"));
|
||||
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
|
||||
BX_DEBUG(("deactivated timer"));
|
||||
if(BX_PIT_THIS s.timer.get_next_event_time()) {
|
||||
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
|
||||
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
|
||||
0);
|
||||
BX_DEBUG(("activated timer"));
|
||||
}
|
||||
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
|
||||
}
|
||||
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
|
||||
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
|
||||
BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
|
||||
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
|
||||
|
||||
}
|
||||
|
||||
bx_bool bx_pit_c::periodic(Bit32u usec_delta)
|
||||
{
|
||||
Bit32u ticks_delta = 0;
|
||||
|
||||
BX_PIT_THIS s.total_usec += usec_delta;
|
||||
ticks_delta=(Bit32u)((USEC_TO_TICKS((Bit64u)(BX_PIT_THIS s.total_usec)))-BX_PIT_THIS s.total_ticks);
|
||||
BX_PIT_THIS s.total_ticks += ticks_delta;
|
||||
|
||||
while ((BX_PIT_THIS s.total_ticks >= TICKS_PER_SECOND) && (BX_PIT_THIS s.total_usec >= USEC_PER_SECOND)) {
|
||||
BX_PIT_THIS s.total_ticks -= TICKS_PER_SECOND;
|
||||
BX_PIT_THIS s.total_usec -= USEC_PER_SECOND;
|
||||
}
|
||||
|
||||
while(ticks_delta>0) {
|
||||
Bit32u maxchange=BX_PIT_THIS s.timer.get_next_event_time();
|
||||
Bit32u timedelta=maxchange;
|
||||
if((maxchange==0) || (maxchange>ticks_delta)) {
|
||||
timedelta=ticks_delta;
|
||||
}
|
||||
BX_PIT_THIS s.timer.clock_all(timedelta);
|
||||
ticks_delta-=timedelta;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bx_pit_c::irq_handler(bx_bool value)
|
||||
{
|
||||
if (value == 1) {
|
||||
DEV_pic_raise_irq(0);
|
||||
} else {
|
||||
DEV_pic_lower_irq(0);
|
||||
}
|
||||
}
|
||||
|
||||
Bit16u bx_pit_c::get_timer(int Timer) {
|
||||
return BX_PIT_THIS s.timer.get_inlatch(Timer);
|
||||
}
|
||||
71
bochs/iodev/pit_wrap.h
Normal file
71
bochs/iodev/pit_wrap.h
Normal file
@ -0,0 +1,71 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef _BX_PIT_WRAP_H
|
||||
#define _BX_PIT_WRAP_H
|
||||
|
||||
#include "bochs.h"
|
||||
#include "pit82c54.h"
|
||||
|
||||
#if BX_USE_PIT_SMF
|
||||
# define BX_PIT_SMF static
|
||||
# define BX_PIT_THIS thePit->
|
||||
#else
|
||||
# define BX_PIT_SMF
|
||||
# define BX_PIT_THIS this->
|
||||
#endif
|
||||
|
||||
class bx_pit_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_pit_c();
|
||||
virtual ~bx_pit_c() {}
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
|
||||
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_PIT_SMF
|
||||
Bit32u read(Bit32u addr, unsigned len);
|
||||
void write(Bit32u addr, Bit32u Value, unsigned len);
|
||||
#endif
|
||||
|
||||
struct s_type {
|
||||
pit_82C54 timer;
|
||||
Bit8u speaker_data_on;
|
||||
bx_bool refresh_clock_div2;
|
||||
Bit64u last_usec;
|
||||
Bit32u last_next_event_time;
|
||||
Bit64u total_ticks;
|
||||
Bit64u total_usec;
|
||||
int timer_handle[3];
|
||||
} s;
|
||||
|
||||
static void timer_handler(void *this_ptr);
|
||||
BX_PIT_SMF void handle_timer();
|
||||
BX_PIT_SMF bx_bool periodic(Bit32u usec_delta);
|
||||
|
||||
BX_PIT_SMF void irq_handler(bx_bool value);
|
||||
|
||||
BX_PIT_SMF Bit16u get_timer(int Timer);
|
||||
};
|
||||
|
||||
#endif // #ifndef _BX_PIT_WRAP_H
|
||||
59
bochs/iodev/pnic_api.h
Normal file
59
bochs/iodev/pnic_api.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Constants etc. for the Bochs/Etherboot pseudo-NIC
|
||||
*
|
||||
* This header file must be valid C and C++.
|
||||
*
|
||||
* Operation of the pseudo-NIC (PNIC) is pretty simple. To write a
|
||||
* command plus data, first write the length of the data to
|
||||
* PNIC_REG_LEN, then write the data a byte at a type to
|
||||
* PNIC_REG_DATA, then write the command code to PNIC_REG_CMD. The
|
||||
* status will be available from PNIC_REG_STAT. The length of any
|
||||
* data returned will be in PNIC_REG_LEN and can be read a byte at a
|
||||
* time from PNIC_REG_DATA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* PCI parameters
|
||||
*/
|
||||
#define PNIC_PCI_VENDOR 0xfefe /* Hopefully these won't clash with */
|
||||
#define PNIC_PCI_DEVICE 0xefef /* any real PCI device IDs. */
|
||||
|
||||
/*
|
||||
* 'Hardware' register addresses, offset from io_base
|
||||
*/
|
||||
#define PNIC_REG_CMD 0x00 /* Command register, 2 bytes, write only */
|
||||
#define PNIC_REG_STAT 0x00 /* Status register, 2 bytes, read only */
|
||||
#define PNIC_REG_LEN 0x02 /* Length register, 2 bytes, read-write */
|
||||
#define PNIC_REG_DATA 0x04 /* Data port, 1 byte, read-write */
|
||||
/*
|
||||
* PNIC_MAX_REG used in Bochs to claim i/o space
|
||||
*/
|
||||
#define PNIC_MAX_REG 0x04
|
||||
|
||||
/*
|
||||
* Command code definitions: write these into PNIC_REG_CMD
|
||||
*/
|
||||
#define PNIC_CMD_NOOP 0x0000
|
||||
#define PNIC_CMD_API_VER 0x0001
|
||||
#define PNIC_CMD_READ_MAC 0x0002
|
||||
#define PNIC_CMD_RESET 0x0003
|
||||
#define PNIC_CMD_XMIT 0x0004
|
||||
#define PNIC_CMD_RECV 0x0005
|
||||
#define PNIC_CMD_RECV_QLEN 0x0006
|
||||
#define PNIC_CMD_MASK_IRQ 0x0007
|
||||
#define PNIC_CMD_FORCE_IRQ 0x0008
|
||||
|
||||
/*
|
||||
* Status code definitions: read these from PNIC_REG_STAT
|
||||
*
|
||||
* We avoid using status codes that might be confused with
|
||||
* randomly-read data (e.g. 0x0000, 0xffff etc.)
|
||||
*/
|
||||
#define PNIC_STATUS_OK 0x4f4b /* 'OK' */
|
||||
#define PNIC_STATUS_UNKNOWN_CMD 0x3f3f /* '??' */
|
||||
|
||||
/*
|
||||
* Other miscellaneous information
|
||||
*/
|
||||
|
||||
#define PNIC_API_VERSION 0x0101 /* 1.1 */
|
||||
3688
bochs/iodev/sb16.cc
Normal file
3688
bochs/iodev/sb16.cc
Normal file
File diff suppressed because it is too large
Load Diff
378
bochs/iodev/sb16.h
Normal file
378
bochs/iodev/sb16.h
Normal file
@ -0,0 +1,378 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// The original version of the SB16 support written and donated by Josef Drexler
|
||||
|
||||
#ifndef BX_IODEV_SB16_H
|
||||
#define BX_IODEV_SB16_H
|
||||
|
||||
#if BX_USE_SB16_SMF
|
||||
# define BX_SB16_SMF static
|
||||
# define BX_SB16_THIS theSB16Device->
|
||||
# define BX_SB16_THISP (theSB16Device)
|
||||
#else
|
||||
# define BX_SB16_SMF
|
||||
# define BX_SB16_THIS this->
|
||||
# define BX_SB16_THISP (this)
|
||||
#endif
|
||||
|
||||
// If the buffer commands are to be inlined:
|
||||
#define BX_SB16_BUFINL BX_CPP_INLINE
|
||||
// BX_CPP_INLINE is defined to the inline keyword for the C++ compiler.
|
||||
|
||||
// maximum number of patch translations
|
||||
#define BX_SB16_PATCHTABLESIZE 1024
|
||||
|
||||
// the resources. Of these, IRQ and DMA's can be changed via a DSP command
|
||||
#define BX_SB16_IO 0x220 // IO base address of DSP, mixer & FM part
|
||||
#define BX_SB16_IOLEN 16 // number of addresses covered
|
||||
#define BX_SB16_IOMPU 0x330 // IO base address of MPU402 part
|
||||
#define BX_SB16_IOMPULEN 4 // number of addresses covered
|
||||
#define BX_SB16_IOADLIB 0x388 // equivalent to 0x220..0x223 and 0x228..0x229
|
||||
#define BX_SB16_IOADLIBLEN 4 // number of addresses covered
|
||||
#define BX_SB16_IRQ theSB16Device->currentirq
|
||||
#define BX_SB16_IRQMPU BX_SB16_IRQ // IRQ for the MPU401 part - same value
|
||||
#define BX_SB16_DMAL theSB16Device->currentdma8
|
||||
#define BX_SB16_DMAH theSB16Device->currentdma16
|
||||
|
||||
/*
|
||||
A few notes:
|
||||
IRQ, DMA8bit and DMA16bit are for the DSP part. These
|
||||
are changeable at runtime in mixer registers 0x80 and 0x81.
|
||||
The defaults after a mixer initialization are IRQ 5, DMA8 1, no DMA16
|
||||
|
||||
Any of the address lengths can be zero to disable that particular
|
||||
subdevice. Turning off the DSP still leaves FM music enabled on the
|
||||
BX_SB16_IOADLIB ports, unless those are disabled as well.
|
||||
|
||||
BX_SB16_IOMPULEN should be 4 or 2. In the latter case, the emulator
|
||||
is completely invisible, and runtime changes are not possible
|
||||
|
||||
BX_SB16_IOADLIBLEN should be 2 or 4. If 0, Ports 0x388.. don't
|
||||
get used, but the OPL2 can still be accessed at 0x228..0x229.
|
||||
If 2, the usual Adlib emulation is enabled. If 4, an OPL3 is
|
||||
emulated at adresses 0x388..0x38b, or two separate OPL2's.
|
||||
*/
|
||||
|
||||
#define BX_SB16_MIX_REG 0x100 // total number of mixer registers
|
||||
|
||||
// The array containing an instrument/bank remapping
|
||||
struct bx_sb16_ins_map {
|
||||
Bit8u oldbankmsb, oldbanklsb, oldprogch;
|
||||
Bit8u newbankmsb, newbanklsb, newprogch;
|
||||
};
|
||||
|
||||
// One operator of the FM emulation
|
||||
#define BX_SB16_FM_NOP 36 // OPL3 has 36 operators
|
||||
#define BX_SB16_FM_OPB 6 // one operator has 6 bytes
|
||||
typedef Bit8u bx_sb16_fm_operator[BX_SB16_FM_OPB];
|
||||
/* Explanation of the values:
|
||||
(note [xx] is one bit for xx; [5 xx] is five bits for xx,
|
||||
all bits listed MSB to LSB)
|
||||
|
||||
[0] = [Tremolo][Vibrato][Sustain][KSR][4 Frequency Multiply]
|
||||
[1] = [2 Key Scale Level][6 Output Level for modulators, reserved for others]
|
||||
[2] = [4 Attack Rate][4 Decay Rate]
|
||||
[3] = [4 Sustain Level][4 Release Rate]
|
||||
[4] = [2 reserved][Right][Left][3 Feedback Factor][SynthType]
|
||||
[5] = [5 reserved][3 Waveform Select]
|
||||
|
||||
Frequency and Output Level are really properties of the channel,
|
||||
so they get stored there. However, Output Level of the modulator
|
||||
in FM synthesis varies the instrument.
|
||||
|
||||
[4] is only set for the first operator, and zeroed for the others.
|
||||
|
||||
All reserved bits are zeroed.
|
||||
*/
|
||||
|
||||
// One channel (1 to 4 operators)
|
||||
#define BX_SB16_FM_NCH 18 // OPL3 has at most 18 channels
|
||||
|
||||
typedef struct {
|
||||
int nop; // number of operators used: 0=disabled, 1=percussion, 2 or 4=melodic
|
||||
int ncarr; // how many carriers this channel has (1..3)
|
||||
int opnum[4]; // operator numbers
|
||||
Bit16u freq; // frequency (in a special code)
|
||||
Bit32u afreq; // actual frequency in milli-Hertz (10^-3 Hz)
|
||||
Bit8u midichan; // assigned midi channel
|
||||
bx_bool needprogch; // has the instrument changed
|
||||
Bit8u midinote; // currently playing midi note
|
||||
bx_bool midion; // is the note on
|
||||
Bit16u midibend; // current value of the pitch bender
|
||||
Bit8u outputlevel[4];// 6-bit output level attenuations
|
||||
Bit8u midivol; // current midi volume (velocity)
|
||||
} bx_sb16_fm_channel;
|
||||
|
||||
|
||||
// This is the class for the input and
|
||||
// output FIFO buffers of the SB16
|
||||
|
||||
class bx_sb16_buffer {
|
||||
public:
|
||||
|
||||
BX_SB16_BUFINL bx_sb16_buffer(void);
|
||||
BX_SB16_BUFINL ~bx_sb16_buffer();
|
||||
BX_SB16_BUFINL void init(int bufferlen);
|
||||
BX_SB16_BUFINL void reset();
|
||||
|
||||
/* These functions return 1 on success and 0 on error */
|
||||
BX_SB16_BUFINL bx_bool put(Bit8u data); // write one byte in the buffer
|
||||
BX_SB16_BUFINL bx_bool puts(const char *data, ...); // write a formatted string to the buffer
|
||||
BX_SB16_BUFINL bx_bool get(Bit8u *data); // read the next available byte
|
||||
BX_SB16_BUFINL bx_bool getw(Bit16u *data); // get word, in order lo/hi
|
||||
BX_SB16_BUFINL bx_bool getw1(Bit16u *data);// get word, in order hi/lo
|
||||
BX_SB16_BUFINL bx_bool full(void); // is the buffer full?
|
||||
BX_SB16_BUFINL bx_bool empty(void); // is it empty?
|
||||
|
||||
BX_SB16_BUFINL void flush(void); // empty the buffer
|
||||
BX_SB16_BUFINL int bytes(void); // return number of bytes in the buffer
|
||||
BX_SB16_BUFINL Bit8u peek(int ahead); // peek ahead number of bytes
|
||||
|
||||
/* These are for caching the command number */
|
||||
BX_SB16_BUFINL void newcommand(Bit8u newcmd, int bytes); // start a new command with length bytes
|
||||
BX_SB16_BUFINL Bit8u currentcommand(void); // return the current command
|
||||
BX_SB16_BUFINL void clearcommand(void); // clear the command
|
||||
BX_SB16_BUFINL bx_bool commanddone(void); // return if all bytes have arrived
|
||||
BX_SB16_BUFINL bx_bool hascommand(void); // return if there is a pending command
|
||||
BX_SB16_BUFINL int commandbytes(void); // return the length of the command
|
||||
|
||||
|
||||
private:
|
||||
Bit8u *buffer;
|
||||
int head,tail,length;
|
||||
Bit8u command;
|
||||
bx_bool havecommand;
|
||||
int bytesneeded;
|
||||
};
|
||||
|
||||
|
||||
// forward definition
|
||||
class bx_sound_output_c;
|
||||
|
||||
// The actual emulator class, emulating the sound blaster ports
|
||||
class bx_sb16_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_sb16_c();
|
||||
virtual ~bx_sb16_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
virtual void after_restore_state(void);
|
||||
|
||||
/* Make writelog available to output functions */
|
||||
BX_SB16_SMF void writelog(int loglev, const char *str, ...);
|
||||
// return midimode and wavemode setting (for lowlevel output class)
|
||||
int get_midimode() const {return midimode;}
|
||||
int get_wavemode() const {return wavemode;}
|
||||
// runtimer parameter handler
|
||||
static Bit64s sb16_param_handler(bx_param_c *param, int set, Bit64s val);
|
||||
|
||||
private:
|
||||
|
||||
int midimode, wavemode, loglevel;
|
||||
Bit32u dmatimer;
|
||||
FILE *logfile, *midifile, *wavefile; // the output files or devices
|
||||
bx_sound_output_c *soundmod;// the output class
|
||||
int currentirq;
|
||||
int currentdma8;
|
||||
int currentdma16;
|
||||
|
||||
// the MPU 401 relevant variables
|
||||
struct bx_sb16_mpu_struct {
|
||||
bx_sb16_buffer datain, dataout, cmd, midicmd;
|
||||
bx_bool uartmode, irqpending, forceuartmode, singlecommand;
|
||||
|
||||
int banklsb[BX_SB16_PATCHTABLESIZE];
|
||||
int bankmsb[BX_SB16_PATCHTABLESIZE]; // current patch lists
|
||||
int program[BX_SB16_PATCHTABLESIZE];
|
||||
|
||||
int timer_handle, current_timer; // no. of delta times passed
|
||||
Bit32u last_delta_time; // timer value at last command
|
||||
bx_bool outputinit;
|
||||
} mpu401;
|
||||
|
||||
// the DSP variables
|
||||
struct bx_sb16_dsp_struct {
|
||||
bx_sb16_buffer datain, dataout;
|
||||
Bit8u resetport; // last value written to the reset port
|
||||
Bit8u speaker,prostereo; // properties of the sound input/output
|
||||
bx_bool irqpending; // Is an IRQ pending (not ack'd)
|
||||
bx_bool midiuartmode; // Is the DSP in MIDI UART mode
|
||||
Bit8u testreg;
|
||||
struct bx_sb16_dsp_dma_struct {
|
||||
// Properties of the current DMA transfer:
|
||||
// mode= 0: no transfer, 1: single-cycle transfer, 2: auto-init DMA
|
||||
// bits= 8 or 16
|
||||
// fifo= ?? Bit used in DMA command, no idea what it means...
|
||||
// output= 0: input, 1: output
|
||||
// bps= bytes per sample; =(dmabits/8)*(dmastereo+1)
|
||||
// stereo= 0: mono, 1: stereo
|
||||
// issigned= 0: unsigned data, 1: signed data
|
||||
// highspeed= 0: normal mode, 1: highspeed mode (only SBPro)
|
||||
// timer= so many us between data bytes
|
||||
int mode, bits, bps, format, timer;
|
||||
bx_bool fifo, output, stereo, issigned, highspeed;
|
||||
Bit16u count; // bytes remaining in this transfer
|
||||
Bit8u *chunk; // buffers up to BX_SOUND_OUTPUT_WAVEPACKETSIZE bytes
|
||||
int chunkindex; // index into the buffer
|
||||
int chunkcount; // for input: size of the recorded input
|
||||
Bit16u timeconstant;
|
||||
Bit16u blocklength, samplerate;
|
||||
} dma;
|
||||
int timer_handle; // handle for the DMA timer
|
||||
bx_bool outputinit; // have the output functions been initialized
|
||||
} dsp;
|
||||
|
||||
// the ASP/CSP registers
|
||||
Bit8u csp_reg[256];
|
||||
|
||||
enum bx_sb16_fm_mode {single, adlib, dual, opl3, fminit};
|
||||
|
||||
// the variables common to all FM emulations
|
||||
struct bx_sb16_opl_struct;
|
||||
friend struct bx_sb16_opl_struct;
|
||||
struct bx_sb16_opl_struct {
|
||||
bx_sb16_fm_mode mode;
|
||||
// modes: single: one OPL2 (OPL3 disabled),
|
||||
// adlib: one OPL2 (no OPL3),
|
||||
// dual: two seperate OPL2
|
||||
// opl3: one OPL3 (enabled)
|
||||
|
||||
int timer_handle;
|
||||
int timer_running;
|
||||
Bit16u midichannels; // bitmask: unused midichannels
|
||||
int drumchannel; // midi channel for percussion (10)
|
||||
int index[2]; // index register for the two chips
|
||||
int wsenable[2]; // wave form select enable
|
||||
Bit16u timer[4]; // two timers on each chip
|
||||
Bit16u timerinit[4]; // initial timer counts
|
||||
int tmask[2]; // the timer masking byte for both chips
|
||||
int tflag[2]; // shows if the timer overflow has occured
|
||||
int percmode[2]; // percussion mode enabled
|
||||
int cyhhnote[2]; // cymbal and high hat midi notes
|
||||
int cyhhon[2]; // cymbal and high hat notes on
|
||||
bx_sb16_fm_operator oper[BX_SB16_FM_NOP];
|
||||
bx_sb16_fm_channel chan[BX_SB16_FM_NCH];
|
||||
} opl;
|
||||
|
||||
struct bx_sb16_mixer_struct {
|
||||
Bit8u regindex;
|
||||
Bit8u reg[BX_SB16_MIX_REG];
|
||||
} mixer;
|
||||
|
||||
struct bx_sb16_emul_struct {
|
||||
bx_sb16_buffer datain, dataout;
|
||||
bx_sb16_ins_map remaplist[256];
|
||||
Bit16u remaps;
|
||||
} emuldata;
|
||||
|
||||
/* DMA input and output, 8 and 16 bit */
|
||||
BX_SB16_SMF void dma_write8(Bit8u *data_byte);
|
||||
BX_SB16_SMF void dma_read8(Bit8u *data_byte);
|
||||
BX_SB16_SMF void dma_write16(Bit16u *data_word);
|
||||
BX_SB16_SMF void dma_read16(Bit16u *data_word);
|
||||
|
||||
/* the MPU 401 part of the emulator */
|
||||
BX_SB16_SMF Bit32u mpu_status(); // read status port 3x1
|
||||
BX_SB16_SMF void mpu_command(Bit32u value); // write command port 3x1
|
||||
BX_SB16_SMF Bit32u mpu_dataread(); // read data port 3x0
|
||||
BX_SB16_SMF void mpu_datawrite(Bit32u value); // write data port 3x0
|
||||
BX_SB16_SMF void mpu_mididata(Bit32u value); // get a midi byte
|
||||
static void mpu_timer (void *);
|
||||
|
||||
/* The DSP part */
|
||||
BX_SB16_SMF void dsp_reset(Bit32u value); // write to reset port 2x6
|
||||
BX_SB16_SMF Bit32u dsp_dataread(); // read from data port 2xa
|
||||
BX_SB16_SMF void dsp_datawrite(Bit32u value); // write to data port 2xa
|
||||
BX_SB16_SMF Bit32u dsp_bufferstatus(); // read buffer status 2xc
|
||||
BX_SB16_SMF Bit32u dsp_status(); // read dsp status 2xe
|
||||
BX_SB16_SMF void dsp_getsamplebyte(Bit8u value);
|
||||
BX_SB16_SMF Bit8u dsp_putsamplebyte();
|
||||
BX_SB16_SMF void dsp_sendwavepacket();
|
||||
BX_SB16_SMF void dsp_getwavepacket();
|
||||
BX_SB16_SMF Bit32u dsp_irq16ack(); // ack 16 bit IRQ 2xf
|
||||
BX_SB16_SMF void dsp_dma(Bit8u command, Bit8u mode, Bit16u length, Bit8u comp);
|
||||
// initiate a DMA transfer
|
||||
BX_SB16_SMF void dsp_dmadone(); // stop a DMA transfer
|
||||
BX_SB16_SMF void dsp_enabledma(); // enable the transfer
|
||||
BX_SB16_SMF void dsp_disabledma(); // temporarily disable DMA
|
||||
static void dsp_dmatimer (void *);
|
||||
|
||||
/* The mixer part */
|
||||
BX_SB16_SMF Bit32u mixer_readdata(void);
|
||||
BX_SB16_SMF void mixer_writedata(Bit32u value);
|
||||
BX_SB16_SMF void mixer_writeregister(Bit32u value);
|
||||
BX_SB16_SMF void set_irq_dma();
|
||||
|
||||
/* The emulator ports to change emulator properties */
|
||||
BX_SB16_SMF Bit32u emul_read (void); // read emulator port
|
||||
BX_SB16_SMF void emul_write(Bit32u value); // write emulator port
|
||||
|
||||
/* The FM emulation part */
|
||||
BX_SB16_SMF void opl_entermode(bx_sb16_fm_mode newmode);
|
||||
BX_SB16_SMF Bit32u opl_status(int chipid);
|
||||
BX_SB16_SMF void opl_index(Bit32u value, int chipid);
|
||||
BX_SB16_SMF void opl_data(Bit32u value, int chipid);
|
||||
static void opl_timer(void *);
|
||||
BX_SB16_SMF void opl_timerevent(void);
|
||||
BX_SB16_SMF void opl_changeop(int channum, int opernum, int byte, int value);
|
||||
BX_SB16_SMF void opl_settimermask(int value, int chipid);
|
||||
BX_SB16_SMF void opl_set4opmode(int new4opmode);
|
||||
BX_SB16_SMF void opl_setmodulation(int channel);
|
||||
BX_SB16_SMF void opl_setpercussion(Bit8u value, int chipid);
|
||||
BX_SB16_SMF void opl_setvolume(int channel, int opnum, int outlevel);
|
||||
BX_SB16_SMF void opl_setfreq(int channel);
|
||||
BX_SB16_SMF void opl_keyonoff(int channel, bx_bool onoff);
|
||||
BX_SB16_SMF void opl_midichannelinit(int channel);
|
||||
|
||||
/* several high level sound handlers */
|
||||
BX_SB16_SMF int currentdeltatime();
|
||||
BX_SB16_SMF void processmidicommand(bx_bool force);
|
||||
BX_SB16_SMF void midiremapprogram(int channel); // remap program change
|
||||
BX_SB16_SMF int converttodeltatime(Bit32u deltatime, Bit8u value[4]);
|
||||
BX_SB16_SMF void writemidicommand(int command, int length, Bit8u data[]);
|
||||
BX_SB16_SMF void writedeltatime(Bit32u deltatime);
|
||||
// write in delta time coding
|
||||
|
||||
BX_SB16_SMF void initmidifile(); // Write midi file header
|
||||
BX_SB16_SMF void finishmidifile(); // write track length etc.
|
||||
BX_SB16_SMF void initvocfile(); // Write voc file header
|
||||
BX_SB16_SMF void writevocblock(int block, Bit32u headerlen, Bit8u header[],
|
||||
Bit32u datalen, Bit8u data[]);
|
||||
BX_SB16_SMF void finishvocfile(); // close voc file
|
||||
|
||||
/* The port IO multiplexer functions */
|
||||
|
||||
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_SB16_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define BOTHLOG(x) (x)
|
||||
#define WRITELOG (BX_SB16_THIS writelog)
|
||||
#define MIDILOG(x) ((BX_SB16_THIS midimode>0?x:0x7f))
|
||||
#define WAVELOG(x) ((BX_SB16_THIS wavemode>0?x:0x7f))
|
||||
|
||||
#endif
|
||||
772
bochs/iodev/scancodes.cc
Normal file
772
bochs/iodev/scancodes.cc
Normal file
@ -0,0 +1,772 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "bochs.h"
|
||||
#include "scancodes.h"
|
||||
|
||||
unsigned char translation8042[256] = {
|
||||
0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
|
||||
0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
|
||||
0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
|
||||
0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
|
||||
0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
|
||||
0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
|
||||
0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
|
||||
0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54,
|
||||
0x80,0x81,0x82,0x41,0x54,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
|
||||
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
|
||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
|
||||
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
|
||||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
|
||||
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
|
||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
|
||||
};
|
||||
|
||||
|
||||
// Definition of scancodes make and break,
|
||||
// for each set (mf1/xt , mf2/at , mf3/ps2)
|
||||
// The table must be in BX_KEY order
|
||||
//
|
||||
scancode scancodes[BX_KEY_NBKEYS][3] =
|
||||
{
|
||||
{ // BX_KEY_CTRL_L ( ibm 58)
|
||||
{ "\x1D" , "\x9D" },
|
||||
{ "\x14" , "\xF0\x14" },
|
||||
{ "\x11" , "\xF0\x11" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SHIFT_L ( ibm 44)
|
||||
{ "\x2A" , "\xAA" },
|
||||
{ "\x12" , "\xF0\x12" },
|
||||
{ "\x12" , "\xF0\x12" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F1 ( ibm 112 )
|
||||
{ "\x3B" , "\xBB" },
|
||||
{ "\x05" , "\xF0\x05" },
|
||||
{ "\x07" , "\xF0\x07" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F2 ( ibm 113 )
|
||||
{ "\x3C" , "\xBC" },
|
||||
{ "\x06" , "\xF0\x06" },
|
||||
{ "\x0F" , "\xF0\x0F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F3 ( ibm 114 )
|
||||
{ "\x3D" , "\xBD" },
|
||||
{ "\x04" , "\xF0\x04" },
|
||||
{ "\x17" , "\xF0\x17" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F4 ( ibm 115 )
|
||||
{ "\x3E" , "\xBE" },
|
||||
{ "\x0C" , "\xF0\x0C" },
|
||||
{ "\x1F" , "\xF0\x1F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F5 ( ibm 116 )
|
||||
{ "\x3F" , "\xBF" },
|
||||
{ "\x03" , "\xF0\x03" },
|
||||
{ "\x27" , "\xF0\x27" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F6 ( ibm 117 )
|
||||
{ "\x40" , "\xC0" },
|
||||
{ "\x0B" , "\xF0\x0B" },
|
||||
{ "\x2F" , "\xF0\x2F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F7 ( ibm 118 )
|
||||
{ "\x41" , "\xC1" },
|
||||
{ "\x83" , "\xF0\x83" },
|
||||
{ "\x37" , "\xF0\x37" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F8 ( ibm 119 )
|
||||
{ "\x42" , "\xC2" },
|
||||
{ "\x0A" , "\xF0\x0A" },
|
||||
{ "\x3F" , "\xF0\x3F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F9 ( ibm 120 )
|
||||
{ "\x43" , "\xC3" },
|
||||
{ "\x01" , "\xF0\x01" },
|
||||
{ "\x47" , "\xF0\x47" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F10 ( ibm 121 )
|
||||
{ "\x44" , "\xC4" },
|
||||
{ "\x09" , "\xF0\x09" },
|
||||
{ "\x4F" , "\xF0\x4F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F11 ( ibm 122 )
|
||||
{ "\x57" , "\xD7" },
|
||||
{ "\x78" , "\xF0\x78" },
|
||||
{ "\x56" , "\xF0\x56" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F12 ( ibm 123 )
|
||||
{ "\x58" , "\xD8" },
|
||||
{ "\x07" , "\xF0\x07" },
|
||||
{ "\x5E" , "\xF0\x5E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_CTRL_R ( ibm 64 )
|
||||
{ "\xE0\x1D" , "\xE0\x9D" },
|
||||
{ "\xE0\x14" , "\xE0\xF0\x14" },
|
||||
{ "\x58" , "\xF0\x58" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SHIFT_R ( ibm 57 )
|
||||
{ "\x36" , "\xB6" },
|
||||
{ "\x59" , "\xF0\x59" },
|
||||
{ "\x59" , "\xF0\x59" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_CAPS_LOCK ( ibm 30 )
|
||||
{ "\x3A" , "\xBA" },
|
||||
{ "\x58" , "\xF0\x58" },
|
||||
{ "\x14" , "\xF0\x14" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_NUM_LOCK ( ibm 90 )
|
||||
{ "\x45" , "\xC5" },
|
||||
{ "\x77" , "\xF0\x77" },
|
||||
{ "\x76" , "\xF0\x76" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_ALT_L ( ibm 60 )
|
||||
{ "\x38" , "\xB8" },
|
||||
{ "\x11" , "\xF0\x11" },
|
||||
{ "\x19" , "\xF0\x19" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_ALT_R ( ibm 62 )
|
||||
{ "\xE0\x38" , "\xE0\xB8" },
|
||||
{ "\xE0\x11" , "\xE0\xF0\x11" },
|
||||
{ "\x39" , "\xF0\x39" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_A ( ibm 31 )
|
||||
{ "\x1E" , "\x9E" },
|
||||
{ "\x1C" , "\xF0\x1C" },
|
||||
{ "\x1C" , "\xF0\x1C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_B ( ibm 50 )
|
||||
{ "\x30" , "\xB0" },
|
||||
{ "\x32" , "\xF0\x32" },
|
||||
{ "\x32" , "\xF0\x32" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_C ( ibm 48 )
|
||||
{ "\x2E" , "\xAE" },
|
||||
{ "\x21" , "\xF0\x21" },
|
||||
{ "\x21" , "\xF0\x21" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_D ( ibm 33 )
|
||||
{ "\x20" , "\xA0" },
|
||||
{ "\x23" , "\xF0\x23" },
|
||||
{ "\x23" , "\xF0\x23" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_E ( ibm 19 )
|
||||
{ "\x12" , "\x92" },
|
||||
{ "\x24" , "\xF0\x24" },
|
||||
{ "\x24" , "\xF0\x24" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_F ( ibm 34 )
|
||||
{ "\x21" , "\xA1" },
|
||||
{ "\x2B" , "\xF0\x2B" },
|
||||
{ "\x2B" , "\xF0\x2B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_G ( ibm 35 )
|
||||
{ "\x22" , "\xA2" },
|
||||
{ "\x34" , "\xF0\x34" },
|
||||
{ "\x34" , "\xF0\x34" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_H ( ibm 36 )
|
||||
{ "\x23" , "\xA3" },
|
||||
{ "\x33" , "\xF0\x33" },
|
||||
{ "\x33" , "\xF0\x33" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_I ( ibm 24 )
|
||||
{ "\x17" , "\x97" },
|
||||
{ "\x43" , "\xF0\x43" },
|
||||
{ "\x43" , "\xF0\x43" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_J ( ibm 37 )
|
||||
{ "\x24" , "\xA4" },
|
||||
{ "\x3B" , "\xF0\x3B" },
|
||||
{ "\x3B" , "\xF0\x3B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_K ( ibm 38 )
|
||||
{ "\x25" , "\xA5" },
|
||||
{ "\x42" , "\xF0\x42" },
|
||||
{ "\x42" , "\xF0\x42" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_L ( ibm 39 )
|
||||
{ "\x26" , "\xA6" },
|
||||
{ "\x4B" , "\xF0\x4B" },
|
||||
{ "\x4B" , "\xF0\x4B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_M ( ibm 52 )
|
||||
{ "\x32" , "\xB2" },
|
||||
{ "\x3A" , "\xF0\x3A" },
|
||||
{ "\x3A" , "\xF0\x3A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_N ( ibm 51 )
|
||||
{ "\x31" , "\xB1" },
|
||||
{ "\x31" , "\xF0\x31" },
|
||||
{ "\x31" , "\xF0\x31" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_O ( ibm 25 )
|
||||
{ "\x18" , "\x98" },
|
||||
{ "\x44" , "\xF0\x44" },
|
||||
{ "\x44" , "\xF0\x44" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_P ( ibm 26 )
|
||||
{ "\x19" , "\x99" },
|
||||
{ "\x4D" , "\xF0\x4D" },
|
||||
{ "\x4D" , "\xF0\x4D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_Q ( ibm 17 )
|
||||
{ "\x10" , "\x90" },
|
||||
{ "\x15" , "\xF0\x15" },
|
||||
{ "\x15" , "\xF0\x15" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_R ( ibm 20 )
|
||||
{ "\x13" , "\x93" },
|
||||
{ "\x2D" , "\xF0\x2D" },
|
||||
{ "\x2D" , "\xF0\x2D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_S ( ibm 32 )
|
||||
{ "\x1F" , "\x9F" },
|
||||
{ "\x1B" , "\xF0\x1B" },
|
||||
{ "\x1B" , "\xF0\x1B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_T ( ibm 21 )
|
||||
{ "\x14" , "\x94" },
|
||||
{ "\x2C" , "\xF0\x2C" },
|
||||
{ "\x2C" , "\xF0\x2C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_U ( ibm 23 )
|
||||
{ "\x16" , "\x96" },
|
||||
{ "\x3C" , "\xF0\x3C" },
|
||||
{ "\x3C" , "\xF0\x3C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_V ( ibm 49 )
|
||||
{ "\x2F" , "\xAF" },
|
||||
{ "\x2A" , "\xF0\x2A" },
|
||||
{ "\x2A" , "\xF0\x2A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_W ( ibm 18 )
|
||||
{ "\x11" , "\x91" },
|
||||
{ "\x1D" , "\xF0\x1D" },
|
||||
{ "\x1D" , "\xF0\x1D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_X ( ibm 47 )
|
||||
{ "\x2D" , "\xAD" },
|
||||
{ "\x22" , "\xF0\x22" },
|
||||
{ "\x22" , "\xF0\x22" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_Y ( ibm 22 )
|
||||
{ "\x15" , "\x95" },
|
||||
{ "\x35" , "\xF0\x35" },
|
||||
{ "\x35" , "\xF0\x35" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_Z ( ibm 46 )
|
||||
{ "\x2C" , "\xAC" },
|
||||
{ "\x1A" , "\xF0\x1A" },
|
||||
{ "\x1A" , "\xF0\x1A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_0 ( ibm 11 )
|
||||
{ "\x0B" , "\x8B" },
|
||||
{ "\x45" , "\xF0\x45" },
|
||||
{ "\x45" , "\xF0\x45" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_1 ( ibm 2 )
|
||||
{ "\x02" , "\x82" },
|
||||
{ "\x16" , "\xF0\x16" },
|
||||
{ "\x16" , "\xF0\x16" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_2 ( ibm 3 )
|
||||
{ "\x03" , "\x83" },
|
||||
{ "\x1E" , "\xF0\x1E" },
|
||||
{ "\x1E" , "\xF0\x1E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_3 ( ibm 4 )
|
||||
{ "\x04" , "\x84" },
|
||||
{ "\x26" , "\xF0\x26" },
|
||||
{ "\x26" , "\xF0\x26" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_4 ( ibm 5 )
|
||||
{ "\x05" , "\x85" },
|
||||
{ "\x25" , "\xF0\x25" },
|
||||
{ "\x25" , "\xF0\x25" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_5 ( ibm 6 )
|
||||
{ "\x06" , "\x86" },
|
||||
{ "\x2E" , "\xF0\x2E" },
|
||||
{ "\x2E" , "\xF0\x2E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_6 ( ibm 7 )
|
||||
{ "\x07" , "\x87" },
|
||||
{ "\x36" , "\xF0\x36" },
|
||||
{ "\x36" , "\xF0\x36" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_7 ( ibm 8 )
|
||||
{ "\x08" , "\x88" },
|
||||
{ "\x3D" , "\xF0\x3D" },
|
||||
{ "\x3D" , "\xF0\x3D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_8 ( ibm 9 )
|
||||
{ "\x09" , "\x89" },
|
||||
{ "\x3E" , "\xF0\x3E" },
|
||||
{ "\x3E" , "\xF0\x3E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_9 ( ibm 10 )
|
||||
{ "\x0A" , "\x8A" },
|
||||
{ "\x46" , "\xF0\x46" },
|
||||
{ "\x46" , "\xF0\x46" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_ESC ( ibm 110 )
|
||||
{ "\x01" , "\x81" },
|
||||
{ "\x76" , "\xF0\x76" },
|
||||
{ "\x08" , "\xF0\x08" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SPACE ( ibm 61 )
|
||||
{ "\x39" , "\xB9" },
|
||||
{ "\x29" , "\xF0\x29" },
|
||||
{ "\x29" , "\xF0\x29" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SINGLE_QUOTE ( ibm 41 )
|
||||
{ "\x28" , "\xA8" },
|
||||
{ "\x52" , "\xF0\x52" },
|
||||
{ "\x52" , "\xF0\x52" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_COMMA ( ibm 53 )
|
||||
{ "\x33" , "\xB3" },
|
||||
{ "\x41" , "\xF0\x41" },
|
||||
{ "\x41" , "\xF0\x41" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_PERIOD ( ibm 54 )
|
||||
{ "\x34" , "\xB4" },
|
||||
{ "\x49" , "\xF0\x49" },
|
||||
{ "\x49" , "\xF0\x49" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SLASH ( ibm 55 )
|
||||
{ "\x35" , "\xB5" },
|
||||
{ "\x4A" , "\xF0\x4A" },
|
||||
{ "\x4A" , "\xF0\x4A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SEMICOLON ( ibm 40 )
|
||||
{ "\x27" , "\xA7" },
|
||||
{ "\x4C" , "\xF0\x4C" },
|
||||
{ "\x4C" , "\xF0\x4C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_EQUALS ( ibm 13 )
|
||||
{ "\x0D" , "\x8D" },
|
||||
{ "\x55" , "\xF0\x55" },
|
||||
{ "\x55" , "\xF0\x55" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_LEFT_BRACKET ( ibm 27 )
|
||||
{ "\x1A" , "\x9A" },
|
||||
{ "\x54" , "\xF0\x54" },
|
||||
{ "\x54" , "\xF0\x54" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_BACKSLASH ( ibm 42, 29)
|
||||
{ "\x2B" , "\xAB" },
|
||||
{ "\x5D" , "\xF0\x5D" },
|
||||
{ "\x53" , "\xF0\x53" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_RIGHT_BRACKET ( ibm 28 )
|
||||
{ "\x1B" , "\x9B" },
|
||||
{ "\x5B" , "\xF0\x5B" },
|
||||
{ "\x5B" , "\xF0\x5B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_MINUS ( ibm 12 )
|
||||
{ "\x0C" , "\x8C" },
|
||||
{ "\x4E" , "\xF0\x4E" },
|
||||
{ "\x4E" , "\xF0\x4E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_GRAVE ( ibm 1 )
|
||||
{ "\x29" , "\xA9" },
|
||||
{ "\x0E" , "\xF0\x0E" },
|
||||
{ "\x0E" , "\xF0\x0E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_BACKSPACE ( ibm 15 )
|
||||
{ "\x0E" , "\x8E" },
|
||||
{ "\x66" , "\xF0\x66" },
|
||||
{ "\x66" , "\xF0\x66" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_ENTER ( ibm 43 )
|
||||
{ "\x1C" , "\x9C" },
|
||||
{ "\x5A" , "\xF0\x5A" },
|
||||
{ "\x5A" , "\xF0\x5A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_TAB ( ibm 16 )
|
||||
{ "\x0F" , "\x8F" },
|
||||
{ "\x0D" , "\xF0\x0D" },
|
||||
{ "\x0D" , "\xF0\x0D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_LEFT_BACKSLASH ( ibm 45 )
|
||||
{ "\x56" , "\xD6" },
|
||||
{ "\x61" , "\xF0\x61" },
|
||||
{ "\x13" , "\xF0\x13" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_PRINT ( ibm 124 )
|
||||
{ "\xE0\x2A\xE0\x37" , "\xE0\xB7\xE0\xAA" },
|
||||
{ "\xE0\x12\xE0\x7C" , "\xE0\xF0\x7C\xE0\xF0\x12" },
|
||||
{ "\x57" , "\xF0\x57" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_SCRL_LOCK ( ibm 125 )
|
||||
{ "\x46" , "\xC6" },
|
||||
{ "\x7E" , "\xF0\x7E" },
|
||||
{ "\x5F" , "\xF0\x5F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_PAUSE ( ibm 126 )
|
||||
{ "\xE1\x1D\x45\xE1\x9D\xC5" , "" },
|
||||
{ "\xE1\x14\x77\xE1\xF0\x14\xF0\x77" , "" },
|
||||
{ "\x62" , "\xF0\x62" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INSERT ( ibm 75 )
|
||||
{ "\xE0\x52" , "\xE0\xD2" },
|
||||
{ "\xE0\x70" , "\xE0\xF0\x70" },
|
||||
{ "\x67" , "\xF0\x67" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_DELETE ( ibm 76 )
|
||||
{ "\xE0\x53" , "\xE0\xD3" },
|
||||
{ "\xE0\x71" , "\xE0\xF0\x71" },
|
||||
{ "\x64" , "\xF0\x64" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_HOME ( ibm 80 )
|
||||
{ "\xE0\x47" , "\xE0\xC7" },
|
||||
{ "\xE0\x6C" , "\xE0\xF0\x6C" },
|
||||
{ "\x6E" , "\xF0\x6E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_END ( ibm 81 )
|
||||
{ "\xE0\x4F" , "\xE0\xCF" },
|
||||
{ "\xE0\x69" , "\xE0\xF0\x69" },
|
||||
{ "\x65" , "\xF0\x65" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_PAGE_UP ( ibm 85 )
|
||||
{ "\xE0\x49" , "\xE0\xC9" },
|
||||
{ "\xE0\x7D" , "\xE0\xF0\x7D" },
|
||||
{ "\x6F" , "\xF0\x6F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_PAGE_DOWN ( ibm 86 )
|
||||
{ "\xE0\x51" , "\xE0\xD1" },
|
||||
{ "\xE0\x7A" , "\xE0\xF0\x7A" },
|
||||
{ "\x6D" , "\xF0\x6D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_ADD ( ibm 106 )
|
||||
{ "\x4E" , "\xCE" },
|
||||
{ "\x79" , "\xF0\x79" },
|
||||
{ "\x7C" , "\xF0\x7C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_SUBTRACT ( ibm 105 )
|
||||
{ "\x4A" , "\xCA" },
|
||||
{ "\x7B" , "\xF0\x7B" },
|
||||
{ "\x84" , "\xF0\x84" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_END ( ibm 93 )
|
||||
{ "\x4F" , "\xCF" },
|
||||
{ "\x69" , "\xF0\x69" },
|
||||
{ "\x69" , "\xF0\x69" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_DOWN ( ibm 98 )
|
||||
{ "\x50" , "\xD0" },
|
||||
{ "\x72" , "\xF0\x72" },
|
||||
{ "\x72" , "\xF0\x72" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_PAGE_DOWN ( ibm 103 )
|
||||
{ "\x51" , "\xD1" },
|
||||
{ "\x7A" , "\xF0\x7A" },
|
||||
{ "\x7A" , "\xF0\x7A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_LEFT ( ibm 92 )
|
||||
{ "\x4B" , "\xCB" },
|
||||
{ "\x6B" , "\xF0\x6B" },
|
||||
{ "\x6B" , "\xF0\x6B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_RIGHT ( ibm 102 )
|
||||
{ "\x4D" , "\xCD" },
|
||||
{ "\x74" , "\xF0\x74" },
|
||||
{ "\x74" , "\xF0\x74" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_HOME ( ibm 91 )
|
||||
{ "\x47" , "\xC7" },
|
||||
{ "\x6C" , "\xF0\x6C" },
|
||||
{ "\x6C" , "\xF0\x6C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_UP ( ibm 96 )
|
||||
{ "\x48" , "\xC8" },
|
||||
{ "\x75" , "\xF0\x75" },
|
||||
{ "\x75" , "\xF0\x75" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_PAGE_UP ( ibm 101 )
|
||||
{ "\x49" , "\xC9" },
|
||||
{ "\x7D" , "\xF0\x7D" },
|
||||
{ "\x7D" , "\xF0\x7D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_INSERT ( ibm 99 )
|
||||
{ "\x52" , "\xD2" },
|
||||
{ "\x70" , "\xF0\x70" },
|
||||
{ "\x70" , "\xF0\x70" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_DELETE ( ibm 104 )
|
||||
{ "\x53" , "\xD3" },
|
||||
{ "\x71" , "\xF0\x71" },
|
||||
{ "\x71" , "\xF0\x71" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_5 ( ibm 97 )
|
||||
{ "\x4C" , "\xCC" },
|
||||
{ "\x73" , "\xF0\x73" },
|
||||
{ "\x73" , "\xF0\x73" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_UP ( ibm 83 )
|
||||
{ "\xE0\x48" , "\xE0\xC8" },
|
||||
{ "\xE0\x75" , "\xE0\xF0\x75" },
|
||||
{ "\x63" , "\xF0\x63" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_DOWN ( ibm 84 )
|
||||
{ "\xE0\x50" , "\xE0\xD0" },
|
||||
{ "\xE0\x72" , "\xE0\xF0\x72" },
|
||||
{ "\x60" , "\xF0\x60" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_LEFT ( ibm 79 )
|
||||
{ "\xE0\x4B" , "\xE0\xCB" },
|
||||
{ "\xE0\x6B" , "\xE0\xF0\x6B" },
|
||||
{ "\x61" , "\xF0\x61" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_RIGHT ( ibm 89 )
|
||||
{ "\xE0\x4D" , "\xE0\xCD" },
|
||||
{ "\xE0\x74" , "\xE0\xF0\x74" },
|
||||
{ "\x6A" , "\xF0\x6A" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_ENTER ( ibm 108 )
|
||||
{ "\xE0\x1C" , "\xE0\x9C" },
|
||||
{ "\xE0\x5A" , "\xE0\xF0\x5A" },
|
||||
{ "\x79" , "\xF0\x79" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_MULTIPLY ( ibm 100 )
|
||||
{ "\x37" , "\xB7" },
|
||||
{ "\x7C" , "\xF0\x7C" },
|
||||
{ "\x7E" , "\xF0\x7E" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_KP_DIVIDE ( ibm 95 )
|
||||
{ "\xE0\x35" , "\xE0\xB5" },
|
||||
{ "\xE0\x4A" , "\xE0\xF0\x4A" },
|
||||
{ "\x77" , "\xF0\x77" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_WIN_L
|
||||
{ "\xE0\x5B" , "\xE0\xDB" },
|
||||
{ "\xE0\x1F" , "\xE0\xF0\x1F" },
|
||||
{ "\x8B" , "\xF0\x8B" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_WIN_R
|
||||
{ "\xE0\x5C" , "\xE0\xDC" },
|
||||
{ "\xE0\x27" , "\xE0\xF0\x27" },
|
||||
{ "\x8C" , "\xF0\x8C" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_MENU
|
||||
{ "\xE0\x5D" , "\xE0\xDD" },
|
||||
{ "\xE0\x2F" , "\xE0\xF0\x2F" },
|
||||
{ "\x8D" , "\xF0\x8D" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_ALT_SYSREQ
|
||||
{ "\x54" , "\xD4" },
|
||||
{ "\x84" , "\xF0\x84" },
|
||||
{ "\x57" , "\xF0\x57" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_CTRL_BREAK
|
||||
{ "\xE0\x46" , "\xE0\xC6" },
|
||||
{ "\xE0\x7E" , "\xE0\xF0\x7E" },
|
||||
{ "\x62" , "\xF0\x62" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_BACK
|
||||
{ "\xE0\x6A" , "\xE0\xEA" },
|
||||
{ "\xE0\x38" , "\xE0\xF0\x38" },
|
||||
{ "\x38" , "\xF0\x38" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_FORWARD
|
||||
{ "\xE0\x69" , "\xE0\xE9" },
|
||||
{ "\xE0\x30" , "\xE0\xF0\x30" },
|
||||
{ "\x30" , "\xF0\x30" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_STOP
|
||||
{ "\xE0\x68" , "\xE0\xE8" },
|
||||
{ "\xE0\x28" , "\xE0\xF0\x28" },
|
||||
{ "\x28" , "\xF0\x28" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_MAIL
|
||||
{ "\xE0\x6C" , "\xE0\xEC" },
|
||||
{ "\xE0\x48" , "\xE0\xF0\x48" },
|
||||
{ "\x48" , "\xF0\x48" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_SEARCH
|
||||
{ "\xE0\x65" , "\xE0\xE5" },
|
||||
{ "\xE0\x10" , "\xE0\xF0\x10" },
|
||||
{ "\x10" , "\xF0\x10" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_FAV
|
||||
{ "\xE0\x66" , "\xE0\xE6" },
|
||||
{ "\xE0\x18" , "\xE0\xF0\x18" },
|
||||
{ "\x18" , "\xF0\x18" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_INT_HOME
|
||||
{ "\xE0\x32" , "\xE0\xB2" },
|
||||
{ "\xE0\x3A" , "\xE0\xF0\x3A" },
|
||||
{ "\x97" , "\xF0\x97" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_POWER_MYCOMP
|
||||
{ "\xE0\x6B" , "\xE0\xEB" },
|
||||
{ "\xE0\x40" , "\xE0\xF0\x40" },
|
||||
{ "\x40" , "\xF0\x40" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_POWER_CALC
|
||||
{ "\xE0\x21" , "\xE0\xA1" },
|
||||
{ "\xE0\x2B" , "\xE0\xF0\x2B" },
|
||||
{ "\x99" , "\xF0\x99" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_POWER_SLEEP
|
||||
{ "\xE0\x5F" , "\xE0\xDF" },
|
||||
{ "\xE0\x3F" , "\xE0\xF0\x3F" },
|
||||
{ "\x7F" , "\xF0\x7F" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_POWER_POWER
|
||||
{ "\xE0\x5E" , "\xE0\xDE" },
|
||||
{ "\xE0\x37" , "\xE0\xF0\x37" },
|
||||
{ "" , "" },
|
||||
},
|
||||
|
||||
{ // BX_KEY_POWER_WAKE
|
||||
{ "\xE0\x63" , "\xE0\xE3" },
|
||||
{ "\xE0\x5E" , "\xE0\xF0\x5E" },
|
||||
{ "" , "" },
|
||||
},
|
||||
|
||||
};
|
||||
35
bochs/iodev/scancodes.h
Normal file
35
bochs/iodev/scancodes.h
Normal file
@ -0,0 +1,35 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#ifndef BX_SCANCODES_H
|
||||
#define BX_SCANCODES_H
|
||||
|
||||
// Translation table of the 8042
|
||||
extern unsigned char translation8042[256];
|
||||
|
||||
typedef struct {
|
||||
const char *make;
|
||||
const char *brek;
|
||||
} scancode;
|
||||
|
||||
// Scancodes table
|
||||
extern scancode scancodes[BX_KEY_NBKEYS][3];
|
||||
|
||||
#endif
|
||||
416
bochs/iodev/scsi_commands.h
Normal file
416
bochs/iodev/scsi_commands.h
Normal file
@ -0,0 +1,416 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* scsi/commands.h
|
||||
Used only in cdrom_amigaos.cc.
|
||||
|
||||
Operation codes for SCSI-2 commands
|
||||
|
||||
30 Nov 94 Peter Urbanec Created file
|
||||
10 Jan 95 Peter Urbanec Added SCSI_ prefix to all commands
|
||||
31 Jan 95 Peter Urbanec Released to public
|
||||
*/
|
||||
|
||||
/* All device types */
|
||||
|
||||
#define SCSI_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_COMPARE 0x39
|
||||
#define SCSI_COPY 0x18
|
||||
#define SCSI_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_INQUIRY 0x12
|
||||
#define SCSI_LOG_SELECT 0x4c
|
||||
#define SCSI_LOG_SENSE 0x4d
|
||||
#define SCSI_MODE_SELECT_6 0x15
|
||||
#define SCSI_MODE_SELECT_10 0x55
|
||||
#define SCSI_MODE_SENSE_6 0x1a
|
||||
#define SCSI_MODE_SENSE_10 0x5a
|
||||
#define SCSI_READ_BUFFER 0x3c
|
||||
#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_REQUEST_SENSE 0x03
|
||||
#define SCSI_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Direct Access devices */
|
||||
|
||||
#define SCSI_DA_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_DA_COMPARE 0x39
|
||||
#define SCSI_DA_COPY 0x18
|
||||
#define SCSI_DA_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_DA_FORMAT_UNIT 0x04
|
||||
#define SCSI_DA_INQUIRY 0x12
|
||||
#define SCSI_DA_LOCK_UNLOCK_CACHE 0x36
|
||||
#define SCSI_DA_LOG_SELECT 0x4c
|
||||
#define SCSI_DA_LOG_SENSE 0x4d
|
||||
#define SCSI_DA_MODE_SELECT_6 0x15
|
||||
#define SCSI_DA_MODE_SELECT_10 0x55
|
||||
#define SCSI_DA_MODE_SENSE_6 0x1a
|
||||
#define SCSI_DA_MODE_SENSE_10 0x5a
|
||||
#define SCSI_DA_PRE_FETCH 0x34
|
||||
#define SCSI_DA_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_DA_READ_6 0x08
|
||||
#define SCSI_DA_READ_10 0x28
|
||||
#define SCSI_DA_READ_BUFFER 0x3c
|
||||
#define SCSI_DA_READ_CAPACITY 0x25
|
||||
#define SCSI_DA_READ_DEFECT_DATA 0x37
|
||||
#define SCSI_DA_READ_LONG 0x3e
|
||||
#define SCSI_DA_REASSIGN_BLOCKS 0x07
|
||||
#define SCSI_DA_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_DA_RELEASE 0x17
|
||||
#define SCSI_DA_REQUEST_SENSE 0x03
|
||||
#define SCSI_DA_RESERVE 0x16
|
||||
#define SCSI_DA_REZERO_UNIT 0x01
|
||||
#define SCSI_DA_SEARCH_DATA_EQUAL 0x31
|
||||
#define SCSI_DA_SEARCH_DATA_HIGH 0x30
|
||||
#define SCSI_DA_SEARCH_DATA_LOW 0x32
|
||||
#define SCSI_DA_SEEK_6 0x0b
|
||||
#define SCSI_DA_SEEK_10 0x2b
|
||||
#define SCSI_DA_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_DA_SET_LIMITS 0x33
|
||||
#define SCSI_DA_START_STOP_UNIT 0x1b
|
||||
#define SCSI_DA_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_DA_TEST_UNIT_READY 0x00
|
||||
#define SCSI_DA_VERIFY 0x2f
|
||||
|
||||
|
||||
/* Sequential access devices */
|
||||
|
||||
#define SCSI_SA_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_SA_COMPARE 0x39
|
||||
#define SCSI_SA_COPY 0x18
|
||||
#define SCSI_SA_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_SA_ERASE 0x19
|
||||
#define SCSI_SA_INQUIRY 0x12
|
||||
#define SCSI_SA_LOAD_UNLOAD 0x1b
|
||||
#define SCSI_SA_LOCATE 0x2b
|
||||
#define SCSI_SA_LOG_SELECT 0x4c
|
||||
#define SCSI_SA_LOG_SENSE 0x4d
|
||||
#define SCSI_SA_MODE_SELECT_6 0x15
|
||||
#define SCSI_SA_MODE_SELECT_10 0x55
|
||||
#define SCSI_SA_MODE_SENSE_6 0x1a
|
||||
#define SCSI_SA_MODE_SENSE_10 0x5a
|
||||
#define SCSI_SA_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_SA_READ 0x08
|
||||
#define SCSI_SA_READ_BLOCK_LIMITS 0x05
|
||||
#define SCSI_SA_READ_BUFFER 0x3c
|
||||
#define SCSI_SA_READ_POSITION 0x34
|
||||
#define SCSI_SA_READ_REVERSE 0x0f
|
||||
#define SCSI_SA_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_SA_RECOVER_BUFFERED_DATA 0x14
|
||||
#define SCSI_SA_RELEASE_UNIT 0x17
|
||||
#define SCSI_SA_REQUEST_SENSE 0x03
|
||||
#define SCSI_SA_RESERVE_UNIT 0x16
|
||||
#define SCSI_SA_REWIND 0x01
|
||||
#define SCSI_SA_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_SA_SPACE 0x11
|
||||
#define SCSI_SA_TEST_UNIT_READY 0x00
|
||||
#define SCSI_SA_VERIFY 0x13
|
||||
#define SCSI_SA_WRITE 0x0a
|
||||
#define SCSI_SA_WRITE_BUFFER 0x3b
|
||||
#define SCSI_SA_WRITE_FILEMARKS 0x10
|
||||
|
||||
|
||||
/* Printer devices */
|
||||
|
||||
#define SCSI_PRT_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_PRT_COMPARE 0x39
|
||||
#define SCSI_PRT_COPY 0x18
|
||||
#define SCSI_PRT_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_PRT_FORMAT 0x04
|
||||
#define SCSI_PRT_INQUIRY 0x12
|
||||
#define SCSI_PRT_LOG_SELECT 0x4c
|
||||
#define SCSI_PRT_LOG_SENSE 0x4d
|
||||
#define SCSI_PRT_MODE_SELECT_6 0x15
|
||||
#define SCSI_PRT_MODE_SELECT_10 0x55
|
||||
#define SCSI_PRT_MODE_SENSE_6 0x1a
|
||||
#define SCSI_PRT_MODE_SENSE_10 0x5a
|
||||
#define SCSI_PRT_PRINT 0x0a
|
||||
#define SCSI_PRT_READ_BUFFER 0x3c
|
||||
#define SCSI_PRT_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_PRT_RECOVER_BUFFERED_DATA 0x14
|
||||
#define SCSI_PRT_RELEASE_UNIT 0x17
|
||||
#define SCSI_PRT_REQUEST_SENSE 0x03
|
||||
#define SCSI_PRT_RESERVE_UNIT 0x16
|
||||
#define SCSI_PRT_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_PRT_SLEW_AND_PRINT 0x0b
|
||||
#define SCSI_PRT_STOP_PRINT 0x1b
|
||||
#define SCSI_PRT_SYNCHRONIZE_BUFFER 0x10
|
||||
#define SCSI_PRT_TEST_UNIT_READY 0x00
|
||||
#define SCSI_PRT_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Processor devices */
|
||||
|
||||
#define SCSI_CPU_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_CPU_COMPARE 0x39
|
||||
#define SCSI_CPU_COPY 0x18
|
||||
#define SCSI_CPU_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_CPU_INQUIRY 0x12
|
||||
#define SCSI_CPU_LOG_SELECT 0x4c
|
||||
#define SCSI_CPU_LOG_SENSE 0x4d
|
||||
#define SCSI_CPU_READ_BUFFER 0x3c
|
||||
#define SCSI_CPU_RECEIVE 0x08
|
||||
#define SCSI_CPU_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_CPU_REQUEST_SENSE 0x03
|
||||
#define SCSI_CPU_SEND 0x0a
|
||||
#define SCSI_CPU_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_CPU_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CPU_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Write Once devices */
|
||||
|
||||
#define SCSI_WO_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_WO_COMPARE 0x39
|
||||
#define SCSI_WO_COPY 0x18
|
||||
#define SCSI_WO_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_WO_INQUIRY 0x12
|
||||
#define SCSI_WO_LOCK_UNLOCK_CACHE 0x36
|
||||
#define SCSI_WO_LOG_SELECT 0x4c
|
||||
#define SCSI_WO_LOG_SENSE 0x4d
|
||||
#define SCSI_WO_MEDIUM_SCAN 0x38
|
||||
#define SCSI_WO_MODE_SELECT_6 0x15
|
||||
#define SCSI_WO_MODE_SELECT_10 0x55
|
||||
#define SCSI_WO_MODE_SENSE_6 0x1a
|
||||
#define SCSI_WO_MODE_SENSE_10 0x5a
|
||||
#define SCSI_WO_PRE_FETCH 0x34
|
||||
#define SCSI_WO_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_WO_READ_6 0x08
|
||||
#define SCSI_WO_READ_10 0x28
|
||||
#define SCSI_WO_READ_12 0xa8
|
||||
#define SCSI_WO_READ_BUFFER 0x3c
|
||||
#define SCSI_WO_READ_CAPACITY 0x25
|
||||
#define SCSI_WO_READ_LONG 0x3e
|
||||
#define SCSI_WO_REASSIGN_BLOCKS 0x07
|
||||
#define SCSI_WO_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_WO_RELEASE 0x17
|
||||
#define SCSI_WO_REQUEST_SENSE 0x03
|
||||
#define SCSI_WO_RESERVE 0x16
|
||||
#define SCSI_WO_REZERO_UNIT 0x01
|
||||
#define SCSI_WO_SEARCH_DATA_EQUAL_10 0x31
|
||||
#define SCSI_WO_SEARCH_DATA_EQUAL_12 0xb1
|
||||
#define SCSI_WO_SEARCH_DATA_HIGH_10 0x30
|
||||
#define SCSI_WO_SEARCH_DATA_HIGH_12 0xb0
|
||||
#define SCSI_WO_SEARCH_DATA_LOW_10 0x32
|
||||
#define SCSI_WO_SEARCH_DATA_LOW_12 0xb2
|
||||
#define SCSI_WO_SEEK_6 0x0b
|
||||
#define SCSI_WO_SEEK_10 0x2b
|
||||
#define SCSI_WO_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_WO_SET_LIMITS_10 0x33
|
||||
#define SCSI_WO_SET_LIMITS_12 0xb3
|
||||
#define SCSI_WO_START_STOP_UNIT 0x1b
|
||||
#define SCSI_WO_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_WO_TEST_UNIT_READY 0x00
|
||||
#define SCSI_WO_VERIFY_10 0x2f
|
||||
#define SCSI_WO_VERIFY_12 0xaf
|
||||
#define SCSI_WO_WRITE_6 0x0a
|
||||
#define SCSI_WO_WRITE_10 0x2a
|
||||
#define SCSI_WO_WRITE_12 0xaa
|
||||
#define SCSI_WO_WRITE_AND_VERIFY_10 0x2e
|
||||
#define SCSI_WO_WRITE_AND_VERIFY_12 0xae
|
||||
#define SCSI_WO_WRITE_BUFFER 0x3b
|
||||
#define SCSI_WO_WRITE_LONG 0x3f
|
||||
|
||||
|
||||
/* CD-ROM devices */
|
||||
|
||||
#define SCSI_CD_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_CD_COMPARE 0x39
|
||||
#define SCSI_CD_COPY 0x18
|
||||
#define SCSI_CD_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_CD_INQUIRY 0x12
|
||||
#define SCSI_CD_LOCK_UNLOCK_CACHE 0x36
|
||||
#define SCSI_CD_LOG_SELECT 0x4c
|
||||
#define SCSI_CD_LOG_SENSE 0x4d
|
||||
#define SCSI_CD_MODE_SELECT_6 0x15
|
||||
#define SCSI_CD_MODE_SELECT_10 0x55
|
||||
#define SCSI_CD_MODE_SENSE_6 0x1a
|
||||
#define SCSI_CD_MODE_SENSE_10 0x5a
|
||||
#define SCSI_CD_PAUSE_RESUME 0x4b
|
||||
#define SCSI_CD_PLAY_AUDIO_10 0x45
|
||||
#define SCSI_CD_PLAY_AUDIO_12 0xa5
|
||||
#define SCSI_CD_PLAY_AUDIO_MSF 0x47
|
||||
#define SCSI_CD_PLAY_AUDIO_TRACK_INDEX 0x48
|
||||
#define SCSI_CD_PLAY_TRACK_RELATIVE_10 0x49
|
||||
#define SCSI_CD_PLAY_TRACK_RELATIVE_12 0xa9
|
||||
#define SCSI_CD_PRE_FETCH 0x34
|
||||
#define SCSI_CD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_CD_READ_6 0x08
|
||||
#define SCSI_CD_READ_10 0x28
|
||||
#define SCSI_CD_READ_12 0xa8
|
||||
#define SCSI_CD_READ_BUFFER 0x3c
|
||||
#define SCSI_CD_READ_CD_ROM_CAPACITY 0x25
|
||||
#define SCSI_CD_READ_HEADER 0x44
|
||||
#define SCSI_CD_READ_LONG 0x3e
|
||||
#define SCSI_CD_READ_SUB_CHANNEL 0x42
|
||||
#define SCSI_CD_READ_TOC 0x43
|
||||
#define SCSI_CD_RECEIVE_DIAGNOSTIC_RESULT 0x1c
|
||||
#define SCSI_CD_RELEASE 0x17
|
||||
#define SCSI_CD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CD_RESERVE 0x16
|
||||
#define SCSI_CD_REZERO_UNIT 0x01
|
||||
#define SCSI_CD_SEARCH_DATA_EQUAL_10 0x31
|
||||
#define SCSI_CD_SEARCH_DATA_EQUAL_12 0xb1
|
||||
#define SCSI_CD_SEARCH_DATA_HIGH_10 0x30
|
||||
#define SCSI_CD_SEARCH_DATA_HIGH_12 0xb0
|
||||
#define SCSI_CD_SEARCH_DATA_LOW_10 0x32
|
||||
#define SCSI_CD_SEARCH_DATA_LOW_12 0xb2
|
||||
#define SCSI_CD_SEEK_6 0x0b
|
||||
#define SCSI_CD_SEEK_10 0x2b
|
||||
#define SCSI_CD_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_CD_SET_LIMITS_10 0x33
|
||||
#define SCSI_CD_SET_LIMITS_12 0xb3
|
||||
#define SCSI_CD_START_STOP_UNIT 0x1b
|
||||
#define SCSI_CD_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_CD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CD_VERIFY_10 0x2f
|
||||
#define SCSI_CD_VERIFY_12 0xaf
|
||||
#define SCSI_CD_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Scanner devices */
|
||||
|
||||
#define SCSI_SC_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_SC_COMPARE 0x39
|
||||
#define SCSI_SC_COPY 0x18
|
||||
#define SCSI_SC_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_SC_GET_DATA_BUFFER_STATUS 0x34
|
||||
#define SCSI_SC_GET_WINDOW 0x25
|
||||
#define SCSI_SC_INQUIRY 0x12
|
||||
#define SCSI_SC_LOG_SELECT 0x4c
|
||||
#define SCSI_SC_LOG_SENSE 0x4d
|
||||
#define SCSI_SC_MODE_SELECT_6 0x15
|
||||
#define SCSI_SC_MODE_SELECT_10 0x55
|
||||
#define SCSI_SC_MODE_SENSE_6 0x1a
|
||||
#define SCSI_SC_MODE_SENSE_10 0x5a
|
||||
#define SCSI_SC_OBJECT_POSITION 0x31
|
||||
#define SCSI_SC_READ 0x28
|
||||
#define SCSI_SC_READ_BUFFER 0x3c
|
||||
#define SCSI_SC_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_SC_RELEASE_UNIT 0x17
|
||||
#define SCSI_SC_REQUEST_SENSE 0x03
|
||||
#define SCSI_SC_RESERVE_UNIT 0x16
|
||||
#define SCSI_SC_SCAN 0x1b
|
||||
#define SCSI_SC_SET_WINDOW 0x24
|
||||
#define SCSI_SC_SEND 0x2a
|
||||
#define SCSI_SC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_SC_TEST_UNIT_READY 0x00
|
||||
#define SCSI_SC_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Optical memory devices */
|
||||
|
||||
#define SCSI_OM_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_OM_COMPARE 0x39
|
||||
#define SCSI_OM_COPY 0x18
|
||||
#define SCSI_OM_COPY_AND_VERIFY 0x3a
|
||||
#define SCSI_OM_ERASE_10 0x2c
|
||||
#define SCSI_OM_ERASE_12 0xac
|
||||
#define SCSI_OM_FORMAT_UNIT 0x04
|
||||
#define SCSI_OM_INQUIRY 0x12
|
||||
#define SCSI_OM_LOCK_UNLOCK_CACHE 0x36
|
||||
#define SCSI_OM_LOG_SELECT 0x4c
|
||||
#define SCSI_OM_LOG_SENSE 0x4d
|
||||
#define SCSI_OM_MEDIUM_SCAN 0x38
|
||||
#define SCSI_OM_MODE_SELECT_6 0x15
|
||||
#define SCSI_OM_MODE_SELECT_10 0x55
|
||||
#define SCSI_OM_MODE_SENSE_6 0x1a
|
||||
#define SCSI_OM_MODE_SENSE_10 0x5a
|
||||
#define SCSI_OM_PRE_FETCH 0x34
|
||||
#define SCSI_OM_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_OM_READ_6 0x08
|
||||
#define SCSI_OM_READ_10 0x28
|
||||
#define SCSI_OM_READ_12 0xa8
|
||||
#define SCSI_OM_READ_BUFFER 0x3c
|
||||
#define SCSI_OM_READ_CAPACITY 0x25
|
||||
#define SCSI_OM_READ_DEFECT_DATA_10 0x37
|
||||
#define SCSI_OM_READ_DEFECT_DATA_12 0xb7
|
||||
#define SCSI_OM_READ_GENERATION 0x29
|
||||
#define SCSI_OM_READ_LONG 0x3e
|
||||
#define SCSI_OM_READ_UPDATED_BLOCK 0x2d
|
||||
#define SCSI_OM_REASSIGN_BLOCKS 0x07
|
||||
#define SCSI_OM_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_OM_RELEASE 0x17
|
||||
#define SCSI_OM_REQUEST_SENSE 0x03
|
||||
#define SCSI_OM_RESERVE 0x16
|
||||
#define SCSI_OM_REZERO_UNIT 0x01
|
||||
#define SCSI_OM_SEARCH_DATA_EQUAL_10 0x31
|
||||
#define SCSI_OM_SEARCH_DATA_EQUAL_12 0xb1
|
||||
#define SCSI_OM_SEARCH_DATA_HIGH_10 0x30
|
||||
#define SCSI_OM_SEARCH_DATA_HIGH_12 0xb0
|
||||
#define SCSI_OM_SEARCH_DATA_LOW_10 0x32
|
||||
#define SCSI_OM_SEARCH_DATA_LOW_12 0xb2
|
||||
#define SCSI_OM_SEEK_6 0x0b
|
||||
#define SCSI_OM_SEEK_10 0x2b
|
||||
#define SCSI_OM_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_OM_SET_LIMITS_10 0x33
|
||||
#define SCSI_OM_SET_LIMITS_12 0xb3
|
||||
#define SCSI_OM_START_STOP_UNIT 0x1b
|
||||
#define SCSI_OM_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_OM_TEST_UNIT_READY 0x00
|
||||
#define SCSI_OM_UPDATE_BLOCK 0x3d
|
||||
#define SCSI_OM_VERIFY_10 0x2f
|
||||
#define SCSI_OM_VERIFY_12 0xaf
|
||||
#define SCSI_OM_WRITE_6 0x0a
|
||||
#define SCSI_OM_WRITE_10 0x2a
|
||||
#define SCSI_OM_WRITE_12 0xaa
|
||||
#define SCSI_OM_WRITE_AND_VERIFY_10 0x2e
|
||||
#define SCSI_OM_WRITE_AND_VERIFY_12 0xae
|
||||
#define SCSI_OM_WRITE_BUFFER 0x3b
|
||||
#define SCSI_OM_WRITE_LONG 0x3f
|
||||
|
||||
|
||||
/* Medium changer devices */
|
||||
|
||||
#define SCSI_MC_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_MC_EXCHANGE_MEDIUM 0xa6
|
||||
#define SCSI_MC_INITIALIZE_ELEMENT_STATUS 0x07
|
||||
#define SCSI_MC_INQUIRY 0x12
|
||||
#define SCSI_MC_LOG_SELECT 0x4c
|
||||
#define SCSI_MC_LOG_SENSE 0x4d
|
||||
#define SCSI_MC_MODE_SELECT_6 0x15
|
||||
#define SCSI_MC_MODE_SELECT_10 0x55
|
||||
#define SCSI_MC_MODE_SENSE_6 0x1a
|
||||
#define SCSI_MC_MODE_SENSE_10 0x5a
|
||||
#define SCSI_MC_MOVE_MEDIUM 0xa5
|
||||
#define SCSI_MC_POSITION_TO_ELEMENT 0x2b
|
||||
#define SCSI_MC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_MC_READ_BUFFER 0x3c
|
||||
#define SCSI_MC_READ_ELEMENT_STATUS 0xb8
|
||||
#define SCSI_MC_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_MC_RELEASE 0x17
|
||||
#define SCSI_MC_REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5
|
||||
#define SCSI_MC_REQUEST_SENSE 0x03
|
||||
#define SCSI_MC_RESERVE 0x16
|
||||
#define SCSI_MC_REZERO_UNIT 0x01
|
||||
#define SCSI_MC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_MC_SEND_VOLUME_TAG 0xb6
|
||||
#define SCSI_MC_TEST_UNIT_READY 0x00
|
||||
#define SCSI_MC_WRITE_BUFFER 0x3b
|
||||
|
||||
|
||||
/* Communications devices */
|
||||
|
||||
#define SCSI_COM_CHANGE_DEFINITION 0x40
|
||||
#define SCSI_COM_GET_MESSAGE_6 0x08
|
||||
#define SCSI_COM_GET_MESSAGE_10 0x28
|
||||
#define SCSI_COM_GET_MESSAGE_12 0xa8
|
||||
#define SCSI_COM_INQUIRY 0x12
|
||||
#define SCSI_COM_LOG_SELECT 0x4c
|
||||
#define SCSI_COM_LOG_SENSE 0x4d
|
||||
#define SCSI_COM_MODE_SELECT_6 0x15
|
||||
#define SCSI_COM_MODE_SELECT_10 0x55
|
||||
#define SCSI_COM_MODE_SENSE_6 0x1a
|
||||
#define SCSI_COM_MODE_SENSE_10 0x5a
|
||||
#define SCSI_COM_READ_BUFFER 0x3c
|
||||
#define SCSI_COM_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
|
||||
#define SCSI_COM_REQUEST_SENSE 0x03
|
||||
#define SCSI_COM_SEND_DIAGNOSTIC 0x1d
|
||||
#define SCSI_COM_SEND_MESSAGE_6 0x0a
|
||||
#define SCSI_COM_SEND_MESSAGE_10 0x2a
|
||||
#define SCSI_COM_SEND_MESSAGE_12 0xaa
|
||||
#define SCSI_COM_TEST_UNIT_READY 0x00
|
||||
#define SCSI_COM_WRITE_BUFFER 0x3b
|
||||
|
||||
792
bochs/iodev/scsi_device.cc
Normal file
792
bochs/iodev/scsi_device.cc
Normal file
@ -0,0 +1,792 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2007-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// SCSI emulation layer ported from the Qemu project
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
|
||||
#include "hdimage.h"
|
||||
#include "cdrom.h"
|
||||
#include "scsi_device.h"
|
||||
|
||||
#define LOG_THIS
|
||||
|
||||
#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
|
||||
#define DEVICE_NAME "SCSI drive"
|
||||
|
||||
static SCSIRequest *free_requests = NULL;
|
||||
static Bit32u serial_number = 12345678;
|
||||
|
||||
scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
|
||||
scsi_completionfn _completion, void *_dev)
|
||||
{
|
||||
type = SCSIDEV_TYPE_DISK;
|
||||
cdrom = NULL;
|
||||
hdimage = _hdimage;
|
||||
requests = NULL;
|
||||
sense = 0;
|
||||
tcq = _tcq;
|
||||
completion = _completion;
|
||||
dev = _dev;
|
||||
cluster_size = 1;
|
||||
locked = 0;
|
||||
inserted = 1;
|
||||
max_lba = (hdimage->hd_size / 512) - 1;
|
||||
sprintf(drive_serial_str, "%d", serial_number++);
|
||||
|
||||
put("SCSID");
|
||||
}
|
||||
|
||||
scsi_device_t::scsi_device_t(LOWLEVEL_CDROM *_cdrom, int _tcq,
|
||||
scsi_completionfn _completion, void *_dev)
|
||||
{
|
||||
type = SCSIDEV_TYPE_CDROM;
|
||||
cdrom = _cdrom;
|
||||
hdimage = NULL;
|
||||
requests = NULL;
|
||||
sense = 0;
|
||||
tcq = _tcq;
|
||||
completion = _completion;
|
||||
dev = _dev;
|
||||
cluster_size = 4;
|
||||
locked = 0;
|
||||
inserted = 1;
|
||||
max_lba = cdrom->capacity() - 1;
|
||||
sprintf(drive_serial_str, "%d", serial_number++);
|
||||
|
||||
put("SCSIC");
|
||||
}
|
||||
|
||||
scsi_device_t::~scsi_device_t(void)
|
||||
{
|
||||
SCSIRequest *r, *next;
|
||||
|
||||
if (requests) {
|
||||
r = requests;
|
||||
while (r != NULL) {
|
||||
next = r->next;
|
||||
delete r;
|
||||
r = next;
|
||||
}
|
||||
}
|
||||
if (free_requests) {
|
||||
r = free_requests;
|
||||
while (r != NULL) {
|
||||
next = r->next;
|
||||
delete r;
|
||||
r = next;
|
||||
}
|
||||
free_requests = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void scsi_device_t::register_state(bx_list_c *parent, const char *name)
|
||||
{
|
||||
bx_list_c *list = new bx_list_c(parent, name, "", 1);
|
||||
new bx_shadow_num_c(list, "sense", &sense);
|
||||
// TODO: save/restore for SCSI requests
|
||||
}
|
||||
|
||||
SCSIRequest* scsi_device_t::scsi_new_request(Bit32u tag)
|
||||
{
|
||||
SCSIRequest *r;
|
||||
|
||||
if (free_requests) {
|
||||
r = free_requests;
|
||||
free_requests = r->next;
|
||||
} else {
|
||||
r = new SCSIRequest;
|
||||
}
|
||||
r->dev = this;
|
||||
r->tag = tag;
|
||||
r->sector_count = 0;
|
||||
r->buf_len = 0;
|
||||
r->status = 0;
|
||||
|
||||
r->next = requests;
|
||||
requests = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_remove_request(SCSIRequest *r)
|
||||
{
|
||||
SCSIRequest *last;
|
||||
|
||||
if (requests == r) {
|
||||
requests = r->next;
|
||||
} else {
|
||||
last = requests;
|
||||
while (last != NULL) {
|
||||
if (last->next != r)
|
||||
last = last->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (last) {
|
||||
last->next = r->next;
|
||||
} else {
|
||||
BX_ERROR(("orphaned request"));
|
||||
}
|
||||
}
|
||||
r->next = free_requests;
|
||||
free_requests = r;
|
||||
}
|
||||
|
||||
SCSIRequest* scsi_device_t::scsi_find_request(Bit32u tag)
|
||||
{
|
||||
SCSIRequest *r = requests;
|
||||
while (r != NULL) {
|
||||
if (r->tag != tag)
|
||||
r = r->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_command_complete(SCSIRequest *r, int status, int _sense)
|
||||
{
|
||||
Bit32u tag;
|
||||
BX_DEBUG(("command complete tag=0x%x status=%d sense=%d", r->tag, status, sense));
|
||||
sense = _sense;
|
||||
tag = r->tag;
|
||||
scsi_remove_request(r);
|
||||
completion(dev, SCSI_REASON_DONE, tag, status);
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_cancel_io(Bit32u tag)
|
||||
{
|
||||
BX_DEBUG(("cancel tag=0x%x", tag));
|
||||
SCSIRequest *r = scsi_find_request(tag);
|
||||
if (r) {
|
||||
scsi_remove_request(r);
|
||||
}
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_read_complete(void *req, int ret)
|
||||
{
|
||||
SCSIRequest *r = (SCSIRequest *)req;
|
||||
|
||||
if (ret) {
|
||||
BX_ERROR(("IO error"));
|
||||
completion(r, SCSI_REASON_DATA, r->tag, 0);
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
|
||||
return;
|
||||
}
|
||||
BX_DEBUG(("data ready tag=0x%x len=%d", r->tag, r->buf_len));
|
||||
|
||||
completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_read_data(Bit32u tag)
|
||||
{
|
||||
Bit32u n;
|
||||
int ret;
|
||||
|
||||
SCSIRequest *r = scsi_find_request(tag);
|
||||
if (!r) {
|
||||
BX_ERROR(("bad read tag 0x%x", tag));
|
||||
// ??? This is the wrong error.
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
return;
|
||||
}
|
||||
if (r->sector_count == (Bit32u)-1) {
|
||||
BX_DEBUG(("read buf_len=%d", r->buf_len));
|
||||
r->sector_count = 0;
|
||||
completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
|
||||
return;
|
||||
}
|
||||
BX_DEBUG(("read sector_count=%d", r->sector_count));
|
||||
if (r->sector_count == 0) {
|
||||
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
|
||||
return;
|
||||
}
|
||||
|
||||
n = r->sector_count;
|
||||
if (n > (Bit32u)(SCSI_DMA_BUF_SIZE / (512 * cluster_size)))
|
||||
n = SCSI_DMA_BUF_SIZE / (512 * cluster_size);
|
||||
r->buf_len = n * 512 * cluster_size;
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
if (!cdrom->read_block(r->dma_buf, (Bit32u)r->sector, 2048)) {
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
} else {
|
||||
scsi_read_complete((void*)r, 0);
|
||||
}
|
||||
} else {
|
||||
ret = (int)hdimage->lseek(r->sector * 512, SEEK_SET);
|
||||
if (ret < 0) {
|
||||
BX_ERROR(("could not lseek() hard drive image file"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
}
|
||||
ret = hdimage->read((bx_ptr_t)r->dma_buf, r->buf_len);
|
||||
if (ret < r->buf_len) {
|
||||
BX_ERROR(("could not read() hard drive image file"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
} else {
|
||||
scsi_read_complete((void*)r, 0);
|
||||
}
|
||||
}
|
||||
r->sector += n;
|
||||
r->sector_count -= n;
|
||||
}
|
||||
|
||||
void scsi_device_t::scsi_write_complete(void *req, int ret)
|
||||
{
|
||||
SCSIRequest *r = (SCSIRequest *)req;
|
||||
Bit32u len;
|
||||
|
||||
if (ret) {
|
||||
BX_ERROR(("IO error"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r->sector_count == 0) {
|
||||
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
|
||||
} else {
|
||||
len = r->sector_count * 512;
|
||||
if (len > SCSI_DMA_BUF_SIZE) {
|
||||
len = SCSI_DMA_BUF_SIZE;
|
||||
}
|
||||
r->buf_len = len;
|
||||
BX_DEBUG(("write complete tag=0x%x more=%d", r->tag, len));
|
||||
completion(dev, SCSI_REASON_DATA, r->tag, len);
|
||||
}
|
||||
}
|
||||
|
||||
int scsi_device_t::scsi_write_data(Bit32u tag)
|
||||
{
|
||||
SCSIRequest *r;
|
||||
Bit32u n;
|
||||
int ret;
|
||||
|
||||
BX_DEBUG(("write data tag=0x%x", tag));
|
||||
r = scsi_find_request(tag);
|
||||
if (!r) {
|
||||
BX_ERROR(("bad write tag 0x%x", tag));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
return 1;
|
||||
}
|
||||
if (type == SCSIDEV_TYPE_DISK) {
|
||||
n = r->buf_len / 512;
|
||||
if (n) {
|
||||
ret = (int)hdimage->lseek(r->sector * 512, SEEK_SET);
|
||||
if (ret < 0) {
|
||||
BX_ERROR(("could not lseek() hard drive image file"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
}
|
||||
ret = hdimage->write((bx_ptr_t)r->dma_buf, r->buf_len);
|
||||
r->sector += n;
|
||||
r->sector_count -= n;
|
||||
if (ret < r->buf_len) {
|
||||
BX_ERROR(("could not write() hard drive image file"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
} else {
|
||||
scsi_write_complete((void*)r, 0);
|
||||
}
|
||||
} else {
|
||||
scsi_write_complete(r, 0);
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("CD-ROM: write not supported"));
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit8u* scsi_device_t::scsi_get_buf(Bit32u tag)
|
||||
{
|
||||
SCSIRequest *r = scsi_find_request(tag);
|
||||
if (!r) {
|
||||
BX_ERROR(("bad buffer tag 0x%x", tag));
|
||||
return NULL;
|
||||
}
|
||||
return r->dma_buf;
|
||||
}
|
||||
|
||||
Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
|
||||
{
|
||||
Bit64u nb_sectors;
|
||||
Bit64u lba;
|
||||
Bit32s len;
|
||||
int cmdlen;
|
||||
int is_write;
|
||||
Bit8u command;
|
||||
Bit8u *outbuf;
|
||||
SCSIRequest *r;
|
||||
|
||||
command = buf[0];
|
||||
r = scsi_find_request(tag);
|
||||
if (r) {
|
||||
BX_ERROR(("tag 0x%x already in use", tag));
|
||||
scsi_cancel_io(tag);
|
||||
}
|
||||
r = scsi_new_request(tag);
|
||||
outbuf = r->dma_buf;
|
||||
is_write = 0;
|
||||
BX_DEBUG(("command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]));
|
||||
switch (command >> 5) {
|
||||
case 0:
|
||||
lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
|
||||
len = buf[4];
|
||||
cmdlen = 6;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
|
||||
len = buf[8] | (buf[7] << 8);
|
||||
cmdlen = 10;
|
||||
break;
|
||||
case 4:
|
||||
lba = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24) |
|
||||
((Bit64u)buf[5] << 32) | ((Bit64u)buf[4] << 40) |
|
||||
((Bit64u)buf[3] << 48) | ((Bit64u)buf[2] << 56);
|
||||
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
|
||||
cmdlen = 16;
|
||||
break;
|
||||
case 5:
|
||||
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
|
||||
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
|
||||
cmdlen = 12;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unsupported command length, command %x", command));
|
||||
goto fail;
|
||||
}
|
||||
if (lun || buf[1] >> 5) {
|
||||
BX_ERROR(("unimplemented LUN %d", lun ? lun : buf[1] >> 5));
|
||||
if ((command != 0x03) && (command != 0x12)) // REQUEST SENSE and INQUIRY
|
||||
goto fail;
|
||||
}
|
||||
switch (command) {
|
||||
case 0x0:
|
||||
BX_DEBUG(("Test Unit Ready"));
|
||||
if (!inserted)
|
||||
goto notready;
|
||||
break;
|
||||
case 0x03:
|
||||
BX_DEBUG(("request Sense (len %d)", len));
|
||||
if (len < 4)
|
||||
goto fail;
|
||||
memset(outbuf, 0, 4);
|
||||
r->buf_len = 4;
|
||||
if ((sense == SENSE_NOT_READY) && (len >= 18)) {
|
||||
memset(outbuf, 0, 18);
|
||||
r->buf_len = 18;
|
||||
outbuf[7] = 10;
|
||||
/* asc 0x3a, ascq 0: Medium not present */
|
||||
outbuf[12] = 0x3a;
|
||||
outbuf[13] = 0;
|
||||
}
|
||||
outbuf[0] = 0xf0;
|
||||
outbuf[1] = 0;
|
||||
outbuf[2] = sense;
|
||||
break;
|
||||
case 0x12:
|
||||
BX_DEBUG(("inquiry (len %d)", len));
|
||||
if (buf[1] & 0x2) {
|
||||
// Command support data - optional, not implemented
|
||||
BX_ERROR(("optional INQUIRY command support request not implemented"));
|
||||
goto fail;
|
||||
} else if (buf[1] & 0x1) {
|
||||
// Vital product data
|
||||
Bit8u page_code = buf[2];
|
||||
if (len < 4) {
|
||||
BX_ERROR(("Error: Inquiry (EVPD[%02X]) buffer size %d is less than 4", page_code, len));
|
||||
goto fail;
|
||||
}
|
||||
switch (page_code) {
|
||||
case 0x00:
|
||||
// Supported page codes, mandatory
|
||||
BX_DEBUG(("Inquiry EVPD[Supported pages] buffer size %d", len));
|
||||
|
||||
r->buf_len = 0;
|
||||
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
outbuf[r->buf_len++] = 5;
|
||||
} else {
|
||||
outbuf[r->buf_len++] = 0;
|
||||
}
|
||||
|
||||
outbuf[r->buf_len++] = 0x00; // this page
|
||||
outbuf[r->buf_len++] = 0x00;
|
||||
outbuf[r->buf_len++] = 3; // number of pages
|
||||
outbuf[r->buf_len++] = 0x00; // list of supported pages (this page)
|
||||
outbuf[r->buf_len++] = 0x80; // unit serial number
|
||||
outbuf[r->buf_len++] = 0x83; // device identification
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
int l;
|
||||
|
||||
// Device serial number, optional
|
||||
if (len < 4) {
|
||||
BX_ERROR(("Error: EVPD[Serial number] Inquiry buffer size %d too small, %d needed", len, 4));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
BX_DEBUG(("Inquiry EVPD[Serial number] buffer size %d\n", len));
|
||||
l = BX_MIN(len, (int)strlen(drive_serial_str));
|
||||
|
||||
r->buf_len = 0;
|
||||
|
||||
// Supported page codes
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
outbuf[r->buf_len++] = 5;
|
||||
} else {
|
||||
outbuf[r->buf_len++] = 0;
|
||||
}
|
||||
|
||||
outbuf[r->buf_len++] = 0x80; // this page
|
||||
outbuf[r->buf_len++] = 0x00;
|
||||
outbuf[r->buf_len++] = l;
|
||||
memcpy(&outbuf[r->buf_len], drive_serial_str, l);
|
||||
r->buf_len += l;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x83:
|
||||
{
|
||||
// Device identification page, mandatory
|
||||
int max_len = 255 - 8;
|
||||
int id_len = strlen(DEVICE_NAME);
|
||||
if (id_len > max_len)
|
||||
id_len = max_len;
|
||||
|
||||
BX_DEBUG(("Inquiry EVPD[Device identification] buffer size %d", len));
|
||||
r->buf_len = 0;
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
outbuf[r->buf_len++] = 5;
|
||||
} else {
|
||||
outbuf[r->buf_len++] = 0;
|
||||
}
|
||||
|
||||
outbuf[r->buf_len++] = 0x83; // this page
|
||||
outbuf[r->buf_len++] = 0x00;
|
||||
outbuf[r->buf_len++] = 3 + id_len;
|
||||
|
||||
outbuf[r->buf_len++] = 0x2; // ASCII
|
||||
outbuf[r->buf_len++] = 0; // not officially assigned
|
||||
outbuf[r->buf_len++] = 0; // reserved
|
||||
outbuf[r->buf_len++] = id_len; // length of data following
|
||||
|
||||
memcpy(&outbuf[r->buf_len], DEVICE_NAME, id_len);
|
||||
r->buf_len += id_len;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("Error: unsupported Inquiry (EVPD[%02X]) buffer size %d", page_code, len));
|
||||
goto fail;
|
||||
}
|
||||
// done with EVPD
|
||||
break;
|
||||
} else {
|
||||
// Standard INQUIRY data
|
||||
if (buf[2] != 0) {
|
||||
BX_ERROR(("Error: Inquiry (STANDARD) page or code is non-zero [%02X]", buf[2]));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// PAGE CODE == 0
|
||||
if (len < 5) {
|
||||
BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 5", len));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (len < 36) {
|
||||
BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 36 (TODO: only 5 required)", len));
|
||||
}
|
||||
}
|
||||
|
||||
if(len > SCSI_MAX_INQUIRY_LEN)
|
||||
len = SCSI_MAX_INQUIRY_LEN;
|
||||
memset(outbuf, 0, len);
|
||||
if (lun || buf[1] >> 5) {
|
||||
outbuf[0] = 0x7f; // LUN not supported
|
||||
} else if (type == SCSIDEV_TYPE_CDROM) {
|
||||
outbuf[0] = 5;
|
||||
outbuf[1] = 0x80;
|
||||
memcpy(&outbuf[16], "BOCHS CD-ROM ", 16);
|
||||
} else {
|
||||
outbuf[0] = 0;
|
||||
memcpy(&outbuf[16], "BOCHS HARDDISK ", 16);
|
||||
}
|
||||
memcpy(&outbuf[8], "BOCHS ", 8);
|
||||
memcpy(&outbuf[32], "1.0", 4);
|
||||
// Identify device as SCSI-3 rev 1.
|
||||
// Some later commands are also implemented.
|
||||
outbuf[2] = 3;
|
||||
outbuf[3] = 2; // Format 2
|
||||
outbuf[4] = len - 5; // Additional Length = (Len - 1) - 4
|
||||
// Sync data transfer and TCQ.
|
||||
outbuf[7] = 0x10 | (tcq ? 0x02 : 0);
|
||||
r->buf_len = len;
|
||||
break;
|
||||
case 0x16:
|
||||
BX_INFO(("Reserve(6)"));
|
||||
if (buf[1] & 1)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x17:
|
||||
BX_INFO(("Release(6)"));
|
||||
if (buf[1] & 1)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x1a:
|
||||
case 0x5a:
|
||||
{
|
||||
Bit8u *p;
|
||||
int page;
|
||||
|
||||
page = buf[2] & 0x3f;
|
||||
BX_DEBUG(("mode sense (page %d, len %d)", page, len));
|
||||
p = outbuf;
|
||||
memset(p, 0, 4);
|
||||
outbuf[1] = 0; /* Default media type. */
|
||||
outbuf[3] = 0; /* Block descriptor length. */
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
outbuf[2] = 0x80; /* Readonly. */
|
||||
}
|
||||
p += 4;
|
||||
if ((page == 4) || (page == 5)) {
|
||||
BX_ERROR(("mode sense: page %d not implemented", page));
|
||||
}
|
||||
if ((page == 8 || page == 0x3f)) {
|
||||
/* Caching page. */
|
||||
memset(p, 0, 20);
|
||||
p[0] = 8;
|
||||
p[1] = 0x12;
|
||||
p[2] = 4; /* WCE */
|
||||
p += 20;
|
||||
}
|
||||
if ((page == 0x3f || page == 0x2a)
|
||||
&& (type == SCSIDEV_TYPE_CDROM)) {
|
||||
/* CD Capabilities and Mechanical Status page. */
|
||||
p[0] = 0x2a;
|
||||
p[1] = 0x14;
|
||||
p[2] = 3; // CD-R & CD-RW read
|
||||
p[3] = 0; // Writing not supported
|
||||
p[4] = 0x7f; /* Audio, composite, digital out,
|
||||
mode 2 form 1&2, multi session */
|
||||
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
|
||||
RW corrected, C2 errors, ISRC,
|
||||
UPC, Bar code */
|
||||
p[6] = 0x2d | (locked ? 2 : 0);
|
||||
/* Locking supported, jumper present, eject, tray */
|
||||
p[7] = 0; /* no volume & mute control, no changer */
|
||||
p[8] = (50 * 176) >> 8; // 50x read speed
|
||||
p[9] = (50 * 176) & 0xff;
|
||||
p[10] = 0 >> 8; // No volume
|
||||
p[11] = 0 & 0xff;
|
||||
p[12] = 2048 >> 8; // 2M buffer
|
||||
p[13] = 2048 & 0xff;
|
||||
p[14] = (16 * 176) >> 8; // 16x read speed current
|
||||
p[15] = (16 * 176) & 0xff;
|
||||
p[18] = (16 * 176) >> 8; // 16x write speed
|
||||
p[19] = (16 * 176) & 0xff;
|
||||
p[20] = (16 * 176) >> 8; // 16x write speed current
|
||||
p[21] = (16 * 176) & 0xff;
|
||||
p += 22;
|
||||
}
|
||||
r->buf_len = p - outbuf;
|
||||
outbuf[0] = r->buf_len - 4;
|
||||
if (r->buf_len > (int)len)
|
||||
r->buf_len = len;
|
||||
}
|
||||
break;
|
||||
case 0x1b:
|
||||
BX_INFO(("Start Stop Unit"));
|
||||
if (type == SCSIDEV_TYPE_CDROM && (buf[4] & 2)) {
|
||||
if (!(buf[4] & 1)) {
|
||||
// eject medium
|
||||
cdrom->eject_cdrom();
|
||||
inserted = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x1e:
|
||||
BX_INFO(("Prevent Allow Medium Removal (prevent = %d)", buf[4] & 3));
|
||||
locked = buf[4] & 1;
|
||||
break;
|
||||
case 0x25:
|
||||
BX_DEBUG(("Read Capacity"));
|
||||
// The normal LEN field for this command is zero
|
||||
memset(outbuf, 0, 8);
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
nb_sectors = cdrom->capacity();
|
||||
} else {
|
||||
nb_sectors = hdimage->hd_size / 512;
|
||||
}
|
||||
/* Returned value is the address of the last sector. */
|
||||
if (nb_sectors) {
|
||||
nb_sectors--;
|
||||
outbuf[0] = (Bit8u)((nb_sectors >> 24) & 0xff);
|
||||
outbuf[1] = (Bit8u)((nb_sectors >> 16) & 0xff);
|
||||
outbuf[2] = (Bit8u)((nb_sectors >> 8) & 0xff);
|
||||
outbuf[3] = (Bit8u)(nb_sectors & 0xff);
|
||||
outbuf[4] = 0;
|
||||
outbuf[5] = 0;
|
||||
outbuf[6] = cluster_size * 2;
|
||||
outbuf[7] = 0;
|
||||
r->buf_len = 8;
|
||||
} else {
|
||||
notready:
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x28:
|
||||
case 0x88:
|
||||
BX_DEBUG(("Read (sector "FMT_LL"d, count %d)", lba, len));
|
||||
if (lba > max_lba)
|
||||
goto illegal_lba;
|
||||
r->sector = lba;
|
||||
r->sector_count = len;
|
||||
break;
|
||||
case 0x0a:
|
||||
case 0x2a:
|
||||
case 0x8a:
|
||||
BX_DEBUG(("Write (sector "FMT_LL"d, count %d)", lba, len));
|
||||
if (lba > max_lba)
|
||||
goto illegal_lba;
|
||||
r->sector = lba;
|
||||
r->sector_count = len;
|
||||
is_write = 1;
|
||||
break;
|
||||
case 0x35:
|
||||
BX_DEBUG(("Syncronise cache (sector "FMT_LL"d, count %d)", lba, len));
|
||||
// TODO: flush cache
|
||||
break;
|
||||
case 0x43:
|
||||
{
|
||||
int start_track, format, msf, toclen;
|
||||
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
msf = buf[1] & 2;
|
||||
format = buf[2] & 0xf;
|
||||
start_track = buf[6];
|
||||
BX_DEBUG(("Read TOC (track %d format %d msf %d)", start_track, format, msf >> 1));
|
||||
cdrom->read_toc(outbuf, &toclen, msf, start_track, format);
|
||||
if (toclen > 0) {
|
||||
if (len > toclen)
|
||||
len = toclen;
|
||||
r->buf_len = len;
|
||||
break;
|
||||
}
|
||||
BX_ERROR(("Read TOC error"));
|
||||
goto fail;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
case 0x46:
|
||||
BX_DEBUG(("Get Configuration (rt %d, maxlen %d)", buf[1] & 3, len));
|
||||
memset(outbuf, 0, 8);
|
||||
/* ??? This shoud probably return much more information. For now
|
||||
just return the basic header indicating the CD-ROM profile. */
|
||||
outbuf[7] = 8; // CD-ROM
|
||||
r->buf_len = 8;
|
||||
break;
|
||||
case 0x56:
|
||||
BX_INFO(("Reserve(10)"));
|
||||
if (buf[1] & 3)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x57:
|
||||
BX_INFO(("Release(10)"));
|
||||
if (buf[1] & 3)
|
||||
goto fail;
|
||||
break;
|
||||
case 0xa0:
|
||||
BX_INFO(("Report LUNs (len %d)", len));
|
||||
if (len < 16)
|
||||
goto fail;
|
||||
memset(outbuf, 0, 16);
|
||||
outbuf[3] = 8;
|
||||
r->buf_len = 16;
|
||||
break;
|
||||
case 0x2f:
|
||||
BX_INFO(("Verify"));
|
||||
break;
|
||||
case 0x23: {
|
||||
// USBMASS-UFI10.pdf rev 1.0 Section 4.10
|
||||
BX_INFO(("READ FORMAT CAPACITIES (MMC)"));
|
||||
|
||||
unsigned len = (buf[7]<<8) | buf[8];
|
||||
#define OUR_LEN 12
|
||||
|
||||
// Cap List Header
|
||||
outbuf[0] = 0;
|
||||
outbuf[1] = 0;
|
||||
outbuf[2] = 0;
|
||||
outbuf[3] = OUR_LEN;
|
||||
|
||||
// Current/Max Cap Header
|
||||
if (type == SCSIDEV_TYPE_CDROM) {
|
||||
nb_sectors = cdrom->capacity();
|
||||
} else {
|
||||
nb_sectors = (hdimage->hd_size / 512);
|
||||
}
|
||||
/* Returned value is the address of the last sector. */
|
||||
outbuf[4] = (Bit8u)((nb_sectors >> 24) & 0xff);
|
||||
outbuf[5] = (Bit8u)((nb_sectors >> 16) & 0xff);
|
||||
outbuf[6] = (Bit8u)((nb_sectors >> 8) & 0xff);
|
||||
outbuf[7] = (Bit8u)(nb_sectors & 0xff);
|
||||
outbuf[8] = 2; // formatted (1 = unformatted)
|
||||
outbuf[9] = 0;
|
||||
outbuf[10] = cluster_size * 2;
|
||||
outbuf[11] = 0;
|
||||
|
||||
r->buf_len = (len < OUR_LEN) ? len : OUR_LEN;
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unknown SCSI command (%2.2x)", buf[0]));
|
||||
fail:
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
|
||||
return 0;
|
||||
illegal_lba:
|
||||
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (r->sector_count == 0 && r->buf_len == 0) {
|
||||
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
|
||||
}
|
||||
len = r->sector_count * 512 * cluster_size + r->buf_len;
|
||||
if (is_write) {
|
||||
return -len;
|
||||
} else {
|
||||
if (!r->sector_count)
|
||||
r->sector_count = (Bit32u) -1;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
|
||||
106
bochs/iodev/scsi_device.h
Normal file
106
bochs/iodev/scsi_device.h
Normal file
@ -0,0 +1,106 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2007 Volker Ruppert
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// SCSI emulation layer ported from the Qemu project
|
||||
|
||||
#ifndef BX_IODEV_SCSI_DEVICE_H
|
||||
#define BX_IODEV_SCSI_DEVICE_H
|
||||
|
||||
typedef void (*scsi_completionfn)(void *opaque, int reason, Bit32u tag,
|
||||
Bit32u arg);
|
||||
class scsi_device_t;
|
||||
class LOWLEVEL_CDROM;
|
||||
|
||||
enum scsidev_type {
|
||||
SCSIDEV_TYPE_DISK,
|
||||
SCSIDEV_TYPE_CDROM
|
||||
};
|
||||
|
||||
enum scsi_reason {
|
||||
SCSI_REASON_DONE,
|
||||
SCSI_REASON_DATA
|
||||
};
|
||||
|
||||
#define SENSE_NO_SENSE 0
|
||||
#define SENSE_NOT_READY 2
|
||||
#define SENSE_HARDWARE_ERROR 4
|
||||
#define SENSE_ILLEGAL_REQUEST 5
|
||||
|
||||
#define STATUS_GOOD 0
|
||||
#define STATUS_CHECK_CONDITION 2
|
||||
|
||||
#define SCSI_DMA_BUF_SIZE 131072
|
||||
#define SCSI_MAX_INQUIRY_LEN 256
|
||||
|
||||
typedef struct SCSIRequest {
|
||||
scsi_device_t *dev;
|
||||
Bit32u tag;
|
||||
Bit64u sector;
|
||||
Bit32u sector_count;
|
||||
int buf_len;
|
||||
Bit8u dma_buf[SCSI_DMA_BUF_SIZE];
|
||||
Bit32u status;
|
||||
struct SCSIRequest *next;
|
||||
} SCSIRequest;
|
||||
|
||||
|
||||
class scsi_device_t : public logfunctions {
|
||||
public:
|
||||
scsi_device_t(device_image_t *_hdimage, int _tcq,
|
||||
scsi_completionfn _completion, void *_dev);
|
||||
scsi_device_t(LOWLEVEL_CDROM *_cdrom, int _tcq,
|
||||
scsi_completionfn _completion, void *_dev);
|
||||
virtual ~scsi_device_t(void);
|
||||
|
||||
void register_state(bx_list_c *parent, const char *name);
|
||||
Bit32s scsi_send_command(Bit32u tag, Bit8u *buf, int lun);
|
||||
void scsi_command_complete(SCSIRequest *r, int status, int sense);
|
||||
void scsi_cancel_io(Bit32u tag);
|
||||
void scsi_read_complete(void *req, int ret);
|
||||
void scsi_read_data(Bit32u tag);
|
||||
void scsi_write_complete(void *req, int ret);
|
||||
int scsi_write_data(Bit32u tag);
|
||||
Bit8u* scsi_get_buf(Bit32u tag);
|
||||
const char *get_serial_number() {return drive_serial_str;}
|
||||
void set_inserted(bx_bool value) {inserted = value;}
|
||||
bx_bool get_inserted() {return inserted;}
|
||||
|
||||
protected:
|
||||
SCSIRequest* scsi_new_request(Bit32u tag);
|
||||
void scsi_remove_request(SCSIRequest *r);
|
||||
SCSIRequest *scsi_find_request(Bit32u tag);
|
||||
|
||||
private:
|
||||
enum scsidev_type type;
|
||||
device_image_t *hdimage;
|
||||
LOWLEVEL_CDROM *cdrom;
|
||||
SCSIRequest *requests;
|
||||
int cluster_size;
|
||||
Bit64u max_lba;
|
||||
int sense;
|
||||
int tcq;
|
||||
scsi_completionfn completion;
|
||||
void *dev;
|
||||
bx_bool locked;
|
||||
bx_bool inserted;
|
||||
char drive_serial_str[21];
|
||||
};
|
||||
|
||||
#endif
|
||||
283
bochs/iodev/scsidefs.h
Normal file
283
bochs/iodev/scsidefs.h
Normal file
@ -0,0 +1,283 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// iodev/scsidefs.h
|
||||
//
|
||||
// This file was copied from ... ?
|
||||
//
|
||||
|
||||
//***************************************************************************
|
||||
// Name: SCSIDEFS.H
|
||||
//
|
||||
// Description: SCSI definitions ('C' Language)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// %%% TARGET STATUS VALUES %%%
|
||||
//***************************************************************************
|
||||
#define STATUS_GOOD 0x00 // Status Good
|
||||
#define STATUS_CHKCOND 0x02 // Check Condition
|
||||
#define STATUS_CONDMET 0x04 // Condition Met
|
||||
#define STATUS_BUSY 0x08 // Busy
|
||||
#define STATUS_INTERM 0x10 // Intermediate
|
||||
#define STATUS_INTCDMET 0x14 // Intermediate-condition met
|
||||
#define STATUS_RESCONF 0x18 // Reservation conflict
|
||||
#define STATUS_COMTERM 0x22 // Command Terminated
|
||||
#define STATUS_QFULL 0x28 // Queue full
|
||||
|
||||
//***************************************************************************
|
||||
// %%% SCSI MISCELLANEOUS EQUATES %%%
|
||||
//***************************************************************************
|
||||
#define MAXLUN 7 // Maximum Logical Unit Id
|
||||
#define MAXTARG 7 // Maximum Target Id
|
||||
#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs
|
||||
#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's
|
||||
|
||||
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
|
||||
//
|
||||
// %%% SCSI COMMAND OPCODES %%%
|
||||
//
|
||||
///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands for all Device Types %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional)
|
||||
#define SCSI_COMPARE 0x39 // Compare (O)
|
||||
#define SCSI_COPY 0x18 // Copy (O)
|
||||
#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O)
|
||||
#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY)
|
||||
#define SCSI_LOG_SELECT 0x4C // Log Select (O)
|
||||
#define SCSI_LOG_SENSE 0x4D // Log Sense (O)
|
||||
#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific)
|
||||
#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific)
|
||||
#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific)
|
||||
#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific)
|
||||
#define SCSI_READ_BUFF 0x3C // Read Buffer (O)
|
||||
#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY)
|
||||
#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O)
|
||||
#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY)
|
||||
#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Direct Access Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_COMPARE 0x39 // Compare (O)
|
||||
#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY)
|
||||
#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O)
|
||||
#define SCSI_PREFETCH 0x34 // Prefetch (O)
|
||||
#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O)
|
||||
#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY)
|
||||
#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY)
|
||||
#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY)
|
||||
#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O)
|
||||
#define SCSI_READ_LONG 0x3E // Read Long (O)
|
||||
#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O)
|
||||
#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O)
|
||||
#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY)
|
||||
#define SCSI_REZERO 0x01 // Rezero Unit (O)
|
||||
#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O)
|
||||
#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O)
|
||||
#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O)
|
||||
#define SCSI_SEEK6 0x0B // Seek 6-Byte (O)
|
||||
#define SCSI_SEEK10 0x2B // Seek 10-Byte (O)
|
||||
#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY)
|
||||
#define SCSI_SET_LIMIT 0x33 // Set Limits (O)
|
||||
#define SCSI_START_STP 0x1B // Start/Stop Unit (O)
|
||||
#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O)
|
||||
#define SCSI_VERIFY 0x2F // Verify (O)
|
||||
#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY)
|
||||
#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY)
|
||||
#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O)
|
||||
#define SCSI_WRITE_LONG 0x3F // Write Long (O)
|
||||
#define SCSI_WRITE_SAME 0x41 // Write Same (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Sequential Access Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_ERASE 0x19 // Erase (MANDATORY)
|
||||
#define SCSI_LOAD_UN 0x1B // Load/Unload (O)
|
||||
#define SCSI_LOCATE 0x2B // Locate (O)
|
||||
#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY)
|
||||
#define SCSI_READ_POS 0x34 // Read Position (O)
|
||||
#define SCSI_READ_REV 0x0F // Read Reverse (O)
|
||||
#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O)
|
||||
#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY)
|
||||
#define SCSI_REWIND 0x01 // Rewind (MANDATORY)
|
||||
#define SCSI_SPACE 0x11 // Space (MANDATORY)
|
||||
#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O)
|
||||
#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Printer Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_PRINT 0x0A // Print (MANDATORY)
|
||||
#define SCSI_SLEW_PNT 0x0B // Slew and Print (O)
|
||||
#define SCSI_STOP_PNT 0x1B // Stop Print (O)
|
||||
#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Processor Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_RECEIVE 0x08 // Receive (O)
|
||||
#define SCSI_SEND 0x0A // Send (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Write-Once Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O)
|
||||
#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O)
|
||||
#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O)
|
||||
#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O)
|
||||
#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O)
|
||||
#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O)
|
||||
#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O)
|
||||
#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O)
|
||||
#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O)
|
||||
#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O)
|
||||
#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O)
|
||||
#define SCSI_WRITE12 0xAA // Write 12-Byte (O)
|
||||
#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O)
|
||||
#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to CD-ROM Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O)
|
||||
#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O)
|
||||
#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O)
|
||||
#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O)
|
||||
#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O)
|
||||
#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O)
|
||||
#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY)
|
||||
#define SCSI_READHEADER 0x44 // Read Header (O)
|
||||
#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O)
|
||||
#define SCSI_READ_TOC 0x43 // Read TOC (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Scanner Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O)
|
||||
#define SCSI_GETWINDOW 0x25 // Get Window (O)
|
||||
#define SCSI_OBJECTPOS 0x31 // Object Postion (O)
|
||||
#define SCSI_SCAN 0x1B // Scan (O)
|
||||
#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Optical Memory Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_UpdateBlk 0x3D // Update Block (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Medium Changer Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O)
|
||||
#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O)
|
||||
#define SCSI_POSTOELEM 0x2B // Position to Element (O)
|
||||
#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O)
|
||||
#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O)
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Commands Unique to Communication Devices %%%
|
||||
//***************************************************************************
|
||||
#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY)
|
||||
#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O)
|
||||
#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O)
|
||||
#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY)
|
||||
#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O)
|
||||
#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O)
|
||||
|
||||
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
|
||||
//
|
||||
// %%% END OF SCSI COMMAND OPCODES %%%
|
||||
//
|
||||
///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
|
||||
|
||||
//***************************************************************************
|
||||
// %%% Request Sense Data Format %%%
|
||||
//***************************************************************************
|
||||
typedef struct {
|
||||
|
||||
BYTE ErrorCode; // Error Code (70H or 71H)
|
||||
BYTE SegmentNum; // Number of current segment descriptor
|
||||
BYTE SenseKey; // Sense Key(See bit definitions too)
|
||||
BYTE InfoByte0; // Information MSB
|
||||
BYTE InfoByte1; // Information MID
|
||||
BYTE InfoByte2; // Information MID
|
||||
BYTE InfoByte3; // Information LSB
|
||||
BYTE AddSenLen; // Additional Sense Length
|
||||
BYTE ComSpecInf0; // Command Specific Information MSB
|
||||
BYTE ComSpecInf1; // Command Specific Information MID
|
||||
BYTE ComSpecInf2; // Command Specific Information MID
|
||||
BYTE ComSpecInf3; // Command Specific Information LSB
|
||||
BYTE AddSenseCode; // Additional Sense Code
|
||||
BYTE AddSenQual; // Additional Sense Code Qualifier
|
||||
BYTE FieldRepUCode; // Field Replaceable Unit Code
|
||||
BYTE SenKeySpec15; // Sense Key Specific 15th byte
|
||||
BYTE SenKeySpec16; // Sense Key Specific 16th byte
|
||||
BYTE SenKeySpec17; // Sense Key Specific 17th byte
|
||||
BYTE AddSenseBytes; // Additional Sense Bytes
|
||||
|
||||
} SENSE_DATA_FMT;
|
||||
|
||||
//***************************************************************************
|
||||
// %%% REQUEST SENSE ERROR CODE %%%
|
||||
//***************************************************************************
|
||||
#define SERROR_CURRENT 0x70 // Current Errors
|
||||
#define SERROR_DEFERED 0x71 // Deferred Errors
|
||||
|
||||
//***************************************************************************
|
||||
// %%% REQUEST SENSE BIT DEFINITIONS %%%
|
||||
//***************************************************************************
|
||||
#define SENSE_VALID 0x80 // Byte 0 Bit 7
|
||||
#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7
|
||||
#define SENSE_EOM 0x40 // Byte 2 Bit 6
|
||||
#define SENSE_ILI 0x20 // Byte 2 Bit 5
|
||||
|
||||
//***************************************************************************
|
||||
// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%%
|
||||
//***************************************************************************
|
||||
#define KEY_NOSENSE 0x00 // No Sense
|
||||
#define KEY_RECERROR 0x01 // Recovered Error
|
||||
#define KEY_NOTREADY 0x02 // Not Ready
|
||||
#define KEY_MEDIUMERR 0x03 // Medium Error
|
||||
#define KEY_HARDERROR 0x04 // Hardware Error
|
||||
#define KEY_ILLGLREQ 0x05 // Illegal Request
|
||||
#define KEY_UNITATT 0x06 // Unit Attention
|
||||
#define KEY_DATAPROT 0x07 // Data Protect
|
||||
#define KEY_BLANKCHK 0x08 // Blank Check
|
||||
#define KEY_VENDSPEC 0x09 // Vendor Specific
|
||||
#define KEY_COPYABORT 0x0A // Copy Abort
|
||||
#define KEY_EQUAL 0x0C // Equal (Search)
|
||||
#define KEY_VOLOVRFLW 0x0D // Volume Overflow
|
||||
#define KEY_MISCOMP 0x0E // Miscompare (Search)
|
||||
#define KEY_RESERVED 0x0F // Reserved
|
||||
|
||||
//***************************************************************************
|
||||
// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%%
|
||||
//***************************************************************************
|
||||
#define DTYPE_DASD 0x00 // Disk Device
|
||||
#define DTYPE_SEQD 0x01 // Tape Device
|
||||
#define DTYPE_PRNT 0x02 // Printer
|
||||
#define DTYPE_PROC 0x03 // Processor
|
||||
#define DTYPE_WORM 0x04 // Write-once read-multiple
|
||||
#define DTYPE_CROM 0x05 // CD-ROM device
|
||||
#define DTYPE_CDROM 0x05 // CD-ROM device
|
||||
#define DTYPE_SCAN 0x06 // Scanner device
|
||||
#define DTYPE_OPTI 0x07 // Optical memory device
|
||||
#define DTYPE_JUKE 0x08 // Medium Changer device
|
||||
#define DTYPE_COMM 0x09 // Communications device
|
||||
#define DTYPE_RESL 0x0A // Reserved (low)
|
||||
#define DTYPE_RESH 0x1E // Reserved (high)
|
||||
#define DTYPE_UNKNOWN 0x1F // Unknown or no device type
|
||||
|
||||
//***************************************************************************
|
||||
// %%% ANSI APPROVED VERSION DEFINITIONS %%%
|
||||
//***************************************************************************
|
||||
#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand
|
||||
#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1)
|
||||
#define ANSI_SCSI2 0x2 // Device complies to SCSI-2
|
||||
#define ANSI_RESLO 0x3 // Reserved (low)
|
||||
#define ANSI_RESHI 0x7 // Reserved (high)
|
||||
142
bochs/iodev/scsipt.h
Normal file
142
bochs/iodev/scsipt.h
Normal file
@ -0,0 +1,142 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// iodev/scsipt.h
|
||||
// This file was copied from ... ?
|
||||
//
|
||||
// distilled information from various header files from Microsoft's
|
||||
// DDK for Windows NT 4.0
|
||||
//
|
||||
|
||||
#ifndef _SCSIPT_H_INC
|
||||
#define _SCSIPT_H_INC
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
UCHAR ScsiStatus;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
UCHAR CdbLength;
|
||||
UCHAR SenseInfoLength;
|
||||
UCHAR DataIn;
|
||||
ULONG DataTransferLength;
|
||||
ULONG TimeOutValue;
|
||||
ULONG DataBufferOffset;
|
||||
ULONG SenseInfoOffset;
|
||||
UCHAR Cdb[16];
|
||||
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
|
||||
|
||||
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
UCHAR ScsiStatus;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
UCHAR CdbLength;
|
||||
UCHAR SenseInfoLength;
|
||||
UCHAR DataIn;
|
||||
ULONG DataTransferLength;
|
||||
ULONG TimeOutValue;
|
||||
PVOID DataBuffer;
|
||||
ULONG SenseInfoOffset;
|
||||
UCHAR Cdb[16];
|
||||
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
|
||||
|
||||
|
||||
typedef struct {
|
||||
SCSI_PASS_THROUGH spt;
|
||||
ULONG Filler;
|
||||
UCHAR ucSenseBuf[32];
|
||||
UCHAR ucDataBuf[512];
|
||||
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
|
||||
|
||||
|
||||
typedef struct {
|
||||
SCSI_PASS_THROUGH_DIRECT spt;
|
||||
ULONG Filler;
|
||||
UCHAR ucSenseBuf[32];
|
||||
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
UCHAR NumberOfLogicalUnits;
|
||||
UCHAR InitiatorBusId;
|
||||
ULONG InquiryDataOffset;
|
||||
} SCSI_BUS_DATA, *PSCSI_BUS_DATA;
|
||||
|
||||
|
||||
typedef struct {
|
||||
UCHAR NumberOfBusses;
|
||||
SCSI_BUS_DATA BusData[1];
|
||||
} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;
|
||||
|
||||
|
||||
typedef struct {
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
BOOLEAN DeviceClaimed;
|
||||
ULONG InquiryDataLength;
|
||||
ULONG NextInquiryDataOffset;
|
||||
UCHAR InquiryData[1];
|
||||
} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ULONG Length;
|
||||
UCHAR PortNumber;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
} SCSI_ADDRESS, *PSCSI_ADDRESS;
|
||||
|
||||
|
||||
/*
|
||||
* method codes
|
||||
*/
|
||||
#define METHOD_BUFFERED 0
|
||||
#define METHOD_IN_DIRECT 1
|
||||
#define METHOD_OUT_DIRECT 2
|
||||
#define METHOD_NEITHER 3
|
||||
|
||||
/*
|
||||
* file access values
|
||||
*/
|
||||
#define FILE_ANY_ACCESS 0
|
||||
#define FILE_READ_ACCESS (0x0001)
|
||||
#define FILE_WRITE_ACCESS (0x0002)
|
||||
|
||||
|
||||
#define IOCTL_SCSI_BASE 0x00000004
|
||||
|
||||
/*
|
||||
* constants for DataIn member of SCSI_PASS_THROUGH* structures
|
||||
*/
|
||||
#define SCSI_IOCTL_DATA_OUT 0
|
||||
#define SCSI_IOCTL_DATA_IN 1
|
||||
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
|
||||
|
||||
/*
|
||||
* Standard IOCTL define
|
||||
*/
|
||||
#define CTL_CODE(DevType, Function, Method, Access) ( \
|
||||
((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
|
||||
)
|
||||
|
||||
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1627
bochs/iodev/serial.cc
Normal file
1627
bochs/iodev/serial.cc
Normal file
File diff suppressed because it is too large
Load Diff
249
bochs/iodev/serial.h
Normal file
249
bochs/iodev/serial.h
Normal file
@ -0,0 +1,249 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_SERIAL_H
|
||||
#define BX_IODEV_SERIAL_H
|
||||
|
||||
// Peter Grehan (grehan@iprg.nokia.com) coded most of this
|
||||
// serial emulation.
|
||||
|
||||
#if BX_USE_SER_SMF
|
||||
# define BX_SER_SMF static
|
||||
# define BX_SER_THIS theSerialDevice->
|
||||
#else
|
||||
# define BX_SER_SMF
|
||||
# define BX_SER_THIS this->
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#define SERIAL_ENABLE
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || defined(__APPLE__) || defined(__sun__)
|
||||
#define SERIAL_ENABLE
|
||||
extern "C" {
|
||||
#include <termios.h>
|
||||
};
|
||||
#endif
|
||||
|
||||
#define BX_SERIAL_MAXDEV 4
|
||||
|
||||
#define BX_PC_CLOCK_XTL 1843200.0
|
||||
|
||||
#define BX_SER_RXIDLE 0
|
||||
#define BX_SER_RXPOLL 1
|
||||
#define BX_SER_RXWAIT 2
|
||||
|
||||
#define BX_SER_THR 0
|
||||
#define BX_SER_RBR 0
|
||||
#define BX_SER_IER 1
|
||||
#define BX_SER_IIR 2
|
||||
#define BX_SER_FCR 2
|
||||
#define BX_SER_LCR 3
|
||||
#define BX_SER_MCR 4
|
||||
#define BX_SER_LSR 5
|
||||
#define BX_SER_MSR 6
|
||||
#define BX_SER_SCR 7
|
||||
|
||||
#define BX_SER_MODE_NULL 0
|
||||
#define BX_SER_MODE_FILE 1
|
||||
#define BX_SER_MODE_TERM 2
|
||||
#define BX_SER_MODE_RAW 3
|
||||
#define BX_SER_MODE_MOUSE 4
|
||||
#define BX_SER_MODE_SOCKET 5
|
||||
#define BX_SER_MODE_PIPE 6
|
||||
|
||||
enum {
|
||||
BX_SER_INT_IER,
|
||||
BX_SER_INT_RXDATA,
|
||||
BX_SER_INT_TXHOLD,
|
||||
BX_SER_INT_RXLSTAT,
|
||||
BX_SER_INT_MODSTAT,
|
||||
BX_SER_INT_FIFO
|
||||
};
|
||||
|
||||
#if USE_RAW_SERIAL
|
||||
class serial_raw;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* UART internal state
|
||||
*/
|
||||
bx_bool ls_interrupt;
|
||||
bx_bool ms_interrupt;
|
||||
bx_bool rx_interrupt;
|
||||
bx_bool tx_interrupt;
|
||||
bx_bool fifo_interrupt;
|
||||
bx_bool ls_ipending;
|
||||
bx_bool ms_ipending;
|
||||
bx_bool rx_ipending;
|
||||
bx_bool fifo_ipending;
|
||||
|
||||
Bit8u IRQ;
|
||||
|
||||
Bit8u rx_fifo_end;
|
||||
Bit8u tx_fifo_end;
|
||||
|
||||
int baudrate;
|
||||
int tx_timer_index;
|
||||
|
||||
int rx_pollstate;
|
||||
int rx_timer_index;
|
||||
int fifo_timer_index;
|
||||
|
||||
int io_mode;
|
||||
int tty_id;
|
||||
SOCKET socket_id;
|
||||
FILE *output;
|
||||
#ifdef WIN32
|
||||
HANDLE pipe;
|
||||
#endif
|
||||
|
||||
#if USE_RAW_SERIAL
|
||||
serial_raw* raw;
|
||||
#endif
|
||||
#if defined(SERIAL_ENABLE) && !defined(WIN32)
|
||||
struct termios term_orig, term_new;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register definitions
|
||||
*/
|
||||
Bit8u rxbuffer; /* receiver buffer register (r/o) */
|
||||
Bit8u thrbuffer; /* transmit holding register (w/o) */
|
||||
/* Interrupt Enable Register */
|
||||
struct {
|
||||
bx_bool rxdata_enable; /* 1=enable receive data interrupts */
|
||||
bx_bool txhold_enable; /* 1=enable tx. holding reg. empty ints */
|
||||
bx_bool rxlstat_enable; /* 1=enable rx line status interrupts */
|
||||
bx_bool modstat_enable; /* 1=enable modem status interrupts */
|
||||
} int_enable;
|
||||
/* Interrupt Identification Register (r/o) */
|
||||
struct {
|
||||
bx_bool ipending; /* 0=interrupt pending */
|
||||
Bit8u int_ID; /* 3-bit interrupt ID */
|
||||
} int_ident;
|
||||
/* FIFO Control Register (w/o) */
|
||||
struct {
|
||||
bx_bool enable; /* 1=enable tx and rx FIFOs */
|
||||
Bit8u rxtrigger; /* 2-bit code for rx fifo trigger level */
|
||||
} fifo_cntl;
|
||||
/* Line Control Register (r/w) */
|
||||
struct {
|
||||
Bit8u wordlen_sel; /* 2-bit code for char length */
|
||||
bx_bool stopbits; /* select stop bit len */
|
||||
bx_bool parity_enable; /* ... */
|
||||
bx_bool evenparity_sel; /* ... */
|
||||
bx_bool stick_parity; /* ... */
|
||||
bx_bool break_cntl; /* 1=send break signal */
|
||||
bx_bool dlab; /* divisor latch access bit */
|
||||
} line_cntl;
|
||||
/* MODEM Control Register (r/w) */
|
||||
struct {
|
||||
bx_bool dtr; /* DTR output value */
|
||||
bx_bool rts; /* RTS output value */
|
||||
bx_bool out1; /* OUTPUT1 value */
|
||||
bx_bool out2; /* OUTPUT2 value */
|
||||
bx_bool local_loopback; /* 1=loopback mode */
|
||||
} modem_cntl;
|
||||
/* Line Status Register (r/w) */
|
||||
struct {
|
||||
bx_bool rxdata_ready; /* 1=receiver data ready */
|
||||
bx_bool overrun_error; /* 1=receive overrun detected */
|
||||
bx_bool parity_error; /* 1=rx char has a bad parity bit */
|
||||
bx_bool framing_error; /* 1=no stop bit detected for rx char */
|
||||
bx_bool break_int; /* 1=break signal detected */
|
||||
bx_bool thr_empty; /* 1=tx hold register (or fifo) is empty */
|
||||
bx_bool tsr_empty; /* 1=shift reg and hold reg empty */
|
||||
bx_bool fifo_error; /* 1=at least 1 err condition in fifo */
|
||||
} line_status;
|
||||
/* Modem Status Register (r/w) */
|
||||
struct {
|
||||
bx_bool delta_cts; /* 1=CTS changed since last read */
|
||||
bx_bool delta_dsr; /* 1=DSR changed since last read */
|
||||
bx_bool ri_trailedge; /* 1=RI moved from low->high */
|
||||
bx_bool delta_dcd; /* 1=CD changed since last read */
|
||||
bx_bool cts; /* CTS input value */
|
||||
bx_bool dsr; /* DSR input value */
|
||||
bx_bool ri; /* RI input value */
|
||||
bx_bool dcd; /* DCD input value */
|
||||
} modem_status;
|
||||
|
||||
Bit8u scratch; /* Scratch Register (r/w) */
|
||||
Bit8u tsrbuffer; /* transmit shift register (internal) */
|
||||
Bit8u rx_fifo[16]; /* receive FIFO (internal) */
|
||||
Bit8u tx_fifo[16]; /* transmit FIFO (internal) */
|
||||
Bit8u divisor_lsb; /* Divisor latch, least-sig. byte */
|
||||
Bit8u divisor_msb; /* Divisor latch, most-sig. byte */
|
||||
} bx_serial_t;
|
||||
|
||||
|
||||
|
||||
class bx_serial_c : public bx_devmodel_c {
|
||||
public:
|
||||
bx_serial_c();
|
||||
virtual ~bx_serial_c();
|
||||
virtual void init(void);
|
||||
virtual void reset(unsigned type);
|
||||
virtual void register_state(void);
|
||||
|
||||
private:
|
||||
bx_serial_t s[BX_SERIAL_MAXDEV];
|
||||
|
||||
int detect_mouse;
|
||||
int mouse_port;
|
||||
int mouse_type;
|
||||
int mouse_delayed_dx;
|
||||
int mouse_delayed_dy;
|
||||
int mouse_delayed_dz;
|
||||
struct {
|
||||
int num_elements;
|
||||
Bit8u buffer[BX_MOUSE_BUFF_SIZE];
|
||||
int head;
|
||||
} mouse_internal_buffer;
|
||||
|
||||
static void lower_interrupt(Bit8u port);
|
||||
static void raise_interrupt(Bit8u port, int type);
|
||||
|
||||
static void rx_fifo_enq(Bit8u port, Bit8u data);
|
||||
|
||||
static void tx_timer_handler(void *);
|
||||
BX_SER_SMF void tx_timer(void);
|
||||
|
||||
static void rx_timer_handler(void *);
|
||||
BX_SER_SMF void rx_timer(void);
|
||||
|
||||
static void fifo_timer_handler(void *);
|
||||
BX_SER_SMF void fifo_timer(void);
|
||||
|
||||
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
void mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
|
||||
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_SER_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
477
bochs/iodev/serial_raw.cc
Normal file
477
bochs/iodev/serial_raw.cc
Normal file
@ -0,0 +1,477 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if USE_RAW_SERIAL
|
||||
|
||||
#include "serial_raw.h"
|
||||
|
||||
#define LOG_THIS
|
||||
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
DWORD WINAPI RawSerialThread(VOID *this_ptr);
|
||||
#endif
|
||||
|
||||
serial_raw::serial_raw(const char *devname)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char portstr[MAX_PATH];
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
DWORD threadID;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
put ("SERR");
|
||||
#ifdef WIN32
|
||||
memset(&dcb, 0, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.fBinary = 1;
|
||||
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
||||
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
dcb.BaudRate = CBR_115200;
|
||||
DCBchanged = FALSE;
|
||||
if (lstrlen(devname) > 0) {
|
||||
wsprintf(portstr, "\\\\.\\%s", devname);
|
||||
hCOM = CreateFile(portstr, GENERIC_READ|GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (hCOM != INVALID_HANDLE_VALUE) {
|
||||
present = 1;
|
||||
GetCommModemStatus(hCOM, &MSR_value);
|
||||
SetupComm(hCOM, 8192, 2048);
|
||||
PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT |
|
||||
PURGE_TXCLEAR | PURGE_RXCLEAR);
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
SetCommMask(hCOM, EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR);
|
||||
memset(&rx_ovl, 0, sizeof(OVERLAPPED));
|
||||
rx_ovl.hEvent = CreateEvent(NULL,TRUE,FALSE,"receive");
|
||||
hRawSerialThread = CreateThread(NULL, 0, RawSerialThread, this, 0, &threadID);
|
||||
#endif
|
||||
} else {
|
||||
present = 0;
|
||||
BX_ERROR(("Raw device '%s' not present", devname));
|
||||
}
|
||||
} else {
|
||||
present = 0;
|
||||
}
|
||||
#else
|
||||
present = 0;
|
||||
#endif
|
||||
set_modem_control(0x00);
|
||||
set_break(0);
|
||||
rxdata_count = 0;
|
||||
}
|
||||
|
||||
serial_raw::~serial_raw(void)
|
||||
{
|
||||
if (present) {
|
||||
#ifdef WIN32
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
thread_quit = TRUE;
|
||||
SetCommMask(hCOM, 0);
|
||||
while (thread_active) Sleep(10);
|
||||
CloseHandle(thread_ovl.hEvent);
|
||||
CloseHandle(rx_ovl.hEvent);
|
||||
CloseHandle(hRawSerialThread);
|
||||
#endif
|
||||
CloseHandle(hCOM);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void serial_raw::set_baudrate(int rate)
|
||||
{
|
||||
BX_DEBUG (("set_baudrate %d", rate));
|
||||
#ifdef WIN32
|
||||
switch (rate) {
|
||||
case 110: dcb.BaudRate = CBR_110; break;
|
||||
case 300: dcb.BaudRate = CBR_300; break;
|
||||
case 600: dcb.BaudRate = CBR_600; break;
|
||||
case 1200: dcb.BaudRate = CBR_1200; break;
|
||||
case 2400: dcb.BaudRate = CBR_2400; break;
|
||||
case 4800: dcb.BaudRate = CBR_4800; break;
|
||||
case 9600: dcb.BaudRate = CBR_9600; break;
|
||||
case 19200: dcb.BaudRate = CBR_19200; break;
|
||||
case 38400: dcb.BaudRate = CBR_38400; break;
|
||||
case 57600: dcb.BaudRate = CBR_57600; break;
|
||||
case 115200: dcb.BaudRate = CBR_115200; break;
|
||||
default: BX_ERROR(("set_baudrate(): unsupported value %d", rate));
|
||||
}
|
||||
DCBchanged = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::set_data_bits(int val)
|
||||
{
|
||||
BX_DEBUG (("set data bits (%d)", val));
|
||||
#ifdef WIN32
|
||||
dcb.ByteSize = val;
|
||||
DCBchanged = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::set_stop_bits(int val)
|
||||
{
|
||||
BX_DEBUG (("set stop bits (%d)", val));
|
||||
#ifdef WIN32
|
||||
if (val == 1) {
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
} if (dcb.ByteSize == 5) {
|
||||
dcb.StopBits = ONE5STOPBITS;
|
||||
} else {
|
||||
dcb.StopBits = TWOSTOPBITS;
|
||||
}
|
||||
DCBchanged = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::set_parity_mode(int mode)
|
||||
{
|
||||
BX_DEBUG (("set parity mode %d", mode));
|
||||
#ifdef WIN32
|
||||
switch (mode) {
|
||||
case 0:
|
||||
dcb.fParity = FALSE;
|
||||
dcb.Parity = NOPARITY;
|
||||
break;
|
||||
case 1:
|
||||
dcb.fParity = TRUE;
|
||||
dcb.Parity = ODDPARITY;
|
||||
break;
|
||||
case 2:
|
||||
dcb.fParity = TRUE;
|
||||
dcb.Parity = EVENPARITY;
|
||||
break;
|
||||
case 3:
|
||||
dcb.fParity = TRUE;
|
||||
dcb.Parity = MARKPARITY;
|
||||
break;
|
||||
case 4:
|
||||
dcb.fParity = TRUE;
|
||||
dcb.Parity = SPACEPARITY;
|
||||
break;
|
||||
}
|
||||
DCBchanged = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::set_break(int mode)
|
||||
{
|
||||
BX_DEBUG (("set break %s", mode?"on":"off"));
|
||||
#ifdef WIN32
|
||||
if (mode) {
|
||||
SetCommBreak(hCOM);
|
||||
} else {
|
||||
ClearCommBreak(hCOM);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::set_modem_control(int ctrl)
|
||||
{
|
||||
BX_DEBUG (("set modem control 0x%02x", ctrl));
|
||||
#ifdef WIN32
|
||||
EscapeCommFunction(hCOM, (ctrl & 0x01)?SETDTR:CLRDTR);
|
||||
EscapeCommFunction(hCOM, (ctrl & 0x02)?SETRTS:CLRRTS);
|
||||
#endif
|
||||
}
|
||||
|
||||
int serial_raw::get_modem_status()
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
status = MSR_value;
|
||||
#endif
|
||||
BX_DEBUG (("get modem status returns 0x%02x", status));
|
||||
return status;
|
||||
}
|
||||
|
||||
void serial_raw::setup_port()
|
||||
{
|
||||
#ifdef WIN32
|
||||
DWORD DErr;
|
||||
COMMTIMEOUTS ctmo;
|
||||
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT |
|
||||
PURGE_TXCLEAR | PURGE_RXCLEAR);
|
||||
memset(&ctmo, 0, sizeof(ctmo));
|
||||
SetCommTimeouts(hCOM, &ctmo);
|
||||
SetCommState(hCOM, &dcb);
|
||||
rxdata_count = 0;
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
thread_rxdata_count = 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_raw::transmit(Bit8u byte)
|
||||
{
|
||||
#ifdef WIN32
|
||||
DWORD DErr, Len2;
|
||||
OVERLAPPED tx_ovl;
|
||||
#endif
|
||||
|
||||
BX_DEBUG (("transmit %d", byte));
|
||||
if (present) {
|
||||
#ifdef WIN32
|
||||
if (DCBchanged) {
|
||||
setup_port();
|
||||
} else {
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
}
|
||||
memset(&tx_ovl, 0, sizeof(OVERLAPPED));
|
||||
tx_ovl.hEvent = CreateEvent(NULL,TRUE,TRUE,"transmit");
|
||||
if (!WriteFile(hCOM, &byte, 1, &Len2, &tx_ovl)) {
|
||||
if (GetLastError() == ERROR_IO_PENDING) {
|
||||
if (WaitForSingleObject(tx_ovl.hEvent, 100) == WAIT_OBJECT_0) {
|
||||
GetOverlappedResult(hCOM, &tx_ovl, &Len2, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Len2 != 1) BX_ERROR(("transmit failed: len = %d", Len2));
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
CloseHandle(tx_ovl.hEvent);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool serial_raw::ready_transmit()
|
||||
{
|
||||
BX_DEBUG (("ready_transmit returning %d", present));
|
||||
return present;
|
||||
}
|
||||
|
||||
bx_bool serial_raw::ready_receive()
|
||||
{
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
|
||||
SetEvent(thread_ovl.hEvent);
|
||||
SetEvent(rx_ovl.hEvent);
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG (("ready_receive returning %d", (rxdata_count > 0)));
|
||||
return (rxdata_count > 0);
|
||||
}
|
||||
|
||||
int serial_raw::receive()
|
||||
{
|
||||
#ifdef WIN32
|
||||
int data;
|
||||
#endif
|
||||
|
||||
if (present) {
|
||||
#ifdef WIN32
|
||||
if (DCBchanged) {
|
||||
setup_port();
|
||||
}
|
||||
data = rxdata_buffer[0];
|
||||
if (rxdata_count > 0) {
|
||||
memcpy(&rxdata_buffer[0], &rxdata_buffer[1], sizeof(Bit16s)*(RX_BUFSIZE-1));
|
||||
rxdata_count--;
|
||||
}
|
||||
if (data < 0) {
|
||||
switch (data) {
|
||||
case RAW_EVENT_CTS_ON:
|
||||
MSR_value |= 0x10;
|
||||
break;
|
||||
case RAW_EVENT_CTS_OFF:
|
||||
MSR_value &= ~0x10;
|
||||
break;
|
||||
case RAW_EVENT_DSR_ON:
|
||||
MSR_value |= 0x20;
|
||||
break;
|
||||
case RAW_EVENT_DSR_OFF:
|
||||
MSR_value &= ~0x20;
|
||||
break;
|
||||
case RAW_EVENT_RING_ON:
|
||||
MSR_value |= 0x40;
|
||||
break;
|
||||
case RAW_EVENT_RING_OFF:
|
||||
MSR_value &= ~0x40;
|
||||
break;
|
||||
case RAW_EVENT_RLSD_ON:
|
||||
MSR_value |= 0x80;
|
||||
break;
|
||||
case RAW_EVENT_RLSD_OFF:
|
||||
MSR_value &= ~0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
#else
|
||||
BX_DEBUG (("receive returning 'A'"));
|
||||
return (int)'A';
|
||||
#endif
|
||||
} else {
|
||||
BX_DEBUG (("receive returning 'A'"));
|
||||
return (int)'A';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
|
||||
DWORD WINAPI RawSerialThread(VOID *this_ptr)
|
||||
{
|
||||
serial_raw *class_ptr = (serial_raw *) this_ptr;
|
||||
class_ptr->serial_thread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serial_raw::serial_thread()
|
||||
{
|
||||
DWORD DErr, Len2;
|
||||
DWORD EvtMask, MSR, Temp;
|
||||
char s1[2];
|
||||
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
|
||||
thread_active = TRUE;
|
||||
thread_quit = FALSE;
|
||||
memset(&thread_ovl, 0, sizeof(OVERLAPPED));
|
||||
thread_ovl.hEvent = CreateEvent(NULL,TRUE,TRUE,"thread");
|
||||
thread_rxdata_count = 0;
|
||||
while (!thread_quit) {
|
||||
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
|
||||
if (thread_rxdata_count > RX_BUFSIZE) {
|
||||
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE);
|
||||
memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE));
|
||||
rxdata_count = RX_BUFSIZE;
|
||||
thread_rxdata_count -= RX_BUFSIZE;
|
||||
} else {
|
||||
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count);
|
||||
rxdata_count = thread_rxdata_count;
|
||||
thread_rxdata_count = 0;
|
||||
}
|
||||
}
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
EvtMask = 0;
|
||||
if (!WaitCommEvent(hCOM, &EvtMask, &thread_ovl)) {
|
||||
if (GetLastError() == ERROR_IO_PENDING) {
|
||||
if (WaitForSingleObject(thread_ovl.hEvent, INFINITE) == WAIT_OBJECT_0) {
|
||||
GetOverlappedResult(hCOM, &thread_ovl, &Temp, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (EvtMask & EV_RXCHAR) {
|
||||
if (thread_rxdata_count < THREAD_RX_BUFSIZE) {
|
||||
do {
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
if (!ReadFile(hCOM, s1, 1, &Len2, &rx_ovl)) {
|
||||
if (GetLastError() == ERROR_IO_PENDING) {
|
||||
if (WaitForSingleObject(rx_ovl.hEvent, INFINITE) != WAIT_OBJECT_0) {
|
||||
Len2 = 0;
|
||||
} else {
|
||||
GetOverlappedResult(hCOM, &rx_ovl, &Len2, FALSE);
|
||||
}
|
||||
} else {
|
||||
Len2 = 0;
|
||||
}
|
||||
}
|
||||
if (Len2 > 0) {
|
||||
enq_event(s1[0]);
|
||||
}
|
||||
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
|
||||
if (thread_rxdata_count > RX_BUFSIZE) {
|
||||
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE);
|
||||
memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE));
|
||||
rxdata_count = RX_BUFSIZE;
|
||||
thread_rxdata_count -= RX_BUFSIZE;
|
||||
} else {
|
||||
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count);
|
||||
rxdata_count = thread_rxdata_count;
|
||||
thread_rxdata_count = 0;
|
||||
}
|
||||
}
|
||||
} while ((Len2 != 0) && (thread_rxdata_count < THREAD_RX_BUFSIZE));
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
}
|
||||
}
|
||||
if (EvtMask & EV_BREAK) {
|
||||
enq_event(RAW_EVENT_BREAK);
|
||||
}
|
||||
if (EvtMask & EV_ERR) {
|
||||
ClearCommError(hCOM, &DErr, NULL);
|
||||
if (DErr & CE_FRAME) {
|
||||
enq_event(RAW_EVENT_FRAME);
|
||||
}
|
||||
if (DErr & CE_OVERRUN) {
|
||||
enq_event(RAW_EVENT_OVERRUN);
|
||||
}
|
||||
if (DErr & CE_RXPARITY) {
|
||||
enq_event(RAW_EVENT_PARITY);
|
||||
}
|
||||
}
|
||||
if (EvtMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
|
||||
GetCommModemStatus(hCOM, &MSR);
|
||||
}
|
||||
if (EvtMask & EV_CTS) {
|
||||
if (MSR & MS_CTS_ON) {
|
||||
enq_event(RAW_EVENT_CTS_ON);
|
||||
} else {
|
||||
enq_event(RAW_EVENT_CTS_OFF);
|
||||
}
|
||||
}
|
||||
if (EvtMask & EV_DSR) {
|
||||
if (MSR & MS_DSR_ON) {
|
||||
enq_event(RAW_EVENT_DSR_ON);
|
||||
} else {
|
||||
enq_event(RAW_EVENT_DSR_OFF);
|
||||
}
|
||||
}
|
||||
if (EvtMask & EV_RING) {
|
||||
if (MSR & MS_RING_ON) {
|
||||
enq_event(RAW_EVENT_RING_ON);
|
||||
} else {
|
||||
enq_event(RAW_EVENT_RING_OFF);
|
||||
}
|
||||
}
|
||||
if (EvtMask & EV_RLSD) {
|
||||
if (MSR & MS_RLSD_ON) {
|
||||
enq_event(RAW_EVENT_RLSD_ON);
|
||||
} else {
|
||||
enq_event(RAW_EVENT_RLSD_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(thread_ovl.hEvent);
|
||||
thread_active = FALSE;
|
||||
}
|
||||
|
||||
void serial_raw::enq_event(Bit16s event)
|
||||
{
|
||||
if (thread_rxdata_count < THREAD_RX_BUFSIZE) {
|
||||
thread_rxdata_buffer[thread_rxdata_count++] = event;
|
||||
} else {
|
||||
fprintf(stderr, "receive buffer overflow\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
97
bochs/iodev/serial_raw.h
Normal file
97
bochs/iodev/serial_raw.h
Normal file
@ -0,0 +1,97 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#if USE_RAW_SERIAL
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/serial.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
// experimental raw serial receive support on win32
|
||||
//#define WIN32_RECEIVE_RAW
|
||||
#endif
|
||||
|
||||
#define P_NONE 0
|
||||
#define P_ODD 1
|
||||
#define P_EVEN 2
|
||||
#define P_HIGH 3
|
||||
#define P_LOW 4
|
||||
|
||||
#define RAW_EVENT_BREAK -1
|
||||
#define RAW_EVENT_CTS_ON -2
|
||||
#define RAW_EVENT_CTS_OFF -3
|
||||
#define RAW_EVENT_DSR_ON -4
|
||||
#define RAW_EVENT_DSR_OFF -5
|
||||
#define RAW_EVENT_RING_ON -6
|
||||
#define RAW_EVENT_RING_OFF -7
|
||||
#define RAW_EVENT_RLSD_ON -8
|
||||
#define RAW_EVENT_RLSD_OFF -9
|
||||
#define RAW_EVENT_FRAME -10
|
||||
#define RAW_EVENT_OVERRUN -11
|
||||
#define RAW_EVENT_PARITY -12
|
||||
|
||||
#define THREAD_RX_BUFSIZE 8192
|
||||
#define RX_BUFSIZE 256
|
||||
|
||||
class serial_raw : public logfunctions {
|
||||
public:
|
||||
serial_raw(const char *devname);
|
||||
virtual ~serial_raw();
|
||||
void set_baudrate(int rate);
|
||||
void set_data_bits(int);
|
||||
void set_stop_bits(int);
|
||||
void set_parity_mode(int mode);
|
||||
void set_break(int mode);
|
||||
void set_modem_control(int ctrl);
|
||||
int get_modem_status();
|
||||
void transmit(Bit8u byte);
|
||||
bx_bool ready_transmit();
|
||||
bx_bool ready_receive();
|
||||
int receive ();
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
void serial_thread();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void setup_port();
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
void enq_event(Bit16s event);
|
||||
#endif
|
||||
bx_bool present;
|
||||
unsigned rxdata_count;
|
||||
#ifdef WIN32
|
||||
HANDLE hCOM;
|
||||
DCB dcb;
|
||||
BOOL DCBchanged;
|
||||
DWORD MSR_value;
|
||||
Bit16s rxdata_buffer[RX_BUFSIZE];
|
||||
#ifdef WIN32_RECEIVE_RAW
|
||||
HANDLE hRawSerialThread;
|
||||
BOOL thread_active;
|
||||
BOOL thread_quit;
|
||||
OVERLAPPED rx_ovl;
|
||||
OVERLAPPED thread_ovl;
|
||||
unsigned thread_rxdata_count;
|
||||
Bit16s thread_rxdata_buffer[THREAD_RX_BUFSIZE];
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
179
bochs/iodev/slowdown_timer.cc
Normal file
179
bochs/iodev/slowdown_timer.cc
Normal file
@ -0,0 +1,179 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "bochs.h"
|
||||
#include "param_names.h"
|
||||
#include "slowdown_timer.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
//These need to stay printfs because they are useless in the log file.
|
||||
#define BX_SLOWDOWN_PRINTF_FEEDBACK 0
|
||||
|
||||
#define SECINUSEC 1000000
|
||||
#define usectosec(a) ((a)/SECINUSEC)
|
||||
#define sectousec(a) ((a)*SECINUSEC)
|
||||
#define nsectousec(a) ((a)/1000)
|
||||
|
||||
#define MSECINUSEC 1000
|
||||
#define usectomsec(a) ((a)/MSECINUSEC)
|
||||
|
||||
#define Qval 1000
|
||||
#define MAXMULT 1.5
|
||||
#define REALTIME_Q SECINUSEC
|
||||
|
||||
#define LOG_THIS bx_slowdown_timer.
|
||||
|
||||
bx_slowdown_timer_c bx_slowdown_timer;
|
||||
|
||||
bx_slowdown_timer_c::bx_slowdown_timer_c()
|
||||
{
|
||||
put("STIME");
|
||||
|
||||
s.start_time=0;
|
||||
s.start_emulated_time=0;
|
||||
s.timer_handle=BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
void bx_slowdown_timer_c::init(void)
|
||||
{
|
||||
// Return early if slowdown timer not selected
|
||||
if ((SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_SLOWDOWN) &&
|
||||
(SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_BOTH))
|
||||
return;
|
||||
|
||||
BX_INFO(("using 'slowdown' timer synchronization method"));
|
||||
s.MAXmultiplier=MAXMULT;
|
||||
s.Q=Qval;
|
||||
|
||||
if(s.MAXmultiplier<1)
|
||||
s.MAXmultiplier=1;
|
||||
|
||||
s.start_time=sectousec(time(NULL));
|
||||
s.start_emulated_time = bx_pc_system.time_usec();
|
||||
s.lasttime=0;
|
||||
if (s.timer_handle == BX_NULL_TIMER_HANDLE) {
|
||||
s.timer_handle=bx_pc_system.register_timer(this, timer_handler, 100 , 1, 1,
|
||||
"slowdown_timer");
|
||||
}
|
||||
bx_pc_system.deactivate_timer(s.timer_handle);
|
||||
bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
|
||||
}
|
||||
|
||||
void bx_slowdown_timer_c::exit(void)
|
||||
{
|
||||
s.timer_handle = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
void bx_slowdown_timer_c::after_restore_state(void)
|
||||
{
|
||||
s.start_emulated_time = bx_pc_system.time_usec();
|
||||
}
|
||||
|
||||
void bx_slowdown_timer_c::timer_handler(void * this_ptr)
|
||||
{
|
||||
bx_slowdown_timer_c * class_ptr = (bx_slowdown_timer_c *) this_ptr;
|
||||
class_ptr->handle_timer();
|
||||
}
|
||||
|
||||
void bx_slowdown_timer_c::handle_timer()
|
||||
{
|
||||
Bit64u total_emu_time = (bx_pc_system.time_usec()) - s.start_emulated_time;
|
||||
Bit64u wanttime = s.lasttime+s.Q;
|
||||
Bit64u totaltime = sectousec(time(NULL)) - s.start_time;
|
||||
Bit64u thistime=(wanttime>totaltime)?wanttime:totaltime;
|
||||
|
||||
#if BX_SLOWDOWN_PRINTF_FEEDBACK
|
||||
printf("Entering slowdown timer handler.\n");
|
||||
#endif
|
||||
|
||||
/* Decide if we're behind.
|
||||
* Set interrupt interval accordingly. */
|
||||
if(totaltime > total_emu_time) {
|
||||
bx_pc_system.deactivate_timer(s.timer_handle);
|
||||
bx_pc_system.activate_timer(s.timer_handle,
|
||||
(Bit32u)(s.MAXmultiplier * (float)((Bit64s)s.Q)), 0);
|
||||
#if BX_SLOWDOWN_PRINTF_FEEDBACK
|
||||
printf("running at MAX speed\n");
|
||||
#endif
|
||||
} else {
|
||||
bx_pc_system.deactivate_timer(s.timer_handle);
|
||||
bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
|
||||
#if BX_SLOWDOWN_PRINTF_FEEDBACK
|
||||
printf("running at NORMAL speed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure we took at least one time quantum. */
|
||||
/* This is a little strange. I'll try to explain.
|
||||
* We're running bochs one second ahead of real time.
|
||||
* this gives us a very precise division on whether
|
||||
* we're ahead or behind the second line.
|
||||
* Basically, here's how it works:
|
||||
* *****|******************|***********...
|
||||
* Time Time+1sec
|
||||
* <^Bochs doesn't delay.
|
||||
* ^>Bochs delays.
|
||||
* <^Bochs runs at MAX speed.
|
||||
* ^>Bochs runs at normal
|
||||
*/
|
||||
if(wanttime > (totaltime+REALTIME_Q)) {
|
||||
#if BX_HAVE_USLEEP
|
||||
usleep(s.Q);
|
||||
#elif BX_HAVE_MSLEEP
|
||||
msleep(usectomsec((Bit32u)s.Q));
|
||||
#elif BX_HAVE_SLEEP
|
||||
sleep(usectosec(s.Q));
|
||||
#else
|
||||
#error do not know have to sleep
|
||||
#endif //delay(wanttime-totaltime);
|
||||
/* alternatively: delay(Q);
|
||||
* This works okay because we share the delay between
|
||||
* two time quantums.
|
||||
*/
|
||||
#if BX_SLOWDOWN_PRINTF_FEEDBACK
|
||||
printf("DELAYING for a quantum\n");
|
||||
#endif
|
||||
}
|
||||
s.lasttime=thistime;
|
||||
|
||||
//Diagnostic info:
|
||||
#if 0
|
||||
if(wanttime > (totaltime+REALTIME_Q)) {
|
||||
if(totaltime > total_emu_time) {
|
||||
printf("Solving OpenBSD problem.\n");
|
||||
} else {
|
||||
printf("too fast.\n");
|
||||
}
|
||||
} else {
|
||||
if(totaltime > total_emu_time) {
|
||||
printf("too slow.\n");
|
||||
} else {
|
||||
printf("sometimes invalid state, normally okay.\n");
|
||||
}
|
||||
}
|
||||
#endif // Diagnostic info
|
||||
}
|
||||
|
||||
53
bochs/iodev/slowdown_timer.h
Normal file
53
bochs/iodev/slowdown_timer.h
Normal file
@ -0,0 +1,53 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#ifndef BX_IODEV_SLOWDOWN_TIMER_H
|
||||
#define BX_IODEV_SLOWDOWN_TIMER_H
|
||||
|
||||
class bx_slowdown_timer_c : public logfunctions {
|
||||
private:
|
||||
struct {
|
||||
Bit64u start_time;
|
||||
Bit64u start_emulated_time;
|
||||
Bit64u lasttime;
|
||||
|
||||
int timer_handle;
|
||||
|
||||
float MAXmultiplier;
|
||||
Bit64u Q; // sleep rate in usec
|
||||
} s;
|
||||
|
||||
public:
|
||||
bx_slowdown_timer_c();
|
||||
|
||||
void init(void);
|
||||
void exit(void);
|
||||
void after_restore_state(void);
|
||||
|
||||
static void timer_handler(void * this_ptr);
|
||||
|
||||
void handle_timer();
|
||||
|
||||
};
|
||||
|
||||
extern bx_slowdown_timer_c bx_slowdown_timer;
|
||||
|
||||
#endif
|
||||
530
bochs/iodev/soundlnx.cc
Normal file
530
bochs/iodev/soundlnx.cc
Normal file
@ -0,0 +1,530 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Josef Drexler coded the original version of the lowlevel sound support
|
||||
// for Linux using OSS. The current version also supports OSS on FreeBSD and
|
||||
// ALSA PCM output on Linux.
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && BX_SUPPORT_SB16
|
||||
|
||||
#define LOG_THIS device->
|
||||
|
||||
#include "soundmod.h"
|
||||
#include "soundlnx.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
bx_sound_linux_c::bx_sound_linux_c(logfunctions *dev)
|
||||
:bx_sound_output_c(dev)
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
alsa_seq.handle = NULL;
|
||||
alsa_pcm.handle = NULL;
|
||||
alsa_buffer = NULL;
|
||||
#endif
|
||||
midi = NULL;
|
||||
wavedevice = NULL;
|
||||
wave = -1;
|
||||
BX_INFO(("Sound output module 'linux' initialized"));
|
||||
}
|
||||
|
||||
bx_sound_linux_c::~bx_sound_linux_c()
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
|
||||
int bx_sound_linux_c::waveready()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_linux_c::midiready()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
int bx_sound_linux_c::alsa_seq_open(const char *alsadev)
|
||||
{
|
||||
char *mididev, *ptr;
|
||||
int client, port, ret = 0;
|
||||
int length = strlen(alsadev) + 1;
|
||||
|
||||
mididev = new char[length];
|
||||
|
||||
if (mididev == NULL)
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
strcpy(mididev, alsadev);
|
||||
ptr = strtok(mididev, ":");
|
||||
if (ptr == NULL) {
|
||||
BX_ERROR(("ALSA sequencer setup: missing client parameters"));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
client = atoi(ptr);
|
||||
ptr = strtok(NULL, ":");
|
||||
if (ptr == NULL) {
|
||||
BX_ERROR(("ALSA sequencer setup: missing port parameter"));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
port = atoi(ptr);
|
||||
|
||||
delete(mididev);
|
||||
|
||||
if (snd_seq_open(&alsa_seq.handle, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) {
|
||||
BX_ERROR(("Couldn't open ALSA sequencer for midi output"));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
ret = snd_seq_create_simple_port(alsa_seq.handle, NULL,
|
||||
SND_SEQ_PORT_CAP_WRITE |
|
||||
SND_SEQ_PORT_CAP_SUBS_WRITE |
|
||||
SND_SEQ_PORT_CAP_READ,
|
||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC);
|
||||
if (ret < 0) {
|
||||
BX_ERROR(("ALSA sequencer: error creating port %s", snd_strerror(errno)));
|
||||
} else {
|
||||
alsa_seq.source_port = ret;
|
||||
ret = snd_seq_connect_to(alsa_seq.handle, alsa_seq.source_port, client, port);
|
||||
if (ret < 0) {
|
||||
BX_ERROR(("ALSA sequencer: could not connect to port %d:%d", client, port));
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
snd_seq_close(alsa_seq.handle);
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
} else {
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int bx_sound_linux_c::openmidioutput(const char *mididev)
|
||||
{
|
||||
if ((mididev == NULL) || (strlen(mididev) < 1))
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
use_alsa_seq = !strncmp(mididev, "alsa:", 5);
|
||||
if (use_alsa_seq) {
|
||||
return alsa_seq_open(mididev+5);
|
||||
}
|
||||
#endif
|
||||
|
||||
midi = fopen(mididev,"w");
|
||||
|
||||
if (midi == NULL) {
|
||||
BX_ERROR(("Couldn't open midi output device %s: %s",
|
||||
mididev, strerror(errno)));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
int bx_sound_linux_c::alsa_seq_output(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
int cmd, chan, value;
|
||||
snd_seq_event_t ev;
|
||||
|
||||
snd_seq_ev_clear(&ev);
|
||||
snd_seq_ev_set_source(&ev, alsa_seq.source_port);
|
||||
snd_seq_ev_set_subs(&ev);
|
||||
snd_seq_ev_set_direct(&ev);
|
||||
cmd = command & 0xf0;
|
||||
chan = command & 0x0f;
|
||||
switch (cmd) {
|
||||
case 0x80:
|
||||
ev.type = SND_SEQ_EVENT_NOTEOFF;
|
||||
ev.data.note.channel = chan;
|
||||
ev.data.note.note = data[0];
|
||||
ev.data.note.velocity = data[1];
|
||||
ev.data.note.duration = delta;
|
||||
break;
|
||||
case 0x90:
|
||||
ev.type = SND_SEQ_EVENT_NOTEON;
|
||||
ev.data.note.channel = chan;
|
||||
ev.data.note.note = data[0];
|
||||
ev.data.note.velocity = data[1];
|
||||
ev.data.note.duration = 0;
|
||||
break;
|
||||
case 0xa0:
|
||||
ev.type = SND_SEQ_EVENT_KEYPRESS;
|
||||
ev.data.control.channel = chan;
|
||||
ev.data.control.param = data[0];
|
||||
ev.data.control.value = data[1];
|
||||
break;
|
||||
case 0xb0:
|
||||
ev.type = SND_SEQ_EVENT_CONTROLLER;
|
||||
ev.data.control.channel = chan;
|
||||
ev.data.control.param = data[0];
|
||||
ev.data.control.value = data[1];
|
||||
break;
|
||||
case 0xc0:
|
||||
ev.type = SND_SEQ_EVENT_PGMCHANGE;
|
||||
ev.data.control.channel = chan;
|
||||
ev.data.control.value = data[0];
|
||||
break;
|
||||
case 0xd0:
|
||||
ev.type = SND_SEQ_EVENT_CHANPRESS;
|
||||
ev.data.control.channel = chan;
|
||||
ev.data.control.value = data[0];
|
||||
break;
|
||||
case 0xe0:
|
||||
ev.type = SND_SEQ_EVENT_PITCHBEND;
|
||||
ev.data.control.channel = chan;
|
||||
value = data[0] | (data[1] << 7);
|
||||
value -= 0x2000;
|
||||
ev.data.control.value = value;
|
||||
break;
|
||||
case 0xf0:
|
||||
BX_ERROR(("alsa_seq_output(): SYSEX not implemented, length=%d", length));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
default:
|
||||
BX_ERROR(("alsa_seq_output(): unknown command 0x%02x, length=%d", command, length));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
snd_seq_event_output(alsa_seq.handle, &ev);
|
||||
snd_seq_drain_output(alsa_seq.handle);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bx_sound_linux_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if ((use_alsa_seq) && (alsa_seq.handle != NULL)) {
|
||||
return alsa_seq_output(delta, command, length, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
UNUSED(delta);
|
||||
|
||||
fputc(command, midi);
|
||||
fwrite(data, 1, length, midi);
|
||||
fflush(midi); // to start playing immediately
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
|
||||
int bx_sound_linux_c::closemidioutput()
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if ((use_alsa_seq) && (alsa_seq.handle != NULL)) {
|
||||
snd_seq_close(alsa_seq.handle);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
#endif
|
||||
fclose(midi);
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
|
||||
int bx_sound_linux_c::openwaveoutput(const char *wavedev)
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
use_alsa_pcm = !strcmp(wavedev, "alsa");
|
||||
if (use_alsa_pcm) {
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
#endif
|
||||
int length = strlen(wavedev) + 1;
|
||||
|
||||
if (wavedevice != NULL)
|
||||
delete(wavedevice);
|
||||
|
||||
wavedevice = new char[length];
|
||||
|
||||
if (wavedevice == NULL)
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
strncpy(wavedevice, wavedev, length);
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
int bx_sound_linux_c::alsa_pcm_open(int frequency, int bits, int stereo, int format)
|
||||
{
|
||||
int ret;
|
||||
snd_pcm_format_t fmt;
|
||||
snd_pcm_hw_params_t *params;
|
||||
unsigned int size, freq;
|
||||
int signeddata = format & 1;
|
||||
|
||||
audio_bufsize = 0;
|
||||
|
||||
if (alsa_pcm.handle == NULL) {
|
||||
ret = snd_pcm_open(&alsa_pcm.handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
BX_INFO(("ALSA: opened default PCM output device"));
|
||||
}
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
snd_pcm_hw_params_any(alsa_pcm.handle, params);
|
||||
snd_pcm_hw_params_set_access(alsa_pcm.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
|
||||
if ((frequency == oldfreq) &&
|
||||
(bits == oldbits) &&
|
||||
(stereo == oldstereo) &&
|
||||
(format == oldformat))
|
||||
return BX_SOUND_OUTPUT_OK; // nothing to do
|
||||
|
||||
oldfreq = frequency;
|
||||
oldbits = bits;
|
||||
oldstereo = stereo;
|
||||
oldformat = format;
|
||||
|
||||
freq = (unsigned int)frequency;
|
||||
|
||||
if (bits == 16) {
|
||||
if (signeddata == 1)
|
||||
fmt = SND_PCM_FORMAT_S16_LE;
|
||||
else
|
||||
fmt = SND_PCM_FORMAT_U16_LE;
|
||||
size = 2;
|
||||
} else if (bits == 8) {
|
||||
if (signeddata == 1)
|
||||
fmt = SND_PCM_FORMAT_S8;
|
||||
else
|
||||
fmt = SND_PCM_FORMAT_U8;
|
||||
size = 1;
|
||||
} else
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
if (stereo) size *= 2;
|
||||
|
||||
snd_pcm_hw_params_set_format(alsa_pcm.handle, params, fmt);
|
||||
snd_pcm_hw_params_set_channels(alsa_pcm.handle, params, (stereo != 0) ? 2 : 1);
|
||||
snd_pcm_hw_params_set_rate_near(alsa_pcm.handle, params, &freq, &dir);
|
||||
|
||||
alsa_pcm.frames = 32;
|
||||
snd_pcm_hw_params_set_period_size_near(alsa_pcm.handle, params, &alsa_pcm.frames, &dir);
|
||||
|
||||
ret = snd_pcm_hw_params(alsa_pcm.handle, params);
|
||||
if (ret < 0) {
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
snd_pcm_hw_params_get_period_size(params, &alsa_pcm.frames, &dir);
|
||||
alsa_bufsize = alsa_pcm.frames * size;
|
||||
BX_DEBUG(("ALSA: buffer size set to %d", alsa_bufsize));
|
||||
if (alsa_buffer != NULL) {
|
||||
free(alsa_buffer);
|
||||
alsa_buffer = NULL;
|
||||
}
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bx_sound_linux_c::startwaveplayback(int frequency, int bits, int stereo, int format)
|
||||
{
|
||||
int fmt, ret;
|
||||
int signeddata = format & 1;
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if (use_alsa_pcm) {
|
||||
return alsa_pcm_open(frequency, bits, stereo, format);
|
||||
}
|
||||
#endif
|
||||
if ((wavedevice == NULL) || (strlen(wavedevice) < 1))
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
if (wave == -1) {
|
||||
wave = open(wavedevice, O_WRONLY);
|
||||
if (wave == -1) {
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
} else {
|
||||
BX_INFO(("OSS: opened output device %s", wavedevice));
|
||||
}
|
||||
} else {
|
||||
if ((frequency == oldfreq) &&
|
||||
(bits == oldbits) &&
|
||||
(stereo == oldstereo) &&
|
||||
(format == oldformat))
|
||||
return BX_SOUND_OUTPUT_OK; // nothing to do
|
||||
}
|
||||
oldfreq = frequency;
|
||||
oldbits = bits;
|
||||
oldstereo = stereo;
|
||||
oldformat = format;
|
||||
|
||||
if (bits == 16)
|
||||
if (signeddata == 1)
|
||||
fmt = AFMT_S16_LE;
|
||||
else
|
||||
fmt = AFMT_U16_LE;
|
||||
else if (bits == 8)
|
||||
if (signeddata == 1)
|
||||
fmt = AFMT_S8;
|
||||
else
|
||||
fmt = AFMT_U8;
|
||||
else
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
// set frequency etc.
|
||||
ret = ioctl(wave, SNDCTL_DSP_RESET);
|
||||
if (ret != 0)
|
||||
BX_DEBUG(("ioctl(SNDCTL_DSP_RESET): %s", strerror(errno)));
|
||||
|
||||
/*
|
||||
ret = ioctl(wave, SNDCTL_DSP_SETFRAGMENT, &fragment);
|
||||
if (ret != 0)
|
||||
WRITELOG(WAVELOG(4), "ioctl(SNDCTL_DSP_SETFRAGMENT, %d): %s",
|
||||
fragment, strerror(errno));
|
||||
*/
|
||||
|
||||
ret = ioctl(wave, SNDCTL_DSP_SETFMT, &fmt);
|
||||
if (ret != 0) // abort if the format is unknown, to avoid playing noise
|
||||
{
|
||||
BX_DEBUG(("ioctl(SNDCTL_DSP_SETFMT, %d): %s",
|
||||
fmt, strerror(errno)));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
ret = ioctl(wave, SNDCTL_DSP_STEREO, &stereo);
|
||||
if (ret != 0)
|
||||
BX_DEBUG(("ioctl(SNDCTL_DSP_STEREO, %d): %s",
|
||||
stereo, strerror(errno)));
|
||||
|
||||
ret = ioctl(wave, SNDCTL_DSP_SPEED, &frequency);
|
||||
if (ret != 0)
|
||||
BX_DEBUG(("ioctl(SNDCTL_DSP_SPEED, %d): %s",
|
||||
frequency, strerror(errno)));
|
||||
|
||||
// ioctl(wave, SNDCTL_DSP_GETBLKSIZE, &fragment);
|
||||
// BX_DEBUG(("current output block size is %d", fragment));
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
int bx_sound_linux_c::alsa_pcm_write()
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (alsa_buffer == NULL) {
|
||||
alsa_buffer = (char *)malloc(alsa_bufsize);
|
||||
}
|
||||
while (audio_bufsize >= alsa_bufsize) {
|
||||
memcpy(alsa_buffer, audio_buffer, alsa_bufsize);
|
||||
ret = snd_pcm_writei(alsa_pcm.handle, alsa_buffer, alsa_pcm.frames);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret == -EPIPE) {
|
||||
/* EPIPE means underrun */
|
||||
BX_ERROR(("ALSA: underrun occurred"));
|
||||
snd_pcm_prepare(alsa_pcm.handle);
|
||||
} else if (ret < 0) {
|
||||
BX_ERROR(("ALSA: error from writei: %s", snd_strerror(ret)));
|
||||
} else if (ret != (int)alsa_pcm.frames) {
|
||||
BX_ERROR(("ALSA: short write, write %d frames", ret));
|
||||
}
|
||||
audio_bufsize -= alsa_bufsize;
|
||||
memcpy(audio_buffer, audio_buffer+alsa_bufsize, audio_bufsize);
|
||||
}
|
||||
if ((audio_bufsize == 0) && (alsa_buffer != NULL)) {
|
||||
free(alsa_buffer);
|
||||
alsa_buffer = NULL;
|
||||
}
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bx_sound_linux_c::sendwavepacket(int length, Bit8u data[])
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if (use_alsa_pcm) {
|
||||
if ((audio_bufsize+length) <= BX_SOUND_LINUX_BUFSIZE) {
|
||||
memcpy(audio_buffer+audio_bufsize, data, length);
|
||||
audio_bufsize += length;
|
||||
} else {
|
||||
BX_ERROR(("ALSA: audio buffer overflow"));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
if (audio_bufsize < alsa_bufsize) {
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
} else {
|
||||
return alsa_pcm_write();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int ret = write(wave, data, length);
|
||||
|
||||
if (ret == length) {
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
} else {
|
||||
BX_ERROR(("OSS: write error"));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
int bx_sound_linux_c::stopwaveplayback()
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if (use_alsa_pcm && (audio_bufsize > 0)) {
|
||||
if (audio_bufsize < alsa_bufsize) {
|
||||
memset(audio_buffer+audio_bufsize, 0, alsa_bufsize-audio_bufsize);
|
||||
audio_bufsize = alsa_bufsize;
|
||||
}
|
||||
alsa_pcm_write();
|
||||
}
|
||||
#endif
|
||||
// ioctl(wave, SNDCTL_DSP_SYNC);
|
||||
// close(wave);
|
||||
// wave = -1;
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_linux_c::closewaveoutput()
|
||||
{
|
||||
#if BX_HAVE_ALSASOUND
|
||||
if (use_alsa_pcm && (alsa_pcm.handle != NULL)) {
|
||||
snd_pcm_drain(alsa_pcm.handle);
|
||||
snd_pcm_close(alsa_pcm.handle);
|
||||
alsa_pcm.handle = NULL;
|
||||
}
|
||||
#endif
|
||||
if (wavedevice != NULL)
|
||||
delete(wavedevice);
|
||||
|
||||
if (wave != -1)
|
||||
{
|
||||
close(wave);
|
||||
wave = -1;
|
||||
}
|
||||
wavedevice = NULL;
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
81
bochs/iodev/soundlnx.h
Normal file
81
bochs/iodev/soundlnx.h
Normal file
@ -0,0 +1,81 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Josef Drexler coded the original version of the lowlevel sound support
|
||||
// for Linux using OSS. The current version also supports OSS on FreeBSD and
|
||||
// ALSA PCM output on Linux.
|
||||
|
||||
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
|
||||
|
||||
#define BX_SOUND_LINUX_BUFSIZE BX_SOUND_OUTPUT_WAVEPACKETSIZE * 2
|
||||
|
||||
#if BX_HAVE_ALSASOUND
|
||||
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
class bx_sound_linux_c : public bx_sound_output_c {
|
||||
public:
|
||||
bx_sound_linux_c(logfunctions *dev);
|
||||
virtual ~bx_sound_linux_c();
|
||||
|
||||
virtual int waveready();
|
||||
virtual int midiready();
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
virtual int openwaveoutput(const char *wavedev);
|
||||
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
|
||||
virtual int sendwavepacket(int length, Bit8u data[]);
|
||||
virtual int stopwaveplayback();
|
||||
virtual int closewaveoutput();
|
||||
|
||||
private:
|
||||
#if BX_HAVE_ALSASOUND
|
||||
int alsa_seq_open(const char *alsadev);
|
||||
int alsa_seq_output(int delta, int command, int length, Bit8u data[]);
|
||||
int alsa_pcm_open(int frequency, int bits, int stereo, int format);
|
||||
int alsa_pcm_write();
|
||||
|
||||
bx_bool use_alsa_seq;
|
||||
bx_bool use_alsa_pcm;
|
||||
struct {
|
||||
snd_seq_t *handle;
|
||||
int source_port;
|
||||
} alsa_seq;
|
||||
struct {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_uframes_t frames;
|
||||
} alsa_pcm;
|
||||
int dir, alsa_bufsize, audio_bufsize;
|
||||
char *alsa_buffer;
|
||||
#endif
|
||||
FILE *midi;
|
||||
char *wavedevice;
|
||||
int wave;
|
||||
Bit8u audio_buffer[BX_SOUND_LINUX_BUFSIZE];
|
||||
int oldfreq,oldbits,oldstereo,oldformat;
|
||||
};
|
||||
|
||||
#endif
|
||||
140
bochs/iodev/soundmod.cc
Normal file
140
bochs/iodev/soundmod.cc
Normal file
@ -0,0 +1,140 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Common sound module code and dummy sound output functions
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if BX_SUPPORT_SB16
|
||||
|
||||
#include "soundmod.h"
|
||||
#include "soundlnx.h"
|
||||
#include "soundosx.h"
|
||||
#include "soundwin.h"
|
||||
|
||||
#define LOG_THIS dev->
|
||||
|
||||
bx_soundmod_ctl_c* theSoundModCtl = NULL;
|
||||
|
||||
int libsoundmod_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theSoundModCtl = new bx_soundmod_ctl_c;
|
||||
bx_devices.pluginSoundModCtl = theSoundModCtl;
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libsoundmod_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theSoundModCtl;
|
||||
}
|
||||
|
||||
int bx_soundmod_ctl_c::init_module(const char *type, void **module, logfunctions *dev)
|
||||
{
|
||||
bx_sound_output_c **soundmod = (bx_sound_output_c**)module;
|
||||
|
||||
if (!strcmp(type, "default")) {
|
||||
*soundmod = new BX_SOUND_OUTPUT_C(dev);
|
||||
} else if (!strcmp(type, "dummy")) {
|
||||
*soundmod = new bx_sound_output_c(dev);
|
||||
} else {
|
||||
BX_PANIC(("unknown sound module type '%s'", type));
|
||||
*soundmod = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The dummy sound output functions. They don't do anything.
|
||||
bx_sound_output_c::bx_sound_output_c(logfunctions *dev)
|
||||
{
|
||||
device = dev;
|
||||
}
|
||||
|
||||
bx_sound_output_c::~bx_sound_output_c()
|
||||
{
|
||||
}
|
||||
|
||||
int bx_sound_output_c::waveready()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::midiready()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::openmidioutput(const char *mididev)
|
||||
{
|
||||
UNUSED(mididev);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
UNUSED(delta);
|
||||
UNUSED(command);
|
||||
UNUSED(length);
|
||||
UNUSED(data);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::closemidioutput()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::openwaveoutput(const char *wavedev)
|
||||
{
|
||||
UNUSED(wavedev);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::startwaveplayback(int frequency, int bits, int stereo, int format)
|
||||
{
|
||||
UNUSED(frequency);
|
||||
UNUSED(bits);
|
||||
UNUSED(stereo);
|
||||
UNUSED(format);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::sendwavepacket(int length, Bit8u data[])
|
||||
{
|
||||
UNUSED(length);
|
||||
UNUSED(data);
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::stopwaveplayback()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_output_c::closewaveoutput()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
68
bochs/iodev/soundmod.h
Normal file
68
bochs/iodev/soundmod.h
Normal file
@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Common code for sound output modules
|
||||
|
||||
// this is the size of a DMA chunk sent to output
|
||||
// it should not be too large to avoid lag, and not too
|
||||
// small to avoid unnecessary overhead.
|
||||
#define BX_SOUND_OUTPUT_WAVEPACKETSIZE 8192
|
||||
|
||||
// Definitions for the output functions
|
||||
#define BX_SOUND_OUTPUT_OK 0
|
||||
#define BX_SOUND_OUTPUT_ERR 1
|
||||
|
||||
// Pseudo device that loads the lowlevel sound module
|
||||
class bx_soundmod_ctl_c : public bx_soundmod_ctl_stub_c {
|
||||
public:
|
||||
bx_soundmod_ctl_c() {}
|
||||
virtual ~bx_soundmod_ctl_c() {}
|
||||
virtual int init_module(const char *type, void **module, logfunctions *dev);
|
||||
};
|
||||
|
||||
// The class with the output functions
|
||||
class bx_sound_output_c : public logfunctions {
|
||||
public:
|
||||
|
||||
/*
|
||||
These functions are the sound output functions, sending
|
||||
the music/sound to the OS specific driver.
|
||||
They are in a different file (soundxxx.cc) because they are
|
||||
non-portable, while everything in sb16.cc is portable
|
||||
*/
|
||||
|
||||
bx_sound_output_c(logfunctions *dev);
|
||||
virtual ~bx_sound_output_c();
|
||||
|
||||
virtual int waveready();
|
||||
virtual int midiready();
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
virtual int openwaveoutput(const char *wavedev);
|
||||
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
|
||||
virtual int sendwavepacket(int length, Bit8u data[]);
|
||||
virtual int stopwaveplayback();
|
||||
virtual int closewaveoutput();
|
||||
protected:
|
||||
logfunctions *device;
|
||||
};
|
||||
409
bochs/iodev/soundosx.cc
Normal file
409
bochs/iodev/soundosx.cc
Normal file
@ -0,0 +1,409 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// This file (SOUNDOSX.CC) written and donated by Brian Huffman
|
||||
|
||||
#ifdef PARANOID
|
||||
#include <MacTypes.h>
|
||||
#endif
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if defined(macintosh) && BX_SUPPORT_SB16
|
||||
|
||||
#define LOG_THIS device->
|
||||
|
||||
#include "soundmod.h"
|
||||
#include "soundosx.h"
|
||||
|
||||
#if BX_WITH_MACOS
|
||||
#include <QuickTimeMusic.h>
|
||||
#else
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/DefaultAudioOutput.h>
|
||||
#include <AudioToolbox/AudioConverter.h>
|
||||
#include <AudioToolbox/AUGraph.h>
|
||||
#include <QuickTime/QuickTimeMusic.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData);
|
||||
OSStatus MyACInputProc (AudioConverterRef inAudioConverter, UInt32* outDataSize,
|
||||
void** outData, void* inUserData);
|
||||
#endif
|
||||
|
||||
// Global variables
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
AUGraph MidiGraph;
|
||||
AudioUnit synthUnit;
|
||||
#endif
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
SndChannelPtr WaveChannel;
|
||||
ExtSoundHeader WaveInfo;
|
||||
ExtSoundHeader WaveHeader[BX_SOUND_OSX_NBUF];
|
||||
#endif
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
AudioUnit WaveOutputUnit = NULL;
|
||||
AudioConverterRef WaveConverter = NULL;
|
||||
#endif
|
||||
|
||||
bx_sound_osx_c::bx_sound_osx_c(logfunctions *dev)
|
||||
:bx_sound_output_c(dev)
|
||||
{
|
||||
MidiOpen = 0;
|
||||
WaveOpen = 0;
|
||||
head = 0;
|
||||
tail = 0;
|
||||
for (int i=0; i<BX_SOUND_OSX_NBUF; i++)
|
||||
WaveLength[i] = 0;
|
||||
BX_INFO(("Sound output module 'osx' initialized"));
|
||||
}
|
||||
|
||||
bx_sound_osx_c::~bx_sound_osx_c()
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
|
||||
int bx_sound_osx_c::midiready()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::openmidioutput(const char *mididev)
|
||||
{
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
ComponentDescription description;
|
||||
AUNode synthNode, outputNode;
|
||||
|
||||
// Create the graph
|
||||
NewAUGraph (&MidiGraph);
|
||||
|
||||
// Open the DLS Synth
|
||||
description.componentType = kAudioUnitComponentType;
|
||||
description.componentSubType = kAudioUnitSubType_MusicDevice;
|
||||
description.componentManufacturer = kAudioUnitID_DLSSynth;
|
||||
description.componentFlags = 0;
|
||||
description.componentFlagsMask = 0;
|
||||
AUGraphNewNode (MidiGraph, &description, 0, NULL, &synthNode);
|
||||
|
||||
// Open the output device
|
||||
description.componentType = kAudioUnitComponentType;
|
||||
description.componentSubType = kAudioUnitSubType_Output;
|
||||
description.componentManufacturer = kAudioUnitID_DefaultOutput;
|
||||
description.componentFlags = 0;
|
||||
description.componentFlagsMask = 0;
|
||||
AUGraphNewNode (MidiGraph, &description, 0, NULL, &outputNode);
|
||||
|
||||
// Connect the devices up
|
||||
AUGraphConnectNodeInput (MidiGraph, synthNode, 1, outputNode, 0);
|
||||
AUGraphUpdate (MidiGraph, NULL);
|
||||
|
||||
// Open and initialize the audio units
|
||||
AUGraphOpen (MidiGraph);
|
||||
AUGraphInitialize (MidiGraph);
|
||||
|
||||
// Turn off the reverb on the synth
|
||||
AUGraphGetNodeInfo (MidiGraph, synthNode, NULL, NULL, NULL, &synthUnit);
|
||||
UInt32 usesReverb = 0;
|
||||
AudioUnitSetProperty (synthUnit, kMusicDeviceProperty_UsesInternalReverb,
|
||||
kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb));
|
||||
|
||||
// Start playing
|
||||
AUGraphStart (MidiGraph);
|
||||
#endif
|
||||
BX_DEBUG(("openmidioutput(%s)", mididev));
|
||||
MidiOpen = 1;
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
BX_DEBUG(("sendmidicommand(%i,%02x,%i)", delta, command, length));
|
||||
if (!MidiOpen) return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
if (length <= 2) {
|
||||
Bit8u arg1 = (length >=1) ? data[0] : 0;
|
||||
Bit8u arg2 = (length >=2) ? data[1] : 0;
|
||||
MusicDeviceMIDIEvent (synthUnit, command, arg1, arg2, delta);
|
||||
}
|
||||
else {
|
||||
MusicDeviceSysEx (synthUnit, data, length);
|
||||
}
|
||||
#endif
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::closemidioutput()
|
||||
{
|
||||
BX_DEBUG(("closemidioutput()"));
|
||||
MidiOpen = 0;
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
AUGraphStop (MidiGraph);
|
||||
AUGraphClose (MidiGraph);
|
||||
#endif
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
#if BX_WITH_MACOS
|
||||
pascal
|
||||
#endif
|
||||
void WaveCallbackProc (SndChannelPtr chan, SndCommand *cmd)
|
||||
{
|
||||
// a new buffer is available, so increment tail pointer
|
||||
int *tail = (int *) (cmd->param2);
|
||||
(*tail)++;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bx_sound_osx_c::openwaveoutput(const char *wavedev)
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
BX_DEBUG(("openwaveoutput(%s)", wavedev));
|
||||
|
||||
// open the default output unit
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
err = SndNewChannel (&WaveChannel, sampledSynth, 0, NewSndCallBackUPP(WaveCallbackProc));
|
||||
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
|
||||
#endif
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
err = OpenDefaultAudioOutput (&WaveOutputUnit);
|
||||
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
|
||||
AudioUnitInitialize (WaveOutputUnit);
|
||||
|
||||
// Set up a callback function to generate output to the output unit
|
||||
AudioUnitInputCallback input;
|
||||
input.inputProc = MyRenderer;
|
||||
input.inputProcRefCon = (void *) this;
|
||||
AudioUnitSetProperty (WaveOutputUnit, kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Global, 0, &input, sizeof(input));
|
||||
#endif
|
||||
|
||||
WaveOpen = 1;
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::startwaveplayback(int frequency, int bits, int stereo, int format)
|
||||
{
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
static int oldfreq, oldbits, oldstereo, oldformat;
|
||||
AudioStreamBasicDescription srcFormat, dstFormat;
|
||||
UInt32 formatSize = sizeof(AudioStreamBasicDescription);
|
||||
#endif
|
||||
|
||||
BX_DEBUG(("startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format));
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
WaveInfo.samplePtr = NULL;
|
||||
WaveInfo.numChannels = stereo ? 2 : 1;
|
||||
WaveInfo.sampleRate = frequency << 16; // sampleRate is a 16.16 fixed-point value
|
||||
WaveInfo.loopStart = 0;
|
||||
WaveInfo.loopEnd = 0;
|
||||
WaveInfo.encode = extSH; // WaveInfo has type ExtSoundHeader
|
||||
WaveInfo.baseFrequency = 1; // not sure what means. It's only a Uint8.
|
||||
WaveInfo.numFrames = 0;
|
||||
//WaveInfo.AIFFSampleRate = frequency; // frequency as float80
|
||||
WaveInfo.markerChunk = NULL;
|
||||
|
||||
WaveInfo.instrumentChunks = NULL;
|
||||
WaveInfo.AESRecording = NULL;
|
||||
WaveInfo.sampleSize = bits * WaveInfo.numChannels;
|
||||
#endif
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
if ((frequency == oldfreq) &&
|
||||
(bits == oldbits) &&
|
||||
(stereo == oldstereo) &&
|
||||
(format == oldformat))
|
||||
return BX_SOUND_OUTPUT_OK; // nothing to do
|
||||
|
||||
oldfreq = frequency;
|
||||
oldbits = bits;
|
||||
oldstereo = stereo;
|
||||
oldformat = format;
|
||||
|
||||
// update the source audio format
|
||||
UInt32 bytes = bits / 8;
|
||||
UInt32 channels = stereo ? 2 : 1;
|
||||
srcFormat.mSampleRate = (Float64) frequency;
|
||||
srcFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
srcFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
if (format & 1) srcFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
srcFormat.mBytesPerPacket = channels * bytes;
|
||||
srcFormat.mFramesPerPacket = 1;
|
||||
srcFormat.mBytesPerFrame = channels * bytes;
|
||||
srcFormat.mChannelsPerFrame = channels;
|
||||
srcFormat.mBitsPerChannel = bytes * 8;
|
||||
|
||||
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
|
||||
if (WaveConverter) AudioConverterDispose (WaveConverter);
|
||||
|
||||
AudioUnitGetProperty (WaveOutputUnit, kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Output, 0, &dstFormat, &formatSize);
|
||||
|
||||
AudioConverterNew (&srcFormat, &dstFormat, &WaveConverter);
|
||||
|
||||
if (srcFormat.mChannelsPerFrame == 1 && dstFormat.mChannelsPerFrame == 2) {
|
||||
// map single-channel input to both output channels
|
||||
SInt32 map[2] = {0,0};
|
||||
AudioConverterSetProperty (WaveConverter, kAudioConverterChannelMap,
|
||||
sizeof(map), (void*) map);
|
||||
}
|
||||
|
||||
if (WavePlaying) AudioOutputUnitStart (WaveOutputUnit);
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::waveready()
|
||||
{
|
||||
// HACK: the -4 is to keep from overwriting buffers that
|
||||
// have been sent, but possibly not yet played. There
|
||||
// should be a better way of doing this.
|
||||
if (WaveOpen && (head - tail < BX_SOUND_OSX_NBUF-4)) {
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
else {
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
// If buffer is full, make sure sound is playing
|
||||
if (WaveOutputUnit && !WavePlaying) {
|
||||
AudioOutputUnitStart (WaveOutputUnit);
|
||||
WavePlaying = 1;
|
||||
}
|
||||
#endif
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::sendwavepacket(int length, Bit8u data[])
|
||||
{
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
SndCommand mySndCommand;
|
||||
#endif
|
||||
|
||||
BX_DEBUG(("sendwavepacket(%d, %p), head=%u", length, data, head));
|
||||
|
||||
// sanity check
|
||||
if ((!WaveOpen) || (head - tail >= BX_SOUND_OSX_NBUF))
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
// find next available buffer
|
||||
int n = head++ % BX_SOUND_OSX_NBUF;
|
||||
|
||||
// put data in buffer
|
||||
memcpy(WaveData[n], data, length);
|
||||
WaveLength[n] = length;
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
memcpy(&WaveHeader[n], &WaveInfo, sizeof(WaveInfo));
|
||||
WaveHeader[n].samplePtr = (char *) (WaveData[n]);
|
||||
WaveHeader[n].numFrames = length * 8 / WaveInfo.sampleSize;
|
||||
#endif
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
// make sure that the sound is playing
|
||||
if (!WavePlaying) {
|
||||
AudioOutputUnitStart (WaveOutputUnit);
|
||||
WavePlaying = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_quicktime
|
||||
// queue buffer to play
|
||||
mySndCommand.cmd = bufferCmd;
|
||||
mySndCommand.param1 = 0;
|
||||
mySndCommand.param2 = (long)(&WaveHeader[n]);
|
||||
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
|
||||
|
||||
// queue callback for when buffer finishes
|
||||
mySndCommand.cmd = callBackCmd;
|
||||
mySndCommand.param1 = 0;
|
||||
mySndCommand.param2 = (long)(&tail);
|
||||
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::stopwaveplayback()
|
||||
{
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_osx_c::closewaveoutput()
|
||||
{
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
|
||||
if (WaveConverter) AudioConverterDispose (WaveConverter);
|
||||
if (WaveOutputUnit) CloseComponent (WaveOutputUnit);
|
||||
WavePlaying = 0;
|
||||
WaveOpen = 0;
|
||||
WaveConverter = NULL;
|
||||
WaveOutputUnit = NULL;
|
||||
#endif
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
|
||||
{
|
||||
UInt32 size = ioData->mDataByteSize;
|
||||
AudioConverterFillBuffer (WaveConverter, MyACInputProc, inRefCon, &size, ioData->mData);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MyACInputProc (AudioConverterRef inAudioConverter,
|
||||
UInt32* outDataSize, void** outData, void* inUserData)
|
||||
{
|
||||
bx_sound_osx_c *self = (bx_sound_osx_c*) inUserData;
|
||||
self->nextbuffer ((int*) outDataSize, outData);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void bx_sound_osx_c::nextbuffer (int *outDataSize, void **outData)
|
||||
{
|
||||
BX_DEBUG(("nextbuffer(), tail=%u", tail));
|
||||
if (head - tail <= 0) {
|
||||
*outData = NULL;
|
||||
*outDataSize = 0;
|
||||
|
||||
// We are getting behind, so stop the output for now
|
||||
AudioOutputUnitStop (WaveOutputUnit);
|
||||
WavePlaying = 0;
|
||||
}
|
||||
else {
|
||||
int n = tail % BX_SOUND_OSX_NBUF;
|
||||
*outData = (void *) (WaveData[n]);
|
||||
*outDataSize = WaveLength[n];
|
||||
tail++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(macintosh)
|
||||
72
bochs/iodev/soundosx.h
Normal file
72
bochs/iodev/soundosx.h
Normal file
@ -0,0 +1,72 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// This file (SOUNDOSX.H) written and donated by Brian Huffman
|
||||
|
||||
|
||||
#ifdef macintosh
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
// uncomment one of these two:
|
||||
#if BX_WITH_MACOS
|
||||
#define BX_SOUND_OSX_use_quicktime
|
||||
#else
|
||||
#define BX_SOUND_OSX_use_converter
|
||||
//#define BX_SOUND_OSX_use_quicktime
|
||||
#endif
|
||||
|
||||
#define BX_SOUND_OSX_NBUF 8 // number of buffers for digital output
|
||||
|
||||
class bx_sound_osx_c : public bx_sound_output_c {
|
||||
public:
|
||||
bx_sound_osx_c(logfunctions *dev);
|
||||
virtual ~bx_sound_osx_c();
|
||||
|
||||
virtual int waveready();
|
||||
virtual int midiready();
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
virtual int openwaveoutput(const char *wavedev);
|
||||
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
|
||||
virtual int sendwavepacket(int length, Bit8u data[]);
|
||||
virtual int stopwaveplayback();
|
||||
virtual int closewaveoutput();
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
void nextbuffer(int *outDataSize, void **outData);
|
||||
#endif
|
||||
|
||||
private:
|
||||
int MidiOpen;
|
||||
int WaveOpen;
|
||||
|
||||
Bit8u WaveData[BX_SOUND_OSX_NBUF][BX_SOUND_OUTPUT_WAVEPACKETSIZE];
|
||||
int WaveLength[BX_SOUND_OSX_NBUF];
|
||||
int head, tail; // buffer pointers
|
||||
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
int WavePlaying;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // macintosh
|
||||
511
bochs/iodev/soundwin.cc
Normal file
511
bochs/iodev/soundwin.cc
Normal file
@ -0,0 +1,511 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file (SOUNDWIN.CC) written and donated by Josef Drexler
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#if defined(WIN32) && BX_SUPPORT_SB16
|
||||
|
||||
#include "soundmod.h"
|
||||
#include "soundwin.h"
|
||||
|
||||
#define LOG_THIS device->
|
||||
|
||||
bx_sound_windows_c::bx_sound_windows_c(logfunctions *dev)
|
||||
:bx_sound_output_c(dev)
|
||||
{
|
||||
MidiOpen = 0;
|
||||
WaveOpen = 0;
|
||||
|
||||
ismidiready = 1;
|
||||
iswaveready = 1;
|
||||
|
||||
// size is the total size of the midi header and buffer and the
|
||||
// BX_SOUND_WINDOWS_NBUF wave header and buffers, all aligned
|
||||
// on a 16-byte boundary
|
||||
|
||||
#define ALIGN(size) ((size + 15) & ~15)
|
||||
|
||||
#define size ALIGN(sizeof(MIDIHDR)) \
|
||||
+ ALIGN(sizeof(WAVEHDR)) \
|
||||
+ ALIGN(BX_SOUND_WINDOWS_MAXSYSEXLEN) * BX_SOUND_WINDOWS_NBUF \
|
||||
+ ALIGN(BX_SOUND_OUTPUT_WAVEPACKETSIZE) * BX_SOUND_WINDOWS_NBUF
|
||||
|
||||
DataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
|
||||
DataPointer = (Bit8u*) GlobalLock(DataHandle);
|
||||
|
||||
if (DataPointer == NULL)
|
||||
BX_PANIC(("GlobalLock returned NULL-pointer"));
|
||||
|
||||
#define NEWBUFFER(size) &(DataPointer[offset]); offset += ALIGN(size)
|
||||
|
||||
unsigned offset = 0;
|
||||
MidiHeader = (LPMIDIHDR) NEWBUFFER(sizeof(MIDIHDR));
|
||||
MidiData = (LPSTR) NEWBUFFER(BX_SOUND_WINDOWS_MAXSYSEXLEN);
|
||||
|
||||
for (int bufnum=0; bufnum<BX_SOUND_WINDOWS_NBUF; bufnum++)
|
||||
{
|
||||
WaveHeader[bufnum] = (LPWAVEHDR) NEWBUFFER(sizeof(WAVEHDR));
|
||||
WaveData[bufnum] = (LPSTR) NEWBUFFER(BX_SOUND_OUTPUT_WAVEPACKETSIZE+64);
|
||||
}
|
||||
|
||||
if (offset > size)
|
||||
BX_PANIC(("Allocated memory was too small!"));
|
||||
|
||||
#undef size
|
||||
#undef ALIGN
|
||||
#undef NEWBUFFER
|
||||
|
||||
BX_INFO(("Sound output module 'win' initialized"));
|
||||
}
|
||||
|
||||
bx_sound_windows_c::~bx_sound_windows_c()
|
||||
{
|
||||
GlobalUnlock(DataHandle);
|
||||
GlobalFree(DataHandle);
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::waveready()
|
||||
{
|
||||
if (iswaveready == 0)
|
||||
checkwaveready();
|
||||
|
||||
if (iswaveready == 1)
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
else
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
int bx_sound_windows_c::midiready()
|
||||
{
|
||||
if (ismidiready == 0)
|
||||
checkmidiready();
|
||||
|
||||
if (ismidiready == 1)
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
else
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::openmidioutput(const char *mididev)
|
||||
{
|
||||
// could make the output device selectable,
|
||||
// but currently only the midi mapper is supported
|
||||
UNUSED(mididev);
|
||||
|
||||
UINT deviceid = (UINT) MIDIMAPPER;
|
||||
|
||||
MidiOpen = 0;
|
||||
|
||||
UINT ret = midiOutOpen(&MidiOut, deviceid, 0, 0, CALLBACK_NULL);
|
||||
if (ret == 0)
|
||||
MidiOpen = 1;
|
||||
|
||||
BX_DEBUG(("midiOutOpen() = %d, MidiOpen: %d", ret, MidiOpen));
|
||||
|
||||
return (MidiOpen == 1) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if (MidiOpen != 1)
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
if ((command == 0xf0) || (command == 0xf7) || (length > 3))
|
||||
{
|
||||
BX_DEBUG(("SYSEX started, length %d", length));
|
||||
ismidiready = 0; // until the buffer is done
|
||||
memcpy(MidiData, data, length);
|
||||
MidiHeader->lpData = MidiData;
|
||||
MidiHeader->dwBufferLength = BX_SOUND_WINDOWS_MAXSYSEXLEN;
|
||||
MidiHeader->dwBytesRecorded = 0;
|
||||
MidiHeader->dwUser = 0;
|
||||
MidiHeader->dwFlags = 0;
|
||||
ret = midiOutPrepareHeader(MidiOut, MidiHeader, sizeof(*MidiHeader));
|
||||
if (ret != 0)
|
||||
BX_ERROR(("midiOutPrepareHeader() = %d", ret));
|
||||
ret = midiOutLongMsg(MidiOut, MidiHeader, sizeof(*MidiHeader));
|
||||
if (ret != 0)
|
||||
BX_ERROR(("midiOutLongMsg() = %d", ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD msg = command;
|
||||
|
||||
for (int i = 0; i<length; i++)
|
||||
msg |= (data[i] << (8 * (i + 1)));
|
||||
|
||||
ret = midiOutShortMsg(MidiOut, msg);
|
||||
BX_DEBUG(("midiOutShortMsg(%x) = %d", msg, ret));
|
||||
}
|
||||
|
||||
return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::closemidioutput()
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if (MidiOpen != 1)
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
|
||||
ret = midiOutReset(MidiOut);
|
||||
if (ismidiready == 0)
|
||||
checkmidiready(); // to clear any pending SYSEX
|
||||
|
||||
ret = midiOutClose(MidiOut);
|
||||
BX_DEBUG(("midiOutClose() = %d", ret));
|
||||
MidiOpen = 0;
|
||||
|
||||
return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::openwaveoutput(const char *wavedev)
|
||||
{
|
||||
// could make the output device selectable,
|
||||
// but currently only the wave mapper is supported
|
||||
UNUSED(wavedev);
|
||||
|
||||
BX_DEBUG(("openwaveoutput(%s)", wavedev));
|
||||
|
||||
#ifdef usewaveOut
|
||||
WaveDevice = (UINT) WAVEMAPPER;
|
||||
|
||||
for (int i=0; i<BX_SOUND_WINDOWS_NBUF; i++)
|
||||
WaveHeader[i]->dwFlags = WHDR_DONE;
|
||||
|
||||
head = 0;
|
||||
tailfull = 0;
|
||||
tailplay = 0;
|
||||
needreopen = 0;
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::playnextbuffer()
|
||||
{
|
||||
UINT ret;
|
||||
PCMWAVEFORMAT waveformat;
|
||||
int bufnum;
|
||||
|
||||
// if the format is different, we have to reopen the device,
|
||||
// so reset it first
|
||||
if (needreopen != 0)
|
||||
if (WaveOpen != 0)
|
||||
ret = waveOutReset(WaveOut);
|
||||
|
||||
// clean up the buffers and mark if output is ready
|
||||
checkwaveready();
|
||||
|
||||
// do we have to play anything?
|
||||
if (tailplay == head)
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
|
||||
// if the format is different, we have to close and reopen the device
|
||||
// or, just open the device if it's not open yet
|
||||
if ((needreopen != 0) || (WaveOpen == 0))
|
||||
{
|
||||
if (WaveOpen != 0)
|
||||
{
|
||||
ret = waveOutClose(WaveOut);
|
||||
WaveOpen = 0;
|
||||
}
|
||||
|
||||
// try three times to find a suitable format
|
||||
for (int tries = 0; tries < 3; tries++)
|
||||
{
|
||||
int frequency = WaveInfo.frequency;
|
||||
int stereo = WaveInfo.stereo;
|
||||
int bits = WaveInfo.bits;
|
||||
// int format = WaveInfo.format;
|
||||
int bps = (bits / 8) * (stereo + 1);
|
||||
|
||||
waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
waveformat.wf.nChannels = stereo + 1;
|
||||
waveformat.wf.nSamplesPerSec = frequency;
|
||||
waveformat.wf.nAvgBytesPerSec = frequency * bps;
|
||||
waveformat.wf.nBlockAlign = bps;
|
||||
waveformat.wBitsPerSample = bits;
|
||||
|
||||
ret = waveOutOpen(&(WaveOut), WaveDevice, (LPWAVEFORMATEX)&(waveformat.wf), 0, 0, CALLBACK_NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
char errormsg[4*MAXERRORLENGTH+1];
|
||||
waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
|
||||
BX_DEBUG(("waveOutOpen: %s", errormsg));
|
||||
switch (tries) {
|
||||
case 0: // maybe try a different frequency
|
||||
if (frequency < 15600)
|
||||
frequency = 11025;
|
||||
else if (frequency < 31200)
|
||||
frequency = 22050;
|
||||
else
|
||||
frequency = 44100;
|
||||
|
||||
BX_DEBUG(("Couldn't open wave device (error %d), trying frequency %d", ret, frequency));
|
||||
break;
|
||||
|
||||
case 1: // or something else
|
||||
frequency = 11025;
|
||||
stereo = 0;
|
||||
bits = 8;
|
||||
bps = 1;
|
||||
|
||||
BX_DEBUG(("Couldn't open wave device again (error %d), trying 11KHz, mono, 8bit", ret));
|
||||
break;
|
||||
|
||||
case 2: // nope, doesn't work
|
||||
BX_ERROR(("Couldn't open wave device (error %d)!", ret));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
BX_DEBUG(("The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,",
|
||||
waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec));
|
||||
BX_DEBUG((" nAvgBytesPerSec=%d, nBlockAlign=%d, wBitsPerSample=%d",
|
||||
waveformat.wf.nAvgBytesPerSec, waveformat.wf.nBlockAlign, waveformat.wBitsPerSample));
|
||||
}
|
||||
else
|
||||
{
|
||||
WaveOpen = 1;
|
||||
needreopen = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (bufnum=tailplay; bufnum != head;
|
||||
bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK, tailplay=bufnum)
|
||||
{
|
||||
BX_DEBUG(("Playing buffer %d", bufnum));
|
||||
|
||||
// prepare the wave header
|
||||
WaveHeader[bufnum]->lpData = WaveData[bufnum];
|
||||
WaveHeader[bufnum]->dwBufferLength = length[bufnum];
|
||||
WaveHeader[bufnum]->dwBytesRecorded = length[bufnum];
|
||||
WaveHeader[bufnum]->dwUser = 0;
|
||||
WaveHeader[bufnum]->dwFlags = 0;
|
||||
WaveHeader[bufnum]->dwLoops = 1;
|
||||
|
||||
ret = waveOutPrepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
|
||||
if (ret != 0)
|
||||
{
|
||||
BX_ERROR(("waveOutPrepareHeader = %d", ret));
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
ret = waveOutWrite(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
|
||||
if (ret != 0)
|
||||
{
|
||||
char errormsg[4*MAXERRORLENGTH+1];
|
||||
waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
|
||||
BX_DEBUG(("waveOutWrite: %s", errormsg));
|
||||
}
|
||||
}
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::startwaveplayback(int frequency, int bits, int stereo, int format)
|
||||
{
|
||||
BX_DEBUG(("startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format));
|
||||
|
||||
#ifdef usewaveOut
|
||||
// check if any of the properties have changed
|
||||
if ((WaveInfo.frequency != frequency) ||
|
||||
(WaveInfo.bits != bits) ||
|
||||
(WaveInfo.stereo != stereo) ||
|
||||
(WaveInfo.format != format))
|
||||
{
|
||||
needreopen = 1;
|
||||
|
||||
// store the current settings to be used by sendwavepacket()
|
||||
WaveInfo.frequency = frequency;
|
||||
WaveInfo.bits = bits;
|
||||
WaveInfo.stereo = stereo;
|
||||
WaveInfo.format = format;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef usesndPlaySnd
|
||||
int bps = (bits / 8) * (stereo + 1);
|
||||
LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0];
|
||||
|
||||
memcpy(header->RIFF, "RIFF", 4);
|
||||
memcpy(header->TYPE, "WAVE", 4);
|
||||
memcpy(header->chnk, "fmt ", 4);
|
||||
header->chnklen = 16;
|
||||
header->waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
header->waveformat.wf.nChannels = stereo + 1;
|
||||
header->waveformat.wf.nSamplesPerSec = frequency;
|
||||
header->waveformat.wf.nAvgBytesPerSec = frequency * bps;
|
||||
header->waveformat.wf.nBlockAlign = bps;
|
||||
header->waveformat.wBitsPerSample = bits;
|
||||
memcpy(header->chnk2, "data", 4);
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::sendwavepacket(int length, Bit8u data[])
|
||||
{
|
||||
#ifdef usewaveOut
|
||||
int bufnum;
|
||||
#endif
|
||||
#ifdef usesndPlaySnd
|
||||
UINT ret;
|
||||
#endif
|
||||
|
||||
BX_DEBUG(("sendwavepacket(%d, %p)", length, data));
|
||||
|
||||
#ifdef usewaveOut
|
||||
bufnum = head;
|
||||
|
||||
memcpy(WaveData[bufnum], data, length);
|
||||
this->length[bufnum] = length;
|
||||
|
||||
// select next buffer to write to
|
||||
bufnum++;
|
||||
bufnum &= BX_SOUND_WINDOWS_NMASK;
|
||||
|
||||
if (((bufnum + 1) & BX_SOUND_WINDOWS_NMASK) == tailfull)
|
||||
{ // this should not actually happen!
|
||||
BX_ERROR(("Output buffer overflow! Not played. Iswaveready was %d", iswaveready));
|
||||
iswaveready = 0; // stop the output for a while
|
||||
return BX_SOUND_OUTPUT_ERR;
|
||||
}
|
||||
|
||||
head = bufnum;
|
||||
|
||||
// check if more buffers are available, otherwise stall the emulator
|
||||
if (((bufnum + 2) & BX_SOUND_WINDOWS_NMASK) == tailfull)
|
||||
{
|
||||
BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Stall.",
|
||||
head, tailfull, tailplay));
|
||||
iswaveready = 0;
|
||||
}
|
||||
|
||||
playnextbuffer();
|
||||
#endif
|
||||
|
||||
#ifdef usesndPlaySnd
|
||||
LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0];
|
||||
|
||||
header->length = length + 36;
|
||||
header->chnk2len = length;
|
||||
|
||||
memcpy(&(header->data), data, length);
|
||||
|
||||
ret = sndPlaySoundA((LPCSTR) header, SND_SYNC | SND_MEMORY);
|
||||
if (ret != 0)
|
||||
{
|
||||
BX_DEBUG(("sndPlaySoundA: %d", ret));
|
||||
}
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::stopwaveplayback()
|
||||
{
|
||||
BX_DEBUG(("stopwaveplayback()"));
|
||||
|
||||
#ifdef usewaveOut
|
||||
// this is handled by checkwaveready() when closing
|
||||
#endif
|
||||
|
||||
#ifdef usesndPlaySnd
|
||||
sndPlaySoundA(NULL, SND_ASYNC | SND_MEMORY);
|
||||
|
||||
WaveOpen = 0;
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
int bx_sound_windows_c::closewaveoutput()
|
||||
{
|
||||
BX_DEBUG(("closewaveoutput"));
|
||||
|
||||
#ifdef usewaveOut
|
||||
if (WaveOpen == 1)
|
||||
{
|
||||
waveOutReset(WaveOut);
|
||||
|
||||
// let checkwaveready() clean up the buffers
|
||||
checkwaveready();
|
||||
|
||||
waveOutClose(WaveOut);
|
||||
|
||||
head = 0;
|
||||
tailfull = 0;
|
||||
tailplay = 0;
|
||||
needreopen = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BX_SOUND_OUTPUT_OK;
|
||||
}
|
||||
|
||||
void bx_sound_windows_c::checkmidiready()
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if ((MidiHeader->dwFlags & MHDR_DONE) != 0)
|
||||
{
|
||||
BX_DEBUG(("SYSEX message done, midi ready again"));
|
||||
ret = midiOutUnprepareHeader(MidiOut, MidiHeader, sizeof(*MidiHeader));
|
||||
ismidiready = 1;
|
||||
}
|
||||
}
|
||||
void bx_sound_windows_c::checkwaveready()
|
||||
{
|
||||
int bufnum;
|
||||
UINT ret;
|
||||
|
||||
// clean up all finished buffers and mark them as available
|
||||
for (bufnum=tailfull; (bufnum != tailplay) &&
|
||||
((WaveHeader[bufnum]->dwFlags & WHDR_DONE) != 0);
|
||||
bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK)
|
||||
{
|
||||
BX_DEBUG(("Buffer %d done.", bufnum));
|
||||
ret = waveOutUnprepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
|
||||
}
|
||||
|
||||
tailfull = bufnum;
|
||||
|
||||
// enable gathering data if a buffer is available
|
||||
if (((head + 2) & BX_SOUND_WINDOWS_NMASK) != tailfull)
|
||||
{
|
||||
BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Ready.",
|
||||
head, tailfull, tailplay));
|
||||
iswaveready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(WIN32)
|
||||
222
bochs/iodev/soundwin.h
Normal file
222
bochs/iodev/soundwin.h
Normal file
@ -0,0 +1,222 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2011 The Bochs Project
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file (SOUNDWIN.H) written and donated by Josef Drexler
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// uncomment one of the following two #defines
|
||||
//#define usesndPlaySnd
|
||||
#define usewaveOut
|
||||
|
||||
#define BX_SOUND_WINDOWS_MAXSYSEXLEN 256 // maximum supported length of a sysex message
|
||||
|
||||
#define BX_SOUND_WINDOWS_NBUF 64 // number of buffers for the output, must be power of 2 and >= 4
|
||||
#define BX_SOUND_WINDOWS_NMASK (BX_SOUND_WINDOWS_NBUF - 1)
|
||||
|
||||
#ifndef WAVEMAPPER
|
||||
#define WAVEMAPPER -1
|
||||
#endif
|
||||
|
||||
// Definitions for WINMM.DLL, if not defined already
|
||||
#ifndef MMSYSERR_NOERROR
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef UINT HMIDIOUT;
|
||||
typedef HMIDIOUT *LPHMIDIOUT;
|
||||
typedef struct midihdr_tag {
|
||||
LPSTR lpData;
|
||||
DWORD dwBufferLength;
|
||||
DWORD dwBytesRecorded;
|
||||
DWORD dwUser;
|
||||
DWORD dwFlags;
|
||||
struct midihdr_tag *lpNext;
|
||||
DWORD reserved;
|
||||
} MIDIHDR, *LPMIDIHDR;
|
||||
|
||||
typedef UINT HWAVEOUT;
|
||||
typedef HWAVEOUT *LPHWAVEOUT;
|
||||
|
||||
typedef struct wavehdr_tag {
|
||||
LPSTR lpData;
|
||||
DWORD dwBufferLength;
|
||||
DWORD dwBytesRecorded;
|
||||
DWORD dwUser;
|
||||
DWORD dwFlags;
|
||||
DWORD dwLoops;
|
||||
struct wavehdr_tag *lpNext;
|
||||
DWORD reserved;
|
||||
} WAVEHDR, *LPWAVEHDR;
|
||||
|
||||
#define WHDR_DONE 0x00000001
|
||||
#define WHDR_PREPARED 0x00000002
|
||||
#define WHDR_BEGINLOOP 0x00000004
|
||||
#define WHDR_ENDLOOP 0x00000008
|
||||
#define WHDR_INQUEUE 0x00000010
|
||||
|
||||
|
||||
typedef struct waveformat_tag {
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
} WAVEFORMAT, *LPWAVEFORMAT;
|
||||
|
||||
#define WAVE_FORMAT_PCM 1
|
||||
|
||||
typedef struct pcmwaveformat_tag {
|
||||
WAVEFORMAT wf;
|
||||
WORD wBitsPerSample;
|
||||
} PCMWAVEFORMAT, *LPPCMWAVEFORMAT;
|
||||
|
||||
#define MIDIMAPPER -1
|
||||
|
||||
#define CALLBACK_NULL 0x00000000
|
||||
#define CALLBACK_WINDOW 0x00010000
|
||||
#define CALLBACK_TASK 0x00020000
|
||||
#define CALLBACK_FUNCTION 0x00030000
|
||||
|
||||
#define MMSYSERR_NOERROR 0
|
||||
#define MMSYSERR_ERROR 1
|
||||
#define MMSYSERR_BADDEVICEID 2
|
||||
#define MMSYSERR_NOTENABLED 3
|
||||
#define MMSYSERR_ALLOCATED 4
|
||||
#define MMSYSERR_INVALHANDLE 5
|
||||
#define MMSYSERR_NODRIVER 6
|
||||
#define MMSYSERR_NOMEM 7
|
||||
#define MMSYSERR_NOTSUPPORTED 8
|
||||
#define MMSYSERR_NOMAP 7
|
||||
|
||||
#define MIDIERR_UNPREPARED 64
|
||||
#define MIDIERR_STILLPLAYING 65
|
||||
#define MIDIERR_NOTREADY 66
|
||||
#define MIDIERR_NODEVICE 67
|
||||
|
||||
#define WAVERR_BADFORMAT 32
|
||||
#define WAVERR_STILLPLAYING 33
|
||||
#define WAVERR_UNPREPARED 34
|
||||
#define WAVERR_SYNC 35
|
||||
|
||||
#define MAXERRORLENGTH 128
|
||||
|
||||
extern "C" {
|
||||
UINT STDCALL midiOutOpen(LPHMIDIOUT, UINT, DWORD, DWORD, DWORD);
|
||||
UINT STDCALL midiOutShortMsg(HMIDIOUT, DWORD);
|
||||
UINT STDCALL midiOutLongMsg(HMIDIOUT, LPMIDIHDR, UINT);
|
||||
UINT STDCALL midiOutPrepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
|
||||
UINT STDCALL midiOutUnprepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
|
||||
UINT STDCALL midiOutReset(HMIDIOUT);
|
||||
UINT STDCALL midiOutClose(HMIDIOUT);
|
||||
|
||||
UINT STDCALL waveOutOpen(LPHWAVEOUT, UINT, LPWAVEFORMAT, DWORD, DWORD, DWORD);
|
||||
UINT STDCALL waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT);
|
||||
UINT STDCALL waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
|
||||
UINT STDCALL waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
|
||||
UINT STDCALL waveOutReset(HWAVEOUT);
|
||||
UINT STDCALL waveOutClose(HWAVEOUT);
|
||||
|
||||
UINT STDCALL waveOutGetErrorTextA(UINT, LPSTR, UINT);
|
||||
|
||||
BOOL STDCALL sndPlaySoundA(LPCSTR, UINT);
|
||||
}
|
||||
#pragma pack(0)
|
||||
|
||||
#endif // MMSYSERR_NOERROR defined
|
||||
|
||||
#ifndef WAVEFILEHEADER
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
char RIFF[4];
|
||||
Bit32u length;
|
||||
char TYPE[4];
|
||||
char chnk[4];
|
||||
Bit32u chnklen;
|
||||
PCMWAVEFORMAT waveformat;
|
||||
char chnk2[4];
|
||||
Bit32u chnk2len;
|
||||
char data[1];
|
||||
} WAVEFILEHEADER, *LPWAVEFILEHEADER;
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
||||
class bx_sound_windows_c : public bx_sound_output_c {
|
||||
public:
|
||||
bx_sound_windows_c(logfunctions *dev);
|
||||
virtual ~bx_sound_windows_c();
|
||||
|
||||
virtual int waveready();
|
||||
virtual int midiready();
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
virtual int openwaveoutput(const char *wavedev);
|
||||
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
|
||||
virtual int sendwavepacket(int length, Bit8u data[]);
|
||||
virtual int stopwaveplayback();
|
||||
virtual int closewaveoutput();
|
||||
|
||||
private:
|
||||
struct bx_sb16_waveinfo_struct {
|
||||
int frequency;
|
||||
int bits;
|
||||
int stereo;
|
||||
int format;
|
||||
};
|
||||
|
||||
HMIDIOUT MidiOut; // Midi output device
|
||||
int MidiOpen; // is it open?
|
||||
HWAVEOUT WaveOut; // Wave output device
|
||||
int WaveOpen; // is it open?
|
||||
|
||||
UINT WaveDevice; // Wave device ID, for waveOutOpen
|
||||
|
||||
// some data for the wave buffers
|
||||
HANDLE DataHandle; // returned by GlobalAlloc()
|
||||
Bit8u *DataPointer; // returned by GlobalLock()
|
||||
|
||||
LPWAVEHDR WaveHeader[BX_SOUND_WINDOWS_NBUF];
|
||||
LPSTR WaveData[BX_SOUND_WINDOWS_NBUF];
|
||||
int length[BX_SOUND_WINDOWS_NBUF]; // length of the data in the buffer
|
||||
int needreopen; // if the format has changed
|
||||
int head,tailfull,tailplay; // These are for three states of the buffers: empty, full, played
|
||||
bx_sb16_waveinfo_struct WaveInfo; // format for the next buffer to be played
|
||||
int iswaveready;
|
||||
|
||||
// and the midi buffer for the SYSEX messages
|
||||
LPMIDIHDR MidiHeader;
|
||||
LPSTR MidiData;
|
||||
int ismidiready;
|
||||
|
||||
int playnextbuffer();
|
||||
void checkmidiready();
|
||||
void checkwaveready();
|
||||
};
|
||||
|
||||
#endif // defined(WIN32)
|
||||
152
bochs/iodev/speaker.cc
Normal file
152
bochs/iodev/speaker.cc
Normal file
@ -0,0 +1,152 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2003 by David N. Welton <davidw@dedasys.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "speaker.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/kd.h>
|
||||
#endif
|
||||
|
||||
#define LOG_THIS theSpeaker->
|
||||
|
||||
bx_speaker_c *theSpeaker= NULL;
|
||||
|
||||
int libspeaker_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
||||
{
|
||||
theSpeaker = new bx_speaker_c();
|
||||
bx_devices.pluginSpeaker = theSpeaker;
|
||||
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSpeaker, BX_PLUGIN_SPEAKER);
|
||||
return(0); // Success
|
||||
}
|
||||
|
||||
void libspeaker_LTX_plugin_fini(void)
|
||||
{
|
||||
delete theSpeaker;
|
||||
}
|
||||
|
||||
bx_speaker_c::bx_speaker_c()
|
||||
{
|
||||
put("SPEAK");
|
||||
|
||||
beep_frequency = 0.0; // Off
|
||||
|
||||
#ifdef __linux__
|
||||
consolefd = open("/dev/console", O_WRONLY);
|
||||
#endif
|
||||
}
|
||||
|
||||
bx_speaker_c::~bx_speaker_c()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (consolefd >= 0) {
|
||||
ioctl(consolefd, KIOCSOUND, 0);
|
||||
close(consolefd);
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_speaker_c::init(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (consolefd != -1) {
|
||||
BX_INFO(("Open /dev/console successfully"));
|
||||
} else {
|
||||
BX_INFO(("Failed to open /dev/console: %s", strerror(errno)));
|
||||
BX_INFO(("Deactivating beep on console"));
|
||||
}
|
||||
#endif
|
||||
|
||||
this->beep_off();
|
||||
}
|
||||
|
||||
void bx_speaker_c::reset(unsigned type)
|
||||
{
|
||||
beep_off();
|
||||
}
|
||||
|
||||
void bx_speaker_c::beep_on(float frequency)
|
||||
{
|
||||
beep_frequency = frequency;
|
||||
|
||||
#ifdef __linux__
|
||||
if (consolefd != -1) {
|
||||
this->info("pc speaker on with frequency %f", frequency);
|
||||
ioctl(consolefd, KIOCSOUND, (int)(clock_tick_rate/frequency));
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
usec_start = bx_pc_system.time_usec();
|
||||
#endif
|
||||
|
||||
// give the gui a chance to signal beep off
|
||||
bx_gui->beep_on(frequency);
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
static struct {
|
||||
DWORD frequency;
|
||||
DWORD msec;
|
||||
} beep_info;
|
||||
|
||||
DWORD WINAPI BeepThread(LPVOID)
|
||||
{
|
||||
static BOOL threadActive = FALSE;
|
||||
|
||||
while (threadActive) Sleep(10);
|
||||
threadActive = TRUE;
|
||||
Beep(beep_info.frequency, beep_info.msec);
|
||||
threadActive = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void bx_speaker_c::beep_off()
|
||||
{
|
||||
if (beep_frequency != 0.0) {
|
||||
#ifdef __linux__
|
||||
if (consolefd != -1) {
|
||||
ioctl(consolefd, KIOCSOUND, 0);
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
// FIXME: sound should start at beep_on() and end here
|
||||
DWORD threadID;
|
||||
beep_info.msec = (DWORD)((bx_pc_system.time_usec() - usec_start) / 1000);
|
||||
beep_info.frequency = (DWORD)beep_frequency;
|
||||
CreateThread(NULL, 0, BeepThread, NULL, 0, &threadID);
|
||||
#endif
|
||||
|
||||
// give the gui a chance to signal beep off
|
||||
bx_gui->beep_off();
|
||||
|
||||
beep_frequency = 0.0;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user