zs.c revision 1.57 1 /* $NetBSD: zs.c,v 1.57 1998/03/21 20:24:11 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Gordon W. Ross.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Zilog Z8530 Dual UART driver (machine-dependent part)
41 *
42 * Runs two serial lines per chip using slave drivers.
43 * Plain tty/async lines use the zs_async slave.
44 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/conf.h>
50 #include <sys/device.h>
51 #include <sys/file.h>
52 #include <sys/ioctl.h>
53 #include <sys/kernel.h>
54 #include <sys/proc.h>
55 #include <sys/tty.h>
56 #include <sys/time.h>
57 #include <sys/syslog.h>
58
59 #include <machine/autoconf.h>
60 #include <machine/bsd_openprom.h>
61 #include <machine/conf.h>
62 #include <machine/cpu.h>
63 #include <machine/eeprom.h>
64 #include <machine/psl.h>
65 #include <machine/z8530var.h>
66
67 #include <dev/cons.h>
68 #include <dev/ic/z8530reg.h>
69
70 #include <sparc/sparc/vaddrs.h>
71 #include <sparc/sparc/auxreg.h>
72 #include <sparc/dev/cons.h>
73
74 #include "kbd.h" /* NKBD */
75 #include "zs.h" /* NZS */
76
77 /* Make life easier for the initialized arrays here. */
78 #if NZS < 3
79 #undef NZS
80 #define NZS 3
81 #endif
82
83 /*
84 * Some warts needed by z8530tty.c -
85 * The default parity REALLY needs to be the same as the PROM uses,
86 * or you can not see messages done with printf during boot-up...
87 */
88 int zs_def_cflag = (CREAD | CS8 | HUPCL);
89 int zs_major = 12;
90
91 /*
92 * The Sun provides a 4.9152 MHz clock to the ZS chips.
93 */
94 #define PCLK (9600 * 512) /* PCLK pin input clock rate */
95
96 /*
97 * Select software interrupt bit based on TTY ipl.
98 */
99 #if PIL_TTY == 1
100 # define IE_ZSSOFT IE_L1
101 #elif PIL_TTY == 4
102 # define IE_ZSSOFT IE_L4
103 #elif PIL_TTY == 6
104 # define IE_ZSSOFT IE_L6
105 #else
106 # error "no suitable software interrupt bit"
107 #endif
108
109 /*
110 * The next three variables provide a shortcut to the channel state
111 * structure used by zscnputc().
112 */
113 int zs_console_unit = -1;
114 int zs_console_channel = -1;
115 struct zs_chanstate *zs_conschanstate;
116
117 #define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2))
118
119 /* The layout of this is hardware-dependent (padding, order). */
120 struct zschan {
121 volatile u_char zc_csr; /* ctrl,status, and indirect access */
122 u_char zc_xxx0;
123 volatile u_char zc_data; /* data */
124 u_char zc_xxx1;
125 };
126 struct zsdevice {
127 /* Yes, they are backwards. */
128 struct zschan zs_chan_b;
129 struct zschan zs_chan_a;
130 };
131
132 /* Saved PROM mappings */
133 static struct zsdevice *zsaddr[NZS];
134
135 /* Flags from cninit() */
136 static int zs_hwflags[NZS][2];
137
138 /* Default speed for each channel */
139 static int zs_defspeed[NZS][2] = {
140 { 9600, /* ttya */
141 9600 }, /* ttyb */
142 { 1200, /* keyboard */
143 1200 }, /* mouse */
144 { 9600, /* ttyc */
145 9600 }, /* ttyd */
146 };
147
148 static u_char zs_init_reg[16] = {
149 0, /* 0: CMD (reset, etc.) */
150 0, /* 1: No interrupts yet. */
151 0, /* 2: IVECT */
152 ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
153 ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
154 ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
155 0, /* 6: TXSYNC/SYNCLO */
156 0, /* 7: RXSYNC/SYNCHI */
157 0, /* 8: alias for data port */
158 ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR,
159 0, /*10: Misc. TX/RX control bits */
160 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
161 14, /*12: BAUDLO (default=9600) */
162 0, /*13: BAUDHI (default=9600) */
163 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
164 ZSWR15_BREAK_IE | ZSWR15_DCD_IE,
165 };
166
167 struct zschan *
168 zs_get_chan_addr(zs_unit, channel)
169 int zs_unit, channel;
170 {
171 struct zsdevice *addr;
172 struct zschan *zc;
173
174 if (zs_unit >= NZS)
175 return (NULL);
176 addr = zsaddr[zs_unit];
177 if (addr == NULL)
178 addr = zsaddr[zs_unit] = findzs(zs_unit);
179 if (addr == NULL)
180 return (NULL);
181 if (channel == 0) {
182 zc = &addr->zs_chan_a;
183 } else {
184 zc = &addr->zs_chan_b;
185 }
186 return (zc);
187 }
188
189
190 /****************************************************************
191 * Autoconfig
192 ****************************************************************/
193
194 /* Definition of the driver for autoconfig. */
195 static int zs_match_mainbus __P((struct device *, struct cfdata *, void *));
196 static int zs_match_obio __P((struct device *, struct cfdata *, void *));
197 static void zs_attach_mainbus __P((struct device *, struct device *, void *));
198 static void zs_attach_obio __P((struct device *, struct device *, void *));
199
200 static void zs_attach __P((struct zsc_softc *, int));
201 static int zs_print __P((void *, const char *name));
202
203 struct cfattach zs_mainbus_ca = {
204 sizeof(struct zsc_softc), zs_match_mainbus, zs_attach_mainbus
205 };
206
207 struct cfattach zs_obio_ca = {
208 sizeof(struct zsc_softc), zs_match_obio, zs_attach_obio
209 };
210
211 extern struct cfdriver zs_cd;
212
213 /* Interrupt handlers. */
214 static int zshard __P((void *));
215 static int zssoft __P((void *));
216 static struct intrhand levelsoft = { zssoft };
217
218 static int zs_get_speed __P((struct zs_chanstate *));
219
220
221 /*
222 * Is the zs chip present?
223 */
224 static int
225 zs_match_mainbus(parent, cf, aux)
226 struct device *parent;
227 struct cfdata *cf;
228 void *aux;
229 {
230 struct mainbus_attach_args *ma = aux;
231
232 if (strcmp(cf->cf_driver->cd_name, ma->ma_name) != 0)
233 return (0);
234
235 return (getpropint(ma->ma_node, "slave", -2) == cf->cf_unit);
236 }
237
238 static int
239 zs_match_obio(parent, cf, aux)
240 struct device *parent;
241 struct cfdata *cf;
242 void *aux;
243 {
244 union obio_attach_args *uoba = aux;
245 struct obio4_attach_args *oba;
246
247 if (uoba->uoba_isobio4 == 0) {
248 struct sbus_attach_args *sa = &uoba->uoba_sbus;
249
250 if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0)
251 return (0);
252
253 return (getpropint(sa->sa_node, "slave", -2) == cf->cf_unit);
254 }
255
256 oba = &uoba->uoba_oba4;
257 return (obio_bus_probe(oba->oba_bustag, oba->oba_paddr,
258 0, 1, NULL, NULL));
259 }
260
261 static void
262 zs_attach_mainbus(parent, self, aux)
263 struct device *parent;
264 struct device *self;
265 void *aux;
266 {
267 struct zsc_softc *zsc = (void *) self;
268 struct mainbus_attach_args *ma = aux;
269 int zs_unit = zsc->zsc_dev.dv_unit;
270
271 zsc->zsc_bustag = ma->ma_bustag;
272 zsc->zsc_dmatag = ma->ma_dmatag;
273
274 /* Use the mapping setup by the Sun PROM. */
275 if (zsaddr[zs_unit] == NULL)
276 zsaddr[zs_unit] = findzs(zs_unit);
277 if ((void*)zsaddr[zs_unit] != ma->ma_promvaddr)
278 panic("zsattach_mainbus");
279
280 zs_attach(zsc, ma->ma_pri);
281 }
282
283 static void
284 zs_attach_obio(parent, self, aux)
285 struct device *parent;
286 struct device *self;
287 void *aux;
288 {
289 struct zsc_softc *zsc = (void *) self;
290 union obio_attach_args *uoba = aux;
291 int zs_unit = zsc->zsc_dev.dv_unit;
292
293 /* Use the mapping setup by the Sun PROM. */
294 if (zsaddr[zs_unit] == NULL)
295 zsaddr[zs_unit] = findzs(zs_unit);
296
297 if (uoba->uoba_isobio4 == 0) {
298 struct sbus_attach_args *sa = &uoba->uoba_sbus;
299 zsc->zsc_bustag = sa->sa_bustag;
300 zsc->zsc_dmatag = sa->sa_dmatag;
301 zs_attach(zsc, sa->sa_pri);
302 } else {
303 struct obio4_attach_args *oba = &uoba->uoba_oba4;
304 zsc->zsc_bustag = oba->oba_bustag;
305 zsc->zsc_dmatag = oba->oba_dmatag;
306 zs_attach(zsc, oba->oba_pri);
307 }
308 }
309 /*
310 * Attach a found zs.
311 *
312 * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR
313 * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE?
314 */
315 static void
316 zs_attach(zsc, pri)
317 struct zsc_softc *zsc;
318 int pri;
319 {
320 struct zsc_attach_args zsc_args;
321 volatile struct zschan *zc;
322 struct zs_chanstate *cs;
323 int s, zs_unit, channel;
324 static int didintr, prevpri;
325
326 printf(" softpri %d\n", PIL_TTY);
327
328 /*
329 * Initialize software state for each channel.
330 */
331 zs_unit = zsc->zsc_dev.dv_unit;
332 for (channel = 0; channel < 2; channel++) {
333 zsc_args.channel = channel;
334 zsc_args.hwflags = zs_hwflags[zs_unit][channel];
335 cs = &zsc->zsc_cs_store[channel];
336 zsc->zsc_cs[channel] = cs;
337 if (zs_unit == zs_console_unit &&
338 channel == zs_console_channel) {
339 zs_conschanstate = cs;
340 }
341
342 cs->cs_channel = channel;
343 cs->cs_private = NULL;
344 cs->cs_ops = &zsops_null;
345 cs->cs_brg_clk = PCLK / 16;
346
347 zc = zs_get_chan_addr(zs_unit, channel);
348 cs->cs_reg_csr = &zc->zc_csr;
349 cs->cs_reg_data = &zc->zc_data;
350
351 bcopy(zs_init_reg, cs->cs_creg, 16);
352 bcopy(zs_init_reg, cs->cs_preg, 16);
353
354 /* XXX: Get these from the PROM properties! */
355 /* XXX: See the mvme167 code. Better. */
356 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
357 cs->cs_defspeed = zs_get_speed(cs);
358 else
359 cs->cs_defspeed = zs_defspeed[zs_unit][channel];
360 cs->cs_defcflag = zs_def_cflag;
361
362 /* Make these correspond to cs_defcflag (-crtscts) */
363 cs->cs_rr0_dcd = ZSRR0_DCD;
364 cs->cs_rr0_cts = 0;
365 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
366 cs->cs_wr5_rts = 0;
367
368 /*
369 * Clear the master interrupt enable.
370 * The INTENA is common to both channels,
371 * so just do it on the A channel.
372 */
373 if (channel == 0) {
374 zs_write_reg(cs, 9, 0);
375 }
376
377 /*
378 * Look for a child driver for this channel.
379 * The child attach will setup the hardware.
380 */
381 if (!config_found(&zsc->zsc_dev, (void *)&zsc_args, zs_print)) {
382 /* No sub-driver. Just reset it. */
383 u_char reset = (channel == 0) ?
384 ZSWR9_A_RESET : ZSWR9_B_RESET;
385 s = splzs();
386 zs_write_reg(cs, 9, reset);
387 splx(s);
388 }
389 }
390
391 /*
392 * Now safe to install interrupt handlers. Note the arguments
393 * to the interrupt handlers aren't used. Note, we only do this
394 * once since both SCCs interrupt at the same level and vector.
395 */
396 if (!didintr) {
397 didintr = 1;
398 prevpri = pri;
399 bus_intr_establish(zsc->zsc_bustag, pri, 0, zshard, NULL);
400 intr_establish(PIL_TTY, &levelsoft);
401 } else if (pri != prevpri)
402 panic("broken zs interrupt scheme");
403
404 evcnt_attach(&zsc->zsc_dev, "intr", &zsc->zsc_intrcnt);
405
406 /*
407 * Set the master interrupt enable and interrupt vector.
408 * (common to both channels, do it on A)
409 */
410 cs = zsc->zsc_cs[0];
411 s = splhigh();
412 /* interrupt vector */
413 zs_write_reg(cs, 2, zs_init_reg[2]);
414 /* master interrupt control (enable) */
415 zs_write_reg(cs, 9, zs_init_reg[9]);
416 splx(s);
417
418 #if 0
419 /*
420 * XXX: L1A hack - We would like to be able to break into
421 * the debugger during the rest of autoconfiguration, so
422 * lower interrupts just enough to let zs interrupts in.
423 * This is done after both zs devices are attached.
424 */
425 if (zs_unit == 1) {
426 printf("zs1: enabling zs interrupts\n");
427 (void)splfd(); /* XXX: splzs - 1 */
428 }
429 #endif
430 }
431
432 static int
433 zs_print(aux, name)
434 void *aux;
435 const char *name;
436 {
437 struct zsc_attach_args *args = aux;
438
439 if (name != NULL)
440 printf("%s: ", name);
441
442 if (args->channel != -1)
443 printf(" channel %d", args->channel);
444
445 return (UNCONF);
446 }
447
448 static volatile int zssoftpending;
449
450 /*
451 * Our ZS chips all share a common, autovectored interrupt,
452 * so we have to look at all of them on each interrupt.
453 */
454 static int
455 zshard(arg)
456 void *arg;
457 {
458 register struct zsc_softc *zsc;
459 register int unit, rr3, rval, softreq;
460
461 rval = softreq = 0;
462 for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
463 zsc = zs_cd.cd_devs[unit];
464 if (zsc == NULL)
465 continue;
466 rr3 = zsc_intr_hard(zsc);
467 /* Count up the interrupts. */
468 if (rr3) {
469 rval |= rr3;
470 zsc->zsc_intrcnt.ev_count++;
471 }
472 softreq |= zsc->zsc_cs[0]->cs_softreq;
473 softreq |= zsc->zsc_cs[1]->cs_softreq;
474 }
475
476 /* We are at splzs here, so no need to lock. */
477 if (softreq && (zssoftpending == 0)) {
478 zssoftpending = IE_ZSSOFT;
479 #if defined(SUN4M)
480 if (CPU_ISSUN4M)
481 raise(0, PIL_TTY);
482 else
483 #endif
484 ienab_bis(IE_ZSSOFT);
485 }
486 return (rval);
487 }
488
489 /*
490 * Similar scheme as for zshard (look at all of them)
491 */
492 static int
493 zssoft(arg)
494 void *arg;
495 {
496 register struct zsc_softc *zsc;
497 register int s, unit;
498
499 /* This is not the only ISR on this IPL. */
500 if (zssoftpending == 0)
501 return (0);
502
503 /*
504 * The soft intr. bit will be set by zshard only if
505 * the variable zssoftpending is zero. The order of
506 * these next two statements prevents our clearing
507 * the soft intr bit just after zshard has set it.
508 */
509 /* ienab_bic(IE_ZSSOFT); */
510 zssoftpending = 0;
511
512 /* Make sure we call the tty layer at spltty. */
513 s = spltty();
514 for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
515 zsc = zs_cd.cd_devs[unit];
516 if (zsc == NULL)
517 continue;
518 (void)zsc_intr_soft(zsc);
519 }
520 splx(s);
521 return (1);
522 }
523
524
525 /*
526 * Compute the current baud rate given a ZS channel.
527 */
528 static int
529 zs_get_speed(cs)
530 struct zs_chanstate *cs;
531 {
532 int tconst;
533
534 tconst = zs_read_reg(cs, 12);
535 tconst |= zs_read_reg(cs, 13) << 8;
536 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst));
537 }
538
539 /*
540 * MD functions for setting the baud rate and control modes.
541 */
542 int
543 zs_set_speed(cs, bps)
544 struct zs_chanstate *cs;
545 int bps; /* bits per second */
546 {
547 int tconst, real_bps;
548
549 if (bps == 0)
550 return (0);
551
552 #ifdef DIAGNOSTIC
553 if (cs->cs_brg_clk == 0)
554 panic("zs_set_speed");
555 #endif
556
557 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
558 if (tconst < 0)
559 return (EINVAL);
560
561 /* Convert back to make sure we can do it. */
562 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
563
564 /* XXX - Allow some tolerance here? */
565 if (real_bps != bps)
566 return (EINVAL);
567
568 cs->cs_preg[12] = tconst;
569 cs->cs_preg[13] = tconst >> 8;
570
571 /* Caller will stuff the pending registers. */
572 return (0);
573 }
574
575 int
576 zs_set_modes(cs, cflag)
577 struct zs_chanstate *cs;
578 int cflag; /* bits per second */
579 {
580 int s;
581
582 /*
583 * Output hardware flow control on the chip is horrendous:
584 * if carrier detect drops, the receiver is disabled, and if
585 * CTS drops, the transmitter is stoped IN MID CHARACTER!
586 * Therefore, NEVER set the HFC bit, and instead use the
587 * status interrupt to detect CTS changes.
588 */
589 s = splzs();
590 if ((cflag & (CLOCAL | MDMBUF)) != 0)
591 cs->cs_rr0_dcd = 0;
592 else
593 cs->cs_rr0_dcd = ZSRR0_DCD;
594 if ((cflag & CRTSCTS) != 0) {
595 cs->cs_wr5_dtr = ZSWR5_DTR;
596 cs->cs_wr5_rts = ZSWR5_RTS;
597 cs->cs_rr0_cts = ZSRR0_CTS;
598 } else if ((cflag & CDTRCTS) != 0) {
599 cs->cs_wr5_dtr = 0;
600 cs->cs_wr5_rts = ZSWR5_DTR;
601 cs->cs_rr0_cts = ZSRR0_CTS;
602 } else if ((cflag & MDMBUF) != 0) {
603 cs->cs_wr5_dtr = 0;
604 cs->cs_wr5_rts = ZSWR5_DTR;
605 cs->cs_rr0_cts = ZSRR0_DCD;
606 } else {
607 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
608 cs->cs_wr5_rts = 0;
609 cs->cs_rr0_cts = 0;
610 }
611 splx(s);
612
613 /* Caller will stuff the pending registers. */
614 return (0);
615 }
616
617
618 /*
619 * Read or write the chip with suitable delays.
620 */
621
622 u_char
623 zs_read_reg(cs, reg)
624 struct zs_chanstate *cs;
625 u_char reg;
626 {
627 u_char val;
628
629 *cs->cs_reg_csr = reg;
630 ZS_DELAY();
631 val = *cs->cs_reg_csr;
632 ZS_DELAY();
633 return (val);
634 }
635
636 void
637 zs_write_reg(cs, reg, val)
638 struct zs_chanstate *cs;
639 u_char reg, val;
640 {
641 *cs->cs_reg_csr = reg;
642 ZS_DELAY();
643 *cs->cs_reg_csr = val;
644 ZS_DELAY();
645 }
646
647 u_char
648 zs_read_csr(cs)
649 struct zs_chanstate *cs;
650 {
651 register u_char val;
652
653 val = *cs->cs_reg_csr;
654 ZS_DELAY();
655 return (val);
656 }
657
658 void zs_write_csr(cs, val)
659 struct zs_chanstate *cs;
660 u_char val;
661 {
662 *cs->cs_reg_csr = val;
663 ZS_DELAY();
664 }
665
666 u_char zs_read_data(cs)
667 struct zs_chanstate *cs;
668 {
669 register u_char val;
670
671 val = *cs->cs_reg_data;
672 ZS_DELAY();
673 return (val);
674 }
675
676 void zs_write_data(cs, val)
677 struct zs_chanstate *cs;
678 u_char val;
679 {
680 *cs->cs_reg_data = val;
681 ZS_DELAY();
682 }
683
684 /****************************************************************
685 * Console support functions (Sun specific!)
686 * Note: this code is allowed to know about the layout of
687 * the chip registers, and uses that to keep things simple.
688 * XXX - I think I like the mvme167 code better. -gwr
689 ****************************************************************/
690
691 extern void Debugger __P((void));
692 void *zs_conschan;
693
694 /*
695 * Handle user request to enter kernel debugger.
696 */
697 void
698 zs_abort(cs)
699 struct zs_chanstate *cs;
700 {
701 register volatile struct zschan *zc = zs_conschan;
702 int rr0;
703
704 /* Wait for end of break to avoid PROM abort. */
705 /* XXX - Limit the wait? */
706 do {
707 rr0 = zc->zc_csr;
708 ZS_DELAY();
709 } while (rr0 & ZSRR0_BREAK);
710
711 #if defined(KGDB)
712 zskgdb(cs);
713 #elif defined(DDB)
714 Debugger();
715 #else
716 printf("stopping on keyboard abort\n");
717 callrom();
718 #endif
719 }
720
721 /*
722 * Polled input char.
723 */
724 int
725 zs_getc(arg)
726 void *arg;
727 {
728 register volatile struct zschan *zc = arg;
729 register int s, c, rr0;
730
731 s = splhigh();
732 /* Wait for a character to arrive. */
733 do {
734 rr0 = zc->zc_csr;
735 ZS_DELAY();
736 } while ((rr0 & ZSRR0_RX_READY) == 0);
737
738 c = zc->zc_data;
739 ZS_DELAY();
740 splx(s);
741
742 /*
743 * This is used by the kd driver to read scan codes,
744 * so don't translate '\r' ==> '\n' here...
745 */
746 return (c);
747 }
748
749 /*
750 * Polled output char.
751 */
752 void
753 zs_putc(arg, c)
754 void *arg;
755 int c;
756 {
757 register volatile struct zschan *zc = arg;
758 register int s, rr0;
759
760 s = splhigh();
761 /* Wait for transmitter to become ready. */
762 do {
763 rr0 = zc->zc_csr;
764 ZS_DELAY();
765 } while ((rr0 & ZSRR0_TX_READY) == 0);
766
767 /*
768 * If the transmitter was busy doing regular tty I/O (ZSWR1_TIE on),
769 * defer our output until the transmit interrupt runs. We still
770 * sync with TX_READY so we can get by with a single-char "queue".
771 */
772 if (zs_conschanstate && (zs_conschanstate->cs_preg[1] & ZSWR1_TIE)) {
773 /*
774 * If a previous held character has not yet gone out, we can
775 * send it now; zsxint() will field the interrupt for our
776 * char, but doesn't care. We're running at sufficiently
777 * high spl for this to work.
778 */
779 if (zs_conschanstate->cs_heldchar != 0)
780 zc->zc_data = zs_conschanstate->cs_heldchar;
781 zs_conschanstate->cs_heldchar = c;
782 ZS_DELAY();
783 splx(s);
784 return;
785 }
786
787 zc->zc_data = c;
788 ZS_DELAY();
789 splx(s);
790 }
791
792 /*****************************************************************/
793
794 static void zscninit __P((struct consdev *));
795 static int zscngetc __P((dev_t));
796 static void zscnputc __P((dev_t, int));
797
798 /*
799 * Console table shared by ttya, ttyb
800 */
801 struct consdev consdev_tty = {
802 nullcnprobe,
803 zscninit,
804 zscngetc,
805 zscnputc,
806 nullcnpollc,
807 };
808
809 static void
810 zscninit(cn)
811 struct consdev *cn;
812 {
813 }
814
815 /*
816 * Polled console input putchar.
817 */
818 static int
819 zscngetc(dev)
820 dev_t dev;
821 {
822 return (zs_getc(zs_conschan));
823 }
824
825 /*
826 * Polled console output putchar.
827 */
828 static void
829 zscnputc(dev, c)
830 dev_t dev;
831 int c;
832 {
833 zs_putc(zs_conschan, c);
834 }
835
836 /*****************************************************************/
837
838 static void prom_cninit __P((struct consdev *));
839 static int prom_cngetc __P((dev_t));
840 static void prom_cnputc __P((dev_t, int));
841
842 /*
843 * The console is set to this one initially,
844 * which lets us use the PROM until consinit()
845 * is called to select a real console.
846 */
847 struct consdev consdev_prom = {
848 nullcnprobe,
849 prom_cninit,
850 prom_cngetc,
851 prom_cnputc,
852 nullcnpollc,
853 };
854
855 /*
856 * The console table pointer is statically initialized
857 * to point to the PROM (output only) table, so that
858 * early calls to printf will work.
859 */
860 struct consdev *cn_tab = &consdev_prom;
861
862 void
863 nullcnprobe(cn)
864 struct consdev *cn;
865 {
866 }
867
868 static void
869 prom_cninit(cn)
870 struct consdev *cn;
871 {
872 }
873
874 /*
875 * PROM console input putchar.
876 * (dummy - this is output only)
877 */
878 static int
879 prom_cngetc(dev)
880 dev_t dev;
881 {
882 return (0);
883 }
884
885 /*
886 * PROM console output putchar.
887 */
888 static void
889 prom_cnputc(dev, c)
890 dev_t dev;
891 int c;
892 {
893 char c0 = (c & 0x7f);
894
895 if (promvec->pv_romvec_vers > 2)
896 (*promvec->pv_v2devops.v2_write)
897 (*promvec->pv_v2bootargs.v2_fd1, &c0, 1);
898 else
899 (*promvec->pv_putchar)(c);
900 }
901
902 /*****************************************************************/
903
904 extern struct consdev consdev_kd;
905
906 static char *prom_inSrc_name[] = {
907 "keyboard/display",
908 "ttya", "ttyb",
909 "ttyc", "ttyd" };
910
911 /*
912 * This function replaces sys/dev/cninit.c
913 * Determine which device is the console using
914 * the PROM "input source" and "output sink".
915 */
916 void
917 consinit()
918 {
919 struct zschan *zc;
920 struct consdev *cn;
921 int channel, zs_unit, zstty_unit;
922 int inSource, outSink;
923
924 if (promvec->pv_romvec_vers > 2) {
925 /* We need to probe the PROM device tree */
926 register int node,fd;
927 char buffer[128];
928 register struct nodeops *no;
929 register struct v2devops *op;
930 register char *cp;
931 extern int fbnode;
932
933 inSource = outSink = -1;
934 no = promvec->pv_nodeops;
935 op = &promvec->pv_v2devops;
936
937 node = findroot();
938 if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) {
939 printf("consinit: increase buffer size and recompile\n");
940 goto setup_output;
941 }
942 /* XXX: fix above */
943
944 no->no_getprop(node, "stdin-path",buffer);
945
946 /*
947 * Open an "instance" of this device.
948 * You'd think it would be appropriate to call v2_close()
949 * on the handle when we're done with it. But that seems
950 * to cause the device to shut down somehow; for the moment,
951 * we simply leave it open...
952 */
953 if ((fd = op->v2_open(buffer)) == 0 ||
954 (node = op->v2_fd_phandle(fd)) == 0) {
955 printf("consinit: bogus stdin path %s.\n",buffer);
956 goto setup_output;
957 }
958 if (no->no_proplen(node,"keyboard") >= 0) {
959 inSource = PROMDEV_KBD;
960 goto setup_output;
961 }
962 if (strcmp(getpropstring(node,"device_type"),"serial") != 0) {
963 /* not a serial, not keyboard. what is it?!? */
964 inSource = -1;
965 goto setup_output;
966 }
967 /*
968 * At this point we assume the device path is in the form
969 * ....device@x,y:a for ttya and ...device@x,y:b for ttyb.
970 * If it isn't, we defer to the ROM
971 */
972 cp = buffer;
973 while (*cp)
974 cp++;
975 cp -= 2;
976 #ifdef DEBUG
977 if (cp < buffer)
978 panic("consinit: bad stdin path %s",buffer);
979 #endif
980 /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
981 if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
982 inSource = PROMDEV_TTYA + (cp[1] - 'a');
983 /* else use rom */
984 setup_output:
985 node = findroot();
986 if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) {
987 printf("consinit: increase buffer size and recompile\n");
988 goto setup_console;
989 }
990 /* XXX: fix above */
991
992 no->no_getprop(node, "stdout-path", buffer);
993
994 if ((fd = op->v2_open(buffer)) == 0 ||
995 (node = op->v2_fd_phandle(fd)) == 0) {
996 printf("consinit: bogus stdout path %s.\n",buffer);
997 goto setup_output;
998 }
999 if (strcmp(getpropstring(node,"device_type"),"display") == 0) {
1000 /* frame buffer output */
1001 outSink = PROMDEV_SCREEN;
1002 fbnode = node;
1003 } else if (strcmp(getpropstring(node,"device_type"), "serial")
1004 != 0) {
1005 /* not screen, not serial. Whatzit? */
1006 outSink = -1;
1007 } else { /* serial console. which? */
1008 /*
1009 * At this point we assume the device path is in the
1010 * form:
1011 * ....device@x,y:a for ttya, etc.
1012 * If it isn't, we defer to the ROM
1013 */
1014 cp = buffer;
1015 while (*cp)
1016 cp++;
1017 cp -= 2;
1018 #ifdef DEBUG
1019 if (cp < buffer)
1020 panic("consinit: bad stdout path %s",buffer);
1021 #endif
1022 /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
1023 if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
1024 outSink = PROMDEV_TTYA + (cp[1] - 'a');
1025 else outSink = -1;
1026 }
1027 } else {
1028 inSource = *promvec->pv_stdin;
1029 outSink = *promvec->pv_stdout;
1030 }
1031
1032 setup_console:
1033
1034 if (inSource != outSink) {
1035 printf("cninit: mismatched PROM output selector\n");
1036 }
1037
1038 switch (inSource) {
1039 default:
1040 printf("cninit: invalid inSource=%d\n", inSource);
1041 callrom();
1042 inSource = PROMDEV_KBD;
1043 /* fall through */
1044
1045 case 0: /* keyboard/display */
1046 #if NKBD > 0
1047 zs_unit = 1; /* XXX - config info! */
1048 channel = 0;
1049 cn = &consdev_kd;
1050 /* Set cn_dev, cn_pri in kd.c */
1051 break;
1052 #else /* NKBD */
1053 printf("cninit: kdb/display not configured\n");
1054 callrom();
1055 inSource = PROMDEV_TTYA;
1056 /* fall through */
1057 #endif /* NKBD */
1058
1059 case PROMDEV_TTYA:
1060 case PROMDEV_TTYB:
1061 zstty_unit = inSource - PROMDEV_TTYA;
1062 zs_unit = 0; /* XXX - config info! */
1063 channel = zstty_unit & 1;
1064 cn = &consdev_tty;
1065 cn->cn_dev = makedev(zs_major, zstty_unit);
1066 cn->cn_pri = CN_REMOTE;
1067 zs_console_unit = zs_unit;
1068 zs_console_channel = channel;
1069 break;
1070
1071 }
1072 /* Now that inSource has been validated, print it. */
1073 printf("console is %s\n", prom_inSrc_name[inSource]);
1074
1075 zc = zs_get_chan_addr(zs_unit, channel);
1076 if (zc == NULL) {
1077 printf("cninit: zs not mapped.\n");
1078 return;
1079 }
1080 zs_conschan = zc;
1081 zs_hwflags[zs_unit][channel] = ZS_HWFLAG_CONSOLE;
1082 cn_tab = cn;
1083 (*cn->cn_init)(cn);
1084 #ifdef KGDB
1085 zs_kgdb_init();
1086 #endif
1087 }
1088