xref: /netbsd-src/sys/dev/tc/zs_ioasic.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /* $NetBSD: zs_ioasic.c,v 1.2 2000/07/05 07:50:57 nisimura Exp $ */
2 
3 /*-
4  * Copyright (c) 1996, 1998 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, Ken Hornstein, and by Jason R. Thorpe of the
9  * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
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 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
41 
42 __KERNEL_RCSID(0, "$NetBSD: zs_ioasic.c,v 1.2 2000/07/05 07:50:57 nisimura Exp $");
43 
44 /*
45  * Zilog Z8530 Dual UART driver (machine-dependent part).  This driver
46  * handles Z8530 chips attached to the Alpha IOASIC.  Modified for
47  * NetBSD/alpha by Ken Hornstein and Jason R. Thorpe.
48  *
49  * Runs two serial lines per chip using slave drivers.
50  * Plain tty/async lines use the zstty slave.
51  */
52 
53 #include "opt_ddb.h"
54 #include "zskbd.h"
55 
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/conf.h>
59 #include <sys/device.h>
60 #include <sys/file.h>
61 #include <sys/ioctl.h>
62 #include <sys/kernel.h>
63 #include <sys/proc.h>
64 #include <sys/tty.h>
65 #include <sys/time.h>
66 #include <sys/syslog.h>
67 
68 #include <machine/autoconf.h>
69 #include <machine/intr.h>
70 #include <machine/z8530var.h>
71 
72 #include <dev/cons.h>
73 #include <dev/ic/z8530reg.h>
74 
75 #include <dev/tc/tcvar.h>
76 #include <dev/tc/ioasicreg.h>
77 #include <dev/tc/ioasicvar.h>
78 
79 #include <dev/tc/zs_ioasicvar.h>
80 
81 #if 1
82 #define SPARSE
83 #endif
84 
85 /*
86  * Helpers for console support.
87  */
88 
89 int	zs_ioasic_cngetc __P((dev_t));
90 void	zs_ioasic_cnputc __P((dev_t, int));
91 void	zs_ioasic_cnpollc __P((dev_t, int));
92 
93 struct consdev zs_ioasic_cons = {
94 	NULL, NULL, zs_ioasic_cngetc, zs_ioasic_cnputc,
95 	zs_ioasic_cnpollc, NULL, NODEV, CN_NORMAL,
96 };
97 
98 tc_offset_t zs_ioasic_console_offset;
99 int zs_ioasic_console_channel;
100 int zs_ioasic_console;
101 
102 int	zs_ioasic_isconsole __P((tc_offset_t, int));
103 
104 struct zs_chanstate zs_ioasic_conschanstate_store;
105 struct zs_chanstate *zs_ioasic_conschanstate;
106 
107 int	zs_getc __P((struct zs_chanstate *));
108 void	zs_putc __P((struct zs_chanstate *, int));
109 void	zs_ioasic_cninit __P((tc_addr_t, tc_offset_t, int));
110 
111 /*
112  * Some warts needed by z8530tty.c
113  */
114 int zs_def_cflag = (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8;
115 int zs_major = 15;
116 
117 /*
118  * ZS chips are feeded a 7.372 MHz clock.
119  */
120 #define	PCLK	(9600 * 768)	/* PCLK pin input clock rate */
121 
122 /* The layout of this is hardware-dependent (padding, order). */
123 struct zshan {
124 	volatile u_int	zc_csr;		/* ctrl,status, and indirect access */
125 #ifdef SPARSE
126 	u_int		zc_pad0;
127 #endif
128 	volatile u_int	zc_data;	/* data */
129 #ifdef SPARSE
130 	u_int		sc_pad1;
131 #endif
132 };
133 
134 struct zsdevice {
135 	/* Yes, they are backwards. */
136 	struct	zshan zs_chan_b;
137 	struct	zshan zs_chan_a;
138 };
139 
140 static u_char zs_ioasic_init_reg[16] = {
141 	0,	/* 0: CMD (reset, etc.) */
142 	0,	/* 1: No interrupts yet. */
143 	0xf0,	/* 2: IVECT */
144 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
145 	ZSWR4_CLK_X16 | ZSWR4_ONESB,
146 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
147 	0,	/* 6: TXSYNC/SYNCLO */
148 	0,	/* 7: RXSYNC/SYNCHI */
149 	0,	/* 8: alias for data port */
150 	ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT,
151 	0,	/*10: Misc. TX/RX control bits */
152 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
153 	22,	/*12: BAUDLO (default=9600) */
154 	0,	/*13: BAUDHI (default=9600) */
155 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
156 	ZSWR15_BREAK_IE,
157 };
158 
159 struct zshan *zs_ioasic_get_chan_addr __P((tc_addr_t, int));
160 
161 struct zshan *
162 zs_ioasic_get_chan_addr(zsaddr, channel)
163 	tc_addr_t zsaddr;
164 	int channel;
165 {
166 	struct zsdevice *addr;
167 	struct zshan *zc;
168 
169 	addr = (struct zsdevice *) zsaddr;
170 #ifdef SPARSE
171 	addr = (struct zsdevice *) TC_DENSE_TO_SPARSE((tc_addr_t) addr);
172 #endif
173 
174 	if (channel == 0)
175 		zc = &addr->zs_chan_a;
176 	else
177 		zc = &addr->zs_chan_b;
178 
179 	return (zc);
180 }
181 
182 
183 /****************************************************************
184  * Autoconfig
185  ****************************************************************/
186 
187 /* Definition of the driver for autoconfig. */
188 int	zs_ioasic_match __P((struct device *, struct cfdata *, void *));
189 void	zs_ioasic_attach __P((struct device *, struct device *, void *));
190 int	zs_ioasic_print __P((void *, const char *name));
191 
192 struct cfattach zsc_ioasic_ca = {
193 	sizeof(struct zsc_softc), zs_ioasic_match, zs_ioasic_attach
194 };
195 
196 /* Interrupt handlers. */
197 int	zs_ioasic_hardintr __P((void *));
198 void	zs_ioasic_softintr __P((void *));
199 
200 extern struct cfdriver ioasic_cd;
201 extern struct cfdriver zsc_cd;
202 
203 /*
204  * Is the zs chip present?
205  */
206 int
207 zs_ioasic_match(parent, cf, aux)
208 	struct device *parent;
209 	struct cfdata *cf;
210 	void *aux;
211 {
212 	struct ioasicdev_attach_args *d = aux;
213 	void *zs_addr;
214 
215 	if (parent->dv_cfdata->cf_driver != &ioasic_cd)
216 		return (0);
217 
218 	/*
219 	 * Make sure that we're looking for the right kind of device.
220 	 */
221 	if (strncmp(d->iada_modname, "z8530   ", TC_ROM_LLEN) != 0 &&
222 	    strncmp(d->iada_modname, "scc", TC_ROM_LLEN) != 0)
223 		return (0);
224 
225 	/*
226 	 * Check user-specified offset against the ioasic offset.
227 	 * Allow it to be wildcarded.
228 	 */
229 	if (cf->cf_loc[IOASICCF_OFFSET] != IOASICCF_OFFSET_DEFAULT &&
230 	    cf->cf_loc[IOASICCF_OFFSET] != d->iada_offset)
231 		return (0);
232 
233 	/*
234 	 * Find out the device address, and check it for validity.
235 	 */
236 	zs_addr = (void *) d->iada_addr;
237 #ifdef SPARSE
238 	zs_addr = (void *) TC_DENSE_TO_SPARSE((tc_addr_t) zs_addr);
239 #endif
240 	if (tc_badaddr(zs_addr))
241 		return (0);
242 
243 	return (1);
244 }
245 
246 /*
247  * Attach a found zs.
248  */
249 void
250 zs_ioasic_attach(parent, self, aux)
251 	struct device *parent;
252 	struct device *self;
253 	void *aux;
254 {
255 	struct zsc_softc *zs = (void *) self;
256 	struct zsc_attach_args zs_args;
257 	struct zs_chanstate *cs;
258 	struct ioasicdev_attach_args *d = aux;
259 	volatile struct zshan *zc;
260 	tc_addr_t zs_addr;
261 	int s, channel;
262 
263 	printf("\n");
264 
265 	/*
266 	 * Initialize software state for each channel.
267 	 */
268 	for (channel = 0; channel < 2; channel++) {
269 		zs_args.channel = channel;
270 		zs_args.hwflags = 0;
271 
272 		cs = &zs->zsc_cs_store[channel];
273 		zs->zsc_cs[channel] = cs;
274 
275 		/*
276 		 * If we're the console, copy the channel state, and
277 		 * adjust the console channel pointer.
278 		 */
279 		if (zs_ioasic_isconsole(d->iada_offset, channel)) {
280 			bcopy(zs_ioasic_conschanstate, cs,
281 			    sizeof(struct zs_chanstate));
282 			zs_ioasic_conschanstate = cs;
283 			zs_args.hwflags |= ZS_HWFLAG_CONSOLE;
284 		} else {
285 			zs_addr = d->iada_addr;
286 			zc = zs_ioasic_get_chan_addr(zs_addr, channel);
287 			cs->cs_reg_csr  = (void *)&zc->zc_csr;
288 
289 			bcopy(zs_ioasic_init_reg, cs->cs_creg, 16);
290 			bcopy(zs_ioasic_init_reg, cs->cs_preg, 16);
291 
292 			cs->cs_defcflag = zs_def_cflag;
293 			cs->cs_defspeed = 9600;		/* XXX */
294 			(void) zs_set_modes(cs, cs->cs_defcflag);
295 		}
296 
297 		cs->cs_channel = channel;
298 		cs->cs_ops = &zsops_null;
299 		cs->cs_brg_clk = PCLK / 16;
300 
301 		/*
302 		 * DCD and CTS interrupts are only meaningful on
303 		 * SCC 0/B.
304 		 *
305 		 * XXX This is sorta gross.
306 		 */
307 		if (d->iada_offset == 0x00100000 && channel == 1)
308 			(u_long)cs->cs_private = ZIP_FLAGS_DCDCTS;
309 		else
310 			cs->cs_private = NULL;
311 
312 		/*
313 		 * Clear the master interrupt enable.
314 		 * The INTENA is common to both channels,
315 		 * so just do it on the A channel.
316 		 */
317 		if (channel == 0) {
318 			zs_write_reg(cs, 9, 0);
319 		}
320 
321 #ifdef notyet /* XXX thorpej */
322 		/*
323 		 * Set up the flow/modem control channel pointer to
324 		 * deal with the weird wiring on the TC Alpha and
325 		 * DECstation.
326 		 */
327 		if (channel == 1)
328 			cs->cs_ctl_chan = zs->zsc_cs[0];
329 		else
330 			cs->cs_ctl_chan = NULL;
331 #endif
332 
333 		/*
334 		 * Look for a child driver for this channel.
335 		 * The child attach will setup the hardware.
336 		 */
337 		if (config_found(self, (void *)&zs_args, zs_ioasic_print)
338 		    == NULL) {
339 			/* No sub-driver.  Just reset it. */
340 			u_char reset = (channel == 0) ?
341 				ZSWR9_A_RESET : ZSWR9_B_RESET;
342 			s = splhigh();
343 			zs_write_reg(cs, 9, reset);
344 			splx(s);
345 		}
346 	}
347 
348 	/*
349 	 * Set up the ioasic interrupt handler.
350 	 */
351 	ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_TTY,
352 	    zs_ioasic_hardintr, zs);
353 	zs->zsc_sih = softintr_establish(IPL_SOFTSERIAL,
354 	    zs_ioasic_softintr, zs);
355 	if (zs->zsc_sih == NULL)
356 		panic("zs_ioasic_attach: unable to register softintr");
357 
358 	/*
359 	 * Set the master interrupt enable and interrupt vector.  The
360 	 * Sun does this only on one channel.  The old Alpha SCC driver
361 	 * did it on both.  We'll do it on both.
362 	 */
363 	s = splhigh();
364 	/* interrupt vector */
365 	zs_write_reg(zs->zsc_cs[0], 2, zs_ioasic_init_reg[2]);
366 	zs_write_reg(zs->zsc_cs[1], 2, zs_ioasic_init_reg[2]);
367 
368 	/* master interrupt control (enable) */
369 	zs_write_reg(zs->zsc_cs[0], 9, zs_ioasic_init_reg[9]);
370 	zs_write_reg(zs->zsc_cs[1], 9, zs_ioasic_init_reg[9]);
371 
372 	/* ioasic interrupt enable */
373 	*(volatile u_int *)(ioasic_base + IOASIC_IMSK) |=
374 		    IOASIC_INTR_SCC_1 | IOASIC_INTR_SCC_0;
375 	tc_mb();
376 
377 	splx(s);
378 }
379 
380 int
381 zs_ioasic_print(aux, name)
382 	void *aux;
383 	const char *name;
384 {
385 	struct zsc_attach_args *args = aux;
386 
387 	if (name != NULL)
388 		printf("%s:", name);
389 
390 	if (args->channel != -1)
391 		printf(" channel %d", args->channel);
392 
393 	return (UNCONF);
394 }
395 
396 
397 /*
398  * Hardware interrupt handler.
399  */
400 int
401 zs_ioasic_hardintr(arg)
402 	void *arg;
403 {
404 	struct zsc_softc *zsc = arg;
405 
406 	/*
407 	 * Call the upper-level MI hardware interrupt handler.
408 	 */
409 	zsc_intr_hard(zsc);
410 
411 	/*
412 	 * Check to see if we need to schedule any software-level
413 	 * processing interrupts.
414 	 */
415 	if (zsc->zsc_cs[0]->cs_softreq | zsc->zsc_cs[1]->cs_softreq)
416 		softintr_schedule(zsc->zsc_sih);
417 
418 	return (1);
419 }
420 
421 /*
422  * Software-level interrupt (character processing, lower priority).
423  */
424 void
425 zs_ioasic_softintr(arg)
426 	void *arg;
427 {
428 	struct zsc_softc *zsc = arg;
429 	int s;
430 
431 	s = spltty();
432 	(void) zsc_intr_soft(zsc);
433 	splx(s);
434 }
435 
436 /*
437  * MD functions for setting the baud rate and control modes.
438  */
439 int
440 zs_set_speed(cs, bps)
441 	struct zs_chanstate *cs;
442 	int bps;	/* bits per second */
443 {
444 	int tconst, real_bps;
445 
446 	if (bps == 0)
447 		return (0);
448 
449 #ifdef DIAGNOSTIC
450 	if (cs->cs_brg_clk == 0)
451 		panic("zs_set_speed");
452 #endif
453 
454 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
455 	if (tconst < 0)
456 		return (EINVAL);
457 
458 	/* Convert back to make sure we can do it. */
459 	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
460 
461 	/* XXX - Allow some tolerance here? */
462 	if (real_bps != bps)
463 		return (EINVAL);
464 
465 	cs->cs_preg[12] = tconst;
466 	cs->cs_preg[13] = tconst >> 8;
467 
468 	/* Caller will stuff the pending registers. */
469 	return (0);
470 }
471 
472 int
473 zs_set_modes(cs, cflag)
474 	struct zs_chanstate *cs;
475 	int cflag;	/* bits per second */
476 {
477 	u_long privflags = (u_long)cs->cs_private;
478 	int s;
479 
480 	/*
481 	 * Output hardware flow control on the chip is horrendous:
482 	 * if carrier detect drops, the receiver is disabled, and if
483 	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
484 	 * Therefore, NEVER set the HFC bit, and instead use the
485 	 * status interrupt to detect CTS changes.
486 	 */
487 	s = splzs();
488 	if ((cflag & (CLOCAL | MDMBUF)) != 0)
489 		cs->cs_rr0_dcd = 0;
490 	else
491 		cs->cs_rr0_dcd = ZSRR0_DCD;
492 	if ((cflag & CRTSCTS) != 0) {
493 		cs->cs_wr5_dtr = ZSWR5_DTR;
494 		cs->cs_wr5_rts = ZSWR5_RTS;
495 		cs->cs_rr0_cts = ZSRR0_CTS;
496 	} else if ((cflag & CDTRCTS) != 0) {
497 		cs->cs_wr5_dtr = 0;
498 		cs->cs_wr5_rts = ZSWR5_DTR;
499 		cs->cs_rr0_cts = ZSRR0_CTS;
500 	} else if ((cflag & MDMBUF) != 0) {
501 		cs->cs_wr5_dtr = 0;
502 		cs->cs_wr5_rts = ZSWR5_DTR;
503 		cs->cs_rr0_cts = ZSRR0_DCD;
504 	} else {
505 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
506 		cs->cs_wr5_rts = 0;
507 		cs->cs_rr0_cts = 0;
508 	}
509 
510 	if ((privflags & ZIP_FLAGS_DCDCTS) == 0) {
511 		cs->cs_rr0_dcd &= ~(ZSRR0_CTS|ZSRR0_DCD);
512 		cs->cs_rr0_cts &= ~(ZSRR0_CTS|ZSRR0_DCD);
513 	}
514 	splx(s);
515 
516 	/* Caller will stuff the pending registers. */
517 	return (0);
518 }
519 
520 /*
521  * Read or write the chip with suitable delays.
522  */
523 u_char
524 zs_read_reg(cs, reg)
525 	struct zs_chanstate *cs;
526 	u_char reg;
527 {
528         struct zshan *zc = (void *)cs->cs_reg_csr;
529 	unsigned val;
530 
531         zc->zc_csr = reg << 8;
532 	tc_mb();
533 	DELAY(5);
534 	val = (zc->zc_csr >> 8) & 0xff;
535 	tc_mb();
536 	DELAY(5);
537 	return (val);
538 }
539 
540 void
541 zs_write_reg(cs, reg, val)
542 	struct zs_chanstate *cs;
543 	u_char reg, val;
544 {
545         struct zshan *zc = (void *)cs->cs_reg_csr;
546 
547         zc->zc_csr = reg << 8;
548         tc_mb();
549 	DELAY(5);
550         zc->zc_csr = val << 8;
551         tc_mb();
552 	DELAY(5);
553 }
554 
555 u_char
556 zs_read_csr(cs)
557 	struct zs_chanstate *cs;
558 {
559 	struct zshan *zc = (void *)cs->cs_reg_csr;
560 	unsigned val;
561 
562 	val = (zc->zc_csr >> 8) & 0xff;
563 	tc_mb();
564 	DELAY(5);
565 
566 	return (val);
567 }
568 
569 void
570 zs_write_csr(cs, val)
571 	struct zs_chanstate *cs;
572 	u_char val;
573 {
574 
575 	struct zshan *zc = (void *)cs->cs_reg_csr;
576 
577 	zc->zc_csr = val << 8;
578 	tc_mb();
579 	DELAY(5);
580 }
581 
582 u_char
583 zs_read_data(cs)
584 	struct zs_chanstate *cs;
585 {
586 	struct zshan *zc = (void *)cs->cs_reg_csr;
587 	unsigned val;
588 
589 	val = (zc->zc_data) >> 8 & 0xff;
590 	tc_mb();
591 	DELAY(5);
592 
593 	return (val);
594 }
595 
596 void
597 zs_write_data(cs, val)
598 	struct zs_chanstate *cs;
599 	u_char val;
600 {
601 
602 	struct zshan *zc = (void *)cs->cs_reg_csr;
603 
604 	zc->zc_data = val << 8;
605 	tc_mb();
606 	DELAY(5);
607 }
608 
609 /****************************************************************
610  * Console support functions (Alpha TC specific!)
611  ****************************************************************/
612 
613 /*
614  * Handle user request to enter kernel debugger.
615  */
616 void
617 zs_abort(cs)
618 	struct zs_chanstate *cs;
619 {
620 	int rr0;
621 
622 	/* Wait for end of break. */
623 	/* XXX - Limit the wait? */
624 	do {
625 		rr0 = zs_read_csr(cs);
626 	} while (rr0 & ZSRR0_BREAK);
627 
628 #if defined(KGDB)
629 	zskgdb(cs);
630 #elif defined(DDB)
631 	Debugger();
632 #else
633 	printf("zs_abort: ignoring break on console\n");
634 #endif
635 }
636 
637 /*
638  * Polled input char.
639  */
640 int
641 zs_getc(cs)
642 	struct zs_chanstate *cs;
643 {
644 	int s, c, rr0;
645 
646 	s = splhigh();
647 	/* Wait for a character to arrive. */
648 	do {
649 		rr0 = zs_read_csr(cs);
650 	} while ((rr0 & ZSRR0_RX_READY) == 0);
651 
652 	c = zs_read_data(cs);
653 	splx(s);
654 
655 	/*
656 	 * This is used by the kd driver to read scan codes,
657 	 * so don't translate '\r' ==> '\n' here...
658 	 */
659 	return (c);
660 }
661 
662 /*
663  * Polled output char.
664  */
665 void
666 zs_putc(cs, c)
667 	struct zs_chanstate *cs;
668 	int c;
669 {
670 	register int s, rr0;
671 
672 	s = splhigh();
673 	/* Wait for transmitter to become ready. */
674 	do {
675 		rr0 = zs_read_csr(cs);
676 	} while ((rr0 & ZSRR0_TX_READY) == 0);
677 
678 	zs_write_data(cs, c);
679 
680 	/* Wait for the character to be transmitted. */
681 	do {
682 		rr0 = zs_read_csr(cs);
683 	} while ((rr0 & ZSRR0_TX_READY) == 0);
684 	splx(s);
685 }
686 
687 /*****************************************************************/
688 
689 /*
690  * zs_ioasic_cninit --
691  *	Initialize the serial channel for console use--either the
692  * primary keyboard or as the serial console.
693  */
694 void
695 zs_ioasic_cninit(ioasic_addr, zs_offset, channel)
696 	tc_addr_t ioasic_addr;
697 	tc_offset_t zs_offset;
698 	int channel;
699 {
700 	struct zs_chanstate *cs;
701 	tc_addr_t zs_addr;
702 	struct zshan *zc;
703 
704 	/*
705 	 * Initialize the console finder helpers.
706 	 */
707 	zs_ioasic_console_offset = zs_offset;
708 	zs_ioasic_console_channel = channel;
709 	zs_ioasic_console = 1;
710 
711 	/*
712 	 * Pointer to channel state.  Later, the console channel
713 	 * state is copied into the softc, and the console channel
714 	 * pointer adjusted to point to the new copy.
715 	 */
716 	zs_ioasic_conschanstate = cs = &zs_ioasic_conschanstate_store;
717 
718 	/*
719 	 * Compute the physical address of the chip, "map" it via
720 	 * K0SEG, and then get the address of the actual channel.
721 	 */
722 	zs_addr = ALPHA_PHYS_TO_K0SEG(ioasic_addr + zs_offset);
723 	zc = zs_ioasic_get_chan_addr(zs_addr, channel);
724 
725 	/* Setup temporary chanstate. */
726 	cs->cs_reg_csr  = (volatile u_char *)&zc->zc_csr;
727 	cs->cs_reg_data = (volatile u_char *)&zc->zc_data;
728 
729 	/* Initialize the pending registers. */
730 	bcopy(zs_ioasic_init_reg, cs->cs_preg, 16);
731 	cs->cs_preg[5] |= (ZSWR5_DTR | ZSWR5_RTS);
732 
733 	/*
734 	 * DCD and CTS interrupts are only meaningful on
735 	 * SCC 0/B.
736 	 *
737 	 * XXX This is sorta gross.
738 	 */
739 	if (zs_offset == 0x00100000 && channel == 1)
740 		(u_long)cs->cs_private = ZIP_FLAGS_DCDCTS;
741 	else
742 		cs->cs_private = NULL;
743 
744 	/* Clear the master interrupt enable. */
745 	zs_write_reg(cs, 9, 0);
746 
747 	/* Reset the whole SCC chip. */
748 	zs_write_reg(cs, 9, ZSWR9_HARD_RESET);
749 
750 	/* Copy "pending" to "current" and H/W. */
751 	zs_loadchannelregs(cs);
752 }
753 
754 /*
755  * zs_ioasic_cnattach --
756  *	Initialize and attach a serial console.
757  */
758 int
759 zs_ioasic_cnattach(ioasic_addr, zs_offset, channel, rate, cflag)
760 	tc_addr_t ioasic_addr;
761 	tc_offset_t zs_offset;
762 	int channel, rate, cflag;
763 {
764 	zs_ioasic_cninit(ioasic_addr, zs_offset, channel);
765 
766 	zs_ioasic_conschanstate->cs_defspeed = rate;
767 	zs_ioasic_conschanstate->cs_defcflag = cflag;
768 
769 	/* Point the console at the SCC. */
770 	cn_tab = &zs_ioasic_cons;
771 
772 	return (0);
773 }
774 
775 /*
776  * zs_ioasic_lk201_cnattach --
777  *	Initialize and attach the primary keyboard.
778  */
779 int
780 zs_ioasic_lk201_cnattach(ioasic_addr, zs_offset, channel)
781 	tc_addr_t ioasic_addr;
782 	tc_offset_t zs_offset;
783 	int channel;
784 {
785 #if (NZSKBD > 0)
786 	zs_ioasic_cninit(ioasic_addr, zs_offset, channel);
787 	zs_ioasic_conschanstate->cs_defspeed = 4800;
788 	zs_ioasic_conschanstate->cs_defcflag =
789 	     (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8;
790 	zs_ioasic_conschanstate->cs_brg_clk = PCLK / 16;
791 	return (zskbd_cnattach(zs_ioasic_conschanstate));
792 #else
793 	return (ENXIO);
794 #endif
795 }
796 
797 int
798 zs_ioasic_isconsole(offset, channel)
799 	tc_offset_t offset;
800 	int channel;
801 {
802 
803 	if (zs_ioasic_console &&
804 	    offset == zs_ioasic_console_offset &&
805 	    channel == zs_ioasic_console_channel)
806 		return (1);
807 
808 	return (0);
809 }
810 
811 /*
812  * Polled console input putchar.
813  */
814 int
815 zs_ioasic_cngetc(dev)
816 	dev_t dev;
817 {
818 
819 	return (zs_getc(zs_ioasic_conschanstate));
820 }
821 
822 /*
823  * Polled console output putchar.
824  */
825 void
826 zs_ioasic_cnputc(dev, c)
827 	dev_t dev;
828 	int c;
829 {
830 
831 	zs_putc(zs_ioasic_conschanstate, c);
832 }
833 
834 /*
835  * Set polling/no polling on console.
836  */
837 void
838 zs_ioasic_cnpollc(dev, onoff)
839 	dev_t dev;
840 	int onoff;
841 {
842 
843 	/* XXX ??? */
844 }
845