1 /* $NetBSD: ofrtc.c,v 1.4 1997/04/16 23:41:53 thorpej Exp $ */ 2 3 /* 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/device.h> 36 37 #include <dev/ofw/openfirm.h> 38 39 struct ofrtc_softc { 40 struct device sc_dev; 41 int sc_phandle; 42 int sc_ihandle; 43 }; 44 45 static int ofrtcprobe __P((struct device *, struct cfdata *, void *)); 46 static void ofrtcattach __P((struct device *, struct device *, void *)); 47 48 struct cfattach ofrtc_ca = { 49 sizeof(struct ofrtc_softc), ofrtcprobe, ofrtcattach 50 }; 51 52 struct cfdriver ofrtc_cd = { 53 NULL, "ofrtc", DV_DULL 54 }; 55 56 static int 57 ofrtcprobe(parent, match, aux) 58 struct device *parent; 59 struct cfdata *match; 60 void *aux; 61 { 62 struct ofprobe *ofp = aux; 63 char type[8]; 64 int l; 65 66 if ((l = OF_getprop(ofp->phandle, "device_type", type, sizeof type - 1)) < 0) 67 return 0; 68 if (l >= sizeof type) 69 return 0; 70 71 return !strcmp(type, "rtc"); 72 } 73 74 static void 75 ofrtcattach(parent, self, aux) 76 struct device *parent, *self; 77 void *aux; 78 { 79 struct ofrtc_softc *of = (void *)self; 80 struct ofprobe *ofp = aux; 81 char name[32]; 82 int l; 83 84 of->sc_phandle = ofp->phandle; 85 of->sc_ihandle = 0; 86 if ((l = OF_getprop(of->sc_phandle, "name", name, sizeof name - 1)) < 0) 87 panic("Device without name?"); 88 if (l >= sizeof name) 89 l = sizeof name - 1; 90 name[l] = 0; 91 printf(": %s\n", name); 92 } 93 94 int 95 ofrtcopen(dev, flags, fmt) 96 dev_t dev; 97 int flags; 98 int fmt; 99 { 100 struct ofrtc_softc *of; 101 int unit = minor(dev); 102 char path[256]; 103 int l; 104 105 if (unit >= ofrtc_cd.cd_ndevs) 106 return ENXIO; 107 if (!(of = ofrtc_cd.cd_devs[unit])) 108 return ENXIO; 109 if (!of->sc_ihandle) { 110 if ((l = OF_package_to_path(of->sc_phandle, path, sizeof path - 1)) < 0) 111 return ENXIO; 112 if (l >= sizeof path) 113 return ENXIO; 114 path[l] = 0; 115 116 if (!(of->sc_ihandle = OF_open(path))) { 117 if (of->sc_ihandle) { 118 OF_close(of->sc_ihandle); 119 of->sc_ihandle = 0; 120 } 121 return ENXIO; 122 } 123 124 } 125 126 return 0; 127 } 128 129 int 130 ofrtcclose(dev, flags, fmt) 131 dev_t dev; 132 int flags; 133 int fmt; 134 { 135 return 0; 136 } 137 138 static void 139 twodigit(bp, i) 140 char *bp; 141 int i; 142 { 143 *bp++ = i / 10 + '0'; 144 *bp = i % 10 + '0'; 145 } 146 147 static int 148 twodigits(bp) 149 char *bp; 150 { 151 int i; 152 153 i = *bp++ - '0'; 154 return i * 10 + *bp++ - '0'; 155 } 156 157 int 158 ofrtcread(dev, uio, flag) 159 dev_t dev; 160 struct uio *uio; 161 int flag; 162 { 163 struct ofrtc_softc *of = ofrtc_cd.cd_devs[minor(dev)]; 164 int date[6]; 165 char buf[14]; 166 int xlen; 167 168 if (uio->uio_offset >= sizeof buf) 169 return 0; 170 171 if (OF_call_method("get-time", of->sc_ihandle, 0, 6, 172 date, date + 1, date + 2, 173 date + 3, date + 4, date + 5)) 174 return EIO; 175 176 twodigit(buf, date[5] % 100); 177 twodigit(buf + 2, date[4]); 178 twodigit(buf + 4, date[3]); 179 twodigit(buf + 6, date[2]); 180 twodigit(buf + 8, date[1]); 181 buf[10] = '.'; 182 twodigit(buf + 11, date[0]); 183 buf[13] = '\n'; 184 185 xlen = sizeof(buf) - uio->uio_offset; 186 if (xlen > uio->uio_resid) 187 xlen = uio->uio_resid; 188 189 return uiomove((caddr_t)buf, xlen, uio); 190 } 191 192 int 193 ofrtcwrite(dev, uio, flag) 194 dev_t dev; 195 struct uio *uio; 196 int flag; 197 { 198 struct ofrtc_softc *of = ofrtc_cd.cd_devs[minor(dev)]; 199 char buf[14]; 200 int cnt, year, error; 201 202 /* 203 * We require atomic updates! 204 */ 205 cnt = uio->uio_resid; 206 if (uio->uio_offset || (cnt != sizeof buf && cnt != sizeof buf - 1)) 207 return EINVAL; 208 209 if (error = uiomove((caddr_t)buf, sizeof buf, uio)) 210 return error; 211 212 if (cnt == sizeof buf && buf[sizeof buf - 1] != '\n') 213 return EINVAL; 214 215 year = twodigits(buf) + 1900; 216 if (year < 1970) 217 year += 100; 218 if (OF_call_method("set-time", of->sc_ihandle, 6, 0, 219 twodigits(buf + 11), twodigits(buf + 8), twodigits(buf + 6), 220 twodigits(buf + 4), twodigits(buf + 2), year)) 221 return EIO; 222 return 0; 223 } 224