1 /* $NetBSD: ofcons.c,v 1.3 1996/10/13 01:38:11 christos Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 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/conf.h> 36 #include <sys/device.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/tty.h> 40 41 #include <dev/cons.h> 42 43 #include <dev/ofw/openfirm.h> 44 45 struct ofc_softc { 46 struct device of_dev; 47 struct tty *of_tty; 48 int of_flags; 49 }; 50 /* flags: */ 51 #define OFPOLL 1 52 53 #define OFBURSTLEN 128 /* max number of bytes to write in one chunk */ 54 55 static int stdin, stdout; 56 57 static int ofcmatch __P((struct device *, void *, void *)); 58 static void ofcattach __P((struct device *, struct device *, void *)); 59 60 struct cfattach ofcons_ca = { 61 sizeof(struct ofc_softc), ofcmatch, ofcattach 62 }; 63 64 struct cfdriver ofcons_cd = { 65 NULL, "ofcons", DV_TTY 66 }; 67 68 static int ofcprobe __P((void)); 69 70 static int 71 ofcmatch(parent, match, aux) 72 struct device *parent; 73 void *match, *aux; 74 { 75 struct ofprobe *ofp = aux; 76 77 if (!ofcprobe()) 78 return 0; 79 return OF_instance_to_package(stdin) == ofp->phandle 80 || OF_instance_to_package(stdout) == ofp->phandle; 81 } 82 83 static void 84 ofcattach(parent, self, aux) 85 struct device *parent, *self; 86 void *aux; 87 { 88 printf("\n"); 89 } 90 91 static void ofcstart __P((struct tty *)); 92 static int ofcparam __P((struct tty *, struct termios *)); 93 static void ofcpoll __P((void *)); 94 95 int 96 ofcopen(dev, flag, mode, p) 97 dev_t dev; 98 int flag, mode; 99 struct proc *p; 100 { 101 struct ofc_softc *sc; 102 int unit = minor(dev); 103 struct tty *tp; 104 105 if (unit >= ofcons_cd.cd_ndevs) 106 return ENXIO; 107 sc = ofcons_cd.cd_devs[unit]; 108 if (!sc) 109 return ENXIO; 110 if (!(tp = sc->of_tty)) 111 sc->of_tty = tp = ttymalloc(); 112 tp->t_oproc = ofcstart; 113 tp->t_param = ofcparam; 114 tp->t_dev = dev; 115 if (!(tp->t_state & TS_ISOPEN)) { 116 tp->t_state |= TS_WOPEN; 117 ttychars(tp); 118 tp->t_iflag = TTYDEF_IFLAG; 119 tp->t_oflag = TTYDEF_OFLAG; 120 tp->t_cflag = TTYDEF_CFLAG; 121 tp->t_lflag = TTYDEF_LFLAG; 122 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 123 ofcparam(tp, &tp->t_termios); 124 ttsetwater(tp); 125 } else if ((tp->t_state&TS_XCLUDE) && suser(p->p_ucred, &p->p_acflag)) 126 return EBUSY; 127 tp->t_state |= TS_CARR_ON; 128 129 if (!(sc->of_flags & OFPOLL)) { 130 sc->of_flags |= OFPOLL; 131 timeout(ofcpoll, sc, 1); 132 } 133 134 return (*linesw[tp->t_line].l_open)(dev, tp); 135 } 136 137 int 138 ofcclose(dev, flag, mode, p) 139 dev_t dev; 140 int flag, mode; 141 struct proc *p; 142 { 143 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 144 struct tty *tp = sc->of_tty; 145 146 untimeout(ofcpoll, sc); 147 sc->of_flags &= ~OFPOLL; 148 (*linesw[tp->t_line].l_close)(tp, flag); 149 ttyclose(tp); 150 return 0; 151 } 152 153 int 154 ofcread(dev, uio, flag) 155 dev_t dev; 156 struct uio *uio; 157 int flag; 158 { 159 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 160 struct tty *tp = sc->of_tty; 161 162 return (*linesw[tp->t_line].l_read)(tp, uio, flag); 163 } 164 165 int 166 ofcwrite(dev, uio, flag) 167 dev_t dev; 168 struct uio *uio; 169 int flag; 170 { 171 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 172 struct tty *tp = sc->of_tty; 173 174 return (*linesw[tp->t_line].l_write)(tp, uio, flag); 175 } 176 177 int 178 ofcioctl(dev, cmd, data, flag, p) 179 dev_t dev; 180 u_long cmd; 181 caddr_t data; 182 int flag; 183 struct proc *p; 184 { 185 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 186 struct tty *tp = sc->of_tty; 187 int error; 188 189 if ((error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)) >= 0) 190 return error; 191 if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0) 192 return error; 193 return ENOTTY; 194 } 195 196 struct tty * 197 ofctty(dev) 198 dev_t dev; 199 { 200 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 201 202 return sc->of_tty; 203 } 204 205 void 206 ofcstop(tp, flag) 207 struct tty *tp; 208 int flag; 209 { 210 } 211 212 static void 213 ofcstart(tp) 214 struct tty *tp; 215 { 216 struct clist *cl; 217 int s, len; 218 u_char buf[OFBURSTLEN]; 219 220 s = spltty(); 221 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 222 splx(s); 223 return; 224 } 225 tp->t_state |= TS_BUSY; 226 splx(s); 227 cl = &tp->t_outq; 228 len = q_to_b(cl, buf, OFBURSTLEN); 229 OF_write(stdout, buf, len); 230 s = spltty(); 231 tp->t_state &= ~TS_BUSY; 232 if (cl->c_cc) { 233 tp->t_state |= TS_TIMEOUT; 234 timeout(ttrstrt, (void *)tp, 1); 235 } 236 if (cl->c_cc <= tp->t_lowat) { 237 if (tp->t_state & TS_ASLEEP) { 238 tp->t_state &= ~TS_ASLEEP; 239 wakeup(cl); 240 } 241 selwakeup(&tp->t_wsel); 242 } 243 splx(s); 244 } 245 246 static int 247 ofcparam(tp, t) 248 struct tty *tp; 249 struct termios *t; 250 { 251 tp->t_ispeed = t->c_ispeed; 252 tp->t_ospeed = t->c_ospeed; 253 tp->t_cflag = t->c_cflag; 254 return 0; 255 } 256 257 static void 258 ofcpoll(aux) 259 void *aux; 260 { 261 struct ofc_softc *sc = aux; 262 struct tty *tp = sc->of_tty; 263 char ch; 264 265 while (OF_read(stdin, &ch, 1) > 0) { 266 if (tp && (tp->t_state & TS_ISOPEN)) 267 (*linesw[tp->t_line].l_rint)(ch, tp); 268 } 269 timeout(ofcpoll, sc, 1); 270 } 271 272 static int 273 ofcprobe() 274 { 275 int chosen; 276 277 if (stdin) 278 return 1; 279 if ((chosen = OF_finddevice("/chosen")) == -1) 280 return 0; 281 if (OF_getprop(chosen, "stdin", &stdin, sizeof stdin) != sizeof stdin 282 || OF_getprop(chosen, "stdout", &stdout, sizeof stdout) != sizeof stdout) 283 return 0; 284 return 1; 285 } 286 287 void 288 ofccnprobe(cd) 289 struct consdev *cd; 290 { 291 int maj; 292 293 if (!ofcprobe()) 294 return; 295 296 for (maj = 0; maj < nchrdev; maj++) 297 if (cdevsw[maj].d_open == ofcopen) 298 break; 299 cd->cn_dev = makedev(maj, 0); 300 cd->cn_pri = CN_INTERNAL; 301 } 302 303 void 304 ofccninit(cd) 305 struct consdev *cd; 306 { 307 } 308 309 int 310 ofccngetc(dev) 311 dev_t dev; 312 { 313 unsigned char ch; 314 int l; 315 316 while ((l = OF_read(stdin, &ch, 1)) != 1) 317 if (l != -2) 318 return -1; 319 return ch; 320 } 321 322 void 323 ofccnputc(dev, c) 324 dev_t dev; 325 int c; 326 { 327 char ch = c; 328 329 OF_write(stdout, &ch, 1); 330 } 331 332 void 333 ofccnpollc(dev, on) 334 dev_t dev; 335 int on; 336 { 337 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)]; 338 339 if (!sc) 340 return; 341 if (on) { 342 if (sc->of_flags & OFPOLL) 343 untimeout(ofcpoll, sc); 344 sc->of_flags &= ~OFPOLL; 345 } else { 346 if (!(sc->of_flags & OFPOLL)) { 347 sc->of_flags |= OFPOLL; 348 timeout(ofcpoll, sc, 1); 349 } 350 } 351 } 352