msi: Add the ability to query a specific context for a patch.
[wine] / dlls / winedos / ioports.c
1 /*
2  * Emulation of processor ioports.
3  *
4  * Copyright 1995 Morten Welinder
5  * Copyright 1998 Andreas Mohr, Ove Kaaven
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 /* Known problems:
23    - only a few ports are emulated.
24    - real-time clock in "cmos" is bogus.  A nifty alarm() setup could
25      fix that, I guess.
26 */
27
28 #include "config.h"
29
30 #include <stdarg.h>
31 #include <stdlib.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "winternl.h"
38 #include "dosexe.h"
39 #include "vga.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(int);
44
45 #if defined(linux) && defined(__i386__)
46 # define DIRECT_IO_ACCESS
47 #else
48 # undef DIRECT_IO_ACCESS
49 #endif  /* linux && __i386__ */
50
51 static struct {
52     WORD        countmax;
53     BOOL16      byte_toggle; /* if TRUE, then hi byte has already been written */
54     WORD        latch;
55     BOOL16      latched;
56     BYTE        ctrlbyte_ch;
57     WORD        oldval;
58 } tmr_8253[3] = {
59     {0xFFFF,    FALSE,  0,      FALSE,  0x36,   0},
60     {0x0012,    FALSE,  0,      FALSE,  0x74,   0},
61     {0x0001,    FALSE,  0,      FALSE,  0xB6,   0},
62 };
63
64 static int dummy_ctr = 0;
65
66 static BYTE parport_8255[4] = {0x4f, 0x20, 0xff, 0xff};
67
68 static BYTE cmosaddress;
69
70 /* if you change anything here, use IO_FixCMOSCheckSum below to compute
71  * the checksum and put the right values in.
72  */
73 static BYTE cmosimage[64] =
74 {
75   0x27, 0x34, 0x31, 0x47, 0x16, 0x15, 0x00, 0x01,
76   0x04, 0x94, 0x26, 0x02, 0x50, 0x80, 0x00, 0x00,
77   0x40, 0xb1, 0x00, 0x9c, 0x01, 0x80, 0x02, 0x00,
78   0x1c, 0x00, 0x00, 0xad, 0x02, 0x10, 0x00, 0x00,
79   0x08, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
80   0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x19,  /* last 2 bytes are checksum */
81   0x00, 0x1c, 0x19, 0x81, 0x00, 0x0e, 0x00, 0x80,
82   0x1b, 0x7b, 0x21, 0x00, 0x00, 0x00, 0x05, 0x5f
83 };
84
85 #if 0
86 static void IO_FixCMOSCheckSum(void)
87 {
88         WORD sum = 0;
89         int i;
90
91         for (i=0x10; i < 0x2d; i++)
92                 sum += cmosimage[i];
93         cmosimage[0x2e] = sum >> 8; /* yes, this IS hi byte !! */
94         cmosimage[0x2f] = sum & 0xff;
95         MESSAGE("calculated hi %02x, lo %02x\n", cmosimage[0x2e], cmosimage[0x2f]);
96 }
97 #endif
98
99 #ifdef DIRECT_IO_ACCESS
100
101 extern int iopl(int level);
102 static char do_direct_port_access = -1;
103 static char port_permissions[0x10000];
104
105 #define IO_READ  1
106 #define IO_WRITE 2
107
108 #endif  /* DIRECT_IO_ACCESS */
109
110 #ifdef HAVE_PPDEV
111 static int do_pp_port_access = -1; /* -1: uninitialized, 1: not available
112                                        0: available);*/
113 #endif
114
115 static void set_timer_maxval(unsigned timer, unsigned maxval)
116 {
117     switch (timer) {
118         case 0: /* System timer counter divisor */
119             DOSVM_SetTimer(maxval);
120             break;
121         case 1: /* RAM refresh */
122             FIXME("RAM refresh counter handling not implemented !\n");
123             break;
124         case 2: /* cassette & speaker */
125             /* speaker on ? */
126             if ((parport_8255[1] & 3) == 3)
127             {
128                 TRACE("Beep (freq: %d) !\n", 1193180 / maxval );
129                 Beep(1193180 / maxval, 20);
130             }
131             break;
132     }
133 }
134
135
136 /**********************************************************************
137  *          IO_port_init
138  */
139
140 /* set_IO_permissions(int val1, int val)
141  * Helper function for IO_port_init
142  */
143 #ifdef DIRECT_IO_ACCESS
144 static void set_IO_permissions(int val1, int val, char rw)
145 {
146         int j;
147         if (val1 != -1) {
148                 if (val == -1) val = 0x3ff;
149                 for (j = val1; j <= val; j++)
150                         port_permissions[j] |= rw;
151
152                 do_direct_port_access = 1;
153
154                 val1 = -1;
155         } else if (val != -1) {
156                 do_direct_port_access = 1;
157
158                 port_permissions[val] |= rw;
159         }
160
161 }
162
163 /* do_IO_port_init_read_or_write(char* temp, char rw)
164  * Helper function for IO_port_init
165  */
166
167 static void do_IO_port_init_read_or_write(const WCHAR *str, char rw)
168 {
169     int val, val1;
170     unsigned int i;
171     WCHAR *end;
172     static const WCHAR allW[] = {'a','l','l',0};
173
174     if (!strcmpiW(str, allW))
175     {
176         for (i=0; i < sizeof(port_permissions); i++)
177             port_permissions[i] |= rw;
178     }
179     else
180     {
181         val = -1;
182         val1 = -1;
183         while (*str)
184         {
185             switch(*str)
186             {
187             case ',':
188             case ' ':
189             case '\t':
190                 set_IO_permissions(val1, val, rw);
191                 val1 = -1;
192                 val = -1;
193                 str++;
194                 break;
195             case '-':
196                 val1 = val;
197                 if (val1 == -1) val1 = 0;
198                 str++;
199                 break;
200             default:
201                 if (isdigitW(*str))
202                 {
203                     val = strtoulW( str, &end, 0 );
204                     if (end == str)
205                     {
206                         val = -1;
207                         str++;
208                     }
209                     else str = end;
210                 }
211                 break;
212             }
213         }
214         set_IO_permissions(val1, val, rw);
215     }
216 }
217
218 static inline BYTE inb( WORD port )
219 {
220     BYTE b;
221     __asm__ __volatile__( "inb %w1,%0" : "=a" (b) : "d" (port) );
222     return b;
223 }
224
225 static inline WORD inw( WORD port )
226 {
227     WORD w;
228     __asm__ __volatile__( "inw %w1,%0" : "=a" (w) : "d" (port) );
229     return w;
230 }
231
232 static inline DWORD inl( WORD port )
233 {
234     DWORD dw;
235     __asm__ __volatile__( "inl %w1,%0" : "=a" (dw) : "d" (port) );
236     return dw;
237 }
238
239 static inline void outb( BYTE value, WORD port )
240 {
241     __asm__ __volatile__( "outb %b0,%w1" : : "a" (value), "d" (port) );
242 }
243
244 static inline void outw( WORD value, WORD port )
245 {
246     __asm__ __volatile__( "outw %w0,%w1" : : "a" (value), "d" (port) );
247 }
248
249 static inline void outl( DWORD value, WORD port )
250 {
251     __asm__ __volatile__( "outl %0,%w1" : : "a" (value), "d" (port) );
252 }
253
254 static void IO_port_init(void)
255 {
256     char tmp[1024];
257     HANDLE root, hkey;
258     DWORD dummy;
259     OBJECT_ATTRIBUTES attr;
260     UNICODE_STRING nameW;
261
262     static const WCHAR portsW[] = {'S','o','f','t','w','a','r','e','\\',
263                                    'W','i','n','e','\\','V','D','M','\\','P','o','r','t','s',0};
264     static const WCHAR readW[] = {'r','e','a','d',0};
265     static const WCHAR writeW[] = {'w','r','i','t','e',0};
266
267     do_direct_port_access = 0;
268     /* Can we do that? */
269     if (!iopl(3))
270     {
271         iopl(0);
272
273         RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
274         attr.Length = sizeof(attr);
275         attr.RootDirectory = root;
276         attr.ObjectName = &nameW;
277         attr.Attributes = 0;
278         attr.SecurityDescriptor = NULL;
279         attr.SecurityQualityOfService = NULL;
280         RtlInitUnicodeString( &nameW, portsW );
281
282         /* @@ Wine registry key: HKCU\Software\Wine\VDM\Ports */
283         if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
284         {
285             RtlInitUnicodeString( &nameW, readW );
286             if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
287             {
288                 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
289                 do_IO_port_init_read_or_write(str, IO_READ);
290             }
291             RtlInitUnicodeString( &nameW, writeW );
292             if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
293             {
294                 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
295                 do_IO_port_init_read_or_write(str, IO_WRITE);
296             }
297             NtClose( hkey );
298         }
299         NtClose( root );
300     }
301 }
302
303 #endif  /* DIRECT_IO_ACCESS */
304
305
306 /**********************************************************************
307  *          inport   (WINEDOS.@)
308  *
309  * Note: The size argument has to be handled correctly _externally_
310  * (as we always return a DWORD)
311  */
312 DWORD WINAPI DOSVM_inport( int port, int size )
313 {
314     DWORD res = ~0U;
315
316     TRACE("%d-byte value from port 0x%04x\n", size, port );
317
318 #ifdef HAVE_PPDEV
319     if (do_pp_port_access == -1) do_pp_port_access =IO_pp_init();
320     if ((do_pp_port_access == 0 ) && (size == 1))
321     {
322         if (!IO_pp_inp(port,&res)) return res;
323     }
324 #endif
325
326 #ifdef DIRECT_IO_ACCESS
327     if (do_direct_port_access == -1) IO_port_init();
328     if ((do_direct_port_access)
329         /* Make sure we have access to the port */
330         && (port_permissions[port] & IO_READ))
331     {
332         iopl(3);
333         switch(size)
334         {
335         case 1: res = inb( port ); break;
336         case 2: res = inw( port ); break;
337         case 4: res = inl( port ); break;
338         }
339         iopl(0);
340         return res;
341     }
342 #endif
343
344     switch (port)
345     {
346     case 0x40:
347     case 0x41:
348     case 0x42:
349         {
350             BYTE chan = port & 3;
351             WORD tempval = 0;
352             if (tmr_8253[chan].latched)
353                 tempval = tmr_8253[chan].latch;
354             else
355             {
356                 dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
357                 if (chan == 0) /* System timer counter divisor */
358                 {
359                     /* FIXME: DOSVM_GetTimer() returns quite rigid values */
360                     tempval = dummy_ctr + (WORD)DOSVM_GetTimer();
361                 }
362                 else
363                 {
364                     /* FIXME: intelligent hardware timer emulation needed */
365                     tempval = dummy_ctr;
366                 }
367             }
368
369             switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
370             {
371             case 0:
372                 res = 0; /* shouldn't happen? */
373                 break;
374             case 1: /* read lo byte */
375                 res = (BYTE)tempval;
376                 tmr_8253[chan].latched = FALSE;
377                 break;
378             case 3: /* read lo byte, then hi byte */
379                 tmr_8253[chan].byte_toggle ^= 1; /* toggle */
380                 if (tmr_8253[chan].byte_toggle)
381                 {
382                     res = (BYTE)tempval;
383                     break;
384                 }
385                 /* else [fall through if read hi byte !] */
386             case 2: /* read hi byte */
387                 res = (BYTE)(tempval >> 8);
388                 tmr_8253[chan].latched = FALSE;
389                 break;
390             }
391         }
392         break;
393     case 0x60:
394         res = DOSVM_Int09ReadScan(NULL);
395         break;
396     case 0x61:
397         res = (DWORD)parport_8255[1];
398         break;
399     case 0x62:
400         res = (DWORD)parport_8255[2];
401         break;
402     case 0x70:
403         res = (DWORD)cmosaddress;
404         break;
405     case 0x71:
406         res = (DWORD)cmosimage[cmosaddress & 0x3f];
407         break;
408     case 0x200:
409     case 0x201:
410         res = ~0U; /* no joystick */
411         break;
412     case 0x22a:
413     case 0x22c:
414     case 0x22e:
415         res = (DWORD)SB_ioport_in( port );
416         break;
417     /* VGA read registers */
418     case 0x3b4:  /* CRT Controller Register - Index (MDA) */
419     case 0x3b5:  /* CRT Controller Register - Other (MDA) */
420     case 0x3ba:  /* General Register - Input status 1 (MDA) */
421     case 0x3c0:  /* Attribute Controller - Address */
422     case 0x3c1:  /* Attribute Controller - Other */
423     case 0x3c2:  /* General Register - Input status 0 */
424     case 0x3c3:  /* General Register - Video subsystem enable */
425     case 0x3c4:  /* Sequencer Register - Address */
426     case 0x3c5:  /* Sequencer Register - Other */
427     case 0x3c6:
428     case 0x3c7:  /* General Register -  DAC State */
429     case 0x3c8:
430     case 0x3c9:
431     case 0x3ca:  /* General Register - Feature control */
432     case 0x3cb:
433     case 0x3cc:  /* General Register - Misc output */
434     case 0x3cd:
435     case 0x3ce:  /* Graphics Controller Register - Address */
436     case 0x3cf:  /* Graphics Controller Register - Other */
437     case 0x3d0:
438     case 0x3d1:
439     case 0x3d2:
440     case 0x3d3:
441     case 0x3d4:  /* CRT Controller Register - Index (CGA) */
442     case 0x3d5:  /* CRT Controller Register - Other (CGA) */
443     case 0x3d6:
444     case 0x3d7:
445     case 0x3d8:
446     case 0x3d9:
447     case 0x3da:
448     case 0x3db:
449     case 0x3dc:
450     case 0x3dd:
451     case 0x3de:
452     case 0x3df:
453         if(size > 1)
454            FIXME("Trying to read more than one byte from VGA!\n");
455         res = (DWORD)VGA_ioport_in( port );
456         break;
457     case 0x00:
458     case 0x01:
459     case 0x02:
460     case 0x03:
461     case 0x04:
462     case 0x05:
463     case 0x06:
464     case 0x07:
465     case 0xC0:
466     case 0xC2:
467     case 0xC4:
468     case 0xC6:
469     case 0xC8:
470     case 0xCA:
471     case 0xCC:
472     case 0xCE:
473     case 0x87:
474     case 0x83:
475     case 0x81:
476     case 0x82:
477     case 0x8B:
478     case 0x89:
479     case 0x8A:
480     case 0x487:
481     case 0x483:
482     case 0x481:
483     case 0x482:
484     case 0x48B:
485     case 0x489:
486     case 0x48A:
487     case 0x08:
488     case 0xD0:
489     case 0x0D:
490     case 0xDA:
491         res = (DWORD)DMA_ioport_in( port );
492         break;
493     default:
494         WARN("Direct I/O read attempted from port %x\n", port);
495         break;
496     }
497     return res;
498 }
499
500
501 /**********************************************************************
502  *          outport  (WINEDOS.@)
503  */
504 void WINAPI DOSVM_outport( int port, int size, DWORD value )
505 {
506     TRACE("IO: 0x%x (%d-byte value) to port 0x%04x\n", value, size, port );
507
508 #ifdef HAVE_PPDEV
509     if (do_pp_port_access == -1) do_pp_port_access = IO_pp_init();
510     if ((do_pp_port_access == 0) && (size == 1))
511     {
512         if (!IO_pp_outp(port,&value)) return;
513     }
514 #endif
515
516 #ifdef DIRECT_IO_ACCESS
517
518     if (do_direct_port_access == -1) IO_port_init();
519     if ((do_direct_port_access)
520         /* Make sure we have access to the port */
521         && (port_permissions[port] & IO_WRITE))
522     {
523         iopl(3);
524         switch(size)
525         {
526         case 1: outb( LOBYTE(value), port ); break;
527         case 2: outw( LOWORD(value), port ); break;
528         case 4: outl( value, port ); break;
529         }
530         iopl(0);
531         return;
532     }
533 #endif
534
535     switch (port)
536     {
537     case 0x20:
538         DOSVM_PIC_ioport_out( port, (BYTE)value );
539         break;
540     case 0x40:
541     case 0x41:
542     case 0x42:
543         {
544             BYTE chan = port & 3;
545
546             /* we need to get the oldval before any lo/hi byte change has been made */
547             if (((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
548                 !tmr_8253[chan].byte_toggle)
549                 tmr_8253[chan].oldval = tmr_8253[chan].countmax;
550             switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
551             {
552             case 0:
553                 break; /* shouldn't happen? */
554             case 1: /* write lo byte */
555                 tmr_8253[chan].countmax =
556                     (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
557                 break;
558             case 3: /* write lo byte, then hi byte */
559                 tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
560                 if (tmr_8253[chan].byte_toggle)
561                 {
562                     tmr_8253[chan].countmax =
563                         (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
564                     break;
565                 }
566                 /* else [fall through if write hi byte !] */
567             case 2: /* write hi byte */
568                 tmr_8253[chan].countmax =
569                     (tmr_8253[chan].countmax & 0x00ff) | ((BYTE)value << 8);
570                 break;
571             }
572             /* if programming is finished and value has changed
573                then update to new value */
574             if ((((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
575                  !tmr_8253[chan].byte_toggle) &&
576                 (tmr_8253[chan].countmax != tmr_8253[chan].oldval))
577                 set_timer_maxval(chan, tmr_8253[chan].countmax);
578         }
579         break;
580     case 0x43:
581        {
582            BYTE chan = ((BYTE)value & 0xc0) >> 6;
583            /* ctrl byte for specific timer channel */
584            if (chan == 3)
585            {
586                FIXME("8254 timer readback not implemented yet\n");
587                break;
588            }
589            switch (((BYTE)value & 0x30) >> 4)
590            {
591            case 0:      /* latch timer */
592                tmr_8253[chan].latched = TRUE;
593                dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
594                if (chan == 0) /* System timer divisor */
595                    tmr_8253[chan].latch = dummy_ctr + (WORD)DOSVM_GetTimer();
596                else
597                {
598                    /* FIXME: intelligent hardware timer emulation needed */
599                    tmr_8253[chan].latch = dummy_ctr;
600                }
601                break;
602            case 3:      /* write lo byte, then hi byte */
603                tmr_8253[chan].byte_toggle = FALSE; /* init */
604                /* fall through */
605            case 1:      /* write lo byte only */
606            case 2:      /* write hi byte only */
607                tmr_8253[chan].ctrlbyte_ch = (BYTE)value;
608                break;
609            }
610        }
611        break;
612     case 0x61:
613         parport_8255[1] = (BYTE)value;
614         if (((parport_8255[1] & 3) == 3) && (tmr_8253[2].countmax != 1))
615         {
616             TRACE("Beep (freq: %d) !\n", 1193180 / tmr_8253[2].countmax);
617             Beep(1193180 / tmr_8253[2].countmax, 20);
618         }
619         break;
620     case 0x70:
621         cmosaddress = (BYTE)value & 0x7f;
622         break;
623     case 0x71:
624         cmosimage[cmosaddress & 0x3f] = (BYTE)value;
625         break;
626     case 0x226:
627     case 0x22c:
628         SB_ioport_out( port, (BYTE)value );
629         break;
630     /* VGA Write registers */
631     case 0x3b4:  /* CRT Controller Register - Index (MDA) */
632     case 0x3b5:  /* CRT Controller Register - Other (MDA) */
633     case 0x3ba:  /* General Register - Feature Control */
634     case 0x3c0:  /* Attribute Controller - Address/Other */
635     case 0x3c1:
636     case 0x3c2:  /* General Register - Misc output */
637     case 0x3c3:  /* General Register - Video subsystem enable */
638     case 0x3c4:  /* Sequencer Register - Address */
639     case 0x3c5:  /* Sequencer Register - Other */
640     case 0x3c6:
641     case 0x3c7:
642     case 0x3c8:
643     case 0x3c9:
644     case 0x3ca:
645     case 0x3cb:
646     case 0x3cc:
647     case 0x3cd:
648     case 0x3ce:  /* Graphics Controller Register - Address */
649     case 0x3cf:  /* Graphics Controller Register - Other */
650     case 0x3d0:
651     case 0x3d1:
652     case 0x3d2:
653     case 0x3d3:
654     case 0x3d4:  /* CRT Controller Register - Index (CGA) */
655     case 0x3d5:  /* CRT Controller Register - Other (CGA) */
656     case 0x3d6:
657     case 0x3d7:
658     case 0x3d8:
659     case 0x3d9:
660     case 0x3da:
661     case 0x3db:
662     case 0x3dc:
663     case 0x3dd:
664     case 0x3de:
665     case 0x3df:
666         VGA_ioport_out( port, LOBYTE(value) );
667         if(size > 1) {
668             VGA_ioport_out( port+1, HIBYTE(value) );
669             if(size > 2) {
670                 VGA_ioport_out( port+2, LOBYTE(HIWORD(value)) );
671                 VGA_ioport_out( port+3, HIBYTE(HIWORD(value)) );
672             }
673         }
674         break;
675     case 0x00:
676     case 0x01:
677     case 0x02:
678     case 0x03:
679     case 0x04:
680     case 0x05:
681     case 0x06:
682     case 0x07:
683     case 0xC0:
684     case 0xC2:
685     case 0xC4:
686     case 0xC6:
687     case 0xC8:
688     case 0xCA:
689     case 0xCC:
690     case 0xCE:
691     case 0x87:
692     case 0x83:
693     case 0x81:
694     case 0x82:
695     case 0x8B:
696     case 0x89:
697     case 0x8A:
698     case 0x487:
699     case 0x483:
700     case 0x481:
701     case 0x482:
702     case 0x48B:
703     case 0x489:
704     case 0x48A:
705     case 0x08:
706     case 0xD0:
707     case 0x0B:
708     case 0xD6:
709     case 0x0A:
710     case 0xD4:
711     case 0x0F:
712     case 0xDE:
713     case 0x09:
714     case 0xD2:
715     case 0x0C:
716     case 0xD8:
717     case 0x0D:
718     case 0xDA:
719     case 0x0E:
720     case 0xDC:
721         DMA_ioport_out( port, (BYTE)value );
722         break;
723     default:
724         WARN("Direct I/O write attempted to port %x\n", port );
725         break;
726     }
727 }