blob: 235b1e1f5e3499c3ec7a2bb8d916dab93d57c750 [file] [log] [blame]
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00001/*
2 * Emulation of processor ioports.
3 *
4 * Copyright 1995 Morten Welinder
Alexandre Julliard638f1691999-01-17 16:32:32 +00005 * Copyright 1998 Andreas Mohr, Ove Kaaven
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00006 */
7
8/* Known problems:
9 - only a few ports are emulated.
10 - real-time clock in "cmos" is bogus. A nifty alarm() setup could
11 fix that, I guess.
12*/
13
Patrik Stridvall17fd4e32001-06-28 18:04:41 +000014#include "config.h"
15
Alexandre Julliard23946ad1997-06-16 17:43:53 +000016#include <ctype.h>
Alexandre Julliard58199531994-04-21 01:20:00 +000017#include <stdlib.h>
Alexandre Julliard383da682000-02-10 22:15:21 +000018#include <stdio.h>
Alexandre Julliard641ee761997-08-04 16:34:36 +000019#include <string.h>
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000020#include <time.h>
Alexandre Julliard641ee761997-08-04 16:34:36 +000021#include <unistd.h>
Jim Aston2e1cafa1999-03-14 16:35:05 +000022#include "windef.h"
Ove Kaavene5557b32000-12-26 00:22:45 +000023#include "callback.h"
Alexandre Julliard641ee761997-08-04 16:34:36 +000024#include "options.h"
Michael Veksler3496b431999-04-01 10:01:20 +000025#include "miscemu.h"
Alexandre Julliard61fece01999-06-26 19:09:08 +000026#include "debugtools.h"
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000027
Dimitrie O. Paun529da542000-11-27 23:54:25 +000028DEFAULT_DEBUG_CHANNEL(int);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000029
James Abbatiello9ad9e652000-08-22 20:38:47 +000030static struct {
31 WORD countmax;
32 BOOL16 byte_toggle; /* if TRUE, then hi byte has already been written */
33 WORD latch;
34 BOOL16 latched;
35 BYTE ctrlbyte_ch;
36 WORD oldval;
37} tmr_8253[3] = {
Ove Kaavene2c477b2001-11-08 17:06:40 +000038 {0xFFFF, FALSE, 0, FALSE, 0x36, 0},
39 {0x0012, FALSE, 0, FALSE, 0x74, 0},
40 {0x0001, FALSE, 0, FALSE, 0xB6, 0},
James Abbatiello9ad9e652000-08-22 20:38:47 +000041};
Andreas Mohr935ccab1999-01-30 13:37:54 +000042
Alexandre Julliard638f1691999-01-17 16:32:32 +000043static int dummy_ctr = 0;
44
45static BYTE parport_8255[4] = {0x4f, 0x20, 0xff, 0xff};
46
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000047static BYTE cmosaddress;
48
Alexandre Julliarde2991ea1995-07-29 13:09:43 +000049static BYTE cmosimage[64] =
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000050{
Alexandre Julliarde2991ea1995-07-29 13:09:43 +000051 0x27, 0x34, 0x31, 0x47, 0x16, 0x15, 0x00, 0x01,
52 0x04, 0x94, 0x26, 0x02, 0x50, 0x80, 0x00, 0x00,
53 0x40, 0xb1, 0x00, 0x9c, 0x01, 0x80, 0x02, 0x00,
54 0x1c, 0x00, 0x00, 0xad, 0x02, 0x10, 0x00, 0x00,
55 0x08, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
Andreas Mohreeaafcc1999-01-03 12:30:43 +000056 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x19,
Alexandre Julliarde2991ea1995-07-29 13:09:43 +000057 0x00, 0x1c, 0x19, 0x81, 0x00, 0x0e, 0x00, 0x80,
58 0x1b, 0x7b, 0x21, 0x00, 0x00, 0x00, 0x05, 0x5f
59};
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000060
Alexandre Julliard641ee761997-08-04 16:34:36 +000061#if defined(linux) && defined(__i386__)
62# define DIRECT_IO_ACCESS
63#else
64# undef DIRECT_IO_ACCESS
Uwe Bonnes6509fa92001-06-26 21:06:07 +000065# undef PP_IO_ACCESS
Alexandre Julliard641ee761997-08-04 16:34:36 +000066#endif /* linux && __i386__ */
67
68#ifdef DIRECT_IO_ACCESS
Alexandre Julliard17216f51997-10-12 16:30:17 +000069
70extern int iopl(int level);
Alexandre Julliardde304902000-06-03 04:50:59 +000071static char do_direct_port_access = -1;
Uwe Bonnes6509fa92001-06-26 21:06:07 +000072#ifdef HAVE_PPDEV
73static char do_pp_port_access = -1; /* -1: uninitialized, 1: not available
74 0: available);*/
75#endif
Alexandre Julliard641ee761997-08-04 16:34:36 +000076static char port_permissions[0x10000];
77
78#define IO_READ 1
79#define IO_WRITE 2
Alexandre Julliard17216f51997-10-12 16:30:17 +000080
Alexandre Julliard638f1691999-01-17 16:32:32 +000081static void IO_FixCMOSCheckSum(void)
Andreas Mohreeaafcc1999-01-03 12:30:43 +000082{
83 WORD sum = 0;
84 int i;
85
86 for (i=0x10; i < 0x2d; i++)
87 sum += cmosimage[i];
88 cmosimage[0x2e] = sum >> 8; /* yes, this IS hi byte !! */
89 cmosimage[0x2f] = sum & 0xff;
Alexandre Julliard61fece01999-06-26 19:09:08 +000090 TRACE("calculated hi %02x, lo %02x\n", cmosimage[0x2e], cmosimage[0x2f]);
Andreas Mohreeaafcc1999-01-03 12:30:43 +000091}
92
Patrik Stridvallc94e0862000-06-07 02:16:47 +000093#endif /* DIRECT_IO_ACCESS */
94
Alexandre Julliard638f1691999-01-17 16:32:32 +000095static void set_timer_maxval(unsigned timer, unsigned maxval)
96{
97 switch (timer) {
98 case 0: /* System timer counter divisor */
Alexandre Julliard8cd55d02001-12-04 19:54:44 +000099 if (Dosvm.SetTimer) Dosvm.SetTimer(maxval);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000100 break;
101 case 1: /* RAM refresh */
Francois Gougete76218d2001-05-09 17:31:31 +0000102 FIXME("RAM refresh counter handling not implemented !\n");
Alexandre Julliard638f1691999-01-17 16:32:32 +0000103 break;
104 case 2: /* cassette & speaker */
105 /* speaker on ? */
106 if (((BYTE)parport_8255[1] & 3) == 3)
107 {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000108 TRACE("Beep (freq: %d) !\n", 1193180 / maxval );
Alexandre Julliard638f1691999-01-17 16:32:32 +0000109 Beep(1193180 / maxval, 20);
110 }
111 break;
112 }
113}
114
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000115/**********************************************************************
116 * IO_port_init
117 */
118
119/* set_IO_permissions(int val1, int val)
120 * Helper function for IO_port_init
121 */
Alexandre Julliard641ee761997-08-04 16:34:36 +0000122#ifdef DIRECT_IO_ACCESS
123static void set_IO_permissions(int val1, int val, char rw)
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000124{
125 int j;
126 if (val1 != -1) {
127 if (val == -1) val = 0x3ff;
128 for (j = val1; j <= val; j++)
129 port_permissions[j] |= rw;
130
131 do_direct_port_access = 1;
132
133 val1 = -1;
134 } else if (val != -1) {
135 do_direct_port_access = 1;
136
137 port_permissions[val] |= rw;
138 }
139
140}
141
142/* do_IO_port_init_read_or_write(char* temp, char rw)
143 * Helper function for IO_port_init
144 */
145
Alexandre Julliard641ee761997-08-04 16:34:36 +0000146static void do_IO_port_init_read_or_write(char* temp, char rw)
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000147{
148 int val, val1, i, len;
149 if (!strcasecmp(temp, "all")) {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000150 MESSAGE("Warning!!! Granting FULL IO port access to"
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000151 " windoze programs!\nWarning!!! "
152 "*** THIS IS NOT AT ALL "
153 "RECOMMENDED!!! ***\n");
154 for (i=0; i < sizeof(port_permissions); i++)
155 port_permissions[i] |= rw;
156
157 } else if (!(!strcmp(temp, "*") || *temp == '\0')) {
158 len = strlen(temp);
159 val = -1;
160 val1 = -1;
161 for (i = 0; i < len; i++) {
162 switch (temp[i]) {
163 case '0':
164 if (temp[i+1] == 'x' || temp[i+1] == 'X') {
165 sscanf(temp+i, "%x", &val);
166 i += 2;
167 } else {
168 sscanf(temp+i, "%d", &val);
169 }
170 while (isxdigit(temp[i]))
171 i++;
172 i--;
173 break;
174 case ',':
175 case ' ':
176 case '\t':
177 set_IO_permissions(val1, val, rw);
178 val1 = -1; val = -1;
179 break;
180 case '-':
181 val1 = val;
182 if (val1 == -1) val1 = 0;
183 break;
184 default:
185 if (temp[i] >= '0' && temp[i] <= '9') {
186 sscanf(temp+i, "%d", &val);
187 while (isdigit(temp[i]))
188 i++;
189 }
190 }
191 }
192 set_IO_permissions(val1, val, rw);
193 }
194}
195
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000196static inline BYTE inb( WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000197{
198 BYTE b;
199 __asm__ __volatile__( "inb %w1,%0" : "=a" (b) : "d" (port) );
200 return b;
201}
202
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000203static inline WORD inw( WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000204{
205 WORD w;
206 __asm__ __volatile__( "inw %w1,%0" : "=a" (w) : "d" (port) );
207 return w;
208}
209
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000210static inline DWORD inl( WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000211{
212 DWORD dw;
213 __asm__ __volatile__( "inl %w1,%0" : "=a" (dw) : "d" (port) );
214 return dw;
215}
216
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000217static inline void outb( BYTE value, WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000218{
219 __asm__ __volatile__( "outb %b0,%w1" : : "a" (value), "d" (port) );
220}
221
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000222static inline void outw( WORD value, WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000223{
224 __asm__ __volatile__( "outw %w0,%w1" : : "a" (value), "d" (port) );
225}
226
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000227static inline void outl( DWORD value, WORD port )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000228{
229 __asm__ __volatile__( "outl %0,%w1" : : "a" (value), "d" (port) );
230}
231
Alexandre Julliardde304902000-06-03 04:50:59 +0000232static void IO_port_init(void)
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000233{
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000234 char temp[1024];
235
Alexandre Julliardde304902000-06-03 04:50:59 +0000236 do_direct_port_access = 0;
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000237 /* Can we do that? */
238 if (!iopl(3)) {
239 iopl(0);
240
241 PROFILE_GetWineIniString( "ports", "read", "*",
242 temp, sizeof(temp) );
Alexandre Julliard641ee761997-08-04 16:34:36 +0000243 do_IO_port_init_read_or_write(temp, IO_READ);
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000244 PROFILE_GetWineIniString( "ports", "write", "*",
245 temp, sizeof(temp) );
Alexandre Julliard641ee761997-08-04 16:34:36 +0000246 do_IO_port_init_read_or_write(temp, IO_WRITE);
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000247 }
Andreas Mohreeaafcc1999-01-03 12:30:43 +0000248 IO_FixCMOSCheckSum();
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000249}
Alexandre Julliard8d24ae61994-04-05 21:42:43 +0000250
Patrik Stridvallc94e0862000-06-07 02:16:47 +0000251#endif /* DIRECT_IO_ACCESS */
Alexandre Julliard641ee761997-08-04 16:34:36 +0000252
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000253/**********************************************************************
254 * IO_inport
Alexandre Julliard638f1691999-01-17 16:32:32 +0000255 *
256 * Note: The size argument has to be handled correctly _externally_
257 * (as we always return a DWORD)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000258 */
Alexandre Julliard638f1691999-01-17 16:32:32 +0000259DWORD IO_inport( int port, int size )
Alexandre Julliard8d24ae61994-04-05 21:42:43 +0000260{
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000261 DWORD res = 0;
Alexandre Julliard8d24ae61994-04-05 21:42:43 +0000262
Alexandre Julliard61fece01999-06-26 19:09:08 +0000263 TRACE("%d-byte value from port 0x%02x\n", size, port );
Andreas Mohr935ccab1999-01-30 13:37:54 +0000264
Uwe Bonnes6509fa92001-06-26 21:06:07 +0000265#ifdef HAVE_PPDEV
266 if (do_pp_port_access == -1)
267 do_pp_port_access =IO_pp_init();
268 if ((do_pp_port_access == 0 ) && (size == 1))
269 if (!IO_pp_inp(port,&res))
270 return res;
271#endif
Alexandre Julliardde304902000-06-03 04:50:59 +0000272#ifdef DIRECT_IO_ACCESS
273 if (do_direct_port_access == -1) IO_port_init();
Alexandre Julliard638f1691999-01-17 16:32:32 +0000274 if ((do_direct_port_access)
275 /* Make sure we have access to the port */
276 && (port_permissions[port] & IO_READ))
Alexandre Julliard641ee761997-08-04 16:34:36 +0000277 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000278 iopl(3);
279 switch(size)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000280 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000281 case 1: res = inb( port ); break;
282 case 2: res = inw( port ); break;
283 case 4: res = inl( port ); break;
284 default:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000285 ERR("invalid data size %d\n", size);
Alexandre Julliard641ee761997-08-04 16:34:36 +0000286 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000287 iopl(0);
288 return res;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000289 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000290#endif
291
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000292 /* first give the DOS VM a chance to handle it */
293 if (Dosvm.inport && Dosvm.inport( port, size, &res )) return res;
294
Alexandre Julliard638f1691999-01-17 16:32:32 +0000295 switch (port)
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000296 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000297 case 0x40:
298 case 0x41:
299 case 0x42:
300 {
301 BYTE chan = port & 3;
302 WORD tempval = 0;
James Abbatiello9ad9e652000-08-22 20:38:47 +0000303 if (tmr_8253[chan].latched)
304 tempval = tmr_8253[chan].latch;
305 else
306 {
307 dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
308 if (chan == 0) /* System timer counter divisor */
309 {
Ove Kaavene5557b32000-12-26 00:22:45 +0000310 /* FIXME: Dosvm.GetTimer() returns quite rigid values */
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000311 if (Dosvm.GetTimer)
Uwe Bonnes23fbf4a2001-08-15 23:19:45 +0000312 tempval = dummy_ctr + (WORD)Dosvm.GetTimer();
313 else
314 tempval = dummy_ctr;
James Abbatiello9ad9e652000-08-22 20:38:47 +0000315 }
316 else
317 {
318 /* FIXME: intelligent hardware timer emulation needed */
319 tempval = dummy_ctr;
320 }
321 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000322
James Abbatiello9ad9e652000-08-22 20:38:47 +0000323 switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
Andreas Mohr935ccab1999-01-30 13:37:54 +0000324 {
James Abbatiello9ad9e652000-08-22 20:38:47 +0000325 case 0:
326 res = 0; /* shouldn't happen? */
327 break;
328 case 1: /* read lo byte */
329 res = (BYTE)tempval;
330 tmr_8253[chan].latched = FALSE;
331 break;
332 case 3: /* read lo byte, then hi byte */
333 tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
334 if (tmr_8253[chan].byte_toggle)
Alexandre Julliard638f1691999-01-17 16:32:32 +0000335 {
336 res = (BYTE)tempval;
337 break;
338 }
339 /* else [fall through if read hi byte !] */
James Abbatiello9ad9e652000-08-22 20:38:47 +0000340 case 2: /* read hi byte */
341 res = (BYTE)(tempval >> 8);
342 tmr_8253[chan].latched = FALSE;
343 break;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000344 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000345 }
James Abbatiello9ad9e652000-08-22 20:38:47 +0000346 break;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000347 case 0x60:
Ove Kaaven866b3371999-03-25 10:51:38 +0000348#if 0 /* what's this port got to do with parport ? */
Alexandre Julliard638f1691999-01-17 16:32:32 +0000349 res = (DWORD)parport_8255[0];
Ove Kaaven866b3371999-03-25 10:51:38 +0000350#endif
Alexandre Julliard638f1691999-01-17 16:32:32 +0000351 break;
352 case 0x61:
353 res = (DWORD)parport_8255[1];
354 break;
355 case 0x62:
356 res = (DWORD)parport_8255[2];
357 break;
358 case 0x70:
359 res = (DWORD)cmosaddress;
360 break;
361 case 0x71:
362 res = (DWORD)cmosimage[cmosaddress & 0x3f];
363 break;
364 case 0x200:
365 case 0x201:
366 res = 0xffffffff; /* no joystick */
367 break;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000368 default:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000369 WARN("Direct I/O read attempted from port %x\n", port);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000370 res = 0xffffffff;
371 break;
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000372 }
Alexandre Julliard61fece01999-06-26 19:09:08 +0000373 TRACE(" returning ( 0x%lx )\n", res );
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000374 return res;
Alexandre Julliard8d24ae61994-04-05 21:42:43 +0000375}
376
Alexandre Julliard234bc241994-12-10 13:02:28 +0000377
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000378/**********************************************************************
379 * IO_outport
380 */
Alexandre Julliard638f1691999-01-17 16:32:32 +0000381void IO_outport( int port, int size, DWORD value )
Alexandre Julliard234bc241994-12-10 13:02:28 +0000382{
Alexandre Julliard61fece01999-06-26 19:09:08 +0000383 TRACE("IO: 0x%lx (%d-byte value) to port 0x%02x\n",
Alexandre Julliard638f1691999-01-17 16:32:32 +0000384 value, size, port );
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000385
Uwe Bonnes6509fa92001-06-26 21:06:07 +0000386#ifdef HAVE_PPDEV
387 if (do_pp_port_access == -1)
388 do_pp_port_access = IO_pp_init();
389 if ((do_pp_port_access == 0) && (size == 1))
390 if (!IO_pp_outp(port,&value))
391 return;
392#endif
Alexandre Julliard641ee761997-08-04 16:34:36 +0000393#ifdef DIRECT_IO_ACCESS
Uwe Bonnes6509fa92001-06-26 21:06:07 +0000394
Alexandre Julliardde304902000-06-03 04:50:59 +0000395 if (do_direct_port_access == -1) IO_port_init();
Alexandre Julliard638f1691999-01-17 16:32:32 +0000396 if ((do_direct_port_access)
397 /* Make sure we have access to the port */
398 && (port_permissions[port] & IO_WRITE))
Alexandre Julliard641ee761997-08-04 16:34:36 +0000399 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000400 iopl(3);
401 switch(size)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000402 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000403 case 1: outb( LOBYTE(value), port ); break;
404 case 2: outw( LOWORD(value), port ); break;
405 case 4: outl( value, port ); break;
406 default:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000407 WARN("Invalid data size %d\n", size);
Alexandre Julliard641ee761997-08-04 16:34:36 +0000408 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000409 iopl(0);
410 return;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000411 }
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000412#endif
413
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000414 /* first give the DOS VM a chance to handle it */
415 if (Dosvm.outport && Dosvm.outport( port, size, value )) return;
416
Alexandre Julliard638f1691999-01-17 16:32:32 +0000417 switch (port)
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000418 {
Alexandre Julliard638f1691999-01-17 16:32:32 +0000419 case 0x40:
420 case 0x41:
421 case 0x42:
422 {
423 BYTE chan = port & 3;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000424
James Abbatiello9ad9e652000-08-22 20:38:47 +0000425 /* we need to get the oldval before any lo/hi byte change has been made */
426 if (((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
427 !tmr_8253[chan].byte_toggle)
428 tmr_8253[chan].oldval = tmr_8253[chan].countmax;
429 switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000430 {
James Abbatiello9ad9e652000-08-22 20:38:47 +0000431 case 0:
432 break; /* shouldn't happen? */
433 case 1: /* write lo byte */
434 tmr_8253[chan].countmax =
435 (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000436 break;
James Abbatiello9ad9e652000-08-22 20:38:47 +0000437 case 3: /* write lo byte, then hi byte */
438 tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
439 if (tmr_8253[chan].byte_toggle)
Alexandre Julliard638f1691999-01-17 16:32:32 +0000440 {
James Abbatiello9ad9e652000-08-22 20:38:47 +0000441 tmr_8253[chan].countmax =
442 (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000443 break;
444 }
445 /* else [fall through if write hi byte !] */
James Abbatiello9ad9e652000-08-22 20:38:47 +0000446 case 2: /* write hi byte */
447 tmr_8253[chan].countmax =
448 (tmr_8253[chan].countmax & 0x00ff) | ((BYTE)value << 8);
Alexandre Julliard641ee761997-08-04 16:34:36 +0000449 break;
450 }
James Abbatiello9ad9e652000-08-22 20:38:47 +0000451 /* if programming is finished and value has changed
452 then update to new value */
453 if ((((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
454 !tmr_8253[chan].byte_toggle) &&
455 (tmr_8253[chan].countmax != tmr_8253[chan].oldval))
456 set_timer_maxval(chan, tmr_8253[chan].countmax);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000457 }
458 break;
459 case 0x43:
James Abbatiello9ad9e652000-08-22 20:38:47 +0000460 {
461 BYTE chan = ((BYTE)value & 0xc0) >> 6;
462 /* ctrl byte for specific timer channel */
463 if (chan == 3)
464 {
465 FIXME("8254 timer readback not implemented yet\n");
466 break;
467 }
468 switch (((BYTE)value & 0x30) >> 4)
469 {
470 case 0: /* latch timer */
471 tmr_8253[chan].latched = TRUE;
472 dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
473 if (chan == 0) /* System timer divisor */
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000474 if (Dosvm.GetTimer)
Uwe Bonnes23fbf4a2001-08-15 23:19:45 +0000475 tmr_8253[chan].latch = dummy_ctr + (WORD)Dosvm.GetTimer();
476 else
477 tmr_8253[chan].latch = dummy_ctr;
James Abbatiello9ad9e652000-08-22 20:38:47 +0000478 else
479 {
480 /* FIXME: intelligent hardware timer emulation needed */
481 tmr_8253[chan].latch = dummy_ctr;
482 }
483 break;
484 case 3: /* write lo byte, then hi byte */
485 tmr_8253[chan].byte_toggle = FALSE; /* init */
486 /* fall through */
487 case 1: /* write lo byte only */
488 case 2: /* write hi byte only */
489 tmr_8253[chan].ctrlbyte_ch = (BYTE)value;
490 break;
491 }
492 }
493 break;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000494 case 0x61:
495 parport_8255[1] = (BYTE)value;
James Abbatiello9ad9e652000-08-22 20:38:47 +0000496 if ((((BYTE)parport_8255[1] & 3) == 3) && (tmr_8253[2].countmax != 1))
Alexandre Julliard638f1691999-01-17 16:32:32 +0000497 {
James Abbatiello9ad9e652000-08-22 20:38:47 +0000498 TRACE("Beep (freq: %d) !\n", 1193180 / tmr_8253[2].countmax);
499 Beep(1193180 / tmr_8253[2].countmax, 20);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000500 }
501 break;
502 case 0x70:
503 cmosaddress = (BYTE)value & 0x7f;
504 break;
505 case 0x71:
506 cmosimage[cmosaddress & 0x3f] = (BYTE)value;
507 break;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000508 default:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000509 WARN("Direct I/O write attempted to port %x\n", port );
Alexandre Julliard638f1691999-01-17 16:32:32 +0000510 break;
Alexandre Julliarde2991ea1995-07-29 13:09:43 +0000511 }
Alexandre Julliard234bc241994-12-10 13:02:28 +0000512}