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