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 /* Let SEF perform startup. */ 164 sef_startup(); 165 } 166 167 int 168 bcd_to_dec(int n) 169 { 170 return ((n >> 4) & 0x0F) * 10 + (n & 0x0F); 171 } 172 173 int 174 dec_to_bcd(int n) 175 { 176 return ((n / 10) << 4) | (n % 10); 177 } 178 179 static int 180 fetch_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t) 181 { 182 return sys_datacopy(who_e, rtcdev_tm, SELF, (vir_bytes) t, 183 sizeof(struct tm)); 184 } 185 186 static int 187 store_t(endpoint_t who_e, vir_bytes rtcdev_tm, struct tm *t) 188 { 189 return sys_datacopy(SELF, (vir_bytes) t, who_e, rtcdev_tm, 190 sizeof(struct tm)); 191 } 192