1 /* 2 * Copyright (c) 1992 OMRON Corporation. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * OMRON Corporation. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)bmc.c 8.1 (Berkeley) 06/10/93 12 */ 13 14 #include "bmc.h" 15 #if NBMC > 0 16 17 #include <sys/param.h> 18 #include <sys/systm.h> 19 #include <sys/ioctl.h> 20 #include <sys/proc.h> 21 #include <sys/tty.h> 22 #include <sys/conf.h> 23 #include <sys/file.h> 24 #include <sys/uio.h> 25 #include <sys/kernel.h> 26 #include <sys/syslog.h> 27 #include <machine/stinger.h> 28 #include <luna68k/dev/device.h> 29 #include <luna68k/dev/sioreg.h> 30 #include <luna68k/dev/siovar.h> 31 #include <luna68k/luna68k/cons.h> 32 33 extern struct sio_portc *sio_port_assign(); 34 35 int bmcprobe(); 36 int bmcopen(); 37 void bmcstart(); 38 int bmcparam(); 39 int bmcintr(); 40 41 struct driver bmcdriver = { 42 bmcprobe, "bmc", 43 }; 44 45 struct bmc_softc { 46 struct sio_portc *sc_pc; 47 int sc_mask; 48 }; 49 50 struct bmc_softc bmc_softc[NBMC]; 51 52 struct tty bmc_tty[NBMC]; 53 54 int bmc_active; 55 int bmcconsole = -1; 56 int bmcdefaultrate = B9600; /* speed of console line is fixed */ 57 int bmcmajor = 13; 58 59 #define bmcunit(x) minor(x) 60 61 extern struct tty *constty; 62 63 /* 64 * key-code decoding 65 */ 66 67 struct bmc_keymap { 68 int km_type; 69 int km_code[2]; 70 }; 71 72 #define KC_CHAR 0x000000FF 73 #define KC_TYPE 0x0000FF00 74 #define KC_CODE 0x00000000 75 #define KC_SHIFT 0x00000100 76 #define KC_IGNORE 0x0000FF00 77 78 #define KS_SHIFT 0 79 #define KS_CTRL 1 80 #define KS_META 2 81 82 struct bmc_keymap bmc_keymap[] = { 83 KC_IGNORE, 0, 0, /* 0 [0x00] */ 84 KC_IGNORE, 0, 0, /* 1 [0x01] */ 85 KC_IGNORE, 0, 0, /* 2 [0x02] */ 86 KC_IGNORE, 0, 0, /* 3 [0x03] */ 87 KC_IGNORE, 0, 0, /* 4 [0x04] */ 88 KC_IGNORE, 0, 0, /* 5 [0x05] */ 89 KC_IGNORE, 0, 0, /* 6 [0x06] */ 90 KC_IGNORE, 0, 0, /* 7 [0x07] */ 91 KC_IGNORE, 0, 0, /* 8 [0x08] */ 92 KC_CODE, 0x09, 0x09, /* 9 [0x09] TAB */ 93 KC_SHIFT, KS_CTRL, KS_CTRL, /* 10 [0x0A] CTRL */ 94 KC_IGNORE, 0, 0, /* 11 [0x0B] */ 95 KC_SHIFT, KS_SHIFT, KS_SHIFT, /* 12 [0x0C] SHIFT */ 96 KC_SHIFT, KS_SHIFT, KS_SHIFT, /* 13 [0x0D] SHIFT */ 97 KC_IGNORE, 0, 0, /* 14 [0x0E] */ 98 KC_SHIFT, KS_META, KS_META, /* 15 [0x0F] META */ 99 KC_CODE, 0x1B, 0x1B, /* 16 [0x10] ESC */ 100 KC_CODE, 0x08, 0x08, /* 17 [0x11] BS */ 101 KC_CODE, 0x0D, 0x0D, /* 18 [0x12] CR */ 102 KC_IGNORE, 0, 0, /* 19 [0x13] */ 103 KC_CODE, 0x20, 0x20, /* 20 [0x14] SP */ 104 KC_CODE, 0x7F, 0x7F, /* 21 [0x15] DEL */ 105 KC_IGNORE, 0, 0, /* 22 [0x16] */ 106 KC_IGNORE, 0, 0, /* 23 [0x17] */ 107 KC_IGNORE, 0, 0, /* 24 [0x18] */ 108 KC_IGNORE, 0, 0, /* 25 [0x19] */ 109 KC_IGNORE, 0, 0, /* 26 [0x1A] */ 110 KC_IGNORE, 0, 0, /* 27 [0x1B] */ 111 KC_IGNORE, 0, 0, /* 28 [0x1C] */ 112 KC_IGNORE, 0, 0, /* 29 [0x1D] */ 113 KC_IGNORE, 0, 0, /* 30 [0x1E] */ 114 KC_IGNORE, 0, 0, /* 31 [0x1F] */ 115 KC_IGNORE, 0, 0, /* 32 [0x20] */ 116 KC_IGNORE, 0, 0, /* 33 [0x21] */ 117 KC_CODE, 0x31, 0x21, /* 34 [0x22] 1 */ 118 KC_CODE, 0x32, 0x22, /* 35 [0x23] 2 */ 119 KC_CODE, 0x33, 0x23, /* 36 [0x24] 3 */ 120 KC_CODE, 0x34, 0x24, /* 37 [0x25] 4 */ 121 KC_CODE, 0x35, 0x25, /* 38 [0x26] 5 */ 122 KC_CODE, 0x36, 0x26, /* 39 [0x27] 6 */ 123 KC_CODE, 0x37, 0x27, /* 40 [0x28] 7 */ 124 KC_CODE, 0x38, 0x28, /* 41 [0x29] 8 */ 125 KC_CODE, 0x39, 0x29, /* 42 [0x2A] 9 */ 126 KC_CODE, 0x30, 0x30, /* 43 [0x2B] 0 */ 127 KC_CODE, 0x2D, 0x3D, /* 44 [0x2C] - */ 128 KC_CODE, 0x5E, 0x7E, /* 45 [0x2D] ^ */ 129 KC_CODE, 0x5C, 0x7C, /* 46 [0x2E] \ */ 130 KC_IGNORE, 0, 0, /* 47 [0x2F] */ 131 KC_IGNORE, 0, 0, /* 48 [0x30] */ 132 KC_IGNORE, 0, 0, /* 49 [0x31] */ 133 KC_CODE, 0x71, 0x51, /* 50 [0x32] q */ 134 KC_CODE, 0x77, 0x57, /* 51 [0x33] w */ 135 KC_CODE, 0x65, 0x45, /* 52 [0x34] e */ 136 KC_CODE, 0x72, 0x52, /* 53 [0x35] r */ 137 KC_CODE, 0x74, 0x54, /* 54 [0x36] t */ 138 KC_CODE, 0x79, 0x59, /* 55 [0x37] y */ 139 KC_CODE, 0x75, 0x55, /* 56 [0x38] u */ 140 KC_CODE, 0x69, 0x49, /* 57 [0x39] i */ 141 KC_CODE, 0x6F, 0x4F, /* 58 [0x3A] o */ 142 KC_CODE, 0x70, 0x50, /* 59 [0x3B] p */ 143 KC_CODE, 0x40, 0x60, /* 60 [0x3C] @ */ 144 KC_CODE, 0x5B, 0x7B, /* 61 [0x3D] [ */ 145 KC_IGNORE, 0, 0, /* 62 [0x3E] */ 146 KC_IGNORE, 0, 0, /* 63 [0x3F] */ 147 KC_IGNORE, 0, 0, /* 64 [0x40] */ 148 KC_IGNORE, 0, 0, /* 65 [0x41] */ 149 KC_CODE, 0x61, 0x41, /* 66 [0x42] a */ 150 KC_CODE, 0x73, 0x53, /* 67 [0x43] s */ 151 KC_CODE, 0x64, 0x44, /* 68 [0x44] d */ 152 KC_CODE, 0x66, 0x46, /* 69 [0x45] f */ 153 KC_CODE, 0x67, 0x47, /* 70 [0x46] g */ 154 KC_CODE, 0x68, 0x48, /* 71 [0x47] h */ 155 KC_CODE, 0x6A, 0x4A, /* 72 [0x48] j */ 156 KC_CODE, 0x6B, 0x4B, /* 73 [0x49] k */ 157 KC_CODE, 0x6C, 0x4C, /* 74 [0x4A] l */ 158 KC_CODE, 0x3B, 0x2B, /* 75 [0x4B] ; */ 159 KC_CODE, 0x3A, 0x2A, /* 76 [0x4C] : */ 160 KC_CODE, 0x5D, 0x7D, /* 77 [0x4D] ] */ 161 KC_IGNORE, 0, 0, /* 78 [0x4E] */ 162 KC_IGNORE, 0, 0, /* 79 [0x4F] */ 163 KC_IGNORE, 0, 0, /* 80 [0x50] */ 164 KC_IGNORE, 0, 0, /* 81 [0x51] */ 165 KC_CODE, 0x7A, 0x5A, /* 82 [0x52] z */ 166 KC_CODE, 0x78, 0x58, /* 83 [0x53] x */ 167 KC_CODE, 0x63, 0x43, /* 84 [0x54] c */ 168 KC_CODE, 0x76, 0x56, /* 85 [0x55] v */ 169 KC_CODE, 0x62, 0x42, /* 86 [0x56] b */ 170 KC_CODE, 0x6E, 0x4E, /* 87 [0x57] n */ 171 KC_CODE, 0x6D, 0x4D, /* 88 [0x58] m */ 172 KC_CODE, 0x2C, 0x3C, /* 89 [0x59] , */ 173 KC_CODE, 0x2E, 0x3E, /* 90 [0x5A] . */ 174 KC_CODE, 0x2F, 0x3F, /* 91 [0x5B] / */ 175 KC_CODE, 0x5F, 0x5F, /* 92 [0x5C] _ */ 176 KC_IGNORE, 0, 0, /* 93 [0x5D] */ 177 KC_IGNORE, 0, 0, /* 94 [0x5E] */ 178 KC_IGNORE, 0, 0, /* 95 [0x5F] */ 179 KC_IGNORE, 0, 0, /* 96 [0x60] */ 180 KC_IGNORE, 0, 0, /* 97 [0x61] */ 181 KC_IGNORE, 0, 0, /* 98 [0x62] */ 182 KC_IGNORE, 0, 0, /* 99 [0x63] */ 183 KC_IGNORE, 0, 0, /* 100 [0x64] */ 184 KC_IGNORE, 0, 0, /* 101 [0x65] */ 185 KC_IGNORE, 0, 0, /* 102 [0x66] */ 186 KC_IGNORE, 0, 0, /* 103 [0x67] */ 187 KC_IGNORE, 0, 0, /* 104 [0x68] */ 188 KC_IGNORE, 0, 0, /* 105 [0x69] */ 189 KC_IGNORE, 0, 0, /* 106 [0x6A] */ 190 KC_IGNORE, 0, 0, /* 107 [0x6B] */ 191 KC_IGNORE, 0, 0, /* 108 [0x6C] */ 192 KC_IGNORE, 0, 0, /* 109 [0x6D] */ 193 KC_IGNORE, 0, 0, /* 110 [0x6E] */ 194 KC_IGNORE, 0, 0, /* 111 [0x6F] */ 195 KC_IGNORE, 0, 0, /* 112 [0x70] */ 196 KC_IGNORE, 0, 0, /* 113 [0x71] */ 197 KC_IGNORE, 0, 0, /* 114 [0x72] */ 198 KC_IGNORE, 0, 0, /* 115 [0x73] */ 199 KC_IGNORE, 0, 0, /* 116 [0x74] */ 200 KC_IGNORE, 0, 0, /* 117 [0x75] */ 201 KC_IGNORE, 0, 0, /* 118 [0x76] */ 202 KC_IGNORE, 0, 0, /* 119 [0x77] */ 203 KC_IGNORE, 0, 0, /* 120 [0x78] */ 204 KC_IGNORE, 0, 0, /* 121 [0x79] */ 205 KC_IGNORE, 0, 0, /* 122 [0x7A] */ 206 KC_IGNORE, 0, 0, /* 123 [0x7B] */ 207 KC_IGNORE, 0, 0, /* 124 [0x7C] */ 208 KC_IGNORE, 0, 0, /* 125 [0x7D] */ 209 KC_IGNORE, 0, 0, /* 126 [0x7E] */ 210 KC_IGNORE, 0, 0, /* 127 [0x7F] */ 211 }; 212 213 int shift_flag = 0; 214 int ctrl_flag = 0; 215 int meta_flag = 0; 216 217 bmc_decode(code) 218 register u_char code; 219 { 220 register unsigned int c, updown; 221 222 if (code & 0x80) 223 updown = 1; 224 else 225 updown = 0; 226 227 code &= 0x7F; 228 229 c = bmc_keymap[code].km_type; 230 231 switch(c) { 232 233 case KC_CODE: 234 if (updown) 235 c = KC_IGNORE; 236 break; 237 238 case KC_SHIFT: 239 switch(bmc_keymap[code].km_code[0]) { 240 case KS_SHIFT: 241 shift_flag = 1 - updown; 242 break; 243 244 case KS_CTRL: 245 ctrl_flag = 1 - updown; 246 break; 247 248 case KS_META: 249 meta_flag = 1 - updown; 250 break; 251 } 252 break; 253 254 default: 255 break; 256 } 257 258 c |= bmc_keymap[code].km_code[shift_flag]; 259 260 if (bmc_keymap[code].km_type == KC_CODE) { 261 if (meta_flag) 262 c |= 0x0080; 263 if (ctrl_flag) 264 c &= 0xFF1F; 265 } 266 267 return(c); 268 } 269 270 271 /* 272 * probe routine 273 */ 274 275 bmcprobe(hd) 276 register struct hp_device *hd; 277 { 278 int unit = hd->hp_unit; 279 register struct bmc_softc *sc = &bmc_softc[unit]; 280 register struct sio_portc *pc; 281 282 if (sc->sc_pc != 0) { 283 pc = sc->sc_pc; 284 printf("bmc%d: port %d, address 0x%x, intr 0x%x (console)\n", 285 pc->pc_unit, pc->pc_port, pc->pc_addr, pc->pc_intr); 286 return(1); 287 } 288 289 /* 290 * Check out bitmap Interface board 291 */ 292 293 if (KernInter.plane == 0) { 294 return(0); 295 } 296 297 /* locate the major number */ 298 for (bmcmajor = 0; bmcmajor < nchrdev; bmcmajor++) 299 if (cdevsw[bmcmajor].d_open == bmcopen) 300 break; 301 302 sc->sc_pc = pc = sio_port_assign(BMC_PORT, bmcmajor, unit, bmcintr); 303 304 printf("bmc%d: port %d, address 0x%x, intr 0x%x\n", 305 pc->pc_unit, pc->pc_port, pc->pc_addr, pc->pc_intr); 306 307 bmdinit(); 308 309 bmc_active |= 1 << unit; 310 return(1); 311 } 312 313 /* 314 * entry routines 315 */ 316 317 /* ARGSUSED */ 318 #ifdef __STDC__ 319 bmcopen(dev_t dev, int flag, int mode, struct proc *p) 320 #else 321 bmcopen(dev, flag, mode, p) 322 dev_t dev; 323 int flag, mode; 324 struct proc *p; 325 #endif 326 { 327 register struct tty *tp; 328 register int unit; 329 int error = 0; 330 331 unit = bmcunit(dev); 332 333 if (unit >= NBMC) 334 return (ENXIO); 335 if ((bmc_active & (1 << unit)) == 0) 336 return (ENXIO); 337 338 tp = &bmc_tty[unit]; 339 tp->t_oproc = bmcstart; 340 tp->t_param = bmcparam; 341 tp->t_dev = dev; 342 if ((tp->t_state & TS_ISOPEN) == 0) { 343 tp->t_state |= TS_WOPEN; 344 ttychars(tp); 345 if (tp->t_ispeed == 0) { 346 tp->t_iflag = TTYDEF_IFLAG; 347 tp->t_oflag = TTYDEF_OFLAG; 348 tp->t_cflag = TTYDEF_CFLAG; 349 /* tp->t_cflag = (CREAD | CS8 | HUPCL); */ 350 tp->t_lflag = TTYDEF_LFLAG; 351 tp->t_ispeed = tp->t_ospeed = bmcdefaultrate; 352 } 353 bmcparam(tp, &tp->t_termios); 354 ttsetwater(tp); 355 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 356 return (EBUSY); 357 tp->t_state |= TS_CARR_ON; 358 (void) spltty(); 359 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 360 (tp->t_state & TS_CARR_ON) == 0) { 361 tp->t_state |= TS_WOPEN; 362 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 363 ttopen, 0)) 364 break; 365 } 366 (void) spl0(); 367 if (error == 0) 368 error = (*linesw[tp->t_line].l_open)(dev, tp); 369 370 return (error); 371 } 372 373 /*ARGSUSED*/ 374 bmcclose(dev, flag, mode, p) 375 dev_t dev; 376 int flag, mode; 377 struct proc *p; 378 { 379 register struct tty *tp; 380 register int unit; 381 382 unit = bmcunit(dev); 383 tp = &bmc_tty[unit]; 384 (*linesw[tp->t_line].l_close)(tp, flag); 385 ttyclose(tp); 386 return (0); 387 } 388 389 bmcread(dev, uio, flag) 390 dev_t dev; 391 struct uio *uio; 392 { 393 register struct tty *tp = &bmc_tty[bmcunit(dev)]; 394 395 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 396 } 397 398 bmcwrite(dev, uio, flag) 399 dev_t dev; 400 struct uio *uio; 401 { 402 register int unit = bmcunit(dev); 403 register struct tty *tp = &bmc_tty[unit]; 404 405 if ((unit == bmcconsole) && constty && 406 (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN)) 407 tp = constty; 408 409 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 410 } 411 412 /* 413 * Stop output on a line. 414 */ 415 /*ARGSUSED*/ 416 bmcstop(tp, flag) 417 register struct tty *tp; 418 { 419 register int s; 420 421 s = spltty(); 422 if (tp->t_state & TS_BUSY) { 423 if ((tp->t_state&TS_TTSTOP)==0) 424 tp->t_state |= TS_FLUSH; 425 } 426 splx(s); 427 } 428 429 bmcioctl(dev, cmd, data, flag, p) 430 dev_t dev; 431 int cmd; 432 caddr_t data; 433 int flag; 434 struct proc *p; 435 { 436 register struct tty *tp; 437 register int unit = bmcunit(dev); 438 register int error; 439 440 tp = &bmc_tty[unit]; 441 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 442 if (error >= 0) 443 return (error); 444 error = ttioctl(tp, cmd, data, flag); 445 if (error >= 0) 446 return (error); 447 448 switch (cmd) { 449 default: 450 return (ENOTTY); 451 } 452 return (0); 453 } 454 455 /* 456 * 457 */ 458 void 459 bmcstart(tp) 460 register struct tty *tp; 461 { 462 int unit = bmcunit(tp->t_dev); 463 register struct bmc_softc *sc = &bmc_softc[unit]; 464 register int cc, s; 465 int hiwat = 0; 466 467 s = spltty(); 468 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) { 469 splx(s); 470 return; 471 } 472 tp->t_state |= TS_BUSY; 473 cc = tp->t_outq.c_cc; 474 if (cc <= tp->t_lowat) { 475 if (tp->t_state & TS_ASLEEP) { 476 tp->t_state &= ~TS_ASLEEP; 477 wakeup((caddr_t)&tp->t_outq); 478 } 479 selwakeup(&tp->t_wsel); 480 } 481 /* 482 * Limit the amount of output we do in one burst 483 * to prevent hogging the CPU. 484 */ 485 while (--cc >= 0) { 486 register int c; 487 488 c = getc(&tp->t_outq); 489 /* 490 * iteputchar() may take a long time and we don't want to 491 * block all interrupts for long periods of time. Since 492 * there is no need to stay at high priority while outputing 493 * the character (since we don't have to worry about 494 * interrupts), we don't. We just need to make sure that 495 * we don't reenter iteputchar, which is guarenteed by the 496 * earlier setting of TS_BUSY. 497 */ 498 splx(s); 499 bmdputc(c & sc->sc_mask); 500 spltty(); 501 } 502 tp->t_state &= ~TS_BUSY; 503 splx(s); 504 } 505 506 bmcparam(tp, t) 507 register struct tty *tp; 508 register struct termios *t; 509 { 510 int unit = bmcunit(tp->t_dev); 511 register struct bmc_softc *sc = &bmc_softc[unit]; 512 register int cflag = t->c_cflag; 513 514 /* and copy to tty */ 515 tp->t_ispeed = t->c_ispeed; 516 tp->t_ospeed = t->c_ospeed; 517 tp->t_cflag = cflag; 518 519 /* 520 * change line speed 521 */ 522 523 switch (cflag&CSIZE) { 524 case CS5: 525 sc->sc_mask = 0x1F ; break; 526 case CS6: 527 sc->sc_mask = 0x3F ; break; 528 case CS7: 529 sc->sc_mask = 0x7F ; break; 530 case CS8: 531 sc->sc_mask = 0xFF ; break; 532 } 533 534 /* 535 * parity 536 */ 537 538 /* 539 * stop bit 540 */ 541 542 return (0); 543 } 544 545 546 /* 547 * interrupt handling 548 */ 549 550 bmcintr(unit) 551 register int unit; 552 { 553 register struct siodevice *sio = bmc_softc[unit].sc_pc->pc_addr; 554 register struct tty *tp; 555 register u_char code; 556 register int c; 557 int s, rr; 558 559 tp = &bmc_tty[unit]; 560 rr = siogetreg(sio); 561 562 if (rr & RR_RXRDY) { 563 code = sio->sio_data; 564 c = bmc_decode(code); 565 if (c & KC_TYPE) /* skip special codes */ 566 return; 567 code = (c & KC_CHAR); 568 if ((tp->t_state & TS_ISOPEN) != 0) 569 (*linesw[tp->t_line].l_rint)(code, tp); 570 } 571 572 if (rr & RR_TXRDY) { 573 sio->sio_cmd = WR0_RSTPEND; 574 } 575 } 576 577 /* 578 * Following are all routines needed for SIO to act as console 579 */ 580 581 bmccnprobe(cp) 582 register struct consdev *cp; 583 { 584 585 if ((KernInter.dipsw & KIFF_DIPSW_NOBM) || (KernInter.plane == 0)) { 586 cp->cn_pri = CN_DEAD; 587 return; 588 } 589 590 /* locate the major number */ 591 for (bmcmajor = 0; bmcmajor < nchrdev; bmcmajor++) 592 if (cdevsw[bmcmajor].d_open == bmcopen) 593 break; 594 595 /* initialize required fields */ 596 cp->cn_dev = makedev(bmcmajor, 0); 597 cp->cn_tp = &bmc_tty[0]; 598 cp->cn_pri = CN_INTERNAL; 599 } 600 601 bmccninit(cp) 602 struct consdev *cp; 603 { 604 int unit = bmcunit(cp->cn_dev); 605 register struct bmc_softc *sc = &bmc_softc[0]; 606 607 sioinit((struct siodevice *) SIO_HARDADDR, bmcdefaultrate); 608 609 bmdinit(); 610 611 /* port assign */ 612 sc->sc_pc = sio_port_assign(BMC_PORT, bmcmajor, 0, bmcintr); 613 614 bmcconsole = unit; 615 bmc_active |= 1 << unit; 616 } 617 618 bmccngetc(dev) 619 dev_t dev; 620 { 621 struct bmc_softc *sc = &bmc_softc[bmcunit(dev)]; 622 struct sio_portc *pc = sc->sc_pc; 623 register int c; 624 register u_char code; 625 626 do { 627 code = sio_imgetc(pc->pc_addr); 628 } while ((c = bmc_decode(code)) & KC_TYPE); 629 630 return(c); 631 } 632 633 bmccnputc(dev, c) 634 dev_t dev; 635 int c; 636 { 637 struct bmc_softc *sc = &bmc_softc[bmcunit(dev)]; 638 struct sio_portc *pc = sc->sc_pc; 639 640 bmdputc(c); 641 } 642 #endif 643