summaryrefslogtreecommitdiffstats
path: root/pintos-progos/devices/pit.c
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/devices/pit.c')
-rw-r--r--pintos-progos/devices/pit.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/pintos-progos/devices/pit.c b/pintos-progos/devices/pit.c
new file mode 100644
index 0000000..bfb1889
--- /dev/null
+++ b/pintos-progos/devices/pit.c
@@ -0,0 +1,83 @@
1#include "devices/pit.h"
2#include <debug.h>
3#include <stdint.h>
4#include "threads/interrupt.h"
5#include "threads/io.h"
6
7/* Interface to 8254 Programmable Interrupt Timer (PIT).
8 Refer to [8254] for details. */
9
10/* 8254 registers. */
11#define PIT_PORT_CONTROL 0x43 /* Control port. */
12#define PIT_PORT_COUNTER(CHANNEL) (0x40 + (CHANNEL)) /* Counter port. */
13
14/* PIT cycles per second. */
15#define PIT_HZ 1193180
16
17/* Configure the given CHANNEL in the PIT. In a PC, the PIT's
18 three output channels are hooked up like this:
19
20 - Channel 0 is connected to interrupt line 0, so that it can
21 be used as a periodic timer interrupt, as implemented in
22 Pintos in devices/timer.c.
23
24 - Channel 1 is used for dynamic RAM refresh (in older PCs).
25 No good can come of messing with this.
26
27 - Channel 2 is connected to the PC speaker, so that it can
28 be used to play a tone, as implemented in Pintos in
29 devices/speaker.c.
30
31 MODE specifies the form of output:
32
33 - Mode 2 is a periodic pulse: the channel's output is 1 for
34 most of the period, but drops to 0 briefly toward the end
35 of the period. This is useful for hooking up to an
36 interrupt controller to generate a periodic interrupt.
37
38 - Mode 3 is a square wave: for the first half of the period
39 it is 1, for the second half it is 0. This is useful for
40 generating a tone on a speaker.
41
42 - Other modes are less useful.
43
44 FREQUENCY is the number of periods per second, in Hz. */
45void
46pit_configure_channel (int channel, int mode, int frequency)
47{
48 uint16_t count;
49 enum intr_level old_level;
50
51 ASSERT (channel == 0 || channel == 2);
52 ASSERT (mode == 2 || mode == 3);
53
54 /* Convert FREQUENCY to a PIT counter value. The PIT has a
55 clock that runs at PIT_HZ cycles per second. We must
56 translate FREQUENCY into a number of these cycles. */
57 if (frequency < 19)
58 {
59 /* Frequency is too low: the quotient would overflow the
60 16-bit counter. Force it to 0, which the PIT treats as
61 65536, the highest possible count. This yields a 18.2
62 Hz timer, approximately. */
63 count = 0;
64 }
65 else if (frequency > PIT_HZ)
66 {
67 /* Frequency is too high: the quotient would underflow to
68 0, which the PIT would interpret as 65536. A count of 1
69 is illegal in mode 2, so we force it to 2, which yields
70 a 596.590 kHz timer, approximately. (This timer rate is
71 probably too fast to be useful anyhow.) */
72 count = 2;
73 }
74 else
75 count = (PIT_HZ + frequency / 2) / frequency;
76
77 /* Configure the PIT mode and load its counters. */
78 old_level = intr_disable ();
79 outb (PIT_PORT_CONTROL, (channel << 6) | 0x30 | (mode << 1));
80 outb (PIT_PORT_COUNTER (channel), count);
81 outb (PIT_PORT_COUNTER (channel), count >> 8);
82 intr_set_level (old_level);
83}