Test that SafeArrayDestroyData keeps the pointer if FADF_STATIC is
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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     HKEY hkey;
258     DWORD dummy;
259     OBJECT_ATTRIBUTES attr;
260     UNICODE_STRING nameW;
261
262     static const WCHAR portsW[] = {'M','a','c','h','i','n','e','\\',
263                                    'S','o','f','t','w','a','r','e','\\',
264                                    'W','i','n','e','\\','W','i','n','e','\\',
265                                    'C','o','n','f','i','g','\\','P','o','r','t','s',0};
266     static const WCHAR readW[] = {'r','e','a','d',0};
267     static const WCHAR writeW[] = {'w','r','i','t','e',0};
268
269     do_direct_port_access = 0;
270     /* Can we do that? */
271     if (!iopl(3))
272     {
273         iopl(0);
274
275         attr.Length = sizeof(attr);
276         attr.RootDirectory = 0;
277         attr.ObjectName = &nameW;
278         attr.Attributes = 0;
279         attr.SecurityDescriptor = NULL;
280         attr.SecurityQualityOfService = NULL;
281         RtlInitUnicodeString( &nameW, portsW );
282
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     }
300 }
301
302 #endif  /* DIRECT_IO_ACCESS */
303
304
305 /**********************************************************************
306  *          inport   (WINEDOS.@)
307  *
308  * Note: The size argument has to be handled correctly _externally_
309  * (as we always return a DWORD)
310  */
311 DWORD WINAPI DOSVM_inport( int port, int size )
312 {
313     DWORD res = ~0U;
314
315     TRACE("%d-byte value from port 0x%04x\n", size, port );
316
317 #ifdef HAVE_PPDEV
318     if (do_pp_port_access == -1) do_pp_port_access =IO_pp_init();
319     if ((do_pp_port_access == 0 ) && (size == 1))
320     {
321         if (!IO_pp_inp(port,&res)) return res;
322     }
323 #endif
324
325 #ifdef DIRECT_IO_ACCESS
326     if (do_direct_port_access == -1) IO_port_init();
327     if ((do_direct_port_access)
328         /* Make sure we have access to the port */
329         && (port_permissions[port] & IO_READ))
330     {
331         iopl(3);
332         switch(size)
333         {
334         case 1: res = inb( port ); break;
335         case 2: res = inw( port ); break;
336         case 4: res = inl( port ); break;
337         }
338         iopl(0);
339         return res;
340     }
341 #endif
342
343     switch (port)
344     {
345     case 0x40:
346     case 0x41:
347     case 0x42:
348         {
349             BYTE chan = port & 3;
350             WORD tempval = 0;
351             if (tmr_8253[chan].latched)
352                 tempval = tmr_8253[chan].latch;
353             else
354             {
355                 dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
356                 if (chan == 0) /* System timer counter divisor */
357                 {
358                     /* FIXME: DOSVM_GetTimer() returns quite rigid values */
359                     tempval = dummy_ctr + (WORD)DOSVM_GetTimer();
360                 }
361                 else
362                 {
363                     /* FIXME: intelligent hardware timer emulation needed */
364                     tempval = dummy_ctr;
365                 }
366             }
367
368             switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
369             {
370             case 0:
371                 res = 0; /* shouldn't happen? */
372                 break;
373             case 1: /* read lo byte */
374                 res = (BYTE)tempval;
375                 tmr_8253[chan].latched = FALSE;
376                 break;
377             case 3: /* read lo byte, then hi byte */
378                 tmr_8253[chan].byte_toggle ^= 1; /* toggle */
379                 if (tmr_8253[chan].byte_toggle)
380                 {
381                     res = (BYTE)tempval;
382                     break;
383                 }
384                 /* else [fall through if read hi byte !] */
385             case 2: /* read hi byte */
386                 res = (BYTE)(tempval >> 8);
387                 tmr_8253[chan].latched = FALSE;
388                 break;
389             }
390         }
391         break;
392     case 0x60:
393         res = DOSVM_Int09ReadScan(NULL);
394         break;
395     case 0x61:
396         res = (DWORD)parport_8255[1];
397         break;
398     case 0x62:
399         res = (DWORD)parport_8255[2];
400         break;
401     case 0x70:
402         res = (DWORD)cmosaddress;
403         break;
404     case 0x71:
405         res = (DWORD)cmosimage[cmosaddress & 0x3f];
406         break;
407     case 0x200:
408     case 0x201:
409         res = ~0U; /* no joystick */
410         break;
411     case 0x22a:
412     case 0x22c:
413     case 0x22e:
414         res = (DWORD)SB_ioport_in( port );
415         break;
416     case 0x3ba:
417     case 0x3c0:
418     case 0x3c1:
419     case 0x3c2:
420     case 0x3c3:
421     case 0x3c4:
422     case 0x3c5:
423     case 0x3c6:
424     case 0x3c7:
425     case 0x3c8:
426     case 0x3c9:
427     case 0x3ca:
428     case 0x3cb:
429     case 0x3cc:
430     case 0x3cd:
431     case 0x3ce:
432     case 0x3cf:
433     case 0x3d0:
434     case 0x3d1:
435     case 0x3d2:
436     case 0x3d3:
437     case 0x3d4:
438     case 0x3d5:
439     case 0x3d6:
440     case 0x3d7:
441     case 0x3d8:
442     case 0x3d9:
443     case 0x3da:
444     case 0x3db:
445     case 0x3dc:
446     case 0x3dd:
447     case 0x3de:
448     case 0x3df:
449         if(size > 1)
450            FIXME("Trying to read more than one byte from VGA!\n");
451         res = (DWORD)VGA_ioport_in( port );
452         break;
453     case 0x00:
454     case 0x01:
455     case 0x02:
456     case 0x03:
457     case 0x04:
458     case 0x05:
459     case 0x06:
460     case 0x07:
461     case 0xC0:
462     case 0xC2:
463     case 0xC4:
464     case 0xC6:
465     case 0xC8:
466     case 0xCA:
467     case 0xCC:
468     case 0xCE:
469     case 0x87:
470     case 0x83:
471     case 0x81:
472     case 0x82:
473     case 0x8B:
474     case 0x89:
475     case 0x8A:
476     case 0x487:
477     case 0x483:
478     case 0x481:
479     case 0x482:
480     case 0x48B:
481     case 0x489:
482     case 0x48A:
483     case 0x08:
484     case 0xD0:
485     case 0x0D:
486     case 0xDA:
487         res = (DWORD)DMA_ioport_in( port );
488         break;
489     default:
490         WARN("Direct I/O read attempted from port %x\n", port);
491         break;
492     }
493     return res;
494 }
495
496
497 /**********************************************************************
498  *          outport  (WINEDOS.@)
499  */
500 void WINAPI DOSVM_outport( int port, int size, DWORD value )
501 {
502     TRACE("IO: 0x%lx (%d-byte value) to port 0x%04x\n", value, size, port );
503
504 #ifdef HAVE_PPDEV
505     if (do_pp_port_access == -1) do_pp_port_access = IO_pp_init();
506     if ((do_pp_port_access == 0) && (size == 1))
507     {
508         if (!IO_pp_outp(port,&value)) return;
509     }
510 #endif
511
512 #ifdef DIRECT_IO_ACCESS
513
514     if (do_direct_port_access == -1) IO_port_init();
515     if ((do_direct_port_access)
516         /* Make sure we have access to the port */
517         && (port_permissions[port] & IO_WRITE))
518     {
519         iopl(3);
520         switch(size)
521         {
522         case 1: outb( LOBYTE(value), port ); break;
523         case 2: outw( LOWORD(value), port ); break;
524         case 4: outl( value, port ); break;
525         }
526         iopl(0);
527         return;
528     }
529 #endif
530
531     switch (port)
532     {
533     case 0x20:
534         DOSVM_PIC_ioport_out( port, (BYTE)value );
535         break;
536     case 0x40:
537     case 0x41:
538     case 0x42:
539         {
540             BYTE chan = port & 3;
541
542             /* we need to get the oldval before any lo/hi byte change has been made */
543             if (((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
544                 !tmr_8253[chan].byte_toggle)
545                 tmr_8253[chan].oldval = tmr_8253[chan].countmax;
546             switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
547             {
548             case 0:
549                 break; /* shouldn't happen? */
550             case 1: /* write lo byte */
551                 tmr_8253[chan].countmax =
552                     (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
553                 break;
554             case 3: /* write lo byte, then hi byte */
555                 tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
556                 if (tmr_8253[chan].byte_toggle)
557                 {
558                     tmr_8253[chan].countmax =
559                         (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
560                     break;
561                 }
562                 /* else [fall through if write hi byte !] */
563             case 2: /* write hi byte */
564                 tmr_8253[chan].countmax =
565                     (tmr_8253[chan].countmax & 0x00ff) | ((BYTE)value << 8);
566                 break;
567             }
568             /* if programming is finished and value has changed
569                then update to new value */
570             if ((((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
571                  !tmr_8253[chan].byte_toggle) &&
572                 (tmr_8253[chan].countmax != tmr_8253[chan].oldval))
573                 set_timer_maxval(chan, tmr_8253[chan].countmax);
574         }
575         break;
576     case 0x43:
577        {
578            BYTE chan = ((BYTE)value & 0xc0) >> 6;
579            /* ctrl byte for specific timer channel */
580            if (chan == 3)
581            {
582                FIXME("8254 timer readback not implemented yet\n");
583                break;
584            }
585            switch (((BYTE)value & 0x30) >> 4)
586            {
587            case 0:      /* latch timer */
588                tmr_8253[chan].latched = TRUE;
589                dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
590                if (chan == 0) /* System timer divisor */
591                    tmr_8253[chan].latch = dummy_ctr + (WORD)DOSVM_GetTimer();
592                else
593                {
594                    /* FIXME: intelligent hardware timer emulation needed */
595                    tmr_8253[chan].latch = dummy_ctr;
596                }
597                break;
598            case 3:      /* write lo byte, then hi byte */
599                tmr_8253[chan].byte_toggle = FALSE; /* init */
600                /* fall through */
601            case 1:      /* write lo byte only */
602            case 2:      /* write hi byte only */
603                tmr_8253[chan].ctrlbyte_ch = (BYTE)value;
604                break;
605            }
606        }
607        break;
608     case 0x61:
609         parport_8255[1] = (BYTE)value;
610         if ((((BYTE)parport_8255[1] & 3) == 3) && (tmr_8253[2].countmax != 1))
611         {
612             TRACE("Beep (freq: %d) !\n", 1193180 / tmr_8253[2].countmax);
613             Beep(1193180 / tmr_8253[2].countmax, 20);
614         }
615         break;
616     case 0x70:
617         cmosaddress = (BYTE)value & 0x7f;
618         break;
619     case 0x71:
620         cmosimage[cmosaddress & 0x3f] = (BYTE)value;
621         break;
622     case 0x226:
623     case 0x22c:
624         SB_ioport_out( port, (BYTE)value );
625         break;
626     case 0x3c0:
627     case 0x3c1:
628     case 0x3c2:
629     case 0x3c3:
630     case 0x3c4:
631     case 0x3c5:
632     case 0x3c6:
633     case 0x3c7:
634     case 0x3c8:
635     case 0x3c9:
636     case 0x3ca:
637     case 0x3cb:
638     case 0x3cc:
639     case 0x3cd:
640     case 0x3ce:
641     case 0x3cf:
642     case 0x3d0:
643     case 0x3d1:
644     case 0x3d2:
645     case 0x3d3:
646     case 0x3d4:
647     case 0x3d5:
648     case 0x3d6:
649     case 0x3d7:
650     case 0x3d8:
651     case 0x3d9:
652     case 0x3da:
653     case 0x3db:
654     case 0x3dc:
655     case 0x3dd:
656     case 0x3de:
657     case 0x3df:
658         VGA_ioport_out( port, LOBYTE(value) );
659         if(size > 1) {
660             VGA_ioport_out( port+1, HIBYTE(value) );
661             if(size > 2) {
662                 VGA_ioport_out( port+2, LOBYTE(HIWORD(value)) );
663                 VGA_ioport_out( port+3, HIBYTE(HIWORD(value)) );
664             }
665         }
666         break;
667     case 0x00:
668     case 0x01:
669     case 0x02:
670     case 0x03:
671     case 0x04:
672     case 0x05:
673     case 0x06:
674     case 0x07:
675     case 0xC0:
676     case 0xC2:
677     case 0xC4:
678     case 0xC6:
679     case 0xC8:
680     case 0xCA:
681     case 0xCC:
682     case 0xCE:
683     case 0x87:
684     case 0x83:
685     case 0x81:
686     case 0x82:
687     case 0x8B:
688     case 0x89:
689     case 0x8A:
690     case 0x487:
691     case 0x483:
692     case 0x481:
693     case 0x482:
694     case 0x48B:
695     case 0x489:
696     case 0x48A:
697     case 0x08:
698     case 0xD0:
699     case 0x0B:
700     case 0xD6:
701     case 0x0A:
702     case 0xD4:
703     case 0x0F:
704     case 0xDE:
705     case 0x09:
706     case 0xD2:
707     case 0x0C:
708     case 0xD8:
709     case 0x0D:
710     case 0xDA:
711     case 0x0E:
712     case 0xDC:
713         DMA_ioport_out( port, (BYTE)value );
714         break;
715     default:
716         WARN("Direct I/O write attempted to port %x\n", port );
717         break;
718     }
719 }