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