1 /* readclock - manipulate the hardware real time clock */ 2 3 #include <sys/types.h> 4 #include <stdlib.h> 5 #include <unistd.h> 6 #include <stdio.h> 7 #include <time.h> 8 #include <errno.h> 9 #include <lib.h> 10 #include <minix/type.h> 11 #include <minix/const.h> 12 #include <minix/callnr.h> 13 #include <minix/log.h> 14 #include <minix/syslib.h> 15 #include <minix/sysutil.h> 16 #include <minix/com.h> 17 #include <minix/type.h> 18 #include <minix/safecopies.h> 19 #include <sys/svrctl.h> 20 21 #include "readclock.h" 22 23 static struct rtc rtc; 24 25 static struct log log = { 26 .name = "readclock", 27 .log_level = LEVEL_INFO, 28 .log_func = default_log 29 }; 30 31 /* functions for transfering struct tm to/from this driver and calling proc. */ 32 static int fetch_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t); 33 static int store_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t); 34 35 /* SEF functions and variables. */ 36 static void sef_local_startup(void); 37 static int sef_cb_init(int type, sef_init_info_t * info); 38 39 int 40 main(int argc, char **argv) 41 { 42 int r; 43 endpoint_t caller; 44 struct tm t; 45 message m; 46 int ipc_status, reply_status; 47 48 env_setargs(argc, argv); 49 sef_local_startup(); 50 51 while (TRUE) { 52 53 /* Receive Message */ 54 r = sef_receive_status(ANY, &m, &ipc_status); 55 if (r != OK) { 56 log_warn(&log, "sef_receive_status() failed\n"); 57 continue; 58 } 59 60 if (is_ipc_notify(ipc_status)) { 61 62 /* Do not reply to notifications. */ 63 continue; 64 } 65 66 caller = m.m_source; 67 68 log_debug(&log, "Got message 0x%x from 0x%x\n", m.m_type, 69 caller); 70 71 switch (m.m_type) { 72 case RTCDEV_GET_TIME: 73 /* Any user can read the time */ 74 reply_status = rtc.get_time(&t, m.m_lc_readclock_rtcdev.flags); 75 if (reply_status != OK) { 76 break; 77 } 78 79 /* write results back to calling process */ 80 reply_status = 81 store_t(caller, m.m_lc_readclock_rtcdev.tm, &t); 82 break; 83 84 case RTCDEV_SET_TIME: 85 /* Only super user is allowed to set the time */ 86 if (getnuid(caller) == SUPER_USER) { 87 /* read time from calling process */ 88 reply_status = 89 fetch_t(caller, m.m_lc_readclock_rtcdev.tm, 90 &t); 91 if (reply_status != OK) { 92 break; 93 } 94 95 reply_status = 96 rtc.set_time(&t, m.m_lc_readclock_rtcdev.flags); 97 } else { 98 reply_status = EPERM; 99 } 100 break; 101 102 case RTCDEV_PWR_OFF: 103 /* Only PM is allowed to set the power off time */ 104 if (caller == PM_PROC_NR) { 105 reply_status = rtc.pwr_off(); 106 } else { 107 reply_status = EPERM; 108 } 109 break; 110 111 default: 112 /* Unrecognized call */ 113 reply_status = EINVAL; 114 break; 115 } 116 117 /* Send Reply */ 118 m.m_type = RTCDEV_REPLY; 119 m.m_readclock_lc_rtcdev.status = reply_status; 120 121 log_debug(&log, "Sending Reply"); 122 123 r = ipc_sendnb(caller, &m); 124 if (r != OK) { 125 log_warn(&log, "ipc_sendnb() failed\n"); 126 continue; 127 } 128 } 129 130 rtc.exit(); 131 return 0; 132 } 133 134 static int 135 sef_cb_init(int type, sef_init_info_t * UNUSED(info)) 136 { 137 int r; 138 139 r = arch_setup(&rtc); 140 if (r != OK) { 141 log_warn(&log, "Clock setup failed\n"); 142 return r; 143 } 144 145 r = rtc.init(); 146 if (r != OK) { 147 log_warn(&log, "Clock initalization failed\n"); 148 return r; 149 } 150 151 return OK; 152 } 153 154 static void 155 sef_local_startup() 156 { 157 /* 158 * Register init callbacks. Use the same function for all event types 159 */ 160 sef_setcb_init_fresh(sef_cb_init); 161 sef_setcb_init_lu(sef_cb_init); 162 sef_setcb_init_restart(sef_cb_init); 163 164 /* 165 * Register live update callbacks. 166 */ 167 /* Agree to update immediately when LU is requested in a valid state. */ 168 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 169 /* Support live update starting from any standard state. */ 170 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard); 171 172 /* Let SEF perform startup. */ 173 sef_startup(); 174 } 175 176 int 177 bcd_to_dec(int n) 178 { 179 return ((n >> 4) & 0x0F) * 10 + (n & 0x0F); 180 } 181 182 int 183 dec_to_bcd(int n) 184 { 185 return ((n / 10) << 4) | (n % 10); 186 } 187 188 static int 189 fetch_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t) 190 { 191 return sys_datacopy(who_e, rtcdev_tm, SELF, (vir_bytes) t, 192 sizeof(struct tm)); 193 } 194 195 static int 196 store_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t) 197 { 198 return sys_datacopy(SELF, (vir_bytes) t, who_e, rtcdev_tm, 199 sizeof(struct tm)); 200 } 201