xref: /minix3/minix/drivers/clock/readclock/readclock.c (revision 3f82ac6a4e188419336747098d0d6616cd2f3d3d)
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
main(int argc,char ** argv)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
sef_cb_init(int type,sef_init_info_t * UNUSED (info))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
sef_local_startup()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
bcd_to_dec(int n)168 bcd_to_dec(int n)
169 {
170 	return ((n >> 4) & 0x0F) * 10 + (n & 0x0F);
171 }
172 
173 int
dec_to_bcd(int n)174 dec_to_bcd(int n)
175 {
176 	return ((n / 10) << 4) | (n % 10);
177 }
178 
179 static int
fetch_t(endpoint_t who_e,vir_bytes rtcdev_tm,struct tm * t)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
store_t(endpoint_t who_e,vir_bytes rtcdev_tm,struct tm * t)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