123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- /*
- * clock.c
- *
- * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <clock.h>
- #include <exception.h>
- #include <syscalls.h>
- #include <irq.h>
- #include <user.h>
- static clock_time_t clock_current_time;
- static byte_t clock_settings;
- void clock_irq(registers_t *regs, byte_t irq_num)
- {
- bool_t pm = FALSE;
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_SECONDS_REG);
- byte_t seconds = cpu_read_port_byte(CMOS_DATA_PORT);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MINUTES_REG);
- byte_t minutes = cpu_read_port_byte(CMOS_DATA_PORT);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_HOURS_REG);
- byte_t hours = cpu_read_port_byte(CMOS_DATA_PORT);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_DAY_REG);
- byte_t day = cpu_read_port_byte(CMOS_DATA_PORT);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MONTH_REG);
- byte_t month = cpu_read_port_byte(CMOS_DATA_PORT);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_YEAR_REG);
- byte_t year = cpu_read_port_byte(CMOS_DATA_PORT);
- if (hours & CLOCK_PM_BIT) pm = TRUE;
- hours &= ~CLOCK_PM_BIT;
- if (!(clock_settings & CLOCK_BINARY_MODE))
- {
- hours = (hours >> 4) * 10 + (hours & 0x0F);
- minutes = (minutes >> 4) * 10 + (minutes & 0x0F);
- seconds = (seconds >> 4) * 10 + (seconds & 0x0F);
- day = (day >> 4) * 10 + (day & 0x0F);
- month = (month >> 4) * 10 + (month & 0x0F);
- year = (year >> 4) * 10 + (year & 0x0F);
- }
- if (!(clock_settings & CLOCK_24HOUR_MODE))
- {
- if (pm) hours += 12;
- else if (hours == 12) hours = 0;
- }
- clock_current_time.seconds = seconds;
- clock_current_time.minutes = minutes;
- clock_current_time.hours = hours;
- clock_current_time.day = day;
- clock_current_time.month = month;
- clock_current_time.year = year;
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STC_REG);
- cpu_read_port_byte(CMOS_DATA_PORT);
- }
- bool_t clock_check_time(clock_time_t *time)
- {
- byte_t max_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- if (time->year % 4 == 0 && (time->year % 100 != 0 || time->year % 400 == 0)) max_days[1]++;
- if (time->seconds >= 60) return FALSE;
- if (time->minutes >= 60) return FALSE;
- if (time->hours >= 24) return FALSE;
- if (time->month > 12 || time->month == 0) return FALSE;
- if (time->day > max_days[time->month - 1]) return FALSE;
- return TRUE;
- }
- sysret_t syscall_clock_get_time(clock_time_t *time)
- {
- if (get_previous_mode() != KERNEL_MODE && !check_usermode(time, sizeof(clock_time_t)))
- {
- return ERR_BADPTR;
- }
- EH_TRY
- {
- time->seconds = clock_current_time.seconds;
- time->minutes = clock_current_time.minutes;
- time->hours = clock_current_time.hours;
- time->day = clock_current_time.day;
- time->month = clock_current_time.month;
- time->year = clock_current_time.year;
- }
- EH_CATCH
- {
- EH_ESCAPE(return ERR_BADPTR);
- }
- EH_DONE;
- return ERR_SUCCESS;
- }
- sysret_t syscall_clock_set_time(clock_time_t *time)
- {
- clock_time_t safe_time = {0};
- if (get_previous_mode() == USER_MODE)
- {
- if (!check_usermode(time, sizeof(clock_time_t))) return ERR_BADPTR;
- EH_TRY safe_time = *time;
- EH_CATCH EH_ESCAPE(return ERR_BADPTR);
- EH_DONE;
- if (!check_privileges(PRIVILEGE_SET_TIME)) return ERR_FORBIDDEN;
- }
- else
- {
- safe_time = *time;
- }
- if (!clock_check_time(&safe_time)) return ERR_INVALID;
- byte_t seconds = safe_time.seconds;
- byte_t minutes = safe_time.minutes;
- byte_t hours = safe_time.hours;
- byte_t day = safe_time.day;
- byte_t month = safe_time.month;
- byte_t year = safe_time.year;
- if (!(clock_settings & CLOCK_BINARY_MODE))
- {
- hours = ((hours / 10) << 4) + (hours % 10);
- minutes = ((minutes / 10) << 4) + (minutes % 10);
- seconds = ((seconds / 10) << 4) + (seconds % 10);
- day = ((day / 10) << 4) + (day % 10);
- month = ((month / 10) << 4) + (month % 10);
- year = ((year / 10) << 4) + (year % 10);
- }
- if (!(clock_settings & CLOCK_24HOUR_MODE) && (hours > 12)) hours |= CLOCK_PM_BIT;
- critical_t critical;
- enter_critical(&critical);
- clock_current_time.seconds = safe_time.seconds;
- clock_current_time.minutes = safe_time.minutes;
- clock_current_time.hours = safe_time.hours;
- clock_current_time.day = safe_time.day;
- clock_current_time.month = safe_time.month;
- clock_current_time.year = safe_time.year;
- disable_nmi();
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_SECONDS_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, seconds);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MINUTES_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, minutes);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_HOURS_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, hours);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_DAY_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, day);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MONTH_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, month);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_YEAR_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, year);
- enable_nmi();
- leave_critical(&critical);
- return ERR_SUCCESS;
- }
- void clock_init()
- {
- critical_t critical;
- enter_critical(&critical);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STB_REG);
- clock_settings = cpu_read_port_byte(CMOS_DATA_PORT);
- if ((clock_settings & (CLOCK_ALARM_INT | CLOCK_PERIODIC_INT | CLOCK_UPDATE_INT)) != CLOCK_UPDATE_INT)
- {
- clock_settings &= ~(CLOCK_ALARM_INT | CLOCK_PERIODIC_INT);
- clock_settings |= CLOCK_UPDATE_INT;
- disable_nmi();
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STB_REG);
- cpu_write_port_byte(CMOS_DATA_PORT, clock_settings);
- enable_nmi();
- }
- register_irq_handler(CLOCK_IRQ, &clock_irq, FALSE);
- cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STC_REG);
- cpu_read_port_byte(CMOS_DATA_PORT);
- leave_critical(&critical);
- }
|