1 #include "rtc.h"
2 #include <common/kprint.h>
3 
4 /*置位0x70的第7位,禁止不可屏蔽中断*/
5 
6 #define read_cmos(addr) ({                                                          \
7     io_out8(0x70, 0x80 | addr);  \
8     io_in8(0x71);                                                                   \
9 })
10 
11 enum CMOSTimeSelector
12 {
13     T_SECOND = 0x0,
14     T_MINUTE = 0x2,
15     T_HOUR = 0x4,
16     T_DAY = 0x7,
17     T_MONTH = 0x8,
18     T_YEAR = 0x9,
19 };
20 
21 
rtc_get_cmos_time(struct rtc_time_t * t)22 int rtc_get_cmos_time(struct rtc_time_t *t)
23 {
24     // 为防止中断请求打断该过程,需要先关中断
25     cli();
26 
27     uint8_t status_register_B = read_cmos(0x0B);                  // 读取状态寄存器B
28     bool is_24h = ((status_register_B & 0x02) ? true : false);    // 判断是否启用24小时模式
29     bool is_binary = ((status_register_B & 0x04) ? true : false); // 判断是否为二进制码
30 
31     do
32     {
33         t->year = read_cmos(0x09);
34         t->month = read_cmos(0x08);
35         t->day = read_cmos(0x07);
36         t->hour = read_cmos(0x04);
37         t->minute = read_cmos(0x02);
38         t->second = read_cmos(0x00);
39     } while (t->second != read_cmos(0x00)); // 若读取时间过程中时间发生跳变则重新读取
40     // 使能NMI中断
41     io_out8(0x70, 0x00);
42 
43     if (!is_binary) // 把BCD转为二进制
44     {
45         t->second = (t->second & 0xf) + (t->second >> 4) * 10;
46         t->minute = (t->minute & 0xf) + (t->minute >> 4) * 10;
47         t->hour = ((t->hour & 0xf) + ((t->hour & 0x70) >> 4) * 10) | (t->hour & 0x80);
48         t->day = (t->day & 0xf) + ((t->day / 16) * 10);
49         t->month = (t->month & 0xf) + (t->month >> 4) * 10;
50         t->year = (t->year & 0xf) + (t->year >> 4) * 10;
51     }
52     t->year += 2000;
53 
54     if ((!is_24h) && t->hour & 0x80) // 将十二小时制转为24小时
55         t->hour = ((t->hour & 0x7f) + 12) % 24;
56     sti();
57     return 0;
58 }
59