1 /* $OpenBSD: pdc.c,v 1.14 2001/04/29 21:05:43 mickey Exp $ */ 2 3 /* 4 * Copyright (c) 1998-2001 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Michael Shalayeff. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND, 27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/tty.h> 37 #include <sys/user.h> 38 #include <sys/timeout.h> 39 40 #include <dev/cons.h> 41 42 #include <machine/conf.h> 43 #include <machine/pdc.h> 44 #include <machine/iomod.h> 45 #include <machine/autoconf.h> 46 47 typedef 48 struct pdc_softc { 49 struct device sc_dv; 50 struct tty *sc_tty; 51 struct timeout sc_to; 52 } pdcsoftc_t; 53 54 pdcio_t pdc; 55 int pdcret[32] PDC_ALIGNMENT; 56 char pdc_consbuf[IODC_MINIOSIZ] PDC_ALIGNMENT; 57 iodcio_t pdc_cniodc, pdc_kbdiodc; 58 pz_device_t *pz_kbd, *pz_cons; 59 int CONADDR; 60 61 int pdcmatch __P((struct device *, void *, void*)); 62 void pdcattach __P((struct device *, struct device *, void *)); 63 64 struct cfattach pdc_ca = { 65 sizeof(pdcsoftc_t), pdcmatch, pdcattach 66 }; 67 68 struct cfdriver pdc_cd = { 69 NULL, "pdc", DV_DULL 70 }; 71 72 void pdcstart __P((struct tty *tp)); 73 void pdctimeout __P((void *v)); 74 int pdcparam __P((struct tty *tp, struct termios *)); 75 int pdccnlookc __P((dev_t dev, int *cp)); 76 77 void 78 pdc_init() 79 { 80 static int kbd_iodc[IODC_MAXSIZE/sizeof(int)]; 81 static int cn_iodc[IODC_MAXSIZE/sizeof(int)]; 82 int err; 83 84 /* XXX locore've done it XXX pdc = (pdcio_t)PAGE0->mem_pdc; */ 85 pz_kbd = &PAGE0->mem_kbd; 86 pz_cons = &PAGE0->mem_cons; 87 88 /* XXX should we reset the console/kbd here? 89 well, /boot did that for us anyway */ 90 if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, 91 pdcret, pz_cons->pz_hpa, IODC_IO, cn_iodc, IODC_MAXSIZE)) < 0 || 92 (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, 93 pdcret, pz_kbd->pz_hpa, IODC_IO, kbd_iodc, IODC_MAXSIZE)) < 0) { 94 #ifdef DEBUG 95 printf("pdc_init: failed reading IODC (%d)\n", err); 96 #endif 97 } 98 99 pdc_cniodc = (iodcio_t)cn_iodc; 100 pdc_kbdiodc = (iodcio_t)kbd_iodc; 101 102 /* XXX make pdc current console */ 103 cn_tab = &constab[0]; 104 /* TODO: detect that we are on cereal, and set CONADDR */ 105 } 106 107 int 108 pdcmatch(parent, cfdata, aux) 109 struct device *parent; 110 void *cfdata; 111 void *aux; 112 { 113 struct cfdata *cf = cfdata; 114 struct confargs *ca = aux; 115 116 /* there could be only one */ 117 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc")) 118 return 0; 119 120 return 1; 121 } 122 123 void 124 pdcattach(parent, self, aux) 125 struct device *parent; 126 struct device *self; 127 void *aux; 128 { 129 struct pdc_softc *sc = (struct pdc_softc *)self; 130 131 if (!pdc) 132 pdc_init(); 133 134 printf("\n"); 135 136 timeout_set(&sc->sc_to, pdctimeout, sc); 137 } 138 139 int 140 pdcopen(dev, flag, mode, p) 141 dev_t dev; 142 int flag, mode; 143 struct proc *p; 144 { 145 int unit = minor(dev); 146 struct pdc_softc *sc; 147 struct tty *tp; 148 int s; 149 int error = 0, setuptimeout; 150 151 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 152 return ENXIO; 153 154 s = spltty(); 155 156 if (sc->sc_tty) 157 tp = sc->sc_tty; 158 else 159 tty_attach(tp = sc->sc_tty = ttymalloc()); 160 161 tp->t_oproc = pdcstart; 162 tp->t_param = pdcparam; 163 tp->t_dev = dev; 164 if ((tp->t_state & TS_ISOPEN) == 0) { 165 tp->t_state |= TS_WOPEN|TS_CARR_ON; 166 ttychars(tp); 167 tp->t_iflag = TTYDEF_IFLAG; 168 tp->t_oflag = TTYDEF_OFLAG; 169 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 170 tp->t_lflag = TTYDEF_LFLAG; 171 tp->t_ispeed = tp->t_ospeed = 9600; 172 ttsetwater(tp); 173 174 setuptimeout = 1; 175 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { 176 splx(s); 177 return EBUSY; 178 } 179 tp->t_state |= TS_CARR_ON; 180 181 splx(s); 182 183 error = (*linesw[tp->t_line].l_open)(dev, tp); 184 if (error == 0 && setuptimeout) 185 pdctimeout(sc); 186 187 return error; 188 } 189 190 int 191 pdcclose(dev, flag, mode, p) 192 dev_t dev; 193 int flag, mode; 194 struct proc *p; 195 { 196 int unit = minor(dev); 197 struct tty *tp; 198 struct pdc_softc *sc; 199 200 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 201 return ENXIO; 202 203 tp = sc->sc_tty; 204 timeout_del(&sc->sc_to); 205 (*linesw[tp->t_line].l_close)(tp, flag); 206 ttyclose(tp); 207 return 0; 208 } 209 210 int 211 pdcread(dev, uio, flag) 212 dev_t dev; 213 struct uio *uio; 214 int flag; 215 { 216 int unit = minor(dev); 217 struct tty *tp; 218 struct pdc_softc *sc; 219 220 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 221 return ENXIO; 222 223 tp = sc->sc_tty; 224 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 225 } 226 227 int 228 pdcwrite(dev, uio, flag) 229 dev_t dev; 230 struct uio *uio; 231 int flag; 232 { 233 int unit = minor(dev); 234 struct tty *tp; 235 struct pdc_softc *sc; 236 237 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 238 return ENXIO; 239 240 tp = sc->sc_tty; 241 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 242 } 243 244 int 245 pdcioctl(dev, cmd, data, flag, p) 246 dev_t dev; 247 u_long cmd; 248 caddr_t data; 249 int flag; 250 struct proc *p; 251 { 252 int unit = minor(dev); 253 int error; 254 struct tty *tp; 255 struct pdc_softc *sc; 256 257 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 258 return ENXIO; 259 260 tp = sc->sc_tty; 261 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 262 if (error >= 0) 263 return error; 264 error = ttioctl(tp, cmd, data, flag, p); 265 if (error >= 0) 266 return error; 267 268 return ENOTTY; 269 } 270 271 int 272 pdcparam(tp, t) 273 struct tty *tp; 274 struct termios *t; 275 { 276 277 return 0; 278 } 279 280 void 281 pdcstart(tp) 282 struct tty *tp; 283 { 284 int s; 285 286 s = spltty(); 287 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) { 288 splx(s); 289 return; 290 } 291 if (tp->t_outq.c_cc <= tp->t_lowat) { 292 if (tp->t_state & TS_ASLEEP) { 293 tp->t_state &= ~TS_ASLEEP; 294 wakeup((caddr_t)&tp->t_outq); 295 } 296 selwakeup(&tp->t_wsel); 297 } 298 tp->t_state |= TS_BUSY; 299 while (tp->t_outq.c_cc != 0) 300 pdccnputc(tp->t_dev, getc(&tp->t_outq)); 301 tp->t_state &= ~TS_BUSY; 302 splx(s); 303 } 304 305 int 306 pdcstop(tp, flag) 307 struct tty *tp; 308 int flag; 309 { 310 int s; 311 312 s = spltty(); 313 if (tp->t_state & TS_BUSY) 314 if ((tp->t_state & TS_TTSTOP) == 0) 315 tp->t_state |= TS_FLUSH; 316 splx(s); 317 return 0; 318 } 319 320 void 321 pdctimeout(v) 322 void *v; 323 { 324 struct pdc_softc *sc = v; 325 struct tty *tp = sc->sc_tty; 326 int c; 327 328 while (pdccnlookc(tp->t_dev, &c)) { 329 if (tp->t_state & TS_ISOPEN) 330 (*linesw[tp->t_line].l_rint)(c, tp); 331 } 332 timeout_add(&sc->sc_to, 1); 333 } 334 335 struct tty * 336 pdctty(dev) 337 dev_t dev; 338 { 339 int unit = minor(dev); 340 struct pdc_softc *sc; 341 342 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 343 return NULL; 344 345 return sc->sc_tty; 346 } 347 348 void 349 pdccnprobe(cn) 350 struct consdev *cn; 351 { 352 cn->cn_dev = makedev(22,0); 353 cn->cn_pri = CN_NORMAL; 354 } 355 356 void 357 pdccninit(cn) 358 struct consdev *cn; 359 { 360 #ifdef DEBUG 361 printf("pdc0: console init\n"); 362 #endif 363 } 364 365 int 366 pdccnlookc(dev, cp) 367 dev_t dev; 368 int *cp; 369 { 370 int err, l; 371 int s = splhigh(); 372 373 err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN, 374 pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 375 376 l = pdcret[0]; 377 *cp = pdc_consbuf[0]; 378 splx(s); 379 #ifdef DEBUG 380 if (err < 0) 381 printf("pdccnlookc: input error: %d\n", err); 382 #endif 383 384 return l; 385 } 386 387 int 388 pdccngetc(dev) 389 dev_t dev; 390 { 391 int c; 392 393 if (!pdc) 394 return 0; 395 396 while(!pdccnlookc(dev, &c)) 397 ; 398 399 return (c); 400 } 401 402 void 403 pdccnputc(dev, c) 404 dev_t dev; 405 int c; 406 { 407 register int err; 408 int s = splhigh(); 409 410 *pdc_consbuf = c; 411 err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT, 412 pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 413 splx(s); 414 415 if (err < 0) { 416 #ifdef DEBUG 417 printf("pdccnputc: output error: %d\n", err); 418 #endif 419 } 420 } 421 422 void 423 pdccnpollc(dev, on) 424 dev_t dev; 425 int on; 426 { 427 428 } 429