Release 980601
[wine/multimedia.git] / msdos / ioports.c
blob7c94280ee5965b15f3c8268270906062c17b1d8b
1 /*
2 * Emulation of processor ioports.
4 * Copyright 1995 Morten Welinder
5 */
7 /* Known problems:
8 - only a few ports are emulated.
9 - real-time clock in "cmos" is bogus. A nifty alarm() setup could
10 fix that, I guess.
13 #include <ctype.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include "windows.h"
19 #include "options.h"
20 #include "debug.h"
22 static BYTE cmosaddress;
24 static BYTE cmosimage[64] =
26 0x27, 0x34, 0x31, 0x47, 0x16, 0x15, 0x00, 0x01,
27 0x04, 0x94, 0x26, 0x02, 0x50, 0x80, 0x00, 0x00,
28 0x40, 0xb1, 0x00, 0x9c, 0x01, 0x80, 0x02, 0x00,
29 0x1c, 0x00, 0x00, 0xad, 0x02, 0x10, 0x00, 0x00,
30 0x08, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x58,
32 0x00, 0x1c, 0x19, 0x81, 0x00, 0x0e, 0x00, 0x80,
33 0x1b, 0x7b, 0x21, 0x00, 0x00, 0x00, 0x05, 0x5f
36 #if defined(linux) && defined(__i386__)
37 # define DIRECT_IO_ACCESS
38 #else
39 # undef DIRECT_IO_ACCESS
40 #endif /* linux && __i386__ */
42 #ifdef DIRECT_IO_ACCESS
44 extern int iopl(int level);
46 static char do_direct_port_access = 0;
47 static char port_permissions[0x10000];
49 #define IO_READ 1
50 #define IO_WRITE 2
52 #endif /* DIRECT_IO_ACCESS */
54 /**********************************************************************
55 * IO_port_init
58 /* set_IO_permissions(int val1, int val)
59 * Helper function for IO_port_init
61 #ifdef DIRECT_IO_ACCESS
62 static void set_IO_permissions(int val1, int val, char rw)
64 int j;
65 if (val1 != -1) {
66 if (val == -1) val = 0x3ff;
67 for (j = val1; j <= val; j++)
68 port_permissions[j] |= rw;
70 do_direct_port_access = 1;
72 val1 = -1;
73 } else if (val != -1) {
74 do_direct_port_access = 1;
76 port_permissions[val] |= rw;
81 /* do_IO_port_init_read_or_write(char* temp, char rw)
82 * Helper function for IO_port_init
85 static void do_IO_port_init_read_or_write(char* temp, char rw)
87 int val, val1, i, len;
88 if (!strcasecmp(temp, "all")) {
89 MSG("Warning!!! Granting FULL IO port access to"
90 " windoze programs!\nWarning!!! "
91 "*** THIS IS NOT AT ALL "
92 "RECOMMENDED!!! ***\n");
93 for (i=0; i < sizeof(port_permissions); i++)
94 port_permissions[i] |= rw;
96 } else if (!(!strcmp(temp, "*") || *temp == '\0')) {
97 len = strlen(temp);
98 val = -1;
99 val1 = -1;
100 for (i = 0; i < len; i++) {
101 switch (temp[i]) {
102 case '0':
103 if (temp[i+1] == 'x' || temp[i+1] == 'X') {
104 sscanf(temp+i, "%x", &val);
105 i += 2;
106 } else {
107 sscanf(temp+i, "%d", &val);
109 while (isxdigit(temp[i]))
110 i++;
111 i--;
112 break;
113 case ',':
114 case ' ':
115 case '\t':
116 set_IO_permissions(val1, val, rw);
117 val1 = -1; val = -1;
118 break;
119 case '-':
120 val1 = val;
121 if (val1 == -1) val1 = 0;
122 break;
123 default:
124 if (temp[i] >= '0' && temp[i] <= '9') {
125 sscanf(temp+i, "%d", &val);
126 while (isdigit(temp[i]))
127 i++;
131 set_IO_permissions(val1, val, rw);
135 static __inline__ BYTE inb( WORD port )
137 BYTE b;
138 __asm__ __volatile__( "inb %w1,%0" : "=a" (b) : "d" (port) );
139 return b;
142 static __inline__ WORD inw( WORD port )
144 WORD w;
145 __asm__ __volatile__( "inw %w1,%0" : "=a" (w) : "d" (port) );
146 return w;
149 static __inline__ DWORD inl( WORD port )
151 DWORD dw;
152 __asm__ __volatile__( "inl %w1,%0" : "=a" (dw) : "d" (port) );
153 return dw;
156 static __inline__ void outb( BYTE value, WORD port )
158 __asm__ __volatile__( "outb %b0,%w1" : : "a" (value), "d" (port) );
161 static __inline__ void outw( WORD value, WORD port )
163 __asm__ __volatile__( "outw %w0,%w1" : : "a" (value), "d" (port) );
166 static __inline__ void outl( DWORD value, WORD port )
168 __asm__ __volatile__( "outl %0,%w1" : : "a" (value), "d" (port) );
171 #endif /* DIRECT_IO_ACCESS */
173 void IO_port_init()
175 #ifdef DIRECT_IO_ACCESS
176 char temp[1024];
178 /* Can we do that? */
179 if (!iopl(3)) {
180 iopl(0);
182 PROFILE_GetWineIniString( "ports", "read", "*",
183 temp, sizeof(temp) );
184 do_IO_port_init_read_or_write(temp, IO_READ);
185 PROFILE_GetWineIniString( "ports", "write", "*",
186 temp, sizeof(temp) );
187 do_IO_port_init_read_or_write(temp, IO_WRITE);
189 #endif /* DIRECT_IO_ACCESS */
193 /**********************************************************************
194 * IO_inport
196 DWORD IO_inport( int port, int count )
198 DWORD res = 0;
199 BYTE b;
201 #ifdef DIRECT_IO_ACCESS
202 if (do_direct_port_access)
204 /* Make sure we have access to the whole range */
205 int i;
206 for (i = 0; i < count; i++)
207 if (!(port_permissions[port+i] & IO_READ)) break;
208 if (i == count)
210 iopl(3);
211 switch(count)
213 case 1: res = inb( port ); break;
214 case 2: res = inw( port ); break;
215 case 4: res = inl( port ); break;
216 default:
217 ERR(int, "invalid count %d\n", count);
219 iopl(0);
220 return res;
223 #endif
225 TRACE(int, "%d bytes from port 0x%02x\n", count, port );
227 while (count-- > 0)
229 switch (port)
231 case 0x70:
232 b = cmosaddress;
233 break;
234 case 0x71:
235 b = cmosimage[cmosaddress & 0x3f];
236 break;
237 default:
238 WARN( int, "Direct I/O read attempted from port %x\n", port);
239 b = 0xff;
240 break;
242 port++;
243 res = (res << 8) | b;
245 TRACE(int, " returning ( 0x%lx )\n", res );
246 return res;
250 /**********************************************************************
251 * IO_outport
253 void IO_outport( int port, int count, DWORD value )
255 BYTE b;
257 TRACE(int, "IO: 0x%lx (%d bytes) to port 0x%02x\n",
258 value, count, port );
260 #ifdef DIRECT_IO_ACCESS
261 if (do_direct_port_access)
263 /* Make sure we have access to the whole range */
264 int i;
265 for (i = 0; i < count; i++)
266 if (!(port_permissions[port+i] & IO_WRITE)) break;
267 if (i == count)
269 iopl(3);
270 switch(count)
272 case 1: outb( LOBYTE(value), port ); break;
273 case 2: outw( LOWORD(value), port ); break;
274 case 4: outl( value, port ); break;
275 default:
276 WARN(int, "Invalid count %d\n", count);
278 iopl(0);
279 return;
282 #endif
284 while (count-- > 0)
286 b = value & 0xff;
287 value >>= 8;
288 switch (port)
290 case 0x70:
291 cmosaddress = b & 0x7f;
292 break;
293 case 0x71:
294 cmosimage[cmosaddress & 0x3f] = b;
295 break;
296 default:
297 WARN(int, "Direct I/O write attempted to port %x\n", port );
298 break;
300 port++;