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