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