1 /* $OpenBSD: pdc.c,v 1.42 2024/05/22 14:25:47 jsg 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 struct consdev pdccons = { NULL, NULL, pdccngetc, pdccnputc, 58 nullcnpollc, NULL, makedev(22, 0), CN_LOWPRI }; 59 60 int pdcmatch(struct device *, void *, void *); 61 void pdcattach(struct device *, struct device *, void *); 62 63 const struct cfattach pdc_ca = { 64 sizeof(pdcsoftc_t), pdcmatch, pdcattach 65 }; 66 67 struct cfdriver pdc_cd = { 68 NULL, "pdc", DV_DULL 69 }; 70 71 void pdcstart(struct tty *tp); 72 void pdctimeout(void *v); 73 int pdcparam(struct tty *tp, struct termios *); 74 int pdccnlookc(dev_t dev, int *cp); 75 76 #if NCOM > 0 77 /* serial console speed table */ 78 static int pdc_speeds[] = { 79 B50, 80 B75, 81 B110, 82 B150, 83 B300, 84 B600, 85 B1200, 86 B2400, 87 B4800, 88 B7200, 89 B9600, 90 B19200, 91 B38400, 92 B57600, 93 B115200, 94 B230400, 95 }; 96 #endif 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 /* Start out with pdc as the console. */ 124 cn_tab = &pdccons; 125 126 /* Figure out console settings. */ 127 #if NCOM > 0 128 if (PAGE0->mem_cons.pz_class == PCL_DUPLEX) { 129 struct pz_device *pzd = &PAGE0->mem_cons; 130 extern int comdefaultrate; 131 #ifdef DEBUG 132 printf("console: class %d flags %b ", 133 pzd->pz_class, pzd->pz_flags, PZF_BITS); 134 printf("bc %d/%d/%d/%d/%d/%d ", 135 pzd->pz_bc[0], pzd->pz_bc[1], pzd->pz_bc[2], 136 pzd->pz_bc[3], pzd->pz_bc[4], pzd->pz_bc[5]); 137 printf("mod %x layers %x/%x/%x/%x/%x/%x hpa %x\n", pzd->pz_mod, 138 pzd->pz_layers[0], pzd->pz_layers[1], pzd->pz_layers[2], 139 pzd->pz_layers[3], pzd->pz_layers[4], pzd->pz_layers[5], 140 pzd->pz_hpa); 141 142 #endif 143 144 /* compute correct baud rate */ 145 if (PZL_SPEED(pzd->pz_layers[0]) < 146 sizeof(pdc_speeds) / sizeof(int)) 147 comdefaultrate = 148 pdc_speeds[PZL_SPEED(pzd->pz_layers[0])]; 149 else 150 comdefaultrate = B9600; /* XXX */ 151 } 152 #endif 153 } 154 155 int 156 pdcmatch(parent, cfdata, aux) 157 struct device *parent; 158 void *cfdata; 159 void *aux; 160 { 161 struct cfdata *cf = cfdata; 162 struct confargs *ca = aux; 163 164 /* there could be only one */ 165 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc")) 166 return 0; 167 168 return 1; 169 } 170 171 void 172 pdcattach(parent, self, aux) 173 struct device *parent; 174 struct device *self; 175 void *aux; 176 { 177 struct pdc_softc *sc = (struct pdc_softc *)self; 178 179 if (!pdc) 180 pdc_init(); 181 182 printf("\n"); 183 184 timeout_set(&sc->sc_to, pdctimeout, sc); 185 } 186 187 int 188 pdcopen(dev, flag, mode, p) 189 dev_t dev; 190 int flag, mode; 191 struct proc *p; 192 { 193 int unit = minor(dev); 194 struct pdc_softc *sc; 195 struct tty *tp; 196 int s; 197 int error = 0, setuptimeout = 0; 198 199 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 200 return ENXIO; 201 202 s = spltty(); 203 204 if (sc->sc_tty) 205 tp = sc->sc_tty; 206 else { 207 tp = sc->sc_tty = ttymalloc(0); 208 } 209 210 tp->t_oproc = pdcstart; 211 tp->t_param = pdcparam; 212 tp->t_dev = dev; 213 if ((tp->t_state & TS_ISOPEN) == 0) { 214 ttychars(tp); 215 tp->t_iflag = TTYDEF_IFLAG; 216 tp->t_oflag = TTYDEF_OFLAG; 217 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 218 tp->t_lflag = TTYDEF_LFLAG; 219 tp->t_ispeed = tp->t_ospeed = B9600; 220 ttsetwater(tp); 221 222 setuptimeout = 1; 223 } else if (tp->t_state&TS_XCLUDE && suser(p) != 0) { 224 splx(s); 225 return (EBUSY); 226 } 227 tp->t_state |= TS_CARR_ON; 228 splx(s); 229 230 error = (*linesw[tp->t_line].l_open)(dev, tp, p); 231 if (error == 0 && setuptimeout) 232 pdctimeout(sc); 233 234 return error; 235 } 236 237 int 238 pdcclose(dev, flag, mode, p) 239 dev_t dev; 240 int flag, mode; 241 struct proc *p; 242 { 243 int unit = minor(dev); 244 struct tty *tp; 245 struct pdc_softc *sc; 246 247 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 248 return ENXIO; 249 250 tp = sc->sc_tty; 251 timeout_del(&sc->sc_to); 252 (*linesw[tp->t_line].l_close)(tp, flag, p); 253 ttyclose(tp); 254 return 0; 255 } 256 257 int 258 pdcread(dev, uio, flag) 259 dev_t dev; 260 struct uio *uio; 261 int flag; 262 { 263 int unit = minor(dev); 264 struct tty *tp; 265 struct pdc_softc *sc; 266 267 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 268 return ENXIO; 269 270 tp = sc->sc_tty; 271 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 272 } 273 274 int 275 pdcwrite(dev, uio, flag) 276 dev_t dev; 277 struct uio *uio; 278 int flag; 279 { 280 int unit = minor(dev); 281 struct tty *tp; 282 struct pdc_softc *sc; 283 284 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 285 return ENXIO; 286 287 tp = sc->sc_tty; 288 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 289 } 290 291 int 292 pdcioctl(dev, cmd, data, flag, p) 293 dev_t dev; 294 u_long cmd; 295 caddr_t data; 296 int flag; 297 struct proc *p; 298 { 299 int unit = minor(dev); 300 int error; 301 struct tty *tp; 302 struct pdc_softc *sc; 303 304 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 305 return ENXIO; 306 307 tp = sc->sc_tty; 308 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 309 if (error >= 0) 310 return error; 311 error = ttioctl(tp, cmd, data, flag, p); 312 if (error >= 0) 313 return error; 314 315 return ENOTTY; 316 } 317 318 int 319 pdcparam(tp, t) 320 struct tty *tp; 321 struct termios *t; 322 { 323 324 return 0; 325 } 326 327 void 328 pdcstart(tp) 329 struct tty *tp; 330 { 331 int s; 332 333 s = spltty(); 334 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) { 335 splx(s); 336 return; 337 } 338 ttwakeupwr(tp); 339 tp->t_state |= TS_BUSY; 340 while (tp->t_outq.c_cc != 0) 341 pdccnputc(tp->t_dev, getc(&tp->t_outq)); 342 tp->t_state &= ~TS_BUSY; 343 splx(s); 344 } 345 346 int 347 pdcstop(tp, flag) 348 struct tty *tp; 349 int flag; 350 { 351 int s; 352 353 s = spltty(); 354 if (tp->t_state & TS_BUSY) 355 if ((tp->t_state & TS_TTSTOP) == 0) 356 tp->t_state |= TS_FLUSH; 357 splx(s); 358 return 0; 359 } 360 361 void 362 pdctimeout(v) 363 void *v; 364 { 365 struct pdc_softc *sc = v; 366 struct tty *tp = sc->sc_tty; 367 int c; 368 369 while (pdccnlookc(tp->t_dev, &c)) { 370 if (tp->t_state & TS_ISOPEN) 371 (*linesw[tp->t_line].l_rint)(c, tp); 372 } 373 timeout_add(&sc->sc_to, 1); 374 } 375 376 struct tty * 377 pdctty(dev) 378 dev_t dev; 379 { 380 int unit = minor(dev); 381 struct pdc_softc *sc; 382 383 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 384 return NULL; 385 386 return sc->sc_tty; 387 } 388 389 int 390 pdccnlookc(dev, cp) 391 dev_t dev; 392 int *cp; 393 { 394 int err, l; 395 int s = splhigh(); 396 397 err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN, 398 pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 399 400 l = pdcret[0]; 401 *cp = pdc_consbuf[0]; 402 splx(s); 403 #ifdef DEBUG 404 if (err < 0) 405 printf("pdccnlookc: input error: %d\n", err); 406 #endif 407 408 return l; 409 } 410 411 int 412 pdccngetc(dev) 413 dev_t dev; 414 { 415 int c; 416 417 if (!pdc) 418 return 0; 419 420 while(!pdccnlookc(dev, &c)) 421 ; 422 423 return (c); 424 } 425 426 void 427 pdccnputc(dev, c) 428 dev_t dev; 429 int c; 430 { 431 register int err; 432 int s = splhigh(); 433 434 *pdc_consbuf = c; 435 err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT, 436 pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 437 splx(s); 438 439 if (err < 0) { 440 #ifdef DEBUG 441 printf("pdccnputc: output error: %d\n", err); 442 #endif 443 } 444 } 445