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
bmc_decode(code)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
bmcprobe(hd)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__
bmcopen(dev_t dev,int flag,int mode,struct proc * p)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*/
bmcclose(dev,flag,mode,p)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
bmcread(dev,uio,flag)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
bmcwrite(dev,uio,flag)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*/
bmcstop(tp,flag)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
bmcioctl(dev,cmd,data,flag,p)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
bmcstart(tp)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
bmcparam(tp,t)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
bmcintr(unit)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
bmccnprobe(cp)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
bmccngetc(dev)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
bmccnputc(dev,c)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