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 46 fwd_set_label(char *label) 47 { 48 target_label = label; 49 return OK; 50 } 51 52 int 53 fwd_init(void) 54 { 55 if (target_label == NULL) { 56 return EINVAL; 57 } 58 return OK; 59 } 60 61 static int 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 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 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 111 fwd_pwr_off(void) 112 { 113 return fwd_msg(RTCDEV_PWR_OFF, NULL, 0, RTCDEV_NOFLAGS); 114 } 115 116 void 117 fwd_exit(void) 118 { 119 target_label = NULL; 120 } 121