ReactOS 0.4.15-dev-8222-g9164419
ps2.c File Reference
#include "ntvdm.h"
#include <debug.h>
#include "emulator.h"
#include "ps2.h"
#include "memory.h"
#include "io.h"
#include "pic.h"
#include "clock.h"
Include dependency graph for ps2.c:

Go to the source code of this file.

Classes

struct  _PS2_PORT
 

Macros

#define NDEBUG
 
#define BUFFER_SIZE   32
 
#define PS2_PORTS   2
 
#define ControllerConfig   Memory[0]
 

Typedefs

typedef struct _PS2_PORT PS2_PORT
 
typedef struct _PS2_PORTPPS2_PORT
 

Functions

static VOID PS2SendCommand (BYTE PS2Port, BYTE Command)
 
static BYTE WINAPI PS2ReadControl (USHORT Port)
 
static BYTE WINAPI PS2ReadData (USHORT Port)
 
static VOID WINAPI PS2WriteControl (USHORT Port, BYTE Data)
 
static VOID WINAPI PS2WriteData (USHORT Port, BYTE Data)
 
static VOID FASTCALL GeneratePS2Irq (ULONGLONG ElapsedTime)
 
BOOLEAN PS2PortQueueRead (BYTE PS2Port)
 
VOID PS2SetDeviceCmdProc (BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
 
BOOLEAN PS2QueuePush (BYTE PS2Port, BYTE Data)
 
BOOLEAN PS2Initialize (VOID)
 
VOID PS2Cleanup (VOID)
 

Variables

static PS2_PORT Ports [PS2_PORTS]
 
static BYTE Memory [0x20]
 
static BYTE StatusRegister = 0x00
 
static BYTE OutputBuffer = 0x00
 
static BYTE ControllerCommand = 0x00
 
static PHARDWARE_TIMER IrqTimer = NULL
 

Macro Definition Documentation

◆ BUFFER_SIZE

#define BUFFER_SIZE   32

Definition at line 31 of file ps2.c.

◆ ControllerConfig

#define ControllerConfig   Memory[0]

Definition at line 55 of file ps2.c.

◆ NDEBUG

#define NDEBUG

Definition at line 18 of file ps2.c.

◆ PS2_PORTS

#define PS2_PORTS   2

Definition at line 51 of file ps2.c.

Typedef Documentation

◆ PPS2_PORT

◆ PS2_PORT

Function Documentation

◆ GeneratePS2Irq()

static VOID FASTCALL GeneratePS2Irq ( ULONGLONG  ElapsedTime)
static

Definition at line 392 of file ps2.c.

393{
394 UNREFERENCED_PARAMETER(ElapsedTime);
395
396 /*
397 * Pop out fresh new data from the PS/2 port output queues, and only
398 * in case there is data ready, generate an IRQ1 or IRQ12 depending
399 * on whether interrupts are enabled for the given port.
400 *
401 * NOTE: The first PS/2 port (keyboard) has priority over the second one (mouse).
402 */
403 if (PS2PortQueueRead(0))
404 {
406 }
407 else if (PS2PortQueueRead(1))
408 {
410 }
411}
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
BOOLEAN PS2PortQueueRead(BYTE PS2Port)
Definition: ps2.c:415
#define ControllerConfig
Definition: ps2.c:55
#define PS2_CONFIG_AUX_INT
Definition: ps2.h:31
#define PS2_CONFIG_KBD_INT
Definition: ps2.h:30
VOID PicInterruptRequest(BYTE Number)
Definition: pic.c:192

Referenced by PS2Initialize().

◆ PS2Cleanup()

VOID PS2Cleanup ( VOID  )

Definition at line 546 of file ps2.c.

547{
549
550 CloseHandle(Ports[1].QueueMutex);
551 CloseHandle(Ports[0].QueueMutex);
552}
#define CloseHandle
Definition: compat.h:739
static PHARDWARE_TIMER IrqTimer
Definition: ps2.c:63
static PS2_PORT Ports[PS2_PORTS]
Definition: ps2.c:52
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:210

Referenced by EmulatorCleanup().

◆ PS2Initialize()

BOOLEAN PS2Initialize ( VOID  )

Definition at line 520 of file ps2.c.

521{
522 /* Initialize the PS/2 ports */
523 Ports[0].IsEnabled = FALSE;
524 Ports[0].QueueEmpty = TRUE;
525 Ports[0].QueueStart = 0;
526 Ports[0].QueueEnd = 0;
528
529 Ports[1].IsEnabled = FALSE;
530 Ports[1].QueueEmpty = TRUE;
531 Ports[1].QueueStart = 0;
532 Ports[1].QueueEnd = 0;
534
535 /* Register the I/O Ports */
538
540 HZ_TO_NS(100),
542
543 return TRUE;
544}
#define HARDWARE_TIMER_ONESHOT
Definition: clock.h:16
#define HZ_TO_NS(Freq)
Definition: clock.h:20
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static BYTE WINAPI PS2ReadControl(USHORT Port)
Definition: ps2.c:90
static VOID FASTCALL GeneratePS2Irq(ULONGLONG ElapsedTime)
Definition: ps2.c:392
static BYTE WINAPI PS2ReadData(USHORT Port)
Definition: ps2.c:109
static VOID WINAPI PS2WriteControl(USHORT Port, BYTE Data)
Definition: ps2.c:130
static VOID WINAPI PS2WriteData(USHORT Port, BYTE Data)
Definition: ps2.c:278
#define PS2_DATA_PORT
Definition: ps2.h:16
#define PS2_CONTROL_PORT
Definition: ps2.h:17
HANDLE QueueMutex
Definition: ps2.c:41
UINT QueueStart
Definition: ps2.c:39
UINT QueueEnd
Definition: ps2.c:40
BOOLEAN QueueEmpty
Definition: ps2.c:37
BOOLEAN IsEnabled
Definition: ps2.c:35
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONGLONG Delay, PHARDWARE_TIMER_PROC Callback)
Definition: clock.c:144
VOID RegisterIoPort(USHORT Port, EMULATOR_INB_PROC InHandler, EMULATOR_OUTB_PROC OutHandler)
Definition: io.c:320
#define CreateMutex
Definition: winbase.h:3756

Referenced by EmulatorInitialize().

◆ PS2PortQueueRead()

BOOLEAN PS2PortQueueRead ( BYTE  PS2Port)

Definition at line 415 of file ps2.c.

416{
419
420 // NOTE: The first PS/2 port (keyboard) has priority over the second one (mouse).
421
422 Port = &Ports[PS2Port];
423
424 if (!Port->IsEnabled) return FALSE;
425
426 /* Make sure the queue is not empty (fast check) */
427 if (Port->QueueEmpty)
428 {
429 /* Only the keyboard should have its last data latched */
430 // FIXME: Alternatively this can be done in PS2ReadData when
431 // we read PS2_DATA_PORT. What is the best solution??
432 if (PS2Port == 0)
433 {
434 OutputBuffer = Port->Queue[(Port->QueueStart - 1) % BUFFER_SIZE];
435 StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL; // Clear flag: keyboard data
436 }
437
438 return FALSE;
439 }
440
441 WaitForSingleObject(Port->QueueMutex, INFINITE);
442
443 /*
444 * Recheck whether the queue is not empty (it may
445 * have changed after having grabbed the mutex).
446 */
447 if (Port->QueueEmpty) goto Done;
448
449 /* Get the data */
450 OutputBuffer = Port->Queue[Port->QueueStart];
451
452 // StatusRegister &= ~(PS2_STAT_AUX_OUT_BUF_FULL | PS2_STAT_OUT_BUF_FULL);
453
454 /* Always set the "Output buffer full" flag */
456
457 /* Set the "Auxiliary output buffer full" flag according to where the data came from */
458 if (PS2Port == 0)
459 StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL; // Clear flag: keyboard data
460 else // if (PS2Port == 1)
461 StatusRegister |= PS2_STAT_AUX_OUT_BUF_FULL; // Set flag: mouse data
462
463 /* Remove the value from the queue */
464 Port->QueueStart++;
465 Port->QueueStart %= BUFFER_SIZE;
466
467 /* Check if the queue is now empty */
468 if (Port->QueueStart == Port->QueueEnd)
469 Port->QueueEmpty = TRUE;
470
471 Result = TRUE;
472
473Done:
474 ReleaseMutex(Port->QueueMutex);
475 return Result;
476}
unsigned char BOOLEAN
#define INFINITE
Definition: serial.h:102
CPPORT Port[4]
Definition: headless.c:35
#define BUFFER_SIZE
Definition: ps2.c:31
static BYTE StatusRegister
Definition: ps2.c:57
#define PS2_STAT_OUT_BUF_FULL
Definition: ps2.h:20
#define PS2_STAT_AUX_OUT_BUF_FULL
Definition: ps2.h:25
Definition: ps2.c:34
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseMutex(IN HANDLE hMutex)
Definition: synch.c:618
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

Referenced by DisableMouseInt(), DosMouseIrq(), EnableMouseInt(), GeneratePS2Irq(), ReadMouseData(), and SendMouseCommand().

◆ PS2QueuePush()

BOOLEAN PS2QueuePush ( BYTE  PS2Port,
BYTE  Data 
)

Definition at line 486 of file ps2.c.

487{
490
491 ASSERT(PS2Port < PS2_PORTS);
492 Port = &Ports[PS2Port];
493
494 if (!Port->IsEnabled) return FALSE;
495
496 WaitForSingleObject(Port->QueueMutex, INFINITE);
497
498 /* Check if the queue is full */
499 if (!Port->QueueEmpty && (Port->QueueStart == Port->QueueEnd))
500 goto Done;
501
502 /* Insert the value in the queue */
503 Port->Queue[Port->QueueEnd] = Data;
504 Port->QueueEnd++;
505 Port->QueueEnd %= BUFFER_SIZE;
506
507 /* The queue is not empty anymore */
508 Port->QueueEmpty = FALSE;
509
510 /* Schedule the IRQ */
512
513 Result = TRUE;
514
515Done:
516 ReleaseMutex(Port->QueueMutex);
517 return Result;
518}
#define ASSERT(a)
Definition: mode.c:44
#define PS2_PORTS
Definition: ps2.c:51
VOID EnableHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:161

Referenced by KeyboardCommand(), KeyboardEventHandler(), MouseCommand(), MouseDispatchPacket(), and PS2WriteData().

◆ PS2ReadControl()

static BYTE WINAPI PS2ReadControl ( USHORT  Port)
static

Definition at line 90 of file ps2.c.

91{
93
94 /*
95 * Be sure the "Keyboard enable" flag is always set.
96 * On IBM PC-ATs this is the state of the hardware keyboard
97 * lock mechanism. It is not widely used, but some programs
98 * still use it, see for example:
99 * http://www.os2museum.com/wp/the-dos-4-0-shell-mouse-mystery/
100 */
102
103 /* We do not have any timeouts nor parity errors */
105
106 return StatusRegister;
107}
#define PS2_STAT_PARITY_ERROR
Definition: ps2.h:27
#define PS2_STAT_GEN_TIMEOUT
Definition: ps2.h:26
#define PS2_STAT_KBD_ENABLE
Definition: ps2.h:24

Referenced by PS2Initialize().

◆ PS2ReadData()

static BYTE WINAPI PS2ReadData ( USHORT  Port)
static

Definition at line 109 of file ps2.c.

110{
112
113 /*
114 * If there is something to read (response byte from the
115 * controller or data from a PS/2 device), read it.
116 */
117 StatusRegister &= ~PS2_STAT_OUT_BUF_FULL;
118
119 // Keep the state of the "Auxiliary output buffer full" flag
120 // in order to remember from where the data came from.
121 // StatusRegister &= ~PS2_STAT_AUX_OUT_BUF_FULL;
122
123 // FIXME: We may check there whether there is data latched in
124 // PS2 ports 1 or 2 (keyboard or mouse) and retrieve it there...
125
126 /* Always return the available byte stored in the output buffer */
127 return OutputBuffer;
128}
static BYTE OutputBuffer
Definition: ps2.c:59

Referenced by PS2Initialize().

◆ PS2SendCommand()

static VOID PS2SendCommand ( BYTE  PS2Port,
BYTE  Command 
)
static

Definition at line 67 of file ps2.c.

68{
70
71 ASSERT(PS2Port < PS2_PORTS);
72 Port = &Ports[PS2Port];
73
74 /*
75 * According to http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccad
76 * any PS/2 command sent reenables the corresponding port.
77 */
78 if (PS2Port == 0)
79 ControllerConfig &= ~PS2_CONFIG_KBD_DISABLE;
80 else // if (PS2Port == 1)
81 ControllerConfig &= ~PS2_CONFIG_AUX_DISABLE;
82
83 Port->IsEnabled = TRUE;
84
85 /* Call the device command */
86 if (Port->DeviceCommand) Port->DeviceCommand(Port->Param, Command);
87}
Definition: shell.h:41

Referenced by PS2WriteData().

◆ PS2SetDeviceCmdProc()

VOID PS2SetDeviceCmdProc ( BYTE  PS2Port,
LPVOID  Param,
PS2_DEVICE_CMDPROC  DeviceCommand 
)

Definition at line 478 of file ps2.c.

479{
480 ASSERT(PS2Port < PS2_PORTS);
481 Ports[PS2Port].Param = Param;
482 Ports[PS2Port].DeviceCommand = DeviceCommand;
483}
LPVOID Param
Definition: ps2.c:43
PS2_DEVICE_CMDPROC DeviceCommand
Definition: ps2.c:44

Referenced by KeyboardInit(), and MouseInit().

◆ PS2WriteControl()

static VOID WINAPI PS2WriteControl ( USHORT  Port,
BYTE  Data 
)
static

Definition at line 130 of file ps2.c.

131{
133
134 switch (Data)
135 {
136 /* Read configuration byte (byte 0 from internal memory) */
137 case 0x20:
138 /* Read byte N from internal memory */
139 case 0x21: case 0x22: case 0x23:
140 case 0x24: case 0x25: case 0x26: case 0x27:
141 case 0x28: case 0x29: case 0x2A: case 0x2B:
142 case 0x2C: case 0x2D: case 0x2E: case 0x2F:
143 case 0x30: case 0x31: case 0x32: case 0x33:
144 case 0x34: case 0x35: case 0x36: case 0x37:
145 case 0x38: case 0x39: case 0x3A: case 0x3B:
146 case 0x3C: case 0x3D: case 0x3E: case 0x3F:
147 {
148 OutputBuffer = Memory[Data & 0x1F];
150 break;
151 }
152
153 /* Write configuration byte (byte 0 from internal memory) */
154 case 0x60:
155 /* Write to byte N of internal memory */
156 case 0x61: case 0x62: case 0x63:
157 case 0x64: case 0x65: case 0x66: case 0x67:
158 case 0x68: case 0x69: case 0x6A: case 0x6B:
159 case 0x6C: case 0x6D: case 0x6E: case 0x6F:
160 case 0x70: case 0x71: case 0x72: case 0x73:
161 case 0x74: case 0x75: case 0x76: case 0x77:
162 case 0x78: case 0x79: case 0x7A: case 0x7B:
163 case 0x7C: case 0x7D: case 0x7E: case 0x7F:
164
165 /* Write controller output port */
166 case 0xD1:
167 /* Write to the first PS/2 port output buffer */
168 case 0xD2:
169 /* Write to the second PS/2 port output buffer */
170 case 0xD3:
171 /* Write to the second PS/2 port input buffer */
172 case 0xD4:
173 {
174 /* These commands require a response */
177 break;
178 }
179
180 /* Disable second PS/2 port */
181 case 0xA7:
182 {
184 Ports[1].IsEnabled = FALSE;
185 break;
186 }
187
188 /* Enable second PS/2 port */
189 case 0xA8:
190 {
191 ControllerConfig &= ~PS2_CONFIG_AUX_DISABLE;
192 Ports[1].IsEnabled = TRUE;
193 break;
194 }
195
196 /* Test second PS/2 port */
197 case 0xA9:
198 {
199 OutputBuffer = 0x00; // Success code
201 break;
202 }
203
204 /* Test PS/2 controller */
205 case 0xAA:
206 {
207 OutputBuffer = 0x55; // Success code
209 break;
210 }
211
212 /* Test first PS/2 port */
213 case 0xAB:
214 {
215 OutputBuffer = 0x00; // Success code
217 break;
218 }
219
220 /* Disable first PS/2 port */
221 case 0xAD:
222 {
224 Ports[0].IsEnabled = FALSE;
225 break;
226 }
227
228 /* Enable first PS/2 port */
229 case 0xAE:
230 {
231 ControllerConfig &= ~PS2_CONFIG_KBD_DISABLE;
232 Ports[0].IsEnabled = TRUE;
233 break;
234 }
235
236 /* Read controller output port */
237 case 0xD0:
238 {
239 /* Bit 0 always set, and bit 1 is the A20 gate state */
241
242 /* Set IRQ1 state */
245 else
246 OutputBuffer &= ~PS2_OUT_IRQ01;
247
248 /* Set IRQ12 state */
251 else
252 OutputBuffer &= ~PS2_OUT_IRQ12;
253
254 /* Check whether data is already present */
256 {
259 else
261 }
262
264 break;
265 }
266
267 /* CPU Reset */
268 case 0xF0: case 0xF2: case 0xF4: case 0xF6:
269 case 0xF8: case 0xFA: case 0xFC: case 0xFE:
270 {
271 /* Stop the VDM */
273 return;
274 }
275 }
276}
VOID EmulatorTerminate(VOID)
Definition: emulator.c:503
static BYTE ControllerCommand
Definition: ps2.c:61
#define PS2_OUT_AUX_DATA
Definition: ps2.h:41
#define PS2_OUT_KBD_DATA
Definition: ps2.h:46
#define PS2_CONFIG_AUX_DISABLE
Definition: ps2.h:35
#define PS2_CONFIG_KBD_DISABLE
Definition: ps2.h:34
#define PS2_OUT_CPU_NO_RESET
Definition: ps2.h:39
#define PS2_OUT_IRQ01
Definition: ps2.h:43
#define PS2_OUT_IRQ12
Definition: ps2.h:44
#define PS2_STAT_COMMAND
Definition: ps2.h:23
BOOLEAN EmulatorGetA20(VOID)
Definition: memory.c:280
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _In_ _Strict_type_match_ POOL_TYPE _In_opt_ ULONG _In_ _Out_ WDFMEMORY * Memory
Definition: wdfmemory.h:169

Referenced by PS2Initialize().

◆ PS2WriteData()

static VOID WINAPI PS2WriteData ( USHORT  Port,
BYTE  Data 
)
static

Definition at line 278 of file ps2.c.

279{
280 /* Check if the controller is waiting for a response */
282 {
283 StatusRegister &= ~PS2_STAT_COMMAND;
284
285 /* Check which command it was */
286 switch (ControllerCommand)
287 {
288 /* Write configuration byte (byte 0 from internal memory) */
289 case 0x60:
290 {
292
293 /*
294 * Synchronize the enable state of the PS/2 ports
295 * with the flags in the configuration byte.
296 */
299
300 /*
301 * Update the "System enabled" flag of the status register
302 * with bit 2 of the controller configuration byte.
303 * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb2
304 * for more details.
305 */
308 else
309 StatusRegister &= ~PS2_STAT_SYSTEM;
310
311 /*
312 * Update the "Keyboard enable" flag of the status register
313 * with the "Ignore keyboard lock" flag of the controller
314 * configuration byte (if set), then reset the latter one.
315 * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb3
316 * for more details.
317 */
319 {
320 ControllerConfig &= ~PS2_CONFIG_NO_KEYLOCK;
322 }
323
324 break;
325 }
326
327 /* Write to byte N of internal memory */
328 case 0x61: case 0x62: case 0x63:
329 case 0x64: case 0x65: case 0x66: case 0x67:
330 case 0x68: case 0x69: case 0x6A: case 0x6B:
331 case 0x6C: case 0x6D: case 0x6E: case 0x6F:
332 case 0x70: case 0x71: case 0x72: case 0x73:
333 case 0x74: case 0x75: case 0x76: case 0x77:
334 case 0x78: case 0x79: case 0x7A: case 0x7B:
335 case 0x7C: case 0x7D: case 0x7E: case 0x7F:
336 {
337 Memory[ControllerCommand & 0x1F] = Data;
338 break;
339 }
340
341 /* Write controller output */
342 case 0xD1:
343 {
344 /* Check if bit 0 is unset */
345 if (!(Data & PS2_OUT_CPU_NO_RESET))
346 {
347 /* CPU disabled - Stop the VDM */
349 return;
350 }
351
352 /* Update the A20 line setting */
354
355 // FIXME: Should we need to add the status of IRQ1 and IRQ12??
356
357 break;
358 }
359
360 /* Push the data byte into the first PS/2 port queue */
361 case 0xD2:
362 {
363 PS2QueuePush(0, Data);
364 break;
365 }
366
367 /* Push the data byte into the second PS/2 port queue */
368 case 0xD3:
369 {
370 PS2QueuePush(1, Data);
371 break;
372 }
373
374 /*
375 * Send a command to the second PS/2 port (by default
376 * it is a command for the first PS/2 port)
377 */
378 case 0xD4:
379 {
381 break;
382 }
383 }
384
385 return;
386 }
387
388 /* By default, send a command to the first PS/2 port */
390}
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
Definition: ps2.c:486
static VOID PS2SendCommand(BYTE PS2Port, BYTE Command)
Definition: ps2.c:67
#define PS2_OUT_A20_SET
Definition: ps2.h:40
#define PS2_CONFIG_NO_KEYLOCK
Definition: ps2.h:33
#define PS2_STAT_SYSTEM
Definition: ps2.h:22
#define PS2_CONFIG_SYSTEM
Definition: ps2.h:32
VOID EmulatorSetA20(BOOLEAN Enabled)
Definition: memory.c:275

Referenced by PS2Initialize().

Variable Documentation

◆ ControllerCommand

BYTE ControllerCommand = 0x00
static

Definition at line 61 of file ps2.c.

Referenced by PS2WriteControl(), and PS2WriteData().

◆ IrqTimer

PHARDWARE_TIMER IrqTimer = NULL
static

Definition at line 63 of file ps2.c.

Referenced by PS2Cleanup(), PS2Initialize(), and PS2QueuePush().

◆ Memory

BYTE Memory[0x20]
static

Definition at line 54 of file ps2.c.

◆ OutputBuffer

BYTE OutputBuffer = 0x00
static

Definition at line 59 of file ps2.c.

Referenced by PS2ReadData().

◆ Ports

◆ StatusRegister