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