[NTVDM] Improve the PCH situation.
[reactos.git] / reactos / subsystems / mvdm / ntvdm / io.c
1 /*
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)
8 */
9
10 #include "ntvdm.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE VARIABLES **********************************************************/
16
17 typedef struct _EMULATOR_IO_HANDLERS
18 {
19 EMULATOR_INB_PROC InB;
20 EMULATOR_INW_PROC InW;
21 EMULATOR_IND_PROC InD;
22
23 EMULATOR_INSB_PROC InsB;
24 EMULATOR_INSW_PROC InsW;
25 EMULATOR_INSD_PROC InsD;
26
27 EMULATOR_OUTB_PROC OutB;
28 EMULATOR_OUTW_PROC OutW;
29 EMULATOR_OUTD_PROC OutD;
30
31 EMULATOR_OUTSB_PROC OutsB;
32 EMULATOR_OUTSW_PROC OutsW;
33 EMULATOR_OUTSD_PROC OutsD;
34 } EMULATOR_IO_HANDLERS, *PEMULATOR_IO_HANDLERS;
35
36 typedef struct _EMULATOR_IOPORT_HANDLERS
37 {
38 HANDLE hVdd; // == NULL if unused,
39 // INVALID_HANDLE_VALUE if handled internally,
40 // a valid VDD handle if handled externally.
41 union
42 {
43 /* For Windows compatibility only, not used internally... */
44 VDD_IO_HANDLERS VddIoHandlers;
45
46 /* ... we use these members internally */
47 EMULATOR_IO_HANDLERS IoHandlers;
48 };
49 } EMULATOR_IOPORT_HANDLERS, *PEMULATOR_IOPORT_HANDLERS;
50
51 /*
52 * This is the list of registered I/O Port handlers.
53 */
54 EMULATOR_IOPORT_HANDLERS IoPortProc[EMULATOR_MAX_IOPORTS_NUM] = {{NULL}};
55
56 /* PUBLIC FUNCTIONS ***********************************************************/
57
58 UCHAR
59 IOReadB(USHORT Port)
60 {
61 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
62 IoPortProc[Port].IoHandlers.InB)
63 {
64 return IoPortProc[Port].IoHandlers.InB(Port);
65 }
66 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
67 IoPortProc[Port].VddIoHandlers.inb_handler)
68 {
69 UCHAR Data;
70 ASSERT(Port <= MAXWORD);
71 IoPortProc[Port].VddIoHandlers.inb_handler(Port, &Data);
72 return Data;
73 }
74 else
75 {
76 /* Return an empty port byte value */
77 DPRINT("Read from unknown port: 0x%X\n", Port);
78 return 0xFF;
79 }
80 }
81
82 VOID
83 IOReadStrB(USHORT Port,
84 PUCHAR Buffer,
85 ULONG Count)
86 {
87 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
88 IoPortProc[Port].IoHandlers.InsB)
89 {
90 IoPortProc[Port].IoHandlers.InsB(Port, Buffer, Count);
91 }
92 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
93 IoPortProc[Port].VddIoHandlers.insb_handler)
94 {
95 ASSERT(Port <= MAXWORD);
96 ASSERT(Count <= MAXWORD);
97 IoPortProc[Port].VddIoHandlers.insb_handler(Port, Buffer, (WORD)Count);
98 }
99 else
100 {
101 while (Count--) *Buffer++ = IOReadB(Port);
102 }
103 }
104
105 VOID
106 IOWriteB(USHORT Port,
107 UCHAR Buffer)
108 {
109 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
110 IoPortProc[Port].IoHandlers.OutB)
111 {
112 IoPortProc[Port].IoHandlers.OutB(Port, Buffer);
113 }
114 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
115 IoPortProc[Port].VddIoHandlers.outb_handler)
116 {
117 ASSERT(Port <= MAXWORD);
118 IoPortProc[Port].VddIoHandlers.outb_handler(Port, Buffer);
119 }
120 else
121 {
122 /* Do nothing */
123 DPRINT("Write to unknown port: 0x%X\n", Port);
124 }
125 }
126
127 VOID
128 IOWriteStrB(USHORT Port,
129 PUCHAR Buffer,
130 ULONG Count)
131 {
132 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
133 IoPortProc[Port].IoHandlers.OutsB)
134 {
135 IoPortProc[Port].IoHandlers.OutsB(Port, Buffer, Count);
136 }
137 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
138 IoPortProc[Port].VddIoHandlers.outsb_handler)
139 {
140 ASSERT(Port <= MAXWORD);
141 ASSERT(Count <= MAXWORD);
142 IoPortProc[Port].VddIoHandlers.outsb_handler(Port, Buffer, (WORD)Count);
143 }
144 else
145 {
146 while (Count--) IOWriteB(Port, *Buffer++);
147 }
148 }
149
150 USHORT
151 IOReadW(USHORT Port)
152 {
153 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
154 IoPortProc[Port].IoHandlers.InW)
155 {
156 return IoPortProc[Port].IoHandlers.InW(Port);
157 }
158 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
159 IoPortProc[Port].VddIoHandlers.inw_handler)
160 {
161 USHORT Data;
162 ASSERT(Port <= MAXWORD);
163 IoPortProc[Port].VddIoHandlers.inw_handler(Port, &Data);
164 return Data;
165 }
166 else
167 {
168 UCHAR Low, High;
169
170 // FIXME: Is it ok on Little endian and Big endian ??
171 Low = IOReadB(Port);
172 High = IOReadB(Port + sizeof(UCHAR));
173 return MAKEWORD(Low, High);
174 }
175 }
176
177 VOID
178 IOReadStrW(USHORT Port,
179 PUSHORT Buffer,
180 ULONG Count)
181 {
182 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
183 IoPortProc[Port].IoHandlers.InsW)
184 {
185 IoPortProc[Port].IoHandlers.InsW(Port, Buffer, Count);
186 }
187 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
188 IoPortProc[Port].VddIoHandlers.insw_handler)
189 {
190 ASSERT(Port <= MAXWORD);
191 ASSERT(Count <= MAXWORD);
192 IoPortProc[Port].VddIoHandlers.insw_handler(Port, Buffer, (WORD)Count);
193 }
194 else
195 {
196 while (Count--) *Buffer++ = IOReadW(Port);
197 }
198 }
199
200 VOID
201 IOWriteW(USHORT Port,
202 USHORT Buffer)
203 {
204 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
205 IoPortProc[Port].IoHandlers.OutW)
206 {
207 IoPortProc[Port].IoHandlers.OutW(Port, Buffer);
208 }
209 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
210 IoPortProc[Port].VddIoHandlers.outw_handler)
211 {
212 ASSERT(Port <= MAXWORD);
213 IoPortProc[Port].VddIoHandlers.outw_handler(Port, Buffer);
214 }
215 else
216 {
217 // FIXME: Is it ok on Little endian and Big endian ??
218 IOWriteB(Port, LOBYTE(Buffer));
219 IOWriteB(Port + sizeof(UCHAR), HIBYTE(Buffer));
220 }
221 }
222
223 VOID
224 IOWriteStrW(USHORT Port,
225 PUSHORT Buffer,
226 ULONG Count)
227 {
228 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
229 IoPortProc[Port].IoHandlers.OutsW)
230 {
231 IoPortProc[Port].IoHandlers.OutsW(Port, Buffer, Count);
232 }
233 else if (IoPortProc[Port].hVdd != NULL && IoPortProc[Port].hVdd != INVALID_HANDLE_VALUE &&
234 IoPortProc[Port].VddIoHandlers.outsw_handler)
235 {
236 ASSERT(Port <= MAXWORD);
237 ASSERT(Count <= MAXWORD);
238 IoPortProc[Port].VddIoHandlers.outsw_handler(Port, Buffer, (WORD)Count);
239 }
240 else
241 {
242 while (Count--) IOWriteW(Port, *Buffer++);
243 }
244 }
245
246 ULONG
247 IOReadD(USHORT Port)
248 {
249 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
250 IoPortProc[Port].IoHandlers.InD)
251 {
252 return IoPortProc[Port].IoHandlers.InD(Port);
253 }
254 else
255 {
256 USHORT Low, High;
257
258 // FIXME: Is it ok on Little endian and Big endian ??
259 Low = IOReadW(Port);
260 High = IOReadW(Port + sizeof(USHORT));
261 return MAKELONG(Low, High);
262 }
263 }
264
265 VOID
266 IOReadStrD(USHORT Port,
267 PULONG Buffer,
268 ULONG Count)
269 {
270 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
271 IoPortProc[Port].IoHandlers.InsD)
272 {
273 IoPortProc[Port].IoHandlers.InsD(Port, Buffer, Count);
274 }
275 else
276 {
277 while (Count--) *Buffer++ = IOReadD(Port);
278 }
279 }
280
281 VOID
282 IOWriteD(USHORT Port,
283 ULONG Buffer)
284 {
285 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
286 IoPortProc[Port].IoHandlers.OutD)
287 {
288 IoPortProc[Port].IoHandlers.OutD(Port, Buffer);
289 }
290 else
291 {
292 // FIXME: Is it ok on Little endian and Big endian ??
293 IOWriteW(Port, LOWORD(Buffer));
294 IOWriteW(Port + sizeof(USHORT), HIWORD(Buffer));
295 }
296 }
297
298 VOID
299 IOWriteStrD(USHORT Port,
300 PULONG Buffer,
301 ULONG Count)
302 {
303 if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
304 IoPortProc[Port].IoHandlers.OutsD)
305 {
306 IoPortProc[Port].IoHandlers.OutsD(Port, Buffer, Count);
307 }
308 else
309 {
310 while (Count--) IOWriteD(Port, *Buffer++);
311 }
312 }
313
314
315 VOID RegisterIoPort(USHORT Port,
316 EMULATOR_INB_PROC InHandler,
317 EMULATOR_OUTB_PROC OutHandler)
318 {
319 if (IoPortProc[Port].IoHandlers.InB == NULL)
320 IoPortProc[Port].IoHandlers.InB = InHandler;
321 else
322 DPRINT1("IoPortProc[0x%X].IoHandlers.InB already registered\n", Port);
323
324 if (IoPortProc[Port].IoHandlers.OutB == NULL)
325 IoPortProc[Port].IoHandlers.OutB = OutHandler;
326 else
327 DPRINT1("IoPortProc[0x%X].IoHandlers.OutB already registered\n", Port);
328
329 /* We hold the I/O port internally */
330 IoPortProc[Port].hVdd = INVALID_HANDLE_VALUE;
331 }
332
333 VOID UnregisterIoPort(USHORT Port)
334 {
335 /*
336 * Put automagically all the fields to zero:
337 * the hVdd gets unregistered as well as all the handlers.
338 */
339 // IoPortProc[Port] = {NULL};
340 RtlZeroMemory(&IoPortProc[Port], sizeof(IoPortProc[Port]));
341 }
342
343 VOID FASTCALL
344 EmulatorReadIo(PFAST486_STATE State,
345 USHORT Port,
346 PVOID Buffer,
347 ULONG DataCount,
348 UCHAR DataSize)
349 {
350 UNREFERENCED_PARAMETER(State);
351
352 if (DataSize == 0 || DataCount == 0) return;
353
354 if (DataSize == sizeof(UCHAR))
355 {
356 if (DataCount == 1)
357 *(PUCHAR)Buffer = IOReadB(Port);
358 else
359 IOReadStrB(Port, Buffer, DataCount);
360 }
361 else if (DataSize == sizeof(USHORT))
362 {
363 if (DataCount == 1)
364 *(PUSHORT)Buffer = IOReadW(Port);
365 else
366 IOReadStrW(Port, Buffer, DataCount);
367 }
368 else if (DataSize == sizeof(ULONG))
369 {
370 if (DataCount == 1)
371 *(PULONG)Buffer = IOReadD(Port);
372 else
373 IOReadStrD(Port, Buffer, DataCount);
374 }
375 else
376 {
377 PUCHAR Address = (PUCHAR)Buffer;
378
379 while (DataCount--)
380 {
381 ULONG CurrentPort = Port;
382 ULONG Count;
383 UCHAR NewDataSize = DataSize;
384
385 /* Read dword */
386 Count = NewDataSize >> 2; // NewDataSize / sizeof(ULONG);
387 NewDataSize = NewDataSize & 3; // NewDataSize % sizeof(ULONG);
388 while (Count--)
389 {
390 *(PULONG)Address = IOReadD(CurrentPort);
391 CurrentPort += sizeof(ULONG);
392 Address += sizeof(ULONG);
393 }
394
395 /* Read word */
396 Count = NewDataSize >> 1; // NewDataSize / sizeof(USHORT);
397 NewDataSize = NewDataSize & 1; // NewDataSize % sizeof(USHORT);
398 while (Count--)
399 {
400 *(PUSHORT)Address = IOReadW(CurrentPort);
401 CurrentPort += sizeof(USHORT);
402 Address += sizeof(USHORT);
403 }
404
405 /* Read byte */
406 Count = NewDataSize; // NewDataSize / sizeof(UCHAR);
407 // NewDataSize = NewDataSize % sizeof(UCHAR);
408 while (Count--)
409 {
410 *(PUCHAR)Address = IOReadB(CurrentPort);
411 CurrentPort += sizeof(UCHAR);
412 Address += sizeof(UCHAR);
413 }
414 }
415 }
416 }
417
418 VOID FASTCALL
419 EmulatorWriteIo(PFAST486_STATE State,
420 USHORT Port,
421 PVOID Buffer,
422 ULONG DataCount,
423 UCHAR DataSize)
424 {
425 UNREFERENCED_PARAMETER(State);
426
427 if (DataSize == 0 || DataCount == 0) return;
428
429 if (DataSize == sizeof(UCHAR))
430 {
431 if (DataCount == 1)
432 IOWriteB(Port, *(PUCHAR)Buffer);
433 else
434 IOWriteStrB(Port, Buffer, DataCount);
435 }
436 else if (DataSize == sizeof(USHORT))
437 {
438 if (DataCount == 1)
439 IOWriteW(Port, *(PUSHORT)Buffer);
440 else
441 IOWriteStrW(Port, Buffer, DataCount);
442 }
443 else if (DataSize == sizeof(ULONG))
444 {
445 if (DataCount == 1)
446 IOWriteD(Port, *(PULONG)Buffer);
447 else
448 IOWriteStrD(Port, Buffer, DataCount);
449 }
450 else
451 {
452 PUCHAR Address = (PUCHAR)Buffer;
453
454 while (DataCount--)
455 {
456 ULONG CurrentPort = Port;
457 ULONG Count;
458 UCHAR NewDataSize = DataSize;
459
460 /* Write dword */
461 Count = NewDataSize >> 2; // NewDataSize / sizeof(ULONG);
462 NewDataSize = NewDataSize & 3; // NewDataSize % sizeof(ULONG);
463 while (Count--)
464 {
465 IOWriteD(CurrentPort, *(PULONG)Address);
466 CurrentPort += sizeof(ULONG);
467 Address += sizeof(ULONG);
468 }
469
470 /* Write word */
471 Count = NewDataSize >> 1; // NewDataSize / sizeof(USHORT);
472 NewDataSize = NewDataSize & 1; // NewDataSize % sizeof(USHORT);
473 while (Count--)
474 {
475 IOWriteW(CurrentPort, *(PUSHORT)Address);
476 CurrentPort += sizeof(USHORT);
477 Address += sizeof(USHORT);
478 }
479
480 /* Write byte */
481 Count = NewDataSize; // NewDataSize / sizeof(UCHAR);
482 // NewDataSize = NewDataSize % sizeof(UCHAR);
483 while (Count--)
484 {
485 IOWriteB(CurrentPort, *(PUCHAR)Address);
486 CurrentPort += sizeof(UCHAR);
487 Address += sizeof(UCHAR);
488 }
489 }
490 }
491 }
492
493
494
495 BOOL
496 WINAPI
497 VDDInstallIOHook(IN HANDLE hVdd,
498 IN WORD cPortRange,
499 IN PVDD_IO_PORTRANGE pPortRange,
500 IN PVDD_IO_HANDLERS IoHandlers)
501 {
502 WORD i;
503
504 /* Check validity of the VDD handle */
505 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
506 {
507 SetLastError(ERROR_INVALID_PARAMETER);
508 return FALSE;
509 }
510
511 /* Loop for each range of I/O ports */
512 while (cPortRange--)
513 {
514 /* Register the range of I/O ports */
515 for (i = pPortRange->First; i <= pPortRange->Last; ++i)
516 {
517 /*
518 * Don't do anything if the I/O port is already
519 * handled internally or externally.
520 */
521 if (IoPortProc[i].hVdd != NULL)
522 {
523 DPRINT1("IoPortProc[0x%X] already registered\n", i);
524 continue;
525 }
526
527 /* Register wrt. the VDD */
528 IoPortProc[i].hVdd = hVdd;
529
530 /* Disable the internal handlers */
531 IoPortProc[i].IoHandlers.InB = NULL;
532 IoPortProc[i].IoHandlers.InW = NULL;
533 IoPortProc[i].IoHandlers.InD = NULL;
534
535 IoPortProc[i].IoHandlers.InsB = NULL;
536 IoPortProc[i].IoHandlers.InsW = NULL;
537 IoPortProc[i].IoHandlers.InsD = NULL;
538
539 IoPortProc[i].IoHandlers.OutB = NULL;
540 IoPortProc[i].IoHandlers.OutW = NULL;
541 IoPortProc[i].IoHandlers.OutD = NULL;
542
543 IoPortProc[i].IoHandlers.OutsB = NULL;
544 IoPortProc[i].IoHandlers.OutsW = NULL;
545 IoPortProc[i].IoHandlers.OutsD = NULL;
546
547 /* Save our handlers */
548 IoPortProc[i].VddIoHandlers = *IoHandlers;
549 }
550
551 /* Go to the next range */
552 ++pPortRange;
553 }
554
555 return TRUE;
556 }
557
558 VOID
559 WINAPI
560 VDDDeInstallIOHook(IN HANDLE hVdd,
561 IN WORD cPortRange,
562 IN PVDD_IO_PORTRANGE pPortRange)
563 {
564 WORD i;
565
566 /* Check validity of the VDD handle */
567 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
568 {
569 SetLastError(ERROR_INVALID_PARAMETER);
570 return;
571 }
572
573 /* Loop for each range of I/O ports */
574 while (cPortRange--)
575 {
576 /* Unregister the range of I/O ports */
577 for (i = pPortRange->First; i <= pPortRange->Last; ++i)
578 {
579 /*
580 * Don't do anything if we don't own the I/O port.
581 */
582 if (IoPortProc[i].hVdd != hVdd)
583 {
584 DPRINT1("IoPortProc[0x%X] owned by somebody else\n", i);
585 continue;
586 }
587
588 /*
589 * Put automagically all the fields to zero:
590 * the hVdd gets unregistered as well as all the handlers.
591 */
592 // IoPortProc[i] = {NULL};
593 RtlZeroMemory(&IoPortProc[i], sizeof(IoPortProc[i]));
594 }
595
596 /* Go to the next range */
597 ++pPortRange;
598 }
599 }
600
601 /* EOF */