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