1 /* $OpenBSD: pdc.c,v 1.25 2003/05/14 23:18:09 miod Exp $ */ 2 3 /* 4 * Copyright (c) 1998-2002 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 hppa_hpa_t conaddr; 60 int conunit; 61 62 int pdcmatch(struct device *, void *, void *); 63 void pdcattach(struct device *, struct device *, void *); 64 65 struct cfattach pdc_ca = { 66 sizeof(pdcsoftc_t), pdcmatch, pdcattach 67 }; 68 69 struct cfdriver pdc_cd = { 70 NULL, "pdc", DV_DULL 71 }; 72 73 void pdcstart(struct tty *tp); 74 void pdctimeout(void *v); 75 int pdcparam(struct tty *tp, struct termios *); 76 int pdccnlookc(dev_t dev, int *cp); 77 78 /* serial console speed table */ 79 static int pdc_speeds[] = { 80 B50, 81 B75, 82 B110, 83 B150, 84 B300, 85 B600, 86 B1200, 87 B2400, 88 B4800, 89 B7200, 90 B9600, 91 B19200, 92 B38400, 93 B57600, 94 B115200, 95 B230400, 96 }; 97 98 void 99 pdc_init() 100 { 101 static int kbd_iodc[IODC_MAXSIZE/sizeof(int)]; 102 static int cn_iodc[IODC_MAXSIZE/sizeof(int)]; 103 int err; 104 105 /* XXX locore've done it XXX pdc = (pdcio_t)PAGE0->mem_pdc; */ 106 pz_kbd = &PAGE0->mem_kbd; 107 pz_cons = &PAGE0->mem_cons; 108 109 /* XXX should we reset the console/kbd here? 110 well, /boot did that for us anyway */ 111 if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, 112 pdcret, pz_cons->pz_hpa, IODC_IO, cn_iodc, IODC_MAXSIZE)) < 0 || 113 (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, 114 pdcret, pz_kbd->pz_hpa, IODC_IO, kbd_iodc, IODC_MAXSIZE)) < 0) { 115 #ifdef DEBUG 116 printf("pdc_init: failed reading IODC (%d)\n", err); 117 #endif 118 } 119 120 pdc_cniodc = (iodcio_t)cn_iodc; 121 pdc_kbdiodc = (iodcio_t)kbd_iodc; 122 123 /* XXX make pdc current console */ 124 cn_tab = &constab[0]; 125 126 /* setup the console */ 127 #include "com.h" 128 #if NCOM_GSC > 0 129 if (PAGE0->mem_cons.pz_class == PCL_DUPLEX) { 130 struct pz_device *pzd = &PAGE0->mem_cons; 131 extern int comdefaultrate; 132 #ifdef DEBUG 133 printf("console: class %d flags %b ", 134 pzd->pz_class, pzd->pz_flags, PZF_BITS); 135 printf("bc %d/%d/%d/%d/%d/%d ", 136 pzd->pz_bc[0], pzd->pz_bc[1], pzd->pz_bc[2], 137 pzd->pz_bc[3], pzd->pz_bc[4], pzd->pz_bc[5]); 138 printf("mod %x layers %x/%x/%x/%x/%x/%x hpa %x\n", pzd->pz_mod, 139 pzd->pz_layers[0], pzd->pz_layers[1], pzd->pz_layers[2], 140 pzd->pz_layers[3], pzd->pz_layers[4], pzd->pz_layers[5], 141 pzd->pz_hpa); 142 #endif 143 conaddr = (u_long)pzd->pz_hpa + IOMOD_DEVOFFSET; 144 conunit = 0; 145 146 /* compute correct baud rate */ 147 if (PZL_SPEED(pzd->pz_layers[0]) < 148 sizeof(pdc_speeds) / sizeof(int)) 149 comdefaultrate = 150 pdc_speeds[PZL_SPEED(pzd->pz_layers[0])]; 151 else 152 comdefaultrate = B9600; /* XXX */ 153 } 154 #endif 155 } 156 157 int 158 pdcmatch(parent, cfdata, aux) 159 struct device *parent; 160 void *cfdata; 161 void *aux; 162 { 163 struct cfdata *cf = cfdata; 164 struct confargs *ca = aux; 165 166 /* there could be only one */ 167 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc")) 168 return 0; 169 170 return 1; 171 } 172 173 void 174 pdcattach(parent, self, aux) 175 struct device *parent; 176 struct device *self; 177 void *aux; 178 { 179 struct pdc_softc *sc = (struct pdc_softc *)self; 180 181 if (!pdc) 182 pdc_init(); 183 184 printf("\n"); 185 186 timeout_set(&sc->sc_to, pdctimeout, sc); 187 } 188 189 int 190 pdcopen(dev, flag, mode, p) 191 dev_t dev; 192 int flag, mode; 193 struct proc *p; 194 { 195 int unit = minor(dev); 196 struct pdc_softc *sc; 197 struct tty *tp; 198 int s; 199 int error = 0, setuptimeout = 0; 200 201 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 202 return ENXIO; 203 204 s = spltty(); 205 206 if (sc->sc_tty) 207 tp = sc->sc_tty; 208 else 209 tty_attach(tp = sc->sc_tty = ttymalloc()); 210 211 tp->t_oproc = pdcstart; 212 tp->t_param = pdcparam; 213 tp->t_dev = dev; 214 if ((tp->t_state & TS_ISOPEN) == 0) { 215 ttychars(tp); 216 tp->t_iflag = TTYDEF_IFLAG; 217 tp->t_oflag = TTYDEF_OFLAG; 218 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 219 tp->t_lflag = TTYDEF_LFLAG; 220 tp->t_ispeed = tp->t_ospeed = B9600; 221 ttsetwater(tp); 222 223 setuptimeout = 1; 224 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { 225 splx(s); 226 return (EBUSY); 227 } 228 tp->t_state |= TS_CARR_ON; 229 splx(s); 230 231 error = (*linesw[tp->t_line].l_open)(dev, tp); 232 if (error == 0 && setuptimeout) 233 pdctimeout(sc); 234 235 return error; 236 } 237 238 int 239 pdcclose(dev, flag, mode, p) 240 dev_t dev; 241 int flag, mode; 242 struct proc *p; 243 { 244 int unit = minor(dev); 245 struct tty *tp; 246 struct pdc_softc *sc; 247 248 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 249 return ENXIO; 250 251 tp = sc->sc_tty; 252 timeout_del(&sc->sc_to); 253 (*linesw[tp->t_line].l_close)(tp, flag); 254 ttyclose(tp); 255 return 0; 256 } 257 258 int 259 pdcread(dev, uio, flag) 260 dev_t dev; 261 struct uio *uio; 262 int flag; 263 { 264 int unit = minor(dev); 265 struct tty *tp; 266 struct pdc_softc *sc; 267 268 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 269 return ENXIO; 270 271 tp = sc->sc_tty; 272 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 273 } 274 275 int 276 pdcwrite(dev, uio, flag) 277 dev_t dev; 278 struct uio *uio; 279 int flag; 280 { 281 int unit = minor(dev); 282 struct tty *tp; 283 struct pdc_softc *sc; 284 285 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 286 return ENXIO; 287 288 tp = sc->sc_tty; 289 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 290 } 291 292 int 293 pdcioctl(dev, cmd, data, flag, p) 294 dev_t dev; 295 u_long cmd; 296 caddr_t data; 297 int flag; 298 struct proc *p; 299 { 300 int unit = minor(dev); 301 int error; 302 struct tty *tp; 303 struct pdc_softc *sc; 304 305 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 306 return ENXIO; 307 308 tp = sc->sc_tty; 309 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 310 if (error >= 0) 311 return error; 312 error = ttioctl(tp, cmd, data, flag, p); 313 if (error >= 0) 314 return error; 315 316 return ENOTTY; 317 } 318 319 int 320 pdcparam(tp, t) 321 struct tty *tp; 322 struct termios *t; 323 { 324 325 return 0; 326 } 327 328 void 329 pdcstart(tp) 330 struct tty *tp; 331 { 332 int s; 333 334 s = spltty(); 335 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) { 336 splx(s); 337 return; 338 } 339 if (tp->t_outq.c_cc <= tp->t_lowat) { 340 if (tp->t_state & TS_ASLEEP) { 341 tp->t_state &= ~TS_ASLEEP; 342 wakeup((caddr_t)&tp->t_outq); 343 } 344 selwakeup(&tp->t_wsel); 345 } 346 tp->t_state |= TS_BUSY; 347 while (tp->t_outq.c_cc != 0) 348 pdccnputc(tp->t_dev, getc(&tp->t_outq)); 349 tp->t_state &= ~TS_BUSY; 350 splx(s); 351 } 352 353 int 354 pdcstop(tp, flag) 355 struct tty *tp; 356 int flag; 357 { 358 int s; 359 360 s = spltty(); 361 if (tp->t_state & TS_BUSY) 362 if ((tp->t_state & TS_TTSTOP) == 0) 363 tp->t_state |= TS_FLUSH; 364 splx(s); 365 return 0; 366 } 367 368 void 369 pdctimeout(v) 370 void *v; 371 { 372 struct pdc_softc *sc = v; 373 struct tty *tp = sc->sc_tty; 374 int c; 375 376 while (pdccnlookc(tp->t_dev, &c)) { 377 if (tp->t_state & TS_ISOPEN) 378 (*linesw[tp->t_line].l_rint)(c, tp); 379 } 380 timeout_add(&sc->sc_to, 1); 381 } 382 383 struct tty * 384 pdctty(dev) 385 dev_t dev; 386 { 387 int unit = minor(dev); 388 struct pdc_softc *sc; 389 390 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 391 return NULL; 392 393 return sc->sc_tty; 394 } 395 396 void 397 pdccnprobe(cn) 398 struct consdev *cn; 399 { 400 cn->cn_dev = makedev(22,0); 401 cn->cn_pri = CN_NORMAL; 402 } 403 404 void 405 pdccninit(cn) 406 struct consdev *cn; 407 { 408 #ifdef DEBUG 409 printf("pdc0: console init\n"); 410 #endif 411 } 412 413 int 414 pdccnlookc(dev, cp) 415 dev_t dev; 416 int *cp; 417 { 418 int err, l; 419 int s = splhigh(); 420 421 err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN, 422 pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 423 424 l = pdcret[0]; 425 *cp = pdc_consbuf[0]; 426 splx(s); 427 #ifdef DEBUG 428 if (err < 0) 429 printf("pdccnlookc: input error: %d\n", err); 430 #endif 431 432 return l; 433 } 434 435 int 436 pdccngetc(dev) 437 dev_t dev; 438 { 439 int c; 440 441 if (!pdc) 442 return 0; 443 444 while(!pdccnlookc(dev, &c)) 445 ; 446 447 return (c); 448 } 449 450 void 451 pdccnputc(dev, c) 452 dev_t dev; 453 int c; 454 { 455 register int err; 456 int s = splhigh(); 457 458 *pdc_consbuf = c; 459 err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT, 460 pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 461 splx(s); 462 463 if (err < 0) { 464 #ifdef DEBUG 465 printf("pdccnputc: output error: %d\n", err); 466 #endif 467 } 468 } 469 470 void 471 pdccnpollc(dev, on) 472 dev_t dev; 473 int on; 474 { 475 476 } 477