| /* | 
 |  * DOS interrupt 21h handler | 
 |  * | 
 |  * Copyright 1993, 1994 Erik Bos | 
 |  * Copyright 1996 Alexandre Julliard | 
 |  * Copyright 1997 Andreas Mohr | 
 |  * Copyright 1998 Uwe Bonnes | 
 |  * Copyright 1998, 1999 Ove Kaaven | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "ntddk.h" | 
 | #include "wine/winbase16.h" | 
 | #include "dosexe.h" | 
 | #include "miscemu.h" | 
 | #include "msdos.h" | 
 | #include "file.h" | 
 | #include "wine/debug.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(int21); | 
 |  | 
 | void WINAPI DOSVM_Int21Handler_Ioctl( CONTEXT86 *context ) | 
 | { | 
 |   const DOS_DEVICE *dev = DOSFS_GetDeviceByHandle( | 
 |       DosFileHandleToWin32Handle(BX_reg(context)) ); | 
 |  | 
 |   if (dev && !strcasecmp( dev->name, "EMMXXXX0" )) { | 
 |     EMS_Ioctl_Handler(context); | 
 |     return; | 
 |   } | 
 |  | 
 |   switch (AL_reg(context)) | 
 |   { | 
 |   case 0x0b: /* SET SHARING RETRY COUNT */ | 
 |       TRACE("IOCTL - SET SHARING RETRY COUNT pause %d retries %d\n", | 
 |            CX_reg(context), DX_reg(context)); | 
 |       if (!CX_reg(context)) | 
 |       { | 
 |          AX_reg(context) = 1; | 
 |          SET_CFLAG(context); | 
 |          break; | 
 |       } | 
 |       DOSMEM_LOL()->sharing_retry_delay = CX_reg(context); | 
 |       if (!DX_reg(context)) | 
 |          DOSMEM_LOL()->sharing_retry_count = DX_reg(context); | 
 |       RESET_CFLAG(context); | 
 |       break; | 
 |   default: | 
 |       DOS3Call( context ); | 
 |   } | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           DOSVM_Int21Handler | 
 |  * | 
 |  * int 21h real-mode handler. Most calls are passed directly to DOS3Call. | 
 |  */ | 
 | void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) | 
 | { | 
 |     RESET_CFLAG(context);  /* Not sure if this is a good idea */ | 
 |  | 
 |     if(AH_reg(context) == 0x0c) /* FLUSH BUFFER AND READ STANDARD INPUT */ | 
 |     { | 
 |         BYTE al = AL_reg(context); /* Input function to execute after flush. */ | 
 |  | 
 |         /* FIXME: buffers are not flushed */ | 
 |  | 
 |         /* | 
 |          * If AL is not one of 0x01, 0x06, 0x07, 0x08, or 0x0a,  | 
 |          * the buffer is flushed but no input is attempted. | 
 |          */ | 
 |         if(al != 0x01 && al != 0x06 && al != 0x07 && al != 0x08 && al != 0x0a) | 
 |             return; | 
 |        | 
 |         AH_reg(context) = al; | 
 |     } | 
 |  | 
 |     switch(AH_reg(context)) | 
 |     { | 
 |     case 0x00: /* TERMINATE PROGRAM */ | 
 |         TRACE("TERMINATE PROGRAM\n"); | 
 |         MZ_Exit( context, FALSE, 0 ); | 
 |         break; | 
 |  | 
 |     case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */ | 
 |         TRACE("DIRECT CHARACTER INPUT WITH ECHO\n"); | 
 |         DOSVM_Int16ReadChar(&AL_reg(context), NULL, FALSE); | 
 |         DOSVM_PutChar(AL_reg(context)); | 
 | 	break; | 
 |  | 
 |     case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */ | 
 |         TRACE("Write Character to Standard Output\n"); | 
 |         DOSVM_PutChar(DL_reg(context)); | 
 |         break; | 
 |  | 
 |     case 0x06: /* DIRECT CONSOLE IN/OUTPUT */ | 
 |         /* FIXME: Use DOSDEV_Peek/Read/Write(DOSDEV_Console(),...) !! */ | 
 |         if (DL_reg(context) == 0xff) { | 
 |             static char scan = 0; | 
 |             TRACE("Direct Console Input\n"); | 
 |             if (scan) { | 
 |                 /* return pending scancode */ | 
 |                 AL_reg(context) = scan; | 
 |                 RESET_ZFLAG(context); | 
 |                 scan = 0; | 
 |             } else { | 
 |                 char ascii; | 
 |                 if (DOSVM_Int16ReadChar(&ascii,&scan,TRUE)) { | 
 |                     DOSVM_Int16ReadChar(&ascii,&scan,FALSE); | 
 |                     /* return ASCII code */ | 
 |                     AL_reg(context) = ascii; | 
 |                     RESET_ZFLAG(context); | 
 |                     /* return scan code on next call only if ascii==0 */ | 
 |                     if (ascii) scan = 0; | 
 |                 } else { | 
 |                     /* nothing pending, clear everything */ | 
 |                     AL_reg(context) = 0; | 
 |                     SET_ZFLAG(context); | 
 |                     scan = 0; /* just in case */ | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             TRACE("Direct Console Output\n"); | 
 |             DOSVM_PutChar(DL_reg(context)); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x07: /* DIRECT CHARACTER INPUT WITHOUT ECHO */ | 
 |         /* FIXME: Use DOSDEV_Peek/Read(DOSDEV_Console(),...) !! */ | 
 |         TRACE("DIRECT CHARACTER INPUT WITHOUT ECHO\n"); | 
 |         DOSVM_Int16ReadChar(&AL_reg(context), NULL, FALSE); | 
 |         break; | 
 |  | 
 |     case 0x08: /* CHARACTER INPUT WITHOUT ECHO */ | 
 |         /* FIXME: Use DOSDEV_Peek/Read(DOSDEV_Console(),...) !! */ | 
 |         TRACE("CHARACTER INPUT WITHOUT ECHO\n"); | 
 |         DOSVM_Int16ReadChar(&AL_reg(context), NULL, FALSE); | 
 |         break; | 
 |  | 
 |     case 0x0b: /* GET STDIN STATUS */ | 
 |         { | 
 |             BIOSDATA *data = DOSMEM_BiosData(); | 
 |             if(data->FirstKbdCharPtr == data->NextKbdCharPtr) | 
 |                 AL_reg(context) = 0; | 
 |             else | 
 |                 AL_reg(context) = 0xff; | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x25: /* SET INTERRUPT VECTOR */ | 
 |         DOSVM_SetRMHandler( AL_reg(context), | 
 |                             (FARPROC16)MAKESEGPTR( context->SegDs, DX_reg(context))); | 
 |         break; | 
 |  | 
 |     case 0x35: /* GET INTERRUPT VECTOR */ | 
 |         TRACE("GET INTERRUPT VECTOR 0x%02x\n",AL_reg(context)); | 
 |         { | 
 |             FARPROC16 addr = DOSVM_GetRMHandler( AL_reg(context) ); | 
 |             context->SegEs = SELECTOROF(addr); | 
 |             BX_reg(context) = OFFSETOF(addr); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x40: /* WRITE TO FILE OR DEVICE */ | 
 |         /* Writes to stdout are handled here. */ | 
 |         if (BX_reg(context) == 1) { | 
 |           BYTE *ptr = CTX_SEG_OFF_TO_LIN(context, | 
 |                                          context->SegDs, | 
 |                                          context->Edx); | 
 |           int i; | 
 |  | 
 |           for(i=0; i<CX_reg(context); i++) | 
 |             DOSVM_PutChar(ptr[i]); | 
 |         } else | 
 |           DOS3Call( context ); | 
 |         break; | 
 |  | 
 |     case 0x44: /* IOCTL */ | 
 |         DOSVM_Int21Handler_Ioctl( context ); | 
 |         break; | 
 |  | 
 |     case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */ | 
 |         TRACE("EXEC %s\n", (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx )); | 
 |         if (!MZ_Exec( context, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx), | 
 |                       AL_reg(context), CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx) )) | 
 |         { | 
 |             AX_reg(context) = GetLastError(); | 
 |             SET_CFLAG(context); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */ | 
 |         TRACE("EXIT with return code %d\n",AL_reg(context)); | 
 |         MZ_Exit( context, FALSE, AL_reg(context) ); | 
 |         break; | 
 |  | 
 |     case 0x4d: /* GET RETURN CODE */ | 
 |         TRACE("GET RETURN CODE (ERRORLEVEL)\n"); | 
 |         AX_reg(context) = DOSVM_retval; | 
 |         DOSVM_retval = 0; | 
 |         break; | 
 |  | 
 |     case 0x50: /* SET CURRENT PROCESS ID (SET PSP ADDRESS) */ | 
 |         TRACE("SET CURRENT PROCESS ID (SET PSP ADDRESS)\n"); | 
 |         DOSVM_psp = BX_reg(context); | 
 |         break; | 
 |  | 
 |     case 0x51: /* GET PSP ADDRESS */ | 
 |         TRACE("GET CURRENT PROCESS ID (GET PSP ADDRESS)\n"); | 
 |         /* FIXME: should we return the original DOS PSP upon */ | 
 |         /*        Windows startup ? */ | 
 |         BX_reg(context) = DOSVM_psp; | 
 |         break; | 
 |  | 
 |     case 0x52: /* "SYSVARS" - GET LIST OF LISTS */ | 
 |         TRACE("SYSVARS - GET LIST OF LISTS\n"); | 
 |         { | 
 |             context->SegEs = HIWORD(DOS_LOLSeg); | 
 |             BX_reg(context) = FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x62: /* GET PSP ADDRESS */ | 
 |         TRACE("GET CURRENT PSP ADDRESS\n"); | 
 |         /* FIXME: should we return the original DOS PSP upon */ | 
 |         /*        Windows startup ? */ | 
 |         BX_reg(context) = DOSVM_psp; | 
 |         break; | 
 |  | 
 |     default: | 
 |         DOS3Call( context ); | 
 |     } | 
 | } |