Added support for DOS EMS memory.
[wine] / dlls / winedos / int21.c
1 /*
2  * DOS interrupt 21h handler
3  */
4
5 #include "config.h"
6
7 #include "windef.h"
8 #include "winbase.h"
9 #include "ntddk.h"
10 #include "wine/winbase16.h"
11 #include "dosexe.h"
12 #include "miscemu.h"
13 #include "msdos.h"
14 #include "console.h"
15 #include "file.h"
16 #include "debugtools.h"
17
18 DEFAULT_DEBUG_CHANNEL(int21);
19
20 void WINAPI DOSVM_Int21Handler_Ioctl( CONTEXT86 *context )
21 {
22   const DOS_DEVICE *dev = DOSFS_GetDeviceByHandle(
23       DosFileHandleToWin32Handle(BX_reg(context)) );
24
25   if (dev && !strcasecmp( dev->name, "EMMXXXX0" )) {
26     EMS_Ioctl_Handler(context);
27     return;
28   }
29
30   switch (AL_reg(context))
31   {
32   case 0x0b: /* SET SHARING RETRY COUNT */
33       TRACE("IOCTL - SET SHARING RETRY COUNT pause %d retries %d\n",
34            CX_reg(context), DX_reg(context));
35       if (!CX_reg(context))
36       {
37          AX_reg(context) = 1;
38          SET_CFLAG(context);
39          break;
40       }
41       DOSMEM_LOL()->sharing_retry_delay = CX_reg(context);
42       if (!DX_reg(context))
43          DOSMEM_LOL()->sharing_retry_count = DX_reg(context);
44       RESET_CFLAG(context);
45       break;
46   default:
47       DOS3Call( context );
48   }
49 }
50
51 /***********************************************************************
52  *           DOSVM_Int21Handler
53  *
54  * int 21h real-mode handler. Most calls are passed directly to DOS3Call.
55  */
56 void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
57 {
58     RESET_CFLAG(context);  /* Not sure if this is a good idea */
59
60     switch(AH_reg(context))
61     {
62     case 0x00: /* TERMINATE PROGRAM */
63         TRACE("TERMINATE PROGRAM\n");
64         MZ_Exit( context, FALSE, 0 );
65         break;
66
67     case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
68         TRACE("DIRECT CHARACTER INPUT WITH ECHO\n");
69         AL_reg(context) = CONSOLE_GetCharacter();
70         /* FIXME: no echo */
71         break;
72
73     case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
74         TRACE("Write Character to Standard Output\n");
75         CONSOLE_Write(DL_reg(context), 0, 0, 0);
76         break;
77
78     case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
79         /* FIXME: Use DOSDEV_Peek/Read/Write(DOSDEV_Console(),...) !! */
80         if (DL_reg(context) == 0xff) {
81             static char scan = 0;
82             TRACE("Direct Console Input\n");
83             if (scan) {
84                 /* return pending scancode */
85                 AL_reg(context) = scan;
86                 RESET_ZFLAG(context);
87                 scan = 0;
88             } else {
89                 char ascii;
90                 if (DOSVM_Int16ReadChar(&ascii,&scan,TRUE)) {
91                     DOSVM_Int16ReadChar(&ascii,&scan,FALSE);
92                     /* return ASCII code */
93                     AL_reg(context) = ascii;
94                     RESET_ZFLAG(context);
95                     /* return scan code on next call only if ascii==0 */
96                     if (ascii) scan = 0;
97                 } else {
98                     /* nothing pending, clear everything */
99                     AL_reg(context) = 0;
100                     SET_ZFLAG(context);
101                     scan = 0; /* just in case */
102                 }
103             }
104         } else {
105             TRACE("Direct Console Output\n");
106             CONSOLE_Write(DL_reg(context), 0, 0, 0);
107         }
108         break;
109
110     case 0x07: /* DIRECT CHARACTER INPUT WITHOUT ECHO */
111         /* FIXME: Use DOSDEV_Peek/Read(DOSDEV_Console(),...) !! */
112         TRACE("DIRECT CHARACTER INPUT WITHOUT ECHO\n");
113         DOSVM_Int16ReadChar(&AL_reg(context), NULL, FALSE);
114         break;
115
116     case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
117         /* FIXME: Use DOSDEV_Peek/Read(DOSDEV_Console(),...) !! */
118         TRACE("CHARACTER INPUT WITHOUT ECHO\n");
119         DOSVM_Int16ReadChar(&AL_reg(context), NULL, FALSE);
120         break;
121
122     case 0x0b: /* GET STDIN STATUS */
123         {
124             char x1,x2;
125
126             if (CONSOLE_CheckForKeystroke(&x1,&x2))
127                 AL_reg(context) = 0xff;
128             else
129                 AL_reg(context) = 0;
130         }
131         break;
132
133     case 0x25: /* SET INTERRUPT VECTOR */
134         DOSVM_SetRMHandler( AL_reg(context),
135                             (FARPROC16)MAKESEGPTR( context->SegDs, DX_reg(context)));
136         break;
137
138     case 0x35: /* GET INTERRUPT VECTOR */
139         TRACE("GET INTERRUPT VECTOR 0x%02x\n",AL_reg(context));
140         {
141             FARPROC16 addr = DOSVM_GetRMHandler( AL_reg(context) );
142             context->SegEs = SELECTOROF(addr);
143             BX_reg(context) = OFFSETOF(addr);
144         }
145         break;
146
147     case 0x44: /* IOCTL */
148         DOSVM_Int21Handler_Ioctl( context );
149         break;
150
151     case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
152         TRACE("EXEC %s\n", (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx ));
153         if (!MZ_Exec( context, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx),
154                       AL_reg(context), CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx) ))
155         {
156             AX_reg(context) = GetLastError();
157             SET_CFLAG(context);
158         }
159         break;
160
161     case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
162         TRACE("EXIT with return code %d\n",AL_reg(context));
163         MZ_Exit( context, FALSE, AL_reg(context) );
164         break;
165
166     case 0x4d: /* GET RETURN CODE */
167         TRACE("GET RETURN CODE (ERRORLEVEL)\n");
168         AX_reg(context) = DOSVM_retval;
169         DOSVM_retval = 0;
170         break;
171
172     case 0x50: /* SET CURRENT PROCESS ID (SET PSP ADDRESS) */
173         TRACE("SET CURRENT PROCESS ID (SET PSP ADDRESS)\n");
174         DOSVM_psp = BX_reg(context);
175         break;
176
177     case 0x51: /* GET PSP ADDRESS */
178         TRACE("GET CURRENT PROCESS ID (GET PSP ADDRESS)\n");
179         /* FIXME: should we return the original DOS PSP upon */
180         /*        Windows startup ? */
181         BX_reg(context) = DOSVM_psp;
182         break;
183
184     case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
185         TRACE("SYSVARS - GET LIST OF LISTS\n");
186         {
187             context->SegEs = HIWORD(DOS_LOLSeg);
188             BX_reg(context) = FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB);
189         }
190         break;
191
192     case 0x62: /* GET PSP ADDRESS */
193         TRACE("GET CURRENT PSP ADDRESS\n");
194         /* FIXME: should we return the original DOS PSP upon */
195         /*        Windows startup ? */
196         BX_reg(context) = DOSVM_psp;
197         break;
198
199     default:
200         DOS3Call( context );
201     }
202 }