1 /* $OpenBSD: pdc.c,v 1.31 2008/01/23 16:37:56 jsing 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/user.h> 36 #include <sys/timeout.h> 37 38 #include <dev/cons.h> 39 40 #include <machine/conf.h> 41 #include <machine/pdc.h> 42 #include <machine/iomod.h> 43 #include <machine/autoconf.h> 44 45 typedef 46 struct pdc_softc { 47 struct device sc_dv; 48 struct tty *sc_tty; 49 struct timeout sc_to; 50 } pdcsoftc_t; 51 52 pdcio_t pdc; 53 int pdcret[32] PDC_ALIGNMENT; 54 char pdc_consbuf[IODC_MINIOSIZ] PDC_ALIGNMENT; 55 iodcio_t pdc_cniodc, pdc_kbdiodc; 56 pz_device_t *pz_kbd, *pz_cons; 57 58 int pdcngetc(dev_t); 59 void pdcnputc(dev_t, char *); 60 61 struct consdev pdccons = { NULL, NULL, pdccngetc, pdccnputc, 62 nullcnpollc, NULL, makedev(22, 0), CN_LOWPRI }; 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 /* Start out with pdc as the console. */ 128 cn_tab = &pdccons; 129 130 /* Figure out console settings. */ 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 146 #endif 147 148 /* compute correct baud rate */ 149 if (PZL_SPEED(pzd->pz_layers[0]) < 150 sizeof(pdc_speeds) / sizeof(int)) 151 comdefaultrate = 152 pdc_speeds[PZL_SPEED(pzd->pz_layers[0])]; 153 else 154 comdefaultrate = B9600; /* XXX */ 155 } 156 #endif 157 } 158 159 int 160 pdcmatch(parent, cfdata, aux) 161 struct device *parent; 162 void *cfdata; 163 void *aux; 164 { 165 struct cfdata *cf = cfdata; 166 struct confargs *ca = aux; 167 168 /* there could be only one */ 169 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc")) 170 return 0; 171 172 return 1; 173 } 174 175 void 176 pdcattach(parent, self, aux) 177 struct device *parent; 178 struct device *self; 179 void *aux; 180 { 181 struct pdc_softc *sc = (struct pdc_softc *)self; 182 183 if (!pdc) 184 pdc_init(); 185 186 printf("\n"); 187 188 timeout_set(&sc->sc_to, pdctimeout, sc); 189 } 190 191 int 192 pdcopen(dev, flag, mode, p) 193 dev_t dev; 194 int flag, mode; 195 struct proc *p; 196 { 197 int unit = minor(dev); 198 struct pdc_softc *sc; 199 struct tty *tp; 200 int s; 201 int error = 0, setuptimeout = 0; 202 203 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 204 return ENXIO; 205 206 s = spltty(); 207 208 if (sc->sc_tty) 209 tp = sc->sc_tty; 210 else { 211 tp = sc->sc_tty = ttymalloc(); 212 } 213 214 tp->t_oproc = pdcstart; 215 tp->t_param = pdcparam; 216 tp->t_dev = dev; 217 if ((tp->t_state & TS_ISOPEN) == 0) { 218 ttychars(tp); 219 tp->t_iflag = TTYDEF_IFLAG; 220 tp->t_oflag = TTYDEF_OFLAG; 221 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 222 tp->t_lflag = TTYDEF_LFLAG; 223 tp->t_ispeed = tp->t_ospeed = B9600; 224 ttsetwater(tp); 225 226 setuptimeout = 1; 227 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { 228 splx(s); 229 return (EBUSY); 230 } 231 tp->t_state |= TS_CARR_ON; 232 splx(s); 233 234 error = (*linesw[tp->t_line].l_open)(dev, tp); 235 if (error == 0 && setuptimeout) 236 pdctimeout(sc); 237 238 return error; 239 } 240 241 int 242 pdcclose(dev, flag, mode, p) 243 dev_t dev; 244 int flag, mode; 245 struct proc *p; 246 { 247 int unit = minor(dev); 248 struct tty *tp; 249 struct pdc_softc *sc; 250 251 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 252 return ENXIO; 253 254 tp = sc->sc_tty; 255 timeout_del(&sc->sc_to); 256 (*linesw[tp->t_line].l_close)(tp, flag); 257 ttyclose(tp); 258 return 0; 259 } 260 261 int 262 pdcread(dev, uio, flag) 263 dev_t dev; 264 struct uio *uio; 265 int flag; 266 { 267 int unit = minor(dev); 268 struct tty *tp; 269 struct pdc_softc *sc; 270 271 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 272 return ENXIO; 273 274 tp = sc->sc_tty; 275 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 276 } 277 278 int 279 pdcwrite(dev, uio, flag) 280 dev_t dev; 281 struct uio *uio; 282 int flag; 283 { 284 int unit = minor(dev); 285 struct tty *tp; 286 struct pdc_softc *sc; 287 288 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 289 return ENXIO; 290 291 tp = sc->sc_tty; 292 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 293 } 294 295 int 296 pdcioctl(dev, cmd, data, flag, p) 297 dev_t dev; 298 u_long cmd; 299 caddr_t data; 300 int flag; 301 struct proc *p; 302 { 303 int unit = minor(dev); 304 int error; 305 struct tty *tp; 306 struct pdc_softc *sc; 307 308 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 309 return ENXIO; 310 311 tp = sc->sc_tty; 312 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 313 if (error >= 0) 314 return error; 315 error = ttioctl(tp, cmd, data, flag, p); 316 if (error >= 0) 317 return error; 318 319 return ENOTTY; 320 } 321 322 int 323 pdcparam(tp, t) 324 struct tty *tp; 325 struct termios *t; 326 { 327 328 return 0; 329 } 330 331 void 332 pdcstart(tp) 333 struct tty *tp; 334 { 335 int s; 336 337 s = spltty(); 338 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) { 339 splx(s); 340 return; 341 } 342 if (tp->t_outq.c_cc <= tp->t_lowat) { 343 if (tp->t_state & TS_ASLEEP) { 344 tp->t_state &= ~TS_ASLEEP; 345 wakeup((caddr_t)&tp->t_outq); 346 } 347 selwakeup(&tp->t_wsel); 348 } 349 tp->t_state |= TS_BUSY; 350 while (tp->t_outq.c_cc != 0) 351 pdccnputc(tp->t_dev, getc(&tp->t_outq)); 352 tp->t_state &= ~TS_BUSY; 353 splx(s); 354 } 355 356 int 357 pdcstop(tp, flag) 358 struct tty *tp; 359 int flag; 360 { 361 int s; 362 363 s = spltty(); 364 if (tp->t_state & TS_BUSY) 365 if ((tp->t_state & TS_TTSTOP) == 0) 366 tp->t_state |= TS_FLUSH; 367 splx(s); 368 return 0; 369 } 370 371 void 372 pdctimeout(v) 373 void *v; 374 { 375 struct pdc_softc *sc = v; 376 struct tty *tp = sc->sc_tty; 377 int c; 378 379 while (pdccnlookc(tp->t_dev, &c)) { 380 if (tp->t_state & TS_ISOPEN) 381 (*linesw[tp->t_line].l_rint)(c, tp); 382 } 383 timeout_add(&sc->sc_to, 1); 384 } 385 386 struct tty * 387 pdctty(dev) 388 dev_t dev; 389 { 390 int unit = minor(dev); 391 struct pdc_softc *sc; 392 393 if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL) 394 return NULL; 395 396 return sc->sc_tty; 397 } 398 399 int 400 pdccnlookc(dev, cp) 401 dev_t dev; 402 int *cp; 403 { 404 int err, l; 405 int s = splhigh(); 406 407 err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN, 408 pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 409 410 l = pdcret[0]; 411 *cp = pdc_consbuf[0]; 412 splx(s); 413 #ifdef DEBUG 414 if (err < 0) 415 printf("pdccnlookc: input error: %d\n", err); 416 #endif 417 418 return l; 419 } 420 421 int 422 pdccngetc(dev) 423 dev_t dev; 424 { 425 int c; 426 427 if (!pdc) 428 return 0; 429 430 while(!pdccnlookc(dev, &c)) 431 ; 432 433 return (c); 434 } 435 436 void 437 pdccnputc(dev, c) 438 dev_t dev; 439 int c; 440 { 441 register int err; 442 int s = splhigh(); 443 444 *pdc_consbuf = c; 445 err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT, 446 pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0); 447 splx(s); 448 449 if (err < 0) { 450 #ifdef DEBUG 451 printf("pdccnputc: output error: %d\n", err); 452 #endif 453 } 454 } 455