1 /*
2  * COPYRIGHT:       GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Virtual DOS Machine
4  * FILE:            subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
5  * PURPOSE:         DOS32 CON Driver
6  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "ntvdm.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #include "emulator.h"
18 
19 #include "dos.h"
20 #include "dos/dem.h"
21 
22 #include "bios/bios.h"
23 
24 /* PRIVATE VARIABLES **********************************************************/
25 
26 PDOS_DEVICE_NODE Con = NULL;
27 BYTE ExtendedCode = 0;
28 
29 /* PRIVATE FUNCTIONS **********************************************************/
30 
31 WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
32 {
33     CHAR Character;
34     WORD BytesRead = 0;
35     PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
36 
37     /* Save AX */
38     USHORT AX = getAX();
39 
40     /*
41      * Use BIOS Get Keystroke function
42      */
43     while (BytesRead < *Length)
44     {
45         if (!ExtendedCode)
46         {
47             /* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
48             setAH(0x00);
49             Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
50 
51             /* Retrieve the character in AL (scan code is in AH) */
52             Character = getAL();
53         }
54         else
55         {
56             /* Return the extended code */
57             Character = ExtendedCode;
58 
59             /* And then clear it */
60             ExtendedCode = 0;
61         }
62 
63         /* Check if this is a special character */
64         if (Character == 0) ExtendedCode = getAH();
65 
66         Pointer[BytesRead++] = Character;
67 
68         /* Stop on first carriage return */
69         if (Character == '\r') break;
70     }
71 
72     *Length = BytesRead;
73 
74     /* Restore AX */
75     setAX(AX);
76     return DOS_DEVSTAT_DONE;
77 }
78 
79 WORD NTAPI ConDrvInputStatus(PDOS_DEVICE_NODE Device)
80 {
81     /* Save AX */
82     USHORT AX = getAX();
83 
84     /* Call the BIOS */
85     setAH(0x01); // or 0x11 for enhanced, but what to choose?
86     Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
87 
88     /* Restore AX */
89     setAX(AX);
90 
91     /* If ZF is set, set the busy bit */
92     if (getZF() && !ExtendedCode) return DOS_DEVSTAT_BUSY;
93     else return DOS_DEVSTAT_DONE;
94 }
95 
96 WORD NTAPI ConDrvWriteOutput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
97 {
98     WORD BytesWritten;
99     PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
100 
101     /* Save AX */
102     USHORT AX = getAX();
103 
104     for (BytesWritten = 0; BytesWritten < *Length; BytesWritten++)
105     {
106         /* Set the character */
107         setAL(Pointer[BytesWritten]);
108 
109         /* Call the BIOS INT 29h "Fast Console Output" function */
110         Int32Call(&DosContext, 0x29);
111     }
112 
113     /* Restore AX */
114     setAX(AX);
115     return DOS_DEVSTAT_DONE;
116 }
117 
118 WORD NTAPI ConDrvOpen(PDOS_DEVICE_NODE Device)
119 {
120     DPRINT("Handle to %Z opened\n", &Device->Name);
121     return DOS_DEVSTAT_DONE;
122 }
123 
124 WORD NTAPI ConDrvClose(PDOS_DEVICE_NODE Device)
125 {
126     DPRINT("Handle to %Z closed\n", &Device->Name);
127     return DOS_DEVSTAT_DONE;
128 }
129 
130 /* PUBLIC FUNCTIONS ***********************************************************/
131 
132 VOID ConDrvInitialize(VOID)
133 {
134     Con = DosCreateDevice(DOS_DEVATTR_STDIN
135                           | DOS_DEVATTR_STDOUT
136                           | DOS_DEVATTR_CON
137                           | DOS_DEVATTR_CHARACTER,
138                           "CON");
139 
140     Con->ReadRoutine        = ConDrvReadInput;
141     Con->InputStatusRoutine = ConDrvInputStatus;
142     Con->WriteRoutine       = ConDrvWriteOutput;
143     Con->OpenRoutine        = ConDrvOpen;
144     Con->CloseRoutine       = ConDrvClose;
145 }
146 
147 VOID ConDrvCleanup(VOID)
148 {
149     if (Con) DosDeleteDevice(Con);
150 }
151