AquilaOS documentation
How it works, and its code
Toggle main menu visibility
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
16
static
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
30
struct
pit_cmd_register
{
31
union
{
32
struct
{
33
uint32_t
bcd
: 1;
34
uint32_t
mode
: 3;
35
uint32_t
access
: 2;
36
uint32_t
channel
: 2;
37
}
__packed
;
38
uint8_t
raw
;
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
52
int
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
62
static
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
82
uint32_t
x86_pit_period_set
(
uint32_t
period_ns)
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
123
void
x86_pit_delay
(
uint32_t
us)
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
}
io_in8
static uint8_t io_in8(struct ioaddr *io, uintptr_t off)
Reads an 8-, 16- or 32-bit register.
Definition
io.h:28
io_out8
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
ioaddr_type_str
static char * ioaddr_type_str(struct ioaddr *io)
Definition
io.h:101
IOADDR_PORT
#define IOADDR_PORT
Definition
io.h:89
system.h
__packed
#define __packed
Definition
system.h:30
io.h
kargs_get
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
Definition
kargs.c:73
kargs.h
misc.h
x86_pit_period_set
uint32_t x86_pit_period_set(uint32_t period_ns)
Makes channel 0 interrupt periodically, for the scheduler's tick.
Definition
pit.c:82
x86_pit_setup
int x86_pit_setup(struct ioaddr *io)
Sets where the PIT's ports are.
Definition
pit.c:52
x86_pit_delay
void x86_pit_delay(uint32_t us)
Waits us microseconds, at most 54 ms, busy.
Definition
pit.c:123
PIT_GATE_PORT
#define PIT_GATE_PORT
Definition
pit.c:23
OUT2
#define OUT2
Definition
pit.c:26
GATE2
#define GATE2
Definition
pit.c:24
PIT_CHANNEL2
#define PIT_CHANNEL2
Definition
pit.c:19
PIT_MODE_SQUARE_WAVE
#define PIT_MODE_SQUARE_WAVE
Definition
pit.c:43
SPEAKER
#define SPEAKER
Definition
pit.c:25
PIT_ACCESS_LOHIBYTE
#define PIT_ACCESS_LOHIBYTE
Definition
pit.c:44
FBASE
#define FBASE
Definition
pit.c:59
PIT_CHANNEL0
#define PIT_CHANNEL0
Definition
pit.c:18
PIT_CMD
#define PIT_CMD
Definition
pit.c:20
atou32
static uint32_t atou32(const char *s)
Converts a decimal string to a number.
Definition
pit.c:62
pit_ioaddr
static struct ioaddr pit_ioaddr
Definition
pit.c:16
printk
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition
printk.c:249
NULL
#define NULL
Definition
stddef.h:27
uint32_t
unsigned int uint32_t
Definition
stddef.h:22
uint8_t
unsigned char uint8_t
Definition
stddef.h:20
string.h
ioaddr
Where a device's registers are.
Definition
io.h:95
ioaddr::addr
uintptr_t addr
Definition
io.h:97
pit_cmd_register::[union].__unnamed0__::[struct].__unnamed0__.__unnamed0__::bcd
uint32_t bcd
pit_cmd_register::[union].__unnamed0__::[struct].__unnamed0__.__unnamed0__::channel
uint32_t channel
pit_cmd_register::[union].__unnamed0__::[struct].__unnamed0__.__unnamed0__::access
uint32_t access
pit_cmd_register::[union].__unnamed0__::[struct].__unnamed0__.__unnamed0__::mode
uint32_t mode
pit_cmd_register
The PIT's command register: which channel, how it is loaded, and in which mode it counts.
Definition
pit.c:30
pit_cmd_register::[union].__unnamed0__::raw
uint8_t raw
kernel
arch
i386
platform
misc
pit.c
Generated by
1.18.0