PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
rtc.c
Go to the documentation of this file.
1#include <kernel/cpu/io.h>
2#include <kernel/log/log.h>
7
8#include <kernel/sync/lock.h>
9#include <time.h>
10
11/**
12 * @brief Real Time Clock
13 * @defgroup kernel_drivers_rtc RTC
14 * @ingroup kernel_drivers
15 *
16 * The RTC driver provides functions to read the current time from the CMOS RTC.
17 *
18 * @see [OSDev CMOS](https://wiki.osdev.org/CMOS)
19 *
20 * @{
21 */
22
24
26static port_t dataPort = 0;
28
30{
31 io_out8(addressPort, reg | 0x80); // Force NMI disable
32 return io_in8(dataPort);
33}
34
35static int rtc_update_in_progress(void)
36{
37 return (rtc_read(0x0A) & 0x80);
38}
39
41{
42 return (bcd >> 4) * 10 + (bcd & 0x0F);
43}
44
46{
48
50 {
51 asm volatile("pause");
52 }
53
54 uint8_t seconds = rtc_bcd_to_bin(rtc_read(0x00));
55 uint8_t minutes = rtc_bcd_to_bin(rtc_read(0x02));
56 uint8_t hours = rtc_bcd_to_bin(rtc_read(0x04));
57 uint8_t day = rtc_bcd_to_bin(rtc_read(0x07));
58 uint8_t month = rtc_bcd_to_bin(rtc_read(0x08));
59 uint8_t year = rtc_bcd_to_bin(rtc_read(0x09));
60
61 uint16_t fullYear;
62 if (centuryRegister != 0)
63 {
65 fullYear = cent * 100 + year;
66 }
67 else
68 {
69 fullYear = (year >= 70) ? (1900 + year) : (2000 + year);
70 }
71
72 struct tm stime = (struct tm){
73 .tm_sec = seconds,
74 .tm_min = minutes,
75 .tm_hour = hours,
76 .tm_mday = day,
77 .tm_mon = month - 1,
78 .tm_year = fullYear - 1900,
79 };
80
81 return mktime(&stime);
82}
83
85 .name = "CMOS RTC",
86 .precision = CLOCKS_PER_SEC,
87 .read_ns = NULL,
88 .read_epoch = rtc_read_epoch,
89};
90
91static uint64_t rtc_init(const char* deviceName)
92{
94
95 acpi_device_cfg_t* acpiCfg = acpi_device_cfg_lookup(deviceName);
96 if (acpiCfg == NULL)
97 {
98 LOG_ERR("rtc failed to get ACPI device config for '%s'\n", deviceName);
99 return ERR;
100 }
101
102 if (acpi_device_cfg_get_port(acpiCfg, 0, &addressPort) == ERR ||
103 acpi_device_cfg_get_port(acpiCfg, 1, &dataPort) == ERR)
104 {
105 LOG_ERR("rtc device '%s' has invalid port resources\n", deviceName);
106 return ERR;
107 }
108
110 if (fadt != NULL)
111 {
112 centuryRegister = fadt->century;
113 }
114
116 {
117 LOG_ERR("failed to register RTC\n");
118 return ERR;
119 }
120
121 return 0;
122}
123
124/** @} */
125
127{
128 switch (event->type)
129 {
131 if (rtc_init(event->deviceAttach.name) == ERR)
132 {
133 LOG_ERR("failed to initialize RTC\n");
134 return ERR;
135 }
136 break;
137 default:
138 break;
139 }
140 return 0;
141}
142
143MODULE_INFO("RTC Driver", "Kai Norberg", "A driver for the CMOS Real Time Clock", OS_VERSION, "MIT", "PNP0B00");
#define CLOCKS_PER_SEC
Definition clock_t.h:15
static void io_out8(port_t port, uint8_t val)
Write an 8-bit value to an I/O port.
Definition io.h:71
static uint8_t io_in8(port_t port)
Read an 8-bit value from an I/O port.
Definition io.h:82
uint16_t port_t
I/O port type.
Definition io.h:27
static uint64_t rtc_init(const char *deviceName)
Definition rtc.c:91
static uint8_t centuryRegister
Definition rtc.c:23
static int rtc_update_in_progress(void)
Definition rtc.c:35
static port_t dataPort
Definition rtc.c:26
static time_t rtc_read_epoch(void)
Definition rtc.c:45
static port_t addressPort
Definition rtc.c:25
static lock_t lock
Definition rtc.c:27
static uint8_t rtc_read(uint8_t reg)
Definition rtc.c:29
static clock_source_t source
Definition rtc.c:84
static uint8_t rtc_bcd_to_bin(uint8_t bcd)
Definition rtc.c:40
#define LOG_ERR(format,...)
Definition log.h:108
#define MODULE_INFO(_name, _author, _description, _version, _licence, _deviceTypes)
Macro to define module information.
Definition module.h:200
@ MODULE_EVENT_DEVICE_ATTACH
Definition module.h:251
uint64_t clock_source_register(const clock_source_t *source)
Register a system timer source.
Definition clock.c:47
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:68
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
acpi_device_cfg_t * acpi_device_cfg_lookup(const char *name)
Retrieves the ACPI device configuration for a device by its name.
Definition devices.c:567
uint64_t acpi_device_cfg_get_port(acpi_device_cfg_t *cfg, uint64_t index, port_t *out)
Retrieves an the nth IO port assigned to an ACPI device.
Definition devices.c:603
#define FADT_SIGNATURE
FADT table signature.
Definition tables.h:103
sdt_header_t * acpi_tables_lookup(const char *signature, uint64_t minSize, uint64_t n)
Lookup the n'th table matching the signature.
Definition tables.c:260
uint64_t _module_procedure(const module_event_t *event)
Definition rtc.c:126
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
ACPI device configuration structure.
Definition devices.h:112
Clock source structure.
Definition clock.h:33
const char * name
Definition clock.h:34
Fixed ACPI Description Table.
Definition tables.h:45
uint8_t century
Definition tables.h:81
A simple ticket lock implementation.
Definition lock.h:43
struct module_event_t::@4::@6 deviceAttach
module_event_type_t type
Definition module.h:268
char * name
Definition module.h:273
Definition time.h:21
int tm_sec
Definition time.h:22
_PUBLIC time_t mktime(struct tm *timeptr)
Definition mktime.c:5
long long unsigned time_t
Definition time_t.h:4