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