Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


timer fix for linux guest
[palacios.git] / palacios / src / devices / 8254.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_dev_mgr.h>
23 #include <palacios/vmm_time.h>
24 #include <palacios/vmm_util.h>
25 #include <palacios/vmm_intr.h>
26 #include <palacios/vmm_config.h>
27 #include <palacios/vmm_io.h>
28
29
30 #ifndef V3_CONFIG_DEBUG_PIT
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36
37 // constants
38 #define OSC_HZ 1193182
39
40
41 /* The 8254 has three counters and one control port */
42 #define CHANNEL0_PORT 0x40
43 #define CHANNEL1_PORT 0x41
44 #define CHANNEL2_PORT 0x42
45 #define COMMAND_PORT 0x43
46 #define SPEAKER_PORT 0x61
47
48
49 #define PIT_INTR_NUM 0
50 #define PIT_SPEAKER_GATE 0x01
51
52 /* The order of these typedefs is important because the numerical values correspond to the 
53  * values coming from the io ports
54  */
55 typedef enum {NOT_RUNNING, PENDING, RUNNING} channel_run_state_t;
56 typedef enum {NOT_WAITING, WAITING_LOBYTE, WAITING_HIBYTE} channel_access_state_t;
57 typedef enum {LATCH_COUNT = 0, LOBYTE_ONLY = 1, HIBYTE_ONLY = 2, LOBYTE_HIBYTE = 3} channel_access_mode_t;
58 typedef enum {IRQ_ON_TERM_CNT = 0, ONE_SHOT = 1, RATE_GEN = 2, SQR_WAVE = 3, SW_STROBE = 4, HW_STROBE = 5} channel_op_mode_t;
59
60
61 struct channel {
62     channel_access_mode_t access_mode;
63     channel_access_state_t access_state;
64     channel_run_state_t run_state;
65
66     channel_op_mode_t op_mode;
67
68
69     // Time til interrupt trigger 
70
71     ushort_t counter;
72     ushort_t reload_value;
73
74     ushort_t latched_value;
75   
76     enum {NOTLATCHED, LATCHED} latch_state;
77
78     enum {LSB, MSB} read_state;
79
80     uint_t output_pin : 1;
81     uint_t gate_input_pin : 1;
82 };
83
84
85 struct pit {
86
87     ullong_t pit_counter;
88     ullong_t pit_reload;
89
90     struct v3_timer * timer;
91
92     struct v3_vm_info * vm;
93
94     struct channel ch_0;
95     struct channel ch_1;
96     struct channel ch_2;
97     uint8_t speaker;
98 };
99
100
101 struct pit_cmd_word {
102     uint_t bcd_mode    : 1;
103     uint_t op_mode     : 3;
104     uint_t access_mode : 2;
105     uint_t channel     : 2;
106 };
107
108 struct pit_rdb_cmd_word {
109     uint_t rsvd         : 1; // SBZ
110     uint_t ch_0         : 1;
111     uint_t ch_1         : 1;
112     uint_t ch_2         : 1;
113     uint_t latch_status : 1;
114     uint_t latch_count  : 1;
115     uint_t readback_cmd : 2; // Must Be 0x3
116 };
117
118 struct pit_rdb_status_word {
119     uint_t bcd_mode     : 1;
120     uint_t op_mode      : 3;
121     uint_t access_mode  : 2;
122     uint_t null_count   : 1;
123     uint_t pin_state    : 1; 
124 };
125
126
127
128 /* 
129  * This should call out to handle_SQR_WAVE_tics, etc... 
130  */
131 // Returns true if the the output signal changed state
132 static int handle_crystal_tics(struct pit * pit, struct channel * ch, uint_t oscillations) {
133     uint_t channel_cycles = 0;
134     uint_t output_changed = 0;
135   
136     // PrintDebug("8254 PIT: %d crystal tics\n", oscillations);
137     if (ch->run_state == PENDING) {
138         oscillations--;
139         ch->counter = ch->reload_value;
140
141         if (ch->op_mode == SQR_WAVE) {
142             ch->counter -= ch->counter % 2;
143         }
144
145         ch->run_state = RUNNING;
146     } else if (ch->run_state != RUNNING) {
147         return output_changed;
148     }
149
150     /*
151       PrintDebug("8254 PIT: Channel Run State = %d, counter=", ch->run_state);
152       PrintTraceLL(ch->counter);
153       PrintDebug("\n");
154     */
155     if (ch->op_mode == SQR_WAVE) {
156         oscillations *= 2;
157     }
158
159     if (ch->counter > oscillations) {
160         ch->counter -= oscillations;
161         return output_changed;
162     } else {
163         ushort_t reload_val = ch->reload_value; 
164
165         if (ch->op_mode == SW_STROBE) {
166             reload_val = 0xffff;
167         }
168
169         oscillations -= ch->counter;
170         ch->counter = 0;
171         channel_cycles = 1;
172
173         if (ch->op_mode == SQR_WAVE) {
174             reload_val -= reload_val % 2;
175         }
176
177         // TODO: Check this....
178         // Is this correct???
179         if (reload_val == 0) {
180             reload_val = 1;
181         }
182
183         channel_cycles += oscillations / reload_val;
184         oscillations = oscillations % reload_val;
185
186         ch->counter = reload_val - oscillations;
187     }
188
189     //  PrintDebug("8254 PIT: Channel Cycles: %d\n", channel_cycles);
190   
191
192
193     switch (ch->op_mode) {
194         case IRQ_ON_TERM_CNT:
195             if ((channel_cycles > 0) && (ch->output_pin == 0)) {
196                 ch->output_pin = 1; 
197                 output_changed = 1;
198             }
199             break;
200         case ONE_SHOT:
201             if ((channel_cycles > 0) && (ch->output_pin == 0)) {
202                 ch->output_pin = 1; 
203                 output_changed = 1;
204             }
205             break;
206         case RATE_GEN:
207             // See the data sheet: we ignore the output pin cycle...
208             if (channel_cycles > 0) {
209                 output_changed = 1;
210             }
211             break;
212         case SQR_WAVE:
213             ch->output_pin = (ch->output_pin + 1) % 2;
214
215             if (ch->output_pin == 1) {
216                 output_changed = 1;
217             }
218
219             break;
220         case SW_STROBE:
221
222             if (channel_cycles > 0) {
223                 if (ch->output_pin == 1) {
224                     ch->output_pin = 0;
225                     output_changed = 1;
226                 }
227             }
228             break;
229         case HW_STROBE:
230             PrintError("Hardware strobe not implemented\n");
231             return -1;
232             break;
233         default:
234             break;
235     }
236
237     return output_changed;
238 }
239                                 
240
241 #include <palacios/vm_guest.h>
242
243 static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
244     struct pit * state = (struct pit *)private_data;
245     //  ullong_t tmp_ctr = state->pit_counter;
246     ullong_t tmp_cycles;
247     uint_t oscillations = 0;
248
249
250     /*
251       PrintDebug("updating cpu_cycles=");
252       PrintTraceLL(cpu_cycles);
253       PrintDebug("\n");
254     
255       PrintDebug("pit_counter=");
256       PrintTraceLL(state->pit_counter);
257       PrintDebug("\n");
258     
259       PrintDebug("pit_reload=");
260       PrintTraceLL(state->pit_reload);
261       PrintDebug("\n");
262     */
263
264     if (state->pit_counter > cpu_cycles) {
265         // Easy...
266         state->pit_counter -= cpu_cycles;
267     } else {
268         ushort_t reload_val = state->pit_reload;
269         // Take off the first part
270         cpu_cycles -= state->pit_counter;
271         state->pit_counter = 0;
272         oscillations = 1;
273     
274         if (cpu_cycles > state->pit_reload) {
275             // how many full oscillations
276       
277             //PrintError("cpu_cycles = %p, reload = %p...\n", 
278             //   (void *)(addr_t)cpu_cycles, 
279             //   (void *)(addr_t)state->pit_reload);
280
281             // How do we check for a one shot....
282             if (state->pit_reload == 0) {
283                 reload_val = 1;
284             }
285
286             tmp_cycles = cpu_cycles;
287
288       
289 #ifdef __V3_64BIT__
290             cpu_cycles = tmp_cycles % state->pit_reload;
291             tmp_cycles = tmp_cycles / state->pit_reload;
292 #else
293             cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
294 #endif
295         
296             oscillations += tmp_cycles;
297         }
298
299         // update counter with remainder (mod reload)
300         state->pit_counter = state->pit_reload - cpu_cycles;    
301
302         if (oscillations) {
303             PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
304         }
305
306         if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
307             // raise interrupt
308             // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
309             v3_raise_irq(info->vm_info, 0);
310         }
311
312         //handle_crystal_tics(state, &(state->ch_1), oscillations);
313         handle_crystal_tics(state, &(state->ch_2), oscillations);
314     }
315   
316
317
318  
319     return;
320 }
321
322 /* This should call out to handle_SQR_WAVE_write, etc...
323  */
324 static int handle_channel_write(struct channel * ch, char val) {
325
326     switch (ch->access_state) {      
327         case WAITING_HIBYTE:
328             {
329                 ushort_t tmp_val = ((ushort_t)val) << 8;
330                 ch->reload_value &= 0x00ff;
331                 ch->reload_value |= tmp_val;
332         
333
334                 if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)){
335                     ch->run_state = PENDING;  
336                 }
337         
338                 if (ch->access_mode == LOBYTE_HIBYTE) {
339                     ch->access_state = WAITING_LOBYTE;
340                 }
341
342                 PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);        
343                 PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
344                 break;
345             }
346         case WAITING_LOBYTE:
347             ch->reload_value &= 0xff00;
348             ch->reload_value |= val;
349       
350             if (ch->access_mode == LOBYTE_HIBYTE) {
351                 ch->access_state = WAITING_HIBYTE;
352             } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
353                 ch->run_state = PENDING;
354             }
355       
356             PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);
357             PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
358             break;
359         default:
360             PrintError("Invalid Access state\n");
361             return -1;
362     }
363     
364
365     switch (ch->op_mode) {
366         case IRQ_ON_TERM_CNT:
367             ch->output_pin = 0;
368             break;
369         case ONE_SHOT:
370             ch->output_pin = 1;
371             break;
372         case RATE_GEN:
373             ch->output_pin = 1;
374             break;
375         case SQR_WAVE:
376             ch->output_pin = 1;
377             break;
378         case SW_STROBE:
379             ch->output_pin = 1;
380             break;
381         default:
382             PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
383             return -1;
384             break;
385     }
386
387
388     return 0;
389 }
390
391
392 static int handle_channel_read(struct channel * ch, char * val) {
393
394     ushort_t * myval;
395
396     if (ch->latch_state == NOTLATCHED) { 
397         myval = &(ch->counter);
398     } else {
399         myval = &(ch->latched_value);
400     }
401
402     if (ch->read_state == LSB) { 
403         *val = ((char*)myval)[0];  // little endian
404         ch->read_state = MSB;
405     } else {
406         *val = ((char*)myval)[1];
407         ch->read_state = LSB;
408         if (ch->latch_state == LATCHED) { 
409             ch->latch_state = NOTLATCHED;
410         }
411     }
412
413     return 0;
414
415 }
416
417 static int handle_speaker_read(uint8_t *speaker, struct channel * ch, char * val) {
418     *val = *speaker;
419
420     if ((*speaker & PIT_SPEAKER_GATE)) {
421         *val |= (ch->output_pin << 5);
422     }
423     
424     return 0;
425 }
426
427 static int handle_speaker_write(uint8_t *speaker, struct channel * ch, char val) {
428     *speaker = (val & ~0x20);
429     return 0;
430 }
431
432 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
433
434     ch->access_mode = cmd.access_mode;
435
436     if (ch->access_mode != 0) {
437         ch->op_mode = cmd.op_mode;
438     }
439
440
441     switch (cmd.access_mode) {
442         case LATCH_COUNT:
443             if (ch->latch_state == NOTLATCHED) { 
444                 ch->latched_value = ch->counter;
445                 ch->latch_state = LATCHED;
446             }
447             break;
448         case HIBYTE_ONLY:
449             ch->access_state = WAITING_HIBYTE;
450             break;
451         case LOBYTE_ONLY: 
452         case LOBYTE_HIBYTE:
453             ch->access_state = WAITING_LOBYTE;
454             break;
455     }
456
457
458     switch (cmd.op_mode) {
459         case IRQ_ON_TERM_CNT:
460             ch->output_pin = 0;
461             break;
462         case ONE_SHOT: 
463             ch->output_pin = 1;
464             break;
465         case RATE_GEN: 
466             ch->output_pin = 1;
467             break;
468         case SQR_WAVE:
469             ch->output_pin = 1;
470             break;
471         case SW_STROBE:
472             ch->output_pin = 1;
473             break;
474         default:
475             PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
476             return -1;
477     }
478
479     return 0;
480     
481 }
482
483
484
485
486 static int pit_read_channel(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
487     struct pit * state = (struct pit *)priv_data;
488     char * val = (char *)dst;
489
490     if (length != 1) {
491         PrintError("8254 PIT: Invalid Read Write length \n");
492         return -1;
493     }
494
495     PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
496
497     switch (port) {
498         case CHANNEL0_PORT: 
499             if (handle_channel_read(&(state->ch_0), val) == -1) {
500                 PrintError("CHANNEL0 read error\n");
501                 return -1;
502             }
503             break;
504         case CHANNEL1_PORT:
505             if (handle_channel_read(&(state->ch_1), val) == -1) {
506                 PrintError("CHANNEL1 read error\n");
507                 return -1;
508             }
509             break;
510         case CHANNEL2_PORT:
511             if (handle_channel_read(&(state->ch_2), val) == -1) {
512                 PrintError("CHANNEL2 read error\n");
513                 return -1;
514             }
515             break;
516         case SPEAKER_PORT:
517             if (handle_speaker_read(&state->speaker, &(state->ch_2), val) == -1) {
518                 PrintError("SPEAKER read error\n");
519                 return -1;
520             }
521             break;
522         default:
523             PrintError("8254 PIT: Read from invalid port (%d)\n", port);
524             return -1;
525     }
526
527     return length;
528 }
529
530
531
532 static int pit_write_channel(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
533     struct pit * state = (struct pit *)priv_data;
534     char val = *(char *)src;
535
536     if (length != 1) {
537         PrintError("8254 PIT: Invalid Write Length\n");
538         return -1;
539     }
540
541     PrintDebug("8254 PIT: Write to PIT Channel %d (%x)\n", port - CHANNEL0_PORT, *(char*)src);
542
543
544     switch (port) {
545         case CHANNEL0_PORT:
546             if (handle_channel_write(&(state->ch_0), val) == -1) {
547                 PrintError("CHANNEL0 write error\n");
548                 return -1;
549             } 
550             break;
551         case CHANNEL1_PORT:
552             if (handle_channel_write(&(state->ch_1), val) == -1) {
553                 PrintError("CHANNEL1 write error\n");
554                 return -1;
555             }
556             break;
557         case CHANNEL2_PORT:
558             if (handle_channel_write(&(state->ch_2), val) == -1) {
559                 PrintError("CHANNEL2 write error\n");   
560                 return -1;
561             }
562             break;
563         case SPEAKER_PORT:
564             if (handle_speaker_write(&state->speaker, &(state->ch_2), val) == -1) {
565                 PrintError("SPEAKER write error\n");
566                 return -1;
567             }
568             break;
569         default:
570             PrintError("8254 PIT: Write to invalid port (%d)\n", port);
571             return -1;
572     }
573
574     return length;
575 }
576
577
578
579
580 static int pit_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
581     struct pit * state = (struct pit *)priv_data;
582     struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
583
584     PrintDebug("8254 PIT: Write to PIT Command port\n");
585     PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
586     if (length != 1) {
587         PrintError("8254 PIT: Write of Invalid length to command port\n");
588         return -1;
589     }
590
591     switch (cmd->channel) {
592         case 0:
593             if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
594                 PrintError("CHANNEL0 command error\n");
595                 return -1;
596             }
597             break;
598         case 1:
599             if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
600                 PrintError("CHANNEL1 command error\n");
601                 return -1;
602             }
603             break;
604         case 2:
605             if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
606                 PrintError("CHANNEL2 command error\n");
607                 return -1;
608             }
609             break;
610         case 3:
611             // Read Back command
612             PrintError("Read back command not implemented\n");
613             return -1;
614             break;
615         default:
616             break;
617     }
618
619
620     return length;
621 }
622
623
624
625
626 static struct v3_timer_ops timer_ops = {
627     .update_timer = pit_update_timer,
628 };
629
630
631 static void init_channel(struct channel * ch) {
632     ch->run_state = NOT_RUNNING;
633     ch->access_state = NOT_WAITING;
634     ch->access_mode = 0;
635     ch->op_mode = 0;
636
637     ch->counter = 0;
638     ch->reload_value = 0;
639     ch->output_pin = 0;
640     ch->gate_input_pin = 0;
641
642     ch->latched_value = 0;
643     ch->latch_state = NOTLATCHED;
644     ch->read_state = LSB;
645
646     return;
647 }
648
649
650
651
652 static int pit_free(void * private_data) {
653     struct pit * state = (struct pit *)private_data;
654     struct guest_info * info = &(state->vm->cores[0]);
655
656
657     if (state->timer) {
658         v3_remove_timer(info, state->timer);
659     }
660  
661     V3_Free(state);
662     return 0;
663 }
664
665 #ifdef V3_CONFIG_KEYED_STREAMS
666 static int pit_checkpoint(struct vm_device *dev, v3_keyed_stream_t stream)
667 {
668     struct pit *p = (struct pit *) (dev->private_data);
669
670     v3_keyed_stream_key_t ks;
671
672     ks = v3_keyed_stream_open_key(stream,dev->name);
673
674     if (!ks) { 
675         return -1;
676     }
677
678     STD_SAVE(stream,ks,p->pit_counter);
679     STD_SAVE(stream,ks,p->pit_reload);
680     STD_SAVE(stream,ks,p->ch_0);
681     STD_SAVE(stream,ks,p->ch_1);
682     STD_SAVE(stream,ks,p->ch_2);
683     STD_SAVE(stream,ks,p->speaker);
684
685     v3_keyed_stream_close_key(stream,ks);
686     
687     return 0;
688
689
690 }
691
692 static int pit_restore(struct vm_device *dev, v3_keyed_stream_t stream)
693 {
694     struct pit *p = (struct pit *) (dev->private_data);
695
696     v3_keyed_stream_key_t ks;
697
698     ks = v3_keyed_stream_open_key(stream,dev->name);
699
700     if (!ks) { 
701         return -1;
702     }
703
704     STD_LOAD(stream,ks,p->pit_counter);
705     STD_LOAD(stream,ks,p->pit_reload);
706     STD_LOAD(stream,ks,p->ch_0);
707     STD_LOAD(stream,ks,p->ch_1);
708     STD_LOAD(stream,ks,p->ch_2);
709     STD_LOAD(stream,ks,p->speaker);
710
711     v3_keyed_stream_close_key(stream,ks);
712     
713     return 0;
714
715
716 }
717 #endif
718
719 static struct v3_device_ops dev_ops = {
720     .free = (int (*)(void *))pit_free,
721 #ifdef V3_CONFIG_KEYED_STREAMS
722     .checkpoint = pit_checkpoint,
723     .restore = pit_restore,
724 #endif
725 };
726
727 #include <palacios/vm_guest.h>
728
729 static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
730     struct pit * pit_state = NULL;
731     struct vm_device * dev = NULL;
732     char * dev_id = v3_cfg_val(cfg, "ID");
733     int ret = 0;
734
735     // PIT is only usable in non-multicore environments
736     // just hardcode the core context
737     struct guest_info * info = &(vm->cores[0]);
738
739     uint_t cpu_khz = info->time_state.guest_cpu_freq;
740     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
741
742     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
743
744     V3_ASSERT(pit_state != NULL);
745     pit_state->speaker = 0;
746     pit_state->vm = vm;
747
748     dev = v3_add_device(vm, dev_id, &dev_ops, pit_state);
749
750     if (dev == NULL) {
751         PrintError("Could not attach device %s\n", dev_id);
752         V3_Free(pit_state);
753         return -1;
754     }
755
756     ret |= v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
757     ret |= v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
758     ret |= v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
759     ret |= v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
760     ret |= v3_dev_hook_io(dev, SPEAKER_PORT, &pit_read_channel, &pit_write_channel);
761
762     if (ret != 0) {
763         PrintError("8254 PIT: Failed to hook IO ports\n");
764         v3_remove_device(dev);
765         return -1;
766     }
767
768 #ifdef V3_CONFIG_DEBUG_PIT
769     PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
770     //PrintTrace(reload_val);
771     PrintDebug("\n");
772 #endif
773
774     
775
776     pit_state->timer = v3_add_timer(info, &timer_ops, pit_state);
777
778     if (pit_state->timer == NULL) {
779         v3_remove_device(dev);
780         return -1;
781     }
782
783     // Get cpu frequency and calculate the global pit oscilattor counter/cycle
784
785     do_divll(reload_val, OSC_HZ);
786     pit_state->pit_counter = reload_val;
787     pit_state->pit_reload = reload_val;
788
789
790     init_channel(&(pit_state->ch_0));
791     init_channel(&(pit_state->ch_1));
792     init_channel(&(pit_state->ch_2));
793
794 #ifdef V3_CONFIG_DEBUG_PIT
795     PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
796     //PrintTraceLL(pit_state->pit_counter);
797     PrintDebug("\n");
798 #endif
799
800     return 0;
801 }
802
803
804 device_register("8254_PIT", pit_init);