  DOSEmu Technical Guide
  The DOSEmu team Edited by Alistair MacDonald  <alis-
  tair@slitesys.demon.co.uk>
  For DOSEMU v0.66 pl5.0

  This document is the amalgamation of a series of technical README
  files which were created to deal with the lack of DOSEmu documenta-
  tion.
  ______________________________________________________________________

  Table of Contents:

  1.      Introduction

  2.      Accessing ports with dosemu

  2.1.    System Integrity

  2.2.    System Security

  2.3.    Speed

  3.      The Virtual Flags

  4.      VM86PLUS, new kernel's vm86 for a full feature dosemu

  4.1.    Restrictions

  4.2.    Parts in the kernel that get changed for vm86plus

  4.2.1.  Changes to arch/i386/kernel/vm86.c

  4.2.1.1.        New vm86() syscall interface

  4.2.1.2.        Additional Data passed to vm86()

  4.2.1.3.        IRQ passing

  4.2.1.4.        Debugger support

  4.2.2.  Changes to arch/i386/kernel/ldt.c

  4.2.2.1.        New functioncode for 'write' in modify_ldt syscall

  4.2.2.2.        'useable' bit in LDT descriptor

  4.2.2.3.        'present' bit in LDT selector

  4.2.3.  Changes to arch/i386/kernel/signal.c

  4.2.4.  Changes to arch/i386/kernel/traps.c

  4.3.    Abandoned 'bells and whistles' from older emumodule

  4.3.1.  Kernel space LDT.

  4.3.2.  LDT Selectors accessing the 'whole space'

  4.3.3.  Fast syscalls

  4.3.4.  Separate syscall interface (syscall manager)

  5.      Video Code

  5.1.    C files

  5.2.    Header files

  5.3.    Notes

  5.4.    Todo

  6.      The old way of generating a bootable DOSEmu

  6.1.    Boot ( 'traditional' method )

  6.1.1.  If you are

  6.1.2.  If you already have a HDIMAGE file

  6.1.3.  If you don't know how to copy files from/to the hdimage

  7.      New Keyboard Code

  7.1.    Whats New

  7.2.    Status

  7.3.    Keyboard server interface

  7.4.    Keyboard server structure

  7.4.1.  queue handling functions

  7.4.2.  The Front End

  7.4.2.1.        Functions in serv_xlat.c

  7.4.2.1.1.      putrawkey

  7.4.2.1.2.      putkey & others

  7.4.3.  The Back End

  7.4.3.1.        Queue Back End in keybint=on mode

  7.4.3.2.        Queue Back End in keybint=off mode

  7.4.3.3.        Functions in newkbd-server.c

  7.5.    Known bugs & incompatibilites

  7.6.    Changes from 0.61.10

  7.7.    TODO

  8.      IBM Character Set

  8.1.    What's new in configuration

  8.1.1.  IBM character set in an xterm

  8.1.2.  IBM character set at the console

  8.1.3.  IBM character set over a serial line into an IBM ANSI terminal

  8.2.    THE FUTURE by Mark Rejhon

  9.      Setting HogThreshold

  10.     Priveleges and Running as User

  10.1.   What we were suffering from

  10.2.   The new 'priv stuff'

  11.     The DANG system

  11.1.   Description

  11.2.   Changes from last compiler release

  11.3.   Using DANG in your code

  11.4.   DANG Markers

  11.5.   DANG_BEGIN_MODULE / DANG_END_MODULE

  11.5.1. DANG_BEGIN_FUNCTION / DANG_END_FUNCTION

  11.5.2. DANG_BEGIN_REMARK / DANG_END_REMARK

  11.5.3. DANG_BEGIN_NEWIDEA / DANG_END_NEWIDEA

  11.5.4. DANG_FIXTHIS

  11.5.5. DANG_BEGIN_CHANGELOG / DANG_END_CHANGELOG

  11.6.   Usage

  11.7.   Future

  12.     mkfatimage -- Make a FAT hdimage pre-loaded with files

  13.     mkfatimage16 -- Make a large FAT hdimage pre-loaded with files

  14.     Documenting DOSEmu

  14.1.   Sections

  14.2.   Emphasising text

  14.3.   Lists

  14.4.   Quoting stuff

  14.5.   Special Characters

  14.6.   Cross-References & URLs

  14.6.1. Cross-References

  14.6.2. URLs

  14.7.   Gotchas

  15.     Sound Code

  15.1.   Current DOSEmu sound code Unfortunately I haven't documented
  this yet. However, the current code has been completely rewritten and
  has been designed to support multiple operating systems and sound
  systems.

  15.2.   Original DOSEMU sound code

  16.     DMA Code

  16.1.   Current DOSEmu DMA code Unfortunately I haven't documented
  this yet. However, the current code has been completely rewritten from
  this.

  16.2.   Original DOSEMU DMA code

  16.2.1. Adding DMA devices to DOSEMU

  17.     DOSEmu Programmable Interrupt Controller

  17.1.   Other features

  17.2.   Caveats

  17.3.   Notes on theory of operation:

  17.3.1. Functions supported from DOSEmu side

  17.3.1.1.       Functions that Interface with DOS:

  17.3.2. Other Functions

  17.4.   A (very) little technical information for the curious

  18.     DOSEMU debugger v0.4

  18.1.   Introduction

  18.2.   Files

  18.2.1. modules

  18.2.2. executable

  18.3.   Installation

  18.4.   Usage

  18.5.   Commands

  18.6.   Performance

  18.7.   Wish List

  18.8.   BUGS

  18.8.1. Known bugs

  19.     MARK REJHON'S 16550 UART EMULATOR

  19.1.   PROGRAMMING INFORMATION

  19.2.   DEBUGGING HELP

  19.3.   FOSSIL EMULATION

  19.4.   COPYRIGHTS

  20.     Recovering the console after a crash

  20.1.   The mail message

  21.     Net code
  ______________________________________________________________________

  11..  IInnttrroodduuccttiioonn

  This documentation is derived from a number of smaller documents. This
  makes it easier for individuals to maintain the documentation relevant
  to their area of expertise. Previous attempts at documenting DOSEmu
  failed because the documentation on a large project like this quickly
  becomes too much for one person to handle.

  These are the technical READMEs. Many of these have traditionally been
  scattered around the source directories.

  22..  AAcccceessssiinngg ppoorrttss wwiitthh ddoosseemmuu

  Beside ports that certain dosemu-subsystems need, the system
  administrator can allow access to specific ports. There are several
  things to consider:

  +o  system integrity

  +o  system security

  +o  speed

  22..11..  SSyysstteemm IInntteeggrriittyy

  To block two programms from accessing a port without knowing that the
  other programm does, this is the strategy dosemu takes.

  +o  If the port is not listed in /proc/ioports, no other program should
     access the port. Dosemu will register theses ports. This will also
     block a second dosemu-process from accessing this ports.

  +o  If the port is listed, there's probbabbly a device that could use
     these ports. So we require the system administrator to give the
     name of the corresponding device. Dosemu tries to open this device
     and hopes this will block other from accessing. The parallel ports
     (0x378-0x37f) and /dev/lp1 act in this way.  To allow access to a
     port registered in /proc/ioports, it is neccessary that the open on
     the device given by the system administrator succeeds. An open
     on/dev/null will always succeed, but useon your own risk.

  22..22..  SSyysstteemm SSeeccuurriittyy

  If the strategy administrator did list ports in /etc/dosemu.conf and
  allow a user listed in /etc/dosemu.users to use dosemu, (s)he must
  know what he is doing.

  22..33..  SSppeeeedd

  For ports below 0x400, each process has a map af ports allowed to
  access. If a port is allowed, vm86() dosen't produce an exception.
  That way, dosemu has no way to log the values written to that port. To
  log the value, the port may not be in that map while inside vm86().
  This produces an exception, and dosemu can decide on a per incident
  case what to do with that exception. But that is rather slow.

  33..  TThhee VViirrttuuaall FFllaaggss

  Info written by Hans <lermen@fgan.de> to describe the virtual flags
  used by DOSEmu

  +o  DOS sees only IF, but IF will never _r_e_a_l_l_y set in the CPU
     flagregister, because this would block Linux. So Linus maintains a
     virtual IF (VIF), which he sets and resets accordingly to CLI, STI,
     POPFx, IRETx.  Because the DOS programm cannot look directly into
     the flagregister (exception the low 8 bits, but the IF is in bit
     9), it does not realize, that the IF isn't set. To see it, it has
     to perform PUSHF and look at the stack.

     Well, but PUSHF or INTxx is intercepted by vm86 and then Linus
     looks at his virtual IF to set the IF _o_n the stack.  Also, if IRETx
     or POPFx happen, Linus is getting the IF _f_r_o_m the stack, sets VIF
     accordingly, but leaves the _r_e_a_l IF untouched.

  +o  Now, how is this realized? This is a bit more complicated.  We have
     3 places were the eflag register is stored in memory:

     vvmm8866ss..rreeggss..eeffllaaggss
        in user space, seen by dosemu

     ccuurrrreenntt-->>ttssss..vv8866ffllaaggss
        virtual flags, macro VEFLAGS

     ccuurrrreenntt-->>ttssss..vvmm8866__iinnffoo-->>rreeggss..eeffllaaggss
        the _r_e_a_l flags, CPU reg. VM86

     The last one is a kernel space copy of vm86_struct.regs.eflags.

     Also there are some masks to define, which bits of the flag should
     be passed to DOS and which should be taken from DOS:

     ccuurrrreenntt-->>ttssss..vv8866mmaasskk
        CPU model dependent bits

     SSAAFFEE__MMAASSKK       ((00xxDDDD55))
        used the way _t_o DOS

     RREETTUURRNN__MMAASSKK     ((00xxDDFFFF))
        used the way _f_r_o_m DOS

     When sys_vm86 is entered, it first makes a copy of the whole
     vm86_struct vm86s (containing regs.eflags) and saves a pointer to
     it to current->tss.vm86_info. It merges the flags from 32-bit user
     space (NOTE: IF is always set) over SAFE_MASK and cur-
     rent->tss.v86mask into current->tss.v86mask. From this point on,
     all changes to VIF, VIP (virtual interrupt pending) are only done
     in VEFLAGS.  To handle the flag setting there are macros within
     vm86.c, which do the following:

     sseett__IIFF,, cclleeaarr__IIFF
        only modifies VEFLAGS;

     cclleeaarr__TTFF
        sets a bit in the _r_e_a_l flags;

     sseett__vvffllaaggss((xx))
        set flags x over SAFE_MASK  to _r_e_a_l flags (IF is not touched)

     xx==ggeett__vvffllaaggss
        returns _r_e_a_l flags over RETURN_MASK and translates VIF of
        VEFLAGS to IF in x;

     When it's time to return from vm86() to user space, the _r_e_a_l flags
     are merged together with VIF and VIP from VEFLAGS and put into the
     userspace vm86s.regs.eflags. This is done by save_v86_state() and
     this does _n_o_t translate the VIF to IF, it should be as it was on
     entry of sys_vm86: set to 1.

  +o  Now what are we doing with eflags in dosemu ?  Well, this I don't
     really know. I saw IF used (told it Larry), I saw VIF tested an
     set, I saw TF cleared, ... and NT flag....

     But I know what Linus thinks that we should do: Always interpret
     and set VIF, and let IF untouched, it will nevertheless set to 1 at
     entry of sys_vm86.

     How I think we should proceed? Well this I did describe in my last
     mail.

     _N_O_T_E VIF and VIP in DOS-CPU-flagsregister are inherited from
     32-bit, so actually they are both ZERO.

     On return to 32-bit, _o_n_l_y VIF will appear in vm86s.regs.eflags !
     _V_I_P _w_i_l_l _b_e _Z_E_R_O, again: _V_I_P will be used _o_n_l_y _o_n_c_e !!!!

     I have to add, that VIP will be cleared, because it is not in any
     of the masks of vm86.

  44..  VVMM8866PPLLUUSS,, nneeww kkeerrnneell''ss vvmm8866 ffoorr aa ffuullll ffeeaattuurree ddoosseemmuu

  ( available now in all kernels >= 2.0.28, >= 2.1.15 )

  The below gives some details on the new kernel vm86 functionality that
  is used for a 'full feature dosemu'. We had more of those kernel
  changes in the older emumodule, but reduced the kernel support to an
  absolute minimum. As a result of this we now have this support in the
  mainstream kernels >= 2.0.28 as well as >= 2.1.15 and do not need
  emumodule any more (removed since dosemu 0.64.3). To distinguish
  between the old vm86 functionality and the new one, we call the later
  VM86PLUS.

  Written on January 14, 1997 by Hans Lermen <lermen@fgan.de>.

  44..11..  RReessttrriiccttiioonnss

  +o  Starting with dosemu-0.64.3 we will no longer support older kernels
     ( < 2.0.28 ) for vm86plus. If you for any reasons can't upgrade the
     kernel, then either use an older dosemu or don't configure the
     vm86plus support.

  +o  Please don't use any 2.1.x kernels ^lt; 2.1.15 and don't use the
     patch that came with dosemu-0.64.1, we changed the syscall
     interface because Linus wanted to be absolutely shure that no older
     (non-dosemu) binary would break.

     Also, don't use any dosemu binaries that were compiled under 2.1.x
     but earlier then 2.1.15.

  44..22..  PPaarrttss iinn tthhee kkeerrnneell tthhaatt ggeett cchhaannggeedd ffoorr vvmm8866pplluuss

  44..22..11..  CChhaannggeess ttoo aarrcchh//ii338866//kkeerrnneell//vvmm8866..cc

  44..22..11..11..  NNeeww vvmm8866(()) ssyyssccaallll iinntteerrffaaccee

  The vm86() syscall of vm86plus contains a generic interface: old style
  vm86 syscall is 113, the new one is 166.  At entry of vm86() the
  vm86_struct gets completely copied into kernel space and now _r_e_m_a_i_n_s
  on the kernel stack until control return to user space. This has the
  advantage that performance is increased as long as emulation loops
  between VM86 and kernel space ( which happens quite often ). A second
  advantage is, that we now better can translate between old
  vm86_struct, vm86plus_struct and kernel 2.1.x changed internal
  pt_regs, hence old vm86 and new vm86plus user space binaries run on
  both 2.0.x and 2.1.x kernel.  The entry routine of the old style
  vm86() translates to the new expanded vm86plus_struct before calling
  the common new do_sys_vm86().

  It is possible to detect the existence of vm86plus support in the
  kernel by just calling vm86(0,(void *)0) on syscall 166 entry.  On
  success 0 is returned, an unpatched kernel will return with -1.

  44..22..11..22..  AAddddiittiioonnaall DDaattaa ppaasssseedd ttoo vvmm8866(())

  When in vm86plus mode vm86() uses the new 'struct vm86plus_struct'
  instead of 'struct vm86_struct'. This contains some additional flags
  that are used to control whether vm86() should return earlier than
  usual to give the timer emulation in dosemu a chance to be in sync.
  Without this, updating the emulated timer chip happens too seldom and
  may even result in 'jumping back', because the granulation is too big
  and rounding happens. As we don't know what granulation the DOS
  application is relying on, we can't emulate the expected behave, hence
  the application locks or crashes.  This especially happens when the
  application is doing micro timing.

  As a downside of 'returning more often', we get DOS-space stack
  overflows, when we suck too much CPU. This we compensate by detecting
  this possibility and decreasing the 'return rate', hence giving more
  CPU back to DOS-space.

  So we can realize a self adapting control loop with this feature.

  44..22..11..33..  IIRRQQ ppaassssiinngg

  Vm86plus also hosts the IRQ passing stuff now, that was a separate
  syscall in the older emumodule (no syscallmgr any more).  As this IRQ
  passing is special to dosemu, we anyway  couldn't it use for other
  (unix) applications. So having it as part of vm86() should be the
  right place.

  44..22..11..44..  DDeebbuuggggeerr ssuuppppoorrtt

  GDB is a great tool, however, we can't debug DOS and/or DPMI code with
  it. Dosemu has its own builtin debugger (dosdebug) which allows
  especially the dosemu developers to track down problems with dosemu
  and DOS applications for which (as usual) we have no source.  ( ...
  and debugging DOS applications always has been the 'heart' of dosemu
  development ).

  Dosdebug uses some special flags and data in 'vm86plus_struct', which
  are passed to vm86(), and vm86() reacts on it and returns back to
  dosemu with the dosdebug special return codes.

  As with dosemu-0.64.1 you now can run both debuggers simultaneously,
  dosdebug as well as GDB. Dosdebug will be triggered only for VM86
  traps and with GDB you may debug dosemu itself. However, GDB can't be
  used when DPMI is in use, because it will break on each trap that is
  used to simulate DPMI, you won't like that.

  44..22..22..  CChhaannggeess ttoo aarrcchh//ii338866//kkeerrnneell//llddtt..cc

  44..22..22..11..  NNeeww ffuunnccttiioonnccooddee ffoorr ''wwrriittee'' iinn mmooddiiffyy__llddtt ssyyssccaallll

  In order to preserve backword compatibility with Wine and Wabi the
  changes in the LDT stuff are only available when using function code
  0x11 for 'write' in the modify_ldt syscall.  Hence old binaries will
  be served with the old LDT behavior.

  44..22..22..22..

  The 'struct modify_ldt_ldt_s' got an additional bit: 'useable'.  This
  is needed for DPMI clients that make use of the 'available' bits in
  the descriptor (bit 52).  'available' means, the hardware isn't using
  it, but software can put information into.

  Because the kernel does not use this bit, its save and harmless.
  Windows 3.1 is such a client, but also some 32-bit DPMI clients are
  reported to need it. This bit only is used for 32-bit clients.  DPMI-
  function SetDescriptorAccessRights (AX=0009) passes this in bit 4 of
  CH ((80386 extended access rights).

  44..22..22..33..

  The function 1 (write_ldt) of syscall modify_ldt() allows
  creation/modification of selectors containing a 'present' bit, that
  get updated correctly later on. These selectors are setup so, that
  they _e_i_t_h_e_r can't be used for access (null-selector) _o_r the call gate
  descriptor (segment present). This call gate of course is checked to
  not give any kernel access rights.  Hence, security will not be hurt
  by this.

  44..22..33..  CChhaannggeess ttoo aarrcchh//ii338866//kkeerrnneell//ssiiggnnaall..cc

  Because DPMI code switches via signal return, some type of selectors
  that the kernel normally would not allow to be loaded into a segment
  registers have been made loadable. The involved register are DS, ES FS
  and GS. Loading of CS or SS is not changed.

  The original kernel code would forbid any non-null selector that
  hasn't privilege level 3, and this also could be one of the LDT
  selectors. However, sys_sigreturn doesn't check the descriptors that
  belong to the selector, hence would not see that they are save.  But
  as we assure proper setting of _a_l_l LDT selector via 'write_ldt' of
  modify_ldt(), we safely may allow LDT selectors to be loaded.  If they
  are not proper, we then get an exception and have a chance to emulate
  access. And because old type binaries (Wabi) will not be able create
  newer type selector (see 2.2.1), gain this wont hurt.

  44..22..44..  CChhaannggeess ttoo aarrcchh//ii338866//kkeerrnneell//ttrraappss..cc

  The low-level exception entry points for INTx (x= 0, 1..5, 6) in the
  kernel normally send a signal to the process, that then may handle the
  exception. For INT1 (debug), the kernel does special treatment and
  checks whether it gets interrupted from VM86.

  Due to limitation in how we can handle signals in dosemu without
  becoming to far behind 'real time' and because we need to handle those
  things on the current vm86() return stack, we need to handle the above
  INTx in a similar manor then INT1.

  When INTx happens out of VM86 (i.e. the CPU was in virtual 8086 mode
  when the exception occurred), we do not send a signal, but return from
  the vm86() syscall with an appropriate return code.

  If the above INTx happens from within old style vm86() call, the
  exceptions also are handled 'the old way'. (backward comptibility)

  44..33..  AAbbaannddoonneedd ''bbeellllss aanndd wwhhiissttlleess'' ffrroomm oollddeerr eemmuummoodduullee

  ( If you have an application that needs it, well then it won't work,
  and please don't ask us to re-implement the old behaviour.  We have
  good reasons for our decision. )

  44..33..11..  KKeerrnneell ssppaaccee LLDDTT..

  Some DPMI clients have really odd programming techniques that don't
  use the LAR instruction to get info from a descriptor but access the
  LDT directly to get it. Well, this is not problem with our user space
  LDT copy (LDT_ALIAS) as long as the DPMI client doesn't need a
  reliable information about the 'accessed bit'.

  In the older emumodule we had a so called KERNEL_LDT, which (readonly)
  accessed the LDT directly in kernel space. This now has been abandoned
  and we use some workarounds which may (or may not) work for the above
  mentioned DPMI clients.

  44..33..22..  LLDDTT SSeelleeccttoorrss aacccceessssiinngg tthhee ''wwhhoollee ssppaaccee''

  DPMI clients may very well try to create selectors with a type and
  size that would overlap with kernel space, though the client normally
  only would access user space with such selectors (e.g. expand down
  segments).

  This was a security hole in the older Linux kernel, that was fixed in
  the early 1.3.x kernel series. Due to complaints on linux-msdos
  emumodule did allow those selectors if dosemu was run as root.
  Because only very few DOS applications are needing this (e.g. some odd
  programmed games), we now favourite security and don't allow this any
  more.

  44..33..33..  FFaasstt ssyyssccaallllss

  In order to gain speed and to be more atomic on some operations we had
  so called fast syscalls, that uses INT 0xe6 to quickly enter kernel
  space get/set the dosemu used IRQ-flags and return without letting the
  kernel a chance to reschedule.

  Today the machines perform much better, so there is no need for for
  those ugly tricks any more. In dosemu-0.64.1 fast syscalls are no
  longer used.

  44..33..44..  SSeeppaarraattee ssyyssccaallll iinntteerrffaaccee ((ssyyssccaallll mmaannaaggeerr))

  The old emumodule uses the syscallmgr interface to establish a new
  (temporary) system call, that was used to interface with emumodule.
  We now have integrated all needed stuff into the vm86 system call,
  hence we do not need this technique any more.

  55..  VViiddeeoo CCooddee

  I have largely reorganized the video code. Be aware that a lot of code
  is now in a different place, and some files were moved or renamed.

  55..11..  CC ffiilleess

     vviiddeeoo//vviiddeeoo..cc
        global variables, init/cleanup code video_init(), video_close(),
        load_file(), video_config_init()

     vviiddeeoo//iinntt1100..cc
        int10 emulation (formerly int10.h), Scroll, clear_screen,
        char_out, set_video_mode

     vviiddeeoo//vvcc..cc
        console switching code (formerly video.c)

     vviiddeeoo//ccoonnssoollee..cc
        console mode routines

     vviiddeeoo//eett44000000..cc,,
        video/s3.c, video/trident.c" card-dependent console/graphics
        switching routines

     vviiddeeoo//vvggaa..cc
        console mode? graphics?

     vviiddeeoo//tteerrmmiinnaall..cc
        terminal mode video update routines (ansi/ncurses)

     vviiddeeoo//XX..cc
        Xwindow stuff

  55..22..  HHeeaaddeerr ffiilleess

     vviiddeeoo//vvcc..hh
        def's relating to console switching (formerly include/video.h)

     iinncclluuddee//vviiddeeoo..hh
        def's for general video status variables and functions

  55..33..  NNootteess

  +o  we now have 'virtual' video support. Every video front-end defines
     a static, initialized structure 'Video_xxx' (e.g. Video_console)
     which contains (mostly) pointers to the appropriate routines for
     certain tasks.

     Please use this when implementing new video front ends!  (See
     video/video.h for more info)

  +o  most of the video code & defs is removed from emu.c and emu.h (now
     mostly in video/video.c)

  +o  int10.h no longer exists (now in video/int10.c)

  +o  sigalrm now again checks the dirty bit(s) in vm86s.screen_bitmap
     before calling update_screen.

     At the moment, it doesn't seem to achieve much, but it might help
     when we use mark's scroll detector, and will be absolutely
     necessary for a good X graphics support.

     Note that for all video memory modifications done outside of vm86
     mode we must now use set_dirty()  (defined in int10.c).  _t_h_i_s _i_s
     _c_u_r_r_e_n_t_l_y _d_i_s_a_b_l_e_d_. _T_o _e_n_a_b_l_e _i_t_, _s_e_t _V_I_D_E_O___C_H_E_C_K___D_I_R_T_Y _t_o _1 _i_n
     _i_n_c_l_u_d_e_/_v_i_d_e_o_._c_.

  55..44..  TTooddoo

  +o  cleanup terminal/console mode initialization (currently called from
     video_init() in video.c) termioInit(), termioClose() should
     probably be split up somehow (i.e. general/terminal/console)

  +o  fix bug: screen is not restored properly when killing dosemu in
     graphics mode

  +o  properly implement set_video_mode()   (int10.c)

  +o  cursor in console mode ok?

  +o  put int10.c into video.c?

  +o  put vc.c into console.c?

  66..  TThhee oolldd wwaayy ooff ggeenneerraattiinngg aa bboooottaabbllee DDOOSSEEmmuu

  Since dosemu-0.66.4 you will not need the complicated method of
  generating a bootable dosemu suite (see Quickstart). However, who
  knows, maybe you need the old information too ...

  66..11..  BBoooott (( ''ttrraaddiittiioonnaall'' mmeetthhoodd ))

  66..11..11..  IIff yyoouu aarree _n_e_w _t_o _D_O_S_E_M_U

  +o  Make _C_E_R_T_A_I_N that your first disk statement in /etc/dosemu.conf _I_S
     pointing to your hdimage!

  +o  Reboot DOS (the real version, not DOSEMU.)  Put a newly formatted
     diskette in your a: drive.  Run "sys a:" to transfer the system
     files to the diskette.  Copy SYS.COM from your DOS directory
     (usually C:.nr bi 1

     Reboot Linux.  Run 'dos -A'.  After a short pause, the system
     should come up.  Try "dir c:" which should list the files on the
     harddrive distribution image.  If that works, run: "sys c:".  Exit
     dos by running "c:\xitemu".  If you have problems, hold down the
     <ctrl> and <alt> buttons simultaneously while pressing <pgdn>.
     (<ctrl><alt><pgdn> will automatically exit dosemu.)

  66..11..22..  IIff yyoouu aallrreeaaddyy hhaavvee aa HHDDIIMMAAGGEE ffiillee

  +o  If you have a previous version of DOSEMU running, you should copy
     the hdimage drive that you boot from.  Some of these files have
     changed.

  66..11..33..  IIff yyoouu ddoonn''tt kknnooww hhooww ttoo ccooppyy ffiilleess ffrroomm//ttoo tthhee hhddiimmaaggee

  +o  Have a look at the recent mtools package (version 3.6 at time of
     writeing).  If you have the following line in /etc/mtools.conf

            drive g: file="/var/lib/dosemu/hdimage" partition=1 offset=128

  then you can use _a_l_l _t_h_e _m_t_o_o_l _c_o_m_m_a_n_d_s to access it, such as

           # mcopy g:autoexec.bat -
           Copying autoexec.bat
           @echo off
           echo "Welcome to dosemu 0.66!"

  77..  NNeeww KKeeyybbooaarrdd CCooddee

  This file describes the new keyboard code which was written in late
  '95 for scottb's dosemu-0.61, and adapted to the mainstream 0.63 in
  mid-'96.

  It was last updated by R.Zimmermann <zimmerm@mathematik.uni-
  marburg.de> on 18 Sep 96 and updated by Hans <lermen@fgan.de> on 17
  Jan 97. ( correction notes marked *HH  -- Hans )

  77..11..  WWhhaattss NNeeww

  What's new in the new keyboard code? A lot.

  To the user:

  +o  Most of the keyboard-related bugs should have gone away. Hope I
     didn't introduce too many new ones (-: Keyboard emulation should be
     more accurate now; some keys are supported that weren't before,
     e.g. Pause.

  +o  The X { keycode } option is now obsolete. This was basically a bad
     hack to make things work, and was incompatible to X servers other
     than XFree86.

  To the dosemu hacker:

  +o  While the old code already claimed to be "client-server" (and was,
     to some extent), the new code introduces a clean, well-defined
     interface between the `server', which is the interface to DOS
     (int9, bios etc.), and the `clients', which are the interfaces to
     the user frontends supported by dosemu. Currently, clients are
     `raw', `slang' (i.e. terminal), and `X'.

     Clients send keystrokes to the server through the interface
     mentioned above (which is defined in "keyboard.h"), the most
     important functions being `putkey()' and `putrawkey()'.

  +o  The keyboard server was rewritten from scratch, the clients were
     heavily modified.

  +o  There is now general and efficient support for pasting large text
     objects.  Simply call paste_text().

  +o  The keyboard-related code is now largely confined to base/keyboard,
     rather than scattered around in various files.

  There is a compile-time option NEW_KBD_CODE (on by default) to
  activate the new keyboard code. The old stuff is still in there, but I
  haven't recently checked whether it still works, or even compiles.
  Once the new code is reasonably well tested I'll remove it.  ( *HH:
  the old code _i_s made workeable and remains ON per default, it will
  stay maintained for a while, so we can easily check where the bugs
  come from )

  Just like the old keyboard code, we still have the rawkeyboard=on/off
  and keybint=on/off modes.

  77..22..  SSttaattuuss

  Almost everything seems to work well now.

  The keyboard server should now quite accurately emulate all key
  combinations described the 'MAKE CODES' & 'SCAN CODES' tables of
  HelpPC 2.1, which I used as a reference.

  See below for a list of known bugs.

  What I need now is YOUR beta-testing... please go ahead and try if all
  your application's wierd key combinations work, and let me know if
  they don't.

  77..33..  KKeeyybbooaarrdd sseerrvveerr iinntteerrffaaccee

  This is all you should need to know if you just want to send
  keystrokes to DOS.

  Use the functions

  +o  putrawkey(t_rawkeycode code);

  +o  putkey(Boolean make, t_keysym key)

  +o  putkey_shift(Boolean make, t_keysym key, t_shiftstate shiftstate)

  You may also read (but not write!) the variable 'shiftstate' if
  necessary.

  ehm... see the DANG comments in base/newkbd-server.c for more
  information...

  _N_O_T_E_: the server's queue is limited to a relatively small number of
  keyboard events (currently 15). IMO, it is not a good idea to let the
  queue be arbitrarily long, as this would render the behaviour more
  incontrollable if the user typed a lot of mad things while a dos
  program wasn't polling the keyboard.

  For pasting, there is special support in base/keyboard/keyb_clients.c
  which runs on top of the server.

  77..44..  KKeeyybbooaarrdd sseerrvveerr ssttrruuccttuurree

  [_N_O_T_E_: you won't need to read this unless you actually want to modify
  the keyboard server code. In that case, however, you MUST read it!]

  [_N_o_t_e_: I'll have to update this. The queue backend works somewhat
  different now.]

  The central data structure of the keyboard server is the dosemu
  keyboard queue (to be distinguished from the bios keyboard buffer,
  which is run by int09 and int16).

  The keyboard server code can be largely divided into the `queue
  frontend' (serv_xlat.c, serv_maps.c), which does keycode translation,
  and the `queue backend' (serv_backend.c, serv_8042.c), which does the
  interfacing to DOS. The two sides communicate only through the queue.
  Each queue entry holds a data structure corresponding to (mostly) one
  keypress or release event. [The exception are the braindead 0xe02a /
  0xe0aa shift key emulation codes the keyboard processor are treated as
  seperate events.]

  Each queue entry holds a up to 4 bytes of raw keycodes for the port
  60h emulation, along with a 2-byte translated int16h keycode and the
  shift state after this event was processed.  Note that the bios_key
  field can be empty (=0), e.g. for shift keys, while the raw field
  should always contain something.

  77..44..11..  qquueeuuee hhaannddlliinngg ffuunnccttiioonnss

  +o  static inline Boolean queue_empty(void);

  +o  static inline void clear_queue(void);

  +o  static inline void write_queue(Bit16u bios_key,t_shiftstate
     shift,Bit32u raw);

  +o  static void read_queue(Bit16u *bios_key, t_shiftstate *shift,
     t_rawkeycode *raw);

  Accordingly, the keyboard code is largely divided into two parts,

  +o  the 'front end' of the queue, responsible for translating keyboard
     events into the 'queue entry' format.

  +o  the 'back end' of the queue, which reads the queue and sends
     keycodes to DOS

  77..44..22..  TThhee FFrroonntt EEnndd

        putrawkey() -------->----+
             \   \               |
              \   v              |
               \  translate()    |
                \     |          |
                 \    v          \    (t_rawkeycode[4])      /---QUEUE----\
            /->---\---|-----------*------------------------> [ raw        ]
           /       \  \  (t_keysym+char)                     [            ]
        putkey() ->-\--*--------------> make_bios_code() --> [ bios_key   ]
           \         \                                       [            ]
            \         v                           /--------> [ shiftstate ]
             \---> do_shift_keys()               /           \------------/
                       |                        /
                       v        (t_shiftstate) /
                   [shiftstate]---------------/

       --------->  data flow (&calls, sometimes)

  77..44..22..11..  FFuunnccttiioonnss iinn sseerrvv__xxllaatt..cc

  +o  static Boolean do_shift_keys(Boolean make, t_keysym key);

  +o  static Bit16u make_bios_code(Boolean make, t_keysym key, uchar
     ascii);

  +o  static uchar translate(t_keysym key);

  +o  static Boolean handle_dosemu_keys(t_keysym key);

  +o  void putrawkey(t_rawkeycode code);

  +o  void putkey(Boolean make, t_keysym key, uchar ascii);

  +o  void putkey_shift(Boolean make, t_keysym key, uchar ascii,
     t_shiftstate s);

  Any keyboard client or other part of dosemu wishing to send keyboard
  events to DOS will do so by calling one of the functions putrawkey,
  putkey, and putkey_shift.

  77..44..22..11..11..  ppuuttrraawwkkeeyy

  is called with a single raw scancode byte. Scancodes from subsequent
  calls are assembled into complete keyboard events, translated and
  placed into the queue.

  77..44..22..11..22..  ppuuttkkeeyy && ootthheerrss

  77..44..33..  TThhee BBaacckk EEnndd

  77..44..33..11..  QQuueeuuee BBaacckk EEnndd iinn kkeeyybbiinntt==oonn mmooddee

                     EMULATOR SIDE        |    x86 SIDE
                                          |
                        ....[through PIC].|....................
                        :                 |           :        v
  QUEUE      .....> out_b_8042() --> [ port 60h ] ----:---> other_int9_handler
  |         :                             |        \  `.......    (:) (|)
  |         :                             |         \         v   (v) (|)
  +->int_chk_q()-> bios_buffer----> [ get_bios_key ]-----> default_int9_handler
        ^  \                           :  |                   |       (|)
        :   \----> shiftstate_buffer   :  |                   v       (v)
        :               |         .....:  |               bios keyb buffer
        :               v        v        |
        :          copy_shift_state() ----+-------------> bios shiftstate
        :                                 |
        :                                 |
        :                                 |
      backend_run()                       |

  Abbreviations:
  int_chk_q() = int_check_queue()
  out_b_8042() = output_byte_8042()

  77..44..33..22..  QQuueeuuee BBaacckk EEnndd iinn kkeeyybbiinntt==ooffff mmooddee

                         EMULATOR SIDE         |    x86 SIDE
                                               |
                    kbd_process()              |
                         :     :               |
                         :     v               |
        QUEUE -----------:--> put_keybuf() ----+-------------> bios keyb buffer
            \            v                     |
             \--------> copy_shift_state() ----+-------------> bios shiftstate
                                               |
                                               |
                                               |

  77..44..33..33..  FFuunnccttiioonnss iinn nneewwkkbbdd--sseerrvveerr..cc

  +o  void do_irq1();

  +o  void clear_keybuf();

  +o  static inline Boolean keybuf_full(void);

  +o  static inline void put_keybuf(Bit16u scancode);

  +o  void copy_shift_state(t_shiftstate shift);

  +o  static void kbd_process(void);

  Transfer of the keyboard events from the dosemu queue to DOS is done
  in two completely different ways, depending on the keybint setting in
  dosemu.conf:

     kkeeyybbiinntt==ooffff
        kbd_process() simply reads the queue until it finds a bios
        keycode (as we're not interested in raw scancodes without int9
        emulation), which it stores in the bios keyboard buffer, while
        also copying the shift state to the appropriate bios variables.

     kkeeyybbiinntt==oonn
        As soon as a key is stored into the empty queue, kbd_process()
        triggers IRQ1 through the PIC emulation, which some time later
        will call do_irq1().

        do_irq1() will prepare for the interrupt execution by reading
        from the queue and storing the values in the variables
        raw_buffer, shiftstate_buffer, and bios_buffer, and then call
        run_irq() to run the actual DOS interrupt handler.

        again, there are two cases:

     +o  the default int09 handler in the dosemu bios (base/bios_emu.S)
        will call the helper function get_bios_key(), which returns the
        translated bios keycode from bios_buffer and copies the
        shiftstate from shiftstate_buffer. The raw keycodes are not
        used.  get_bios_key() may also return 0 if no translated keycode
        is ready.

        The int9 handler will also call the `keyboard hook' int15h,
        ax=????.

     +o  if a dos application or TSR has redirected the keyboard
        interrupt, its handler might read from port 60h to get raw
        scancodes.  Port 60h is of course virtualized, and the read
        returns the value from raw_buffer.

        Note that a mix between the two cases is also possible, e.g. a
        TSR's int9 handler first reads port 60h to check if a particular
        key was pressed, then gives over to the default int9 handler.
        Even these cases should be (and are, I think) handled properly.

        Note also that in any case, int9 is called once for each raw
        scancode byte. Eg.,suppose the user pressed the PgDn key, whose
        raw scancode is E0 51:

     +o  first call to int9:

                     read port 60h        = 0xe0
                     read port 60h        = 0xe0   (**)
                     call get_bios_key()  = 0
                     iret

     do_irq1() reschedules IRQ1 because further scancodes are in the
     queue

     +o  second call to int9

                     read port 60h        = 0x51
                     call get_bios_key()  = 0x5100    (bios scancode of PgDn)
                     iret

     (** multiple port 60h reads during the same interrupt yield the
     same result.)

  This is not a complete documentation. If you actually want to hack the
  keyboard server, you can't avoid reading the code, I'm afraid ;-)

  77..55..  KKnnoowwnn bbuuggss && iinnccoommppaattiibbiilliitteess

  +o  behaviour wrt. cli/sti is inaccurate, because the PIC code
     currently doesn't allow un-requesting if IRQ's.

  +o  emulation of special 8042 and keyboard commands is incomplete and
     probably still somewhat faulty.

  +o  the 'internal' keyboard flags in seg 0x40, like E0 prefix received
     etc.  are never set. This shouldn't hurt, for all but the most
     braindead TSRs.

  +o  CAPS LOCK uppercase translation may be incorrect for some (non-
     german) national characters.

  +o  typematic codes in X and non-raw modes are Make+Break, not just
     Make.  This shouldn't hurt, though.

  +o  in X mode, shift+Gray cursor keys deliver numbers if NumLock is
     off.  This is an X problem, and AFIK nothing can be done about it.

  +o  in X, something may be wrong with F11+F12 handling (and again,
     possibly necessarily wrong).

  +o  the Pause key works in terms of raw scancodes, however it's
     function is not implemented (i.e. it doesn't actually halt DOS
     execution.)

  +o  in terminal (i.e. slang) mode, several things might be wrong or at
     least improveable.

  +o  there is no difference between the int16h functions 0,1 and the
     extended functions 0x10,0x11 - i.e. 0,1 don't filter out extended
     keycodes.

  +o  keyb.exe still doesn't work (hangs) - most probably due to the
     above.

  77..66..  CChhaannggeess ffrroomm 00..6611..1100

  +o  adapted to 0.63.55

  +o  adapted to 0.63.33

  +o  renamed various files

  +o  various minor cleanups

  +o  removed putkey_shift, added set_shiftstate

  +o  in RAW mode, read current shiftstate at startup

  +o  created base/keyboard/keyb_client.c for general client
     initialisation and paste support.

  77..77..  TTOODDOO

  +o  find what's wrong with TC++ 1.0

  +o  implement pause key

  +o  adapt x2dos (implement interface to send keystrokes from outside
     dosemu)

  +o  once everything is proved to work, remove the old keyboard code

  88..  IIBBMM CChhaarraacctteerr SSeett

  This is Mark Rejhon's version 2 of terminal support for the IBM
  graphics character set with a remote DOSEMU or a xterm DOSEMU.   Don't
  take these patches as final or original, as there is some cleaning up
  to do, Look forward to version 3 of the terminal support...! :-)

  Please give feedback or suggestions to Mark Rejhon at the
  <marky@magmacom.com> address.  Thanks!

  This prereleases updates supports:

  +o  "xdosemu" script to run DOSEMU in a normal xterm/rxvt!

  +o  IBM characters in telnet or kermit session from a Linux console.

  +o  IBM characters in an IBM character terminal like minicom or a DOS-
     based ANSI terminal.

  88..11..  WWhhaatt''ss nneeww iinn ccoonnffiigguurraattiioonn

  There is a new keyword called "charset" which accept either of these
  values: "latin" "ibm" and "fullibm".   View ./video/terminal.h for
  more information on these character set.  Here are the instructions on
  how to activate the 8-bit graphical IBM character set for DOSEMU:

  88..11..11..  IIBBMM cchhaarraacctteerr sseett iinn aann xxtteerrmm

  GREAT NEWS: You just use your existing ordinary "rxvt" or "xterm".
  Just install the VGA font by going into the DOSEMU directory and
  running the "xinstallvgafont" script by typing "./xinstallvgafont".
  Then just run "xdosemu" to start a DOSEMU window!

  88..11..22..  IIBBMM cchhaarraacctteerr sseett aatt tthhee ccoonnssoollee

  This will work if you are using the Linux console for telnet or
  kermit, to run a remote DOSEMU session.  Just simply run the
  "ibmtermdos" command on the remote end.  It puts the Linux console to
  use the IBM font for VT100 display, so that high ASCII characters are
  directly printable.

  _N_O_T_E_: This will not work with "screen" or any other programs that
  affect character set mapping to the Linux console screen.  For this,
  you should specify "charset fullibm" inside the "video { }"
  configuration in /etc/dosemu.conf.

  88..11..33..  IIBBMM cchhaarraacctteerr sseett oovveerr aa sseerriiaall lliinnee iinnttoo aann IIBBMM AANNSSII tteerrmmiinnaall

  Simply specify "charset fullibm" inside the "video { }" configuration
  in /etc/dosemu.conf and then run "dos" in the normal manner.  You must
  be running in an ANSI emulation mode (or a vt102 mode that is
  compatible with ANSI and uses the IBM character set.)

  88..22..  TTHHEE FFUUTTUURREE bbyy MMaarrkk RReejjhhoonn

  +o  NCURSES color to be added.  The IBM character set problem is
     solved.

  +o  clean up terminal code.

  +o  Add command line interface for character set and for serial port
     enable/disabling.

  +o  Use a separate "terminal { }" line for all the ncurses/termcap
     related configuration, instead of putting it in the "video { }"
     line.

  99..  SSeettttiinngg HHooggTThhrreesshhoolldd

  Greetings DOSEMU fans,

  Hogthreshold is a value that you may modify in your DOSEMU.CONF file.
  It is a measure of the "niceness" of Dosemu.  That is to say, it
  attempts to return to Linux while DOS is 'idling' so that DOSEMU does
  not hog all the CPU cycles while waiting at the DOS prompt.

  Determining the optimal Hogthreshold value involves a little bit of
  magic (but not so much really.)  One way is to try different values
  and look at the 'top' reading in another console.  Setting the value
  too low may mildly slow Dosemu performance.  Setting the value too
  high will keep the idling code from working.

  That said, a good basic value to try is "half of your Bogo-Mips
  value".  (The Bogo-Mips value is displayed when the kernel is booting,
  it's an imaginary value somewhat related to CPU performance.)

  Setting the value to 0 will disable idling entirely.  The default
  value is 10.

  This files is some kind of FAQ on how to use the 'HogThreshold' value
  in the dosemu config file.

  In case you have more questions feel free to ask me (
  <andi@andiunx.m.isar.de>).

  Those of you who simply want to have DOSEMU running at highest
  possible speed simply leave the value to zero, but if you are
  concerned about DOSEMU eating too much CPU time it's worth playing
  with the HogThreshold value.

     WWhhyy ddoo II nneeeedd ttoo sseett tthhee HHooggTThhrreesshhoolldd vvaalluuee,, wwhhyy ccaann''tt DDOOSSEEMMUU
        just stop if it is waiting for a keystroke ?"  The reason is the
        way how DOS and a lot of applications have implemented

        It's most often done by something similar to the following code
        fragment :

          wait_for_key:
                  ; do something
                  mov ah,1
                  int 0x16 ; check key status
                  jz      wait_for_key ; jump if no key
                  ; found a key
                  mov ah,0
                  int 0x16 ; get key

     This means that the application is busy waiting for the keystroke.

     WWhhaatt iiss aa ggoooodd vvaalluuee ffoorr HHooggTThhrreesshhoolldd ttoo ssttaarrtt wwiitthh ??
        On a 40 MHZ 486 start with a value of 10.  Increase this value
        if you to have your DOS application run faster, decrease it if
        you think too much CPU time is used.

     IItt ddooeess nnoott wwoorrkk oonn mmyy mmaacchhiinnee..
        You need to have at least dosemu0.53pl40 in order to have the
        anti-hog code in effect.

     WWhhyy nnoott ssiimmppllyy uussee aa vveerryy llooww vvaalluuee ooff
        Do I really have to try an individual value of HogThreshold ?"
        This would slow down your DOS application. But why not, DOS is
        slow anyway :-).

     HHooww ddoo II ffoouunndd oouutt aabboouutt CCPPUU uussaaggee ooff DDOOSSEEMMUU ??
        Simply use 'top'. It displays cpu and memory usage.

  P.S.  If you want to change the HogThreshold value during execution,
  simply call int e6h w/al=12h & bx=the new value.  This is what
  speed.com does. If you are interested, please take a look at speed.c.

  Notes:  If your application is unkind enough to do waits using an
  int16h fcn 1h loop without calling the keyboard idle interrupt (int
  28h), this code is not going to help much.  If someone runs into a
  program like this, let me ( <scottb@eecs.nwu.edu> ) know and I'll
  rewrite something into the int16 bios.

  1100..  TThhiiss sseeccttiioonn wwrriitttteenn bbyy HHaannss LLeerrmmeenn <<lleerrmmeenn@@ffggaann..ddee>> ,, AApprr 66,,
  11999977 PPrriivveelleeggeess aanndd RRuunnnniinngg aass UUsseerr

  1100..11..  WWhhaatt wwee wweerree ssuuffffeerriinngg ffrroomm

  Well, I got sick with the complaints about 'have problems running as
  user' and did much effort to 'learn' about what we were doing with
  priv-settings.  To make it short: It was a real mess, there was the
  whole dosemu history of different strategies to reach the same aim.
  Well, this didn't make it clearer. I appreciate all the efforts that
  were done by a lot of people in the team to make that damn stuff
  working, and atleast finding all those places _w_h_e_r_e we need to handle
  privs was a great work and is yet worth.

  The main odds happened because sometimes functions, that were called
  within a priv_on/off()...priv_default() brackets were calling
  priv_on/off()...priv_default() themselves. And with introduction of
  this priv_default() macro, which handled the 'default' case (run as
  user or run as root) the confusion was complete. Conclusion: recursive
  settings were not handled, and you always had to manually keep track
  of wether privs were on or off. ... terrible and not maintainable.

  Therefore I decided to do it 'the right way (tm)' and overworked it
  completely. The only thing that now remains to do, is to check for
  more places where we have to temporary allow/disallow root
  priviledges. I also decided to be a good boy and make 'RUN_AS_ROOT' a
  compile time option and 'run as user' the _d_e_f_a_u_l_t one.

  (promise: I'll also will run dosemu as user before releasing, so that
  I can see, if something goes wrong with it ;-)

  1100..22..  TThhee nneeww ''pprriivv ssttuuffff''

  This works as follows

  +o  All settings have to be done in 'pairs' such as

               enter_priv_on();   /* need to have root access for 'do_something' */
               do_something();
               leave_priv_setting();

  or

               enter_priv_off();  /* need pure user access for 'do_something' */
               do_something();
               leave_priv_setting();

  +o  On enter_priv_XXX() the current state will be saved (pushed) on a
     socalled 'privilege stack' and restored (popped) by
     leave_priv_setting(); Hence, you never again have to worry about
     previous priv settings, and whenever you feel you need to switch
     off or on privs, you can do it without coming into trouble.

  +o  We now have the system calls (getuid, setreuid, etc.) _o_n_l_y in
     src/base/misc/priv.c. We cash the setting and don't do unnecessary
     systemcalls. Hence NEVER call 'getuid', 'setreuid' etc. yourself,
     instead use the above supplied functions. The only places where I
     broke this 'holy law' myself was when printing the log, showing
     both values (the _r_e_a_l and the cached on).

  +o  In case of dosemu was startet out of a root login, we skip _a_l_l
     priv-settings. There is a new variable 'under_root_login' which is
     only set when dosemu is started from a root login.

  +o  On all places were iopl() is called outside a
     enter_priv...leave_priv bracket, the new priv_iopl() function is to
     be used in order to force privileges.

  This is much cleaner and 'automagically' also solves the problem with
  the old 'priv_off/default' sheme. Because, 'running as user' just
  needs to do _one_ priv_off at start of dosemu, if we don't do it we
  are

  A last remark: Though it may be desirable to have a non suid root
  dosemu, this is not possible. Even if we get GGI in the official
  kernel, we can't solve the problems with port access (which we need
  for a lot of DOS apps) This leads to the fact that 'i_am_root' will be
  always '1', makeing it a macro gives GCC a changes optimize away the
  checks for it.  We will leave 'i_am_root' in, maybe there is some day
  in the future that gives us a kernel allowing a ports stuff without
  root privilege,

  1111..  TThhee DDAANNGG ssyysstteemm

  1111..11..  DDeessccrriippttiioonn

  The DANG compiler is a perl script which produces a linuxdoc-sgml
  document from special comments embedded in the DOSEmu source code.
  This document is intended to give an overview of the DOSEmu code for
  the benefit of hackers.

  1111..22..  CChhaannggeess ffrroomm llaasstt ccoommppiilleerr rreelleeaassee

  +o  Recognizes 'maintainer:' information.

  +o

  +o  Corrections to sgml special character protection.

  1111..33..  UUssiinngg DDAANNGG iinn yyoouurr ccooddee

  TTHHEE FFOOLLLLOOWWIINNGG MMAAYY NNOOTT SSOOUUNNDD VVEERRYY NNIICCEE,, BBUUTT IISS IINNTTEENNDDEEDD TTOO KKEEEEPP DDAANNGG AASS
  IITT WWAASS DDEESSIIGGNNEEDD TTOO BBEE -- AA _G_U_I_D_E FFOORR _N_O_V_I_C_E_S..

  DANG is not intended to be a vehicle for copyrights, gratuitous plugs,
  or anything similar. It is intended to guide hackers through the maze
  of DOSEmu source code. The comments should be short and informative. I
  will mercilessly hack out comments which do not conform to this. If
  this damages anything, or annoys anyone, so be it.

  I spent hours correcting the DOSEmu 0.63.1 source code because some
  developers didn't follow the rules. They are very simple, and I'll
  remind you of the below. (I am here to co-ordinate this, not do the
  work. The comments are the responsibility of all of us.)

  1111..44..  DDAANNGG MMaarrkkeerrss

  Some initial comments:

  +o  All the text is passed through a text formatting system. This means
     that text may not be formatted how you want it to be. If you insist
     on having something formatted in a particular way, then it probably
     shouldn't be in DANG. Try a README instead. Embedding sgml tags in
     the comment will probably not work.

  +o  Copyrights and long detailed discussions should not be in DANG. If
     there is a good reason for including a copyright notice, then it
     should be included _O_N_C_E, prefereably in the group summary file (see

  +o  If I say something _m_u_s_t be done in a particular way, then it _M_U_S_T.
     There is no point in doing it differently because the script will
     not work correctly (and changing the script won't help anyone
     else.) In most cases the reason for a particular style is to help
     users who are actually reading the SOURCE file.

  1111..55..  DDAANNGG__BBEEGGIINN__MMOODDUULLEE // DDAANNGG__EENNDD__MMOODDUULLEE

  These should enclose a piece of summary text at the start of a file.
  It should explain the purpose of the file. Anything on the same line
  as DANG_BEGIN_MODULE is ignored. A future version may use the rest of
  this line to provide a user selected name for the module.  There may
  be any number of lines of text.  To include information on the
  maintainer(s) of a module, put 'maintainer:' on a blank line. The
  following lines should contain the maintainers details in form:

       name ..... <user@address>

  There should only be one maintainer on a line. There can be no other
  lines of description before DANG_END_MODULE.

  Example:

       /*
        * DANG_BEGIN_MODULE
        *
        * This is the goobledygook module. It provides BAR services. Currently there
        * are no facilities for mixing a 'FOO' cocktail. The stubs are in 'mix_foo()'.
        *
        * Maintainer:
        *      Alistair MacDonald      <alistair@slitesys.demon.co.uk>
        *      Foo Bar                 <foobar@inter.net.junk>
        *
        * DANG_END_MODULE
        */

  1111..55..11..  DDAANNGG__BBEEGGIINN__FFUUNNCCTTIIOONN // DDAANNGG__EENNDD__FFUUNNCCTTIIOONN

  This is used to describe functions. Ideally this should only be
  complicated or important functions as this avoids cluttering DANG with
  lots of descriptions for trivial functions. Any text on the same line
  as

  There are two optional sub-markers: 'description:' & 'arguments:'
  These can be included at any point, and the default marker is a
  description. The difference is that arguments are converted into a
  bulleted list. For this reason, there should be only one argument (&
  it's description) per line.  I suggest that arguments should be in the
  form 'name - description of name'.

  Example:

       /*
        * DANG_BEGIN_FUNCTION mix_foo
        *
        * This function provides the foo mixing for the module. The 'foo' cocktail
        * is used to wet the throat of busy hackers.
        *
        * arguments:
        *  soft_drink - the type of soft drink to use.
        *  ice_cream - the flavour of ice-cream required
        *
        * description:
        * A number of hackers would prefer something a little stronger.
        *
        * DANG_END_FUNCTION
        */

  1111..55..22..  DDAANNGG__BBEEGGIINN__RREEMMAARRKK // DDAANNGG__EENNDD__RREEMMAARRKK

  This is used to provide in-context comments within the code. They can
  be used to describe some particularly interesting or complex code. It
  should be borne in mind that this will be out of context in DANG, and
  that DANG is intended for Novice DOSEmu hackers too ...

  Example:

       /*
        * DANG_BEGIN_REMARK
        *
        * We select the method of preparation of the cocktail, according to the type
        * of cocktail being prepared. To do this we divide the cocktails up into :
        * VERY_ALCHOHOLIC, MILDLY_ALCHOHOLIC & ALCOHOL_FREE
        *
        * DANG_END_REMARK
        */

  1111..55..33..  DDAANNGG__BBEEGGIINN__NNEEWWIIDDEEAA // DDAANNGG__EENNDD__NNEEWWIIDDEEAA

  This is used to make a note of a new idea which we would like to have
  implemented, or an alternative way of coding something. This can be
  used as a scratch pad until the idea is in a state where someone can
  actually begin coding.

  Example:

  /*
   * DANG_BEGIN_NEWIDEA
   *
   * Rather than hard coding the names of the mixer functions we could try
   * using an array constructed at compile time - Alistair
   *
   * How to we get the list of functions ? - Foo
   *
   * DANG_END_NEWIDEA
   */

  1111..55..44..  DDAANNGG__FFIIXXTTHHIISS

  This is for single line comments on an area which needs fixing. This
  should say where the fix is required. This may become a multi-line
  comment in the future.

  Example:

       /* DANG_FIXTHIS The mix_foo() function should be written to replace the stub */

  1111..55..55..  DDAANNGG__BBEEGGIINN__CCHHAANNGGEELLOOGG // DDAANNGG__EENNDD__CCHHAANNGGEELLOOGG

  This is not currently used. It should be placed around the CHANGES
  section in the code. It was intended to be used along with the DPR.

  * No Example *

  1111..66..  UUssaaggee

  The current version of the configuration file resides in
  './src/doc/DANG'. The program needs to be told where to find this
  using '-c <file>'. On my system I run it in the './src/doc/DANG'
  directory using './DANG_c.pl -c DANG_CONFIG', but its really up to
  you.

  The other options are '-v' for verbose mode and '-i'.  -v isn't really
  useful, but it does tell you what it is doing at all times.  -i is
  'irritating mode' and makes comments in the DANG file about missing
  items, such as no MODULE information, no FUNCTION information, etc.

  If the program is executed with a list of files as parameters then the
  files will be processed, but no sgml output produced. This can be used
  for basic debugging, as it warns you when there are missing BEGIN/END
  markers, etc.

  1111..77..  FFuuttuurree

  I have vaguelly started writing the successor of this program. This
  will be a more general program with a more flexible configuration
  system. Don't hold your breath for an imminent release though. The new
  version will make it easier to change the markers & document
  structure, as well as providing feedback on errors.

  1122..  mmkkffaattiimmaaggee ---- MMaakkee aa FFAATT hhddiimmaaggee pprree--llooaaddeedd wwiitthh ffiilleess

  This section from Pasi Eronen <peronen@vipunen.hut.fi> (1995-08-28)

  To put it brief, mkfatimage creates a hdimage file for dosemu that's
  pre-loaded with the files specified on the command line. It's purpose
  is to remove the need to include a hdimage.dist file in the dosemu
  distribution (and it saves about 100K in the .tar.gz size on the way).

  I haven't done any modifications to the makefiles since they're
  changing all the time anyway, but the idea is to run mkfatimage after
  compiling dosemu to create a hdimage of the programs in the commands
  directory. An additional benefit is that we always get the most recent
  versions (since they were just compiled).

  As always, comments, suggestions, etc. are welcome.

  1133..  mmkkffaattiimmaaggee1166 ---- MMaakkee aa llaarrggee FFAATT hhddiimmaaggee pprree--llooaaddeedd wwiitthh ffiilleess

  I have also attached (gzipped in MIME format) mkfatimage16.c, a
  modified version of mkfatimage which takes an additional switch -t
  number of tracks and automatically switches to the 16-bit FAT format
  if the specified size is > 16MB.  I have deleted the "real" DOS
  partition from my disk, and so I am now running an entirely "virtual"
  DOS system within a big hdimage!

  1144..  DDooccuummeennttiinngg DDOOSSEEmmuu

  This is all about the new style DOSEmu documentation. When I was
  discussing this with Hans he was concerned (as I am) about the fact
  that we are all programmers - and generally programmers are poor at
  documentation. Of course, I'd love you all to prove me (us ?) wrong!

  However, _e_v_e_r_y programmer can handle the few basic linuxdoc-sgml
  commands that are need to make some really good documents! Much of
  linuxdoc-sgml is like HTML, which is hardly surprising as they are
  both SGMLs. The source to this document may make useful reading (This
  is the file './src/doc/README/doc')

  1144..11..  SSeeccttiioonnss

  There are 5 section levels you can use. They are all automatically
  numbered. Your choices are:

     <<sseecctt>>
        A top level section. This is indexed.

     <<sseecctt11>>
        A 1st level section. This is indexed.

     <<sseecctt22>>
        A 2nd level section. This is _n_o_t indexed.

     <<sseecctt33>>
        A 3rd level section. This is _n_o_t indexed.

     <<sseecctt44>>
        A 4th level section. This is _n_o_t indexed.

  +o  You _c_a_n_n_o_t skip section levels on the way down (ie you must go
     <sect>,<sect1>,<sect2> and not <sect>,<sect2>).  On the way back it
     doesn't matter!
  +o  Any text on the same line as the tag will be used to identify the
     section

  +o  You must have a <p> before you start the section text

  1144..22..  EEmmpphhaassiissiinngg tteexxtt

  I think there are lots of ways of doing this, but I've only been using
  2:

     <<eemm>>......<<//eemm>>
        Emphasises text like _t_h_i_s.

     <<bbff>>......<<//bbff>>
        Emboldens text like tthhiiss.

  There is a useful shorthand here. These (and many other tags) can be
  written either as:

  +o  <em>...</em>

  +o  <em/.../

  This second form can be very useful.

  1144..33..  LLiissttss

  Here we have 3 useful types:

     iitteemmiizzee
        A standard bulletted list

     eennuumm
        A numbered list

     ddeessccrriipp
        A description list (like this)

  For the ``itemize'' and ``enum'' lists the items are marked with
  <item>. eg:

       <itemize>
       <item> item 1
       <item> item 2
       </itemize>

  For the ``descrip'' lists the items are marked with either
  <tag>...</tag> or it's short form (<tag/.../). eg:

       <descrip>
       <tag>item 1</tag> is here
       <tag/item 2/ is here!
       </descrip>

  1144..44..  QQuuoottiinngg ssttuuffff

  If you want to quote a small amount use <tt>. eg:

  This is ./src/doc/README/doc

  To quote a large section, such as part of a file or an example use
  <tscreen> and <verb>. eg:

       <tscreen><verb>
       <descrip>
       </descrip>
       </verb></tscreen>

  Note that the order of closing the tags is the reverse of opening! You
  also still need to ``quote'' any < or > characters although most other
  characters should be OK.

  1144..55..  SSppeecciiaall CChhaarraacctteerrss

  Obviously some characters are going to need to be quoted. In general
  these are the same ones as HTML (eg < is written as &lt;) There are 2
  additional exceptions (which had me in trouble until I realised) which
  are [ and ]. These _m_u_s_t be written as &lsqb; and &rsqb;.

  1144..66..  CCrroossss--RReeffeerreenncceess && UURRLLss

  One of the extra feature that this lets us do is include URLs and
  cross-references.

  1144..66..11..  CCrroossss--RReeffeerreenncceess

  These have 2 parts: a label, and a reference.

  The label is <label id="...">

  The reference is <ref id="..." name="...">. The id should refer to a
  lable somewhere else in the document (not necessarily the same file as
  the REAMDE's consist of multiple files) The content of name will be
  used as the link text.

  1144..66..22..  UURRLLss

  This looks slightly horrible, but is very flexible. It looks quite
  similar to the reference above. It is <htmlurl url="..."  name="...">.
  The url will be active _o_n_l_y for HTML. The text in _n_a_m_e will be used at
  all times. This means that it is possible to make things like email
  addresses look good! eg:

       <htmlurl url="mailto:someone@no.where.com" name="&lt;someone@no.where.com&gt;">

  Which will appear as <someone@no.where.com>

  1144..77..  GGoottcchhaass

  +o  You _m_u_s_t do the sect*'s in sequence on the way up

  +o  You _m_u_s_t have a <p> after each sect*

  +o  You _m_u_s_t close your lists

  +o  You _m_u_s_t reverse the order of the tags when closing tscreen/verb
     structures

  +o  You _m_u_s_t replace <, >, [ and ]

  1155..  SSoouunndd CCooddee

  1155..11..  UUnnffoorrttuunnaatteellyy II hhaavveenn''tt ddooccuummeenntteedd tthhiiss yyeett.. HHoowweevveerr,, tthhee ccuurr--
  rreenntt ccooddee hhaass bbeeeenn ccoommpplleetteellyy rreewwrriitttteenn aanndd hhaass bbeeeenn ddeessiiggnneedd ttoo ssuupp--
  ppoorrtt mmuullttiippllee ooppeerraattiinngg ssyysstteemmss aanndd ssoouunndd ssyysstteemmss..  CCuurrrreenntt DDOOSSEEmmuu
  ssoouunndd ccooddee

  1155..22..  OOrriiggiinnaall DDOOSSEEMMUU ssoouunndd ccooddee

           Copyright (C) 1995  Joel N. Weber II

           This sound code is free software; you can redistribute it and/or modify
           it under the terms of the GNU General Public License as published by
           the Free Software Foundation; either version 2 of the License, or
           (at your option) any later version.

           This program 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 General Public License for more details.

  This is a very incomplete sound blaster pro emulator.  I recomend you
  get the PC Game Programmer's Encycolpedia; I give the URL at the end
  of this document.

  The mixer emulator probably doesn't do the math precisely enough (why
  did Hannu use a round base 10 number when all the sound boards I know
  use base 2?)  It ignores obscure registers.  So repeatedly reading and
  writing data will zero the volume.  If you want to fix this, send
  Hannu a message indicating that you want the volume to be out of 255.
  It will probably fix the problem that he advertises with his driver:
  if you read the volume and write it back as is, you'll get zero volume
  in the end.  And on the obscure registers issue, it only pays
  attention to volumes and the dsp stereo bit.  The filters probably
  don't matter much, but the record source will need to be added some
  day.

  The dsp only supports reset and your basic dma playpack.  Recording
  hasn't been implemented, directly reading and writing samples won't
  work too well because it's too timing sensitive, and compression isn't
  supported.

  FM currently has been ignored.  Maybe there's a PCGPE newer than 1.0
  which describes the OPL3.  But I have an OPL3, and it would be nice if
  it emulated that.

  MIDI and joystick functions are ignored.  And I think that DOSEMU is
  supposed to already have good CDROM support, but I don't know how well
  audio CD players will work.

  If you're having performance problems with wavesample playback, read
  /usr/src/linux/drivers/sound/Readme.v30, which describes the fragment
  parameter which you currently can adjust in ../include/sound.h

  I haven't tested this code extensively.  All the software that came
  with my system is for Windows.  (My father claimed that one of
  Compaq's advantages is user friendlyness.  Well, user friendlyness and
  hackerfriendlyness don't exactly go hand in hand.  I also haven't
  found a way to disable bios shadowing or even know if it's
  happening...)  I can't get either of my DOS games to work, either
  (Descent and Sim City 2000).  Can't you guys support the Cirrus?  (Oh,
  and while I'm complaining, those mystery ports that SimEarth needs are
  for the FM synthesiser.  Watch it guys, you might generate interrupts
  with that....)

  Reference:

  PC Game Programers Encyclopedia
  ftp://teeri.oulu.fi/pub/msdos/programming/gpe/

  Joel Weber (age 15)

  July 17, 1995

  1166..  DDMMAA CCooddee

  1166..11..  UUnnffoorrttuunnaatteellyy II hhaavveenn''tt ddooccuummeenntteedd tthhiiss yyeett.. HHoowweevveerr,, tthhee ccuurr--
  rreenntt ccooddee hhaass bbeeeenn ccoommpplleetteellyy rreewwrriitttteenn ffrroomm tthhiiss..  CCuurrrreenntt DDOOSSEEmmuu DDMMAA
  ccooddee

  1166..22..  OOrriiggiinnaall DDOOSSEEMMUU DDMMAA ccooddee

           DOSEMU DMA code
           Copyright (C) 1995  Joel N. Weber II

           This dma code is free software; you can redistribute it and/or modify
           it under the terms of the GNU General Public License as published by
           the Free Software Foundation; either version 2 of the License, or
           (at your option) any later version.

           This program 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 General Public License for more details.

  This is intended to be a reasonably complete implementation of dma.
  However, the following has been omitted:

  +o  There is no command register.  Half the bits control hardware
     details, two bits are related to memory to memory transfer, and two
     bits have misc. functions that might be useful execpt that they are
     global, so probably only the bios messes with them.  And dosemu's
     psuedo-bios certainly doesn't need them.

  +o  16 bit DMA isn't supported, because I'm not quite sure how it's
     supposed to work.  DMA channels 4-7 are treated the same way as 0-3
     execpt that they have different address.  Also, my currnet goal is
     a sb pro emulator, and the sb pro doesn't use 16 bit DMA.  So it's
     really a combination of lack of information and lack of need.

  +o  Verify is not supported.  It doesn't actually move any data, so how
     can it possibly be simulated?

  +o  The mode selection that determines whether to transfer one byte at
     a time or several is ignored because we want to feed the data to
     the kernel efficiently and let it control the speed.

  +o  Cascade mode really isn't supported; however all the channels are
     available so I don't consider it nessisary.

  +o  Autoinitialization may be broken.  From the docs I have, the
     current and reload registers might be written at the same time???
     I can't tell.

  +o  The docs I have refer to a "temporary register".  I can't figure
     out what it is, so guess what: It ain't implemented.  (It's only a
     read register).

  The following is known to be broken.  It should be fixed.  Any
  volunteers? :-)

  +o  dma_ff1 is not used yet

  +o  Address decrement is not supported.  As far as I know, there's no
     simple, effecient flag to pass to the kernel.

  +o  I should have used much more bitwise logic and conditional
     expressions.

  This is my second real C program, and I had a lot of experience in
  Pascal before that.

  1166..22..11..  AAddddiinngg DDMMAA ddeevviicceess ttoo DDOOSSEEMMUU

  Read include/dma.h.  In the dma_ch struct, you'll find some fields
  that don't exist on the real DMA controller itself.  Those are for you
  to fill in.  I trust that they are self-explainatory.

  One trick that you should know: if you know you're writing to a device
  which will fill up and you want the transfer to occur in the
  background, open the file with O_NONBLOCK.

  References:

  PC Game Programers Encyclopedia
  ftp://teeri.oulu.fi/pub/msdos/programming/gpe/

  The Intel Microprocessors: 8086/8088, 80186, 80286, 80386, 80486,
  Barry B. Brey,ISBN 0-02-314250-2,1994,Macmillan

  (The only reason I use this book so extensively is it's the only one
  like it that I can find in the Hawaii State Library System :-)

  1177..  DDOOSSEEmmuu PPrrooggrraammmmaabbllee IInntteerrrruupptt CCoonnttrroolllleerr

  This emulation, in files picu.c and picu.h, emulates all of the useful
  features of the two 8259 programmable interrupt controllers.  Support
  includes these i/o commands:

     IICCWW11    bbiittss 00 aanndd 11
        number of ICWs to expect

     IICCWW22    bbiittss 33 -- 77
        base address of IRQs

     IICCWW33    nnoo bbiittss
        accepted but ignored

     IICCWW44    nnoo bbiittss
        accepted but ignored

     OOCCWW11    aallll bbiittss
        sets interrupt mask

     OOCCWW22    bbiittss 77,,55--00
        EOI commands only

     OOCCWW33    bbiittss 00,,11,,55,,66
        select read register, select special mask mode

  Reads of both PICs ports are supported completely.

  1177..11..  OOtthheerr ffeeaattuurreess

  +o  Support for 16 additional lower priority interrupts.  Interrupts
     are run in a fully nested fashion.  All interrupts call dosemu
     functions, which may then determine if the vm mode interrupt should
     be executed.  The vm mode interrupt is executed via a function
     call.

  +o  Limited support for the non-maskable interrupt.  This is handled
     the same way as the extra low priority interrupts, but has the
     highest priority of all.

  +o  Masking is handled correctly: masking bit 2 of PIC0 also masks all
     IRQs on PIC1.

  +o  An additional mask register is added for use by dosemu itself.
     This register initially has all interrupts masked, and checks that
     a dosemu function has been registered for the interrupt before
     unmasking it.

  +o  Dos IRQ handlers are deemed complete when they notify the PIC via
     OCW2 writes.  The additional lower priority interrupts are deemed
     complete as soon as they are successfully started.

  +o  Interrupts are triggered when the PIC emulator, called in the vm86
     loop, detects a bit set in the interrupt request register.  This
     register is a global variable, so that any dosemu code can easily
     trigger an interrupt.

  1177..22..

  CCaavveeaattss

  OCW2 support is not exactly correct for IRQs 8 - 15.  The correct
  sequence is that an OCW2 to PIC0 enables IRQs 0, 1, 3, 4, 5, 6, and 7;
  and an OCW2 to PIC1 enables IRQs 8-15 (IRQ2 is really IRQ9).  This
  emulation simply enables everything after two OCW2s, regardless of
  which PIC they are sent to.

  OCW2s reset the currently executing interrupt, not the highest
  priority one, although the two should always be the same, unless some
  dos programmer tries special mask mode.  This emulation works
  correctly in special mask mode:  all types of EOIs (specific and non-
  specific) are treated as specific EOIs to the currently executing
  interrupt.  The interrupt specification in a specific EOI is ignored.

  Modes not supported:

  +o  Auto-EOI (see below)

  +o  8080-8085

  +o  Polling

  +o  Rotating Priority

  None of these modes is useable in a PC, anyway.  The 16 additional
  interrupts are run in Auto-EOI mode, since any dos code for them
  shouldn't include OCW2s.  The level 0 (NMI) interrupt is also handled
  this way.

  1177..33..

  NNootteess oonn tthheeoorryy ooff ooppeerraattiioonn::

  The documentation refers to levels.  These are priority levels, the
  lowest (0) having highest priority.  Priority zero is reserved for use
  by NMI.  The levels correspond with IRQ numbers as follows:

         IRQ0=1  IRQ1=2   IRQ8=3  IRQ9=4  IRQ10=5 IRQ11=6 IRQ12=7 IRQ13=8
         IRQ14=9 IRQ15=10 IRQ3=11 IRQ4=12 IRQ5=13 IRQ6=14 IRQ7=15

  There is no IRQ2; it's really IRQ9.

  There are 16 more levels (16 - 31) available for use by dosemu
  functions.

  If all levels were activated, from 31 down to 1 at the right rate, the
  two functions run_irqs() and do_irq() could recurse up to 15 times.
  No other functions would recurse; however a top level interrupt
  handler that served more than one level could get re-entered, but only
  while the first level started was in a call to do_irq().  If all
  levels were activated at once, there would be no recursion.  There
  would also be no recursion if the dos irq code didn't enable
  interrupts early, which is quite common.

  1177..33..11..  FFuunnccttiioonnss ssuuppppoorrtteedd ffrroomm DDOOSSEEmmuu ssiiddee

  1177..33..11..11..  FFuunnccttiioonnss tthhaatt IInntteerrffaaccee wwiitthh DDOOSS::

     uunnssiiggnneedd cchhaarr rreeaadd__ppiiccuu00((ppoorrtt)),,
        unsigned char read_picu1(port)" should be called by the i/o
        handler whenever a read of the PIC i/o ports is requested.  The
        "port" parameter is either a 0 or a 1; for PIC0 these correspond
        to i/o addresses 0x20 and 0x21.  For PIC1 they correspond with
        i/o addresses 0xa0 and 0xa1.  The returned value is the byte
        that was read.

     vvooiidd wwrriittee__ppiiccuu00((ppoorrtt,,uunnssiiggnneedd cchhaarr vvaalluuee)),,
        void write_picu1(port,unsigned char value)" should be called by
        the i/o handler whenever a write to a PIC port is requested.
        Port mapping is the same as for read_picu, above.  The value to
        be written is passed in parameter "value".

     iinntt ddoo__iirrqq(())
        is the function that actually executes a dos interrupt.
        do_irq() looks up the correct interrupt, and if it points to the
        dosemu "bios", does nothing and returns a 1.  It is assumed that
        the calling function will test this value and run the dosemu
        emulation code directly if needed.  If the interrupt is
        revectored to dos or application code, run_int() is called,
        followed by a while loop executing the standard run_vm86() and
        other calls.  The in-service register is checked by the while
        statement, and when the necessary OCW2s have been received, the
        loop exits and a 0 is returned to the caller.  Note that the 16
        interrupts that are not part of the standard AT PIC system will
        not be writing OCW2s; for these interrupts the vm86 loop is
        executed once, and control is returned before the corresponding
        dos code has completed.  If run_int() is called, the flags, cs,
        and ip are pushed onto the stack, and cs:ip is pointed to
        PIC_SEG:PIC_OFF in the bios, where there is a hlt instruction.
        This is handled by pic_iret.

        Since the while loop above checks for interrupts, this function
        can be re-entered.  In the worst case, a total of about 1k of
        process stack space could be needed.

     ppiicc__ssttii(()),,
        pic_cli()" These are really macros that should be called when an
        sti or cli instruction is encountered.  Alternately, these could
        be called as part of run_irqs() before anything else is done,
        based on the condition of the vm86 v_iflag.  Note that pic_cli()
        sets the pic_iflag to a non-zero value, and pic_sti() sets
        pic_iflag to zero.

     ppiicc__iirreett(())
        should be called whenever it is reasonably certain that an iret
        has occurred.  This call need not be done at exactly the right
        time, its only function is to activate any pending interrupts.
        A pending interrupt is one which was self-scheduled.  For
        example, if the IRQ4 code calls pic_request(PIC_IRQ4), the
        request won't have any effect until after pic_iret() is called.
        It is held off until this call in an effort to avoid filling up
        the stack.  If pic_iret() is called too soon, it may aggravate
        stack overflow problems.  If it is called too late, a self-
        scheduled interrupt won't occur quite as soon.  To guarantee
        that pic_iret will be called, do_irq saves the real return
        address on the stack, then pushes the address of a hlt, which
        generates a SIGSEGV.  Because the SIGSEGV comes before the hlt,
        pic_iret can be called by the signal handler, as well as from
        the vm86 loop.  In either case, pic_iret looks for this
        situation, and pops the real flags, cs, and ip.

  1177..33..22..  OOtthheerr FFuunnccttiioonnss

     vvooiidd rruunn__iirrqqss(())
        causes the PIC code to run all requested interrupts, in priority
        order.  The execution of this function is described below.

        First we save the old interrupt level.  Then *or* the interrupt
        mask and the in-service register, and use the complement of that
        to mask off any interrupt requests that are inhibited.  Then we
        enter a loop, looking for any bits still set.  When one is
        found, it's interrupt level is compared with the old level, to
        make sure it is a higher priority.  If special mask mode is set,
        the old level is biased so that this test can't fail.  Once we
        know we want to run this interrupt, the request bit is atomicly
        cleared and double checked (in case something else came along
        and cleared it somehow).  Finally, if the bit was actually
        cleared by this code, the appropriate bit is set in the in-
        service register.  The second pic register (for PIC1) is also
        set if needed.  Then the user code registered for this interrupt
        is called.  Finally, when the user code returns, the in-service
        register(s) are reset, the old interrupt level is restored, and
        control is returned to the caller.  The assembly language
        version of this funcction takes up to about 16 486 clocks if no
        request bits are set, plus 100-150 clocks for each bit that is
        set in the request register.

     vvooiidd ppiiccuu__sseettii((uunnssiiggnneedd iinntt lleevveell,,vvooiidd ((**ffuunncc)),, uunnssiiggnneedd iinntt iivveecc))
        sets the interrupt vector and emulator function to be called
        then the bit of the interrupt request register corresponding to
        level is set.  The interrupt vector is ignored if level<16,
        since those vectors are under the control of dos.  If the
        function is specified as NULL, the mask bit for that level is
        set.

     vvooiidd ppiiccuu__mmaasskkii((iinntt lleevveell))
        sets the emulator mask bit for that level, inhibiting its
        execution.

     vvooiidd ppiiccuu__uunnmmaasskk((iinntt iilleevveell))
        checks if an emulator function is assigned to the given level.
        If so, the mask bit for the level is reset.

     vvooiidd ppiicc__wwaattcchh(())
        runs periodically and checks for 'stuck' interrupt requests.
        These can happen if an irq causes a stack switch and enables
        interrupts before returning.  If an interrupt is stuck this way
        for 2 successive calls to pic_watch, that interrupt is
        activated.

  1177..44..  AA ((vveerryy)) lliittttllee tteecchhnniiccaall iinnffoorrmmaattiioonn ffoorr tthhee ccuurriioouuss

  There are two big differences when using pic.  First, interrupts are
  not queued beyond a depth of 1 for each interrupt.  It is up to the
  interrupt code to detect that further interrupts are required and
  reschedule itself.  Second, interrupt handlers are designated at
  dosemu initialization time.  Triggering them involves merely
  specifying the appropriate irq.

  Since timer interrupts are always spaced apart, the lack of queueing
  has no effect on them.  The keyboard interrupts are re-scheduled if
  there is anything in the scan_queue.

  1188..  DDOOSSEEMMUU ddeebbuuggggeerr vv00..44

  This section written on 7/10/96.  Send comments to Max Parke
  <mhp@light.lightlink.com> and to Hans Lermen <lermen@fgan.de>

  1188..11..  IInnttrroodduuccttiioonn

  This is release v0.4 of the DOSEMU debugger, with the following
  features:

  +o  interactive

  +o  DPMI-support

  +o  display/disassembly/modify of registers and memory (DOS and DPMI)

  +o  display/disassembly memory (dosemu code and data)

  +o  read-only access to DOSEMU kernel via memory dump and disassembly

  +o  uses /usr/src/dosemu/dosemu.map for above

  +o  breakpoints (int3-style, breakpoint on INT xx and DPMI-INT xx)

  +o  DPMI-INT breakpoints can have an AX value for matching.  (e.g.
     'bpintd 31 0203' will stop _before_ DPMI function 0x203)

  +o  symbolic debugging via microsoft linker .MAP file support

  +o  access is via the 'dosdebug' client from another virtual console.
     So, you have a "debug window" and the DOS window/keyboard, etc. are
     undisturbed.    VM86 execution can be started, stopped, etc.

  +o  If dosemu 'hangs' you can use the 'kill' command from dosbugger to
     recover.

  +o  code base is on dosemu-0.63.1.50

  1188..22..  FFiilleess

  All changes are #ifdef'ed with USE_MHPDBG

  1188..22..11..  mmoodduulleess

  +o

  +o

  +o

  +o

  +o

  1188..22..22..  eexxeeccuuttaabbllee

  +o

  1188..33..  IInnssttaallllaattiioonn

  In order to use DOSEMU debugger you must also use EMUMODULE.

  During ./configure be sure you have _N_O_T set --enable-noemumod

  1188..44..  UUssaaggee

  To run, start up DOSEMU.  Then switch to another virtual console (or
  remote login) and do:

         dosdebug

  If there are more then one dosemu process running, you will need to
  pass the pid to dosdebug, e.g:

         dosdebug 2134

  _N_O_T_E_: You must be the owner of the running dosemu to 'debug-login'.

  You should get connected and a banner message.  If you type 'q', only
  the terminal client will terminate, if you type 'kill', both dosemu
  and the terminal client will be terminated.

  1188..55..  CCoommmmaannddss

  See mhpdbgc.c for code and cmd table.

  (all numeric args in hex)

     ??  Print a help page

     qq  Quit the debug session

     kkiillll
        Kill the dosemu process (this may take a while, so be patient)
        See also ``Recovering the display''

     ccoonnssoollee nn
        Switch to console n

     rr  list regs

     rr rreegg vvaall
        change contents of 'reg' to 'val' (e.g: r AX 1234)

     ee AADDDDRR HHEEXXSSTTRR
        modify memory (0-1Mb)

     dd AADDDDRR SSIIZZEE
        dump memory (no limit)

     uu AADDDDRR SSIIZZEE
        unassemble memory (no limit)

     gg  go (if stopped)

     ssttoopp
        stop (if running)

     mmooddee 00||11||++dd||--dd
        set mode (0=SEG16, 1=LIN32) for u and d commands +d enables DPMI
        mode (default on startup), -d disables DPMI mode.

     tt  single step (not fully debugged!!!)

     ttff single step, force over IRET and POPF _N_O_T_E_: the scope of 't'
        'tf' or a 'come back for break' is either 'in DPMI' or realmode,
        depending on wether a DPMI-client is active (in_dpmi).

     rr3322
        dump regs in 32 bit format

     bbpp aaddddrr
        set int3 style breakpoint _N_O_T_E_: the scope is defined wether a
        DPMI-client is active (in_dpmi). The resulting 'come back' will
        force the mode that was when you defined the breakpoint.

     bbcc bbrreeaakkpp..NNoo..
        Clear a breakpoint.

     bbppiinntt xxxx
        set breakpoint on INT xx

     bbcciinntt xxxx
        clr breakpoint on INT xx

     bbppiinnttdd xxxx aaxx
        set breakpoint on DPMI INT xx optionaly matching ax.

     bbcciinnttdd xxxx aaxx
        clear  breakpoint on DPMI INT xx.

     bbppllooaadd
        set one shot breakpoint at entry point of the next loaded DOS-
        program.

     bbll list active breakpoints

     llddtt sseell lliinneess
        dump ldt starting at selector 'sel' for 'lines'

     ((rrmmaappffiillee))
        (internal command to read /usr/src/dosemu/dosemu.map at startup
        time)

     rruusseerrmmaapp oorrgg ffnn
        read microsoft linker format .MAP file "fn" code origin = "org".
        for example if your code is at 1234:0, org would be 12340.

  Addresses may be specified as:

  1. a linear address.  Allows 'd' and 'u' commands to look at both
     DOSEMU kernel and DOS box memory (0-1Mb).

  2. a seg:off address (0-1Mb) seg as well as off can be a symbolic
     registers name (e.g cs:eip) is prefixed by # (e.g. #00af:0000.  You
     may force a seg to treaten as LDT selector by prefixing the '#'.
     Accordingly to the default address mode 'off' under DPMI is 16 or
     32 bit.  When in DPMI mode, and you want to address/display
     realmode stuff, then you must switch off DPMI mode ('mode -d')

  3. a symbolic address.    usermap is searched first, then dosemu map.
     ( not for DPMI programms )

  4. an asterisk(*): CS:IP    (cs:eip)

  5. a dollar sign($): SS:SP  (ss:esp)

  1188..66..  PPeerrffoorrmmaannccee

  If you have dosemu compiled with the debugger support, but the
  debugger is not active and/or the process is not stopped, you will not
  see any great performance penalty.

  1188..77..  WWiisshh LLiisstt

  Main wish is to add support for hardware debug registers (if someone
  would point me in the direction, what syscalls to use, etc.)  Then you
  could breakpoint on memory reads/writes, etc!

  1188..88..  BBUUGGSS

  There must be some.

  1188..88..11..  KKnnoowwnn bbuuggss

  +o  Though you may set breakpoints and do singlestep in Windows31, this
     is a 'one shot': It will bomb _a_f_t_e_r you type 'g' again.  ( I
     suspect this is a timer problem, we _r_e_a_l_l_y should freeze the timer
     and all hardware/mouse IRQs while the program is in 'stop').
     Debugging and singlestepping through DJGPP code doesn't have any
     problems.

  +o  INT3 type breakpoints in DPMI code are _v_e_r_y tricky, because you
     never know when the client has remapped/freed the piece of code
     that is patched with 0xCC ( the one byte INT3 instruction ).  Use
     that with caution !!

  +o  Single stepping doesn't work correctly on call's. May be the trap-
     flag is lost.  However, when in DPMI the problems are minor.

  +o  popf sometime clears the trap-flag, so single stepping results in a
     'go' command.

  +o  When stopped for a long period, the BIOS-timer will be updated to
     fast and may result in stack overflow. We need to also stop the
     timer for dosemu.

  +o  When not stopped, setting break points doesn't work properly.  So,
     as a work around: Only set breakpoints while in stop.

  1199..  MMAARRKK RREEJJHHOONN''SS 1166555500 UUAARRTT EEMMUULLAATTOORR

  The ./src/base/serial directory contains Mark Rejhon's 16550A UART
  emulation code.

  Please send bug reports related to DOSEMU serial to either
  <marky@magmacom.com> or <ag115@freenet.carleton.ca>

  The files in this subdirectory are:

     MMaakkeeffiillee
        The Makefile for this subdir.

     sseerr__iinniitt..cc
        Serial initialization code.

     sseerr__ppoorrttss..cc
        Serial Port I/O emulation code.

     sseerr__iirrqq..cc
        Serial Interrupts emulation code.

     iinntt1144..cc
        BIOS int14 emulation code.

     ffoossssiill..cc
        FOSSIL driver emulation code.

     ....//ccoommmmaannddss//ffoossssiill..SS
        DOS part of FOSSIL emulation.

     sseerr__ddeeffss..hh
        Include file for above files only.

     ....//iinncclluuddee//sseerriiaall..hh
        General include file for all DOSEMU code.

  Redistribution of these files is permitted under the terms of the GNU
  Public License (GPL).  See end of this file for more information.

  1199..11..  PPRROOGGRRAAMMMMIINNGG IINNFFOORRMMAATTIIOONN

  Information on a 16550 is based on information from HELPPC.EXE 2.1 and
  results from National Semiconductor's COMTEST.EXE diagnostics program.
  This code aims to emulate a 16550A as accurately as possible, using
  just reasonably POSIX.2 compliant code.  In some cases, this code does
  a better job than OS/2 serial emulation (in non-direct mode) done by
  its COM.SYS driver!  There may be about 100 kilobytes of source code,
  but nearly 50% of this size are comments!

  This 16550A emulator never even touches the real serial ports, it
  merely traps port writes, and does the I/O via file functions on a
  device in /dev.  Interrupts are also simulated as necessary.

  One of the most important things to know before programming this
  serial code, is to understand how the com[] array works.

  Most of the serial variables are stored in the com[] array.  The com[]
  array is a structure in itself.   Take a look at the for more info
  about this.  Only the most commonly referenced global variables are
  listed here:

     ccoonnffiigg..nnuumm__sseerr
        Number of serial ports active.

     ccoomm[[xx]]..bbaassee__ppoorrtt
        The base port address of emulated serial port.

     ccoomm[[xx]]..rreeaall__ccoommppoorrtt
        The COM port number.

     ccoomm[[xx]]..iinntteerrrruupptt
        The PIC interrupt level (based on IRQ number)

     ccoomm[[xx]]..mmoouussee
        Flag  mouse (to enable extended features)

     ccoomm[[xx]]..ffdd
        File descriptor for port device

     ccoomm[[xx]]..ddeevv[[]]
        Filename of port port device

     ccoomm[[xx]]..ddeevv__lloocckkeedd
        Flag whether device has been locked

  The arbritary example variable 'x' in com[x] can have a minimum value
  of 0 and a maximum value of (config.numser - 1).  There can be no gaps
  for the value 'x', even though gaps between actual COM ports are
  permitted.  It is strongly noted that the 'x' does not equal the COM
  port number.  This example code illustrates the fact, and how the
  com[x] array works:

                 for (i = 0; i < config.numser; i++)
                   s_printf("COM port number %d has a base address of %x",
                            com[i].real_comport, com[i].base_port);

  1199..22..  DDEEBBUUGGGGIINNGG HHEELLPP

  If you require heavy debugging output for serial operations, please
  take a look in ./ser_defs.h for the following defines:

     SSEERR__DDEEBBUUGG__MMAAIINN   ((00 oorr 11))
        extra debug output on the most critical information.

     SSEERR__DDEEBBUUGG__HHEEAAVVYY   ((00 oorr 11))
        super-heavy extra debug output, including all ports reads and
        writes, and every character received and transmitted!

     SSEERR__DDEEBBUUGG__IINNTTEERRRRUUPPTT   ((00 oorr 11))
        additional debug output related to serial interrupt code,
        including flagging serial interrupts, or PIC-driven code.

     SSEERR__DDEEBBUUGG__FFOOSSSSIILL__RRWW   ((00 oorr 11))
        heavy FOSSIL debug output, including all reads and writes.

     SSEERR__DDEEBBUUGG__FFOOSSSSIILL__SSTTAATTUUSS   ((00 oorr 11))
        super-heavy FOSSIL debug output, including all status checks.

  1199..33..  FFOOSSSSIILL EEMMUULLAATTIIOONN

  The FOSSIL emulation requires a memory-resident DOS module,
  FOSSIL.COM. If you don't load it, the code in fossil.c does nothing,
  permitting you to use another FOSSIL driver such as X00 or BNU.

  The emulation isn't as complete as it could be. Some calls aren't
  implemented at all. However, the programs I've tried don't seem to use
  these calls. Check fossil.c if you're interested in details.

  I've done only minimal testing on this code, but at least the
  performance seems to be quite good. Depending on system load, I got
  Zmodem speeds ranging from 1500 to nearly 3800 cps over a 38400 bps
  null-modem cable when sending data to another PC. Zmodem receive,
  however, was only about 2200 cps, since Linux tried to slow down the
  sender with flow control (I'm not sure why).

  1199..44..  CCOOPPYYRRIIGGHHTTSS

  Most of the code in the DOSEMU 'serial' subdirectory is: Copyright (C)
  1995 by Mark D. Rejhon <marky@magmacom.com> with the following
  exceptions:

  FOSSIL driver emulation is Copyright (C) 1995 by Pasi Eronen
  <pasi@forum.nullnet.fi>.

  Lock-file functions were derived from Taylor UUCP: Copyright (C) 1991,
  1992 Ian Lance Taylor Uri Blumenthal <uri@watson.ibm.com> (C) 1994
  Paul Cadach, <paul@paul.east.alma-ata.su> (C) 1994

  UART definitions were derived from /linux/include/linux/serial.h
  Copyright (C) 1992 by Theodore Ts'o.

  All of this serial code is free software; you can redistribute it
  and/or modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation; either version 2 of the
  License, or (at your option) any later version.

  2200..  RReeccoovveerriinngg tthhee ccoonnssoollee aafftteerr aa ccrraasshh

  The below is a mail from Kevin Buhr <buhr@stat.wisc.edu> , that was
  posted on linux-msdos some time ago. Because it describes a way to
  recover from a totally locked console, the technique described below
  was partially intergrated in dosdebug. So, the below 'switchcon.c' is
  now part of dosdebug and you may use it via:

         dosdebug
         console n

  where n is the console you want to switch to.

  But keep in mind, that dosdebug tries to kill your dosemu process the
  safest way it can, so first use dosdebug's kill command:

         dosdebug
         kill

  In the worst case you will get the following output on your remote
  terminal:

          ...oh dear, have to do kill SIGKILL
          dosemu process (pid 1234) is killed
          If you want to switch to an other console,
          then enter a number between 1..8, else just type enter:
          2      <========= this is what you enter
          dosdebug terminated
          NOTE: If you had a totally locked console,
                you may have to blindly type in 'kbd -a; texmode
                on the console you switched to.

  2200..11..  TThhee mmaaiill mmeessssaaggee

  Date: Fri, 21 Apr 95 14:16 CDT
  To: tegla@katalin.csoma.elte.hu
  Cc: linux-msdos@vger.rutgers.edu
  In-Reply-To: <Pine.LNX.3.91.950421163705.1348B-100000@katalin.csoma.elte.hu> (message from Nagy Peter on Fri, 21 Apr 1995 16:51:27 +0200 (MET DST))
  Subject: Restoring text mode (was Re: talk)
  From: buhr@stat.wisc.edu (Kevin Buhr)
  Sender: owner-linux-msdos@vger.rutgers.edu
  Precedence: bulk
  Status: RO
  X-Status:

  | But when dosemu dies in graphics mode ( this happens every 30 minutes
  | or so), it leaves the screen in graphics mode. You can do anything
  | blindly (even start dosemu again) but the console screen is always left
  | in graphics mode.

  I know what you mean... this is a real pain in the ass.

  Here's my solution.  A few useful scripts and programs are supplied
  with the SVGA binaries.  "savetextmode" is a script that will write
  register and font information to "/tmp/textregs" and "/tmp/fontdata".
  Run this from the console as root while you're in text mode.  If
  you've got a cron job that clears out your "/tmp" directory, you'll
  probably want to copy these someplace safe.

  The next time "dosemu" or something similar takes out your video, use
  the "textmode" script (which reads the register and font from those
  temporary files and also restores the palette), and everything should
  be back to normal.  Of course, this assumes you're able to get enough
  control of your computer to enter the "textmode" command as root at
  the console ("restoretextmode" complains if executed from a terminal
  other than the console).  One solution is to modify the source for
  "restoretextmode" to operate correctly from off-console.

  I'm lazy, so I use a little program called "switchcon" (source
  attached) that takes a single integer argument and switches to that
  virtual console.

  So, if "dosemu" dies hard (so that "ctrl-alt-pagedown" doesn't work)
  or exits without restoring text mode, I do this:

          (1)  Log in from another terminal
          (2)  Kill "dosemu", if necessary.  Killing with SIGTERM will
               usually restore text mode automatically, but if I have
               to SIGKILL it, I continue...
          (3)  Run "switchcon" as root to switch to another VC
          (4)  Sometimes I have to run "kbd_mode -a", too, if I'm stuck
               in raw mode

  If Linux fails to automatically restore text mode, I log in (blindly)
  as root on the console and run "textmode".  With the canned register
  and font files in place, this inevitably brings me back to text mode
  bliss.

  Kevin <buhr@stat.wisc.edu>

                          *       *       *

  switchcon.c:

  #include <stdio.h>
  #include <stdlib.h>
  #include <fcntl.h>
  #include <linux/vt.h>
  #include <sys/ioctl.h>

  main( int argc, char **argv ) {
     int newvt;
     int vt;

     if(argc != 2 || !(newvt = atoi(argv[1]))) {
        fprintf(stderr, "syntax: switchcon number\n");
        exit(2);
     }

     vt = open( "/dev/tty1", O_RDONLY );
     if( vt == -1 ) {
        perror("open(/dev/tty1)");
        exit(1);
     }
     if( ioctl( vt, VT_ACTIVATE, newvt ) ) {
        perror("ioctl(VT_ACTIVATE)");
        exit(1);
     }
     if( ioctl( vt, VT_WAITACTIVE, newvt ) ) {
        perror("ioctl(VT_WAITACTIVE)");
        exit(1);
     }

     close(vt);

     return(0);
  }

  2211..  NNeett ccooddee

  +o  Added support for multiple type handling.  So it does type
     demultiplexing within dosemu.

     So we are able to run telbin and pdipx/netx  simultaneously ;-)

  +o  Changed the code for F_DRIVER_INFO. If the handle is '0', it need
     not be valid handle (when input to this function).  At least CUTCP
     simply set this value to zero when it requests for info for the
     first time. The current code wrongly treated it as valid handle,
     and returned the class of first registered type.

  +o  Some things still to be done ...

  +o  Novell Hack is currently disabled.

  +o  Compare class along with type when a new packet arrives.

  +o  Lots of clean ups required. (I have put in lots of pd_printf's.)
     Need to be removed even if debug is not used because function call
     within packet handler is very costly ...

  +o  change all 'dsn0' / 'dosnet' to vnet (i.e. virtual net.) or so.

     and

  +o  Use of SIGIO ...

  +o  Special protocol stack to do demultiplexing of types??

  +o  Use of devices instead of the current mechanism of implementing v-
     net?

  _N_O_T_E_: THERE ARE STILL BUGS.  The dosemu session just hangs. -- Usually
  when in CUTCP. (And specially when I open two sessions.)  What is
  strange is, it seems to work fine for some time even when two sessions
  are opened.  I strongly feel  it is due to new PIC code because it is
  used heavily by the network code ... (especially in interactive telnet
  sessions.)

  Vinod <vinod@cse.iitb.ernet.in>

