xref: /netbsd-src/sys/arch/mac68k/dev/zs.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: zs.c,v 1.10 1996/10/13 03:21:31 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Gordon W. Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon Ross
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Zilog Z8530 Dual UART driver (machine-dependent part)
35  *
36  * Runs two serial lines per chip using slave drivers.
37  * Plain tty/async lines use the zs_async slave.
38  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/device.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/ioctl.h>
48 #include <sys/tty.h>
49 #include <sys/time.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
52 
53 #include <dev/cons.h>
54 #include "z8530reg.h"
55 #include <machine/z8530var.h>
56 
57 #include <machine/autoconf.h>
58 #include <machine/cpu.h>
59 #include <machine/viareg.h>
60 
61 /*
62  * XXX: Hard code this to make console init easier...
63  */
64 #define	NZSC	1		/* XXX */
65 
66 /*
67  * Define interrupt levels.
68  */
69 #define ZSHARD_PRI	6	/* Wired on the CPU board... */
70 #define ZSSOFT_PRI	3	/* Want tty pri (4) but this is OK. */
71 
72 /* The layout of this is hardware-dependent (padding, order). */
73 struct zschan {
74 	volatile u_char	zc_csr;		/* ctrl,status, and indirect access */
75 	u_char		zc_xxx0;
76 	u_char		zc_xxx1;
77 	u_char		zc_xxx2;
78 	volatile u_char	zc_data;	/* data */
79 	u_char		zc_xxx3;
80 	u_char		zc_xxx4;
81 	u_char		zc_xxx5;
82 };
83 /*
84  * The zsdevice structure is not used on the mac68k port as the
85  * chip is wired up weird. Channel B & A are interspursed with
86  * the data & control bytes
87 struct zsdevice {
88 	/! Yes, they are backwards. !/
89 	struct	zschan zs_chan_b;
90 	struct	zschan zs_chan_a;
91 };
92 */
93 
94 /* Saved PROM mappings */
95 static char *zsaddr[NZSC];	/* See zs_init() */
96 /* Flags from cninit() */
97 static int zs_hwflags[NZSC][2];
98 /* Default speed for each channel */
99 static int zs_defspeed[NZSC][2] = {
100 	{ 9600, 	/* tty00 */
101 	  9600 },	/* tty01 */
102 };
103 /* console stuff */
104 void *zs_conschan = 0;
105 int   zs_consunit;
106 /* device that the console is attached to--if serial. */
107 dev_t	mac68k_zsdev;
108 /* Mac stuff, some vestages of old mac serial driver here */
109 volatile unsigned char *sccA = 0;
110 
111 static struct zschan	*zs_get_chan_addr __P((int zsc_unit, int channel));
112 void			zs_init __P((void));
113 
114 static struct zschan *
115 zs_get_chan_addr(zsc_unit, channel)
116 	int zsc_unit, channel;
117 {
118 	char *addr;
119 	struct zschan *zc;
120 
121 	if (zsc_unit >= NZSC)
122 		return NULL;
123 	addr = zsaddr[zsc_unit];
124 	if (addr == NULL)
125 		return NULL;
126 	if (channel == 0) {
127 		zc = (struct zschan *)(addr +2);
128 		/* handle the fact the ports are intertwined. */
129 	} else {
130 		zc = (struct zschan *)(addr);
131 	}
132 	return (zc);
133 }
134 
135 
136 /* Find PROM mappings (for console support). */
137 static int zsinited = 0; /* 0 = not, 1 = inited, not attached, 2= attached */
138 
139 void
140 zs_init()
141 {
142 	if ((zsinited == 2)&&(zsaddr[0] != (char *) sccA))
143 		panic("Moved zs0 address after attached!");
144 	zsaddr[0] = (char *) sccA;
145 	zsinited = 1;
146 	if (zs_conschan != 0){ /* we might have moved io under the console */
147 		zs_conschan = zs_get_chan_addr(0, zs_consunit);
148 		/* so recalc the console port */
149 	}
150 }
151 
152 
153 /*
154  * Even though zsparam will set up the clock multiples, etc., we
155  * still set them here as: 1) mice & keyboards don't use zsparam,
156  * and 2) the console stuff uses these defaults before device
157  * attach.
158  */
159 
160 static u_char zs_init_reg[16] = {
161 	0,	/* 0: CMD (reset, etc.) */
162 	ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE,
163 	0x18 + ZSHARD_PRI,	/* IVECT */
164 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
165 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
166 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
167 	0,	/* 6: TXSYNC/SYNCLO */
168 	0,	/* 7: RXSYNC/SYNCHI */
169 	0,	/* 8: alias for data port */
170 	ZSWR9_MASTER_IE,
171 	0,	/*10: Misc. TX/RX control bits */
172 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
173 	14,	/*12: BAUDLO (default=9600) */
174 	0,	/*13: BAUDHI (default=9600) */
175 	ZSWR14_BAUD_ENA,
176 	ZSWR15_BREAK_IE | ZSWR15_DCD_IE | ZSWR15_CTS_IE,
177 };
178 
179 
180 /****************************************************************
181  * Autoconfig
182  ****************************************************************/
183 
184 /* Definition of the driver for autoconfig. */
185 static int	zsc_match __P((struct device *, void *, void *));
186 static void	zsc_attach __P((struct device *, struct device *, void *));
187 static int	zsc_print __P((void *aux, const char *name));
188 
189 struct cfattach zsc_ca = {
190 	sizeof(struct zsc_softc), zsc_match, zsc_attach
191 };
192 
193 struct cfdriver zsc_cd = {
194 	NULL, "zsc", DV_DULL
195 };
196 
197 int	zshard __P((void *));
198 int	zssoft __P((void *));
199 
200 
201 /*
202  * Is the zs chip present?
203  */
204 static int
205 zsc_match(parent, vcf, aux)
206 	struct device *parent;
207 	void *vcf;
208 	void *aux;
209 {
210 	return 1;
211 }
212 
213 static int
214 zsc_print(aux, name)
215 	void *aux;
216 	const char *name;
217 {
218 	struct zsc_attach_args *args = aux;
219 
220 	if (name != NULL)
221 		printf("%s: ", name);
222 
223 	if (args->channel != -1)
224 		printf(" channel %d", args->channel);
225 
226 	return UNCONF;
227 }
228 
229 /*
230  * Attach a found zs.
231  *
232  * Match slave number to zs unit number, so that misconfiguration will
233  * not set up the keyboard as ttya, etc.
234  */
235 static void
236 zsc_attach(parent, self, aux)
237 	struct device *parent;
238 	struct device *self;
239 	void *aux;
240 {
241 	struct zsc_softc *zsc = (void *) self;
242 	struct zsc_attach_args zsc_args;
243 	volatile struct zschan *zc;
244 	struct zs_chanstate *cs;
245 	int zsc_unit, channel;
246 	int reset, s, chip;
247 
248 	if (!zsinited) zs_init();
249 	zsinited = 2;
250 
251 	zsc_unit = zsc->zsc_dev.dv_unit;
252 
253 	/* Make sure everything's inited ok. */
254 	if (zsaddr[zsc_unit] == NULL)
255 		panic("zs_attach: zs%d not mapped\n", zsc_unit);
256 
257 	/*
258 	 * Initialize software state for each channel.
259 	 */
260 	for (channel = 0; channel < 2; channel++) {
261 		cs = &zsc->zsc_cs[channel];
262 
263 		zc = zs_get_chan_addr(zsc_unit, channel);
264 		cs->cs_reg_csr  = &zc->zc_csr;
265 		cs->cs_reg_data = &zc->zc_data;
266 
267 		cs->cs_channel = channel;
268 		cs->cs_private = NULL;
269 		cs->cs_ops = &zsops_null;
270 
271 		/* Define BAUD rate clock for the MI code. */
272 		cs->cs_pclk_div16 = mac68k_machine.sccClkConst*2;
273 		cs->cs_csource = 0;
274 		cs->cs_psource = 0;
275 
276 		cs->cs_defspeed = zs_defspeed[zsc_unit][channel];
277 
278 		bcopy(zs_init_reg, cs->cs_creg, 16);
279 		bcopy(zs_init_reg, cs->cs_preg, 16);
280 
281 		/*
282 		 * Clear the master interrupt enable.
283 		 * The INTENA is common to both channels,
284 		 * so just do it on the A channel.
285 		 */
286 		if (channel == 0) {
287 			zs_write_reg(cs, 9, 0);
288 
289 			chip = 0; /* We'll turn chip checking on post 1.2 */
290 			printf(" chip type %d \n",chip);
291 		}
292 		cs->cs_chip = chip;
293 
294 		/*
295 		 * Look for a child driver for this channel.
296 		 * The child attach will setup the hardware.
297 		 */
298 		zsc_args.channel = channel;
299 		zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
300 		if (!config_found(self, (void *) &zsc_args, zsc_print)) {
301 			/* No sub-driver.  Just reset it. */
302 			reset = (channel == 0) ?
303 				ZSWR9_A_RESET : ZSWR9_B_RESET;
304 			s = splzs();
305 			zs_write_reg(cs,  9, reset);
306 			splx(s);
307 		}
308 	}
309 
310 	/*
311 	 * Set the master interrupt enable and interrupt vector.
312 	 * (common to both channels, do it on A)
313 	 */
314 	cs = &zsc->zsc_cs[0];
315 	s = splzs();
316 	/* interrupt vector */
317 	zs_write_reg(cs, 2, zs_init_reg[2]);
318 	/* master interrupt control (enable) */
319 	zs_write_reg(cs, 9, zs_init_reg[9]);
320 	splx(s);
321 }
322 
323 void
324 zstty_mdattach(zsc, zst, cs, tp)
325 	struct zsc_softc *zsc;
326 	struct zstty_softc *zst;
327 	struct zs_chanstate *cs;
328 	struct tty *tp;
329 {
330 	int theflags;
331 
332 	zst->zst_resetdef = 0;
333 	cs->cs_clock_count = 3; /* internal + externals */
334 	cs->cs_cclk_flag = 0;  /* Not doing anything fancy by default */
335 	cs->cs_pclk_flag = 0;
336 	cs->cs_clocks[0].clk = mac68k_machine.sccClkConst*32;
337 	cs->cs_clocks[0].flags = ZSC_RTXBRG; /* allowing divide by 16 will
338 					melt the driver! */
339 
340 	cs->cs_clocks[1].flags = ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
341 	cs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
342 	if (zst->zst_dev.dv_unit == 0) {
343 		theflags = mac68k_machine.modem_flags;
344 		cs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;
345 		cs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;
346 	} else if (zst->zst_dev.dv_unit == 1) {
347 		theflags = mac68k_machine.print_flags;
348 		cs->cs_clocks[1].flags = ZSC_VARIABLE;
349 		/*
350 		 * Yes, we aren't defining ANY clock source enables for the
351 		 * printer's DCD clock in. The hardware won't let us
352 		 * use it. But a clock will freak out the chip, so we
353 		 * let you set it, telling us to bar interrupts on the line.
354 		 */
355 		cs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;
356 		cs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;
357 	}
358 
359 	if (cs->cs_clocks[1].clk)
360 		zst->zst_hwflags |= ZS_HWFLAG_IGDCD;
361 	if (cs->cs_clocks[2].clk)
362 		zst->zst_hwflags |= ZS_HWFLAG_IGCTS;
363 
364 	if (theflags & ZSMAC_RAW) {
365 		zst->zst_cflag = ZSTTY_RAW_CFLAG;
366 		zst->zst_iflag = ZSTTY_RAW_IFLAG;
367 		zst->zst_lflag = ZSTTY_RAW_LFLAG;
368 		zst->zst_oflag = ZSTTY_RAW_OFLAG;
369 		printf(" (raw defaults)");
370 	}
371 	if (theflags & ZSMAC_LOCALTALK) {
372 		printf(" shielding from LocalTalk");
373 		zst->zst_ospeed = tp->t_ospeed = 1;
374 		zst->zst_ispeed = tp->t_ispeed = 1;
375 		cs->cs_defspeed = 1;
376 		cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
377 		cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
378 		zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
379 		zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
380 		/*
381 		 * If we might have LocalTalk, then make sure we have the
382 		 * Baud rate low-enough to not do any damage.
383 		 */
384 	}
385 
386 	/* For the mac, we have rtscts = check CTS for output control, no
387 	 * input control. mdmbuf means check DCD for output, and use DTR
388 	 * for input control. mdmbuf & rtscts means use CTS for output
389 	 * control, and DTR for input control. */
390 
391 	zst->zst_hwimasks[1] = 0;
392 	zst->zst_hwimasks[2] = ZSWR5_DTR;
393 	zst->zst_hwimasks[3] = ZSWR5_DTR;
394 }
395 
396 int
397 zsmdioctl(tp, com, data, flag, p)
398 	struct tty *tp;
399 	u_long com;
400 	caddr_t data;
401 	int flag;
402 	struct proc *p;
403 {
404 	return (-1);
405 }
406 
407 void
408 zsmd_setclock(cs)
409 	struct zs_chanstate *cs;
410 {
411 	if (cs->cs_channel != 0)
412 		return;
413 	/*
414 	 * If the new clock has the external bit set, then select the
415 	 * external source.
416 	 */
417 	via_set_modem((cs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);
418 }
419 
420 int
421 zshard(arg)
422 	void *arg;
423 {
424 	struct zsc_softc *zsc;
425 	int unit, rval;
426 #ifdef ZSMACDEBUG
427 	itecnputc(mac68k_zsdev, 'Z');
428 #endif
429 
430 	rval = 0;
431 	unit = zsc_cd.cd_ndevs;
432 	while (--unit >= 0) {
433 		zsc = zsc_cd.cd_devs[unit];
434 		if (zsc != NULL) {
435 			rval |= zsc_intr_hard(zsc);
436 		}
437 	}
438 #ifdef ZSMACDEBUG
439 	itecnputc(mac68k_zsdev, '\n');
440 #endif
441 	return (rval);
442 }
443 
444 int zssoftpending;
445 
446 void
447 zsc_req_softint(zsc)
448 	struct zsc_softc *zsc;
449 {
450 	if (zssoftpending == 0) {
451 		/* We are at splzs here, so no need to lock. */
452 		zssoftpending = ZSSOFT_PRI;
453 	/*	isr_soft_request(ZSSOFT_PRI); */
454 		setsoftserial();
455 	}
456 }
457 
458 int
459 zssoft(arg)
460 	void *arg;
461 {
462 	struct zsc_softc *zsc;
463 	int unit;
464 
465 	/* This is not the only ISR on this IPL. */
466 	if (zssoftpending == 0)
467 		return (0);
468 
469 	/*
470 	 * The soft intr. bit will be set by zshard only if
471 	 * the variable zssoftpending is zero.  The order of
472 	 * these next two statements prevents our clearing
473 	 * the soft intr bit just after zshard has set it.
474 	 */
475 /*	isr_soft_clear(ZSSOFT_PRI); */
476 	zssoftpending = 0;
477 
478 	/* Do ttya/ttyb first, because they go faster. */
479 	unit = zsc_cd.cd_ndevs;
480 	while (--unit >= 0) {
481 		zsc = zsc_cd.cd_devs[unit];
482 		if (zsc != NULL) {
483 			(void) zsc_intr_soft(zsc);
484 		}
485 	}
486 	return (1);
487 }
488 
489 
490 /*
491  * Read or write the chip with suitable delays.
492  */
493 #define	ZS_DELAY()
494 /*
495  * MacII hardware has the delay built in. No need for extra delay. :-)
496  */
497 
498 u_char
499 zs_read_reg(cs, reg)
500 	struct zs_chanstate *cs;
501 	u_char reg;
502 {
503 	u_char val;
504 
505 	*cs->cs_reg_csr = reg;
506 	ZS_DELAY();
507 	val = *cs->cs_reg_csr;
508 	ZS_DELAY();
509 	return val;
510 }
511 
512 void
513 zs_write_reg(cs, reg, val)
514 	struct zs_chanstate *cs;
515 	u_char reg, val;
516 {
517 	*cs->cs_reg_csr = reg;
518 	ZS_DELAY();
519 	*cs->cs_reg_csr = val;
520 	ZS_DELAY();
521 }
522 
523 u_char zs_read_csr(cs)
524 	struct zs_chanstate *cs;
525 {
526 	register u_char v;
527 
528 	v = (*cs->cs_reg_csr) ^ ZSRR0_CTS;
529 	/* make up for the fact CTS is wired backwards */
530 	ZS_DELAY();
531 	return v;
532 }
533 
534 u_char zs_read_data(cs)
535 	struct zs_chanstate *cs;
536 {
537 	register u_char v;
538 
539 	v = *cs->cs_reg_data;
540 	ZS_DELAY();
541 	return v;
542 }
543 
544 void  zs_write_csr(cs, val)
545 	struct zs_chanstate *cs;
546 	u_char val;
547 {
548 	*cs->cs_reg_csr = val;
549 	ZS_DELAY();
550 }
551 
552 void  zs_write_data(cs, val)
553 	struct zs_chanstate *cs;
554 	u_char val;
555 {
556 	*cs->cs_reg_data = val;
557 	ZS_DELAY();
558 }
559 
560 /****************************************************************
561  * Console support functions (Originally Sun3 specific!)
562  * Now works w/ just mac68k port!
563  ****************************************************************/
564 
565 #define zscnpollc	nullcnpollc
566 cons_decl(zs);
567 
568 static void	zs_putc __P((register volatile struct zschan *, int));
569 static int	zs_getc __P((register volatile struct zschan *));
570 static void	zscnsetup __P((void));
571 extern int	zsopen __P(( dev_t dev, int flags, int mode, struct proc *p));
572 
573 /*
574  * Console functions.
575  */
576 
577 /*
578  * This code modled after the zs_setparam routine in zskgdb
579  * It sets the console unit to a known state so we can output
580  * correctly.
581  */
582 static void
583 zscnsetup()
584 {
585 	struct zs_chanstate cs;
586 	struct zschan *zc;
587 	int    tconst, s;
588 
589 	/* Setup temporary chanstate. */
590 	bzero((caddr_t)&cs, sizeof(cs));
591 	zc = zs_conschan;
592 	cs.cs_reg_csr  = &zc->zc_csr;
593 	cs.cs_reg_data = &zc->zc_data;
594 	cs.cs_channel = zs_consunit;
595 
596 	bcopy(zs_init_reg, cs.cs_preg, 16);
597 	tconst = BPS_TO_TCONST(mac68k_machine.sccClkConst*2, zs_defspeed[0][zs_consunit]);
598         cs.cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
599 	cs.cs_preg[1] = 0; /* don't enable interrupts */
600         cs.cs_preg[12] = tconst;
601         cs.cs_preg[13] = tconst >> 8;
602 
603         s = splhigh();
604         zs_loadchannelregs(&cs);
605         splx(s);
606 }
607 
608 /*
609  * zscnprobe is the routine which gets called as the kernel is trying to
610  * figure out where the console should be. Each io driver which might
611  * be the console (as defined in mac68k/conf.c) gets probed. The probe
612  * fills in the consdev structure. Important parts are the device #,
613  * and the console priority. Values are CN_DEAD (don't touch me),
614  * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
615  * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
616  *
617  * As the mac's a bit different, we do extra work here. We mainly check
618  * to see if we have serial echo going on, and if the tty's are supposed
619  * to default to raw or not.
620  */
621 void
622 zscnprobe(struct consdev * cp)
623 {
624         extern u_long   IOBase;
625         int     maj, unit;
626 
627         for (maj = 0; maj < nchrdev; maj++) {
628                 if (cdevsw[maj].d_open == zsopen) {
629                         break;
630                 }
631         }
632         if (maj == nchrdev) {
633                 /* no console entry for us */
634                 if (mac68k_machine.serial_boot_echo) {
635                         mac68k_set_io_offsets(IOBase);
636                 	zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
637 			zs_consunit = 1;
638 			zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
639 			zs_init();
640                         zscnsetup();
641                 }
642                 return;
643         }
644 
645         cp->cn_pri = CN_NORMAL;                 /* Lower than CN_INTERNAL */
646         if (mac68k_machine.serial_console != 0) {
647                 cp->cn_pri = CN_REMOTE;         /* Higher than CN_INTERNAL */
648                 mac68k_machine.serial_boot_echo =0;
649         }
650 
651         unit = (mac68k_machine.serial_console == 1) ? 0 : 1;
652 	zs_consunit = unit;
653 
654         mac68k_zsdev = cp->cn_dev = makedev(maj, unit);
655 
656         if (mac68k_machine.serial_boot_echo) {
657                 /*
658                  * at this point, we know that we don't have a serial
659                  * console, but are doing echo
660                  */
661                 mac68k_set_io_offsets(IOBase);
662                 zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
663 		zs_consunit = 1;
664 		zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
665 		zs_init();
666                 zscnsetup();
667         }
668         return;
669 }
670 
671 void
672 zscninit(struct consdev * cp)
673 {
674         extern u_long   IOBase;
675 	int chan = minor(cp->cn_dev & 1);
676 
677         mac68k_set_io_offsets(IOBase);
678 	zs_conschan = (struct zschan *) -1;
679 	zs_consunit = chan;
680 	zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
681 #ifdef ZS_CONSOLE_ABORT
682 	zs_hwflags[0][zs_consunit] |= ZS_HWFLAG_CONABRT;
683 #endif
684 	zs_init();
685         /*
686 	 * zsinit will set up the addresses of the scc. It will also, if
687 	 * zs_conschan != 0, calculate the new address of the conschan for
688 	 * unit zs_consunit. So zs_init implicitly sets zs_conschan to the right
689 	 * number. :-)
690          */
691         zscnsetup();
692         printf("\nNetBSD/mac68k console\n");
693 }
694 
695 
696 /*
697  * Polled input char.
698  */
699 static int
700 zs_getc(zc)
701 	register volatile struct zschan *zc;
702 {
703 	register int s, c, rr0;
704 
705 	s = splhigh();
706 	/* Wait for a character to arrive. */
707 	do {
708 		rr0 = zc->zc_csr;
709 		ZS_DELAY();
710 	} while ((rr0 & ZSRR0_RX_READY) == 0);
711 
712 	c = zc->zc_data;
713 	ZS_DELAY();
714 	splx(s);
715 
716 	/*
717 	 * This is used by the kd driver to read scan codes,
718 	 * so don't translate '\r' ==> '\n' here...
719 	 */
720 	return (c);
721 }
722 
723 /*
724  * Polled output char.
725  */
726 static void
727 zs_putc(zc, c)
728 	register volatile struct zschan *zc;
729 	int c;
730 {
731 	register int s, rr0;
732 	register long wait = 0;
733 
734 	s = splhigh();
735 	/* Wait for transmitter to become ready. */
736 	do {
737 		rr0 = zc->zc_csr;
738 		ZS_DELAY();
739 	} while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
740 
741 	if ((rr0 & ZSRR0_TX_READY) != 0) {
742 		zc->zc_data = c;
743 		ZS_DELAY();
744 	}
745 	splx(s);
746 }
747 
748 
749 /*
750  * Polled console input putchar.
751  */
752 int
753 zscngetc(dev)
754 	dev_t dev;
755 {
756 	register volatile struct zschan *zc = zs_conschan;
757 	register int c;
758 
759 	c = zs_getc(zc);
760 	return (c);
761 }
762 
763 /*
764  * Polled console output putchar.
765  */
766 void
767 zscnputc(dev, c)
768 	dev_t dev;
769 	int c;
770 {
771 	register volatile struct zschan *zc = zs_conschan;
772 
773 	zs_putc(zc, c);
774 }
775 
776 
777 
778 /*
779  * Handle user request to enter kernel debugger.
780  */
781 void
782 zs_abort(zst)
783 	register struct zstty_softc *zst;
784 {
785 	register volatile struct zschan *zc = zs_conschan;
786 	int rr0;
787 	register long wait = 0;
788 
789 	if ((zst->zst_hwflags & ZS_HWFLAG_CONABRT) == 0)
790 		return;
791 
792 	/* Wait for end of break to avoid PROM abort. */
793 	/* XXX - Limit the wait? */
794 	do {
795 		rr0 = zc->zc_csr;
796 		ZS_DELAY();
797 	} while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
798 
799 	if (wait > ZSABORT_DELAY) {
800 		if (zst != NULL) zst->zst_hwflags &= ~ZS_HWFLAG_CONABRT;
801 	/* If we time out, turn off the abort ability! */
802 	}
803 
804 	/* XXX - Always available, but may be the PROM monitor. */
805 	Debugger();
806 }
807