AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
pit.c
Go to the documentation of this file.
1
9
10#include <core/system.h>
11#include <core/string.h>
12#include <core/kargs.h>
13#include <cpu/io.h>
14#include <platform/misc.h>
15
16static struct ioaddr pit_ioaddr;
17
18#define PIT_CHANNEL0 0x00
19#define PIT_CHANNEL2 0x02
20#define PIT_CMD 0x03
21
22/* channel 2's gate and output, in the speaker's port */
23#define PIT_GATE_PORT 0x61
24#define GATE2 0x01
25#define SPEAKER 0x02
26#define OUT2 0x20
27
31 union {
32 struct {
33 uint32_t bcd : 1;
34 uint32_t mode : 3;
35 uint32_t access : 2;
37 } __packed;
39 } __packed;
40} __packed;
41
42#define PIT_MODE_RATE_GENERATOR 0x2
43#define PIT_MODE_SQUARE_WAVE 0x3
44#define PIT_ACCESS_LOHIBYTE 0x3
45
52int x86_pit_setup(struct ioaddr *io)
53{
54 printk("i8254: Initializing [%p (%s)]\n", io->addr, ioaddr_type_str(io));
55 pit_ioaddr = *io;
56 return 0;
57}
58
59#define FBASE 1193182ULL /* the PIT's oscillator runs at 1.193182 MHz */
60
62static uint32_t atou32(const char *s)
63{
64 uint32_t ret = 0;
65
66 while (*s) {
67 ret = ret * 10 + (*s - '0');
68 ++s;
69 }
70
71 return ret;
72}
73
83{
84 printk("i8254: requested period %d ns\n", period_ns);
85
86 uint32_t div;
87 const char *arg_div = NULL;
88
89 if (!kargs_get("i8254.div", &arg_div) && arg_div) {
90 div = atou32(arg_div);
91 } else {
92 div = period_ns/838UL;
93 }
94
95 /* the divisor register is 16 bits wide */
96 if (div == 0) div = 1;
97 if (div > 0xFFFF) div = 0xFFFF;
98
99 period_ns = 1000000000UL/(FBASE/div);
100
101 printk("i8254: Setting period to %d ns (div = %d)\n", period_ns, div);
102
103 struct pit_cmd_register cmd = {
104 .bcd = 0,
105 .mode = PIT_MODE_SQUARE_WAVE,
106 .access = PIT_ACCESS_LOHIBYTE,
107 .channel = 0,
108 };
109
110 io_out8(&pit_ioaddr, PIT_CMD, cmd.raw);
111 io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 0) & 0xFF);
112 io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 8) & 0xFF);
113
114 return period_ns;
115}
116
124{
125 struct ioaddr gate = {.addr = PIT_GATE_PORT, .type = IOADDR_PORT};
126 uint32_t count = (uint32_t) (FBASE * us / 1000000ULL);
127
128 if (count > 0xFFFF)
129 count = 0xFFFF;
130
131 /* the gate off, and the speaker off */
132 io_out8(&gate, 0, (io_in8(&gate, 0) & ~(GATE2 | SPEAKER)));
133
134 struct pit_cmd_register cmd = {
135 .bcd = 0,
136 .mode = 0, /* "interrupt on terminal count": count down once */
137 .access = PIT_ACCESS_LOHIBYTE,
138 .channel = 2,
139 };
140
141 io_out8(&pit_ioaddr, PIT_CMD, cmd.raw);
142 io_out8(&pit_ioaddr, PIT_CHANNEL2, count & 0xFF);
143 io_out8(&pit_ioaddr, PIT_CHANNEL2, count >> 8);
144
145 /* the gate on: it counts */
146 io_out8(&gate, 0, (io_in8(&gate, 0) & ~SPEAKER) | GATE2);
147
148 /* bounded (each read takes a microsecond or more), so that a machine
149 * without a PIT doesn't hang: the wait is then too short, and what it
150 * timed is wrong, which the message says */
151 long i;
152
153 for (i = 0; i < 10000000 && !(io_in8(&gate, 0) & OUT2); ++i)
154 ;
155
156 if (i == 10000000)
157 printk("i8254: channel 2 didn't count down: no PIT?\n");
158
159 io_out8(&gate, 0, io_in8(&gate, 0) & ~GATE2);
160}
static uint8_t io_in8(struct ioaddr *io, uintptr_t off)
Reads an 8-, 16- or 32-bit register.
Definition io.h:28
static void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)
Writes an 8-, 16- or 32-bit register.
Definition io.h:44
static char * ioaddr_type_str(struct ioaddr *io)
Definition io.h:101
#define IOADDR_PORT
Definition io.h:89
#define __packed
Definition system.h:30
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
Definition kargs.c:73
uint32_t x86_pit_period_set(uint32_t period_ns)
Makes channel 0 interrupt periodically, for the scheduler's tick.
Definition pit.c:82
int x86_pit_setup(struct ioaddr *io)
Sets where the PIT's ports are.
Definition pit.c:52
void x86_pit_delay(uint32_t us)
Waits us microseconds, at most 54 ms, busy.
Definition pit.c:123
#define PIT_GATE_PORT
Definition pit.c:23
#define OUT2
Definition pit.c:26
#define GATE2
Definition pit.c:24
#define PIT_CHANNEL2
Definition pit.c:19
#define PIT_MODE_SQUARE_WAVE
Definition pit.c:43
#define SPEAKER
Definition pit.c:25
#define PIT_ACCESS_LOHIBYTE
Definition pit.c:44
#define FBASE
Definition pit.c:59
#define PIT_CHANNEL0
Definition pit.c:18
#define PIT_CMD
Definition pit.c:20
static uint32_t atou32(const char *s)
Converts a decimal string to a number.
Definition pit.c:62
static struct ioaddr pit_ioaddr
Definition pit.c:16
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
Where a device's registers are.
Definition io.h:95
uintptr_t addr
Definition io.h:97
The PIT's command register: which channel, how it is loaded, and in which mode it counts.
Definition pit.c:30