These are the remaining important files, that do not really fit into another group. These should not be dismissed as unimportant - rather, they are often amongst the most important.
These are the functions defined in base/async/int.c.
DEFAULT_INTERRUPT is the default interrupt service routine called when DOSEMU initializes.
int0x21 call
we trap this for two functions: simulating the EMMXXXX0 device and fudging the CONFIG.XXX and AUTOEXEC.XXX bootup files.
note that the emulation herein may cause problems with programs that like to take control of certain int 21h functions, or that change functions that the true int 21h functions use. An example of the latter is ANSI.SYS, which changes int 10h, and int 21h uses int 10h. for the moment, ANSI.SYS won't work anyway, so it's no problem.
This function runs the specified caller function in response to an int instruction. Where i is the interrupt function to execute and from_int specifies if we are comming directly from an int instruction.
This function runs the instruction with the following model _CS:_IP is the address to start executing at after the caller function terminates, and _EFLAGS are the flags to use after termination. For the simple case of an int instruction this is easy. _CS:_IP = retCS:retIP and _FLAGS = retFLAGS as well equally the current values (retIP = curIP +2 technically).
However if the function is called (from dos) by simulating an int instruction (something that is common with chained interrupt vectors) _CS:_IP = BIOS_SEG:HLT_OFF(i) and _FLAGS = curFLAGS while retCS, retIP, and retFlags are on the stack. These I pop and place in the appropriate registers.
This functions actions certainly correct for functions executing an int/iret discipline. And almost certianly correct for functions executing an int/retf#2 discipline (with flag changes), as an iret is always possilbe. However functions like dos int 0x25 and 0x26 executing with a int/retf will not be handled correctlty by this function and if you need to handle them inside dosemu use a halt handler instead.
Finally there is a possible trouble spot lurking in this code. Interrupts are only implicitly disabled when it calls the caller function, so if for some reason the main loop would be entered before the caller function returns wrong code may execute if the retFLAGS have interrupts enabled!
This is only a real handicap for sequences of dosemu code execute for long periods of time as we try to improve timer response and prevent signal queue overflows! -- EB 10 March 1997
Grumble do to code that executes before interrupts, and the semantics of default_interupt, I can't implement this function as I would like. In the tricky case of being called from dos by simulating an int instruction, I must leave retCS, retIP, on the stack. But I can safely read retFlags so I do. I pop retCS, and retIP just before returning to dos, as well as dropping the stack slot that held retFlags.
This improves consistency of interrupt handling, but not quite as much as if I could handle it the way I would like. -- EB 30 Nov 1997
DO_INT is used to deal with interrupts returned to DOSEMU by the kernel.
SETUP_INTERRUPTS is used to initialize the interrupt_function array which directs handling of interrupts in protected mode and also initializes the base vector for interrupts in real mode.
Setup initial interrupts which can be revectored so that the kernel does not need to return to DOSEMU if such an interrupt occurs.
Some video BIOSes need access to the PIT timer 2, and some (e.g. Matrox) directly read the timer output on port 0x61. If we don't allow video port access, this will be totally emulated; else, we give temporary access to the needed ports (timer at 0x42, timer config at 0x43 and timer out/speaker at 0x61), provided they were not previously enabled by SPKR_NATIVE - AV
-----
Many video BIOSes use hi interrupt vector locations as scratchpad area - this is because they come before DOS and feel safe to do it. But we are initializing vectors before video, so this only causes trouble. I assume no video BIOS will ever: - change vectors < 0xe0 (0:380-0:3ff area) - change anything in the vector area _after_ installation - AV
These are the functions defined in arch/linux/async/sigsegv.c.
All CPU exceptions (except 13=general_protection from V86 mode, which is directly scanned by the kernel) are handled here.
Prints information about an exception: exception number, error code, address, reason, etc.
These are the functions defined in arch/linux/async/signal.c.
The IRQ numbers to monitor are taken from config.sillyint, each bit corresponding to one IRQ. The higher 16 bit are defining the use of SIGIO
Initialize the signals to have NONE being blocked. Currently this is NOT of much use to DOSEMU.
Stop additional signals from interrupting DOSEMU.
Allow all signals to interrupt DOSEMU.
Due to signals happening at any time, the actual work to be done because a signal occurs is done here in a serial fashion.
The concept, should this eventualy work, is that a signal should only flag that it has occurred and let DOSEMU deal with it in an orderly fashion as it executes the rest of it's code.
Arguments are:
context - signal context to save.
signal_call - signal handling routine to be called.
Whenever I/O occurs on devices allowing SIGIO to occur, DOSEMU will be flagged to run this call which inturn checks which fd(s) was set and execute the proper routine to get the I/O from that device.
Check for keyboard coming from client For now, first byte is interrupt requests from Client
These are the functions defined in base/misc/disks.c.
Test by opening all floppies/hardrives configured.
These are the functions defined in base/dev/misc/timers.c.
ensure the 0x40 port timer is initially set correctly
Every time we get a TIMER signal from Linux, this procedure is called. It checks to see if we should queue a timer interrupt based on the current values.
do_sound handles the _emulated_ mode pc-speaker emulation.
As far as I can determine all cases of the pc-speaker are now emulated. But I am not sure where Rainer Zimmerman got his (pit[2].mode == 2) || (pit[2].mode == 3) test in the original implementation, it doesn't seem to cause problems though.
The implementation of speaker_on & speaker_off can be found in src/base/speaker.c
Major Changes from version written by Rainter Zimmerman.
o Added support for programs that control the directly through bit 1 of port61.
o Added a generic interface to allow multiple speaker backends.
o Implemented X speaker code so the emulated speaker now works in X.
--EB 21 September 1997
This is experimental TIMER-IRQ CHAIN code! This is a function to determine whether it is time to invoke a new timer irq 0 event. Normally it is 18 times a second, but many video games set it to 100 times per second or more. Since the kernel cannot keep an accurate timer interrupt, the job of this routine is to perform a chained timer irq 0 right after the previous timer irq 0. This routine should, ideally, be called right after the end of a timer irq, if possible.
This would speed up high frequency timer interrupts if this code can be converted into an assembly macro equivalent!
PLEASE NOTE
This code has been replaced by interrupt scheduling code in pic. The result is that we simply call pic_sched and run the dos interrupt. If the new code causes no problems, I'll revise this section permanently.
These are the functions defined in base/misc/shared.c.
Setup all memory areas to be shared with clients.
Output info required for client activity (NOTE: 'client activity' as of 2000/02/02 totally disabled, but left file structure compatible, --Hans)
These are the functions defined in base/misc/dos2linux.c.
Runs a command and prints the (stdout and stderr) output on the dosemu screen.
Return values mean:
Arguments are:
buffer - string with command to execute
These are the functions defined in base/misc/ioctl.c.
Initialize fd_sets to NULL for both SIGIO and NON-SIGIO.
Arguments are:
fd - File handle to add to select statment
want_sigio - want SIGIO (1) if it's available, or not (0).
Arguments are:
fd - File handle to remove from select statment.
used_sigio - used SIGIO (1) if it's available, or not (0).
These are the functions defined in base/dev/misc/lpt.c.
Initialize printer control structures
These are the functions defined in base/dev/misc/pci.c.
Use standard 32-bit (type 1) access method to read PCI configuration space data
32-bit I/O port output on PCI ports (0xcf8=addr,0xcfc=data) Optimization: trap the config writes (outd 0xcf8 with bit31=1). Since this kind of access is always followed by another R/W access to port 0xcfc, we can just set it as pending and merge it with the following operation, saving two calls to priv_iopl().
Register standard PCI ports 0xcf8-0xcff
These are the functions defined in base/dev/misc/joystick.c.
Assigns the Linux joystick reader to the one specified. Sets the Linux axis ranges based on what joystick API is being used.
Update the button status for each joystick.
We must perform "button mapping" if only the first joystick is enabled ie. we are required to map the "excessive" buttons (>2) from the first joystick onto the second: -- 3rd button of 1st joy --> 1st button of 2nd joy -- 4th button of 1st joy --> 2nd button of 2nd joy
Update the axis status for each joystick.
We must perform "axis mapping" if only the first joystick is enabled ie. we are required to map the "excessive" axes (>2) from the first joystick onto the second: -- 3rd axis of 1st joy --> 2st axis of 2nd joy -- 4th axis of 1st joy --> 1st axis of 2nd joy (yes, these are reversed deliberately because it's what happens in DOS)
Convert a Linux joystick reading to a DOS one by making use of the differences in the allowable ranges of joystick readings.
NOTE: I don't know whether or not Linux returns exponential readings for the joystick but (apparently) DOS programs expect the reading to be exponential and so if this is to be fixed, it should probably be done in this function.
Update global joystick status variables given a Linux joystick event.
Process the event queue for _both_ linux joysticks using nonblocking reads with the new joystick API (joy_reader_new).
This must be done before any joystick status is given to DOS as all events are queued until they are processed and we want to return the current state of the joystick -- not what it was some time ago. _Both_ joysticks are processed here because of axis/button mapping affecting the status of the emulated joysticks (what DOS sees).
Eventually called from DOS to get the button status of joysticks. The threaded version will simply get the readings from global variables. The unthreaded versions will perform non-blocking reads using the old joystick API.
Eventually called from DOS to get the axis status of joysticks. The threaded version will simply get the readings from global variables. The unthreaded versions will perform non-blocking reads using the old joystick API.
The @param invalid_val is the value to return to signify a non-existent axis.
This is the int15 function 0x84 handler (ie. BIOS joystick emulation), called from src/base/async/int.c.
The real BIOS actually reads its values straight from the joystick port (0x201) but we don't bother because we can read it from globals faster :)
Because of this, it returns the joystick axis readings with the same range as port 0x201 BUT for some reason, a real BIOS has a different range of joystick readings than direct port access (anyone know why?). No programs seem to expect a certain range of values except for Alley Cat which seems to want a range of about 1-50 but only from port 0x201.
This function emulates reads from the joystick port (0x201) -- this is the most common way of detecting and reading the joystick.
The real implementation of this port actually times out and resets the equivalent of the joy_port_x and joy_port_y axis counters if the time between 2 reads is too great (how great?) but no programs, I have seen, make use of this behaviour.
Linux joystick readers:
We make a runtime decision based on the detected joystick API version (and #ifdef USE_PTHREADS) on which reader to use. We can select from the following readers:
1. joy_reader_nojoy: simply tells DOS programs that you have no joystick 2. joy_reader_old: uses old, non-blocking joystick API (<1.0.0); limited to 2 axes 3. joy_reader_new: uses new, non-blocking joystick API (>=1.0.0); a (little) slower than joy_reader_new_threaded 4. joy_reader_new_threaded: uses new, BLOCKING joystick API (>=1.0.0); efficient but requires pthreads
-----
Register the joystick ports so that correct port values are returned for programs that try to detect the joystick (or the lack of one).
-----
if the 2nd joystick is enabled, we ignore any button >= 2 regardless of which joystick it is (if it's the 1st, the 2nd joystick would overwrite its buttons; if it's the 2nd, it would be out of range)
-----
if the 2nd joystick is enabled, we ignore any axis >= 2 regardless of which joystick it is (if it's the 1st, the 2nd joystick would overwrite its axes; if it's the 2nd, it would be out of range)
-----
Here we set the range of possible axis readings for Linux. You should _not_ change these values unless you know what you are doing.
They are later used in joy_emu_axis_conv() as part of a calculation to compress axis readings to an acceptable range for DOS programs (usually somewhere between 5 and 150).
-----
Apparently, the Carry Flag is cleared if int15 function 0x84 exists and it is set if it doesn't exist.
But what does this mean? Does the existence of such a BIOS function depend on the existence of a Game Card/SoundBlaster, or does it just mean that there is such an implemented BIOS function, regardless of whether or not you have a joystick?
I have never seen a real BIOS set the Carry Flag on this call, even on a computer without a joystick -- so to mimick what happens in the real world, I just clear the Carry Flag regardless of whether the user has a joystick or not. This could be incorrect behaviour so it may have to be changed in the future.
-----
Here we set bits based on joystick axis counters. The code here is particularly tricky and if you try to change it, you will probably break it :)
-----
Here we read the button status from Linux (programs can read the button status from the port, _without_ making a dummy write to the port first so the Linux read must be done _here_) and return it.
does this code work for ports other than 0x201? */
-----
joy_reset() is called immediately after joy_init(), which is rather inconvenient (anyone heard of a port_unregister_handler()?) so we don't bother resetting at all but in the future this could cause problems */
-----
I've lost my joystick Y-cable (lets you connect two joysticks to one gameport) so the code to handle two joysticks is totally untested! */
-----
What happens if you read a word from the joystick port? Analysis of a real DOS system shows that it reads a byte and doubles it up but I don't know if this is the correct behaviour... */
-----
joy_port_outw is not exactly correct at all but what would you do? */
The Helper Interrupt uses the following groups:
0x00 - Check for DOSEMU 0x01-0x11 - Initialisation functions & Debugging 0x12 - Set hogthreshold (aka garrot?) 0x20 - MFS functions 0x21-0x22 - EMS functions 0x28 - Garrot Functions for use with the mouse 0x29 - Serial functions 0x30 - Whether to use the BOOTDISK predicate 0x33 - Mouse Functions 0x40 - CD-ROM functions 0x50-0x5f - DOSEMU/Linux communications 50 -- run unix command in ES:DX 51,52? 53 -- do system(ES:DX) 54 -- get CPU speed 55 -- get terminal type 0x60-0x6f - reserved for plug-ins 0x7a - IPX functions 0x8x -- utility functions 0x80 -- getcwd(ES:DX, size AX) 0x81 -- chdir(ES:DX) 0xdc - helper for DosC kernel 0xfe - called from our MBR, emulate MBR-code. 0xff - Terminate DOSEMU
There are (as yet) no guidelines on choosing areas for new functions.