blob: 12571efc2a3b14e9c5011f539dfcf1cf7636f9e9 [file] [log] [blame]
bellard80cabfa2004-03-14 12:20:30 +00001/*
2 * QEMU 8253/8254 interval timer emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard80cabfa2004-03-14 12:20:30 +00004 * Copyright (c) 2003-2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellard80cabfa2004-03-14 12:20:30 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "hw.h"
25#include "pc.h"
26#include "isa.h"
27#include "qemu-timer.h"
bellard80cabfa2004-03-14 12:20:30 +000028
bellardb0a21b52004-03-31 18:58:38 +000029//#define DEBUG_PIT
30
bellardec844b92004-05-03 23:18:25 +000031#define RW_STATE_LSB 1
32#define RW_STATE_MSB 2
33#define RW_STATE_WORD0 3
34#define RW_STATE_WORD1 4
bellard80cabfa2004-03-14 12:20:30 +000035
bellardec844b92004-05-03 23:18:25 +000036typedef struct PITChannelState {
37 int count; /* can be 65536 */
38 uint16_t latched_count;
39 uint8_t count_latched;
40 uint8_t status_latched;
41 uint8_t status;
42 uint8_t read_state;
43 uint8_t write_state;
44 uint8_t write_latch;
45 uint8_t rw_mode;
46 uint8_t mode;
47 uint8_t bcd; /* not supported */
48 uint8_t gate; /* timer start */
49 int64_t count_load_time;
50 /* irq handling */
51 int64_t next_transition_time;
52 QEMUTimer *irq_timer;
pbrookd537cf62007-04-07 18:14:41 +000053 qemu_irq irq;
bellardec844b92004-05-03 23:18:25 +000054} PITChannelState;
55
Blue Swirl64d7e9a2011-02-13 19:54:40 +000056typedef struct PITState {
57 ISADevice dev;
Richard Henderson60ea6aa2011-08-10 15:28:15 -070058 MemoryRegion ioports;
Blue Swirl64d7e9a2011-02-13 19:54:40 +000059 uint32_t irq;
60 uint32_t iobase;
bellardec844b92004-05-03 23:18:25 +000061 PITChannelState channels[3];
Blue Swirl64d7e9a2011-02-13 19:54:40 +000062} PITState;
bellardec844b92004-05-03 23:18:25 +000063
64static PITState pit_state;
bellard80cabfa2004-03-14 12:20:30 +000065
bellardb0a21b52004-03-31 18:58:38 +000066static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
67
bellard80cabfa2004-03-14 12:20:30 +000068static int pit_get_count(PITChannelState *s)
69{
70 uint64_t d;
71 int counter;
72
Paolo Bonzini74475452011-03-11 16:47:48 +010073 d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
Juan Quintela6ee093c2009-09-10 03:04:26 +020074 get_ticks_per_sec());
bellard80cabfa2004-03-14 12:20:30 +000075 switch(s->mode) {
76 case 0:
77 case 1:
78 case 4:
79 case 5:
80 counter = (s->count - d) & 0xffff;
81 break;
82 case 3:
83 /* XXX: may be incorrect for odd counts */
84 counter = s->count - ((2 * d) % s->count);
85 break;
86 default:
87 counter = s->count - (d % s->count);
88 break;
89 }
90 return counter;
91}
92
93/* get pit output bit */
bellardec844b92004-05-03 23:18:25 +000094static int pit_get_out1(PITChannelState *s, int64_t current_time)
bellard80cabfa2004-03-14 12:20:30 +000095{
96 uint64_t d;
97 int out;
98
Juan Quintela6ee093c2009-09-10 03:04:26 +020099 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
100 get_ticks_per_sec());
bellard80cabfa2004-03-14 12:20:30 +0000101 switch(s->mode) {
102 default:
103 case 0:
104 out = (d >= s->count);
105 break;
106 case 1:
107 out = (d < s->count);
108 break;
109 case 2:
110 if ((d % s->count) == 0 && d != 0)
111 out = 1;
112 else
113 out = 0;
114 break;
115 case 3:
116 out = (d % s->count) < ((s->count + 1) >> 1);
117 break;
118 case 4:
119 case 5:
120 out = (d == s->count);
121 break;
122 }
123 return out;
124}
125
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000126int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
bellardec844b92004-05-03 23:18:25 +0000127{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000128 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardec844b92004-05-03 23:18:25 +0000129 PITChannelState *s = &pit->channels[channel];
130 return pit_get_out1(s, current_time);
131}
132
bellardb0a21b52004-03-31 18:58:38 +0000133/* return -1 if no transition will occur. */
ths5fafdf22007-09-16 21:08:06 +0000134static int64_t pit_get_next_transition_time(PITChannelState *s,
bellardb0a21b52004-03-31 18:58:38 +0000135 int64_t current_time)
bellard80cabfa2004-03-14 12:20:30 +0000136{
bellardb0a21b52004-03-31 18:58:38 +0000137 uint64_t d, next_time, base;
138 int period2;
bellard80cabfa2004-03-14 12:20:30 +0000139
Juan Quintela6ee093c2009-09-10 03:04:26 +0200140 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
141 get_ticks_per_sec());
bellard80cabfa2004-03-14 12:20:30 +0000142 switch(s->mode) {
143 default:
144 case 0:
bellard80cabfa2004-03-14 12:20:30 +0000145 case 1:
bellardb0a21b52004-03-31 18:58:38 +0000146 if (d < s->count)
147 next_time = s->count;
148 else
149 return -1;
bellard80cabfa2004-03-14 12:20:30 +0000150 break;
151 case 2:
bellardb0a21b52004-03-31 18:58:38 +0000152 base = (d / s->count) * s->count;
153 if ((d - base) == 0 && d != 0)
154 next_time = base + s->count;
155 else
156 next_time = base + s->count + 1;
bellard80cabfa2004-03-14 12:20:30 +0000157 break;
158 case 3:
bellardb0a21b52004-03-31 18:58:38 +0000159 base = (d / s->count) * s->count;
160 period2 = ((s->count + 1) >> 1);
ths5fafdf22007-09-16 21:08:06 +0000161 if ((d - base) < period2)
bellardb0a21b52004-03-31 18:58:38 +0000162 next_time = base + period2;
163 else
164 next_time = base + s->count;
bellard80cabfa2004-03-14 12:20:30 +0000165 break;
166 case 4:
167 case 5:
bellardb0a21b52004-03-31 18:58:38 +0000168 if (d < s->count)
169 next_time = s->count;
170 else if (d == s->count)
171 next_time = s->count + 1;
bellard80cabfa2004-03-14 12:20:30 +0000172 else
bellardb0a21b52004-03-31 18:58:38 +0000173 return -1;
bellard80cabfa2004-03-14 12:20:30 +0000174 break;
175 }
bellardb0a21b52004-03-31 18:58:38 +0000176 /* convert to timer units */
Juan Quintela6ee093c2009-09-10 03:04:26 +0200177 next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
178 PIT_FREQ);
bellard1154e442004-04-02 20:58:56 +0000179 /* fix potential rounding problems */
180 /* XXX: better solution: use a clock at PIT_FREQ Hz */
181 if (next_time <= current_time)
182 next_time = current_time + 1;
bellardb0a21b52004-03-31 18:58:38 +0000183 return next_time;
bellard80cabfa2004-03-14 12:20:30 +0000184}
185
186/* val must be 0 or 1 */
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000187void pit_set_gate(ISADevice *dev, int channel, int val)
bellard80cabfa2004-03-14 12:20:30 +0000188{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000189 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardec844b92004-05-03 23:18:25 +0000190 PITChannelState *s = &pit->channels[channel];
191
bellard80cabfa2004-03-14 12:20:30 +0000192 switch(s->mode) {
193 default:
194 case 0:
195 case 4:
196 /* XXX: just disable/enable counting */
197 break;
198 case 1:
199 case 5:
200 if (s->gate < val) {
201 /* restart counting on rising edge */
Paolo Bonzini74475452011-03-11 16:47:48 +0100202 s->count_load_time = qemu_get_clock_ns(vm_clock);
bellardb0a21b52004-03-31 18:58:38 +0000203 pit_irq_timer_update(s, s->count_load_time);
bellard80cabfa2004-03-14 12:20:30 +0000204 }
205 break;
206 case 2:
207 case 3:
208 if (s->gate < val) {
209 /* restart counting on rising edge */
Paolo Bonzini74475452011-03-11 16:47:48 +0100210 s->count_load_time = qemu_get_clock_ns(vm_clock);
bellardb0a21b52004-03-31 18:58:38 +0000211 pit_irq_timer_update(s, s->count_load_time);
bellard80cabfa2004-03-14 12:20:30 +0000212 }
213 /* XXX: disable/enable counting */
214 break;
215 }
216 s->gate = val;
217}
218
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000219int pit_get_gate(ISADevice *dev, int channel)
bellardec844b92004-05-03 23:18:25 +0000220{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000221 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardec844b92004-05-03 23:18:25 +0000222 PITChannelState *s = &pit->channels[channel];
223 return s->gate;
224}
225
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000226int pit_get_initial_count(ISADevice *dev, int channel)
bellardfd06c372006-04-24 21:58:30 +0000227{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000228 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardfd06c372006-04-24 21:58:30 +0000229 PITChannelState *s = &pit->channels[channel];
230 return s->count;
231}
232
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000233int pit_get_mode(ISADevice *dev, int channel)
bellardfd06c372006-04-24 21:58:30 +0000234{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000235 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardfd06c372006-04-24 21:58:30 +0000236 PITChannelState *s = &pit->channels[channel];
237 return s->mode;
238}
239
bellard80cabfa2004-03-14 12:20:30 +0000240static inline void pit_load_count(PITChannelState *s, int val)
241{
242 if (val == 0)
243 val = 0x10000;
Paolo Bonzini74475452011-03-11 16:47:48 +0100244 s->count_load_time = qemu_get_clock_ns(vm_clock);
bellard80cabfa2004-03-14 12:20:30 +0000245 s->count = val;
bellardb0a21b52004-03-31 18:58:38 +0000246 pit_irq_timer_update(s, s->count_load_time);
bellard80cabfa2004-03-14 12:20:30 +0000247}
248
bellardec844b92004-05-03 23:18:25 +0000249/* if already latched, do not latch again */
250static void pit_latch_count(PITChannelState *s)
251{
252 if (!s->count_latched) {
253 s->latched_count = pit_get_count(s);
254 s->count_latched = s->rw_mode;
255 }
256}
257
bellardb41a2cd2004-03-14 21:46:48 +0000258static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
bellard80cabfa2004-03-14 12:20:30 +0000259{
bellardec844b92004-05-03 23:18:25 +0000260 PITState *pit = opaque;
bellard80cabfa2004-03-14 12:20:30 +0000261 int channel, access;
262 PITChannelState *s;
263
264 addr &= 3;
265 if (addr == 3) {
266 channel = val >> 6;
bellardec844b92004-05-03 23:18:25 +0000267 if (channel == 3) {
268 /* read back command */
269 for(channel = 0; channel < 3; channel++) {
270 s = &pit->channels[channel];
271 if (val & (2 << channel)) {
272 if (!(val & 0x20)) {
273 pit_latch_count(s);
274 }
275 if (!(val & 0x10) && !s->status_latched) {
276 /* status latch */
277 /* XXX: add BCD and null count */
Paolo Bonzini74475452011-03-11 16:47:48 +0100278 s->status = (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
bellardec844b92004-05-03 23:18:25 +0000279 (s->rw_mode << 4) |
280 (s->mode << 1) |
281 s->bcd;
282 s->status_latched = 1;
283 }
284 }
285 }
286 } else {
287 s = &pit->channels[channel];
288 access = (val >> 4) & 3;
289 if (access == 0) {
290 pit_latch_count(s);
291 } else {
292 s->rw_mode = access;
293 s->read_state = access;
294 s->write_state = access;
295
296 s->mode = (val >> 1) & 7;
297 s->bcd = val & 1;
298 /* XXX: update irq timer ? */
299 }
bellard80cabfa2004-03-14 12:20:30 +0000300 }
301 } else {
bellardec844b92004-05-03 23:18:25 +0000302 s = &pit->channels[addr];
303 switch(s->write_state) {
304 default:
bellard80cabfa2004-03-14 12:20:30 +0000305 case RW_STATE_LSB:
306 pit_load_count(s, val);
307 break;
308 case RW_STATE_MSB:
309 pit_load_count(s, val << 8);
310 break;
311 case RW_STATE_WORD0:
bellardec844b92004-05-03 23:18:25 +0000312 s->write_latch = val;
313 s->write_state = RW_STATE_WORD1;
314 break;
bellard80cabfa2004-03-14 12:20:30 +0000315 case RW_STATE_WORD1:
bellardec844b92004-05-03 23:18:25 +0000316 pit_load_count(s, s->write_latch | (val << 8));
317 s->write_state = RW_STATE_WORD0;
bellard80cabfa2004-03-14 12:20:30 +0000318 break;
319 }
320 }
321}
322
bellardb41a2cd2004-03-14 21:46:48 +0000323static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
bellard80cabfa2004-03-14 12:20:30 +0000324{
bellardec844b92004-05-03 23:18:25 +0000325 PITState *pit = opaque;
bellard80cabfa2004-03-14 12:20:30 +0000326 int ret, count;
327 PITChannelState *s;
ths3b46e622007-09-17 08:09:54 +0000328
bellard80cabfa2004-03-14 12:20:30 +0000329 addr &= 3;
bellardec844b92004-05-03 23:18:25 +0000330 s = &pit->channels[addr];
331 if (s->status_latched) {
332 s->status_latched = 0;
333 ret = s->status;
334 } else if (s->count_latched) {
335 switch(s->count_latched) {
336 default:
337 case RW_STATE_LSB:
bellard80cabfa2004-03-14 12:20:30 +0000338 ret = s->latched_count & 0xff;
bellardec844b92004-05-03 23:18:25 +0000339 s->count_latched = 0;
340 break;
341 case RW_STATE_MSB:
342 ret = s->latched_count >> 8;
343 s->count_latched = 0;
344 break;
345 case RW_STATE_WORD0:
346 ret = s->latched_count & 0xff;
347 s->count_latched = RW_STATE_MSB;
348 break;
349 }
350 } else {
351 switch(s->read_state) {
352 default:
353 case RW_STATE_LSB:
354 count = pit_get_count(s);
355 ret = count & 0xff;
356 break;
357 case RW_STATE_MSB:
358 count = pit_get_count(s);
359 ret = (count >> 8) & 0xff;
360 break;
361 case RW_STATE_WORD0:
362 count = pit_get_count(s);
363 ret = count & 0xff;
364 s->read_state = RW_STATE_WORD1;
365 break;
366 case RW_STATE_WORD1:
367 count = pit_get_count(s);
368 ret = (count >> 8) & 0xff;
369 s->read_state = RW_STATE_WORD0;
370 break;
371 }
bellard80cabfa2004-03-14 12:20:30 +0000372 }
373 return ret;
374}
375
bellardb0a21b52004-03-31 18:58:38 +0000376static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
377{
378 int64_t expire_time;
379 int irq_level;
380
381 if (!s->irq_timer)
382 return;
383 expire_time = pit_get_next_transition_time(s, current_time);
bellardec844b92004-05-03 23:18:25 +0000384 irq_level = pit_get_out1(s, current_time);
pbrookd537cf62007-04-07 18:14:41 +0000385 qemu_set_irq(s->irq, irq_level);
bellardb0a21b52004-03-31 18:58:38 +0000386#ifdef DEBUG_PIT
387 printf("irq_level=%d next_delay=%f\n",
ths5fafdf22007-09-16 21:08:06 +0000388 irq_level,
Juan Quintela6ee093c2009-09-10 03:04:26 +0200389 (double)(expire_time - current_time) / get_ticks_per_sec());
bellardb0a21b52004-03-31 18:58:38 +0000390#endif
391 s->next_transition_time = expire_time;
392 if (expire_time != -1)
393 qemu_mod_timer(s->irq_timer, expire_time);
394 else
395 qemu_del_timer(s->irq_timer);
396}
397
398static void pit_irq_timer(void *opaque)
399{
400 PITChannelState *s = opaque;
401
402 pit_irq_timer_update(s, s->next_transition_time);
403}
404
Juan Quintela5122b432009-08-20 19:42:31 +0200405static const VMStateDescription vmstate_pit_channel = {
406 .name = "pit channel",
407 .version_id = 2,
408 .minimum_version_id = 2,
409 .minimum_version_id_old = 2,
410 .fields = (VMStateField []) {
411 VMSTATE_INT32(count, PITChannelState),
412 VMSTATE_UINT16(latched_count, PITChannelState),
413 VMSTATE_UINT8(count_latched, PITChannelState),
414 VMSTATE_UINT8(status_latched, PITChannelState),
415 VMSTATE_UINT8(status, PITChannelState),
416 VMSTATE_UINT8(read_state, PITChannelState),
417 VMSTATE_UINT8(write_state, PITChannelState),
418 VMSTATE_UINT8(write_latch, PITChannelState),
419 VMSTATE_UINT8(rw_mode, PITChannelState),
420 VMSTATE_UINT8(mode, PITChannelState),
421 VMSTATE_UINT8(bcd, PITChannelState),
422 VMSTATE_UINT8(gate, PITChannelState),
423 VMSTATE_INT64(count_load_time, PITChannelState),
424 VMSTATE_INT64(next_transition_time, PITChannelState),
425 VMSTATE_END_OF_LIST()
bellardb0a21b52004-03-31 18:58:38 +0000426 }
Juan Quintela5122b432009-08-20 19:42:31 +0200427};
bellardb0a21b52004-03-31 18:58:38 +0000428
Juan Quintela5122b432009-08-20 19:42:31 +0200429static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
bellardb0a21b52004-03-31 18:58:38 +0000430{
bellardec844b92004-05-03 23:18:25 +0000431 PITState *pit = opaque;
bellardb0a21b52004-03-31 18:58:38 +0000432 PITChannelState *s;
433 int i;
ths3b46e622007-09-17 08:09:54 +0000434
bellardb0a21b52004-03-31 18:58:38 +0000435 if (version_id != 1)
436 return -EINVAL;
437
438 for(i = 0; i < 3; i++) {
bellardec844b92004-05-03 23:18:25 +0000439 s = &pit->channels[i];
thsbee8d682007-12-16 23:41:11 +0000440 s->count=qemu_get_be32(f);
bellardb0a21b52004-03-31 18:58:38 +0000441 qemu_get_be16s(f, &s->latched_count);
bellardec844b92004-05-03 23:18:25 +0000442 qemu_get_8s(f, &s->count_latched);
443 qemu_get_8s(f, &s->status_latched);
444 qemu_get_8s(f, &s->status);
445 qemu_get_8s(f, &s->read_state);
446 qemu_get_8s(f, &s->write_state);
447 qemu_get_8s(f, &s->write_latch);
448 qemu_get_8s(f, &s->rw_mode);
bellardb0a21b52004-03-31 18:58:38 +0000449 qemu_get_8s(f, &s->mode);
450 qemu_get_8s(f, &s->bcd);
451 qemu_get_8s(f, &s->gate);
thsbee8d682007-12-16 23:41:11 +0000452 s->count_load_time=qemu_get_be64(f);
bellardb0a21b52004-03-31 18:58:38 +0000453 if (s->irq_timer) {
thsbee8d682007-12-16 23:41:11 +0000454 s->next_transition_time=qemu_get_be64(f);
bellardb0a21b52004-03-31 18:58:38 +0000455 qemu_get_timer(f, s->irq_timer);
456 }
457 }
458 return 0;
459}
460
Juan Quintela5122b432009-08-20 19:42:31 +0200461static const VMStateDescription vmstate_pit = {
462 .name = "i8254",
463 .version_id = 2,
464 .minimum_version_id = 2,
465 .minimum_version_id_old = 1,
466 .load_state_old = pit_load_old,
467 .fields = (VMStateField []) {
468 VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
469 VMSTATE_TIMER(channels[0].irq_timer, PITState),
470 VMSTATE_END_OF_LIST()
471 }
472};
473
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000474static void pit_reset(DeviceState *dev)
bellard80cabfa2004-03-14 12:20:30 +0000475{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000476 PITState *pit = container_of(dev, PITState, dev.qdev);
bellard80cabfa2004-03-14 12:20:30 +0000477 PITChannelState *s;
478 int i;
479
480 for(i = 0;i < 3; i++) {
bellardec844b92004-05-03 23:18:25 +0000481 s = &pit->channels[i];
bellard80cabfa2004-03-14 12:20:30 +0000482 s->mode = 3;
483 s->gate = (i != 2);
484 pit_load_count(s, 0);
485 }
bellardd7d02e32004-06-20 12:58:36 +0000486}
487
aliguori16b29ae2008-12-17 23:28:44 +0000488/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
489void hpet_pit_disable(void) {
490 PITChannelState *s;
491 s = &pit_state.channels[0];
aliguorie0dd1142009-01-26 20:32:18 +0000492 if (s->irq_timer)
493 qemu_del_timer(s->irq_timer);
aliguori16b29ae2008-12-17 23:28:44 +0000494}
495
aurel32c50c2d62008-12-18 22:42:43 +0000496/* When HPET is reset or leaving legacy mode, it must reenable i8254
aliguori16b29ae2008-12-17 23:28:44 +0000497 * timer 0
498 */
499
500void hpet_pit_enable(void)
501{
502 PITState *pit = &pit_state;
503 PITChannelState *s;
504 s = &pit->channels[0];
505 s->mode = 3;
506 s->gate = 1;
507 pit_load_count(s, 0);
508}
509
Richard Henderson60ea6aa2011-08-10 15:28:15 -0700510static const MemoryRegionPortio pit_portio[] = {
511 { 0, 4, 1, .write = pit_ioport_write },
512 { 0, 3, 1, .read = pit_ioport_read },
513 PORTIO_END_OF_LIST()
514};
515
516static const MemoryRegionOps pit_ioport_ops = {
517 .old_portio = pit_portio
518};
519
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000520static int pit_initfn(ISADevice *dev)
bellardd7d02e32004-06-20 12:58:36 +0000521{
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000522 PITState *pit = DO_UPCAST(PITState, dev, dev);
bellardd7d02e32004-06-20 12:58:36 +0000523 PITChannelState *s;
524
525 s = &pit->channels[0];
526 /* the timer 0 is connected to an IRQ */
Paolo Bonzini74475452011-03-11 16:47:48 +0100527 s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
Jan Kiszkaee951a32011-02-19 18:56:22 +0100528 s->irq = isa_get_irq(pit->irq);
bellard80cabfa2004-03-14 12:20:30 +0000529
Richard Henderson60ea6aa2011-08-10 15:28:15 -0700530 memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
531 isa_register_ioport(dev, &pit->ioports, pit->iobase);
bellardd7d02e32004-06-20 12:58:36 +0000532
Jan Kiszkaca22a3a2011-03-06 16:09:49 +0100533 qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
534
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000535 return 0;
bellard80cabfa2004-03-14 12:20:30 +0000536}
Blue Swirl64d7e9a2011-02-13 19:54:40 +0000537
538static ISADeviceInfo pit_info = {
539 .qdev.name = "isa-pit",
540 .qdev.size = sizeof(PITState),
541 .qdev.vmsd = &vmstate_pit,
542 .qdev.reset = pit_reset,
543 .qdev.no_user = 1,
544 .init = pit_initfn,
545 .qdev.props = (Property[]) {
546 DEFINE_PROP_UINT32("irq", PITState, irq, -1),
547 DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
548 DEFINE_PROP_END_OF_LIST(),
549 },
550};
551
552static void pit_register(void)
553{
554 isa_qdev_register(&pit_info);
555}
556device_init(pit_register)