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