2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/io.c
5 * PURPOSE: I/O Port Handlers
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
15 /* PRIVATE VARIABLES **********************************************************/
17 typedef struct _EMULATOR_IO_HANDLERS
19 EMULATOR_INB_PROC InB
;
20 EMULATOR_INW_PROC InW
;
21 EMULATOR_IND_PROC InD
;
23 EMULATOR_INSB_PROC InsB
;
24 EMULATOR_INSW_PROC InsW
;
25 EMULATOR_INSD_PROC InsD
;
27 EMULATOR_OUTB_PROC OutB
;
28 EMULATOR_OUTW_PROC OutW
;
29 EMULATOR_OUTD_PROC OutD
;
31 EMULATOR_OUTSB_PROC OutsB
;
32 EMULATOR_OUTSW_PROC OutsW
;
33 EMULATOR_OUTSD_PROC OutsD
;
34 } EMULATOR_IO_HANDLERS
, *PEMULATOR_IO_HANDLERS
;
36 typedef struct _EMULATOR_IOPORT_HANDLERS
38 HANDLE hVdd
; // == NULL if unused,
39 // INVALID_HANDLE_VALUE if handled internally,
40 // a valid VDD handle if handled externally.
43 /* For Windows compatibility only, not used internally... */
44 VDD_IO_HANDLERS VddIoHandlers
;
46 /* ... we use these members internally */
47 EMULATOR_IO_HANDLERS IoHandlers
;
49 } EMULATOR_IOPORT_HANDLERS
, *PEMULATOR_IOPORT_HANDLERS
;
52 * This is the list of registered I/O Port handlers.
54 EMULATOR_IOPORT_HANDLERS IoPortProc
[EMULATOR_MAX_IOPORTS_NUM
] = {{NULL
}};
56 /* PUBLIC FUNCTIONS ***********************************************************/
61 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
62 IoPortProc
[Port
].IoHandlers
.InB
)
64 return IoPortProc
[Port
].IoHandlers
.InB(Port
);
66 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
67 IoPortProc
[Port
].VddIoHandlers
.inb_handler
)
70 ASSERT(Port
<= MAXWORD
);
71 IoPortProc
[Port
].VddIoHandlers
.inb_handler(Port
, &Data
);
76 /* Return an empty port byte value */
77 DPRINT("Read from unknown port: 0x%X\n", Port
);
83 IOReadStrB(USHORT Port
,
87 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
88 IoPortProc
[Port
].IoHandlers
.InsB
)
90 IoPortProc
[Port
].IoHandlers
.InsB(Port
, Buffer
, Count
);
92 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
93 IoPortProc
[Port
].VddIoHandlers
.insb_handler
)
95 ASSERT(Port
<= MAXWORD
);
96 ASSERT(Count
<= MAXWORD
);
97 IoPortProc
[Port
].VddIoHandlers
.insb_handler(Port
, Buffer
, (WORD
)Count
);
101 while (Count
--) *Buffer
++ = IOReadB(Port
);
106 IOWriteB(USHORT Port
,
109 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
110 IoPortProc
[Port
].IoHandlers
.OutB
)
112 IoPortProc
[Port
].IoHandlers
.OutB(Port
, Buffer
);
114 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
115 IoPortProc
[Port
].VddIoHandlers
.outb_handler
)
117 ASSERT(Port
<= MAXWORD
);
118 IoPortProc
[Port
].VddIoHandlers
.outb_handler(Port
, Buffer
);
123 DPRINT("Write to unknown port: 0x%X\n", Port
);
128 IOWriteStrB(USHORT Port
,
132 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
133 IoPortProc
[Port
].IoHandlers
.OutsB
)
135 IoPortProc
[Port
].IoHandlers
.OutsB(Port
, Buffer
, Count
);
137 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
138 IoPortProc
[Port
].VddIoHandlers
.outsb_handler
)
140 ASSERT(Port
<= MAXWORD
);
141 ASSERT(Count
<= MAXWORD
);
142 IoPortProc
[Port
].VddIoHandlers
.outsb_handler(Port
, Buffer
, (WORD
)Count
);
146 while (Count
--) IOWriteB(Port
, *Buffer
++);
153 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
154 IoPortProc
[Port
].IoHandlers
.InW
)
156 return IoPortProc
[Port
].IoHandlers
.InW(Port
);
158 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
159 IoPortProc
[Port
].VddIoHandlers
.inw_handler
)
162 ASSERT(Port
<= MAXWORD
);
163 IoPortProc
[Port
].VddIoHandlers
.inw_handler(Port
, &Data
);
170 // FIXME: Is it ok on Little endian and Big endian ??
172 High
= IOReadB(Port
+ sizeof(UCHAR
));
173 return MAKEWORD(Low
, High
);
178 IOReadStrW(USHORT Port
,
182 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
183 IoPortProc
[Port
].IoHandlers
.InsW
)
185 IoPortProc
[Port
].IoHandlers
.InsW(Port
, Buffer
, Count
);
187 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
188 IoPortProc
[Port
].VddIoHandlers
.insw_handler
)
190 ASSERT(Port
<= MAXWORD
);
191 ASSERT(Count
<= MAXWORD
);
192 IoPortProc
[Port
].VddIoHandlers
.insw_handler(Port
, Buffer
, (WORD
)Count
);
196 while (Count
--) *Buffer
++ = IOReadW(Port
);
201 IOWriteW(USHORT Port
,
204 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
205 IoPortProc
[Port
].IoHandlers
.OutW
)
207 IoPortProc
[Port
].IoHandlers
.OutW(Port
, Buffer
);
209 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
210 IoPortProc
[Port
].VddIoHandlers
.outw_handler
)
212 ASSERT(Port
<= MAXWORD
);
213 IoPortProc
[Port
].VddIoHandlers
.outw_handler(Port
, Buffer
);
217 // FIXME: Is it ok on Little endian and Big endian ??
218 IOWriteB(Port
, LOBYTE(Buffer
));
219 IOWriteB(Port
+ sizeof(UCHAR
), HIBYTE(Buffer
));
224 IOWriteStrW(USHORT Port
,
228 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
229 IoPortProc
[Port
].IoHandlers
.OutsW
)
231 IoPortProc
[Port
].IoHandlers
.OutsW(Port
, Buffer
, Count
);
233 else if (IoPortProc
[Port
].hVdd
!= NULL
&& IoPortProc
[Port
].hVdd
!= INVALID_HANDLE_VALUE
&&
234 IoPortProc
[Port
].VddIoHandlers
.outsw_handler
)
236 ASSERT(Port
<= MAXWORD
);
237 ASSERT(Count
<= MAXWORD
);
238 IoPortProc
[Port
].VddIoHandlers
.outsw_handler(Port
, Buffer
, (WORD
)Count
);
242 while (Count
--) IOWriteW(Port
, *Buffer
++);
249 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
250 IoPortProc
[Port
].IoHandlers
.InD
)
252 return IoPortProc
[Port
].IoHandlers
.InD(Port
);
258 // FIXME: Is it ok on Little endian and Big endian ??
260 High
= IOReadW(Port
+ sizeof(USHORT
));
261 return MAKELONG(Low
, High
);
266 IOReadStrD(USHORT Port
,
270 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
271 IoPortProc
[Port
].IoHandlers
.InsD
)
273 IoPortProc
[Port
].IoHandlers
.InsD(Port
, Buffer
, Count
);
277 while (Count
--) *Buffer
++ = IOReadD(Port
);
282 IOWriteD(USHORT Port
,
285 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
286 IoPortProc
[Port
].IoHandlers
.OutD
)
288 IoPortProc
[Port
].IoHandlers
.OutD(Port
, Buffer
);
292 // FIXME: Is it ok on Little endian and Big endian ??
293 IOWriteW(Port
, LOWORD(Buffer
));
294 IOWriteW(Port
+ sizeof(USHORT
), HIWORD(Buffer
));
299 IOWriteStrD(USHORT Port
,
303 if (IoPortProc
[Port
].hVdd
== INVALID_HANDLE_VALUE
&&
304 IoPortProc
[Port
].IoHandlers
.OutsD
)
306 IoPortProc
[Port
].IoHandlers
.OutsD(Port
, Buffer
, Count
);
310 while (Count
--) IOWriteD(Port
, *Buffer
++);
315 VOID
RegisterIoPort(USHORT Port
,
316 EMULATOR_INB_PROC InHandler
,
317 EMULATOR_OUTB_PROC OutHandler
)
319 if (IoPortProc
[Port
].IoHandlers
.InB
== NULL
)
320 IoPortProc
[Port
].IoHandlers
.InB
= InHandler
;
322 DPRINT1("IoPortProc[0x%X].IoHandlers.InB already registered\n", Port
);
324 if (IoPortProc
[Port
].IoHandlers
.OutB
== NULL
)
325 IoPortProc
[Port
].IoHandlers
.OutB
= OutHandler
;
327 DPRINT1("IoPortProc[0x%X].IoHandlers.OutB already registered\n", Port
);
329 /* We hold the I/O port internally */
330 IoPortProc
[Port
].hVdd
= INVALID_HANDLE_VALUE
;
333 VOID
UnregisterIoPort(USHORT Port
)
336 * Put automagically all the fields to zero:
337 * the hVdd gets unregistered as well as all the handlers.
339 // IoPortProc[Port] = {NULL};
340 RtlZeroMemory(&IoPortProc
[Port
], sizeof(IoPortProc
[Port
]));
344 EmulatorReadIo(PFAST486_STATE State
,
350 UNREFERENCED_PARAMETER(State
);
352 if (DataSize
== 0 || DataCount
== 0) return;
354 if (DataSize
== sizeof(UCHAR
))
357 *(PUCHAR
)Buffer
= IOReadB(Port
);
359 IOReadStrB(Port
, Buffer
, DataCount
);
361 else if (DataSize
== sizeof(USHORT
))
364 *(PUSHORT
)Buffer
= IOReadW(Port
);
366 IOReadStrW(Port
, Buffer
, DataCount
);
368 else if (DataSize
== sizeof(ULONG
))
371 *(PULONG
)Buffer
= IOReadD(Port
);
373 IOReadStrD(Port
, Buffer
, DataCount
);
377 PUCHAR Address
= (PUCHAR
)Buffer
;
381 ULONG CurrentPort
= Port
;
383 UCHAR NewDataSize
= DataSize
;
386 Count
= NewDataSize
>> 2; // NewDataSize / sizeof(ULONG);
387 NewDataSize
= NewDataSize
& 3; // NewDataSize % sizeof(ULONG);
390 *(PULONG
)Address
= IOReadD(CurrentPort
);
391 CurrentPort
+= sizeof(ULONG
);
392 Address
+= sizeof(ULONG
);
396 Count
= NewDataSize
>> 1; // NewDataSize / sizeof(USHORT);
397 NewDataSize
= NewDataSize
& 1; // NewDataSize % sizeof(USHORT);
400 *(PUSHORT
)Address
= IOReadW(CurrentPort
);
401 CurrentPort
+= sizeof(USHORT
);
402 Address
+= sizeof(USHORT
);
406 Count
= NewDataSize
; // NewDataSize / sizeof(UCHAR);
407 // NewDataSize = NewDataSize % sizeof(UCHAR);
410 *(PUCHAR
)Address
= IOReadB(CurrentPort
);
411 CurrentPort
+= sizeof(UCHAR
);
412 Address
+= sizeof(UCHAR
);
419 EmulatorWriteIo(PFAST486_STATE State
,
425 UNREFERENCED_PARAMETER(State
);
427 if (DataSize
== 0 || DataCount
== 0) return;
429 if (DataSize
== sizeof(UCHAR
))
432 IOWriteB(Port
, *(PUCHAR
)Buffer
);
434 IOWriteStrB(Port
, Buffer
, DataCount
);
436 else if (DataSize
== sizeof(USHORT
))
439 IOWriteW(Port
, *(PUSHORT
)Buffer
);
441 IOWriteStrW(Port
, Buffer
, DataCount
);
443 else if (DataSize
== sizeof(ULONG
))
446 IOWriteD(Port
, *(PULONG
)Buffer
);
448 IOWriteStrD(Port
, Buffer
, DataCount
);
452 PUCHAR Address
= (PUCHAR
)Buffer
;
456 ULONG CurrentPort
= Port
;
458 UCHAR NewDataSize
= DataSize
;
461 Count
= NewDataSize
>> 2; // NewDataSize / sizeof(ULONG);
462 NewDataSize
= NewDataSize
& 3; // NewDataSize % sizeof(ULONG);
465 IOWriteD(CurrentPort
, *(PULONG
)Address
);
466 CurrentPort
+= sizeof(ULONG
);
467 Address
+= sizeof(ULONG
);
471 Count
= NewDataSize
>> 1; // NewDataSize / sizeof(USHORT);
472 NewDataSize
= NewDataSize
& 1; // NewDataSize % sizeof(USHORT);
475 IOWriteW(CurrentPort
, *(PUSHORT
)Address
);
476 CurrentPort
+= sizeof(USHORT
);
477 Address
+= sizeof(USHORT
);
481 Count
= NewDataSize
; // NewDataSize / sizeof(UCHAR);
482 // NewDataSize = NewDataSize % sizeof(UCHAR);
485 IOWriteB(CurrentPort
, *(PUCHAR
)Address
);
486 CurrentPort
+= sizeof(UCHAR
);
487 Address
+= sizeof(UCHAR
);
497 VDDInstallIOHook(IN HANDLE hVdd
,
499 IN PVDD_IO_PORTRANGE pPortRange
,
500 IN PVDD_IO_HANDLERS IoHandlers
)
504 /* Check validity of the VDD handle */
505 if (hVdd
== NULL
|| hVdd
== INVALID_HANDLE_VALUE
)
507 SetLastError(ERROR_INVALID_PARAMETER
);
511 /* Loop for each range of I/O ports */
514 /* Register the range of I/O ports */
515 for (i
= pPortRange
->First
; i
<= pPortRange
->Last
; ++i
)
518 * Don't do anything if the I/O port is already
519 * handled internally or externally.
521 if (IoPortProc
[i
].hVdd
!= NULL
)
523 DPRINT1("IoPortProc[0x%X] already registered\n", i
);
527 /* Register wrt. the VDD */
528 IoPortProc
[i
].hVdd
= hVdd
;
530 /* Disable the internal handlers */
531 IoPortProc
[i
].IoHandlers
.InB
= NULL
;
532 IoPortProc
[i
].IoHandlers
.InW
= NULL
;
533 IoPortProc
[i
].IoHandlers
.InD
= NULL
;
535 IoPortProc
[i
].IoHandlers
.InsB
= NULL
;
536 IoPortProc
[i
].IoHandlers
.InsW
= NULL
;
537 IoPortProc
[i
].IoHandlers
.InsD
= NULL
;
539 IoPortProc
[i
].IoHandlers
.OutB
= NULL
;
540 IoPortProc
[i
].IoHandlers
.OutW
= NULL
;
541 IoPortProc
[i
].IoHandlers
.OutD
= NULL
;
543 IoPortProc
[i
].IoHandlers
.OutsB
= NULL
;
544 IoPortProc
[i
].IoHandlers
.OutsW
= NULL
;
545 IoPortProc
[i
].IoHandlers
.OutsD
= NULL
;
547 /* Save our handlers */
548 IoPortProc
[i
].VddIoHandlers
= *IoHandlers
;
551 /* Go to the next range */
560 VDDDeInstallIOHook(IN HANDLE hVdd
,
562 IN PVDD_IO_PORTRANGE pPortRange
)
566 /* Check validity of the VDD handle */
567 if (hVdd
== NULL
|| hVdd
== INVALID_HANDLE_VALUE
)
569 SetLastError(ERROR_INVALID_PARAMETER
);
573 /* Loop for each range of I/O ports */
576 /* Unregister the range of I/O ports */
577 for (i
= pPortRange
->First
; i
<= pPortRange
->Last
; ++i
)
580 * Don't do anything if we don't own the I/O port.
582 if (IoPortProc
[i
].hVdd
!= hVdd
)
584 DPRINT1("IoPortProc[0x%X] owned by somebody else\n", i
);
589 * Put automagically all the fields to zero:
590 * the hVdd gets unregistered as well as all the handlers.
592 // IoPortProc[i] = {NULL};
593 RtlZeroMemory(&IoPortProc
[i
], sizeof(IoPortProc
[i
]));
596 /* Go to the next range */