Annotation of sys/arch/mac68k/dev/zs.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zs.c,v 1.23 2007/01/14 18:50:23 martin Exp $ */
2: /* $NetBSD: zs.c,v 1.19 1998/01/12 19:22:18 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1996-1998 Bill Studenmund
6: * Copyright (c) 1995 Gordon W. Ross
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. The name of the author may not be used to endorse or promote products
18: * derived from this software without specific prior written permission.
19: * 4. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by Gordon Ross
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: /*
36: * Zilog Z8530 Dual UART driver (machine-dependent part)
37: *
38: * Runs two serial lines per chip using slave drivers.
39: * Plain tty/async lines use the zs_async slave.
40: * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
41: * Other ports use their own mice & keyboard slaves.
42: *
43: * Credits & history:
44: *
45: * With NetBSD 1.1, port-mac68k started using a port of the port-sparc
46: * (port-sun3?) zs.c driver (which was in turn based on code in the
47: * Berkeley 4.4 Lite release). Bill Studenmund did the port, with
48: * help from Allen Briggs and Gordon Ross <gwr@netbsd.org>. Noud de
49: * Brouwer field-tested the driver at a local ISP.
50: *
51: * Bill Studenmund and Gordon Ross then ported the machine-independant
52: * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an
53: * intermediate version (mac68k using a local, patched version of
54: * the m.i. drivers), with NetBSD 1.3 containing a full version.
55: */
56:
57: #include <sys/param.h>
58: #include <sys/systm.h>
59: #include <sys/proc.h>
60: #include <sys/device.h>
61: #include <sys/conf.h>
62: #include <sys/file.h>
63: #include <sys/ioctl.h>
64: #include <sys/tty.h>
65: #include <sys/time.h>
66: #include <sys/kernel.h>
67: #include <sys/syslog.h>
68:
69: #include <dev/cons.h>
70:
71: #include <mac68k/dev/z8530reg.h>
72: #include <machine/z8530var.h>
73:
74: #include <machine/autoconf.h>
75: #include <machine/cpu.h>
76: #include <machine/psc.h>
77: #include <machine/viareg.h>
78:
79: #ifdef DDB
80: #include <ddb/db_var.h>
81: #endif
82:
83: /* Are these in a header file anywhere? */
84: /* Booter flags interface */
85: #define ZSMAC_RAW 0x01
86: #define ZSMAC_LOCALTALK 0x02
87: #define ZS_STD_BRG (57600*4)
88:
89: #include "zsc.h" /* get the # of zs chips defined */
90:
91: /*
92: * Some warts needed by z8530tty.c -
93: */
94: int zs_def_cflag = (CREAD | CS8 | HUPCL);
95: int zs_major = 12;
96:
97: /*
98: * abort detection on console will now timeout after iterating on a loop
99: * the following # of times. Cheep hack. Also, abort detection is turned
100: * off after a timeout (i.e. maybe there's not a terminal hooked up).
101: */
102: #define ZSABORT_DELAY 3000000
103:
104: /*
105: * Define interrupt levels.
106: */
107: #define ZSHARD_PRI 4 /* Wired on the CPU board... */
108: /*
109: * Serial port cards with zs chips on them are actually at the
110: * NuBus interrupt level, which is lower than 4. But blocking
111: * level 4 interrupts will block those interrupts too, so level
112: * 4 is fine.
113: */
114:
115: /* The layout of this is hardware-dependent (padding, order). */
116: struct zschan {
117: volatile u_char zc_csr; /* ctrl,status, and indirect access */
118: u_char zc_xxx0;
119: u_char zc_xxx1; /* part of the other channel lives here!*/
120: u_char zc_xxx2; /* Yea Apple! */
121: volatile u_char zc_data; /* data */
122: u_char zc_xxx3;
123: u_char zc_xxx4;
124: u_char zc_xxx5;
125: };
126:
127: /* Saved PROM mappings */
128: static char *zsaddr[NZSC]; /* See zs_init() */
129: /* Flags from cninit() */
130: static int zs_hwflags[NZSC][2];
131: /* Default speed for each channel */
132: static int zs_defspeed[NZSC][2] = {
133: { 9600, /* tty00 */
134: 9600 }, /* tty01 */
135: };
136: void *zs_conschan = 0;
137: int zs_consunit;
138: /* device to which the console is attached--if serial. */
139: dev_t mac68k_zsdev;
140: /* Mac stuff */
141: volatile unsigned char *sccA = 0;
142: int nzsc_attached = 0; /* needed as long as we have spurious
143: * interrupt problems.
144: */
145:
146: static struct zschan *zs_get_chan_addr(int zsc_unit, int channel);
147: void zs_init(void);
148: int zs_cn_check_speed(int bps);
149:
150: static struct zschan *
151: zs_get_chan_addr(zsc_unit, channel)
152: int zsc_unit, channel;
153: {
154: char *addr;
155: struct zschan *zc;
156:
157: if (zsc_unit >= NZSC)
158: return NULL;
159: addr = zsaddr[zsc_unit];
160: if (addr == NULL)
161: return NULL;
162: if (channel == 0) {
163: zc = (struct zschan *)(addr +2);
164: /* handle the fact the ports are intertwined. */
165: } else {
166: zc = (struct zschan *)(addr);
167: }
168: return (zc);
169: }
170:
171:
172: /* Find PROM mappings (for console support). */
173: int zsinited = 0; /* 0 = not, 1 = inited, not attached, 2= attached */
174:
175: void
176: zs_init()
177: {
178: if ((zsinited == 2)&&(zsaddr[0] != (char *) sccA))
179: panic("Moved zs0 address after attached!");
180: zsaddr[0] = (char *) sccA;
181: zsinited = 1;
182: if (zs_conschan != 0){ /* we might have moved io under the console */
183: zs_conschan = zs_get_chan_addr(0, zs_consunit);
184: /* so recalc the console port */
185: }
186: }
187:
188:
189: /*
190: * Even though zsparam will set up the clock multiples, etc., we
191: * still set them here as: 1) mice & keyboards don't use zsparam,
192: * and 2) the console stuff uses these defaults before device
193: * attach.
194: */
195:
196: static u_char zs_init_reg[16] = {
197: 0, /* 0: CMD (reset, etc.) */
198: ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE,
199: 0x18 + ZSHARD_PRI, /* IVECT */
200: ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
201: ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
202: ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
203: 0, /* 6: TXSYNC/SYNCLO */
204: 0, /* 7: RXSYNC/SYNCHI */
205: 0, /* 8: alias for data port */
206: ZSWR9_MASTER_IE,
207: 0, /*10: Misc. TX/RX control bits */
208: ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
209: 14, /*12: BAUDLO (default=9600) */
210: 0, /*13: BAUDHI (default=9600) */
211: ZSWR14_BAUD_ENA,
212: ZSWR15_BREAK_IE | ZSWR15_DCD_IE | ZSWR15_CTS_IE,
213: };
214:
215:
216: /****************************************************************
217: * Autoconfig
218: ****************************************************************/
219:
220: /* Definition of the driver for autoconfig. */
221: static int zsc_match(struct device *, void *, void *);
222: static void zsc_attach(struct device *, struct device *, void *);
223: static int zsc_print(void *, const char *name);
224:
225: struct cfattach zsc_ca = {
226: sizeof(struct zsc_softc), zsc_match, zsc_attach
227: };
228:
229: struct cfdriver zsc_cd = {
230: NULL, "zsc", DV_DULL
231: };
232:
233: int zshard(void *);
234: int zssoft(void *);
235:
236:
237: /*
238: * Is the zs chip present?
239: */
240: static int
241: zsc_match(parent, vcf, aux)
242: struct device *parent;
243: void *vcf;
244: void *aux;
245: {
246: return 1;
247: }
248:
249: /*
250: * Attach a found zs.
251: *
252: * Match slave number to zs unit number, so that misconfiguration will
253: * not set up the keyboard as ttya, etc.
254: */
255: static void
256: zsc_attach(parent, self, aux)
257: struct device *parent;
258: struct device *self;
259: void *aux;
260: {
261: struct zsc_softc *zsc = (void *)self;
262: struct zsc_attach_args zsc_args;
263: volatile struct zschan *zc;
264: struct xzs_chanstate *xcs;
265: struct zs_chanstate *cs;
266: int zsc_unit, channel;
267: int s, chip, theflags;
268:
269: if (!zsinited)
270: zs_init();
271: zsinited = 2;
272:
273: zsc_unit = zsc->zsc_dev.dv_unit;
274:
275: /* Make sure everything's inited ok. */
276: if (zsaddr[zsc_unit] == NULL)
277: panic("zs_attach: zs%d not mapped", zsc_unit);
278:
279: chip = 0;
280: #ifdef DEBUG
281: printf(" chip type %d",chip);
282: #endif
283: printf("\n");
284:
285: /*
286: * Initialize software state for each channel.
287: */
288: for (channel = 0; channel < 2; channel++) {
289: zsc_args.channel = channel;
290: zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
291: xcs = &zsc->xzsc_xcs_store[channel];
292: cs = &xcs->xzs_cs;
293: zsc->zsc_cs[channel] = cs;
294:
295: cs->cs_channel = channel;
296: cs->cs_private = NULL;
297: cs->cs_ops = &zsops_null;
298:
299: zc = zs_get_chan_addr(zsc_unit, channel);
300: cs->cs_reg_csr = &zc->zc_csr;
301: cs->cs_reg_data = &zc->zc_data;
302:
303: if (channel == 0) /* Double check interrupts are off */
304: zs_write_reg(cs, 9, 0);
305:
306: bcopy(zs_init_reg, cs->cs_creg, 16);
307: bcopy(zs_init_reg, cs->cs_preg, 16);
308:
309: /* Current BAUD rate generator clock. */
310: cs->cs_brg_clk = ZS_STD_BRG; /* RTxC is 230400*16, so use 230400 */
311: cs->cs_defspeed = zs_defspeed[zsc_unit][channel];
312: cs->cs_defcflag = zs_def_cflag;
313:
314: /* Make these correspond to cs_defcflag (-crtscts) */
315: cs->cs_rr0_dcd = ZSRR0_DCD;
316: cs->cs_rr0_cts = 0;
317: cs->cs_wr5_dtr = ZSWR5_DTR;
318: cs->cs_wr5_rts = 0;
319:
320: #ifdef __notyet__
321: cs->cs_slave_type = ZS_SLAVE_NONE;
322: #endif
323:
324: /* Define BAUD rate stuff. */
325: xcs->cs_clocks[0].clk = ZS_STD_BRG * 16;
326: xcs->cs_clocks[0].flags = ZSC_RTXBRG;
327: xcs->cs_clocks[1].flags =
328: ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
329: xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
330: xcs->cs_clock_count = 3;
331:
332: if (channel == 0) {
333: theflags = mac68k_machine.modem_flags;
334: xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;
335: xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;
336: } else {
337: theflags = mac68k_machine.print_flags;
338: xcs->cs_clocks[1].flags = ZSC_VARIABLE;
339: /*
340: * Yes, we aren't defining ANY clock source enables for
341: * the printer's DCD clock in. The hardware won't let
342: * us use it. But a clock will freak out the chip, so
343: * we let you set it, telling us to bar interrupts on
344: * the line.
345: */
346: xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;
347: xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;
348: }
349: if (xcs->cs_clocks[1].clk)
350: zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
351: if (xcs->cs_clocks[2].clk)
352: zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;
353:
354: #ifdef DEBUG
355: printf("zsc%d channel %d: d_speed %6d DCD clk %ld CTS clk %ld",
356: zsc_unit, channel, cs->cs_defspeed,
357: xcs->cs_clocks[1].clk, xcs->cs_clocks[2].clk);
358: #endif
359:
360: /* Set defaults in our "extended" chanstate. */
361: xcs->cs_csource = 0;
362: xcs->cs_psource = 0;
363: xcs->cs_cclk_flag = 0; /* Nothing fancy by default */
364: xcs->cs_pclk_flag = 0;
365:
366: if (theflags & ZSMAC_RAW) {
367: zsc_args.hwflags |= ZS_HWFLAG_RAW;
368: #ifdef DEBUG
369: printf(" (raw defaults)");
370: #endif
371: }
372:
373: /*
374: * XXX - This might be better done with a "stub" driver
375: * (to replace zstty) that ignores LocalTalk for now.
376: */
377: if (theflags & ZSMAC_LOCALTALK) {
378: printf(" shielding from LocalTalk");
379: cs->cs_defspeed = 1;
380: cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
381: cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
382: zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
383: zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
384: /*
385: * If we might have LocalTalk, then make sure we have
386: * the Baud rate low-enough to not do any damage.
387: */
388: }
389:
390: /*
391: * We used to disable chip interrupts here, but we now
392: * do that in zscnprobe, just in case MacOS left the chip on.
393: */
394:
395: xcs->cs_chip = chip;
396:
397: /* Stash away a copy of the final H/W flags. */
398: xcs->cs_hwflags = zsc_args.hwflags;
399:
400: #ifdef DEBUG
401: printf("\n");
402: #endif
403:
404: /*
405: * Look for a child driver for this channel.
406: * The child attach will setup the hardware.
407: */
408: if (!config_found(self, (void *)&zsc_args, zsc_print)) {
409: /* No sub-driver. Just reset it. */
410: u_char reset = (channel == 0) ?
411: ZSWR9_A_RESET : ZSWR9_B_RESET;
412: s = splzs();
413: zs_write_reg(cs, 9, reset);
414: splx(s);
415: }
416: }
417:
418: if (current_mac_model->class == MACH_CLASSAV) {
419: add_psc_lev4_intr(PSCINTR_SCCA, zshard, zsc);
420: add_psc_lev4_intr(PSCINTR_SCCB, zshard, zsc);
421: } else {
422: intr_establish(zshard, zsc, ZSHARD_PRI, self->dv_xname);
423: }
424:
425: /* XXX - Now safe to install interrupt handlers. */
426:
427: /*
428: * Set the master interrupt enable and interrupt vector.
429: * (common to both channels, do it on A)
430: */
431: cs = zsc->zsc_cs[0];
432: s = splzs();
433: /* interrupt vector */
434: zs_write_reg(cs, 2, zs_init_reg[2]);
435: /* master interrupt control (enable) */
436: zs_write_reg(cs, 9, zs_init_reg[9]);
437: nzsc_attached++;
438: splx(s);
439: }
440:
441: static int
442: zsc_print(aux, name)
443: void *aux;
444: const char *name;
445: {
446: struct zsc_attach_args *args = aux;
447:
448: if (name != NULL)
449: printf("%s: ", name);
450:
451: if (args->channel != -1)
452: printf(" channel %d", args->channel);
453: return UNCONF;
454: }
455:
456: int
457: zsmdioctl(cs, cmd, data)
458: struct zs_chanstate *cs;
459: u_long cmd;
460: caddr_t data;
461: {
462: switch (cmd) {
463: default:
464: return (-1);
465: }
466: return (0);
467: }
468:
469: void
470: zsmd_setclock(cs)
471: struct zs_chanstate *cs;
472: {
473: struct xzs_chanstate *xcs = (void *)cs;
474:
475: if (cs->cs_channel != 0)
476: return;
477:
478: /*
479: * If the new clock has the external bit set, then select the
480: * external source.
481: */
482: via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);
483: }
484:
485: static int zssoftpending;
486:
487: /*
488: * Do the minimum work to pull data off of the chip and queue it up
489: * for later processing.
490: */
491: int
492: zshard(arg)
493: void *arg;
494: {
495: struct zsc_softc *zsc = (struct zsc_softc *)arg;
496: int rval;
497:
498: if (zsc == NULL)
499: return 0;
500:
501: rval = 0;
502: rval |= zsc_intr_hard(zsc);
503: if ((zsc->zsc_cs[0]->cs_softreq) || (zsc->zsc_cs[1]->cs_softreq)) {
504: /* zsc_req_softint(zsc); */
505: /* We are at splzs here, so no need to lock. */
506: if (zssoftpending == 0) {
507: zssoftpending = 1;
508: setsoftserial();
509: }
510: }
511: return (rval);
512: }
513:
514: /*
515: * Similar scheme as for zshard (look at all of them)
516: */
517: int
518: zssoft(arg)
519: void *arg;
520: {
521: register struct zsc_softc *zsc;
522: register int unit;
523:
524: /* This is not the only ISR on this IPL. */
525: if (zssoftpending == 0)
526: return (0);
527:
528: /*
529: * The soft intr. bit will be set by zshard only if
530: * the variable zssoftpending is zero.
531: */
532: zssoftpending = 0;
533:
534: for (unit = 0; unit < zsc_cd.cd_ndevs; ++unit) {
535: zsc = zsc_cd.cd_devs[unit];
536: if (zsc == NULL)
537: continue;
538: (void) zsc_intr_soft(zsc);
539: }
540: return (1);
541: }
542:
543:
544: #ifndef ZS_TOLERANCE
545: #define ZS_TOLERANCE 51
546: /* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */
547: #endif
548:
549: /*
550: * check out a rate for acceptability from the internal clock
551: * source. Used in console config to validate a requested
552: * default speed. Placed here so that all the speed checking code is
553: * in one place.
554: *
555: * != 0 means ok.
556: */
557: int
558: zs_cn_check_speed(bps)
559: int bps; /* target rate */
560: {
561: int tc, rate;
562:
563: tc = BPS_TO_TCONST(ZS_STD_BRG, bps);
564: if (tc < 0)
565: return 0;
566: rate = TCONST_TO_BPS(ZS_STD_BRG, tc);
567: if (ZS_TOLERANCE > abs(((rate - bps)*1000)/bps))
568: return 1;
569: else
570: return 0;
571: }
572:
573: /*
574: * Search through the signal sources in the channel, and
575: * pick the best one for the baud rate requested. Return
576: * a -1 if not achievable in tolerance. Otherwise return 0
577: * and fill in the values.
578: *
579: * This routine draws inspiration from the Atari port's zs.c
580: * driver in NetBSD 1.1 which did the same type of source switching.
581: * Tolerance code inspired by comspeed routine in isa/com.c.
582: *
583: * By Bill Studenmund, 1996-05-12
584: */
585: int
586: zs_set_speed(cs, bps)
587: struct zs_chanstate *cs;
588: int bps; /* bits per second */
589: {
590: struct xzs_chanstate *xcs = (void *) cs;
591: int i, tc, tc0 = 0, tc1, s, sf = 0;
592: int src, rate0, rate1, err, tol;
593:
594: if (bps == 0)
595: return (0);
596:
597: src = -1; /* no valid source yet */
598: tol = ZS_TOLERANCE;
599:
600: /*
601: * Step through all the sources and see which one matches
602: * the best. A source has to match BETTER than tol to be chosen.
603: * Thus if two sources give the same error, the first one will be
604: * chosen. Also, allow for the possability that one source might run
605: * both the BRG and the direct divider (i.e. RTxC).
606: */
607: for (i=0; i < xcs->cs_clock_count; i++) {
608: if (xcs->cs_clocks[i].clk <= 0)
609: continue; /* skip non-existant or bad clocks */
610: if (xcs->cs_clocks[i].flags & ZSC_BRG) {
611: /* check out BRG at /16 */
612: tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps);
613: if (tc1 >= 0) {
614: rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1);
615: err = abs(((rate1 - bps)*1000)/bps);
616: if (err < tol) {
617: tol = err;
618: src = i;
619: sf = xcs->cs_clocks[i].flags & ~ZSC_DIV; tc0 = tc1;
620: rate0 = rate1;
621: }
622: }
623: }
624: if (xcs->cs_clocks[i].flags & ZSC_DIV) {
625: /*
626: * Check out either /1, /16, /32, or /64
627: * Note: for /1, you'd better be using a synchronized
628: * clock!
629: */
630: int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps);
631: int b1 = b0 >> 4, e1 = abs(b1-bps);
632: int b2 = b1 >> 1, e2 = abs(b2-bps);
633: int b3 = b2 >> 1, e3 = abs(b3-bps);
634:
635: if (e0 < e1 && e0 < e2 && e0 < e3) {
636: err = e0;
637: rate1 = b0;
638: tc1 = ZSWR4_CLK_X1;
639: } else if (e0 > e1 && e1 < e2 && e1 < e3) {
640: err = e1;
641: rate1 = b1;
642: tc1 = ZSWR4_CLK_X16;
643: } else if (e0 > e2 && e1 > e2 && e2 < e3) {
644: err = e2;
645: rate1 = b2;
646: tc1 = ZSWR4_CLK_X32;
647: } else {
648: err = e3;
649: rate1 = b3;
650: tc1 = ZSWR4_CLK_X64;
651: }
652:
653: err = (err * 1000)/bps;
654: if (err < tol) {
655: tol = err;
656: src = i;
657: sf = xcs->cs_clocks[i].flags & ~ZSC_BRG;
658: tc0 = tc1;
659: rate0 = rate1;
660: }
661: }
662: }
663: #ifdef ZSMACDEBUG
664: printf("Checking for rate %d. Found source #%d.\n",bps, src);
665: #endif
666: if (src == -1)
667: return (EINVAL); /* no can do */
668:
669: /*
670: * The M.I. layer likes to keep cs_brg_clk current, even though
671: * we are the only ones who should be touching the BRG's rate.
672: *
673: * Note: we are assuming that any ZSC_EXTERN signal source comes in
674: * on the RTxC pin. Correct for the mac68k obio zsc.
675: */
676: if (sf & ZSC_EXTERN)
677: cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4;
678: else
679: cs->cs_brg_clk = ZS_STD_BRG;
680:
681: /*
682: * Now we have a source, so set it up.
683: */
684: s = splzs();
685: xcs->cs_psource = src;
686: xcs->cs_pclk_flag = sf;
687: bps = rate0;
688: if (sf & ZSC_BRG) {
689: cs->cs_preg[4] = ZSWR4_CLK_X16;
690: cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
691: if (sf & ZSC_PCLK) {
692: cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
693: } else {
694: cs->cs_preg[14] = ZSWR14_BAUD_ENA;
695: }
696: tc = tc0;
697: } else {
698: cs->cs_preg[4] = tc0;
699: if (sf & ZSC_RTXDIV) {
700: cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC; } else {
701: cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC; }
702: cs->cs_preg[14]= 0;
703: tc = 0xffff;
704: }
705: /* Set the BAUD rate divisor. */
706: cs->cs_preg[12] = tc;
707: cs->cs_preg[13] = tc >> 8;
708: splx(s);
709:
710: #ifdef ZSMACDEBUG
711: printf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
712: bps, tc, src, sf);
713: printf("Registers are: 4 %x, 11 %x, 14 %x\n\n",
714: cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]);
715: #endif
716:
717: cs->cs_preg[5] |= ZSWR5_RTS; /* Make sure the drivers are on! */
718:
719: /* Caller will stuff the pending registers. */
720: return (0);
721: }
722:
723: int
724: zs_set_modes(cs, cflag)
725: struct zs_chanstate *cs;
726: int cflag; /* bits per second */
727: {
728: struct xzs_chanstate *xcs = (void*)cs;
729: int s;
730:
731: /*
732: * Make sure we don't enable hfc on a signal line we're ignoring.
733: * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS,
734: * this code also effectivly turns off ZSWR15_CTS_IE.
735: *
736: * Also, disable DCD interrupts if we've been told to ignore
737: * the DCD pin. Happens on mac68k because the input line for
738: * DCD can also be used as a clock input. (Just set CLOCAL.)
739: *
740: * If someone tries to turn an invalid flow mode on, Just Say No
741: * (Suggested by gwr)
742: */
743: #if 0
744: if ((cflag & CDTRCTS) && (cflag & (CRTSCTS | MDMBUF)))
745: return (EINVAL);
746: #endif
747: if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) {
748: if (cflag & MDMBUF)
749: return (EINVAL);
750: cflag |= CLOCAL;
751: }
752: #if 0
753: if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & (CRTSCTS | CDTRCTS)))
754: return (EINVAL);
755: #endif
756:
757: /*
758: * Output hardware flow control on the chip is horrendous:
759: * if carrier detect drops, the receiver is disabled, and if
760: * CTS drops, the transmitter is stoped IN MID CHARACTER!
761: * Therefore, NEVER set the HFC bit, and instead use the
762: * status interrupt to detect CTS changes.
763: */
764: s = splzs();
765: if ((cflag & (CLOCAL | MDMBUF)) != 0)
766: cs->cs_rr0_dcd = 0;
767: else
768: cs->cs_rr0_dcd = ZSRR0_DCD;
769: /*
770: * The mac hardware only has one output, DTR (HSKo in Mac
771: * parlance). In HFC mode, we use it for the functions
772: * typically served by RTS and DTR on other ports, so we
773: * have to fake the upper layer out some.
774: *
775: * CRTSCTS we use CTS as an input which tells us when to shut up.
776: * We make no effort to shut up the other side of the connection.
777: * DTR is used to hang up the modem.
778: *
779: * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to
780: * shut up the other side.
781: */
782: if ((cflag & CRTSCTS) != 0){
783: cs->cs_wr5_dtr = ZSWR5_DTR;
784: cs->cs_wr5_rts = 0;
785: cs->cs_rr0_cts = ZSRR0_CTS;
786: #if 0
787: } else if ((cflag & CDTRCTS) != 0) {
788: cs->cs_wr5_dtr = 0;
789: cs->cs_wr5_rts = ZSWR5_DTR;
790: cs->cs_rr0_cts = ZSRR0_CTS;
791: #endif
792: } else if ((cflag & MDMBUF) != 0) {
793: cs->cs_wr5_dtr = 0;
794: cs->cs_wr5_rts = ZSWR5_DTR;
795: cs->cs_rr0_cts = ZSRR0_DCD;
796: } else {
797: cs->cs_wr5_dtr = ZSWR5_DTR;
798: cs->cs_wr5_rts = 0;
799: cs->cs_rr0_cts = 0;
800: }
801: splx(s);
802:
803: /* Caller will stuff the pending registers. */
804: return(0);
805: }
806:
807: /*
808: * Read or write the chip with suitable delays.
809: * MacII hardware has the delay built in.
810: * No need for extra delay. :-) However, some clock-chiped
811: * macs, or zsc's on serial add-on boards might need it.
812: */
813: #define ZS_DELAY()
814:
815: u_char
816: zs_read_reg(cs, reg)
817: struct zs_chanstate *cs;
818: u_char reg;
819: {
820: u_char val;
821:
822: *cs->cs_reg_csr = reg;
823: ZS_DELAY();
824: val = *cs->cs_reg_csr;
825: ZS_DELAY();
826: return val;
827: }
828:
829: void
830: zs_write_reg(cs, reg, val)
831: struct zs_chanstate *cs;
832: u_char reg, val;
833: {
834: *cs->cs_reg_csr = reg;
835: ZS_DELAY();
836: *cs->cs_reg_csr = val;
837: ZS_DELAY();
838: }
839:
840: u_char zs_read_csr(cs)
841: struct zs_chanstate *cs;
842: {
843: u_char val;
844:
845: val = *cs->cs_reg_csr;
846: ZS_DELAY();
847: /* make up for the fact CTS is wired backwards */
848: val ^= ZSRR0_CTS;
849: return val;
850: }
851:
852: void zs_write_csr(cs, val)
853: struct zs_chanstate *cs;
854: register u_char val;
855: {
856: /* Note, the csr does not write CTS... */
857: *cs->cs_reg_csr = val;
858: ZS_DELAY();
859: }
860:
861: u_char zs_read_data(cs)
862: struct zs_chanstate *cs;
863: {
864: register u_char val;
865:
866: val = *cs->cs_reg_data;
867: ZS_DELAY();
868: return val;
869: }
870:
871: void zs_write_data(cs, val)
872: struct zs_chanstate *cs;
873: u_char val;
874: {
875: *cs->cs_reg_data = val;
876: ZS_DELAY();
877: }
878:
879: /****************************************************************
880: * Console support functions (mac68k specific!)
881: * Note: this code is allowed to know about the layout of
882: * the chip registers, and uses that to keep things simple.
883: * XXX - I think I like the mvme167 code better. -gwr
884: * XXX - Well :-P :-) -wrs
885: ****************************************************************/
886:
887: #define zscnpollc nullcnpollc
888: cons_decl(zs);
889:
890: static void zs_putc(register volatile struct zschan *, int);
891: static int zs_getc(register volatile struct zschan *);
892: static void zscnsetup(void);
893: extern int zsopen( dev_t dev, int flags, int mode, struct proc *p);
894:
895: /*
896: * Console functions.
897: */
898:
899: /*
900: * This code modled after the zs_setparam routine in zskgdb
901: * It sets the console unit to a known state so we can output
902: * correctly.
903: */
904: static void
905: zscnsetup()
906: {
907: struct xzs_chanstate xcs;
908: struct zs_chanstate *cs;
909: struct zschan *zc;
910: int tconst, s;
911:
912: /* Setup temporary chanstate. */
913: bzero((caddr_t)&xcs, sizeof(xcs));
914: cs = &xcs.xzs_cs;
915: zc = zs_conschan;
916: cs->cs_reg_csr = &zc->zc_csr;
917: cs->cs_reg_data = &zc->zc_data;
918: cs->cs_channel = zs_consunit;
919: cs->cs_brg_clk = ZS_STD_BRG;
920:
921: bcopy(zs_init_reg, cs->cs_preg, 16);
922: cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
923: cs->cs_preg[15] = ZSWR15_BREAK_IE;
924: tconst = BPS_TO_TCONST(cs->cs_brg_clk,
925: zs_defspeed[0][zs_consunit]);
926: cs->cs_preg[12] = tconst;
927: cs->cs_preg[13] = tconst >> 8;
928: /* can't use zs_set_speed as we haven't set up the
929: * signal sources, and it's not worth it for now
930: */
931:
932: /*
933: * As zs_loadchannelregs doesn't touch reg 9 (interrupt control),
934: * we won't accidentally turn on interrupts below
935: */
936: s = splhigh();
937: zs_loadchannelregs(cs);
938: splx(s);
939: }
940:
941: /*
942: * zscnprobe is the routine which gets called as the kernel is trying to
943: * figure out where the console should be. Each io driver which might
944: * be the console (as defined in mac68k/conf.c) gets probed. The probe
945: * fills in the consdev structure. Important parts are the device #,
946: * and the console priority. Values are CN_DEAD (don't touch me),
947: * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
948: * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
949: *
950: * As the mac's a bit different, we do extra work here. We mainly check
951: * to see if we have serial echo going on. Also chould check for default
952: * speeds.
953: */
954: void
955: zscnprobe(struct consdev * cp)
956: {
957: extern u_long IOBase;
958: int maj, unit, i;
959:
960: for (maj = 0; maj < nchrdev; maj++) {
961: if (cdevsw[maj].d_open == zsopen) {
962: break;
963: }
964: }
965: if (maj != nchrdev) {
966: cp->cn_pri = CN_NORMAL; /* Lower than CN_INTERNAL */
967: if (mac68k_machine.serial_console != 0) {
968: cp->cn_pri = CN_REMOTE; /* Higher than CN_INTERNAL */
969: mac68k_machine.serial_boot_echo =0;
970: }
971:
972: unit = (mac68k_machine.serial_console == 1) ? 0 : 1;
973: zs_consunit = unit;
974: zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
975:
976: mac68k_zsdev = cp->cn_dev = makedev(maj, unit);
977: }
978: if (mac68k_machine.serial_boot_echo) {
979: /*
980: * at this point, we know that we don't have a serial
981: * console, but are doing echo
982: */
983: zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
984: zs_consunit = 1; /* printer port */
985: }
986:
987: if ((i = mac68k_machine.modem_d_speed) > 0) {
988: if (zs_cn_check_speed(i))
989: zs_defspeed[0][0] = i;
990: }
991: if ((i = mac68k_machine.print_d_speed) > 0) {
992: if (zs_cn_check_speed(i))
993: zs_defspeed[0][1] = i;
994: }
995: mac68k_set_io_offsets(IOBase);
996: zs_init();
997: /*
998: * zsinit will set up the addresses of the scc. It will also, if
999: * zs_conschan != 0, calculate the new address of the conschan for
1000: * unit zs_consunit. So if we are (or think we are) going to use the
1001: * chip for console I/O, we just set up the internal addresses for it.
1002: *
1003: * Now turn off interrupts for the chip. Note: this code piece is the
1004: * only vestage of the NetBSD 1.0 ser driver. :-)
1005: */
1006: unit = sccA[2]; /* reset reg. access */
1007: unit = sccA[0];
1008: sccA[2] = 9; sccA[2] = 0; /* write 0 to reg. 9, clearing MIE */
1009: sccA[2] = ZSWR0_CLR_INTR; unit = sccA[2]; /* reset any pending ints. */
1010: sccA[0] = ZSWR0_CLR_INTR; unit = sccA[0];
1011:
1012: if (mac68k_machine.serial_boot_echo)
1013: zscnsetup();
1014: }
1015:
1016: void
1017: zscninit(struct consdev * cp)
1018: {
1019: zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
1020: /*
1021: * zsinit will set up the addresses of the scc. It will also, if
1022: * zs_conschan != 0, calculate the new address of the conschan for
1023: * unit zs_consunit. So zs_init implicitly sets zs_conschan to the right
1024: * number. :-)
1025: */
1026: zscnsetup();
1027: }
1028:
1029:
1030: /*
1031: * Polled input char.
1032: */
1033: static int
1034: zs_getc(zc)
1035: register volatile struct zschan *zc;
1036: {
1037: register int s, c, rr0;
1038:
1039: s = splhigh();
1040: /* Wait for a character to arrive. */
1041: do {
1042: rr0 = zc->zc_csr;
1043: ZS_DELAY();
1044: } while ((rr0 & ZSRR0_RX_READY) == 0);
1045:
1046: c = zc->zc_data;
1047: ZS_DELAY();
1048: splx(s);
1049:
1050: return (c);
1051: }
1052:
1053: /*
1054: * Polled output char.
1055: */
1056: static void
1057: zs_putc(zc, c)
1058: register volatile struct zschan *zc;
1059: int c;
1060: {
1061: register int s, rr0;
1062: register long wait = 0;
1063:
1064: s = splhigh();
1065: /* Wait for transmitter to become ready. */
1066: do {
1067: rr0 = zc->zc_csr;
1068: ZS_DELAY();
1069: } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
1070:
1071: if ((rr0 & ZSRR0_TX_READY) != 0) {
1072: zc->zc_data = c;
1073: ZS_DELAY();
1074: }
1075: splx(s);
1076: }
1077:
1078:
1079: /*
1080: * Polled console input putchar.
1081: */
1082: int
1083: zscngetc(dev)
1084: dev_t dev;
1085: {
1086: register volatile struct zschan *zc = zs_conschan;
1087: register int c;
1088:
1089: c = zs_getc(zc);
1090: return (c);
1091: }
1092:
1093: /*
1094: * Polled console output putchar.
1095: */
1096: void
1097: zscnputc(dev, c)
1098: dev_t dev;
1099: int c;
1100: {
1101: register volatile struct zschan *zc = zs_conschan;
1102:
1103: zs_putc(zc, c);
1104: }
1105:
1106:
1107:
1108: /*
1109: * Handle user request to enter kernel debugger.
1110: */
1111: void
1112: zs_abort(cs)
1113: struct zs_chanstate *cs;
1114: {
1115: volatile struct zschan *zc = zs_conschan;
1116: int rr0;
1117: register long wait = 0;
1118:
1119: /* Wait for end of break to avoid PROM abort. */
1120: do {
1121: rr0 = zc->zc_csr;
1122: ZS_DELAY();
1123: } while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
1124:
1125: if (wait > ZSABORT_DELAY)
1126: return; /* XXX */
1127: #ifdef DDB
1128: if (db_console)
1129: Debugger();
1130: #endif
1131: }
CVSweb