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