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