xref: /minix3/minix/drivers/clock/readclock/forward.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /*
2  * Some real time clocks are embedded within other multi-function chips.
3  * Drivers for such chips will implement the RTCDEV protocol and the
4  * readclock driver will simply forward on the message to the driver.
5  * This keeps things simple for any other services that need to access
6  * the RTC as they only have to know / care about the readclock driver.
7  */
8 
9 #include <minix/syslib.h>
10 #include <minix/drvlib.h>
11 #include <minix/sysutil.h>
12 #include <minix/log.h>
13 #include <minix/rs.h>
14 #include <minix/ds.h>
15 #include <minix/safecopies.h>
16 
17 #include <sys/mman.h>
18 #include <sys/types.h>
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <time.h>
27 #include <lib.h>
28 
29 #include "forward.h"
30 #include "readclock.h"
31 
32 static int fwd_msg(int type, struct tm *t, int t_access, int flags);
33 
34 static struct log log = {
35 	.name = "readclock.fwd",
36 	.log_level = LEVEL_INFO,
37 	.log_func = default_log
38 };
39 
40 /*
41  * Label of the driver that messages should be forwarded to.
42  */
43 static char *target_label;
44 
45 int
fwd_set_label(char * label)46 fwd_set_label(char *label)
47 {
48 	target_label = label;
49 	return OK;
50 }
51 
52 int
fwd_init(void)53 fwd_init(void)
54 {
55 	if (target_label == NULL) {
56 		return EINVAL;
57 	}
58 	return OK;
59 }
60 
61 static int
fwd_msg(int type,struct tm * t,int t_access,int flags)62 fwd_msg(int type, struct tm *t, int t_access, int flags)
63 {
64 	int r;
65 	message m;
66 	endpoint_t ep;
67 	cp_grant_id_t gid;
68 
69 	r = ds_retrieve_label_endpt(target_label, &ep);
70 	if (r != 0) {
71 		return -1;
72 	}
73 
74 	if (type == RTCDEV_PWR_OFF) {
75 		/* RTCDEV_PWR_OFF messages don't contain any data/flags. */
76 		return _syscall(ep, RTCDEV_PWR_OFF, &m);
77 	}
78 
79 	gid = cpf_grant_direct(ep, (vir_bytes) t, sizeof(struct tm), t_access);
80 	if (!GRANT_VALID(gid)) {
81 		log_warn(&log, "Could not create grant.\n");
82 		return -1;
83 	}
84 
85 	m.m_lc_readclock_rtcdev.grant = gid;
86 	m.m_lc_readclock_rtcdev.flags = flags;
87 
88 	r = _syscall(ep, type, &m);
89 	cpf_revoke(gid);
90 	if (r != RTCDEV_REPLY || m.m_readclock_lc_rtcdev.status != 0) {
91 		log_warn(&log, "Call to '%s' failed.\n", target_label);
92 		return -1;
93 	}
94 
95 	return OK;
96 }
97 
98 int
fwd_get_time(struct tm * t,int flags)99 fwd_get_time(struct tm *t, int flags)
100 {
101 	return fwd_msg(RTCDEV_GET_TIME_G, t, CPF_WRITE, flags);
102 }
103 
104 int
fwd_set_time(struct tm * t,int flags)105 fwd_set_time(struct tm *t, int flags)
106 {
107 	return fwd_msg(RTCDEV_SET_TIME_G, t, CPF_READ, flags);
108 }
109 
110 int
fwd_pwr_off(void)111 fwd_pwr_off(void)
112 {
113 	return fwd_msg(RTCDEV_PWR_OFF, NULL, 0, RTCDEV_NOFLAGS);
114 }
115 
116 void
fwd_exit(void)117 fwd_exit(void)
118 {
119 	target_label = NULL;
120 }
121