17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5a52acef5Skchow * Common Development and Distribution License (the "License").
6a52acef5Skchow * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Serial I/O driver for Z8530 chips
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
367c478bd9Sstevel@tonic-gate #include <sys/stream.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
397c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/zsdev.h>
437c478bd9Sstevel@tonic-gate #include <sys/debug.h>
447c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #include <sys/conf.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/errno.h>
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #define ZS_TRACING
517c478bd9Sstevel@tonic-gate #ifdef ZS_TRACING
527c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate * Temp tracepoint definitions
567c478bd9Sstevel@tonic-gate */
577c478bd9Sstevel@tonic-gate #define TR_FAC_ZS 51
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define TR_ZS_H_INT_START 1
607c478bd9Sstevel@tonic-gate #define TR_ZS_H_INT_END 2
617c478bd9Sstevel@tonic-gate #define TR_ZS_INT_START 3
627c478bd9Sstevel@tonic-gate #define TR_ZS_INT_END 4
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #define TR_FAC_ZS_INT 52
657c478bd9Sstevel@tonic-gate #define TR_READ_START 1
667c478bd9Sstevel@tonic-gate #define TR_READ_END 2
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #endif /* ZSH_TRACING */
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(zs->intrstats)
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #ifndef MAXZS
737c478bd9Sstevel@tonic-gate #define MAXZS 4
747c478bd9Sstevel@tonic-gate #endif
757c478bd9Sstevel@tonic-gate int maxzs = MAXZS;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate int nzs = 0;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate struct zscom *zscom;
807c478bd9Sstevel@tonic-gate struct zscom *zscurr;
817c478bd9Sstevel@tonic-gate struct zscom *zslast;
827c478bd9Sstevel@tonic-gate struct zs_prog *zs_prog;
837c478bd9Sstevel@tonic-gate char *zssoftCAR;
847c478bd9Sstevel@tonic-gate int zs_watchdog_count = 10; /* countdown to determine if tx hung */
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate int zs_drain_check = 15000000; /* tunable: exit drain check time */
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate #ifdef ZS_DEBUG
897c478bd9Sstevel@tonic-gate char zs_h_log[ZS_H_LOG_MAX +10];
907c478bd9Sstevel@tonic-gate int zs_h_log_n = 0;
917c478bd9Sstevel@tonic-gate #define zs_h_log_add(c) \
927c478bd9Sstevel@tonic-gate { \
937c478bd9Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \
947c478bd9Sstevel@tonic-gate zs_h_log_n = 0; \
957c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \
967c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate #else /* NO_ZS_DEBUG */
1007c478bd9Sstevel@tonic-gate #define zs_h_log_add(c)
1017c478bd9Sstevel@tonic-gate #endif /* ZS_DEBUG */
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * Driver data
1067c478bd9Sstevel@tonic-gate */
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate #define GETPROP(dip, str, defval) \
1097c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, (str), (defval))
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate int zs_usec_delay = 1;
1127c478bd9Sstevel@tonic-gate int zssoftpend;
1137c478bd9Sstevel@tonic-gate ddi_softintr_t zs_softintr_id;
1147c478bd9Sstevel@tonic-gate time_t default_dtrlow = 3; /* hold dtr low nearly this long on close */
1157c478bd9Sstevel@tonic-gate static ddi_iblock_cookie_t zs_iblock;
1167c478bd9Sstevel@tonic-gate static ddi_iblock_cookie_t zs_hi_iblock;
1177c478bd9Sstevel@tonic-gate static int zs_addedsoft = 0;
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate * Driver information for auto-configuration stuff.
1227c478bd9Sstevel@tonic-gate */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate static int zsprobe(dev_info_t *dev);
1257c478bd9Sstevel@tonic-gate static int zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd);
1267c478bd9Sstevel@tonic-gate static int zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd);
1277c478bd9Sstevel@tonic-gate void zsopinit(struct zscom *zs, struct zsops *zso);
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate static void zsnull_intr(struct zscom *zs);
1307c478bd9Sstevel@tonic-gate static int zsnull_softint(struct zscom *zs);
1317c478bd9Sstevel@tonic-gate static int zsnull_suspend(struct zscom *zs);
1327c478bd9Sstevel@tonic-gate static int zsnull_resume(struct zscom *zs);
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate struct zsops zsops_null = {
1357c478bd9Sstevel@tonic-gate zsnull_intr,
1367c478bd9Sstevel@tonic-gate zsnull_intr,
1377c478bd9Sstevel@tonic-gate zsnull_intr,
1387c478bd9Sstevel@tonic-gate zsnull_intr,
1397c478bd9Sstevel@tonic-gate zsnull_softint,
1407c478bd9Sstevel@tonic-gate zsnull_suspend,
1417c478bd9Sstevel@tonic-gate zsnull_resume
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate extern struct streamtab asynctab; /* default -- from zs_async.c */
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate uint_t zs_high_intr(caddr_t argzs);
1477c478bd9Sstevel@tonic-gate uint_t zsintr(caddr_t intarg);
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate extern int zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1507c478bd9Sstevel@tonic-gate void **result);
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
1537c478bd9Sstevel@tonic-gate int spec_type, minor_t minor_num);
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate extern struct streamtab zsstab;
1567c478bd9Sstevel@tonic-gate int zssoftpend; /* soft interrupt pending */
1577c478bd9Sstevel@tonic-gate kmutex_t zs_soft_lock; /* adapt.lock,to use to protect data */
1587c478bd9Sstevel@tonic-gate /* common to sev. streams or ports */
1597c478bd9Sstevel@tonic-gate kmutex_t zs_curr_lock; /* lock protecting zscurr */
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate extern kcondvar_t lbolt_cv;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * curently the only spin lock level 12 for all ocasions
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate #define ZSS_CONF_FLAG (D_NEW | D_MP)
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate static struct cb_ops cb_zs_ops = {
1707c478bd9Sstevel@tonic-gate nulldev, /* cb_open */
1717c478bd9Sstevel@tonic-gate nulldev, /* cb_close */
1727c478bd9Sstevel@tonic-gate nodev, /* cb_strategy */
1737c478bd9Sstevel@tonic-gate nodev, /* cb_print */
1747c478bd9Sstevel@tonic-gate nodev, /* cb_dump */
1757c478bd9Sstevel@tonic-gate nodev, /* cb_read */
1767c478bd9Sstevel@tonic-gate nodev, /* cb_write */
1777c478bd9Sstevel@tonic-gate nodev, /* cb_ioctl */
1787c478bd9Sstevel@tonic-gate nodev, /* cb_devmap */
1797c478bd9Sstevel@tonic-gate nodev, /* cb_mmap */
1807c478bd9Sstevel@tonic-gate nodev, /* cb_segmap */
1817c478bd9Sstevel@tonic-gate nochpoll, /* cb_chpoll */
1827c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
1837c478bd9Sstevel@tonic-gate &asynctab, /* cb_stream */
1847c478bd9Sstevel@tonic-gate (int)(ZSS_CONF_FLAG) /* cb_flag */
1857c478bd9Sstevel@tonic-gate };
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate struct dev_ops zs_ops = {
1887c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */
1897c478bd9Sstevel@tonic-gate 0, /* devo_refcnt */
1907c478bd9Sstevel@tonic-gate zsc_info, /* devo_getinfo */
1917c478bd9Sstevel@tonic-gate nulldev, /* devo_identify */
1927c478bd9Sstevel@tonic-gate zsprobe, /* devo_probe */
1937c478bd9Sstevel@tonic-gate zsattach, /* devo_attach */
1947c478bd9Sstevel@tonic-gate zsdetach, /* devo_detach */
1957c478bd9Sstevel@tonic-gate nodev, /* devo_reset */
1967c478bd9Sstevel@tonic-gate &cb_zs_ops, /* devo_cb_ops */
1977c478bd9Sstevel@tonic-gate (struct bus_ops *)NULL, /* devo_bus_ops */
198*19397407SSherry Moore ddi_power, /* devo_power */
199*19397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
2057c478bd9Sstevel@tonic-gate */
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
2167c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
217*19397407SSherry Moore "Z8530 serial driver",
2187c478bd9Sstevel@tonic-gate &zs_ops, /* driver ops */
2197c478bd9Sstevel@tonic-gate };
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2227c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
2237c478bd9Sstevel@tonic-gate };
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate int
_init(void)2267c478bd9Sstevel@tonic-gate _init(void)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate int
_fini(void)2327c478bd9Sstevel@tonic-gate _fini(void)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate return (EBUSY);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2387c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate static int
zsprobe(dev_info_t * dev)2447c478bd9Sstevel@tonic-gate zsprobe(dev_info_t *dev)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate struct zscc_device *zsaddr;
2477c478bd9Sstevel@tonic-gate int rval;
2487c478bd9Sstevel@tonic-gate auto char c;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate rval = DDI_PROBE_FAILURE;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate * temporarily map in registers
2547c478bd9Sstevel@tonic-gate */
2557c478bd9Sstevel@tonic-gate if (ddi_map_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0)) {
2567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zsprobe: unable to map registers");
2577c478bd9Sstevel@tonic-gate return (rval);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate * NON-DDI Compliant call
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate mon_clock_stop();
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate * get in sync with the chip
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) {
2707c478bd9Sstevel@tonic-gate goto out;
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate drv_usecwait(2);
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate * The traditional test for the presence of an 8530 has been to write
2767c478bd9Sstevel@tonic-gate * a 15 (octal 017) to its control register address, then read it back.
2777c478bd9Sstevel@tonic-gate * A Z8530 will respond to this with the contents of Read-Register 15.
2787c478bd9Sstevel@tonic-gate * If this address were memory, or something else, we would expect to
2797c478bd9Sstevel@tonic-gate * see the 15 again. Normally, the contents of RR15 will be entirely
2807c478bd9Sstevel@tonic-gate * different. A Z8530 does not use the D0 and D2 bits of register 15,
2817c478bd9Sstevel@tonic-gate * so they should equal zero. Compatable chips should do the same.
2827c478bd9Sstevel@tonic-gate * Beware of "enhanced" SCC's that do not guarantee this.
2837c478bd9Sstevel@tonic-gate */
2847c478bd9Sstevel@tonic-gate if (ddi_poke8(dev, (char *)&zsaddr->zscc_control, '\017')
2857c478bd9Sstevel@tonic-gate != DDI_SUCCESS) {
2867c478bd9Sstevel@tonic-gate goto out;
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate drv_usecwait(2);
2897c478bd9Sstevel@tonic-gate if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) {
2907c478bd9Sstevel@tonic-gate goto out;
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate drv_usecwait(2);
2937c478bd9Sstevel@tonic-gate if (c & 5) {
2947c478bd9Sstevel@tonic-gate goto out;
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate rval = DDI_PROBE_SUCCESS;
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate out:
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate * NON-DDI Compliant call
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate mon_clock_start();
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate ddi_unmap_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0);
3067c478bd9Sstevel@tonic-gate return (rval);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3107c478bd9Sstevel@tonic-gate static int
zsattach(dev_info_t * dev,ddi_attach_cmd_t cmd)3117c478bd9Sstevel@tonic-gate zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate struct zscom *zs;
3147c478bd9Sstevel@tonic-gate int loops, i;
3157c478bd9Sstevel@tonic-gate uint_t s;
3167c478bd9Sstevel@tonic-gate int rtsdtr_bits = 0;
3177c478bd9Sstevel@tonic-gate char softcd;
3187c478bd9Sstevel@tonic-gate uchar_t rr;
3197c478bd9Sstevel@tonic-gate short speed[2];
3207c478bd9Sstevel@tonic-gate int current_chip = ddi_get_instance(dev);
3217c478bd9Sstevel@tonic-gate struct zscc_device *tmpzs; /* for mapping purposes */
3227c478bd9Sstevel@tonic-gate char name[16];
3237c478bd9Sstevel@tonic-gate int keyboard_prop;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate switch (cmd) {
3267c478bd9Sstevel@tonic-gate case DDI_ATTACH:
3277c478bd9Sstevel@tonic-gate break;
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate case DDI_RESUME:
3307c478bd9Sstevel@tonic-gate zs = &zscom[current_chip*2];
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate * Try to resume first channel
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS)
3357c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate * And the second channel
3387c478bd9Sstevel@tonic-gate */
3397c478bd9Sstevel@tonic-gate zs++;
3407c478bd9Sstevel@tonic-gate if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS) {
3417c478bd9Sstevel@tonic-gate zs--;
3427c478bd9Sstevel@tonic-gate if (!zs->zs_suspend ||
3437c478bd9Sstevel@tonic-gate (zs->zs_suspend)(zs) != DDI_SUCCESS)
3447c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
3457c478bd9Sstevel@tonic-gate "zs: inconsistent suspend/resume state");
3467c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate default:
3517c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate if (zscom == NULL) {
3557c478bd9Sstevel@tonic-gate mutex_init(&zs_soft_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL);
3567c478bd9Sstevel@tonic-gate mutex_init(&zs_curr_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL_HI);
3577c478bd9Sstevel@tonic-gate zscom = kmem_zalloc(maxzs * sizeof (struct zscom), KM_SLEEP);
3587c478bd9Sstevel@tonic-gate zs_prog = kmem_zalloc(maxzs * sizeof (struct zs_prog),
3597c478bd9Sstevel@tonic-gate KM_SLEEP);
3607c478bd9Sstevel@tonic-gate zssoftCAR = kmem_zalloc(maxzs, KM_SLEEP);
3617c478bd9Sstevel@tonic-gate /* don't set nzs until arrays are allocated */
3627c478bd9Sstevel@tonic-gate membar_producer();
3637c478bd9Sstevel@tonic-gate nzs = maxzs;
3647c478bd9Sstevel@tonic-gate zscurr = &zscom[(current_chip*2) + 1];
3657c478bd9Sstevel@tonic-gate zslast = &zscom[current_chip*2];
3667c478bd9Sstevel@tonic-gate i = GETPROP(dev, "zs-usec-delay", 0);
3677c478bd9Sstevel@tonic-gate zs_usec_delay = (i <= 0) ? 1 : i;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate if (2 * current_chip >= maxzs) {
3717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
3727c478bd9Sstevel@tonic-gate "zs: unable to allocate resources for chip %d.",
3737c478bd9Sstevel@tonic-gate current_chip);
3747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Change zs:maxzs in /etc/system");
3757c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate zs = &zscom[current_chip*2];
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * map in the device registers
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate if (ddi_map_regs(dev, 0, (caddr_t *)&zs->zs_addr, 0, 0)) {
3837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: unable to map registers\n",
3847c478bd9Sstevel@tonic-gate current_chip);
3857c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate tmpzs = zs->zs_addr;
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate * Non-DDI compliant Sun-Ness specfic call(s)
3927c478bd9Sstevel@tonic-gate */
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate * Stop the monitor's polling interrupt.
3967c478bd9Sstevel@tonic-gate *
3977c478bd9Sstevel@tonic-gate * I know that this is not exactly obvious. On all sunmon PROM
3987c478bd9Sstevel@tonic-gate * machines, the PROM has can have a high level periodic clock
3997c478bd9Sstevel@tonic-gate * interrupt going at this time. It uses this periodic interrupt
4007c478bd9Sstevel@tonic-gate * to poll the console tty or kbd uart to check for things like
4017c478bd9Sstevel@tonic-gate * BREAK or L1-A (abort). While we're probing this device out we
4027c478bd9Sstevel@tonic-gate * have to shut that off so the PROM won't get confused by what
4037c478bd9Sstevel@tonic-gate * we're doing to the zs. This has caused some pretty funny bugs
4047c478bd9Sstevel@tonic-gate * in its time.
4057c478bd9Sstevel@tonic-gate *
4067c478bd9Sstevel@tonic-gate * For OPENPROM machines, the prom takes level12 interrupts directly,
4077c478bd9Sstevel@tonic-gate * but we call this routine anyway (I forget why).
4087c478bd9Sstevel@tonic-gate */
4097c478bd9Sstevel@tonic-gate mon_clock_stop();
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * Go critical to keep uart from urking.
4137c478bd9Sstevel@tonic-gate */
4147c478bd9Sstevel@tonic-gate s = ddi_enter_critical();
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate * We are about to issue a full reset to this chip.
4187c478bd9Sstevel@tonic-gate * First, now that interrupts are blocked, we will delay up to a
4197c478bd9Sstevel@tonic-gate * half-second, checking both channels for any stray activity.
4207c478bd9Sstevel@tonic-gate * Next we will preserve the time constants from both channels,
4217c478bd9Sstevel@tonic-gate * so that they can be restored after the reset. This is especially
4227c478bd9Sstevel@tonic-gate * important for the console device. Finally, do the reset and
4237c478bd9Sstevel@tonic-gate * follow it with an extended recovery while the chip settles down.
4247c478bd9Sstevel@tonic-gate */
4257c478bd9Sstevel@tonic-gate for (loops = 0; loops++ <= 500; DELAY(1000)) {
4267c478bd9Sstevel@tonic-gate SCC_READA(1, rr);
4277c478bd9Sstevel@tonic-gate if ((rr & ZSRR1_ALL_SENT) == 0) continue;
4287c478bd9Sstevel@tonic-gate SCC_READB(1, rr);
4297c478bd9Sstevel@tonic-gate if ((rr & ZSRR1_ALL_SENT) == 0) continue;
4307c478bd9Sstevel@tonic-gate SCC_READA(0, rr);
4317c478bd9Sstevel@tonic-gate if ((rr & ZSRR0_TX_READY) == 0) continue;
4327c478bd9Sstevel@tonic-gate SCC_READB(0, rr);
4337c478bd9Sstevel@tonic-gate if ((rr & ZSRR0_TX_READY) != 0) break;
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate SCC_READA(12, speed[0]);
4377c478bd9Sstevel@tonic-gate SCC_READA(13, rr);
4387c478bd9Sstevel@tonic-gate speed[0] |= rr << 8;
4397c478bd9Sstevel@tonic-gate SCC_READB(12, speed[1]);
4407c478bd9Sstevel@tonic-gate SCC_READB(13, rr);
4417c478bd9Sstevel@tonic-gate speed[1] |= rr << 8;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_RESET_WORLD);
4447c478bd9Sstevel@tonic-gate DELAY(10);
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate * Set up the other components of the zscom structs for this chip.
4487c478bd9Sstevel@tonic-gate */
4497c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) {
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * Property for ignoring DCD.
4527c478bd9Sstevel@tonic-gate * We switch between 'a' and 'b' ports for this device.
4537c478bd9Sstevel@tonic-gate */
454a52acef5Skchow static char prop[] = "port-a-ignore-cd";
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate * For this channel, set the hardware address, allocate the
4587c478bd9Sstevel@tonic-gate * high-level mutex, and update the zscurr pointer.
4597c478bd9Sstevel@tonic-gate * The high-level lock is shared by both channels because
4607c478bd9Sstevel@tonic-gate * 8530 register addressing is non-atomic and asymetrical.
4617c478bd9Sstevel@tonic-gate * Multiple threads crossing paths during this operation
4627c478bd9Sstevel@tonic-gate * could trash the chip, and thus, possibly the system console.
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate if (i == 0) { /* port A */
4657c478bd9Sstevel@tonic-gate zs->zs_addr = (struct zscc_device *)
4667c478bd9Sstevel@tonic-gate ((uintptr_t)tmpzs | ZSOFF);
4677c478bd9Sstevel@tonic-gate (zs+1)->zs_excl_hi = zs->zs_excl_hi = &zs_curr_lock;
4687c478bd9Sstevel@tonic-gate } else { /* port B */
4697c478bd9Sstevel@tonic-gate zs++;
4707c478bd9Sstevel@tonic-gate zs->zs_addr = (struct zscc_device *)
4717c478bd9Sstevel@tonic-gate ((uintptr_t)tmpzs & ~ZSOFF);
4727c478bd9Sstevel@tonic-gate zscurr = zs;
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate zs->zs_unit = current_chip * 2 + i;
4757c478bd9Sstevel@tonic-gate zs->zs_dip = dev;
4767c478bd9Sstevel@tonic-gate zs->zs_excl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
4777c478bd9Sstevel@tonic-gate mutex_init(zs->zs_excl, NULL, MUTEX_DRIVER, (void *)ZS_PL);
4787c478bd9Sstevel@tonic-gate zs->zs_ocexcl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
4797c478bd9Sstevel@tonic-gate mutex_init(zs->zs_ocexcl, NULL, MUTEX_DRIVER, (void *)ZS_PL);
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate prop[5] = 'a' + i;
4847c478bd9Sstevel@tonic-gate softcd = GETPROP((dev_info_t *)(dev), prop, 0);
4857c478bd9Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = softcd;
4867c478bd9Sstevel@tonic-gate if (softcd)
4877c478bd9Sstevel@tonic-gate rtsdtr_bits = ZSWR5_RTS | ZSWR5_DTR;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate keyboard_prop = GETPROP((dev_info_t *)(zs->zs_dip),
4907c478bd9Sstevel@tonic-gate "keyboard", 0);
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate * Set up the default asynch modes
4967c478bd9Sstevel@tonic-gate * so the monitor will still work
4977c478bd9Sstevel@tonic-gate */
4987c478bd9Sstevel@tonic-gate SCC_WRITE(4, ZSWR4_PARITY_EVEN | ZSWR4_1_STOP | ZSWR4_X16_CLK);
4997c478bd9Sstevel@tonic-gate SCC_WRITE(3, ZSWR3_RX_8);
5007c478bd9Sstevel@tonic-gate SCC_WRITE(11, ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD);
5017c478bd9Sstevel@tonic-gate SCC_WRITE(12, (speed[i] & 0xff));
5027c478bd9Sstevel@tonic-gate SCC_WRITE(13, (speed[i] >> 8) & 0xff);
5037c478bd9Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_BAUD_FROM_PCLK);
5047c478bd9Sstevel@tonic-gate SCC_WRITE(3, ZSWR3_RX_8 | ZSWR3_RX_ENABLE);
5057c478bd9Sstevel@tonic-gate SCC_WRITE(5, ZSWR5_TX_ENABLE | ZSWR5_TX_8 | rtsdtr_bits);
5067c478bd9Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK);
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate * The SYNC pin on the second SCC (keyboard & mouse) may not
5107c478bd9Sstevel@tonic-gate * be connected and noise creates transitions on this line.
5117c478bd9Sstevel@tonic-gate * This floods the system with interrupts, unless the
5127c478bd9Sstevel@tonic-gate * Sync/Hunt Interrupt Enable is cleared. So write
5137c478bd9Sstevel@tonic-gate * register 15 with everything we need but that one.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate if (keyboard_prop) {
5167c478bd9Sstevel@tonic-gate SCC_WRITE(15, ZSR15_BREAK | ZSR15_TX_UNDER |
5177c478bd9Sstevel@tonic-gate ZSR15_CTS | ZSR15_CD);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
5217c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
5227c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate zs->zs_dtrlow = gethrestime_sec() - default_dtrlow;
5257c478bd9Sstevel@tonic-gate cv_init(&zs->zs_flags_cv, NULL, CV_DEFAULT, NULL);
5267c478bd9Sstevel@tonic-gate zsa_init(zs);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
5307c478bd9Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT);
5317c478bd9Sstevel@tonic-gate DELAY(4000);
5327c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate * Two levels of interrupt - chip interrupts at a high level (12),
5367c478bd9Sstevel@tonic-gate * (which is seen below as zs_high_intr), and then as a secondary
5377c478bd9Sstevel@tonic-gate * stage soft interrupt as seen in zsintr below.
5387c478bd9Sstevel@tonic-gate *
5397c478bd9Sstevel@tonic-gate * Because zs_high_intr does a window save, as well as calls to
5407c478bd9Sstevel@tonic-gate * other functions, we cannot install it as a "fast" interrupt
5417c478bd9Sstevel@tonic-gate * that would execute right out of the trap window. Too bad...
5427c478bd9Sstevel@tonic-gate */
5437c478bd9Sstevel@tonic-gate if (ddi_add_intr(dev, (uint_t)0, &zs_hi_iblock,
5447c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)0, zs_high_intr,
5457c478bd9Sstevel@tonic-gate (caddr_t)0) != DDI_SUCCESS) {
5467c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cannot set high level zs interrupt");
5477c478bd9Sstevel@tonic-gate /*NOTREACHED*/
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate if (zs_addedsoft == 0) {
5517c478bd9Sstevel@tonic-gate if (ddi_add_softintr(dev, DDI_SOFTINT_HIGH, &zs_softintr_id,
5527c478bd9Sstevel@tonic-gate &zs_iblock, (ddi_idevice_cookie_t *)0,
5537c478bd9Sstevel@tonic-gate zsintr, (caddr_t)0) != DDI_SUCCESS) {
5547c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC,
5557c478bd9Sstevel@tonic-gate "cannot set second stage zs interrupt");
5567c478bd9Sstevel@tonic-gate /*NOTREACHED*/
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate zs_addedsoft++; /* we only need one zsintr! */
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate if (zs > zslast)
5637c478bd9Sstevel@tonic-gate zslast = zs;
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate (void) ddi_exit_critical(s);
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate * Non-DDI compliant Sun-Ness specific call
5697c478bd9Sstevel@tonic-gate */
5707c478bd9Sstevel@tonic-gate mon_clock_start(); /* re-enable monitor's polling interrupt */
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate if (!GETPROP(zs->zs_dip, "keyboard", 0)) {
5737c478bd9Sstevel@tonic-gate static char *serial_line = DDI_NT_SERIAL_MB;
5747c478bd9Sstevel@tonic-gate static char *dial_out = DDI_NT_SERIAL_MB_DO;
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate * Export names for channel a or b consconfig match...
5787c478bd9Sstevel@tonic-gate * The names exported to the filesystem include the
5797c478bd9Sstevel@tonic-gate * designated tty'a' type name and may not match the PROM
5807c478bd9Sstevel@tonic-gate * pathname.
5817c478bd9Sstevel@tonic-gate * Note the special name "obp-console-name" used in these calls.
5827c478bd9Sstevel@tonic-gate * This keeps the ports and devlinks programs from seeing these
5837c478bd9Sstevel@tonic-gate * names. (But allows ddi_pathname_to_dev_t to see them.)
5847c478bd9Sstevel@tonic-gate * We don't need to do this if the instance number is zero,
5857c478bd9Sstevel@tonic-gate * because we'll create them below, in this case.
5867c478bd9Sstevel@tonic-gate */
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate if (ddi_get_instance(dev) != 0) {
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate * Select a node type unused by ddi/devfs
5927c478bd9Sstevel@tonic-gate */
5937c478bd9Sstevel@tonic-gate static char *obp_type = "obp-console-name";
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate (void) strcpy(name, "a");
5967c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
5977c478bd9Sstevel@tonic-gate ddi_get_instance(dev) * 2,
5987c478bd9Sstevel@tonic-gate obp_type, NULL) == DDI_FAILURE) {
5997c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6007c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate (void) strcpy(name, "b");
6037c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
6047c478bd9Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1,
6057c478bd9Sstevel@tonic-gate obp_type, NULL) == DDI_FAILURE) {
6067c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6077c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate /*
6127c478bd9Sstevel@tonic-gate * Export normal device names...
6137c478bd9Sstevel@tonic-gate */
6147c478bd9Sstevel@tonic-gate (void) sprintf(name, "%c", (ddi_get_instance(dev) + 'a'));
6157c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
6167c478bd9Sstevel@tonic-gate ddi_get_instance(dev) * 2,
6177c478bd9Sstevel@tonic-gate serial_line, NULL) == DDI_FAILURE) {
6187c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6197c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate (void) sprintf(name, "%c", (ddi_get_instance(dev) + 'b'));
6227c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
6237c478bd9Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1,
6247c478bd9Sstevel@tonic-gate serial_line, NULL) == DDI_FAILURE) {
6257c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6267c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate (void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'a'));
6297c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
6307c478bd9Sstevel@tonic-gate (ddi_get_instance(dev) * 2) | OUTLINE,
6317c478bd9Sstevel@tonic-gate dial_out, NULL) == DDI_FAILURE) {
6327c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6337c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate (void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'b'));
6367c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR,
6377c478bd9Sstevel@tonic-gate ((ddi_get_instance(dev) * 2) + 1) | OUTLINE,
6387c478bd9Sstevel@tonic-gate dial_out, NULL) == DDI_FAILURE) {
6397c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6407c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate } else {
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate * Create keyboard and mouse nodes which devfs doesn't see
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate /*
6497c478bd9Sstevel@tonic-gate * This set of minor nodes is for use with the consconfig_dacf
6507c478bd9Sstevel@tonic-gate * module for the sun4u platforms. (See PSARC/1998/212)
6517c478bd9Sstevel@tonic-gate */
6527c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, "keyboard", S_IFCHR,
6537c478bd9Sstevel@tonic-gate ddi_get_instance(dev) * 2) == DDI_FAILURE) {
6547c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6557c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, "mouse", S_IFCHR,
6597c478bd9Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) {
6607c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6617c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate * These minor nodes are for use with pre-sun4u platforms.
6667c478bd9Sstevel@tonic-gate * Either one set or the other will be opened by consconfig.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate (void) strcpy(name, "a");
6697c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, name, S_IFCHR,
6707c478bd9Sstevel@tonic-gate ddi_get_instance(dev) * 2) == DDI_FAILURE) {
6717c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6727c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate (void) strcpy(name, "b");
6767c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, name, S_IFCHR,
6777c478bd9Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) {
6787c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
6797c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate ddi_report_dev(dev);
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate * Initialize power management bookkeeping; components are
6877c478bd9Sstevel@tonic-gate * created idle.
6887c478bd9Sstevel@tonic-gate */
6897c478bd9Sstevel@tonic-gate if (pm_create_components(dev, 3) == DDI_SUCCESS) {
6907c478bd9Sstevel@tonic-gate (void) pm_busy_component(dev, 0);
6917c478bd9Sstevel@tonic-gate pm_set_normal_power(dev, 0, 1);
6927c478bd9Sstevel@tonic-gate pm_set_normal_power(dev, 1, 1);
6937c478bd9Sstevel@tonic-gate pm_set_normal_power(dev, 2, 1);
6947c478bd9Sstevel@tonic-gate } else {
6957c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate (void) sprintf(name, "zsc%d", current_chip);
6997c478bd9Sstevel@tonic-gate zs->intrstats = kstat_create("zs", current_chip, name, "controller",
7007c478bd9Sstevel@tonic-gate KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
7017c478bd9Sstevel@tonic-gate if (zs->intrstats) {
7027c478bd9Sstevel@tonic-gate kstat_install(zs->intrstats);
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate static int
zsdetach(dev_info_t * dev,ddi_detach_cmd_t cmd)7097c478bd9Sstevel@tonic-gate zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate struct zscom *zs;
7127c478bd9Sstevel@tonic-gate int current_chip = ddi_get_instance(dev);
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate switch (cmd) {
7157c478bd9Sstevel@tonic-gate case DDI_DETACH:
7167c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate case DDI_SUSPEND:
7197c478bd9Sstevel@tonic-gate zs = &zscom[current_chip*2];
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate * Try to suspend first channel
7227c478bd9Sstevel@tonic-gate */
7237c478bd9Sstevel@tonic-gate if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS)
7247c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7257c478bd9Sstevel@tonic-gate /*
7267c478bd9Sstevel@tonic-gate * And the second channel
7277c478bd9Sstevel@tonic-gate */
7287c478bd9Sstevel@tonic-gate zs++;
7297c478bd9Sstevel@tonic-gate if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS) {
7307c478bd9Sstevel@tonic-gate zs--;
7317c478bd9Sstevel@tonic-gate if (!zs->zs_resume ||
7327c478bd9Sstevel@tonic-gate (zs->zs_resume)(zs) != DDI_SUCCESS)
7337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
7347c478bd9Sstevel@tonic-gate "zs: inconsistent suspend/resume state");
7357c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate default:
7407c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate * SCC High Level Interrupt Handler
7467c478bd9Sstevel@tonic-gate *
7477c478bd9Sstevel@tonic-gate * This routine fields the level 12 interrupts generated by the 8530 chips.
7487c478bd9Sstevel@tonic-gate * When the SCC interrupts the conditions that triggered it are available
7497c478bd9Sstevel@tonic-gate * for reference in Read Register 3 of the A channel (RR3A). We process
7507c478bd9Sstevel@tonic-gate * all the pending interrupts before returning. The maximum interrupts
7517c478bd9Sstevel@tonic-gate * that will be processed before returning is set to 6, which is twice
7527c478bd9Sstevel@tonic-gate * the size of RX-FIFO.
7537c478bd9Sstevel@tonic-gate * We keep a pointer to the B side of the most recently interrupting chip
7547c478bd9Sstevel@tonic-gate * in zscurr.
7557c478bd9Sstevel@tonic-gate */
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate * 'argzs' actually 'struct zscom *argzs'
7597c478bd9Sstevel@tonic-gate */
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate #define ZSRR3_INT_PENDING (ZSRR3_IP_B_STAT | ZSRR3_IP_B_TX | ZSRR3_IP_B_RX |\
7627c478bd9Sstevel@tonic-gate ZSRR3_IP_A_STAT | ZSRR3_IP_A_TX | ZSRR3_IP_A_RX)
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate #define ZSRR1_ANY_ERRORS (ZSRR1_PE | ZSRR1_DO | ZSRR1_FE | ZSRR1_RXEOF)
7657c478bd9Sstevel@tonic-gate #define ZS_HIGH_INTR_LOOPLIMIT 6
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7687c478bd9Sstevel@tonic-gate uint_t
zs_high_intr(caddr_t argzs)7697c478bd9Sstevel@tonic-gate zs_high_intr(caddr_t argzs)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate struct zscom *zs;
7727c478bd9Sstevel@tonic-gate uchar_t stat, isource, count;
7737c478bd9Sstevel@tonic-gate int unit;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_START, "zs_h_int start");
7767c478bd9Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
7777c478bd9Sstevel@tonic-gate zs = zscurr; /* Points at Channel B */
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate ZSNEXTPOLL(zs, zscurr);
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate SCC_READA(3, isource);
7827c478bd9Sstevel@tonic-gate start_zs_h:
7837c478bd9Sstevel@tonic-gate count = ZS_HIGH_INTR_LOOPLIMIT;
7847c478bd9Sstevel@tonic-gate while ((isource & ZSRR3_INT_PENDING) && (count--)) {
7857c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_B_STAT)
7867c478bd9Sstevel@tonic-gate (zs->zs_xsint)(zs);
7877c478bd9Sstevel@tonic-gate else {
7887c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_B_TX)
7897c478bd9Sstevel@tonic-gate (zs->zs_txint)(zs);
7907c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_B_RX) {
7917c478bd9Sstevel@tonic-gate SCC_READ(1, stat);
7927c478bd9Sstevel@tonic-gate if (stat & ZSRR1_ANY_ERRORS)
7937c478bd9Sstevel@tonic-gate (zs->zs_srint)(zs);
7947c478bd9Sstevel@tonic-gate else if ((SCC_READ0()) & ZSRR0_RX_READY)
7957c478bd9Sstevel@tonic-gate (zs->zs_rxint)(zs);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate zs -= 1;
8007c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_A_STAT)
8017c478bd9Sstevel@tonic-gate (zs->zs_xsint)(zs);
8027c478bd9Sstevel@tonic-gate else {
8037c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_A_TX)
8047c478bd9Sstevel@tonic-gate (zs->zs_txint)(zs);
8057c478bd9Sstevel@tonic-gate if (isource & ZSRR3_IP_A_RX) {
8067c478bd9Sstevel@tonic-gate SCC_READ(1, stat);
8077c478bd9Sstevel@tonic-gate if (stat & ZSRR1_ANY_ERRORS)
8087c478bd9Sstevel@tonic-gate (zs->zs_srint)(zs);
8097c478bd9Sstevel@tonic-gate else if ((SCC_READ0()) & ZSRR0_RX_READY)
8107c478bd9Sstevel@tonic-gate (zs->zs_rxint)(zs);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate zs = zscurr;
8157c478bd9Sstevel@tonic-gate SCC_READA(3, isource);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate if (count == ZS_HIGH_INTR_LOOPLIMIT) {
8197c478bd9Sstevel@tonic-gate unit = (nzs >> 1) - 1;
8207c478bd9Sstevel@tonic-gate while (unit--) {
8217c478bd9Sstevel@tonic-gate zs += 2; /* Always Channel B */
8227c478bd9Sstevel@tonic-gate if (zs > zslast)
8237c478bd9Sstevel@tonic-gate zs = &zscom[1];
8247c478bd9Sstevel@tonic-gate if (!zs->zs_ops)
8257c478bd9Sstevel@tonic-gate continue;
8267c478bd9Sstevel@tonic-gate SCC_READA(3, isource);
8277c478bd9Sstevel@tonic-gate if (isource & ZSRR3_INT_PENDING) {
8287c478bd9Sstevel@tonic-gate zscurr = zs; /* update zscurr and */
8297c478bd9Sstevel@tonic-gate goto start_zs_h;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate if (zs->intrstats) {
8337c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++;
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
8367c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end");
8377c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); /* Must not be for us. */
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate if (zs->intrstats) {
8407c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock); /* we're done with zscurr */
8437c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end");
8447c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate /*
8487c478bd9Sstevel@tonic-gate * Handle a second-stage interrupt.
8497c478bd9Sstevel@tonic-gate */
8507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8517c478bd9Sstevel@tonic-gate uint_t
zsintr(caddr_t intarg)8527c478bd9Sstevel@tonic-gate zsintr(caddr_t intarg)
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate struct zscom *zs;
8557c478bd9Sstevel@tonic-gate int rv;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate * Test and clear soft interrupt.
8597c478bd9Sstevel@tonic-gate */
8607c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_INT_START,
8617c478bd9Sstevel@tonic-gate "zs_int start");
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate mutex_enter(&zs_curr_lock);
8647c478bd9Sstevel@tonic-gate rv = zssoftpend;
8657c478bd9Sstevel@tonic-gate if (rv != 0) {
8667c478bd9Sstevel@tonic-gate zssoftpend = 0;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate mutex_exit(&zs_curr_lock);
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate if (rv) {
8717c478bd9Sstevel@tonic-gate for (zs = &zscom[0]; zs <= zslast; zs++) {
8727c478bd9Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) {
8737c478bd9Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT;
8747c478bd9Sstevel@tonic-gate (*zs->zs_ops->zsop_softint)(zs);
8757c478bd9Sstevel@tonic-gate if (zs->intrstats) {
8767c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SOFT]++;
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_INT_END,
8827c478bd9Sstevel@tonic-gate "zs_int end");
8837c478bd9Sstevel@tonic-gate return (rv);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate void
setzssoft(void)8877c478bd9Sstevel@tonic-gate setzssoft(void)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate ddi_trigger_softintr(zs_softintr_id);
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate /*
8937c478bd9Sstevel@tonic-gate * Install a new ops vector into low level vector routine addresses
8947c478bd9Sstevel@tonic-gate */
8957c478bd9Sstevel@tonic-gate void
zsopinit(struct zscom * zs,struct zsops * zso)8967c478bd9Sstevel@tonic-gate zsopinit(struct zscom *zs, struct zsops *zso)
8977c478bd9Sstevel@tonic-gate {
8987c478bd9Sstevel@tonic-gate zs->zs_txint = zso->zsop_txint;
8997c478bd9Sstevel@tonic-gate zs->zs_xsint = zso->zsop_xsint;
9007c478bd9Sstevel@tonic-gate zs->zs_rxint = zso->zsop_rxint;
9017c478bd9Sstevel@tonic-gate zs->zs_srint = zso->zsop_srint;
9027c478bd9Sstevel@tonic-gate zs->zs_suspend = zso->zsop_suspend;
9037c478bd9Sstevel@tonic-gate zs->zs_resume = zso->zsop_resume;
9047c478bd9Sstevel@tonic-gate zs->zs_ops = zso;
9057c478bd9Sstevel@tonic-gate zs->zs_flags = 0;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate /*
9097c478bd9Sstevel@tonic-gate * Set or get the modem control status.
9107c478bd9Sstevel@tonic-gate *
9117c478bd9Sstevel@tonic-gate * This routine relies on the fact that the bits of interest in RR0 (CD and
9127c478bd9Sstevel@tonic-gate * CTS) do not overlap the bits of interest in WR5 (RTS and DTR). Thus, they
9137c478bd9Sstevel@tonic-gate * can be combined into a single 'int' without harm.
9147c478bd9Sstevel@tonic-gate */
9157c478bd9Sstevel@tonic-gate int
zsmctl(struct zscom * zs,int bits,int how)9167c478bd9Sstevel@tonic-gate zsmctl(struct zscom *zs, int bits, int how)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate int mbits, obits;
9197c478bd9Sstevel@tonic-gate time_t now, held;
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl_hi));
9227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl));
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate again:
9257c478bd9Sstevel@tonic-gate mbits = zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR);
9267c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
9277c478bd9Sstevel@tonic-gate mbits |= SCC_READ0() & (ZSRR0_CD|ZSRR0_CTS);
9287c478bd9Sstevel@tonic-gate ZSDELAY();
9297c478bd9Sstevel@tonic-gate obits = mbits;
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate switch (how) {
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate case DMSET:
9347c478bd9Sstevel@tonic-gate mbits = bits;
9357c478bd9Sstevel@tonic-gate break;
9367c478bd9Sstevel@tonic-gate
9377c478bd9Sstevel@tonic-gate case DMBIS:
9387c478bd9Sstevel@tonic-gate mbits |= bits;
9397c478bd9Sstevel@tonic-gate break;
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate case DMBIC:
9427c478bd9Sstevel@tonic-gate mbits &= ~bits;
9437c478bd9Sstevel@tonic-gate break;
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate case DMGET:
9467c478bd9Sstevel@tonic-gate return (mbits);
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate now = gethrestime_sec();
9507c478bd9Sstevel@tonic-gate held = now - zs->zs_dtrlow;
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate /*
9537c478bd9Sstevel@tonic-gate * if DTR is going low, stash current time away
9547c478bd9Sstevel@tonic-gate */
9557c478bd9Sstevel@tonic-gate if (~mbits & obits & ZSWR5_DTR)
9567c478bd9Sstevel@tonic-gate zs->zs_dtrlow = now;
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * if DTR is going high, sleep until it has been low a bit
9607c478bd9Sstevel@tonic-gate */
9617c478bd9Sstevel@tonic-gate if ((mbits & ~obits & ZSWR5_DTR) && (held < default_dtrlow)) {
9627c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9637c478bd9Sstevel@tonic-gate cv_wait(&lbolt_cv, zs->zs_excl);
9647c478bd9Sstevel@tonic-gate if (zs->zs_suspended)
9657c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
9667c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9677c478bd9Sstevel@tonic-gate goto again;
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate zs->zs_wreg[5] &= ~(ZSWR5_RTS|ZSWR5_DTR);
9717c478bd9Sstevel@tonic-gate SCC_BIS(5, mbits & (ZSWR5_RTS|ZSWR5_DTR));
9727c478bd9Sstevel@tonic-gate return (mbits);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate * Program the Z8530 registers.
9777c478bd9Sstevel@tonic-gate */
9787c478bd9Sstevel@tonic-gate void
zs_program(struct zs_prog * zspp)9797c478bd9Sstevel@tonic-gate zs_program(struct zs_prog *zspp)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate struct zscom *zs = zspp->zs;
9827c478bd9Sstevel@tonic-gate int loops;
9837c478bd9Sstevel@tonic-gate uchar_t c;
9847c478bd9Sstevel@tonic-gate uchar_t wr10 = 0, wr14 = 0;
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl));
9877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl_hi));
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate * There are some special cases to account for before reprogramming.
9917c478bd9Sstevel@tonic-gate * We might be transmitting, so delay 100,000 usec (worst case at 110
9927c478bd9Sstevel@tonic-gate * baud) for this to finish, then disable the receiver until later,
9937c478bd9Sstevel@tonic-gate * reset the External Status Change latches and the error bits, and
9947c478bd9Sstevel@tonic-gate * drain the receive FIFO.
9957c478bd9Sstevel@tonic-gate * XXX: Doing any kind of reset (WR9) here causes trouble!
9967c478bd9Sstevel@tonic-gate */
9977c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_SYNC) {
9987c478bd9Sstevel@tonic-gate SCC_WRITE(7, SDLCFLAG);
9997c478bd9Sstevel@tonic-gate wr10 = ZSWR10_PRESET_ONES;
10007c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_NRZI)
10017c478bd9Sstevel@tonic-gate wr10 |= ZSWR10_NRZI;
10027c478bd9Sstevel@tonic-gate SCC_WRITE(10, wr10);
10037c478bd9Sstevel@tonic-gate } else {
10047c478bd9Sstevel@tonic-gate for (loops = 1000; loops > 0; --loops) {
10057c478bd9Sstevel@tonic-gate SCC_READ(1, c);
10067c478bd9Sstevel@tonic-gate if (c & ZSRR1_ALL_SENT)
10077c478bd9Sstevel@tonic-gate break;
10087c478bd9Sstevel@tonic-gate DELAY(100);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate SCC_WRITE(3, 0);
10117c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
10127c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
10137c478bd9Sstevel@tonic-gate c = SCC_READDATA(); /* Empty the FIFO */
10147c478bd9Sstevel@tonic-gate c = SCC_READDATA();
10157c478bd9Sstevel@tonic-gate c = SCC_READDATA();
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate /*
10197c478bd9Sstevel@tonic-gate * Programming the SCC is done in three phases.
10207c478bd9Sstevel@tonic-gate * Phase one sets operating modes:
10217c478bd9Sstevel@tonic-gate */
10227c478bd9Sstevel@tonic-gate SCC_WRITE(4, zspp->wr4);
10237c478bd9Sstevel@tonic-gate SCC_WRITE(11, zspp->wr11);
10247c478bd9Sstevel@tonic-gate SCC_WRITE(12, zspp->wr12);
10257c478bd9Sstevel@tonic-gate SCC_WRITE(13, zspp->wr13);
10267c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_PLL) {
10277c478bd9Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_SRC_BAUD);
10287c478bd9Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_NRZI);
10297c478bd9Sstevel@tonic-gate } else
10307c478bd9Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_DISABLE);
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate * Phase two enables special hardware functions:
10347c478bd9Sstevel@tonic-gate */
10357c478bd9Sstevel@tonic-gate wr14 = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA;
10367c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_LOOP)
10377c478bd9Sstevel@tonic-gate wr14 |= ZSWR14_LOCAL_LOOPBACK;
10387c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_ECHO)
10397c478bd9Sstevel@tonic-gate wr14 |= ZSWR14_AUTO_ECHO;
10407c478bd9Sstevel@tonic-gate SCC_WRITE(14, wr14);
10417c478bd9Sstevel@tonic-gate SCC_WRITE(3, zspp->wr3);
10427c478bd9Sstevel@tonic-gate SCC_WRITE(5, zspp->wr5);
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXCRC);
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate if (zspp->flags & ZSP_PARITY_SPECIAL) {
10477c478bd9Sstevel@tonic-gate SCC_WRITE(1, ZSWR1_PARITY_SPECIAL);
10487c478bd9Sstevel@tonic-gate } else {
10497c478bd9Sstevel@tonic-gate SCC_WRITE(1, 0);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate /*
10537c478bd9Sstevel@tonic-gate * Phase three enables interrupt sources:
10547c478bd9Sstevel@tonic-gate */
10557c478bd9Sstevel@tonic-gate SCC_WRITE(15, zspp->wr15);
10567c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
10577c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
10587c478bd9Sstevel@tonic-gate SCC_BIS(1, ZSWR1_INIT);
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate static void
zsnull_intr(struct zscom * zs)10627c478bd9Sstevel@tonic-gate zsnull_intr(struct zscom *zs)
10637c478bd9Sstevel@tonic-gate {
10647c478bd9Sstevel@tonic-gate short c;
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
10677c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
10687c478bd9Sstevel@tonic-gate c = SCC_READDATA();
10697c478bd9Sstevel@tonic-gate ZSDELAY();
10707c478bd9Sstevel@tonic-gate #ifdef lint
10717c478bd9Sstevel@tonic-gate c = c;
10727c478bd9Sstevel@tonic-gate #endif /* lint */
10737c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate static int
zsnull_softint(struct zscom * zs)10777c478bd9Sstevel@tonic-gate zsnull_softint(struct zscom *zs)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: unexpected soft int\n", zs->zs_unit);
10807c478bd9Sstevel@tonic-gate return (0);
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate * These will be called on suspend/resume for un-opened zs ports.
10857c478bd9Sstevel@tonic-gate */
10867c478bd9Sstevel@tonic-gate static int
zsnull_suspend(struct zscom * zs)10877c478bd9Sstevel@tonic-gate zsnull_suspend(struct zscom *zs)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate struct zs_prog *zspp = &zs_prog[zs->zs_unit];
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate /*
10927c478bd9Sstevel@tonic-gate * Get a copy of the current registers
10937c478bd9Sstevel@tonic-gate */
10947c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
10957c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
10967c478bd9Sstevel@tonic-gate zspp->zs = zs;
10977c478bd9Sstevel@tonic-gate zspp->flags = 0;
10987c478bd9Sstevel@tonic-gate zspp->wr3 = zs->zs_wreg[3];
10997c478bd9Sstevel@tonic-gate zspp->wr4 = zs->zs_wreg[4];
11007c478bd9Sstevel@tonic-gate zspp->wr5 = zs->zs_wreg[5];
11017c478bd9Sstevel@tonic-gate zspp->wr11 = zs->zs_wreg[11];
11027c478bd9Sstevel@tonic-gate zspp->wr12 = zs->zs_wreg[12];
11037c478bd9Sstevel@tonic-gate zspp->wr13 = zs->zs_wreg[13];
11047c478bd9Sstevel@tonic-gate zspp->wr15 = zs->zs_wreg[15];
11057c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11067c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate static int
zsnull_resume(struct zscom * zs)11127c478bd9Sstevel@tonic-gate zsnull_resume(struct zscom *zs)
11137c478bd9Sstevel@tonic-gate {
11147c478bd9Sstevel@tonic-gate struct zs_prog *zspp = &zs_prog[zs->zs_unit];
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate * Restore registers
11187c478bd9Sstevel@tonic-gate */
11197c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
11207c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
11217c478bd9Sstevel@tonic-gate zs_program(zspp);
11227c478bd9Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE);
11237c478bd9Sstevel@tonic-gate DELAY(4000);
11247c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11257c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11267c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
11277c478bd9Sstevel@tonic-gate }
1128