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