xref: /titanic_53/usr/src/uts/common/io/pcic.c (revision 0d282d1376eb7ba06504448622a6d65726e4bd3e)
13db86aabSstevel /*
23db86aabSstevel  * CDDL HEADER START
33db86aabSstevel  *
43db86aabSstevel  * The contents of this file are subject to the terms of the
53db86aabSstevel  * Common Development and Distribution License (the "License").
63db86aabSstevel  * You may not use this file except in compliance with the License.
73db86aabSstevel  *
83db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
103db86aabSstevel  * See the License for the specific language governing permissions
113db86aabSstevel  * and limitations under the License.
123db86aabSstevel  *
133db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
143db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
163db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
173db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
183db86aabSstevel  *
193db86aabSstevel  * CDDL HEADER END
203db86aabSstevel  */
213db86aabSstevel 
223db86aabSstevel /*
233db86aabSstevel  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
243db86aabSstevel  * Use is subject to license terms.
253db86aabSstevel  */
263db86aabSstevel 
273db86aabSstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
283db86aabSstevel 
293db86aabSstevel /*
303db86aabSstevel  * PCIC device/interrupt handler
313db86aabSstevel  *	The "pcic" driver handles the Intel 82365SL, Cirrus Logic
323db86aabSstevel  *	and Toshiba (and possibly other clones) PCMCIA adapter chip
333db86aabSstevel  *	sets.  It implements a subset of Socket Services as defined
343db86aabSstevel  *	in the Solaris PCMCIA design documents
353db86aabSstevel  */
363db86aabSstevel 
373db86aabSstevel /*
383db86aabSstevel  * currently defined "properties"
393db86aabSstevel  *
403db86aabSstevel  * clock-frequency		bus clock frequency
413db86aabSstevel  * smi				system management interrupt override
423db86aabSstevel  * need-mult-irq		need status IRQ for each pair of sockets
433db86aabSstevel  * disable-audio		don't route audio signal to speaker
443db86aabSstevel  */
453db86aabSstevel 
463db86aabSstevel 
473db86aabSstevel #include <sys/types.h>
483db86aabSstevel #include <sys/inttypes.h>
493db86aabSstevel #include <sys/param.h>
503db86aabSstevel #include <sys/systm.h>
513db86aabSstevel #include <sys/user.h>
523db86aabSstevel #include <sys/buf.h>
533db86aabSstevel #include <sys/file.h>
543db86aabSstevel #include <sys/uio.h>
553db86aabSstevel #include <sys/conf.h>
563db86aabSstevel #include <sys/stat.h>
573db86aabSstevel #include <sys/autoconf.h>
583db86aabSstevel #include <sys/vtoc.h>
593db86aabSstevel #include <sys/dkio.h>
603db86aabSstevel #include <sys/ddi.h>
613db86aabSstevel #include <sys/sunddi.h>
623db86aabSstevel #include <sys/sunndi.h>
633db86aabSstevel #include <sys/var.h>
643db86aabSstevel #include <sys/callb.h>
653db86aabSstevel #include <sys/open.h>
663db86aabSstevel #include <sys/ddidmareq.h>
673db86aabSstevel #include <sys/dma_engine.h>
683db86aabSstevel #include <sys/kstat.h>
693db86aabSstevel #include <sys/kmem.h>
703db86aabSstevel #include <sys/modctl.h>
713db86aabSstevel #include <sys/pci.h>
723db86aabSstevel #include <sys/pci_impl.h>
733db86aabSstevel 
743db86aabSstevel #include <sys/pctypes.h>
753db86aabSstevel #include <sys/pcmcia.h>
763db86aabSstevel #include <sys/sservice.h>
773db86aabSstevel 
783db86aabSstevel #include <sys/note.h>
793db86aabSstevel 
803db86aabSstevel #include <sys/pcic_reg.h>
813db86aabSstevel #include <sys/pcic_var.h>
823db86aabSstevel 
833db86aabSstevel #if defined(__sparc)
843db86aabSstevel #include <sys/pci/pci_nexus.h>
853db86aabSstevel #endif
863db86aabSstevel 
87*0d282d13Srw148561 #include <sys/hotplug/hpcsvc.h>
883db86aabSstevel #include <sys/syshw.h>
893db86aabSstevel #include "cardbus/cardbus.h"
903db86aabSstevel 
913db86aabSstevel #define	SOFTC_SIZE	(sizeof (anp_t))
923db86aabSstevel 
933db86aabSstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
943db86aabSstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t);
953db86aabSstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t);
963db86aabSstevel static uint_t pcic_intr(caddr_t, caddr_t);
973db86aabSstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t);
983db86aabSstevel static int pcic_probe(dev_info_t *);
993db86aabSstevel 
1003db86aabSstevel static int pcic_open(dev_t *, int, int, cred_t *);
1013db86aabSstevel static int pcic_close(dev_t, int, int, cred_t *);
1023db86aabSstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1033db86aabSstevel 
1043db86aabSstevel typedef struct pcm_regs pcm_regs_t;
1053db86aabSstevel 
1063db86aabSstevel static void pcic_init_assigned(dev_info_t *);
1073db86aabSstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *,
1083db86aabSstevel 	pci_regspec_t *, int);
1093db86aabSstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int);
1103db86aabSstevel 
1113db86aabSstevel /*
1123db86aabSstevel  * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls
1133db86aabSstevel  * are xlated into DMA ctlops. To make this nexus work on x86, we
1143db86aabSstevel  * need to have the default ddi_dma_mctl ctlops in the bus_ops
1153db86aabSstevel  * structure, just to pass the request to the parent. The correct
1163db86aabSstevel  * ctlops should be ddi_no_dma_mctl because so far we don't do DMA.
1173db86aabSstevel  */
1183db86aabSstevel static
1193db86aabSstevel struct bus_ops pcmciabus_ops = {
1203db86aabSstevel 	BUSO_REV,
1213db86aabSstevel 	pcmcia_bus_map,
1223db86aabSstevel 	NULL,
1233db86aabSstevel 	NULL,
1243db86aabSstevel 	NULL,
1253db86aabSstevel 	i_ddi_map_fault,
1263db86aabSstevel 	ddi_no_dma_map,
1273db86aabSstevel 	ddi_no_dma_allochdl,
1283db86aabSstevel 	ddi_no_dma_freehdl,
1293db86aabSstevel 	ddi_no_dma_bindhdl,
1303db86aabSstevel 	ddi_no_dma_unbindhdl,
1313db86aabSstevel 	ddi_no_dma_flush,
1323db86aabSstevel 	ddi_no_dma_win,
1333db86aabSstevel 	ddi_dma_mctl,
1343db86aabSstevel 	pcmcia_ctlops,
1353db86aabSstevel 	pcmcia_prop_op,
1363db86aabSstevel 	NULL,				/* (*bus_get_eventcookie)();	*/
1373db86aabSstevel 	NULL,				/* (*bus_add_eventcall)();	*/
1383db86aabSstevel 	NULL,				/* (*bus_remove_eventcall)();	*/
1393db86aabSstevel 	NULL,				/* (*bus_post_event)();		*/
1403db86aabSstevel 	NULL,				/* (*bus_intr_ctl)();		*/
1413db86aabSstevel 	NULL,				/* (*bus_config)(); 		*/
1423db86aabSstevel 	NULL,				/* (*bus_unconfig)(); 		*/
1433db86aabSstevel 	NULL,				/* (*bus_fm_init)(); 		*/
1443db86aabSstevel 	NULL,				/* (*bus_fm_fini)(); 		*/
1453db86aabSstevel 	NULL,				/* (*bus_enter)()		*/
1463db86aabSstevel 	NULL,				/* (*bus_exit)()		*/
1473db86aabSstevel 	NULL,				/* (*bus_power)()		*/
1483db86aabSstevel 	pcmcia_intr_ops			/* (*bus_intr_op)(); 		*/
1493db86aabSstevel };
1503db86aabSstevel 
1513db86aabSstevel static struct cb_ops pcic_cbops = {
1523db86aabSstevel 	pcic_open,
1533db86aabSstevel 	pcic_close,
1543db86aabSstevel 	nodev,
1553db86aabSstevel 	nodev,
1563db86aabSstevel 	nodev,
1573db86aabSstevel 	nodev,
1583db86aabSstevel 	nodev,
1593db86aabSstevel 	pcic_ioctl,
1603db86aabSstevel 	nodev,
1613db86aabSstevel 	nodev,
1623db86aabSstevel 	nodev,
1633db86aabSstevel 	nochpoll,
1643db86aabSstevel 	ddi_prop_op,
1653db86aabSstevel 	NULL,
1663db86aabSstevel #ifdef CARDBUS
1673db86aabSstevel 	D_NEW | D_MP | D_HOTPLUG
1683db86aabSstevel #else
1693db86aabSstevel 	D_NEW | D_MP
1703db86aabSstevel #endif
1713db86aabSstevel };
1723db86aabSstevel 
1733db86aabSstevel static struct dev_ops pcic_devops = {
1743db86aabSstevel 	DEVO_REV,
1753db86aabSstevel 	0,
1763db86aabSstevel 	pcic_getinfo,
1773db86aabSstevel 	nulldev,
1783db86aabSstevel 	pcic_probe,
1793db86aabSstevel 	pcic_attach,
1803db86aabSstevel 	pcic_detach,
1813db86aabSstevel 	nulldev,
1823db86aabSstevel 	&pcic_cbops,
1833db86aabSstevel 	&pcmciabus_ops,
1843db86aabSstevel 	NULL
1853db86aabSstevel };
1863db86aabSstevel 
1873db86aabSstevel void *pcic_soft_state_p = NULL;
1883db86aabSstevel static int pcic_maxinst = -1;
1893db86aabSstevel static timeout_id_t pcic_delayed_resume_toid;
1903db86aabSstevel 
1913db86aabSstevel int pcic_do_insertion = 1;
1923db86aabSstevel int pcic_do_removal = 1;
1933db86aabSstevel 
1943db86aabSstevel struct irqmap {
1953db86aabSstevel 	int irq;
1963db86aabSstevel 	int count;
1973db86aabSstevel } pcic_irq_map[16];
1983db86aabSstevel 
1993db86aabSstevel 
2003db86aabSstevel int pcic_debug = 0x0;
2013db86aabSstevel static  void    pcic_err(dev_info_t *dip, int level, const char *fmt, ...);
2023db86aabSstevel extern void cardbus_dump_pci_config(dev_info_t *dip);
2033db86aabSstevel extern void cardbus_dump_socket(dev_info_t *dip);
2043db86aabSstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle);
2053db86aabSstevel static void pcic_dump_debqueue(char *msg);
2063db86aabSstevel 
2073db86aabSstevel #if defined(PCIC_DEBUG)
2083db86aabSstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t);
2093db86aabSstevel 
2103db86aabSstevel #define	pcic_mutex_enter(a)	\
2113db86aabSstevel 	{ \
2123db86aabSstevel 		pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \
2133db86aabSstevel 		mutex_enter(a); \
2143db86aabSstevel 	};
2153db86aabSstevel 
2163db86aabSstevel #define	pcic_mutex_exit(a)	\
2173db86aabSstevel 	{ \
2183db86aabSstevel 		pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \
2193db86aabSstevel 		mutex_exit(a); \
2203db86aabSstevel 	};
2213db86aabSstevel 
2223db86aabSstevel #else
2233db86aabSstevel #define	pcic_mutex_enter(a)	mutex_enter(a)
2243db86aabSstevel #define	pcic_mutex_exit(a)	mutex_exit(a)
2253db86aabSstevel #endif
2263db86aabSstevel 
2273db86aabSstevel #define	PCIC_VCC_3VLEVEL	1
2283db86aabSstevel #define	PCIC_VCC_5VLEVEL	2
2293db86aabSstevel #define	PCIC_VCC_12LEVEL	3
2303db86aabSstevel 
2313db86aabSstevel /* bit patterns to select voltage levels */
2323db86aabSstevel int pcic_vpp_levels[13] = {
2333db86aabSstevel 	0, 0, 0,
2343db86aabSstevel 	1,	/* 3.3V */
2353db86aabSstevel 	0,
2363db86aabSstevel 	1,	/* 5V */
2373db86aabSstevel 	0, 0, 0, 0, 0, 0,
2383db86aabSstevel 	2	/* 12V */
2393db86aabSstevel };
2403db86aabSstevel 
2413db86aabSstevel uint8_t pcic_cbv_levels[13] = {
2423db86aabSstevel 	0, 0, 0,
2433db86aabSstevel 	3,			/* 3.3V */
2443db86aabSstevel 	0,
2453db86aabSstevel 	2,			/* 5V */
2463db86aabSstevel 	0, 0, 0, 0, 0, 0,
2473db86aabSstevel 	1			/* 12V */
2483db86aabSstevel };
2493db86aabSstevel 
2503db86aabSstevel struct power_entry pcic_power[4] = {
2513db86aabSstevel 	{
2523db86aabSstevel 		0, VCC|VPP1|VPP2
2533db86aabSstevel 	},
2543db86aabSstevel 	{
2553db86aabSstevel 		33,		/* 3.3Volt */
2563db86aabSstevel 		VCC|VPP1|VPP2
2573db86aabSstevel 	},
2583db86aabSstevel 	{
2593db86aabSstevel 		5*10,		/* 5Volt */
2603db86aabSstevel 		VCC|VPP1|VPP2	/* currently only know about this */
2613db86aabSstevel 	},
2623db86aabSstevel 	{
2633db86aabSstevel 		12*10,		/* 12Volt */
2643db86aabSstevel 		VPP1|VPP2
2653db86aabSstevel 	}
2663db86aabSstevel };
2673db86aabSstevel 
2683db86aabSstevel /*
2693db86aabSstevel  * Base used to allocate ranges of PCI memory on x86 systems
2703db86aabSstevel  * Each instance gets a chunk above the base that is used to map
2713db86aabSstevel  * in the memory and I/O windows for that device.
2723db86aabSstevel  * Pages below the base are also allocated for the EXCA registers,
2733db86aabSstevel  * one per instance.
2743db86aabSstevel  */
2753db86aabSstevel #define	PCIC_PCI_MEMCHUNK	0x1000000
2763db86aabSstevel 
2773db86aabSstevel static int pcic_wait_insert_time = 5000000;	/* In micro-seconds */
2783db86aabSstevel static int pcic_debounce_time = 200000; /* In micro-seconds */
2793db86aabSstevel 
2803db86aabSstevel struct debounce {
2813db86aabSstevel 	pcic_socket_t *pcs;
2823db86aabSstevel 	clock_t expire;
2833db86aabSstevel 	struct debounce *next;
2843db86aabSstevel };
2853db86aabSstevel 
2863db86aabSstevel static syshw_t pcic_syshw = {
2873db86aabSstevel 	0, "PC Card Socket 0", SH_CONNECTION,
2883db86aabSstevel 	SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID|SYSHW_VAL0_VALID,
2893db86aabSstevel 	B_FALSE, {2, 0, 0, 0}
2903db86aabSstevel };
2913db86aabSstevel 
2923db86aabSstevel static struct debounce *pcic_deb_queue = NULL;
2933db86aabSstevel static kmutex_t pcic_deb_mtx;
2943db86aabSstevel static kcondvar_t pcic_deb_cv;
2953db86aabSstevel static kthread_t *pcic_deb_threadid;
2963db86aabSstevel 
2973db86aabSstevel static inthandler_t *pcic_handlers;
2983db86aabSstevel 
2993db86aabSstevel static void pcic_setup_adapter(pcicdev_t *);
3003db86aabSstevel static int pcic_change(pcicdev_t *, int);
3013db86aabSstevel static int pcic_ll_reset(pcicdev_t *, int);
3023db86aabSstevel static void pcic_mswait(pcicdev_t *, int, int);
3033db86aabSstevel static boolean_t pcic_check_ready(pcicdev_t *, int);
3043db86aabSstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int);
3053db86aabSstevel static void pcic_ready_wait(pcicdev_t *, int);
3063db86aabSstevel extern int pcmcia_get_intr(dev_info_t *, int);
3073db86aabSstevel extern int pcmcia_return_intr(dev_info_t *, int);
3083db86aabSstevel 
3093db86aabSstevel static int pcic_callback(dev_info_t *, int (*)(), int);
3103db86aabSstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *);
3113db86aabSstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *);
3123db86aabSstevel static int pcic_get_page(dev_info_t *, get_page_t *);
3133db86aabSstevel static int pcic_get_socket(dev_info_t *, get_socket_t *);
3143db86aabSstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *);
3153db86aabSstevel static int pcic_get_window(dev_info_t *, get_window_t *);
3163db86aabSstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *);
3173db86aabSstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *);
3183db86aabSstevel static int pcic_reset_socket(dev_info_t *, int, int);
3193db86aabSstevel static int pcic_set_page(dev_info_t *, set_page_t *);
3203db86aabSstevel static int pcic_set_window(dev_info_t *, set_window_t *);
3213db86aabSstevel static int pcic_set_socket(dev_info_t *, set_socket_t *);
3223db86aabSstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *);
3233db86aabSstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
3243db86aabSstevel static void pcic_pm_detection(void *);
3253db86aabSstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned);
3263db86aabSstevel static int clext_reg_read(pcicdev_t *, int, uchar_t);
3273db86aabSstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t);
3283db86aabSstevel static int pcic_calc_speed(pcicdev_t *, uint32_t);
3293db86aabSstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *);
3303db86aabSstevel static int pcic_find_pci_type(pcicdev_t *);
3313db86aabSstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int);
3323db86aabSstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t);
3333db86aabSstevel static uint_t pcic_cd_softint(caddr_t, caddr_t);
3343db86aabSstevel static uint8_t pcic_getb(pcicdev_t *, int, int);
3353db86aabSstevel static void pcic_putb(pcicdev_t *, int, int, int8_t);
3363db86aabSstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *);
3373db86aabSstevel static uint_t pcic_softintr(caddr_t, caddr_t);
3383db86aabSstevel 
3393db86aabSstevel static void pcic_debounce(pcic_socket_t *);
3403db86aabSstevel static void pcic_delayed_resume(void *);
3413db86aabSstevel static void *pcic_add_debqueue(pcic_socket_t *, int);
3423db86aabSstevel static void pcic_rm_debqueue(void *);
3433db86aabSstevel static void pcic_deb_thread();
3443db86aabSstevel 
3453db86aabSstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3463db86aabSstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3473db86aabSstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg);
3483db86aabSstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value);
3493db86aabSstevel static void pcic_cb_enable_intr(dev_info_t *);
3503db86aabSstevel static void pcic_cb_disable_intr(dev_info_t *);
3513db86aabSstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq);
3523db86aabSstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket);
3533db86aabSstevel 
3543db86aabSstevel static cb_nexus_cb_t pcic_cbnexus_ops = {
3553db86aabSstevel 	pcic_cb_enable_intr,
3563db86aabSstevel 	pcic_cb_disable_intr
3573db86aabSstevel };
3583db86aabSstevel 
3593db86aabSstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel);
3603db86aabSstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket);
3613db86aabSstevel 
3623db86aabSstevel static void pcic_syshw_cardstate(syshw_t *, void *);
3633db86aabSstevel 
3643db86aabSstevel #if defined(__sparc)
3653db86aabSstevel static int pcic_fault(enum pci_fault_ops op, void *arg);
3663db86aabSstevel #endif
3673db86aabSstevel 
3683db86aabSstevel /*
3693db86aabSstevel  * Default to support for Voyager IIi if sparc is defined.
3703db86aabSstevel  * Appart from the PCI base addresses this only effect the TI1250.
3713db86aabSstevel  */
3723db86aabSstevel #if defined(sparc)
3733db86aabSstevel #define	VOYAGER
3743db86aabSstevel #endif
3753db86aabSstevel 
3763db86aabSstevel 
3773db86aabSstevel /*
3783db86aabSstevel  * pcmcia_attach() uses 0 and 128 upwards for the initpcmcia and devctl
3793db86aabSstevel  * interfaces so we use 254.
3803db86aabSstevel  */
3813db86aabSstevel #define	SYSHW_MINOR	254
3823db86aabSstevel 
3833db86aabSstevel /*
3843db86aabSstevel  * Forward declarations for syshw interface (See end of file).
3853db86aabSstevel  */
3863db86aabSstevel static void syshw_attach(pcicdev_t *);
3873db86aabSstevel static void syshw_detach(pcicdev_t *);
3883db86aabSstevel static void syshw_resume(pcicdev_t *);
3893db86aabSstevel 
3903db86aabSstevel #ifdef VOYAGER
3913db86aabSstevel static uint_t syshw_intr(caddr_t);
3923db86aabSstevel static uint_t syshw_intr_hi(pcicdev_t *);
3933db86aabSstevel #endif
3943db86aabSstevel 
3953db86aabSstevel static int syshw_open(dev_t *, int, int, cred_t *);
3963db86aabSstevel static int syshw_close(dev_t, int, int, cred_t *);
3973db86aabSstevel static int syshw_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
3983db86aabSstevel static uint32_t syshw_add2map(syshw_t *, void (*)(syshw_t *, void *), void *);
3993db86aabSstevel static void syshw_send_signal(int);
4003db86aabSstevel 
4013db86aabSstevel /*
4023db86aabSstevel  * pcmcia interface operations structure
4033db86aabSstevel  * this is the private interface that is exported to the nexus
4043db86aabSstevel  */
4053db86aabSstevel pcmcia_if_t pcic_if_ops = {
4063db86aabSstevel 	PCIF_MAGIC,
4073db86aabSstevel 	PCIF_VERSION,
4083db86aabSstevel 	pcic_callback,
4093db86aabSstevel 	pcic_get_adapter,
4103db86aabSstevel 	pcic_get_page,
4113db86aabSstevel 	pcic_get_socket,
4123db86aabSstevel 	pcic_get_status,
4133db86aabSstevel 	pcic_get_window,
4143db86aabSstevel 	pcic_inquire_adapter,
4153db86aabSstevel 	pcic_inquire_socket,
4163db86aabSstevel 	pcic_inquire_window,
4173db86aabSstevel 	pcic_reset_socket,
4183db86aabSstevel 	pcic_set_page,
4193db86aabSstevel 	pcic_set_window,
4203db86aabSstevel 	pcic_set_socket,
4213db86aabSstevel 	pcic_set_interrupt,
4223db86aabSstevel 	pcic_clear_interrupt,
4233db86aabSstevel 	NULL,
4243db86aabSstevel };
4253db86aabSstevel 
4263db86aabSstevel /*
4273db86aabSstevel  * chip type identification routines
4283db86aabSstevel  * this list of functions is searched until one of them succeeds
4293db86aabSstevel  * or all fail.  i82365SL is assumed if failed.
4303db86aabSstevel  */
4313db86aabSstevel static int pcic_ci_cirrus(pcicdev_t *);
4323db86aabSstevel static int pcic_ci_vadem(pcicdev_t *);
4333db86aabSstevel static int pcic_ci_ricoh(pcicdev_t *);
4343db86aabSstevel 
4353db86aabSstevel int (*pcic_ci_funcs[])(pcicdev_t *) = {
4363db86aabSstevel 	pcic_ci_cirrus,
4373db86aabSstevel 	pcic_ci_vadem,
4383db86aabSstevel 	pcic_ci_ricoh,
4393db86aabSstevel 	NULL
4403db86aabSstevel };
4413db86aabSstevel 
4423db86aabSstevel static struct modldrv modldrv = {
4433db86aabSstevel 	&mod_driverops,		/* Type of module. This one is a driver */
4443db86aabSstevel 	"PCIC PCMCIA adapter driver %I%",	/* Name of the module. */
4453db86aabSstevel 	&pcic_devops,		/* driver ops */
4463db86aabSstevel };
4473db86aabSstevel 
4483db86aabSstevel static struct modlinkage modlinkage = {
4493db86aabSstevel 	MODREV_1, (void *)&modldrv, NULL
4503db86aabSstevel };
4513db86aabSstevel 
4523db86aabSstevel int
4533db86aabSstevel _init()
4543db86aabSstevel {
4553db86aabSstevel 	int stat;
4563db86aabSstevel 
4573db86aabSstevel 	/* Allocate soft state */
4583db86aabSstevel 	if ((stat = ddi_soft_state_init(&pcic_soft_state_p,
4593db86aabSstevel 	    SOFTC_SIZE, 2)) != DDI_SUCCESS)
4603db86aabSstevel 		return (stat);
4613db86aabSstevel 
4623db86aabSstevel 	if ((stat = mod_install(&modlinkage)) != 0)
4633db86aabSstevel 		ddi_soft_state_fini(&pcic_soft_state_p);
4643db86aabSstevel 
4653db86aabSstevel 	return (stat);
4663db86aabSstevel }
4673db86aabSstevel 
4683db86aabSstevel int
4693db86aabSstevel _fini()
4703db86aabSstevel {
4713db86aabSstevel 	int stat = 0;
4723db86aabSstevel 
4733db86aabSstevel 	if ((stat = mod_remove(&modlinkage)) != 0)
4743db86aabSstevel 		return (stat);
4753db86aabSstevel 
4763db86aabSstevel 	if (pcic_deb_threadid) {
4773db86aabSstevel 		mutex_enter(&pcic_deb_mtx);
4783db86aabSstevel 		pcic_deb_threadid = 0;
4793db86aabSstevel 		while (!pcic_deb_threadid)
4803db86aabSstevel 			cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
4813db86aabSstevel 		pcic_deb_threadid = 0;
4823db86aabSstevel 		mutex_exit(&pcic_deb_mtx);
4833db86aabSstevel 
4843db86aabSstevel 		mutex_destroy(&pcic_deb_mtx);
4853db86aabSstevel 		cv_destroy(&pcic_deb_cv);
4863db86aabSstevel 	}
4873db86aabSstevel 
4883db86aabSstevel 	ddi_soft_state_fini(&pcic_soft_state_p);
4893db86aabSstevel 
4903db86aabSstevel 	return (stat);
4913db86aabSstevel }
4923db86aabSstevel 
4933db86aabSstevel int
4943db86aabSstevel _info(struct modinfo *modinfop)
4953db86aabSstevel {
4963db86aabSstevel 	return (mod_info(&modlinkage, modinfop));
4973db86aabSstevel }
4983db86aabSstevel 
4993db86aabSstevel /*
5003db86aabSstevel  * pcic_getinfo()
5013db86aabSstevel  *	provide instance/device information about driver
5023db86aabSstevel  */
5033db86aabSstevel /*ARGSUSED*/
5043db86aabSstevel static int
5053db86aabSstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
5063db86aabSstevel {
5073db86aabSstevel 	anp_t *anp;
5083db86aabSstevel 	int error = DDI_SUCCESS;
5093db86aabSstevel 	minor_t minor;
5103db86aabSstevel 
5113db86aabSstevel 	switch (cmd) {
5123db86aabSstevel 	    case DDI_INFO_DEVT2DEVINFO:
5133db86aabSstevel 		minor = getminor((dev_t)arg);
5143db86aabSstevel 		if (minor == SYSHW_MINOR)
5153db86aabSstevel 			minor = 0;
5163db86aabSstevel 		else
5173db86aabSstevel 			minor &= 0x7f;
5183db86aabSstevel 		if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor)))
5193db86aabSstevel 			*result = NULL;
5203db86aabSstevel 		else
5213db86aabSstevel 			*result = anp->an_dip;
5223db86aabSstevel 		break;
5233db86aabSstevel 	    case DDI_INFO_DEVT2INSTANCE:
5243db86aabSstevel 		minor = getminor((dev_t)arg);
5253db86aabSstevel 		if (minor == SYSHW_MINOR)
5263db86aabSstevel 			minor = 0;
5273db86aabSstevel 		else
5283db86aabSstevel 			minor &= 0x7f;
5293db86aabSstevel 		*result = (void *)((long)minor);
5303db86aabSstevel 		break;
5313db86aabSstevel 	    default:
5323db86aabSstevel 		error = DDI_FAILURE;
5333db86aabSstevel 		break;
5343db86aabSstevel 	}
5353db86aabSstevel 	return (error);
5363db86aabSstevel }
5373db86aabSstevel 
5383db86aabSstevel static int
5393db86aabSstevel pcic_probe(dev_info_t *dip)
5403db86aabSstevel {
5413db86aabSstevel 	int value;
5423db86aabSstevel 	ddi_device_acc_attr_t attr;
5433db86aabSstevel 	ddi_acc_handle_t handle;
5443db86aabSstevel 	uchar_t *index, *data;
5453db86aabSstevel 
5463db86aabSstevel 	if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
5473db86aabSstevel 	    return (DDI_PROBE_DONTCARE);
5483db86aabSstevel 
5493db86aabSstevel 	/*
5503db86aabSstevel 	 * find a PCIC device (any vendor)
5513db86aabSstevel 	 * while there can be up to 4 such devices in
5523db86aabSstevel 	 * a system, we currently only look for 1
5533db86aabSstevel 	 * per probe.  There will be up to 2 chips per
5543db86aabSstevel 	 * instance since they share I/O space
5553db86aabSstevel 	 */
5563db86aabSstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5573db86aabSstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
5583db86aabSstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5593db86aabSstevel 
5603db86aabSstevel 	if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
5613db86aabSstevel 				(caddr_t *)&index,
5623db86aabSstevel 				PCIC_ISA_CONTROL_REG_OFFSET,
5633db86aabSstevel 				PCIC_ISA_CONTROL_REG_LENGTH,
5643db86aabSstevel 				&attr, &handle) != DDI_SUCCESS)
5653db86aabSstevel 	    return (DDI_PROBE_FAILURE);
5663db86aabSstevel 
5673db86aabSstevel 	data = index + 1;
5683db86aabSstevel 
5693db86aabSstevel #if defined(PCIC_DEBUG)
5703db86aabSstevel 	if (pcic_debug)
5713db86aabSstevel 		cmn_err(CE_CONT, "pcic_probe: entered\n");
5723db86aabSstevel 	if (pcic_debug)
5733db86aabSstevel 		cmn_err(CE_CONT, "\tindex=%p\n", (void *)index);
5743db86aabSstevel #endif
5753db86aabSstevel 	ddi_put8(handle, index, PCIC_CHIP_REVISION);
5763db86aabSstevel 	ddi_put8(handle, data, 0);
5773db86aabSstevel 	value = ddi_get8(handle, data);
5783db86aabSstevel #if defined(PCIC_DEBUG)
5793db86aabSstevel 	if (pcic_debug)
5803db86aabSstevel 		cmn_err(CE_CONT, "\tchip revision register = %x\n", value);
5813db86aabSstevel #endif
5823db86aabSstevel 	if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW &&
5833db86aabSstevel 	    (value & 0x30) == 0) {
5843db86aabSstevel 		/*
5853db86aabSstevel 		 * we probably have a PCIC chip in the system
5863db86aabSstevel 		 * do a little more checking.  If we find one,
5873db86aabSstevel 		 * reset everything in case of softboot
5883db86aabSstevel 		 */
5893db86aabSstevel 		ddi_put8(handle, index, PCIC_MAPPING_ENABLE);
5903db86aabSstevel 		ddi_put8(handle, data, 0);
5913db86aabSstevel 		value = ddi_get8(handle, data);
5923db86aabSstevel #if defined(PCIC_DEBUG)
5933db86aabSstevel 		if (pcic_debug)
5943db86aabSstevel 			cmn_err(CE_CONT, "\tzero test = %x\n", value);
5953db86aabSstevel #endif
5963db86aabSstevel 		/* should read back as zero */
5973db86aabSstevel 		if (value == 0) {
5983db86aabSstevel 			/*
5993db86aabSstevel 			 * we do have one and it is off the bus
6003db86aabSstevel 			 */
6013db86aabSstevel #if defined(PCIC_DEBUG)
6023db86aabSstevel 			if (pcic_debug)
6033db86aabSstevel 				cmn_err(CE_CONT, "pcic_probe: success\n");
6043db86aabSstevel #endif
6053db86aabSstevel 			ddi_regs_map_free(&handle);
6063db86aabSstevel 			return (DDI_PROBE_SUCCESS);
6073db86aabSstevel 		}
6083db86aabSstevel 	}
6093db86aabSstevel #if defined(PCIC_DEBUG)
6103db86aabSstevel 	if (pcic_debug)
6113db86aabSstevel 		cmn_err(CE_CONT, "pcic_probe: failed\n");
6123db86aabSstevel #endif
6133db86aabSstevel 	ddi_regs_map_free(&handle);
6143db86aabSstevel 	return (DDI_PROBE_FAILURE);
6153db86aabSstevel }
6163db86aabSstevel 
6173db86aabSstevel /*
6183db86aabSstevel  * These are just defaults they can also be changed via a property in the
6193db86aabSstevel  * conf file.
6203db86aabSstevel  */
6213db86aabSstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM;
6223db86aabSstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM;
6233db86aabSstevel static int pcic_do_pcmcia_sr = 0;
6243db86aabSstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL;
6253db86aabSstevel 
6263db86aabSstevel /*
6273db86aabSstevel  * enable insertion/removal interrupt for 32bit cards
6283db86aabSstevel  */
6293db86aabSstevel static int
6303db86aabSstevel cardbus_enable_cd_intr(dev_info_t *dip)
6313db86aabSstevel {
6323db86aabSstevel 	ddi_acc_handle_t	iohandle;
6333db86aabSstevel 	caddr_t	ioaddr;
6343db86aabSstevel 	ddi_device_acc_attr_t attr;
6353db86aabSstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6363db86aabSstevel 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
6373db86aabSstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6383db86aabSstevel 	(void) ddi_regs_map_setup(dip, 1,
6393db86aabSstevel 				(caddr_t *)&ioaddr,
6403db86aabSstevel 				0,
6413db86aabSstevel 				4096,
6423db86aabSstevel 				&attr, &iohandle);
6433db86aabSstevel 
6443db86aabSstevel 	/* CSC Interrupt: Card detect interrupt on */
6453db86aabSstevel 	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK),
6463db86aabSstevel 		ddi_get32(iohandle,
6473db86aabSstevel 		(uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK);
6483db86aabSstevel 
6493db86aabSstevel 	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT),
6503db86aabSstevel 		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
6513db86aabSstevel 
6523db86aabSstevel 	ddi_regs_map_free(&iohandle);
6533db86aabSstevel 	return (1);
6543db86aabSstevel }
6553db86aabSstevel 
6563db86aabSstevel /*
6573db86aabSstevel  * pcic_attach()
6583db86aabSstevel  *	attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver
6593db86aabSstevel  *	to the system.  This is a child of "sysbus" since that is where
6603db86aabSstevel  *	the hardware lives, but it provides services to the "pcmcia"
6613db86aabSstevel  *	nexus driver.  It gives a pointer back via its private data
6623db86aabSstevel  *	structure which contains both the dip and socket services entry
6633db86aabSstevel  *	points
6643db86aabSstevel  */
6653db86aabSstevel static int
6663db86aabSstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6673db86aabSstevel {
6683db86aabSstevel 	anp_t *pcic_nexus;
6693db86aabSstevel 	pcicdev_t *pcic;
6703db86aabSstevel 	int irqlevel, value;
6713db86aabSstevel 	int pci_cfrn, pci_ctrn;
6723db86aabSstevel 	int i, j, smi, actual;
6733db86aabSstevel 	char *typename;
6743db86aabSstevel 	char bus_type[16] = "(unknown)";
6753db86aabSstevel 	int len = sizeof (bus_type);
6763db86aabSstevel 	ddi_device_acc_attr_t attr;
6773db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
6783db86aabSstevel 	uint_t	pri;
6793db86aabSstevel 	syshw_t *shwp;
6803db86aabSstevel 
6813db86aabSstevel #if defined(PCIC_DEBUG)
6823db86aabSstevel 	if (pcic_debug) {
6833db86aabSstevel 		cmn_err(CE_CONT, "pcic_attach: entered\n");
6843db86aabSstevel 	}
6853db86aabSstevel #endif
6863db86aabSstevel 	switch (cmd) {
6873db86aabSstevel 	case DDI_ATTACH:
6883db86aabSstevel 		break;
6893db86aabSstevel 	case DDI_RESUME:
6903db86aabSstevel 		pcic = anp->an_private;
6913db86aabSstevel 		/*
6923db86aabSstevel 		 * for now, this is a simulated resume.
6933db86aabSstevel 		 * a real one may need different things.
6943db86aabSstevel 		 */
6953db86aabSstevel 		if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) {
6963db86aabSstevel 			mutex_enter(&pcic->pc_lock);
6973db86aabSstevel 			/* should probe for new sockets showing up */
6983db86aabSstevel 			pcic_setup_adapter(pcic);
6993db86aabSstevel 			syshw_resume(pcic);
7003db86aabSstevel 			pcic->pc_flags &= ~PCF_SUSPENDED;
7013db86aabSstevel 			mutex_exit(&pcic->pc_lock);
7023db86aabSstevel 			(void) pcmcia_begin_resume(dip);
7033db86aabSstevel 			/*
7043db86aabSstevel 			 * this will do the CARD_INSERTION
7053db86aabSstevel 			 * due to needing time for threads to
7063db86aabSstevel 			 * run, it must be delayed for a short amount
7073db86aabSstevel 			 * of time.  pcmcia_wait_insert checks for all
7083db86aabSstevel 			 * children to be removed and then triggers insert.
7093db86aabSstevel 			 */
7103db86aabSstevel 			/*
7113db86aabSstevel 			 * The reason for having a single timeout here
7123db86aabSstevel 			 * rather than seperate timeout()s for each instance
7133db86aabSstevel 			 * is due to the limited number (2) of callout threads
7143db86aabSstevel 			 * available in Solaris 2.6. A single 1250A ends up
7153db86aabSstevel 			 * as two instances of the interface with one slot each.
7163db86aabSstevel 			 * The pcic_delayed_resume() function ends by calling
7173db86aabSstevel 			 * pcmcia_wait_insert() which at one point does a
7183db86aabSstevel 			 * delay(). delay() is implemented with a timeout()
7193db86aabSstevel 			 * call so you end up with both the callout()
7203db86aabSstevel 			 * threads waiting to be woken up by another callout().
7213db86aabSstevel 			 * This situation locks up the machine hence the
7223db86aabSstevel 			 * convolution here to only use one timeout.
7233db86aabSstevel 			 */
7243db86aabSstevel 			if (!pcic_delayed_resume_toid)
7253db86aabSstevel 				pcic_delayed_resume_toid =
7263db86aabSstevel 				    timeout(pcic_delayed_resume, (caddr_t)0,
7273db86aabSstevel 				    drv_usectohz(pcic_wait_insert_time));
7283db86aabSstevel 
7293db86aabSstevel 			/*
7303db86aabSstevel 			 * for complete implementation need END_RESUME (later)
7313db86aabSstevel 			 */
7323db86aabSstevel 			return (DDI_SUCCESS);
7333db86aabSstevel 
7343db86aabSstevel 		}
7353db86aabSstevel 		return (DDI_SUCCESS);
7363db86aabSstevel 	default:
7373db86aabSstevel 		return (DDI_FAILURE);
7383db86aabSstevel 	}
7393db86aabSstevel 
7403db86aabSstevel 	/*
7413db86aabSstevel 	 * Allocate soft state associated with this instance.
7423db86aabSstevel 	 */
7433db86aabSstevel 	if (ddi_soft_state_zalloc(pcic_soft_state_p,
7443db86aabSstevel 				ddi_get_instance(dip)) != DDI_SUCCESS) {
7453db86aabSstevel 		cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n",
7463db86aabSstevel 			ddi_get_instance(dip));
7473db86aabSstevel 		return (DDI_FAILURE);
7483db86aabSstevel 	}
7493db86aabSstevel 
7503db86aabSstevel 	pcic_nexus = ddi_get_soft_state(pcic_soft_state_p,
7513db86aabSstevel 	    ddi_get_instance(dip));
7523db86aabSstevel 
7533db86aabSstevel 	pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP);
7543db86aabSstevel 
7553db86aabSstevel 	pcic->dip = dip;
7563db86aabSstevel 	pcic_nexus->an_dip = dip;
7573db86aabSstevel 	pcic_nexus->an_if = &pcic_if_ops;
7583db86aabSstevel 	pcic_nexus->an_private = pcic;
7593db86aabSstevel 	pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]);
7603db86aabSstevel 	pcic->pc_power = pcic_power;
7613db86aabSstevel 
7623db86aabSstevel 	pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7633db86aabSstevel 	    "pci-control-reg-number", pci_control_reg_num);
7643db86aabSstevel 	pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7653db86aabSstevel 	    "pci-config-reg-number", pci_config_reg_num);
7663db86aabSstevel 
7673db86aabSstevel 	ddi_set_driver_private(dip, pcic_nexus);
7683db86aabSstevel 
7693db86aabSstevel 	/*
7703db86aabSstevel 	 * pcic->pc_irq is really the IPL level we want to run at
7713db86aabSstevel 	 * set the default values here and override from intr spec
7723db86aabSstevel 	 */
7733db86aabSstevel 	pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7743db86aabSstevel 					"interrupt-priorities", -1);
7753db86aabSstevel 
7763db86aabSstevel 	if (pcic->pc_irq == -1) {
7773db86aabSstevel 		int			actual;
7783db86aabSstevel 		uint_t			pri;
7793db86aabSstevel 		ddi_intr_handle_t	hdl;
7803db86aabSstevel 
7813db86aabSstevel 		/* see if intrspec tells us different */
7823db86aabSstevel 		if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
7833db86aabSstevel 		    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) {
7843db86aabSstevel 			if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS)
7853db86aabSstevel 				pcic->pc_irq = pri;
7863db86aabSstevel 			else
7873db86aabSstevel 				pcic->pc_irq = LOCK_LEVEL + 1;
7883db86aabSstevel 			(void) ddi_intr_free(hdl);
7893db86aabSstevel 		}
7903db86aabSstevel 	}
7913db86aabSstevel 	pcic_nexus->an_ipl = pcic->pc_irq;
7923db86aabSstevel 
7933db86aabSstevel 	/*
7943db86aabSstevel 	 * Check our parent bus type. We do different things based on which
7953db86aabSstevel 	 * bus we're on.
7963db86aabSstevel 	 */
7973db86aabSstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7983db86aabSstevel 				PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
7993db86aabSstevel 				"device_type", (caddr_t)&bus_type[0], &len) !=
8003db86aabSstevel 							DDI_PROP_SUCCESS) {
8013db86aabSstevel 		if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
8023db86aabSstevel 				PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
8033db86aabSstevel 				"bus-type", (caddr_t)&bus_type[0], &len) !=
8043db86aabSstevel 							DDI_PROP_SUCCESS) {
8053db86aabSstevel 
8063db86aabSstevel 			cmn_err(CE_CONT,
8073db86aabSstevel 				"pcic%d: can't find parent bus type\n",
8083db86aabSstevel 				ddi_get_instance(dip));
8093db86aabSstevel 
8103db86aabSstevel 			kmem_free(pcic, sizeof (pcicdev_t));
8113db86aabSstevel 			return (DDI_FAILURE);
8123db86aabSstevel 		}
8133db86aabSstevel 	} /* ddi_prop_op("device_type") */
8143db86aabSstevel 
8153db86aabSstevel 	if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0) {
8163db86aabSstevel 		pcic->pc_flags = PCF_PCIBUS;
8173db86aabSstevel 	} else {
8183db86aabSstevel #if defined(__sparc)
8193db86aabSstevel 		cmn_err(CE_CONT, "pcic%d: unsupported parent bus type: [%s]\n",
8203db86aabSstevel 			ddi_get_instance(dip), bus_type);
8213db86aabSstevel 
8223db86aabSstevel 		kmem_free(pcic, sizeof (pcicdev_t));
8233db86aabSstevel 		return (DDI_FAILURE);
8243db86aabSstevel #else
8253db86aabSstevel 		pcic->pc_flags = 0;
8263db86aabSstevel #endif
8273db86aabSstevel 	}
8283db86aabSstevel 
8293db86aabSstevel 	if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
8303db86aabSstevel 						DDI_PROP_CANSLEEP,
8313db86aabSstevel 						"clock-frequency", 0)) == 0) {
8323db86aabSstevel 		if (pcic->pc_flags & PCF_PCIBUS)
8333db86aabSstevel 			pcic->bus_speed = PCIC_PCI_DEF_SYSCLK;
8343db86aabSstevel 		else
8353db86aabSstevel 			pcic->bus_speed = PCIC_ISA_DEF_SYSCLK;
8363db86aabSstevel 	} else {
8373db86aabSstevel 		/*
8383db86aabSstevel 		 * OBP can declare the speed in Hz...
8393db86aabSstevel 		 */
8403db86aabSstevel 		if (pcic->bus_speed > 1000000)
8413db86aabSstevel 			pcic->bus_speed /= 1000000;
8423db86aabSstevel 	} /* ddi_prop_op("clock-frequency") */
8433db86aabSstevel 
8443db86aabSstevel 	pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */
8453db86aabSstevel 
8463db86aabSstevel #ifdef	PCIC_DEBUG
8473db86aabSstevel 	if (pcic_debug) {
8483db86aabSstevel 		cmn_err(CE_CONT,
8493db86aabSstevel 			"pcic%d: parent bus type = [%s], speed = %d MHz\n",
8503db86aabSstevel 			ddi_get_instance(dip),
8513db86aabSstevel 			bus_type, pcic->bus_speed);
8523db86aabSstevel 	}
8533db86aabSstevel #endif
8543db86aabSstevel 
8553db86aabSstevel 	/*
8563db86aabSstevel 	 * The reg properties on a PCI node are different than those
8573db86aabSstevel 	 *	on a non-PCI node. Handle that difference here.
8583db86aabSstevel 	 *	If it turns out to be a CardBus chip, we have even more
8593db86aabSstevel 	 *	differences.
8603db86aabSstevel 	 */
8613db86aabSstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
8623db86aabSstevel 		int class_code;
8633db86aabSstevel #if defined(__i386) || defined(__amd64)
8643db86aabSstevel 		pcic->pc_base = 0x1000000;
8653db86aabSstevel 		pcic->pc_bound = (uint32_t)~0;
8663db86aabSstevel 		pcic->pc_iobase = 0x1000;
8673db86aabSstevel 		pcic->pc_iobound = 0xefff;
8683db86aabSstevel #elif defined(__sparc)
8693db86aabSstevel 		pcic->pc_base = 0x0;
8703db86aabSstevel 		pcic->pc_bound = (uint32_t)~0;
8713db86aabSstevel 		pcic->pc_iobase = 0x00000;
8723db86aabSstevel 		pcic->pc_iobound = 0xffff;
8733db86aabSstevel #endif
8743db86aabSstevel 
8753db86aabSstevel 		/* usually need to get at config space so map first */
8763db86aabSstevel 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8773db86aabSstevel 		attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8783db86aabSstevel 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8793db86aabSstevel 
8803db86aabSstevel 		if (ddi_regs_map_setup(dip, pci_cfrn,
8813db86aabSstevel 					(caddr_t *)&pcic->cfgaddr,
8823db86aabSstevel 					PCIC_PCI_CONFIG_REG_OFFSET,
8833db86aabSstevel 					PCIC_PCI_CONFIG_REG_LENGTH,
8843db86aabSstevel 					&attr,
8853db86aabSstevel 					&pcic->cfg_handle) !=
8863db86aabSstevel 		    DDI_SUCCESS) {
8873db86aabSstevel 			cmn_err(CE_CONT,
8883db86aabSstevel 				"pcic%d: unable to map config space"
8893db86aabSstevel 				"regs\n",
8903db86aabSstevel 				ddi_get_instance(dip));
8913db86aabSstevel 
8923db86aabSstevel 			kmem_free(pcic, sizeof (pcicdev_t));
8933db86aabSstevel 			return (DDI_FAILURE);
8943db86aabSstevel 		} /* ddi_regs_map_setup */
8953db86aabSstevel 
8963db86aabSstevel 		class_code = ddi_getprop(DDI_DEV_T_ANY, dip,
8973db86aabSstevel 					DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
8983db86aabSstevel 					"class-code", -1);
8993db86aabSstevel #ifdef  PCIC_DEBUG
9003db86aabSstevel 		if (pcic_debug) {
9013db86aabSstevel 			cmn_err(CE_CONT, "pcic_attach class_code=%x\n",
9023db86aabSstevel 			    class_code);
9033db86aabSstevel 		}
9043db86aabSstevel #endif
9053db86aabSstevel 
9063db86aabSstevel 		switch (class_code) {
9073db86aabSstevel 		case PCIC_PCI_CARDBUS:
9083db86aabSstevel 			pcic->pc_flags |= PCF_CARDBUS;
9093db86aabSstevel 			pcic->pc_io_type = PCIC_IO_TYPE_YENTA;
9103db86aabSstevel 			/*
9113db86aabSstevel 			 * Get access to the adapter registers on the
9123db86aabSstevel 			 * PCI bus.  A 4K memory page
9133db86aabSstevel 			 */
9143db86aabSstevel #if defined(PCIC_DEBUG)
9153db86aabSstevel 			pcic_err(dip, 8, "Is Cardbus device\n");
9163db86aabSstevel 			if (pcic_debug) {
9173db86aabSstevel 				int nr;
9183db86aabSstevel 				long rs;
9193db86aabSstevel 				(void) ddi_dev_nregs(dip, &nr);
9203db86aabSstevel 				pcic_err(dip, 9, "\tdev, cfgaddr 0x%p,"
9213db86aabSstevel 				    "cfghndl 0x%p nregs %d",
9223db86aabSstevel 				    (void *)pcic->cfgaddr,
9233db86aabSstevel 				    (void *)pcic->cfg_handle, nr);
9243db86aabSstevel 
9253db86aabSstevel 				(void) ddi_dev_regsize(dip,
9263db86aabSstevel 				    PCIC_PCI_CONTROL_REG_NUM, &rs);
9273db86aabSstevel 
9283db86aabSstevel 				pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n",
9293db86aabSstevel 				    PCIC_PCI_CONTROL_REG_NUM, (int)rs);
9303db86aabSstevel 			}
9313db86aabSstevel #endif
9323db86aabSstevel 			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9333db86aabSstevel 			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9343db86aabSstevel 			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9353db86aabSstevel 
9363db86aabSstevel 			if (ddi_regs_map_setup(dip, pci_ctrn,
9373db86aabSstevel 						(caddr_t *)&pcic->ioaddr,
9383db86aabSstevel 						PCIC_PCI_CONTROL_REG_OFFSET,
9393db86aabSstevel 						PCIC_CB_CONTROL_REG_LENGTH,
9403db86aabSstevel 						&attr, &pcic->handle) !=
9413db86aabSstevel 			    DDI_SUCCESS) {
9423db86aabSstevel 				cmn_err(CE_CONT,
9433db86aabSstevel 					"pcic%d: unable to map PCI regs\n",
9443db86aabSstevel 					ddi_get_instance(dip));
9453db86aabSstevel 				ddi_regs_map_free(&pcic->cfg_handle);
9463db86aabSstevel 				kmem_free(pcic, sizeof (pcicdev_t));
9473db86aabSstevel 				return (DDI_FAILURE);
9483db86aabSstevel 			} /* ddi_regs_map_setup */
9493db86aabSstevel 
9503db86aabSstevel 			/*
9513db86aabSstevel 			 * Find out the chip type - If we're on a PCI bus,
9523db86aabSstevel 			 *	the adapter has that information in the PCI
9533db86aabSstevel 			 *	config space.
9543db86aabSstevel 			 * Note that we call pcic_find_pci_type here since
9553db86aabSstevel 			 *	it needs a valid mapped pcic->handle to
9563db86aabSstevel 			 *	access some of the adapter registers in
9573db86aabSstevel 			 *	some cases.
9583db86aabSstevel 			 */
9593db86aabSstevel 			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9603db86aabSstevel 				ddi_regs_map_free(&pcic->handle);
9613db86aabSstevel 				ddi_regs_map_free(&pcic->cfg_handle);
9623db86aabSstevel 				kmem_free(pcic, sizeof (pcicdev_t));
9633db86aabSstevel 				cmn_err(CE_WARN, "pcic: %s: unsupported "
9643db86aabSstevel 								"bridge\n",
9653db86aabSstevel 							ddi_get_name_addr(dip));
9663db86aabSstevel 				return (DDI_FAILURE);
9673db86aabSstevel 			}
9683db86aabSstevel 			break;
9693db86aabSstevel 
9703db86aabSstevel 		default:
9713db86aabSstevel 		case PCIC_PCI_PCMCIA:
9723db86aabSstevel 			/*
9733db86aabSstevel 			 * Get access to the adapter IO registers on the
9743db86aabSstevel 			 * PCI bus config space.
9753db86aabSstevel 			 */
9763db86aabSstevel 			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9773db86aabSstevel 			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9783db86aabSstevel 			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9793db86aabSstevel 
9803db86aabSstevel 			/*
9813db86aabSstevel 			 * We need a default mapping to the adapter's IO
9823db86aabSstevel 			 *	control register space. For most adapters
9833db86aabSstevel 			 *	that are of class PCIC_PCI_PCMCIA (or of
9843db86aabSstevel 			 *	a default class) the control registers
9853db86aabSstevel 			 *	will be using the 82365-type control/data
9863db86aabSstevel 			 *	format.
9873db86aabSstevel 			 */
9883db86aabSstevel 			if (ddi_regs_map_setup(dip, pci_ctrn,
9893db86aabSstevel 						(caddr_t *)&pcic->ioaddr,
9903db86aabSstevel 						PCIC_PCI_CONTROL_REG_OFFSET,
9913db86aabSstevel 						PCIC_PCI_CONTROL_REG_LENGTH,
9923db86aabSstevel 						&attr,
9933db86aabSstevel 						&pcic->handle) != DDI_SUCCESS) {
9943db86aabSstevel 				cmn_err(CE_CONT,
9953db86aabSstevel 					"pcic%d: unable to map PCI regs\n",
9963db86aabSstevel 					ddi_get_instance(dip));
9973db86aabSstevel 				ddi_regs_map_free(&pcic->cfg_handle);
9983db86aabSstevel 				kmem_free(pcic, sizeof (pcicdev_t));
9993db86aabSstevel 				return (DDI_FAILURE);
10003db86aabSstevel 			} /* ddi_regs_map_setup */
10013db86aabSstevel 
10023db86aabSstevel 			/*
10033db86aabSstevel 			 * Find out the chip type - If we're on a PCI bus,
10043db86aabSstevel 			 *	the adapter has that information in the PCI
10053db86aabSstevel 			 *	config space.
10063db86aabSstevel 			 * Note that we call pcic_find_pci_type here since
10073db86aabSstevel 			 *	it needs a valid mapped pcic->handle to
10083db86aabSstevel 			 *	access some of the adapter registers in
10093db86aabSstevel 			 *	some cases.
10103db86aabSstevel 			 */
10113db86aabSstevel 			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
10123db86aabSstevel 				ddi_regs_map_free(&pcic->handle);
10133db86aabSstevel 				ddi_regs_map_free(&pcic->cfg_handle);
10143db86aabSstevel 				kmem_free(pcic, sizeof (pcicdev_t));
10153db86aabSstevel 				cmn_err(CE_WARN, "pcic: %s: unsupported "
10163db86aabSstevel 								"bridge\n",
10173db86aabSstevel 							ddi_get_name_addr(dip));
10183db86aabSstevel 				return (DDI_FAILURE);
10193db86aabSstevel 			}
10203db86aabSstevel 
10213db86aabSstevel 			/*
10223db86aabSstevel 			 * Some PCI-PCMCIA(R2) adapters are Yenta-compliant
10233db86aabSstevel 			 *	for extended registers even though they are
10243db86aabSstevel 			 *	not CardBus adapters. For those adapters,
10253db86aabSstevel 			 *	re-map pcic->handle to be large enough to
10263db86aabSstevel 			 *	encompass the Yenta registers.
10273db86aabSstevel 			 */
10283db86aabSstevel 			switch (pcic->pc_type) {
10293db86aabSstevel 			    case PCIC_TI_PCI1031:
10303db86aabSstevel 				ddi_regs_map_free(&pcic->handle);
10313db86aabSstevel 
10323db86aabSstevel 				if (ddi_regs_map_setup(dip,
10333db86aabSstevel 						PCIC_PCI_CONTROL_REG_NUM,
10343db86aabSstevel 						(caddr_t *)&pcic->ioaddr,
10353db86aabSstevel 						PCIC_PCI_CONTROL_REG_OFFSET,
10363db86aabSstevel 						PCIC_CB_CONTROL_REG_LENGTH,
10373db86aabSstevel 						&attr,
10383db86aabSstevel 						&pcic->handle) != DDI_SUCCESS) {
10393db86aabSstevel 					cmn_err(CE_CONT,
10403db86aabSstevel 						"pcic%d: unable to map "
10413db86aabSstevel 								"PCI regs\n",
10423db86aabSstevel 						ddi_get_instance(dip));
10433db86aabSstevel 					ddi_regs_map_free(&pcic->cfg_handle);
10443db86aabSstevel 					kmem_free(pcic, sizeof (pcicdev_t));
10453db86aabSstevel 					return (DDI_FAILURE);
10463db86aabSstevel 				} /* ddi_regs_map_setup */
10473db86aabSstevel 				break;
10483db86aabSstevel 			    default:
10493db86aabSstevel 				break;
10503db86aabSstevel 			} /* switch (pcic->pc_type) */
10513db86aabSstevel 			break;
10523db86aabSstevel 		} /* switch (class_code) */
10533db86aabSstevel 	} else {
10543db86aabSstevel 		/*
10553db86aabSstevel 		 * We're not on a PCI bus, so assume an ISA bus type
10563db86aabSstevel 		 * register property. Get access to the adapter IO
10573db86aabSstevel 		 * registers on a non-PCI bus.
10583db86aabSstevel 		 */
10593db86aabSstevel 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
10603db86aabSstevel 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
10613db86aabSstevel 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
10623db86aabSstevel 		pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM;
10633db86aabSstevel 		pcic->io_reg_num = PCIC_ISA_IO_REG_NUM;
10643db86aabSstevel 
10653db86aabSstevel 		if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
10663db86aabSstevel 					(caddr_t *)&pcic->ioaddr,
10673db86aabSstevel 					PCIC_ISA_CONTROL_REG_OFFSET,
10683db86aabSstevel 					PCIC_ISA_CONTROL_REG_LENGTH,
10693db86aabSstevel 					&attr,
10703db86aabSstevel 					&pcic->handle) != DDI_SUCCESS) {
10713db86aabSstevel 			cmn_err(CE_CONT,
10723db86aabSstevel 				"pcic%d: unable to map ISA registers\n",
10733db86aabSstevel 				ddi_get_instance(dip));
10743db86aabSstevel 
10753db86aabSstevel 			kmem_free(pcic, sizeof (pcicdev_t));
10763db86aabSstevel 			return (DDI_FAILURE);
10773db86aabSstevel 		} /* ddi_regs_map_setup */
10783db86aabSstevel 
10793db86aabSstevel 		/* ISA bus is limited to 24-bits, but not first 640K */
10803db86aabSstevel 		pcic->pc_base = 0xd0000;
10813db86aabSstevel 		pcic->pc_bound = (uint32_t)~0;
10823db86aabSstevel 		pcic->pc_iobase = 0x1000;
10833db86aabSstevel 		pcic->pc_iobound = 0xefff;
10843db86aabSstevel 	} /* !PCF_PCIBUS */
10853db86aabSstevel 
10863db86aabSstevel #ifdef  PCIC_DEBUG
10873db86aabSstevel 	if (pcic_debug) {
10883db86aabSstevel 		cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n",
10893db86aabSstevel 		    pcic->pc_flags, pcic->pc_type);
10903db86aabSstevel 	}
10913db86aabSstevel #endif
10923db86aabSstevel 
10933db86aabSstevel 	/*
10943db86aabSstevel 	 * Setup various adapter registers for the PCI case. For the
10953db86aabSstevel 	 * non-PCI case, find out the chip type.
10963db86aabSstevel 	 */
10973db86aabSstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
10983db86aabSstevel 		int iline;
10993db86aabSstevel #if defined(__sparc)
11003db86aabSstevel 		iline = 0;
11013db86aabSstevel #else
11023db86aabSstevel 		iline = cardbus_validate_iline(dip, pcic->cfg_handle);
11033db86aabSstevel #endif
11043db86aabSstevel 
11053db86aabSstevel 		/* set flags and socket counts based on chip type */
11063db86aabSstevel 		switch (pcic->pc_type) {
11073db86aabSstevel 			uint32_t cfg;
11083db86aabSstevel 		case PCIC_INTEL_i82092:
11093db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
11103db86aabSstevel 					pcic->cfgaddr + PCIC_82092_PCICON);
11113db86aabSstevel 			/* we can only support 4 Socket version */
11123db86aabSstevel 			if (cfg & PCIC_82092_4_SOCKETS) {
11133db86aabSstevel 			    pcic->pc_numsockets = 4;
11143db86aabSstevel 			    pcic->pc_type = PCIC_INTEL_i82092;
11153db86aabSstevel 			    if (iline != 0xFF)
11163db86aabSstevel 				    pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11173db86aabSstevel 			    else
11183db86aabSstevel 				    pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11193db86aabSstevel 			} else {
11203db86aabSstevel 			    cmn_err(CE_CONT,
11213db86aabSstevel 				    "pcic%d: Intel 82092 adapter "
11223db86aabSstevel 				    "in unsupported configuration: 0x%x",
11233db86aabSstevel 				    ddi_get_instance(pcic->dip), cfg);
11243db86aabSstevel 			    pcic->pc_numsockets = 0;
11253db86aabSstevel 			} /* PCIC_82092_4_SOCKETS */
11263db86aabSstevel 			break;
11273db86aabSstevel 		case PCIC_CL_PD6730:
11283db86aabSstevel 		case PCIC_CL_PD6729:
11293db86aabSstevel 			pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11303db86aabSstevel 			cfg = ddi_getprop(DDI_DEV_T_ANY, dip,
11313db86aabSstevel 						DDI_PROP_CANSLEEP,
11323db86aabSstevel 						"interrupts", 0);
11333db86aabSstevel 			/* if not interrupt pin then must use ISA style IRQs */
11343db86aabSstevel 			if (cfg == 0 || iline == 0xFF)
11353db86aabSstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11363db86aabSstevel 			else {
11373db86aabSstevel 				/*
11383db86aabSstevel 				 * we have the option to use PCI interrupts.
11393db86aabSstevel 				 * this might not be optimal but in some cases
11403db86aabSstevel 				 * is the only thing possible (sparc case).
11413db86aabSstevel 				 * we now deterine what is possible.
11423db86aabSstevel 				 */
11433db86aabSstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11443db86aabSstevel 			}
11453db86aabSstevel 			pcic->pc_numsockets = 2;
11463db86aabSstevel 			pcic->pc_flags |= PCF_IO_REMAP;
11473db86aabSstevel 			break;
11483db86aabSstevel 		case PCIC_TI_PCI1031:
11493db86aabSstevel 			/* this chip doesn't do CardBus but looks like one */
11503db86aabSstevel 			pcic->pc_flags &= ~PCF_CARDBUS;
11513db86aabSstevel 			/* FALLTHROUGH */
11523db86aabSstevel 		default:
11533db86aabSstevel 			pcic->pc_flags |= PCF_IO_REMAP;
11543db86aabSstevel 			/* FALLTHROUGH */
11553db86aabSstevel 			/* indicate feature even if not supported */
11563db86aabSstevel 			pcic->pc_flags |= PCF_DMA | PCF_ZV;
11573db86aabSstevel 			/* Not sure if these apply to all these chips */
11583db86aabSstevel 			pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP);
11593db86aabSstevel 			pcic->pc_flags |= pcic_use_cbpwrctl;
11603db86aabSstevel 
11613db86aabSstevel 			pcic->pc_numsockets = 1; /* one per function */
11623db86aabSstevel 			if (iline != 0xFF) {
11633db86aabSstevel 				uint8_t cfg;
11643db86aabSstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11653db86aabSstevel 
11663db86aabSstevel 				cfg = ddi_get8(pcic->cfg_handle,
11673db86aabSstevel 					(pcic->cfgaddr + PCIC_BRIDGE_CTL_REG));
11683db86aabSstevel 				cfg &= (~PCIC_FUN_INT_MOD_ISA);
11693db86aabSstevel 				ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
11703db86aabSstevel 					PCIC_BRIDGE_CTL_REG), cfg);
11713db86aabSstevel 			}
11723db86aabSstevel 			else
11733db86aabSstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11743db86aabSstevel 			pcic->pc_io_type = PCIC_IOTYPE_YENTA;
11753db86aabSstevel 			break;
11763db86aabSstevel 		}
11773db86aabSstevel 	} else {
11783db86aabSstevel 		/*
11793db86aabSstevel 		 * We're not on a PCI bus so do some more
11803db86aabSstevel 		 *	checking for adapter type here.
11813db86aabSstevel 		 * For the non-PCI bus case:
11823db86aabSstevel 		 * It could be any one of a number of different chips
11833db86aabSstevel 		 * If we can't determine anything else, it is assumed
11843db86aabSstevel 		 * to be an Intel 82365SL.  The Cirrus Logic PD6710
11853db86aabSstevel 		 * has an extension register that provides unique
11863db86aabSstevel 		 * identification. Toshiba chip isn't detailed as yet.
11873db86aabSstevel 		 */
11883db86aabSstevel 
11893db86aabSstevel 		/* Init the CL id mode */
11903db86aabSstevel 		pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
11913db86aabSstevel 		value = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
11923db86aabSstevel 
11933db86aabSstevel 		/* default to Intel i82365SL and then refine */
11943db86aabSstevel 		pcic->pc_type = PCIC_I82365SL;
11953db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_I82365SL;
11963db86aabSstevel 		for (value = 0; pcic_ci_funcs[value] != NULL; value++) {
11973db86aabSstevel 			/* go until one succeeds or none left */
11983db86aabSstevel 			if (pcic_ci_funcs[value](pcic))
11993db86aabSstevel 				break;
12003db86aabSstevel 		}
12013db86aabSstevel 
12023db86aabSstevel 		/* any chip specific flags get set here */
12033db86aabSstevel 		switch (pcic->pc_type) {
12043db86aabSstevel 		case PCIC_CL_PD6722:
12053db86aabSstevel 			pcic->pc_flags |= PCF_DMA;
12063db86aabSstevel 		}
12073db86aabSstevel 
12083db86aabSstevel 		for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
12093db86aabSstevel 			/*
12103db86aabSstevel 			 * look for total number of sockets.
12113db86aabSstevel 			 * basically check each possible socket for
12123db86aabSstevel 			 * presence like in probe
12133db86aabSstevel 			 */
12143db86aabSstevel 
12153db86aabSstevel 			/* turn all windows off */
12163db86aabSstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
12173db86aabSstevel 			value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE);
12183db86aabSstevel 
12193db86aabSstevel 			/*
12203db86aabSstevel 			 * if a zero is read back, then this socket
12213db86aabSstevel 			 * might be present. It would be except for
12223db86aabSstevel 			 * some systems that map the secondary PCIC
12233db86aabSstevel 			 * chip space back to the first.
12243db86aabSstevel 			 */
12253db86aabSstevel 			if (value != 0) {
12263db86aabSstevel 				/* definitely not so skip */
12273db86aabSstevel 				/* note: this is for Compaq support */
12283db86aabSstevel 				continue;
12293db86aabSstevel 			}
12303db86aabSstevel 
12313db86aabSstevel 			/* further tests */
12323db86aabSstevel 			value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) &
12333db86aabSstevel 				PCIC_REV_MASK;
12343db86aabSstevel 			if (!(value >= PCIC_REV_LEVEL_LOW &&
12353db86aabSstevel 				value <= PCIC_REV_LEVEL_HI))
12363db86aabSstevel 				break;
12373db86aabSstevel 
12383db86aabSstevel 			pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa);
12393db86aabSstevel 			pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55);
12403db86aabSstevel 			value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW);
12413db86aabSstevel 
12423db86aabSstevel 			j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW);
12433db86aabSstevel 			if (value != 0xaa || j != 0x55)
12443db86aabSstevel 				break;
12453db86aabSstevel 
12463db86aabSstevel 			/*
12473db86aabSstevel 			 * at this point we know if we have hardware
12483db86aabSstevel 			 * of some type and not just the bus holding
12493db86aabSstevel 			 * a pattern for us. We still have to determine
12503db86aabSstevel 			 * the case where more than 2 sockets are
12513db86aabSstevel 			 * really the same due to peculiar mappings of
12523db86aabSstevel 			 * hardware.
12533db86aabSstevel 			 */
12543db86aabSstevel 			j = pcic->pc_numsockets++;
12553db86aabSstevel 			pcic->pc_sockets[j].pcs_flags = 0;
12563db86aabSstevel 			pcic->pc_sockets[j].pcs_io = pcic->ioaddr;
12573db86aabSstevel 			pcic->pc_sockets[j].pcs_socket = i;
12583db86aabSstevel 
12593db86aabSstevel 			/* put PC Card into RESET, just in case */
12603db86aabSstevel 			value = pcic_getb(pcic, i, PCIC_INTERRUPT);
12613db86aabSstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT,
12623db86aabSstevel 					value & ~PCIC_RESET);
12633db86aabSstevel 		}
12643db86aabSstevel 
12653db86aabSstevel #if defined(PCIC_DEBUG)
12663db86aabSstevel 		if (pcic_debug)
12673db86aabSstevel 			cmn_err(CE_CONT, "num sockets = %d\n",
12683db86aabSstevel 				pcic->pc_numsockets);
12693db86aabSstevel #endif
12703db86aabSstevel 		if (pcic->pc_numsockets == 0) {
12713db86aabSstevel 			ddi_regs_map_free(&pcic->handle);
12723db86aabSstevel 			kmem_free(pcic, sizeof (pcicdev_t));
12733db86aabSstevel 			return (DDI_FAILURE);
12743db86aabSstevel 		}
12753db86aabSstevel 
12763db86aabSstevel 		/*
12773db86aabSstevel 		 * need to think this through again in light of
12783db86aabSstevel 		 * Compaq not following the model that all the
12793db86aabSstevel 		 * chip vendors recommend.  IBM 755 seems to be
12803db86aabSstevel 		 * afflicted as well.  Basically, if the vendor
12813db86aabSstevel 		 * wired things wrong, socket 0 responds for socket 2
12823db86aabSstevel 		 * accesses, etc.
12833db86aabSstevel 		 */
12843db86aabSstevel 		if (pcic->pc_numsockets > 2) {
12853db86aabSstevel 			int count = pcic->pc_numsockets / 4;
12863db86aabSstevel 			for (i = 0; i < count; i++) {
12873db86aabSstevel 				/* put pattern into socket 0 */
12883db86aabSstevel 				pcic_putb(pcic, i,
12893db86aabSstevel 						PCIC_SYSMEM_0_STARTLOW, 0x11);
12903db86aabSstevel 
12913db86aabSstevel 				/* put pattern into socket 2 */
12923db86aabSstevel 				pcic_putb(pcic, i + 2,
12933db86aabSstevel 						PCIC_SYSMEM_0_STARTLOW, 0x33);
12943db86aabSstevel 
12953db86aabSstevel 				/* read back socket 0 */
12963db86aabSstevel 				value = pcic_getb(pcic, i,
12973db86aabSstevel 						    PCIC_SYSMEM_0_STARTLOW);
12983db86aabSstevel 
12993db86aabSstevel 				/* read back chip 1 socket 0 */
13003db86aabSstevel 				j = pcic_getb(pcic, i + 2,
13013db86aabSstevel 						PCIC_SYSMEM_0_STARTLOW);
13023db86aabSstevel 				if (j == value) {
13033db86aabSstevel 					pcic->pc_numsockets -= 2;
13043db86aabSstevel 				}
13053db86aabSstevel 			}
13063db86aabSstevel 		}
13073db86aabSstevel 
13083db86aabSstevel 		smi = 0xff;	/* no more override */
13093db86aabSstevel 
13103db86aabSstevel 		if (ddi_getprop(DDI_DEV_T_NONE, dip,
13113db86aabSstevel 				DDI_PROP_DONTPASS, "need-mult-irq",
13123db86aabSstevel 				0xffff) != 0xffff)
13133db86aabSstevel 			pcic->pc_flags |= PCF_MULT_IRQ;
13143db86aabSstevel 
13153db86aabSstevel 	} /* !PCF_PCIBUS */
13163db86aabSstevel 
13173db86aabSstevel 	/*
13183db86aabSstevel 	 * some platforms/busses need to have resources setup
13193db86aabSstevel 	 * this is temporary until a real resource allocator is
13203db86aabSstevel 	 * implemented.
13213db86aabSstevel 	 */
13223db86aabSstevel 
13233db86aabSstevel 	pcic_init_assigned(dip);
13243db86aabSstevel 
13253db86aabSstevel 	typename = pcic->pc_chipname;
13263db86aabSstevel 
13273db86aabSstevel #ifdef	PCIC_DEBUG
13283db86aabSstevel 	if (pcic_debug) {
13293db86aabSstevel 		int nregs, nintrs;
13303db86aabSstevel 
13313db86aabSstevel 		if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
13323db86aabSstevel 			nregs = 0;
13333db86aabSstevel 
13343db86aabSstevel 		if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS)
13353db86aabSstevel 			nintrs = 0;
13363db86aabSstevel 
13373db86aabSstevel 		cmn_err(CE_CONT,
13383db86aabSstevel 			"pcic%d: %d register sets, %d interrupts\n",
13393db86aabSstevel 			ddi_get_instance(dip), nregs, nintrs);
13403db86aabSstevel 
13413db86aabSstevel 		nintrs = 0;
13423db86aabSstevel 		while (nregs--) {
13433db86aabSstevel 			off_t size;
13443db86aabSstevel 
13453db86aabSstevel 			if (ddi_dev_regsize(dip, nintrs, &size) ==
13463db86aabSstevel 			    DDI_SUCCESS) {
13473db86aabSstevel 				cmn_err(CE_CONT,
13483db86aabSstevel 					"\tregnum %d size %ld (0x%lx)"
13493db86aabSstevel 					"bytes",
13503db86aabSstevel 					nintrs, size, size);
13513db86aabSstevel 				if (nintrs ==
13523db86aabSstevel 				    (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ?
13533db86aabSstevel 				    PCIC_ISA_CONTROL_REG_NUM :
13543db86aabSstevel 				    PCIC_PCI_CONTROL_REG_NUM))
13553db86aabSstevel 					cmn_err(CE_CONT,
13563db86aabSstevel 						" mapped at: 0x%p\n",
13573db86aabSstevel 						(void *)pcic->ioaddr);
13583db86aabSstevel 				else
13593db86aabSstevel 					cmn_err(CE_CONT, "\n");
13603db86aabSstevel 			} else {
13613db86aabSstevel 				cmn_err(CE_CONT,
13623db86aabSstevel 					"\tddi_dev_regsize(rnumber"
13633db86aabSstevel 					"= %d) returns DDI_FAILURE\n",
13643db86aabSstevel 					nintrs);
13653db86aabSstevel 			}
13663db86aabSstevel 			nintrs++;
13673db86aabSstevel 		} /* while */
13683db86aabSstevel 	} /* if (pcic_debug) */
13693db86aabSstevel #endif
13703db86aabSstevel 
13713db86aabSstevel 	cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL);
13723db86aabSstevel 
13733db86aabSstevel 	if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
13743db86aabSstevel 						"disable-audio", 0))
13753db86aabSstevel 		pcic->pc_flags |= PCF_AUDIO;
13763db86aabSstevel 
13773db86aabSstevel 	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
13783db86aabSstevel 	    "disable-cardbus", 0))
13793db86aabSstevel 		pcic->pc_flags &= ~PCF_CARDBUS;
13803db86aabSstevel 
13813db86aabSstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL,
13823db86aabSstevel 	    typename);
13833db86aabSstevel 
13843db86aabSstevel 	/*
13853db86aabSstevel 	 * Init all socket SMI levels to 0 (no SMI)
13863db86aabSstevel 	 */
13873db86aabSstevel 	for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
13883db86aabSstevel 	    pcic->pc_sockets[i].pcs_smi = 0;
13893db86aabSstevel 	    pcic->pc_sockets[i].pcs_debounce_id = 0;
13903db86aabSstevel 	    pcic->pc_sockets[i].pcs_pcic = pcic;
13913db86aabSstevel 	}
13923db86aabSstevel 	pcic->pc_lastreg = -1; /* just to make sure we are in sync */
13933db86aabSstevel 
13943db86aabSstevel 	/*
13953db86aabSstevel 	 * Setup the IRQ handler(s)
13963db86aabSstevel 	 */
13973db86aabSstevel 	switch (pcic->pc_intr_mode) {
13983db86aabSstevel 		int xx;
13993db86aabSstevel 	case PCIC_INTR_MODE_ISA:
14003db86aabSstevel 	/*
14013db86aabSstevel 	 * On a non-PCI bus, we just use whatever SMI IRQ level was
14023db86aabSstevel 	 *	specified above, and the IO IRQ levels are allocated
14033db86aabSstevel 	 *	dynamically.
14043db86aabSstevel 	 */
14053db86aabSstevel 		for (xx = 15, smi = 0; xx >= 0; xx--) {
14063db86aabSstevel 			if (PCIC_IRQ(xx) &
14073db86aabSstevel 			    PCIC_AVAIL_IRQS) {
14083db86aabSstevel 				smi = pcmcia_get_intr(dip, xx);
14093db86aabSstevel 				if (smi >= 0)
14103db86aabSstevel 					break;
14113db86aabSstevel 			}
14123db86aabSstevel 		}
14133db86aabSstevel #if defined(PCIC_DEBUG)
14143db86aabSstevel 		if (pcic_debug)
14153db86aabSstevel 			cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi);
14163db86aabSstevel #endif
14173db86aabSstevel 		/* init to same so share is easy */
14183db86aabSstevel 		for (i = 0; i < pcic->pc_numsockets; i++)
14193db86aabSstevel 			pcic->pc_sockets[i].pcs_smi = smi;
14203db86aabSstevel 		/* any special handling of IRQ levels */
14213db86aabSstevel 		if (pcic->pc_flags & PCF_MULT_IRQ) {
14223db86aabSstevel 			for (i = 2; i < pcic->pc_numsockets; i++) {
14233db86aabSstevel 				if ((i & 1) == 0) {
14243db86aabSstevel 					int xx;
14253db86aabSstevel 					for (xx = 15, smi = 0; xx >= 0; xx--) {
14263db86aabSstevel 						if (PCIC_IRQ(xx) &
14273db86aabSstevel 						    PCIC_AVAIL_IRQS) {
14283db86aabSstevel 							smi =
14293db86aabSstevel 							    pcmcia_get_intr(dip,
14303db86aabSstevel 									    xx);
14313db86aabSstevel 							if (smi >= 0)
14323db86aabSstevel 								break;
14333db86aabSstevel 						}
14343db86aabSstevel 					}
14353db86aabSstevel 				}
14363db86aabSstevel 				if (smi >= 0)
14373db86aabSstevel 					pcic->pc_sockets[i].pcs_smi = smi;
14383db86aabSstevel 			}
14393db86aabSstevel 		}
14403db86aabSstevel 		pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets *
14413db86aabSstevel 		    sizeof (ddi_intr_handle_t), KM_SLEEP);
14423db86aabSstevel 		for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) {
14433db86aabSstevel 			struct intrspec *ispecp;
14443db86aabSstevel 			struct ddi_parent_private_data *pdp;
14453db86aabSstevel 
14463db86aabSstevel 			if (irqlevel == pcic->pc_sockets[i].pcs_smi)
14473db86aabSstevel 				continue;
14483db86aabSstevel 			else {
14493db86aabSstevel 				irqlevel = pcic->pc_sockets[i].pcs_smi;
14503db86aabSstevel 			}
14513db86aabSstevel 			/*
14523db86aabSstevel 			 * now convert the allocated IRQ into an intrspec
14533db86aabSstevel 			 * and ask our parent to add it.  Don't use
14543db86aabSstevel 			 * the ddi_add_intr since we don't have a
14553db86aabSstevel 			 * default intrspec in all cases.
14563db86aabSstevel 			 *
14573db86aabSstevel 			 * note: this sort of violates DDI but we don't
14583db86aabSstevel 			 *	 get hardware intrspecs for many of the devices.
14593db86aabSstevel 			 *	 at the same time, we know how to allocate them
14603db86aabSstevel 			 *	 so we do the right thing.
14613db86aabSstevel 			 */
14623db86aabSstevel 			if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i],
14633db86aabSstevel 			    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
14643db86aabSstevel 			    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
14653db86aabSstevel 				cmn_err(CE_WARN, "%s: ddi_intr_alloc failed",
14663db86aabSstevel 				    ddi_get_name(dip));
14673db86aabSstevel 				goto isa_exit1;
14683db86aabSstevel 			}
14693db86aabSstevel 
14703db86aabSstevel 			/*
14713db86aabSstevel 			 * See earlier note:
14723db86aabSstevel 			 * Since some devices don't have 'intrspec'
14733db86aabSstevel 			 * we make one up in rootnex.
14743db86aabSstevel 			 *
14753db86aabSstevel 			 * However, it is not properly initialized as
14763db86aabSstevel 			 * the data it needs is present in this driver
14773db86aabSstevel 			 * and there is no interface to pass that up.
14783db86aabSstevel 			 * Specially 'irqlevel' is very important and
14793db86aabSstevel 			 * it is part of pcic struct.
14803db86aabSstevel 			 *
14813db86aabSstevel 			 * Set 'intrspec' up here; otherwise adding the
14823db86aabSstevel 			 * interrupt will fail.
14833db86aabSstevel 			 */
14843db86aabSstevel 			pdp = ddi_get_parent_data(dip);
14853db86aabSstevel 			ispecp = (struct intrspec *)&pdp->par_intr[0];
14863db86aabSstevel 			ispecp->intrspec_vec = irqlevel;
14873db86aabSstevel 			ispecp->intrspec_pri = pcic->pc_irq;
14883db86aabSstevel 
14893db86aabSstevel 			/* Stay compatible w/ PCMCIA */
14903db86aabSstevel 			pcic->pc_pri = (ddi_iblock_cookie_t)
14913db86aabSstevel 			    (uintptr_t)pcic->pc_irq;
14923db86aabSstevel 			pcic->pc_dcookie.idev_priority =
14933db86aabSstevel 			    (uintptr_t)pcic->pc_pri;
14943db86aabSstevel 			pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel;
14953db86aabSstevel 
14963db86aabSstevel 			(void) ddi_intr_set_pri(pcic->pc_intr_htblp[i],
14973db86aabSstevel 			    pcic->pc_irq);
14983db86aabSstevel 
14993db86aabSstevel 			if (i == 0) {
15003db86aabSstevel 				mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER,
15013db86aabSstevel 				    DDI_INTR_PRI(pcic->pc_irq));
15023db86aabSstevel 				mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER,
15033db86aabSstevel 				    NULL);
15043db86aabSstevel 			}
15053db86aabSstevel 
15063db86aabSstevel 			if (ddi_intr_add_handler(pcic->pc_intr_htblp[i],
15073db86aabSstevel 			    pcic_intr, (caddr_t)pcic, NULL)) {
15083db86aabSstevel 				cmn_err(CE_WARN,
15093db86aabSstevel 				    "%s: ddi_intr_add_handler failed",
15103db86aabSstevel 				    ddi_get_name(dip));
15113db86aabSstevel 				goto isa_exit2;
15123db86aabSstevel 			}
15133db86aabSstevel 
15143db86aabSstevel 			if (ddi_intr_enable(pcic->pc_intr_htblp[i])) {
15153db86aabSstevel 				cmn_err(CE_WARN, "%s: ddi_intr_enable failed",
15163db86aabSstevel 				    ddi_get_name(dip));
15173db86aabSstevel 				for (j = i; j < 0; j--)
15183db86aabSstevel 					(void) ddi_intr_remove_handler(
15193db86aabSstevel 					    pcic->pc_intr_htblp[j]);
15203db86aabSstevel 				goto isa_exit2;
15213db86aabSstevel 			}
15223db86aabSstevel 		}
15233db86aabSstevel 		break;
15243db86aabSstevel 	case PCIC_INTR_MODE_PCI_1:
15253db86aabSstevel 	case PCIC_INTR_MODE_PCI:
15263db86aabSstevel 		/*
15273db86aabSstevel 		 * If we're on a PCI bus, we route all interrupts, both SMI
15283db86aabSstevel 		 * and IO interrupts, through a single interrupt line.
15293db86aabSstevel 		 * Assign the SMI IRQ level to the IO IRQ level here.
15303db86aabSstevel 		 */
15313db86aabSstevel 		pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t),
15323db86aabSstevel 		    KM_SLEEP);
15333db86aabSstevel 		if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp,
15343db86aabSstevel 		    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
15353db86aabSstevel 		    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS)
15363db86aabSstevel 			goto pci_exit1;
15373db86aabSstevel 
15383db86aabSstevel 		if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0],
15393db86aabSstevel 		    &pri) != DDI_SUCCESS) {
15403db86aabSstevel 			(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
15413db86aabSstevel 			goto pci_exit1;
15423db86aabSstevel 		}
15433db86aabSstevel 
15443db86aabSstevel 		pcic->pc_pri = (void *)(uintptr_t)pri;
15453db86aabSstevel 		mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri);
15463db86aabSstevel 		mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL);
15473db86aabSstevel 
15483db86aabSstevel 		if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0],
15493db86aabSstevel 		    pcic_intr, (caddr_t)pcic, NULL))
15503db86aabSstevel 			goto pci_exit2;
15513db86aabSstevel 
15523db86aabSstevel 		if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) {
15533db86aabSstevel 			(void) ddi_intr_remove_handler(
15543db86aabSstevel 			    pcic->pc_pci_intr_hdlp[0]);
15553db86aabSstevel 			goto pci_exit2;
15563db86aabSstevel 		}
15573db86aabSstevel 
15583db86aabSstevel 		/* Stay compatible w/ PCMCIA */
15593db86aabSstevel 		pcic->pc_dcookie.idev_priority = (ushort_t)pri;
15603db86aabSstevel 
15613db86aabSstevel 		/* init to same (PCI) so share is easy */
15623db86aabSstevel 		for (i = 0; i < pcic->pc_numsockets; i++)
15633db86aabSstevel 			pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */
15643db86aabSstevel 		break;
15653db86aabSstevel 	}
15663db86aabSstevel 
15673db86aabSstevel 	/*
15683db86aabSstevel 	 * Setup the adapter hardware to some reasonable defaults.
15693db86aabSstevel 	 */
15703db86aabSstevel 	mutex_enter(&pcic->pc_lock);
15713db86aabSstevel 	/* mark the driver state as attached */
15723db86aabSstevel 	pcic->pc_flags |= PCF_ATTACHED;
15733db86aabSstevel 	pcic_setup_adapter(pcic);
15743db86aabSstevel 
15753db86aabSstevel 	for (j = 0; j < pcic->pc_numsockets; j++)
15763db86aabSstevel 		if (ddi_intr_add_softint(dip,
15773db86aabSstevel 		    &pcic->pc_sockets[j].pcs_cd_softint_hdl,
15783db86aabSstevel 		    PCIC_SOFTINT_PRI_VAL, pcic_cd_softint,
15793db86aabSstevel 		    (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS)
15803db86aabSstevel 			goto pci_exit2;
15813db86aabSstevel 
15823db86aabSstevel #if defined(PCIC_DEBUG)
15833db86aabSstevel 	if (pcic_debug)
15843db86aabSstevel 		cmn_err(CE_CONT, "type = %s sockets = %d\n", typename,
15853db86aabSstevel 						pcic->pc_numsockets);
15863db86aabSstevel #endif
15873db86aabSstevel 
15883db86aabSstevel 	pcic_nexus->an_iblock = &pcic->pc_pri;
15893db86aabSstevel 	pcic_nexus->an_idev = &pcic->pc_dcookie;
15903db86aabSstevel 
15913db86aabSstevel 	mutex_exit(&pcic->pc_lock);
15923db86aabSstevel 
15933db86aabSstevel #ifdef CARDBUS
15943db86aabSstevel 	(void) cardbus_enable_cd_intr(dip);
15953db86aabSstevel 	if (pcic_debug) {
15963db86aabSstevel 
15973db86aabSstevel 		cardbus_dump_pci_config(dip);
15983db86aabSstevel 		cardbus_dump_socket(dip);
15993db86aabSstevel 	}
16003db86aabSstevel 
16013db86aabSstevel 	/*
16023db86aabSstevel 	 * Give the Cardbus misc module a chance to do it's per-adapter
16033db86aabSstevel 	 * instance setup. Note that there is no corresponding detach()
16043db86aabSstevel 	 * call.
16053db86aabSstevel 	 */
16063db86aabSstevel 	if (pcic->pc_flags & PCF_CARDBUS)
16073db86aabSstevel 		if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) {
16083db86aabSstevel 			cmn_err(CE_CONT,
16093db86aabSstevel 			    "pcic_attach: cardbus_attach failed\n");
16103db86aabSstevel 			goto pci_exit2;
16113db86aabSstevel 		}
16123db86aabSstevel #endif
16133db86aabSstevel 
16143db86aabSstevel 	/*
16153db86aabSstevel 	 * Give the PCMCIA misc module a chance to do it's per-adapter
16163db86aabSstevel 	 *	instance setup.
16173db86aabSstevel 	 */
16183db86aabSstevel 	if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS)
16193db86aabSstevel 		goto pci_exit2;
16203db86aabSstevel 
16213db86aabSstevel 	syshw_attach(pcic);
16223db86aabSstevel 	if (pcic_maxinst == -1) {
16233db86aabSstevel 		/* This assumes that all instances run at the same IPL. */
16243db86aabSstevel 		mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL);
16253db86aabSstevel 		cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL);
16263db86aabSstevel 		pcic_deb_threadid = thread_create((caddr_t)NULL, 0,
16273db86aabSstevel 		    pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN,
16283db86aabSstevel 		    v.v_maxsyspri - 2);
16293db86aabSstevel 	}
16303db86aabSstevel 	pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip));
16313db86aabSstevel 	/*
16323db86aabSstevel 	 * Setup a debounce timeout to do an initial card detect
16333db86aabSstevel 	 * and enable interrupts.
16343db86aabSstevel 	 */
16353db86aabSstevel 	for (j = 0; j < pcic->pc_numsockets; j++) {
16363db86aabSstevel 		shwp = kmem_alloc(sizeof (syshw_t), KM_SLEEP);
16373db86aabSstevel 		if (shwp) {
16383db86aabSstevel 			bcopy(&pcic_syshw, shwp, sizeof (pcic_syshw));
16393db86aabSstevel 			pcic_syshw.id_string[15]++;
16403db86aabSstevel 			pcic->pc_sockets[j].pcs_syshwsig =
16413db86aabSstevel 			    syshw_add2map(shwp, pcic_syshw_cardstate,
16423db86aabSstevel 				&pcic->pc_sockets[j]);
16433db86aabSstevel 		}
16443db86aabSstevel 		pcic->pc_sockets[j].pcs_debounce_id =
16453db86aabSstevel 		    pcic_add_debqueue(&pcic->pc_sockets[j],
16463db86aabSstevel 			drv_usectohz(pcic_debounce_time));
16473db86aabSstevel 	}
16483db86aabSstevel 
16493db86aabSstevel 	return (i);
16503db86aabSstevel 
16513db86aabSstevel isa_exit2:
16523db86aabSstevel 	mutex_destroy(&pcic->intr_lock);
16533db86aabSstevel 	mutex_destroy(&pcic->pc_lock);
16543db86aabSstevel 	for (j = i; j < 0; j--)
16553db86aabSstevel 		(void) ddi_intr_free(pcic->pc_intr_htblp[j]);
16563db86aabSstevel isa_exit1:
16573db86aabSstevel 	(void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi);
16583db86aabSstevel 	ddi_regs_map_free(&pcic->handle);
16593db86aabSstevel 	if (pcic->pc_flags & PCF_PCIBUS)
16603db86aabSstevel 		ddi_regs_map_free(&pcic->cfg_handle);
16613db86aabSstevel 	kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets *
16623db86aabSstevel 	    sizeof (ddi_intr_handle_t));
16633db86aabSstevel 	kmem_free(pcic, sizeof (pcicdev_t));
16643db86aabSstevel 		return (DDI_FAILURE);
16653db86aabSstevel 
16663db86aabSstevel pci_exit2:
16673db86aabSstevel 	mutex_destroy(&pcic->intr_lock);
16683db86aabSstevel 	mutex_destroy(&pcic->pc_lock);
16693db86aabSstevel 	(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16703db86aabSstevel pci_exit1:
16713db86aabSstevel 	ddi_regs_map_free(&pcic->handle);
16723db86aabSstevel 	if (pcic->pc_flags & PCF_PCIBUS)
16733db86aabSstevel 		ddi_regs_map_free(&pcic->cfg_handle);
16743db86aabSstevel 	kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16753db86aabSstevel 	kmem_free(pcic, sizeof (pcicdev_t));
16763db86aabSstevel 	return (DDI_FAILURE);
16773db86aabSstevel }
16783db86aabSstevel 
16793db86aabSstevel /*
16803db86aabSstevel  * pcic_detach()
16813db86aabSstevel  *	request to detach from the system
16823db86aabSstevel  */
16833db86aabSstevel static int
16843db86aabSstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
16853db86aabSstevel {
16863db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
16873db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
16883db86aabSstevel 	int i;
16893db86aabSstevel 
16903db86aabSstevel 	switch (cmd) {
16913db86aabSstevel 	case DDI_DETACH:
16923db86aabSstevel 		/* don't detach if the nexus still talks to us */
16933db86aabSstevel 		if (pcic->pc_callback != NULL)
16943db86aabSstevel 			return (DDI_FAILURE);
16953db86aabSstevel 		syshw_detach(pcic);
16963db86aabSstevel 
16973db86aabSstevel 		/* kill off the pm simulation */
16983db86aabSstevel 		if (pcic->pc_pmtimer)
16993db86aabSstevel 			(void) untimeout(pcic->pc_pmtimer);
17003db86aabSstevel 
17013db86aabSstevel 		/* turn everything off for all sockets and chips */
17023db86aabSstevel 		for (i = 0; i < pcic->pc_numsockets; i++) {
17033db86aabSstevel 			if (pcic->pc_sockets[i].pcs_debounce_id)
17043db86aabSstevel 				pcic_rm_debqueue(
17053db86aabSstevel 				    pcic->pc_sockets[i].pcs_debounce_id);
17063db86aabSstevel 			pcic->pc_sockets[i].pcs_debounce_id = 0;
17073db86aabSstevel 
17083db86aabSstevel 			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
17093db86aabSstevel 			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
17103db86aabSstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17113db86aabSstevel 			/* disable interrupts and put card into RESET */
17123db86aabSstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
17133db86aabSstevel 		}
17143db86aabSstevel 		(void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]);
17153db86aabSstevel 		(void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]);
17163db86aabSstevel 		(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
17173db86aabSstevel 		kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
17183db86aabSstevel 		pcic->pc_flags = 0;
17193db86aabSstevel 		mutex_destroy(&pcic->pc_lock);
17203db86aabSstevel 		mutex_destroy(&pcic->intr_lock);
17213db86aabSstevel 		cv_destroy(&pcic->pm_cv);
17223db86aabSstevel 		if (pcic->pc_flags & PCF_PCIBUS)
17233db86aabSstevel 		    ddi_regs_map_free(&pcic->cfg_handle);
17243db86aabSstevel 		if (pcic->handle)
17253db86aabSstevel 		    ddi_regs_map_free(&pcic->handle);
17263db86aabSstevel 		kmem_free(pcic, sizeof (pcicdev_t));
17273db86aabSstevel 		ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip));
17283db86aabSstevel 		return (DDI_SUCCESS);
17293db86aabSstevel 
17303db86aabSstevel 	case DDI_SUSPEND:
17313db86aabSstevel 	case DDI_PM_SUSPEND:
17323db86aabSstevel 		/*
17333db86aabSstevel 		 * we got a suspend event (either real or imagined)
17343db86aabSstevel 		 * so notify the nexus proper that all existing cards
17353db86aabSstevel 		 * should go away.
17363db86aabSstevel 		 */
17373db86aabSstevel 		mutex_enter(&pcic->pc_lock);
17383db86aabSstevel #ifdef CARDBUS
17393db86aabSstevel 		if (pcic->pc_flags & PCF_CARDBUS)
17403db86aabSstevel 			for (i = 0; i < pcic->pc_numsockets; i++)
17413db86aabSstevel 				if ((pcic->pc_sockets[i].pcs_flags &
17423db86aabSstevel 				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) ==
17433db86aabSstevel 				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS))
17443db86aabSstevel 					if (!cardbus_can_suspend(dip)) {
17453db86aabSstevel 						mutex_exit(&pcic->pc_lock);
17463db86aabSstevel 						cmn_err(CE_WARN,
17473db86aabSstevel 						    "Please unconfigure all "
17483db86aabSstevel 						    "CardBus devices before "
17493db86aabSstevel 						    "attempting to suspend\n");
17503db86aabSstevel 						return (DDI_FAILURE);
17513db86aabSstevel 					}
17523db86aabSstevel #endif
17533db86aabSstevel 		/* turn everything off for all sockets and chips */
17543db86aabSstevel 		for (i = 0; i < pcic->pc_numsockets; i++) {
17553db86aabSstevel 			if (pcic->pc_sockets[i].pcs_debounce_id)
17563db86aabSstevel 				pcic_rm_debqueue(
17573db86aabSstevel 				    pcic->pc_sockets[i].pcs_debounce_id);
17583db86aabSstevel 			pcic->pc_sockets[i].pcs_debounce_id = 0;
17593db86aabSstevel 
17603db86aabSstevel 			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
17613db86aabSstevel 			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
17623db86aabSstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17633db86aabSstevel 			/* disable interrupts and put card into RESET */
17643db86aabSstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
17653db86aabSstevel 			pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
17663db86aabSstevel 			if (pcic->pc_flags & PCF_CBPWRCTL)
17673db86aabSstevel 				pcic_putcb(pcic, CB_CONTROL, 0);
17683db86aabSstevel 
17693db86aabSstevel 			if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) {
17703db86aabSstevel 				pcic->pc_sockets[i].pcs_flags = PCS_STARTING;
17713db86aabSstevel 				/*
17723db86aabSstevel 				 * Because we are half way through a save
17733db86aabSstevel 				 * all this does is schedule a removal event
17743db86aabSstevel 				 * to cs for when the system comes back.
17753db86aabSstevel 				 * This doesn't actually matter.
17763db86aabSstevel 				 */
17773db86aabSstevel 				if (!pcic_do_pcmcia_sr && pcic_do_removal &&
17783db86aabSstevel 				    pcic->pc_callback) {
17793db86aabSstevel 					PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
17803db86aabSstevel 					    PCE_CARD_REMOVAL,
17813db86aabSstevel 					    pcic->pc_sockets[i].pcs_socket);
17823db86aabSstevel 				}
17833db86aabSstevel 			}
17843db86aabSstevel 		}
17853db86aabSstevel 
17863db86aabSstevel 		pcic->pc_flags |= PCF_SUSPENDED;
17873db86aabSstevel 		mutex_exit(&pcic->pc_lock);
17883db86aabSstevel 		pcic_delayed_resume_toid = 0;
17893db86aabSstevel 
17903db86aabSstevel 		/*
17913db86aabSstevel 		 * when true power management exists, save the adapter
17923db86aabSstevel 		 * state here to enable a recovery.  For the emulation
17933db86aabSstevel 		 * condition, the state is gone
17943db86aabSstevel 		 */
17953db86aabSstevel 		return (DDI_SUCCESS);
17963db86aabSstevel 
17973db86aabSstevel 	default:
17983db86aabSstevel 		return (EINVAL);
17993db86aabSstevel 	}
18003db86aabSstevel }
18013db86aabSstevel 
18023db86aabSstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14));
18033db86aabSstevel static uint32_t pcic_tisysctl_offbits = 0;
18043db86aabSstevel static uint32_t pcic_default_latency = 0x40;
18053db86aabSstevel 
18063db86aabSstevel static void
18073db86aabSstevel pcic_setup_adapter(pcicdev_t *pcic)
18083db86aabSstevel {
18093db86aabSstevel 	int i;
18103db86aabSstevel 	int value, flags;
18113db86aabSstevel 
18123db86aabSstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
18133db86aabSstevel 		/*
18143db86aabSstevel 		 * all PCI-to-PCMCIA bus bridges need memory and I/O enabled
18153db86aabSstevel 		 */
18163db86aabSstevel 		flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM);
18173db86aabSstevel 		pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags);
18183db86aabSstevel 	}
18193db86aabSstevel 	/* enable each socket */
18203db86aabSstevel 	for (i = 0; i < pcic->pc_numsockets; i++) {
18213db86aabSstevel 		pcic->pc_sockets[i].pcs_flags = 0;
18223db86aabSstevel 		/* find out the socket capabilities (I/O vs memory) */
18233db86aabSstevel 		value = pcic_getb(pcic, i,
18243db86aabSstevel 					PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK;
18253db86aabSstevel 		if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH)
18263db86aabSstevel 			pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO;
18273db86aabSstevel 
18283db86aabSstevel 		/* disable all windows just in case */
18293db86aabSstevel 		pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
18303db86aabSstevel 
18313db86aabSstevel 		switch (pcic->pc_type) {
18323db86aabSstevel 			uint32_t cfg32;
18333db86aabSstevel 			uint16_t cfg16;
18343db86aabSstevel 			uint8_t cfg;
18353db86aabSstevel 
18363db86aabSstevel 		    /* enable extended registers for Vadem */
18373db86aabSstevel 		    case PCIC_VADEM_VG469:
18383db86aabSstevel 		    case PCIC_VADEM:
18393db86aabSstevel 
18403db86aabSstevel 			/* enable card status change interrupt for socket */
18413db86aabSstevel 			break;
18423db86aabSstevel 
18433db86aabSstevel 		    case PCIC_I82365SL:
18443db86aabSstevel 			break;
18453db86aabSstevel 
18463db86aabSstevel 		    case PCIC_CL_PD6710:
18473db86aabSstevel 			pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE);
18483db86aabSstevel 			break;
18493db86aabSstevel 
18503db86aabSstevel 			/*
18513db86aabSstevel 			 * On the CL_6730, we need to set up the interrupt
18523db86aabSstevel 			 * signalling mode (PCI mode) and set the SMI and
18533db86aabSstevel 			 * IRQ interrupt lines to PCI/level-mode.
18543db86aabSstevel 			 */
18553db86aabSstevel 		    case PCIC_CL_PD6730:
18563db86aabSstevel 			switch (pcic->pc_intr_mode) {
18573db86aabSstevel 			case PCIC_INTR_MODE_PCI_1:
18583db86aabSstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3,
18593db86aabSstevel 						((clext_reg_read(pcic, i,
18603db86aabSstevel 						PCIC_CLEXT_MISC_CTL_3) &
18613db86aabSstevel 						~PCIC_CLEXT_INT_PCI) |
18623db86aabSstevel 						PCIC_CLEXT_INT_PCI));
18633db86aabSstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18643db86aabSstevel 						(PCIC_CLEXT_IRQ_LVL_MODE |
18653db86aabSstevel 						PCIC_CLEXT_SMI_LVL_MODE));
18663db86aabSstevel 				cfg = PCIC_CL_LP_DYN_MODE;
18673db86aabSstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18683db86aabSstevel 				break;
18693db86aabSstevel 			case PCIC_INTR_MODE_ISA:
18703db86aabSstevel 				break;
18713db86aabSstevel 			}
18723db86aabSstevel 			break;
18733db86aabSstevel 			/*
18743db86aabSstevel 			 * On the CL_6729, we set the SMI and IRQ interrupt
18753db86aabSstevel 			 *	lines to PCI/level-mode. as well as program the
18763db86aabSstevel 			 *	correct clock speed divider bit.
18773db86aabSstevel 			 */
18783db86aabSstevel 		    case PCIC_CL_PD6729:
18793db86aabSstevel 			switch (pcic->pc_intr_mode) {
18803db86aabSstevel 			case PCIC_INTR_MODE_PCI_1:
18813db86aabSstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18823db86aabSstevel 						(PCIC_CLEXT_IRQ_LVL_MODE |
18833db86aabSstevel 						PCIC_CLEXT_SMI_LVL_MODE));
18843db86aabSstevel 
18853db86aabSstevel 				break;
18863db86aabSstevel 			case PCIC_INTR_MODE_ISA:
18873db86aabSstevel 				break;
18883db86aabSstevel 			}
18893db86aabSstevel 			if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) {
18903db86aabSstevel 				cfg = 0;
18913db86aabSstevel 				cfg |= PCIC_CL_TIMER_CLK_DIV;
18923db86aabSstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18933db86aabSstevel 			}
18943db86aabSstevel 			break;
18953db86aabSstevel 		    case PCIC_INTEL_i82092:
18963db86aabSstevel 			cfg = PCIC_82092_EN_TIMING;
18973db86aabSstevel 			if (pcic->bus_speed < PCIC_SYSCLK_33MHZ)
18983db86aabSstevel 			    cfg |= PCIC_82092_PCICLK_25MHZ;
18993db86aabSstevel 			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
19003db86aabSstevel 						PCIC_82092_PCICON, cfg);
19013db86aabSstevel 			break;
19023db86aabSstevel 		    case PCIC_TI_PCI1130:
19033db86aabSstevel 		    case PCIC_TI_PCI1131:
19043db86aabSstevel 		    case PCIC_TI_PCI1250:
19053db86aabSstevel 		    case PCIC_TI_PCI1031:
19063db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
19073db86aabSstevel 					pcic->cfgaddr + PCIC_DEVCTL_REG);
19083db86aabSstevel 			cfg &= ~PCIC_DEVCTL_INTR_MASK;
19093db86aabSstevel 			switch (pcic->pc_intr_mode) {
19103db86aabSstevel 			case PCIC_INTR_MODE_ISA:
19113db86aabSstevel 				cfg |= PCIC_DEVCTL_INTR_ISA;
19123db86aabSstevel 				break;
19133db86aabSstevel 			}
19143db86aabSstevel #ifdef PCIC_DEBUG
19153db86aabSstevel 			if (pcic_debug) {
19163db86aabSstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
19173db86aabSstevel 				    "write reg 0x%x=%x \n",
19183db86aabSstevel 				    PCIC_DEVCTL_REG, cfg);
19193db86aabSstevel 			}
19203db86aabSstevel #endif
19213db86aabSstevel 			ddi_put8(pcic->cfg_handle,
19223db86aabSstevel 					pcic->cfgaddr + PCIC_DEVCTL_REG,
19233db86aabSstevel 					cfg);
19243db86aabSstevel 
19253db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
19263db86aabSstevel 					pcic->cfgaddr + PCIC_CRDCTL_REG);
19273db86aabSstevel 			cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC|
19283db86aabSstevel 					PCIC_CRDCTL_PCIFUNC);
19293db86aabSstevel 			switch (pcic->pc_intr_mode) {
19303db86aabSstevel 			case PCIC_INTR_MODE_PCI_1:
19313db86aabSstevel 				cfg |= PCIC_CRDCTL_PCIINTR |
19323db86aabSstevel 					PCIC_CRDCTL_PCICSC |
19333db86aabSstevel 					PCIC_CRDCTL_PCIFUNC;
19343db86aabSstevel 				pcic->pc_flags |= PCF_USE_SMI;
19353db86aabSstevel 				break;
19363db86aabSstevel 			}
19373db86aabSstevel #ifdef PCIC_DEBUG
19383db86aabSstevel 			if (pcic_debug) {
19393db86aabSstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
19403db86aabSstevel 				    " write reg 0x%x=%x \n",
19413db86aabSstevel 				    PCIC_CRDCTL_REG, cfg);
19423db86aabSstevel 			}
19433db86aabSstevel #endif
19443db86aabSstevel 			ddi_put8(pcic->cfg_handle,
19453db86aabSstevel 					pcic->cfgaddr + PCIC_CRDCTL_REG,
19463db86aabSstevel 					cfg);
19473db86aabSstevel 			break;
19483db86aabSstevel 		    case PCIC_TI_PCI1221:
19493db86aabSstevel 		    case PCIC_TI_PCI1225:
19503db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
19513db86aabSstevel 			    pcic->cfgaddr + PCIC_DEVCTL_REG);
19523db86aabSstevel 			cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE);
19533db86aabSstevel #ifdef PCIC_DEBUG
19543db86aabSstevel 			if (pcic_debug) {
19553db86aabSstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
19563db86aabSstevel 				    " write reg 0x%x=%x \n",
19573db86aabSstevel 				    PCIC_DEVCTL_REG, cfg);
19583db86aabSstevel 			}
19593db86aabSstevel #endif
19603db86aabSstevel 			ddi_put8(pcic->cfg_handle,
19613db86aabSstevel 			    pcic->cfgaddr + PCIC_DEVCTL_REG, cfg);
19623db86aabSstevel 
19633db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
19643db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG);
19653db86aabSstevel 			if (pcic->pc_type == PCIC_TI_PCI1225) {
19663db86aabSstevel 				cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
19673db86aabSstevel 			} else {
19683db86aabSstevel 				cfg |= PCIC_DIAG_ASYNC;
19693db86aabSstevel 			}
19703db86aabSstevel 			pcic->pc_flags |= PCF_USE_SMI;
19713db86aabSstevel #ifdef PCIC_DEBUG
19723db86aabSstevel 			if (pcic_debug) {
19733db86aabSstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
19743db86aabSstevel 				    " write reg 0x%x=%x \n",
19753db86aabSstevel 				    PCIC_DIAG_REG, cfg);
19763db86aabSstevel 			}
19773db86aabSstevel #endif
19783db86aabSstevel 			ddi_put8(pcic->cfg_handle,
19793db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19803db86aabSstevel 			break;
19813db86aabSstevel 		    case PCIC_TI_PCI1520:
19820e995c33Srw148561 		    case PCIC_TI_PCI1510:
19833db86aabSstevel 		    case PCIC_TI_VENDOR:
19843db86aabSstevel 			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
19853db86aabSstevel 				cfg = ddi_get8(pcic->cfg_handle,
19863db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
19873db86aabSstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
19883db86aabSstevel 				ddi_put8(pcic->cfg_handle,
19893db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
19903db86aabSstevel 					cfg);
19913db86aabSstevel 			}
19923db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
19933db86aabSstevel 					pcic->cfgaddr + PCIC_DEVCTL_REG);
19943db86aabSstevel 			cfg &= ~PCIC_DEVCTL_INTR_MASK;
19953db86aabSstevel 			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA)
19963db86aabSstevel 				cfg |= PCIC_DEVCTL_INTR_ISA;
19973db86aabSstevel 			ddi_put8(pcic->cfg_handle,
19983db86aabSstevel 					pcic->cfgaddr + PCIC_DEVCTL_REG,
19993db86aabSstevel 					cfg);
20003db86aabSstevel 
20013db86aabSstevel 			/* tie INTA and INTB together */
20023db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
20033db86aabSstevel 				(pcic->cfgaddr + PCIC_SYSCTL_REG + 3));
20043db86aabSstevel 			cfg |= PCIC_SYSCTL_INTRTIE;
20053db86aabSstevel 			ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
20063db86aabSstevel 				PCIC_SYSCTL_REG + 3), cfg);
20073db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
20083db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG);
20093db86aabSstevel 			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
20103db86aabSstevel 			ddi_put8(pcic->cfg_handle,
20113db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
20123db86aabSstevel 			break;
20133db86aabSstevel 		    case PCIC_TI_PCI1410:
20143db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle,
20153db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG);
20163db86aabSstevel 			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
20173db86aabSstevel 			ddi_put8(pcic->cfg_handle,
20183db86aabSstevel 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
20193db86aabSstevel 			break;
20203db86aabSstevel 		    case PCIC_TOSHIBA_TOPIC100:
20213db86aabSstevel 		    case PCIC_TOSHIBA_TOPIC95:
20223db86aabSstevel 		    case PCIC_TOSHIBA_VENDOR:
20233db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20243db86aabSstevel 				PCIC_TOSHIBA_SLOT_CTL_REG);
20253db86aabSstevel 			cfg |= (PCIC_TOSHIBA_SCR_SLOTON |
20263db86aabSstevel 				PCIC_TOSHIBA_SCR_SLOTEN);
20273db86aabSstevel 			cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK);
20283db86aabSstevel 			cfg |= PCIC_TOSHIBA_SCR_PRT_3E2;
20293db86aabSstevel 			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
20303db86aabSstevel 				PCIC_TOSHIBA_SLOT_CTL_REG, cfg);
20313db86aabSstevel 			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20323db86aabSstevel 				PCIC_TOSHIBA_INTR_CTL_REG);
20333db86aabSstevel 			switch (pcic->pc_intr_mode) {
20343db86aabSstevel 			case PCIC_INTR_MODE_ISA:
20353db86aabSstevel 				cfg &= ~PCIC_TOSHIBA_ICR_SRC;
20363db86aabSstevel 				ddi_put8(pcic->cfg_handle,
20373db86aabSstevel 					pcic->cfgaddr +
20383db86aabSstevel 					PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20393db86aabSstevel 
20403db86aabSstevel 				cfg = ddi_get8(pcic->cfg_handle,
20413db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20423db86aabSstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
20433db86aabSstevel 				ddi_put8(pcic->cfg_handle,
20443db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20453db86aabSstevel 					cfg);
20463db86aabSstevel 				break;
20473db86aabSstevel 			case PCIC_INTR_MODE_PCI_1:
20483db86aabSstevel 				cfg |= PCIC_TOSHIBA_ICR_SRC;
20493db86aabSstevel 				cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK);
20503db86aabSstevel 				cfg |= PCIC_TOSHIBA_ICR_PIN_INTA;
20513db86aabSstevel 				ddi_put8(pcic->cfg_handle,
20523db86aabSstevel 					pcic->cfgaddr +
20533db86aabSstevel 					PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20543db86aabSstevel 				break;
20553db86aabSstevel 			}
20563db86aabSstevel 			break;
20573db86aabSstevel 		    case PCIC_O2MICRO_VENDOR:
20583db86aabSstevel 			cfg32 = ddi_get32(pcic->cfg_handle,
20593db86aabSstevel 				(uint32_t *)(pcic->cfgaddr +
20603db86aabSstevel 				PCIC_O2MICRO_MISC_CTL));
20613db86aabSstevel 			switch (pcic->pc_intr_mode) {
20623db86aabSstevel 			case PCIC_INTR_MODE_ISA:
20633db86aabSstevel 				cfg32 |= (PCIC_O2MICRO_ISA_LEGACY |
20643db86aabSstevel 					PCIC_O2MICRO_INT_MOD_PCI);
20653db86aabSstevel 				ddi_put32(pcic->cfg_handle,
20663db86aabSstevel 					(uint32_t *)(pcic->cfgaddr +
20673db86aabSstevel 					PCIC_O2MICRO_MISC_CTL),
20683db86aabSstevel 					cfg32);
20693db86aabSstevel 				cfg = ddi_get8(pcic->cfg_handle,
20703db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20713db86aabSstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
20723db86aabSstevel 				ddi_put8(pcic->cfg_handle,
20733db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20743db86aabSstevel 					cfg);
20753db86aabSstevel 				break;
20763db86aabSstevel 			case PCIC_INTR_MODE_PCI_1:
20773db86aabSstevel 				cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY;
20783db86aabSstevel 				cfg32 |= PCIC_O2MICRO_INT_MOD_PCI;
20793db86aabSstevel 				ddi_put32(pcic->cfg_handle,
20803db86aabSstevel 					(uint32_t *)(pcic->cfgaddr +
20813db86aabSstevel 					PCIC_O2MICRO_MISC_CTL),
20823db86aabSstevel 					cfg32);
20833db86aabSstevel 				break;
20843db86aabSstevel 			}
20853db86aabSstevel 			break;
20863db86aabSstevel 		    case PCIC_RICOH_VENDOR:
20873db86aabSstevel 			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
20883db86aabSstevel 				cfg16 = ddi_get16(pcic->cfg_handle,
20893db86aabSstevel 					(uint16_t *)(pcic->cfgaddr +
20903db86aabSstevel 					PCIC_RICOH_MISC_CTL_2));
20913db86aabSstevel 				cfg16 |= (PCIC_RICOH_CSC_INT_MOD |
20923db86aabSstevel 					PCIC_RICOH_FUN_INT_MOD);
20933db86aabSstevel 				ddi_put16(pcic->cfg_handle,
20943db86aabSstevel 					(uint16_t *)(pcic->cfgaddr +
20953db86aabSstevel 					PCIC_RICOH_MISC_CTL_2),
20963db86aabSstevel 					cfg16);
20973db86aabSstevel 
20983db86aabSstevel 				cfg16 = ddi_get16(pcic->cfg_handle,
20993db86aabSstevel 					(uint16_t *)(pcic->cfgaddr +
21003db86aabSstevel 					PCIC_RICOH_MISC_CTL));
21013db86aabSstevel 				cfg16 |= PCIC_RICOH_SIRQ_EN;
21023db86aabSstevel 				ddi_put16(pcic->cfg_handle,
21033db86aabSstevel 					(uint16_t *)(pcic->cfgaddr +
21043db86aabSstevel 					PCIC_RICOH_MISC_CTL),
21053db86aabSstevel 					cfg16);
21063db86aabSstevel 
21073db86aabSstevel 				cfg = ddi_get8(pcic->cfg_handle,
21083db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
21093db86aabSstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
21103db86aabSstevel 				ddi_put8(pcic->cfg_handle,
21113db86aabSstevel 					pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
21123db86aabSstevel 					cfg);
21133db86aabSstevel 			}
21143db86aabSstevel 			break;
21153db86aabSstevel 		    default:
21163db86aabSstevel 			break;
21173db86aabSstevel 		} /* switch */
21183db86aabSstevel 
21193db86aabSstevel 		/* setup general card status change interrupt */
21203db86aabSstevel 		switch (pcic->pc_type) {
21213db86aabSstevel 			case PCIC_TI_PCI1225:
21223db86aabSstevel 			case PCIC_TI_PCI1221:
21233db86aabSstevel 			case PCIC_TI_PCI1031:
21243db86aabSstevel 			case PCIC_TI_PCI1520:
21253db86aabSstevel 			case PCIC_TI_PCI1410:
21263db86aabSstevel 				pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21273db86aabSstevel 				    PCIC_CHANGE_DEFAULT);
21283db86aabSstevel 				break;
21293db86aabSstevel 			default:
21303db86aabSstevel 				if (pcic->pc_intr_mode ==
21313db86aabSstevel 					PCIC_INTR_MODE_PCI_1) {
21323db86aabSstevel 					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21333db86aabSstevel 						PCIC_CHANGE_DEFAULT);
21343db86aabSstevel 					break;
21353db86aabSstevel 				} else {
21363db86aabSstevel 					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21373db86aabSstevel 						PCIC_CHANGE_DEFAULT |
21383db86aabSstevel 					(pcic->pc_sockets[i].pcs_smi << 4));
21393db86aabSstevel 					break;
21403db86aabSstevel 				}
21413db86aabSstevel 		}
21423db86aabSstevel 
21433db86aabSstevel 		pcic->pc_flags |= PCF_INTRENAB;
21443db86aabSstevel 
21453db86aabSstevel 		/* take card out of RESET */
21463db86aabSstevel 		pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET);
21473db86aabSstevel 		/* turn power off and let CS do this */
21483db86aabSstevel 		pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
21493db86aabSstevel 
21503db86aabSstevel 		/* final chip specific initialization */
21513db86aabSstevel 		switch (pcic->pc_type) {
21523db86aabSstevel 		    case PCIC_VADEM:
21533db86aabSstevel 			pcic_putb(pcic, i, PCIC_VG_CONTROL,
21543db86aabSstevel 					PCIC_VC_DELAYENABLE);
21553db86aabSstevel 			pcic->pc_flags |= PCF_DEBOUNCE;
21563db86aabSstevel 			/* FALLTHROUGH */
21573db86aabSstevel 		    case PCIC_I82365SL:
21583db86aabSstevel 			pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL,
21593db86aabSstevel 					PCIC_GC_CSC_WRITE);
21603db86aabSstevel 			/* clear any pending interrupts */
21613db86aabSstevel 			value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE);
21623db86aabSstevel 			pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value);
21633db86aabSstevel 			break;
21643db86aabSstevel 		    /* The 82092 uses PCI config space to enable interrupts */
21653db86aabSstevel 		    case PCIC_INTEL_i82092:
21663db86aabSstevel 			pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI,
21673db86aabSstevel 							PCIC_82092_INT_ENABLE);
21683db86aabSstevel 			break;
21693db86aabSstevel 		    case PCIC_CL_PD6729:
21703db86aabSstevel 			if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) {
21713db86aabSstevel 				value = pcic_getb(pcic, i, PCIC_MISC_CTL_2);
21723db86aabSstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2,
21733db86aabSstevel 						value | PCIC_CL_TIMER_CLK_DIV);
21743db86aabSstevel 			}
21753db86aabSstevel 			break;
21763db86aabSstevel 		} /* switch */
21773db86aabSstevel 
21783db86aabSstevel #if defined(PCIC_DEBUG)
21793db86aabSstevel 		if (pcic_debug)
21803db86aabSstevel 			cmn_err(CE_CONT,
21813db86aabSstevel 				"socket %d value=%x, flags = %x (%s)\n",
21823db86aabSstevel 				i, value, pcic->pc_sockets[i].pcs_flags,
21833db86aabSstevel 				(pcic->pc_sockets[i].pcs_flags &
21843db86aabSstevel 					PCS_CARD_PRESENT) ?
21853db86aabSstevel 						"card present" : "no card");
21863db86aabSstevel #endif
21873db86aabSstevel 	}
21883db86aabSstevel }
21893db86aabSstevel 
21903db86aabSstevel /*
21913db86aabSstevel  * pcic_intr(caddr_t, caddr_t)
21923db86aabSstevel  *	interrupt handler for the PCIC style adapter
21933db86aabSstevel  *	handles all basic interrupts and also checks
21943db86aabSstevel  *	for status changes and notifies the nexus if
21953db86aabSstevel  *	necessary
21963db86aabSstevel  *
21973db86aabSstevel  *	On PCI bus adapters, also handles all card
21983db86aabSstevel  *	IO interrupts.
21993db86aabSstevel  */
22003db86aabSstevel /*ARGSUSED*/
22013db86aabSstevel uint32_t
22023db86aabSstevel pcic_intr(caddr_t arg1, caddr_t arg2)
22033db86aabSstevel {
22043db86aabSstevel 	pcicdev_t *pcic = (pcicdev_t *)arg1;
22053db86aabSstevel 	int value = 0, i, ret = DDI_INTR_UNCLAIMED;
22063db86aabSstevel 	uint8_t status;
22073db86aabSstevel 	uint_t io_ints;
22083db86aabSstevel 
22093db86aabSstevel #if defined(PCIC_DEBUG)
22103db86aabSstevel 	pcic_err(pcic->dip, 0xf,
22113db86aabSstevel 		"pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x"
22123db86aabSstevel 		" pc_numsockets=%d \n",
22133db86aabSstevel 		pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets);
22143db86aabSstevel #endif
22153db86aabSstevel 
22163db86aabSstevel 	if (!(pcic->pc_flags & PCF_ATTACHED))
22173db86aabSstevel 	    return (DDI_INTR_UNCLAIMED);
22183db86aabSstevel 
22193db86aabSstevel 	mutex_enter(&pcic->intr_lock);
22203db86aabSstevel 
22213db86aabSstevel 	if (pcic->pc_flags & PCF_SUSPENDED) {
22223db86aabSstevel 		mutex_exit(&pcic->intr_lock);
22233db86aabSstevel 		return (ret);
22243db86aabSstevel 	}
22253db86aabSstevel 
22263db86aabSstevel 	/*
22273db86aabSstevel 	 * need to change to only ACK and touch the slot that
22283db86aabSstevel 	 * actually caused the interrupt.  Currently everything
22293db86aabSstevel 	 * is acked
22303db86aabSstevel 	 *
22313db86aabSstevel 	 * we need to look at all known sockets to determine
22323db86aabSstevel 	 * what might have happened, so step through the list
22333db86aabSstevel 	 * of them
22343db86aabSstevel 	 */
22353db86aabSstevel #ifdef VOYAGER
22363db86aabSstevel 	ret = syshw_intr_hi(pcic);
22373db86aabSstevel #endif
22383db86aabSstevel 
22393db86aabSstevel 	/*
22403db86aabSstevel 	 * Set the bitmask for IO interrupts to initially include all sockets
22413db86aabSstevel 	 */
22423db86aabSstevel 	io_ints = (1 << pcic->pc_numsockets) - 1;
22433db86aabSstevel 
22443db86aabSstevel 	for (i = 0; i < pcic->pc_numsockets; i++) {
22453db86aabSstevel 		int card_type;
22463db86aabSstevel 		pcic_socket_t *sockp;
22473db86aabSstevel 		int value_cb = 0;
22483db86aabSstevel 
22493db86aabSstevel 		sockp = &pcic->pc_sockets[i];
22503db86aabSstevel 		/* get the socket's I/O addresses */
22513db86aabSstevel 
22523db86aabSstevel 		if (sockp->pcs_flags & PCS_WAITING) {
22533db86aabSstevel 			io_ints &= ~(1 << i);
22543db86aabSstevel 			continue;
22553db86aabSstevel 		}
22563db86aabSstevel 
22573db86aabSstevel 		if (sockp->pcs_flags & PCS_CARD_IO)
22583db86aabSstevel 			card_type = IF_IO;
22593db86aabSstevel 		else
22603db86aabSstevel 			card_type = IF_MEMORY;
22613db86aabSstevel 
22623db86aabSstevel 		if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA)
22633db86aabSstevel 			value_cb = pcic_getcb(pcic, CB_STATUS_EVENT);
22643db86aabSstevel 
22653db86aabSstevel 		value = pcic_change(pcic, i);
22663db86aabSstevel 
22673db86aabSstevel 		if ((value != 0) || (value_cb != 0)) {
22683db86aabSstevel 			int x = pcic->pc_cb_arg;
22693db86aabSstevel 
22703db86aabSstevel 			ret = DDI_INTR_CLAIMED;
22713db86aabSstevel 
22723db86aabSstevel #if defined(PCIC_DEBUG)
22733db86aabSstevel 			pcic_err(pcic->dip, 0x9,
22743db86aabSstevel 			    "card_type = %d, value_cb = 0x%x\n",
22753db86aabSstevel 			    card_type,
22763db86aabSstevel 			    value_cb ? value_cb :
22773db86aabSstevel 				pcic_getcb(pcic, CB_STATUS_EVENT));
22783db86aabSstevel 			if (pcic_debug)
22793db86aabSstevel 				cmn_err(CE_CONT,
22803db86aabSstevel 					"\tchange on socket %d (%x)\n", i,
22813db86aabSstevel 					value);
22823db86aabSstevel #endif
22833db86aabSstevel 			/* find out what happened */
22843db86aabSstevel 			status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS);
22853db86aabSstevel 
22863db86aabSstevel 			/* acknowledge the interrupt */
22873db86aabSstevel 			if (value_cb)
22883db86aabSstevel 				pcic_putcb(pcic, CB_STATUS_EVENT, value_cb);
22893db86aabSstevel 
22903db86aabSstevel 			if (value)
22913db86aabSstevel 				pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE,
22923db86aabSstevel 				    value);
22933db86aabSstevel 
22943db86aabSstevel 			if (pcic->pc_callback == NULL) {
22953db86aabSstevel 				/* if not callback handler, nothing to do */
22963db86aabSstevel 				continue;
22973db86aabSstevel 			}
22983db86aabSstevel 
22993db86aabSstevel 			/* Card Detect */
23003db86aabSstevel 			if (value & PCIC_CD_DETECT ||
23013db86aabSstevel 			    value_cb & CB_PS_CCDMASK) {
23023db86aabSstevel 				uint8_t irq;
23033db86aabSstevel #if defined(PCIC_DEBUG)
23043db86aabSstevel 				if (pcic_debug)
23053db86aabSstevel 					cmn_err(CE_CONT,
23063db86aabSstevel 						"\tcd_detect: status=%x,"
23073db86aabSstevel 						" flags=%x\n",
23083db86aabSstevel 						status, sockp->pcs_flags);
23093db86aabSstevel #else
23103db86aabSstevel #ifdef lint
23113db86aabSstevel 				if (status == 0)
23123db86aabSstevel 				    status++;
23133db86aabSstevel #endif
23143db86aabSstevel #endif
23153db86aabSstevel 				/*
23163db86aabSstevel 				 * Turn off all interrupts for this socket here.
23173db86aabSstevel 				 */
23183db86aabSstevel 				irq = pcic_getb(pcic, sockp->pcs_socket,
23193db86aabSstevel 				    PCIC_MANAGEMENT_INT);
23203db86aabSstevel 				irq &= ~PCIC_CHANGE_MASK;
23213db86aabSstevel 				pcic_putb(pcic, sockp->pcs_socket,
23223db86aabSstevel 				    PCIC_MANAGEMENT_INT, irq);
23233db86aabSstevel 
23243db86aabSstevel 				pcic_putcb(pcic, CB_STATUS_MASK, 0x0);
23253db86aabSstevel 
2326*0d282d13Srw148561 				/*
2327*0d282d13Srw148561 				 * Put the socket in debouncing state so that
2328*0d282d13Srw148561 				 * the leaf driver won't receive interrupts.
2329*0d282d13Srw148561 				 * Crucial for handling surprise-removal.
2330*0d282d13Srw148561 				 */
2331*0d282d13Srw148561 				sockp->pcs_flags |= PCS_DEBOUNCING;
2332*0d282d13Srw148561 
23333db86aabSstevel 				if (!sockp->pcs_cd_softint_flg) {
23343db86aabSstevel 					sockp->pcs_cd_softint_flg = 1;
23353db86aabSstevel 					(void) ddi_intr_trigger_softint(
23363db86aabSstevel 					    sockp->pcs_cd_softint_hdl, NULL);
23373db86aabSstevel 				}
23383db86aabSstevel 
23393db86aabSstevel 				io_ints &= ~(1 << i);
23403db86aabSstevel 			} /* PCIC_CD_DETECT */
23413db86aabSstevel 
23423db86aabSstevel 			/* Ready/Change Detect */
23433db86aabSstevel 			sockp->pcs_state ^= SBM_RDYBSY;
23443db86aabSstevel 			if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) {
23453db86aabSstevel 				sockp->pcs_flags |= PCS_READY;
23463db86aabSstevel 				PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i);
23473db86aabSstevel 			}
23483db86aabSstevel 
23493db86aabSstevel 			/* Battery Warn Detect */
23503db86aabSstevel 			if (card_type == IF_MEMORY &&
23513db86aabSstevel 			    value & PCIC_BW_DETECT &&
23523db86aabSstevel 			    !(sockp->pcs_state & SBM_BVD2)) {
23533db86aabSstevel 				sockp->pcs_state |= SBM_BVD2;
23543db86aabSstevel 				PC_CALLBACK(pcic->dip, x,
23553db86aabSstevel 						PCE_CARD_BATTERY_WARN, i);
23563db86aabSstevel 			}
23573db86aabSstevel 
23583db86aabSstevel 			/* Battery Dead Detect */
23593db86aabSstevel 			if (value & PCIC_BD_DETECT) {
23603db86aabSstevel 				/*
23613db86aabSstevel 				 * need to work out event if RI not enabled
23623db86aabSstevel 				 * and card_type == IF_IO
23633db86aabSstevel 				 */
23643db86aabSstevel 				if (card_type == IF_MEMORY &&
23653db86aabSstevel 					!(sockp->pcs_state & SBM_BVD1)) {
23663db86aabSstevel 					sockp->pcs_state |= SBM_BVD1;
23673db86aabSstevel 					PC_CALLBACK(pcic->dip, x,
23683db86aabSstevel 							PCE_CARD_BATTERY_DEAD,
23693db86aabSstevel 							i);
23703db86aabSstevel 				} else {
23713db86aabSstevel 					/*
23723db86aabSstevel 					 * information in pin replacement
23733db86aabSstevel 					 * register if one is available
23743db86aabSstevel 					 */
23753db86aabSstevel 					PC_CALLBACK(pcic->dip, x,
23763db86aabSstevel 							PCE_CARD_STATUS_CHANGE,
23773db86aabSstevel 							i);
23783db86aabSstevel 				} /* IF_MEMORY */
23793db86aabSstevel 			} /* PCIC_BD_DETECT */
23803db86aabSstevel 		} /* if pcic_change */
23813db86aabSstevel 		/*
23823db86aabSstevel 		 * for any controllers that we can detect whether a socket
23833db86aabSstevel 		 * had an interrupt for the PC Card, we should sort that out
23843db86aabSstevel 		 * here.
23853db86aabSstevel 		 */
23863db86aabSstevel 	} /* for pc_numsockets */
23873db86aabSstevel 
23883db86aabSstevel 	/*
23893db86aabSstevel 	 * If we're on a PCI bus, we may need to cycle through each IO
23903db86aabSstevel 	 *	interrupt handler that is registered since they all
23913db86aabSstevel 	 *	share the same interrupt line.
23923db86aabSstevel 	 */
23933db86aabSstevel 
23943db86aabSstevel 
23953db86aabSstevel #if defined(PCIC_DEBUG)
23963db86aabSstevel 	pcic_err(pcic->dip, 0xf,
23973db86aabSstevel 	    "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n",
23983db86aabSstevel 	    pcic->pc_intr_mode, pcic->pc_type, io_ints);
23993db86aabSstevel #endif
24003db86aabSstevel 
2401*0d282d13Srw148561 	if (io_ints) {
2402*0d282d13Srw148561 		if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED)
24033db86aabSstevel 			ret = DDI_INTR_CLAIMED;
24043db86aabSstevel 	}
24053db86aabSstevel 
24063db86aabSstevel 	mutex_exit(&pcic->intr_lock);
24073db86aabSstevel 
24083db86aabSstevel #if defined(PCIC_DEBUG)
24093db86aabSstevel 	pcic_err(pcic->dip, 0xf,
24103db86aabSstevel 	    "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n",
24113db86aabSstevel 	    ret, value, DDI_INTR_CLAIMED);
24123db86aabSstevel #endif
24133db86aabSstevel 
24143db86aabSstevel 	return (ret);
24153db86aabSstevel }
24163db86aabSstevel 
24173db86aabSstevel /*
24183db86aabSstevel  * pcic_change()
24193db86aabSstevel  *	check to see if this socket had a change in state
24203db86aabSstevel  *	by checking the status change register
24213db86aabSstevel  */
24223db86aabSstevel static int
24233db86aabSstevel pcic_change(pcicdev_t *pcic, int socket)
24243db86aabSstevel {
24253db86aabSstevel 	return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE));
24263db86aabSstevel }
24273db86aabSstevel 
24283db86aabSstevel /*
24293db86aabSstevel  * pcic_do_io_intr - calls client interrupt handlers
24303db86aabSstevel  */
24313db86aabSstevel static int
24323db86aabSstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets)
24333db86aabSstevel {
24343db86aabSstevel 	inthandler_t *tmp;
24353db86aabSstevel 	int ret = DDI_INTR_UNCLAIMED;
24363db86aabSstevel 
24373db86aabSstevel #if defined(PCIC_DEBUG)
24383db86aabSstevel 	pcic_err(pcic->dip, 0xf,
24393db86aabSstevel 		"pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n",
24403db86aabSstevel 		(void *)pcic, (int)sockets, (void *)pcic->irq_top);
24413db86aabSstevel #endif
24423db86aabSstevel 
24433db86aabSstevel 	if (pcic->irq_top != NULL) {
24443db86aabSstevel 	    tmp = pcic->irq_current;
24453db86aabSstevel 
24463db86aabSstevel 	    do {
24473db86aabSstevel 		int cur = pcic->irq_current->socket;
24483db86aabSstevel 		pcic_socket_t *sockp =
24493db86aabSstevel 				&pcic->pc_sockets[cur];
24503db86aabSstevel 
24513db86aabSstevel #if defined(PCIC_DEBUG)
24523db86aabSstevel 		pcic_err(pcic->dip, 0xf,
24533db86aabSstevel 		    "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n",
24543db86aabSstevel 		    sockp->pcs_flags, PCS_CARD_PRESENT);
24553db86aabSstevel 		pcic_err(pcic->dip, 0xf,
24563db86aabSstevel 		    "\t sockets=%d cur=%d intr=%p arg1=%p "
24573db86aabSstevel 		    "arg2=%p\n",
24583db86aabSstevel 		    sockets, cur, (void *)pcic->irq_current->intr,
24593db86aabSstevel 		    pcic->irq_current->arg1,
24603db86aabSstevel 		    pcic->irq_current->arg2);
24613db86aabSstevel #endif
2462*0d282d13Srw148561 		if ((sockp->pcs_flags & PCS_CARD_PRESENT) &&
2463*0d282d13Srw148561 		    !(sockp->pcs_flags & PCS_DEBOUNCING) &&
2464*0d282d13Srw148561 		    (sockets & (1 << cur))) {
24653db86aabSstevel 
24663db86aabSstevel 			if ((*pcic->irq_current->intr)(pcic->irq_current->arg1,
24673db86aabSstevel 			    pcic->irq_current->arg2) == DDI_INTR_CLAIMED)
24683db86aabSstevel 				ret = DDI_INTR_CLAIMED;
24693db86aabSstevel 
24703db86aabSstevel #if defined(PCIC_DEBUG)
24713db86aabSstevel 			pcic_err(pcic->dip, 0xf,
24723db86aabSstevel 			    "\t ret=%d DDI_INTR_CLAIMED=%d\n",
24733db86aabSstevel 			    ret, DDI_INTR_CLAIMED);
24743db86aabSstevel #endif
24753db86aabSstevel 		}
24763db86aabSstevel 
24773db86aabSstevel 
24783db86aabSstevel 		if ((pcic->irq_current = pcic->irq_current->next) == NULL)
24793db86aabSstevel 					pcic->irq_current = pcic->irq_top;
24803db86aabSstevel 
24813db86aabSstevel 	    } while (pcic->irq_current != tmp);
24823db86aabSstevel 
24833db86aabSstevel 	    if ((pcic->irq_current = pcic->irq_current->next) == NULL)
24843db86aabSstevel 					pcic->irq_current = pcic->irq_top;
24853db86aabSstevel 
24863db86aabSstevel 	} else {
24873db86aabSstevel 		ret = DDI_INTR_UNCLAIMED;
24883db86aabSstevel 	}
24893db86aabSstevel 
24903db86aabSstevel #if defined(PCIC_DEBUG)
24913db86aabSstevel 	pcic_err(pcic->dip, 0xf,
24923db86aabSstevel 		"pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n",
24933db86aabSstevel 		ret, DDI_INTR_CLAIMED);
24943db86aabSstevel #endif
24953db86aabSstevel 
24963db86aabSstevel 	return (ret);
24973db86aabSstevel 
24983db86aabSstevel }
24993db86aabSstevel 
25003db86aabSstevel /*
25013db86aabSstevel  * pcic_inquire_adapter()
25023db86aabSstevel  *	SocketServices InquireAdapter function
25033db86aabSstevel  *	get characteristics of the physical adapter
25043db86aabSstevel  */
25053db86aabSstevel /*ARGSUSED*/
25063db86aabSstevel static int
25073db86aabSstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
25083db86aabSstevel {
25093db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
25103db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
25113db86aabSstevel 
25123db86aabSstevel 	config->NumSockets = pcic->pc_numsockets;
25133db86aabSstevel 	config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK;
25143db86aabSstevel 	config->NumEDCs = 0;
25153db86aabSstevel 	config->AdpCaps = 0;
25163db86aabSstevel 	config->ActiveHigh = 0;
25173db86aabSstevel 	config->ActiveLow = PCIC_AVAIL_IRQS;
25183db86aabSstevel 	config->NumPower = pcic->pc_numpower;
25193db86aabSstevel 	config->power_entry = pcic->pc_power; /* until we resolve this */
25203db86aabSstevel #if defined(PCIC_DEBUG)
25213db86aabSstevel 	if (pcic_debug) {
25223db86aabSstevel 		cmn_err(CE_CONT, "pcic_inquire_adapter:\n");
25233db86aabSstevel 		cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets);
25243db86aabSstevel 		cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows);
25253db86aabSstevel 	}
25263db86aabSstevel #endif
25273db86aabSstevel 	config->ResourceFlags = 0;
25283db86aabSstevel 	switch (pcic->pc_intr_mode) {
25293db86aabSstevel 	case PCIC_INTR_MODE_PCI_1:
25303db86aabSstevel 		config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS |
25313db86aabSstevel 			RES_IRQ_SHAREABLE;
25323db86aabSstevel 		break;
25333db86aabSstevel 	}
25343db86aabSstevel 	return (SUCCESS);
25353db86aabSstevel }
25363db86aabSstevel 
25373db86aabSstevel /*
25383db86aabSstevel  * pcic_callback()
25393db86aabSstevel  *	The PCMCIA nexus calls us via this function
25403db86aabSstevel  *	in order to set the callback function we are
25413db86aabSstevel  *	to call the nexus with
25423db86aabSstevel  */
25433db86aabSstevel /*ARGSUSED*/
25443db86aabSstevel static int
25453db86aabSstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg)
25463db86aabSstevel {
25473db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
25483db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
25493db86aabSstevel 
25503db86aabSstevel 	if (handler != NULL) {
25513db86aabSstevel 		pcic->pc_callback = handler;
25523db86aabSstevel 		pcic->pc_cb_arg  = arg;
25533db86aabSstevel 		pcic->pc_flags |= PCF_CALLBACK;
25543db86aabSstevel 	} else {
25553db86aabSstevel 		pcic->pc_callback = NULL;
25563db86aabSstevel 		pcic->pc_cb_arg = 0;
25573db86aabSstevel 		pcic->pc_flags &= ~PCF_CALLBACK;
25583db86aabSstevel 	}
25593db86aabSstevel 	/*
25603db86aabSstevel 	 * we're now registered with the nexus
25613db86aabSstevel 	 * it is acceptable to do callbacks at this point.
25623db86aabSstevel 	 * don't call back from here though since it could block
25633db86aabSstevel 	 */
25643db86aabSstevel 	return (PC_SUCCESS);
25653db86aabSstevel }
25663db86aabSstevel 
25673db86aabSstevel /*
25683db86aabSstevel  * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed)
25693db86aabSstevel  *	calculate the speed bits from the specified memory speed
25703db86aabSstevel  *	there may be more to do here
25713db86aabSstevel  */
25723db86aabSstevel 
25733db86aabSstevel static int
25743db86aabSstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed)
25753db86aabSstevel {
25763db86aabSstevel 	uint32_t wspeed = 1;	/* assume 1 wait state when unknown */
25773db86aabSstevel 	uint32_t bspeed = PCIC_ISA_DEF_SYSCLK;
25783db86aabSstevel 
25793db86aabSstevel 	switch (pcic->pc_type) {
25803db86aabSstevel 	    case PCIC_I82365SL:
25813db86aabSstevel 	    case PCIC_VADEM:
25823db86aabSstevel 	    case PCIC_VADEM_VG469:
25833db86aabSstevel 	    default:
25843db86aabSstevel 		/* Intel chip wants it in waitstates */
25853db86aabSstevel 		wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3;
25863db86aabSstevel 		if (speed <= wspeed)
25873db86aabSstevel 			wspeed = 0;
25883db86aabSstevel 		else if (speed <= (wspeed += mhztons(bspeed)))
25893db86aabSstevel 			wspeed = 1;
25903db86aabSstevel 		else if (speed <= (wspeed += mhztons(bspeed)))
25913db86aabSstevel 			wspeed = 2;
25923db86aabSstevel 		else
25933db86aabSstevel 			wspeed = 3;
25943db86aabSstevel 		wspeed <<= 6; /* put in right bit positions */
25953db86aabSstevel 		break;
25963db86aabSstevel 
25973db86aabSstevel 	    case PCIC_INTEL_i82092:
25983db86aabSstevel 		wspeed = SYSMEM_82092_80NS;
25993db86aabSstevel 		if (speed > 80)
26003db86aabSstevel 		    wspeed = SYSMEM_82092_100NS;
26013db86aabSstevel 		if (speed > 100)
26023db86aabSstevel 		    wspeed = SYSMEM_82092_150NS;
26033db86aabSstevel 		if (speed > 150)
26043db86aabSstevel 		    wspeed = SYSMEM_82092_200NS;
26053db86aabSstevel 		if (speed > 200)
26063db86aabSstevel 		    wspeed = SYSMEM_82092_250NS;
26073db86aabSstevel 		if (speed > 250)
26083db86aabSstevel 		    wspeed = SYSMEM_82092_600NS;
26093db86aabSstevel 		wspeed <<= 5;	/* put in right bit positions */
26103db86aabSstevel 		break;
26113db86aabSstevel 
26123db86aabSstevel 	} /* switch */
26133db86aabSstevel 
26143db86aabSstevel 	return (wspeed);
26153db86aabSstevel }
26163db86aabSstevel 
26173db86aabSstevel /*
26183db86aabSstevel  * These values are taken from the PC Card Standard Electrical Specification.
26193db86aabSstevel  * Generally the larger value is taken if 2 are possible.
26203db86aabSstevel  */
26213db86aabSstevel static struct pcic_card_times {
26223db86aabSstevel 	uint16_t cycle;	/* Speed as found in the atribute space of he card. */
26233db86aabSstevel 	uint16_t setup;	/* Corresponding address setup time. */
26243db86aabSstevel 	uint16_t width;	/* Corresponding width, OE or WE. */
26253db86aabSstevel 	uint16_t hold;	/* Corresponding data or address hold time. */
26263db86aabSstevel } pcic_card_times[] = {
26273db86aabSstevel 
26283db86aabSstevel /*
26293db86aabSstevel  * Note: The rounded up times for 250, 200 & 150 have been increased
26303db86aabSstevel  * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi.
26313db86aabSstevel  * See BugID 00663.
26323db86aabSstevel  */
26333db86aabSstevel 
26343db86aabSstevel /*
26353db86aabSstevel  * Rounded up times           Original times from
26363db86aabSstevel  * that add up to the         the PCMCIA Spec.
26373db86aabSstevel  * cycle time.
26383db86aabSstevel  */
26393db86aabSstevel 	{600, 180, 370, 140},	/* 100, 300,  70 */
26403db86aabSstevel 	{400, 120, 300, 90},	/* Made this one up */
26413db86aabSstevel 	{250, 100, 190, 70},	/*  30, 150,  30 */
26423db86aabSstevel 	{200, 80, 170, 70},	/*  20, 120,  30 */
26433db86aabSstevel 	{150, 50, 110, 40},	/*  20,  80,  20 */
26443db86aabSstevel 	{100, 40, 80, 40},	/*  10,  60,  15 */
26453db86aabSstevel 	{0, 10, 60, 15}		/*  10,  60,  15 */
26463db86aabSstevel };
26473db86aabSstevel 
26483db86aabSstevel /*
26493db86aabSstevel  * pcic_set_cdtimers
26503db86aabSstevel  *	This is specific to several Cirrus Logic chips
26513db86aabSstevel  */
26523db86aabSstevel static void
26533db86aabSstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset)
26543db86aabSstevel {
26553db86aabSstevel 	int cmd, set, rec, offset, clk_pulse;
26563db86aabSstevel 	struct pcic_card_times *ctp;
26573db86aabSstevel 
26583db86aabSstevel 	if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1))
26593db86aabSstevel 		offset = 3;
26603db86aabSstevel 	else
26613db86aabSstevel 		offset = 0;
26623db86aabSstevel 
26633db86aabSstevel 	clk_pulse = mhztons(pcic->bus_speed);
26643db86aabSstevel 	for (ctp = pcic_card_times; speed < ctp->cycle; ctp++);
26653db86aabSstevel 
26663db86aabSstevel 	/*
26673db86aabSstevel 	 * Add (clk_pulse/2) and an extra 1 to account for rounding errors.
26683db86aabSstevel 	 */
26693db86aabSstevel 	set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26703db86aabSstevel 	if (set < 0)
26713db86aabSstevel 		set = 0;
26723db86aabSstevel 
26733db86aabSstevel 	cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26743db86aabSstevel 	if (cmd < 0)
26753db86aabSstevel 		cmd = 0;
26763db86aabSstevel 
26773db86aabSstevel 	rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2;
26783db86aabSstevel 	if (rec < 0)
26793db86aabSstevel 		rec = 0;
26803db86aabSstevel 
26813db86aabSstevel #if defined(PCIC_DEBUG)
26823db86aabSstevel 	pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n"
26833db86aabSstevel 	    "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n",
26843db86aabSstevel 	    (unsigned)speed, offset == 3 ? 1 : 0,
26853db86aabSstevel 	    ctp->cycle, clk_pulse, cmd, set, rec);
26863db86aabSstevel #endif
26873db86aabSstevel 
26883db86aabSstevel 	pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd);
26893db86aabSstevel 	pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set);
26903db86aabSstevel 	pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec);
26913db86aabSstevel }
26923db86aabSstevel 
26933db86aabSstevel /*
26943db86aabSstevel  * pcic_set_window
26953db86aabSstevel  *	essentially the same as the Socket Services specification
26963db86aabSstevel  *	We use socket and not adapter since they are identifiable
26973db86aabSstevel  *	but the rest is the same
26983db86aabSstevel  *
26993db86aabSstevel  *	dip	pcic driver's device information
27003db86aabSstevel  *	window	parameters for the request
27013db86aabSstevel  */
27023db86aabSstevel static int
27033db86aabSstevel pcic_set_window(dev_info_t *dip, set_window_t *window)
27043db86aabSstevel {
27053db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
27063db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
27073db86aabSstevel 	int select;
27083db86aabSstevel 	int socket, pages, which, ret;
27093db86aabSstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[window->socket];
27103db86aabSstevel 	ra_return_t res;
27113db86aabSstevel 	ndi_ra_request_t req;
27123db86aabSstevel 	uint32_t base = window->base;
27133db86aabSstevel 
27143db86aabSstevel #if defined(PCIC_DEBUG)
27153db86aabSstevel 	if (pcic_debug) {
27163db86aabSstevel 		cmn_err(CE_CONT, "pcic_set_window: entered\n");
27173db86aabSstevel 		cmn_err(CE_CONT,
27183db86aabSstevel 			"\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
27193db86aabSstevel 			window->window, window->socket, window->WindowSize,
27203db86aabSstevel 			window->speed);
27213db86aabSstevel 		cmn_err(CE_CONT,
27223db86aabSstevel 			"\tbase=%x, state=%x\n", (unsigned)window->base,
27233db86aabSstevel 			(unsigned)window->state);
27243db86aabSstevel 	}
27253db86aabSstevel #endif
27263db86aabSstevel 
27273db86aabSstevel 	/*
27283db86aabSstevel 	 * do some basic sanity checking on what we support
27293db86aabSstevel 	 * we don't do paged mode
27303db86aabSstevel 	 */
27313db86aabSstevel 	if (window->state & WS_PAGED) {
27323db86aabSstevel 		cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n");
27333db86aabSstevel 		return (BAD_ATTRIBUTE);
27343db86aabSstevel 	}
27353db86aabSstevel 
27363db86aabSstevel 	/*
27373db86aabSstevel 	 * we don't care about previous mappings.
27383db86aabSstevel 	 * Card Services will deal with that so don't
27393db86aabSstevel 	 * even check
27403db86aabSstevel 	 */
27413db86aabSstevel 
27423db86aabSstevel 	socket = window->socket;
27433db86aabSstevel 
27443db86aabSstevel 	if (!(window->state & WS_IO)) {
27453db86aabSstevel 		int win, tmp;
27463db86aabSstevel 		pcs_memwin_t *memp;
27473db86aabSstevel #if defined(PCIC_DEBUG)
27483db86aabSstevel 		if (pcic_debug)
27493db86aabSstevel 			cmn_err(CE_CONT, "\twindow type is memory\n");
27503db86aabSstevel #endif
27513db86aabSstevel 		/* this is memory window mapping */
27523db86aabSstevel 		win = window->window % PCIC_NUMWINSOCK;
27533db86aabSstevel 		tmp = window->window / PCIC_NUMWINSOCK;
27543db86aabSstevel 
27553db86aabSstevel 		/* only windows 2-6 can do memory mapping */
27563db86aabSstevel 		if (tmp != window->socket || win < PCIC_IOWINDOWS) {
27573db86aabSstevel 			cmn_err(CE_CONT,
27583db86aabSstevel 				"\tattempt to map to non-mem window\n");
27593db86aabSstevel 			return (BAD_WINDOW);
27603db86aabSstevel 		}
27613db86aabSstevel 
27623db86aabSstevel 		if (window->WindowSize == 0)
27633db86aabSstevel 			window->WindowSize = MEM_MIN;
27643db86aabSstevel 		else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) {
27653db86aabSstevel 			cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n");
27663db86aabSstevel 			return (BAD_SIZE);
27673db86aabSstevel 		}
27683db86aabSstevel 
27693db86aabSstevel 		mutex_enter(&pcic->pc_lock); /* protect the registers */
27703db86aabSstevel 
27713db86aabSstevel 		memp = &sockp->pcs_windows[win].mem;
27723db86aabSstevel 		memp->pcw_speed = window->speed;
27733db86aabSstevel 
27743db86aabSstevel 		win -= PCIC_IOWINDOWS; /* put in right range */
27753db86aabSstevel 
27763db86aabSstevel 		if (window->WindowSize != memp->pcw_len)
27773db86aabSstevel 			which = memp->pcw_len;
27783db86aabSstevel 		else
27793db86aabSstevel 			which = 0;
27803db86aabSstevel 
27813db86aabSstevel 		if (window->state & WS_ENABLED) {
27823db86aabSstevel 			uint32_t wspeed;
27833db86aabSstevel #if defined(PCIC_DEBUG)
27843db86aabSstevel 			if (pcic_debug) {
27853db86aabSstevel 				cmn_err(CE_CONT,
27863db86aabSstevel 					"\tbase=%x, win=%d\n", (unsigned)base,
27873db86aabSstevel 					win);
27883db86aabSstevel 				if (which)
27893db86aabSstevel 					cmn_err(CE_CONT,
27903db86aabSstevel 						"\tneed to remap window\n");
27913db86aabSstevel 			}
27923db86aabSstevel #endif
27933db86aabSstevel 
27943db86aabSstevel 			if (which && (memp->pcw_status & PCW_MAPPED)) {
27953db86aabSstevel 				ddi_regs_map_free(&memp->pcw_handle);
27963db86aabSstevel 				res.ra_addr_lo = memp->pcw_base;
27973db86aabSstevel 				res.ra_len = memp->pcw_len;
27983db86aabSstevel 				(void) pcmcia_free_mem(dip, &res);
27993db86aabSstevel 				memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
28003db86aabSstevel 				memp->pcw_hostmem = NULL;
28013db86aabSstevel 				memp->pcw_base = NULL;
28023db86aabSstevel 				memp->pcw_len = 0;
28033db86aabSstevel 			}
28043db86aabSstevel 
28053db86aabSstevel 			which = window->WindowSize >> PAGE_SHIFT;
28063db86aabSstevel 
28073db86aabSstevel 			if (!(memp->pcw_status & PCW_MAPPED)) {
28083db86aabSstevel 				ret = 0;
28093db86aabSstevel 
28103db86aabSstevel 				memp->pcw_base = base;
28113db86aabSstevel 				bzero(&req, sizeof (req));
28123db86aabSstevel 				req.ra_len = which << PAGE_SHIFT;
28133db86aabSstevel 				req.ra_addr = (uint64_t)memp->pcw_base;
28143db86aabSstevel 				req.ra_boundbase = pcic->pc_base;
28153db86aabSstevel 				req.ra_boundlen  = pcic->pc_bound;
28163db86aabSstevel 				req.ra_flags = (memp->pcw_base ?
28173db86aabSstevel 					NDI_RA_ALLOC_SPECIFIED : 0) |
28183db86aabSstevel 					NDI_RA_ALLOC_BOUNDED;
28193db86aabSstevel 				req.ra_align_mask =
28203db86aabSstevel 					(PAGESIZE - 1) | (PCIC_PAGE - 1);
28213db86aabSstevel #if defined(PCIC_DEBUG)
28223db86aabSstevel 				    pcic_err(dip, 8,
28233db86aabSstevel 					    "\tlen 0x%"PRIx64
28243db86aabSstevel 					    "addr 0x%"PRIx64"bbase 0x%"PRIx64
28253db86aabSstevel 					    " blen 0x%"PRIx64" flags 0x%x"
28263db86aabSstevel 					    " algn 0x%"PRIx64"\n",
28273db86aabSstevel 					    req.ra_len, req.ra_addr,
28283db86aabSstevel 					    req.ra_boundbase,
28293db86aabSstevel 					    req.ra_boundlen, req.ra_flags,
28303db86aabSstevel 					    req.ra_align_mask);
28313db86aabSstevel #endif
28323db86aabSstevel 
28333db86aabSstevel 				ret = pcmcia_alloc_mem(dip, &req, &res);
28343db86aabSstevel 				if (ret == DDI_FAILURE) {
28353db86aabSstevel 					mutex_exit(&pcic->pc_lock);
28363db86aabSstevel 					cmn_err(CE_WARN,
28373db86aabSstevel 					"\tpcmcia_alloc_mem() failed\n");
28383db86aabSstevel 					return (BAD_SIZE);
28393db86aabSstevel 				}
28403db86aabSstevel 				memp->pcw_base = res.ra_addr_lo;
28413db86aabSstevel 				base = memp->pcw_base;
28423db86aabSstevel 
28433db86aabSstevel #if defined(PCIC_DEBUG)
28443db86aabSstevel 				if (pcic_debug)
28453db86aabSstevel 					cmn_err(CE_CONT,
28463db86aabSstevel 						"\tsetwindow: new base=%x\n",
28473db86aabSstevel 						(unsigned)memp->pcw_base);
28483db86aabSstevel #endif
28493db86aabSstevel 				memp->pcw_len = window->WindowSize;
28503db86aabSstevel 
28513db86aabSstevel 				which = pcmcia_map_reg(pcic->dip,
28523db86aabSstevel 						window->child,
28533db86aabSstevel 						&res,
28543db86aabSstevel 						(uint32_t)(window->state &
28553db86aabSstevel 						    0xffff) |
28563db86aabSstevel 						    (window->socket << 16),
28573db86aabSstevel 						(caddr_t *)&memp->pcw_hostmem,
28583db86aabSstevel 						&memp->pcw_handle,
28593db86aabSstevel 						&window->attr, NULL);
28603db86aabSstevel 
28613db86aabSstevel 				if (which != DDI_SUCCESS) {
28623db86aabSstevel 
28633db86aabSstevel 					cmn_err(CE_WARN, "\tpcmcia_map_reg() "
28643db86aabSstevel 						"failed\n");
28653db86aabSstevel 
28663db86aabSstevel 				    res.ra_addr_lo = memp->pcw_base;
28673db86aabSstevel 				    res.ra_len = memp->pcw_len;
28683db86aabSstevel 				    (void) pcmcia_free_mem(pcic->dip, &res);
28693db86aabSstevel 
28703db86aabSstevel 				    mutex_exit(&pcic->pc_lock);
28713db86aabSstevel 
28723db86aabSstevel 				    return (BAD_WINDOW);
28733db86aabSstevel 				}
28743db86aabSstevel 				memp->pcw_status |= PCW_MAPPED;
28753db86aabSstevel #if defined(PCIC_DEBUG)
28763db86aabSstevel 				if (pcic_debug)
28773db86aabSstevel 					cmn_err(CE_CONT,
28783db86aabSstevel 						"\tmap=%x, hostmem=%p\n",
28793db86aabSstevel 						which,
28803db86aabSstevel 						(void *)memp->pcw_hostmem);
28813db86aabSstevel #endif
28823db86aabSstevel 			} else {
28833db86aabSstevel 				base = memp->pcw_base;
28843db86aabSstevel 			}
28853db86aabSstevel 
28863db86aabSstevel 			/* report the handle back to caller */
28873db86aabSstevel 			window->handle = memp->pcw_handle;
28883db86aabSstevel 
28893db86aabSstevel #if defined(PCIC_DEBUG)
28903db86aabSstevel 			if (pcic_debug) {
28913db86aabSstevel 				cmn_err(CE_CONT,
28923db86aabSstevel 					"\twindow mapped to %x@%x len=%d\n",
28933db86aabSstevel 					(unsigned)window->base,
28943db86aabSstevel 					(unsigned)memp->pcw_base,
28953db86aabSstevel 					memp->pcw_len);
28963db86aabSstevel 			}
28973db86aabSstevel #endif
28983db86aabSstevel 
28993db86aabSstevel 			/* find the register set offset */
29003db86aabSstevel 			select = win * PCIC_MEM_1_OFFSET;
29013db86aabSstevel #if defined(PCIC_DEBUG)
29023db86aabSstevel 			if (pcic_debug)
29033db86aabSstevel 				cmn_err(CE_CONT, "\tselect=%x\n", select);
29043db86aabSstevel #endif
29053db86aabSstevel 
29063db86aabSstevel 			/*
29073db86aabSstevel 			 * at this point, the register window indicator has
29083db86aabSstevel 			 * been converted to be an offset from the first
29093db86aabSstevel 			 * set of registers that are used for programming
29103db86aabSstevel 			 * the window mapping and the offset used to select
29113db86aabSstevel 			 * the correct set of registers to access the
29123db86aabSstevel 			 * specified socket.  This allows basing everything
29133db86aabSstevel 			 * off the _0 window
29143db86aabSstevel 			 */
29153db86aabSstevel 
29163db86aabSstevel 			/* map the physical page base address */
29173db86aabSstevel 			which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0;
29183db86aabSstevel 			which |= (window->speed <= MEM_SPEED_MIN) ?
29193db86aabSstevel 				SYSMEM_ZERO_WAIT : 0;
29203db86aabSstevel 
29213db86aabSstevel 			/* need to select register set */
29223db86aabSstevel 			select = PCIC_MEM_1_OFFSET * win;
29233db86aabSstevel 
29243db86aabSstevel 			pcic_putb(pcic, socket,
29253db86aabSstevel 					PCIC_SYSMEM_0_STARTLOW + select,
29263db86aabSstevel 					SYSMEM_LOW(base));
29273db86aabSstevel 			pcic_putb(pcic, socket,
29283db86aabSstevel 					PCIC_SYSMEM_0_STARTHI + select,
29293db86aabSstevel 					SYSMEM_HIGH(base) | which);
29303db86aabSstevel 
29313db86aabSstevel 			/*
29323db86aabSstevel 			 * Some adapters can decode window addresses greater
29333db86aabSstevel 			 * than 16-bits worth, so handle them here.
29343db86aabSstevel 			 */
29353db86aabSstevel 			switch (pcic->pc_type) {
29363db86aabSstevel 			case PCIC_INTEL_i82092:
29373db86aabSstevel 				pcic_putb(pcic, socket,
29383db86aabSstevel 						PCIC_82092_CPAGE,
29393db86aabSstevel 						SYSMEM_EXT(base));
29403db86aabSstevel 				break;
29413db86aabSstevel 			case PCIC_CL_PD6729:
29423db86aabSstevel 			case PCIC_CL_PD6730:
29433db86aabSstevel 				clext_reg_write(pcic, socket,
29443db86aabSstevel 						PCIC_CLEXT_MMAP0_UA + win,
29453db86aabSstevel 						SYSMEM_EXT(base));
29463db86aabSstevel 				break;
29473db86aabSstevel 			case PCIC_TI_PCI1130:
29483db86aabSstevel 				/*
29493db86aabSstevel 				 * Note that the TI chip has one upper byte
29503db86aabSstevel 				 * per socket so all windows get bound to a
29513db86aabSstevel 				 * 16MB segment.  This must be detected and
29523db86aabSstevel 				 * handled appropriately.  We can detect that
29533db86aabSstevel 				 * it is done by seeing if the pc_base has
29543db86aabSstevel 				 * changed and changing when the register
29553db86aabSstevel 				 * is first set.  This will force the bounds
29563db86aabSstevel 				 * to be correct.
29573db86aabSstevel 				 */
29583db86aabSstevel 				if (pcic->pc_bound == 0xffffffff) {
29593db86aabSstevel 					pcic_putb(pcic, socket,
29603db86aabSstevel 						    PCIC_TI_WINDOW_PAGE_PCI,
29613db86aabSstevel 						    SYSMEM_EXT(base));
29623db86aabSstevel 					pcic->pc_base = SYSMEM_EXT(base) << 24;
29633db86aabSstevel 					pcic->pc_bound = 0x1000000;
29643db86aabSstevel 				}
29653db86aabSstevel 				break;
29663db86aabSstevel 			case PCIC_TI_PCI1031:
29673db86aabSstevel 			case PCIC_TI_PCI1131:
29683db86aabSstevel 			case PCIC_TI_PCI1250:
29693db86aabSstevel 			case PCIC_TI_PCI1225:
29703db86aabSstevel 			case PCIC_TI_PCI1221:
29713db86aabSstevel 			case PCIC_SMC_34C90:
29723db86aabSstevel 			case PCIC_CL_PD6832:
29733db86aabSstevel 			case PCIC_RICOH_RL5C466:
29743db86aabSstevel 			case PCIC_TI_PCI1410:
29753db86aabSstevel 			case PCIC_ENE_1410:
29763db86aabSstevel 			case PCIC_TI_PCI1510:
29773db86aabSstevel 			case PCIC_TI_PCI1520:
29783db86aabSstevel 			case PCIC_O2_OZ6912:
29793db86aabSstevel 			case PCIC_TI_PCI1420:
29803db86aabSstevel 			case PCIC_ENE_1420:
29813db86aabSstevel 			case PCIC_TI_VENDOR:
29823db86aabSstevel 			case PCIC_TOSHIBA_TOPIC100:
29833db86aabSstevel 			case PCIC_TOSHIBA_TOPIC95:
29843db86aabSstevel 			case PCIC_TOSHIBA_VENDOR:
29853db86aabSstevel 			case PCIC_RICOH_VENDOR:
29863db86aabSstevel 			case PCIC_O2MICRO_VENDOR:
29873db86aabSstevel 				pcic_putb(pcic, socket,
29883db86aabSstevel 						PCIC_YENTA_MEM_PAGE + win,
29893db86aabSstevel 						SYSMEM_EXT(base));
29903db86aabSstevel 				break;
29913db86aabSstevel 			default:
29923db86aabSstevel 				cmn_err(CE_NOTE, "pcic_set_window: unknown "
29933db86aabSstevel 						"cardbus vendor:0x%X\n",
29943db86aabSstevel 						pcic->pc_type);
29953db86aabSstevel 				pcic_putb(pcic, socket,
29963db86aabSstevel 						PCIC_YENTA_MEM_PAGE + win,
29973db86aabSstevel 						SYSMEM_EXT(base));
29983db86aabSstevel 
29993db86aabSstevel 				break;
30003db86aabSstevel 			} /* switch */
30013db86aabSstevel 
30023db86aabSstevel 			/*
30033db86aabSstevel 			 * specify the length of the mapped range
30043db86aabSstevel 			 * we convert to pages (rounding up) so that
30053db86aabSstevel 			 * the hardware gets the right thing
30063db86aabSstevel 			 */
30073db86aabSstevel 			pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE;
30083db86aabSstevel 
30093db86aabSstevel 			/*
30103db86aabSstevel 			 * Setup this window's timing.
30113db86aabSstevel 			 */
30123db86aabSstevel 			switch (pcic->pc_type) {
30133db86aabSstevel 			case PCIC_CL_PD6729:
30143db86aabSstevel 			case PCIC_CL_PD6730:
30153db86aabSstevel 			case PCIC_CL_PD6710:
30163db86aabSstevel 			case PCIC_CL_PD6722:
30173db86aabSstevel 				wspeed = SYSMEM_CLTIMER_SET_0;
30183db86aabSstevel 				pcic_set_cdtimers(pcic, socket,
30193db86aabSstevel 							window->speed,
30203db86aabSstevel 							wspeed);
30213db86aabSstevel 				break;
30223db86aabSstevel 
30233db86aabSstevel 			case PCIC_INTEL_i82092:
30243db86aabSstevel 			default:
30253db86aabSstevel 				wspeed = pcic_calc_speed(pcic, window->speed);
30263db86aabSstevel 				break;
30273db86aabSstevel 			} /* switch */
30283db86aabSstevel 
30293db86aabSstevel #if defined(PCIC_DEBUG)
30303db86aabSstevel 			if (pcic_debug)
30313db86aabSstevel 				cmn_err(CE_CONT,
30323db86aabSstevel 					"\twindow %d speed bits = %x for "
30333db86aabSstevel 					"%dns\n",
30343db86aabSstevel 					win, (unsigned)wspeed, window->speed);
30353db86aabSstevel #endif
30363db86aabSstevel 
30373db86aabSstevel 			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select,
30383db86aabSstevel 					SYSMEM_LOW(base +
30393db86aabSstevel 						    (pages * PCIC_PAGE)-1));
30403db86aabSstevel 
30413db86aabSstevel 			wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1);
30423db86aabSstevel 			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select,
30433db86aabSstevel 					wspeed);
30443db86aabSstevel 
30453db86aabSstevel 			/*
30463db86aabSstevel 			 * now map the card's memory pages - we start with page
30473db86aabSstevel 			 * 0
30483db86aabSstevel 			 * we also default to AM -- set page might change it
30493db86aabSstevel 			 */
30503db86aabSstevel 			base = memp->pcw_base;
30513db86aabSstevel 			pcic_putb(pcic, socket,
30523db86aabSstevel 					PCIC_CARDMEM_0_LOW + select,
30533db86aabSstevel 					CARDMEM_LOW(0 - (uint32_t)base));
30543db86aabSstevel 
30553db86aabSstevel 			pcic_putb(pcic, socket,
30563db86aabSstevel 					PCIC_CARDMEM_0_HI + select,
30573db86aabSstevel 					CARDMEM_HIGH(0 - (uint32_t)base) |
30583db86aabSstevel 					CARDMEM_REG_ACTIVE);
30593db86aabSstevel 
30603db86aabSstevel 			/*
30613db86aabSstevel 			 * enable the window even though redundant
30623db86aabSstevel 			 * and SetPage may do it again.
30633db86aabSstevel 			 */
30643db86aabSstevel 			select = pcic_getb(pcic, socket,
30653db86aabSstevel 					PCIC_MAPPING_ENABLE);
30663db86aabSstevel 			select |= SYSMEM_WINDOW(win);
30673db86aabSstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30683db86aabSstevel 			memp->pcw_offset = 0;
30693db86aabSstevel 			memp->pcw_status |= PCW_ENABLED;
30703db86aabSstevel 		} else {
30713db86aabSstevel 			/*
30723db86aabSstevel 			 * not only do we unmap the memory, the
30733db86aabSstevel 			 * window has been turned off.
30743db86aabSstevel 			 */
30753db86aabSstevel 			if (which && memp->pcw_status & PCW_MAPPED) {
30763db86aabSstevel 				ddi_regs_map_free(&memp->pcw_handle);
30773db86aabSstevel 				res.ra_addr_lo = memp->pcw_base;
30783db86aabSstevel 				res.ra_len = memp->pcw_len;
30793db86aabSstevel 				(void) pcmcia_free_mem(pcic->dip, &res);
30803db86aabSstevel 				memp->pcw_hostmem = NULL;
30813db86aabSstevel 				memp->pcw_status &= ~PCW_MAPPED;
30823db86aabSstevel 			}
30833db86aabSstevel 
30843db86aabSstevel 			/* disable current mapping */
30853db86aabSstevel 			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
30863db86aabSstevel 			select &= ~SYSMEM_WINDOW(win);
30873db86aabSstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30883db86aabSstevel 			memp->pcw_status &= ~PCW_ENABLED;
30893db86aabSstevel 		}
30903db86aabSstevel 		memp->pcw_len = window->WindowSize;
30913db86aabSstevel 		window->handle = memp->pcw_handle;
30923db86aabSstevel #if defined(PCIC_DEBUG)
30933db86aabSstevel 		if (pcic_debug)
30943db86aabSstevel 			xxdmp_all_regs(pcic, window->socket, -1);
30953db86aabSstevel #endif
30963db86aabSstevel 	} else {
30973db86aabSstevel 		/*
30983db86aabSstevel 		 * This is a request for an IO window
30993db86aabSstevel 		 */
31003db86aabSstevel 		int win, tmp;
31013db86aabSstevel 		pcs_iowin_t *winp;
31023db86aabSstevel 				/* I/O windows */
31033db86aabSstevel #if defined(PCIC_DEBUG)
31043db86aabSstevel 		if (pcic_debug)
31053db86aabSstevel 			cmn_err(CE_CONT, "\twindow type is I/O\n");
31063db86aabSstevel #endif
31073db86aabSstevel 
31083db86aabSstevel 		/* only windows 0 and 1 can do I/O */
31093db86aabSstevel 		win = window->window % PCIC_NUMWINSOCK;
31103db86aabSstevel 		tmp = window->window / PCIC_NUMWINSOCK;
31113db86aabSstevel 
31123db86aabSstevel 		if (win >= PCIC_IOWINDOWS || tmp != window->socket) {
31133db86aabSstevel 			cmn_err(CE_WARN,
31143db86aabSstevel 				"\twindow is out of range (%d)\n",
31153db86aabSstevel 				window->window);
31163db86aabSstevel 			return (BAD_WINDOW);
31173db86aabSstevel 		}
31183db86aabSstevel 
31193db86aabSstevel 		mutex_enter(&pcic->pc_lock); /* protect the registers */
31203db86aabSstevel 
31213db86aabSstevel 		winp = &sockp->pcs_windows[win].io;
31223db86aabSstevel 		winp->pcw_speed = window->speed;
31233db86aabSstevel 		if (window->WindowSize != 1 && window->WindowSize & 1) {
31243db86aabSstevel 			/* we don't want an odd-size window */
31253db86aabSstevel 			window->WindowSize++;
31263db86aabSstevel 		}
31273db86aabSstevel 		winp->pcw_len = window->WindowSize;
31283db86aabSstevel 
31293db86aabSstevel 		if (window->state & WS_ENABLED) {
31303db86aabSstevel 			if (winp->pcw_status & PCW_MAPPED) {
31313db86aabSstevel 				ddi_regs_map_free(&winp->pcw_handle);
31323db86aabSstevel 				res.ra_addr_lo = winp->pcw_base;
31333db86aabSstevel 				res.ra_len = winp->pcw_len;
31343db86aabSstevel 				(void) pcmcia_free_io(pcic->dip, &res);
31353db86aabSstevel 				winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
31363db86aabSstevel 			}
31373db86aabSstevel 
31383db86aabSstevel 			/*
31393db86aabSstevel 			 * if the I/O address wasn't allocated, allocate
31403db86aabSstevel 			 *	it now. If it was allocated, it better
31413db86aabSstevel 			 *	be free to use.
31423db86aabSstevel 			 * The winp->pcw_offset value is set and used
31433db86aabSstevel 			 *	later on if the particular adapter
31443db86aabSstevel 			 *	that we're running on has the ability
31453db86aabSstevel 			 *	to translate IO accesses to the card
31463db86aabSstevel 			 *	(such as some adapters  in the Cirrus
31473db86aabSstevel 			 *	Logic family).
31483db86aabSstevel 			 */
31493db86aabSstevel 			winp->pcw_offset = 0;
31503db86aabSstevel 
31513db86aabSstevel 			/*
31523db86aabSstevel 			 * Setup the request parameters for the
31533db86aabSstevel 			 *	requested base and length. If
31543db86aabSstevel 			 *	we're on an adapter that has
31553db86aabSstevel 			 *	IO window offset registers, then
31563db86aabSstevel 			 *	we don't need a specific base
31573db86aabSstevel 			 *	address, just a length, and then
31583db86aabSstevel 			 *	we'll cause the correct IO address
31593db86aabSstevel 			 *	to be generated on the socket by
31603db86aabSstevel 			 *	setting up the IO window offset
31613db86aabSstevel 			 *	registers.
31623db86aabSstevel 			 * For adapters that support this capability, we
31633db86aabSstevel 			 *	always use the IO window offset registers,
31643db86aabSstevel 			 *	even if the passed base/length would be in
31653db86aabSstevel 			 *	range.
31663db86aabSstevel 			 */
31673db86aabSstevel 			base = window->base;
31683db86aabSstevel 			bzero(&req, sizeof (req));
31693db86aabSstevel 			req.ra_len = window->WindowSize;
31703db86aabSstevel 
31713db86aabSstevel 			req.ra_addr = (uint64_t)
31723db86aabSstevel 				((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base);
31733db86aabSstevel 			req.ra_flags = (req.ra_addr) ?
31743db86aabSstevel 						NDI_RA_ALLOC_SPECIFIED : 0;
31753db86aabSstevel 
31763db86aabSstevel 			req.ra_flags |= NDI_RA_ALIGN_SIZE;
31773db86aabSstevel 			/* need to rethink this */
31783db86aabSstevel 			req.ra_boundbase = pcic->pc_iobase;
31793db86aabSstevel 			req.ra_boundlen = pcic->pc_iobound;
31803db86aabSstevel 			req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
31813db86aabSstevel 
31823db86aabSstevel #if defined(PCIC_DEBUG)
31833db86aabSstevel 			    pcic_err(dip, 8,
31843db86aabSstevel 					"\tlen 0x%"PRIx64" addr 0x%"PRIx64
31853db86aabSstevel 					"bbase 0x%"PRIx64
31863db86aabSstevel 					"blen 0x%"PRIx64" flags 0x%x algn 0x%"
31873db86aabSstevel 					PRIx64"\n",
31883db86aabSstevel 					req.ra_len, (uint64_t)req.ra_addr,
31893db86aabSstevel 					req.ra_boundbase,
31903db86aabSstevel 					req.ra_boundlen, req.ra_flags,
31913db86aabSstevel 					req.ra_align_mask);
31923db86aabSstevel #endif
31933db86aabSstevel 
31943db86aabSstevel 			/*
31953db86aabSstevel 			 * Try to allocate the space. If we fail this,
31963db86aabSstevel 			 *	return the appropriate error depending
31973db86aabSstevel 			 *	on whether the caller specified a
31983db86aabSstevel 			 *	specific base address or not.
31993db86aabSstevel 			 */
32003db86aabSstevel 			if (pcmcia_alloc_io(dip, &req, &res) == DDI_FAILURE) {
32013db86aabSstevel 				winp->pcw_status &= ~PCW_ENABLED;
32023db86aabSstevel 				mutex_exit(&pcic->pc_lock);
32033db86aabSstevel 				cmn_err(CE_WARN, "Failed to alloc I/O:\n"
32043db86aabSstevel 					"\tlen 0x%" PRIx64 " addr 0x%" PRIx64
32053db86aabSstevel 					"bbase 0x%" PRIx64
32063db86aabSstevel 					"blen 0x%" PRIx64 "flags 0x%x"
32073db86aabSstevel 					"algn 0x%" PRIx64 "\n",
32083db86aabSstevel 					req.ra_len, req.ra_addr,
32093db86aabSstevel 					req.ra_boundbase,
32103db86aabSstevel 					req.ra_boundlen, req.ra_flags,
32113db86aabSstevel 					req.ra_align_mask);
32123db86aabSstevel 
32133db86aabSstevel 				return (base?BAD_BASE:BAD_SIZE);
32143db86aabSstevel 			} /* pcmcia_alloc_io */
32153db86aabSstevel 
32163db86aabSstevel 			/*
32173db86aabSstevel 			 * Don't change the original base. Either we use
32183db86aabSstevel 			 * the offset registers below (PCF_IO_REMAP is set)
32193db86aabSstevel 			 * or it was allocated correctly anyway.
32203db86aabSstevel 			 */
32213db86aabSstevel 			winp->pcw_base = res.ra_addr_lo;
32223db86aabSstevel 
32233db86aabSstevel #if defined(PCIC_DEBUG)
32243db86aabSstevel 			    pcic_err(dip, 8,
32253db86aabSstevel 				    "\tsetwindow: new base=%x orig base 0x%x\n",
32263db86aabSstevel 				    (unsigned)winp->pcw_base, base);
32273db86aabSstevel #endif
32283db86aabSstevel 
32293db86aabSstevel 			if ((which = pcmcia_map_reg(pcic->dip,
32303db86aabSstevel 						window->child,
32313db86aabSstevel 						&res,
32323db86aabSstevel 						(uint32_t)(window->state &
32333db86aabSstevel 						    0xffff) |
32343db86aabSstevel 						    (window->socket << 16),
32353db86aabSstevel 						(caddr_t *)&winp->pcw_hostmem,
32363db86aabSstevel 						&winp->pcw_handle,
32373db86aabSstevel 						&window->attr,
32383db86aabSstevel 						base)) != DDI_SUCCESS) {
32393db86aabSstevel 
32403db86aabSstevel 					cmn_err(CE_WARN, "pcmcia_map_reg()"
32413db86aabSstevel 						"failed\n");
32423db86aabSstevel 
32433db86aabSstevel 				    res.ra_addr_lo = winp->pcw_base;
32443db86aabSstevel 				    res.ra_len = winp->pcw_len;
32453db86aabSstevel 				    (void) pcmcia_free_io(pcic->dip, &res);
32463db86aabSstevel 
32473db86aabSstevel 				    mutex_exit(&pcic->pc_lock);
32483db86aabSstevel 				    return (BAD_WINDOW);
32493db86aabSstevel 			}
32503db86aabSstevel 
32513db86aabSstevel 			window->handle = winp->pcw_handle;
32523db86aabSstevel 			winp->pcw_status |= PCW_MAPPED;
32533db86aabSstevel 
32543db86aabSstevel 			/* find the register set offset */
32553db86aabSstevel 			select = win * PCIC_IO_OFFSET;
32563db86aabSstevel 
32573db86aabSstevel #if defined(PCIC_DEBUG)
32583db86aabSstevel 			if (pcic_debug) {
32593db86aabSstevel 				cmn_err(CE_CONT,
32603db86aabSstevel 					"\tenable: window=%d, select=%x, "
32613db86aabSstevel 					"base=%x, handle=%p\n",
32623db86aabSstevel 					win, select,
32633db86aabSstevel 					(unsigned)window->base,
32643db86aabSstevel 					(void *)window->handle);
32653db86aabSstevel 			}
32663db86aabSstevel #endif
32673db86aabSstevel 			/*
32683db86aabSstevel 			 * at this point, the register window indicator has
32693db86aabSstevel 			 * been converted to be an offset from the first
32703db86aabSstevel 			 * set of registers that are used for programming
32713db86aabSstevel 			 * the window mapping and the offset used to select
32723db86aabSstevel 			 * the correct set of registers to access the
32733db86aabSstevel 			 * specified socket.  This allows basing everything
32743db86aabSstevel 			 * off the _0 window
32753db86aabSstevel 			 */
32763db86aabSstevel 
32773db86aabSstevel 			/* map the I/O base in */
32783db86aabSstevel 			pcic_putb(pcic, socket,
32793db86aabSstevel 					PCIC_IO_ADDR_0_STARTLOW + select,
32803db86aabSstevel 					LOW_BYTE((uint32_t)winp->pcw_base));
32813db86aabSstevel 			pcic_putb(pcic, socket,
32823db86aabSstevel 					PCIC_IO_ADDR_0_STARTHI + select,
32833db86aabSstevel 					HIGH_BYTE((uint32_t)winp->pcw_base));
32843db86aabSstevel 
32853db86aabSstevel 			pcic_putb(pcic, socket,
32863db86aabSstevel 					PCIC_IO_ADDR_0_STOPLOW + select,
32873db86aabSstevel 					LOW_BYTE((uint32_t)winp->pcw_base +
32883db86aabSstevel 						window->WindowSize - 1));
32893db86aabSstevel 			pcic_putb(pcic, socket,
32903db86aabSstevel 					PCIC_IO_ADDR_0_STOPHI + select,
32913db86aabSstevel 					HIGH_BYTE((uint32_t)winp->pcw_base +
32923db86aabSstevel 						window->WindowSize - 1));
32933db86aabSstevel 
32943db86aabSstevel 			/*
32953db86aabSstevel 			 * We've got the requested IO space, now see if we
32963db86aabSstevel 			 *	need to adjust the IO window offset registers
32973db86aabSstevel 			 *	so that the correct IO address is generated
32983db86aabSstevel 			 *	at the socket. If this window doesn't have
32993db86aabSstevel 			 *	this capability, then we're all done setting
33003db86aabSstevel 			 *	up the IO resources.
33013db86aabSstevel 			 */
33023db86aabSstevel 			if (pcic->pc_flags & PCF_IO_REMAP) {
33033db86aabSstevel 
33043db86aabSstevel 
33053db86aabSstevel 				/*
33063db86aabSstevel 				 * Note that only 16 bits are used to program
33073db86aabSstevel 				 * the registers but leave 32 bits on pcw_offset
33083db86aabSstevel 				 * so that we can generate the original base
33093db86aabSstevel 				 * in get_window()
33103db86aabSstevel 				 */
33113db86aabSstevel 				winp->pcw_offset = (base - winp->pcw_base);
33123db86aabSstevel 
33133db86aabSstevel 				pcic_putb(pcic, socket,
33143db86aabSstevel 					PCIC_IO_OFFSET_LOW +
33153db86aabSstevel 					(win * PCIC_IO_OFFSET_OFFSET),
33163db86aabSstevel 					winp->pcw_offset & 0x0ff);
33173db86aabSstevel 				pcic_putb(pcic, socket,
33183db86aabSstevel 					PCIC_IO_OFFSET_HI +
33193db86aabSstevel 					(win * PCIC_IO_OFFSET_OFFSET),
33203db86aabSstevel 					(winp->pcw_offset >> 8) & 0x0ff);
33213db86aabSstevel 
33223db86aabSstevel 			} /* PCF_IO_REMAP */
33233db86aabSstevel 
33243db86aabSstevel 			/* now get the other details (size, etc) right */
33253db86aabSstevel 
33263db86aabSstevel 			/*
33273db86aabSstevel 			 * Set the data size control bits here. Most of the
33283db86aabSstevel 			 *	adapters will ignore IOMEM_16BIT when
33293db86aabSstevel 			 *	IOMEM_IOCS16 is set, except for the Intel
33303db86aabSstevel 			 *	82092, which only pays attention to the
33313db86aabSstevel 			 *	IOMEM_16BIT bit. Sigh... Intel can't even
33323db86aabSstevel 			 *	make a proper clone of their own chip.
33333db86aabSstevel 			 * The 82092 also apparently can't set the timing
33343db86aabSstevel 			 *	of I/O windows.
33353db86aabSstevel 			 */
33363db86aabSstevel 			which = (window->state & WS_16BIT) ?
33373db86aabSstevel 					(IOMEM_16BIT | IOMEM_IOCS16) : 0;
33383db86aabSstevel 
33393db86aabSstevel 			switch (pcic->pc_type) {
33403db86aabSstevel 			case PCIC_CL_PD6729:
33413db86aabSstevel 			case PCIC_CL_PD6730:
33423db86aabSstevel 			case PCIC_CL_PD6710:
33433db86aabSstevel 			case PCIC_CL_PD6722:
33443db86aabSstevel 			case PCIC_CL_PD6832:
33453db86aabSstevel 				/*
33463db86aabSstevel 				 * Select Timer Set 1 - this will take
33473db86aabSstevel 				 *	effect when the PCIC_IO_CONTROL
33483db86aabSstevel 				 *	register is written to later on;
33493db86aabSstevel 				 *	the call to pcic_set_cdtimers
33503db86aabSstevel 				 *	just sets up the timer itself.
33513db86aabSstevel 				 */
33523db86aabSstevel 				which |= IOMEM_CLTIMER_SET_1;
33533db86aabSstevel 				pcic_set_cdtimers(pcic, socket,
33543db86aabSstevel 							window->speed,
33553db86aabSstevel 							IOMEM_CLTIMER_SET_1);
33563db86aabSstevel 				which |= IOMEM_IOCS16;
33573db86aabSstevel 				break;
33583db86aabSstevel 			case PCIC_TI_PCI1031:
33593db86aabSstevel 
33603db86aabSstevel 				if (window->state & WS_16BIT)
33613db86aabSstevel 				    which |= IOMEM_WAIT16;
33623db86aabSstevel 
33633db86aabSstevel 				break;
33643db86aabSstevel 			case PCIC_TI_PCI1130:
33653db86aabSstevel 
33663db86aabSstevel 				if (window->state & WS_16BIT)
33673db86aabSstevel 				    which |= IOMEM_WAIT16;
33683db86aabSstevel 
33693db86aabSstevel 				break;
33703db86aabSstevel 			case PCIC_INTEL_i82092:
33713db86aabSstevel 				break;
33723db86aabSstevel 			default:
33733db86aabSstevel 				if (window->speed >
33743db86aabSstevel 						mhztons(pcic->bus_speed) * 3)
33753db86aabSstevel 				    which |= IOMEM_WAIT16;
33763db86aabSstevel #ifdef notdef
33773db86aabSstevel 				if (window->speed <
33783db86aabSstevel 						mhztons(pcic->bus_speed) * 6)
33793db86aabSstevel 				    which |= IOMEM_ZERO_WAIT;
33803db86aabSstevel #endif
33813db86aabSstevel 				break;
33823db86aabSstevel 			} /* switch (pc_type) */
33833db86aabSstevel 
33843db86aabSstevel 			/*
33853db86aabSstevel 			 * Setup the data width and timing
33863db86aabSstevel 			 */
33873db86aabSstevel 			select = pcic_getb(pcic, socket, PCIC_IO_CONTROL);
33883db86aabSstevel 			select &= ~(PCIC_IO_WIN_MASK << (win * 4));
33893db86aabSstevel 			select |= IOMEM_SETWIN(win, which);
33903db86aabSstevel 			pcic_putb(pcic, socket, PCIC_IO_CONTROL, select);
33913db86aabSstevel 
33923db86aabSstevel 			/*
33933db86aabSstevel 			 * Enable the IO window
33943db86aabSstevel 			 */
33953db86aabSstevel 			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
33963db86aabSstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
33973db86aabSstevel 						select | IOMEM_WINDOW(win));
33983db86aabSstevel 
33993db86aabSstevel 			winp->pcw_status |= PCW_ENABLED;
34003db86aabSstevel 
34013db86aabSstevel #if defined(PCIC_DEBUG)
34023db86aabSstevel 			if (pcic_debug) {
34033db86aabSstevel 				cmn_err(CE_CONT,
34043db86aabSstevel 					"\twhich = %x, select = %x (%x)\n",
34053db86aabSstevel 					which, select,
34063db86aabSstevel 					IOMEM_SETWIN(win, which));
34073db86aabSstevel 				xxdmp_all_regs(pcic, window->socket * 0x40, 24);
34083db86aabSstevel 			}
34093db86aabSstevel #endif
34103db86aabSstevel 		} else {
34113db86aabSstevel 			/*
34123db86aabSstevel 			 * not only do we unmap the IO space, the
34133db86aabSstevel 			 * window has been turned off.
34143db86aabSstevel 			 */
34153db86aabSstevel 			if (winp->pcw_status & PCW_MAPPED) {
34163db86aabSstevel 				ddi_regs_map_free(&winp->pcw_handle);
34173db86aabSstevel 				res.ra_addr_lo = winp->pcw_base;
34183db86aabSstevel 				res.ra_len = winp->pcw_len;
34193db86aabSstevel 				(void) pcmcia_free_io(pcic->dip, &res);
34203db86aabSstevel 				winp->pcw_status &= ~PCW_MAPPED;
34213db86aabSstevel 			}
34223db86aabSstevel 
34233db86aabSstevel 			/* disable current mapping */
34243db86aabSstevel 			select = pcic_getb(pcic, socket,
34253db86aabSstevel 						PCIC_MAPPING_ENABLE);
34263db86aabSstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
34273db86aabSstevel 					select &= ~IOMEM_WINDOW(win));
34283db86aabSstevel 			winp->pcw_status &= ~PCW_ENABLED;
34293db86aabSstevel 
34303db86aabSstevel 			winp->pcw_base = 0;
34313db86aabSstevel 			winp->pcw_len = 0;
34323db86aabSstevel 			winp->pcw_offset = 0;
34333db86aabSstevel 			window->base = 0;
34343db86aabSstevel 			/* now make sure we don't accidentally re-enable */
34353db86aabSstevel 			/* find the register set offset */
34363db86aabSstevel 			select = win * PCIC_IO_OFFSET;
34373db86aabSstevel 			pcic_putb(pcic, socket,
34383db86aabSstevel 					PCIC_IO_ADDR_0_STARTLOW + select, 0);
34393db86aabSstevel 			pcic_putb(pcic, socket,
34403db86aabSstevel 					PCIC_IO_ADDR_0_STARTHI + select, 0);
34413db86aabSstevel 			pcic_putb(pcic, socket,
34423db86aabSstevel 					PCIC_IO_ADDR_0_STOPLOW + select, 0);
34433db86aabSstevel 			pcic_putb(pcic, socket,
34443db86aabSstevel 					PCIC_IO_ADDR_0_STOPHI + select, 0);
34453db86aabSstevel 		}
34463db86aabSstevel 	}
34473db86aabSstevel 	mutex_exit(&pcic->pc_lock);
34483db86aabSstevel 
34493db86aabSstevel 	return (SUCCESS);
34503db86aabSstevel }
34513db86aabSstevel 
34523db86aabSstevel /*
34533db86aabSstevel  * pcic_card_state()
34543db86aabSstevel  *	compute the instantaneous Card State information
34553db86aabSstevel  */
34563db86aabSstevel static int
34573db86aabSstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp)
34583db86aabSstevel {
34593db86aabSstevel 	int value, result;
34603db86aabSstevel #if defined(PCIC_DEBUG)
34613db86aabSstevel 	int orig_value;
34623db86aabSstevel #endif
34633db86aabSstevel 
34643db86aabSstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
34653db86aabSstevel 
34663db86aabSstevel 	value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS);
34673db86aabSstevel 
34683db86aabSstevel #if defined(PCIC_DEBUG)
34693db86aabSstevel 	orig_value = value;
34703db86aabSstevel 	if (pcic_debug >= 8)
34713db86aabSstevel 		cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n",
34723db86aabSstevel 			(void *)sockp,
34733db86aabSstevel 			value,
34743db86aabSstevel 			"\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
34753db86aabSstevel 			sockp->pcs_socket);
34763db86aabSstevel #endif
34773db86aabSstevel 	/*
34783db86aabSstevel 	 * Lie to socket services if we are not ready.
34793db86aabSstevel 	 * This is when we are starting up or during debounce timeouts
34803db86aabSstevel 	 * or if the card is a cardbus card.
34813db86aabSstevel 	 */
34823db86aabSstevel 	if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) &&
34833db86aabSstevel 	    !sockp->pcs_debounce_id &&
34843db86aabSstevel 	    (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) {
34853db86aabSstevel 		result = SBM_CD;
34863db86aabSstevel 
34873db86aabSstevel 		if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON))
34883db86aabSstevel 			result |= SBM_WP;
34893db86aabSstevel 		if (value & PCIC_POWER_ON) {
34903db86aabSstevel 			if (value & PCIC_READY)
34913db86aabSstevel 				result |= SBM_RDYBSY;
34923db86aabSstevel 			value = (~value) & (PCIC_BVD1 | PCIC_BVD2);
34933db86aabSstevel 			if (value & PCIC_BVD1)
34943db86aabSstevel 				result |= SBM_BVD1;
34953db86aabSstevel 			if (value & PCIC_BVD2)
34963db86aabSstevel 				result |= SBM_BVD2;
34973db86aabSstevel 		}
34983db86aabSstevel 	} else
34993db86aabSstevel 		result = 0;
35003db86aabSstevel 
35013db86aabSstevel 	mutex_exit(&pcic->pc_lock);
35023db86aabSstevel 
35033db86aabSstevel #if defined(PCIC_DEBUG)
35043db86aabSstevel 	pcic_err(pcic->dip, 8,
35053db86aabSstevel 	    "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n",
35063db86aabSstevel 	    (void *) sockp, orig_value,
35073db86aabSstevel 	    "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35083db86aabSstevel 	    sockp->pcs_socket, result);
35093db86aabSstevel #endif
35103db86aabSstevel 
35113db86aabSstevel 	return (result);
35123db86aabSstevel }
35133db86aabSstevel 
35143db86aabSstevel /*
35153db86aabSstevel  * pcic_set_page()
35163db86aabSstevel  *	SocketServices SetPage function
35173db86aabSstevel  *	set the page of PC Card memory that should be in the mapped
35183db86aabSstevel  *	window
35193db86aabSstevel  */
35203db86aabSstevel /*ARGSUSED*/
35213db86aabSstevel static int
35223db86aabSstevel pcic_set_page(dev_info_t *dip, set_page_t *page)
35233db86aabSstevel {
35243db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
35253db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
35263db86aabSstevel 	int select;
35273db86aabSstevel 	int which, socket, window;
35283db86aabSstevel 	uint32_t base;
35293db86aabSstevel 	pcs_memwin_t *memp;
35303db86aabSstevel 
35313db86aabSstevel 	/* get real socket/window numbers */
35323db86aabSstevel 	window = page->window % PCIC_NUMWINSOCK;
35333db86aabSstevel 	socket = page->window / PCIC_NUMWINSOCK;
35343db86aabSstevel 
35353db86aabSstevel #if defined(PCIC_DEBUG)
35363db86aabSstevel 	if (pcic_debug) {
35373db86aabSstevel 		cmn_err(CE_CONT,
35383db86aabSstevel 			"pcic_set_page: window=%d, socket=%d, page=%d\n",
35393db86aabSstevel 			window, socket, page->page);
35403db86aabSstevel 	}
35413db86aabSstevel #endif
35423db86aabSstevel 	/* only windows 2-6 work on memory */
35433db86aabSstevel 	if (window < PCIC_IOWINDOWS)
35443db86aabSstevel 		return (BAD_WINDOW);
35453db86aabSstevel 
35463db86aabSstevel 	/* only one page supported (but any size) */
35473db86aabSstevel 	if (page->page != 0)
35483db86aabSstevel 		return (BAD_PAGE);
35493db86aabSstevel 
35503db86aabSstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
35513db86aabSstevel 
35523db86aabSstevel 	memp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
35533db86aabSstevel 	window -= PCIC_IOWINDOWS;
35543db86aabSstevel 
35553db86aabSstevel #if defined(PCIC_DEBUG)
35563db86aabSstevel 	if (pcic_debug)
35573db86aabSstevel 		cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n",
35583db86aabSstevel 			(uint32_t)memp->pcw_base,
35593db86aabSstevel 			(void *)memp->pcw_hostmem, memp->pcw_len);
35603db86aabSstevel #endif
35613db86aabSstevel 
35623db86aabSstevel 	/* window must be enabled */
35633db86aabSstevel 	if (!(memp->pcw_status & PCW_ENABLED))
35643db86aabSstevel 		return (BAD_ATTRIBUTE);
35653db86aabSstevel 
35663db86aabSstevel 	/* find the register set offset */
35673db86aabSstevel 	select = window * PCIC_MEM_1_OFFSET;
35683db86aabSstevel #if defined(PCIC_DEBUG)
35693db86aabSstevel 	if (pcic_debug)
35703db86aabSstevel 		cmn_err(CE_CONT, "\tselect=%x\n", select);
35713db86aabSstevel #endif
35723db86aabSstevel 
35733db86aabSstevel 	/*
35743db86aabSstevel 	 * now map the card's memory pages - we start with page 0
35753db86aabSstevel 	 */
35763db86aabSstevel 
35773db86aabSstevel 	which = 0;		/* assume simple case */
35783db86aabSstevel 	if (page->state & PS_ATTRIBUTE) {
35793db86aabSstevel 		which |= CARDMEM_REG_ACTIVE;
35803db86aabSstevel 		memp->pcw_status |= PCW_ATTRIBUTE;
35813db86aabSstevel 	} else {
35823db86aabSstevel 		memp->pcw_status &= ~PCW_ATTRIBUTE;
35833db86aabSstevel 	}
35843db86aabSstevel 
35853db86aabSstevel 	/*
35863db86aabSstevel 	 * if caller says Write Protect, enforce it.
35873db86aabSstevel 	 */
35883db86aabSstevel 	if (page->state & PS_WP) {
35893db86aabSstevel 		which |= CARDMEM_WRITE_PROTECT;
35903db86aabSstevel 		memp->pcw_status |= PCW_WP;
35913db86aabSstevel 	} else {
35923db86aabSstevel 		memp->pcw_status &= ~PCW_WP;
35933db86aabSstevel 	}
35943db86aabSstevel #if defined(PCIC_DEBUG)
35953db86aabSstevel 	if (pcic_debug) {
35963db86aabSstevel 		cmn_err(CE_CONT, "\tmemory type = %s\n",
35973db86aabSstevel 			(which & CARDMEM_REG_ACTIVE) ? "attribute" : "common");
35983db86aabSstevel 		if (which & CARDMEM_WRITE_PROTECT)
35993db86aabSstevel 			cmn_err(CE_CONT, "\twrite protect\n");
36003db86aabSstevel 		cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n",
36013db86aabSstevel 			(unsigned)page->offset,
36023db86aabSstevel 			(unsigned)memp->pcw_base,
36033db86aabSstevel 			(int)page->offset - (int)memp->pcw_base & 0xffffff);
36043db86aabSstevel 	}
36053db86aabSstevel #endif
36063db86aabSstevel 	/* address computation based on 64MB range and not larger */
36073db86aabSstevel 	base = (uint32_t)memp->pcw_base & 0x3ffffff;
36083db86aabSstevel 	pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select,
36093db86aabSstevel 	    CARDMEM_LOW((int)page->offset - (int)base));
36103db86aabSstevel 	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select);
36113db86aabSstevel 	pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select,
36123db86aabSstevel 	    CARDMEM_HIGH((int)page->offset - base) | which);
36133db86aabSstevel 	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select);
36143db86aabSstevel 
36153db86aabSstevel 	/*
36163db86aabSstevel 	 * while not really necessary, this just makes sure
36173db86aabSstevel 	 * nothing turned the window off behind our backs
36183db86aabSstevel 	 */
36193db86aabSstevel 	which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36203db86aabSstevel 	which |= SYSMEM_WINDOW(window);
36213db86aabSstevel 	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which);
36223db86aabSstevel 	(void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36233db86aabSstevel 
36243db86aabSstevel 	memp->pcw_offset = (off_t)page->offset;
36253db86aabSstevel 
36263db86aabSstevel #if defined(PCIC_DEBUG)
36273db86aabSstevel 	if (pcic_debug) {
36283db86aabSstevel 		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36293db86aabSstevel 			(void *)memp->pcw_hostmem,
36303db86aabSstevel 			(uint32_t)*memp->pcw_hostmem);
36313db86aabSstevel 
36323db86aabSstevel 		xxdmp_all_regs(pcic, socket, -1);
36333db86aabSstevel 
36343db86aabSstevel 		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36353db86aabSstevel 			(void *)memp->pcw_hostmem,
36363db86aabSstevel 			(uint32_t)*memp->pcw_hostmem);
36373db86aabSstevel 	}
36383db86aabSstevel #endif
36393db86aabSstevel 
36403db86aabSstevel 	if (which & PCW_ATTRIBUTE)
36413db86aabSstevel 		pcic_mswait(pcic, socket, 2);
36423db86aabSstevel 
36433db86aabSstevel 	mutex_exit(&pcic->pc_lock);
36443db86aabSstevel 
36453db86aabSstevel 	return (SUCCESS);
36463db86aabSstevel }
36473db86aabSstevel 
36483db86aabSstevel /*
36493db86aabSstevel  * pcic_set_vcc_level()
36503db86aabSstevel  *
36513db86aabSstevel  *	set voltage based on adapter information
36523db86aabSstevel  *
36533db86aabSstevel  *	this routine implements a limited solution for support of 3.3v cards.
36543db86aabSstevel  *	the general solution, which would fully support the pcmcia spec
36553db86aabSstevel  *	as far as allowing client drivers to request which voltage levels
36563db86aabSstevel  *	to be set, requires more framework support and driver changes - ess
36573db86aabSstevel  */
36583db86aabSstevel static int
36593db86aabSstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket)
36603db86aabSstevel {
36613db86aabSstevel 	uint32_t socket_present_state;
36623db86aabSstevel 
36633db86aabSstevel #if defined(PCIC_DEBUG)
36643db86aabSstevel 	if (pcic_debug) {
36653db86aabSstevel 		cmn_err(CE_CONT,
36663db86aabSstevel 			"pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n",
36673db86aabSstevel 			(void *)pcic, socket->VccLevel);
36683db86aabSstevel 	}
36693db86aabSstevel #endif
36703db86aabSstevel 
36713db86aabSstevel 	/*
36723db86aabSstevel 	 * check VccLevel
36733db86aabSstevel 	 * if this is zero, power is being turned off
36743db86aabSstevel 	 * if it is non-zero, power is being turned on.
36753db86aabSstevel 	 */
36763db86aabSstevel 	if (socket->VccLevel == 0) {
36773db86aabSstevel 		return (0);
36783db86aabSstevel 	}
36793db86aabSstevel 
36803db86aabSstevel 	/*
36813db86aabSstevel 	 * range checking for sanity's sake
36823db86aabSstevel 	 */
36833db86aabSstevel 	if (socket->VccLevel >= pcic->pc_numpower) {
36843db86aabSstevel 		return (BAD_VCC);
36853db86aabSstevel 	}
36863db86aabSstevel 
36873db86aabSstevel 	switch (pcic->pc_io_type) {
36883db86aabSstevel 	/*
36893db86aabSstevel 	 * Yenta-compliant adapters have vcc info in the extended registers
36903db86aabSstevel 	 * Other adapters can be added as needed, but the 'default' case
36913db86aabSstevel 	 * has been left as it was previously so as not to break existing
36923db86aabSstevel 	 * adapters.
36933db86aabSstevel 	 */
36943db86aabSstevel 	case PCIC_IO_TYPE_YENTA:
36953db86aabSstevel 		/*
36963db86aabSstevel 		 * Here we ignore the VccLevel passed in and read the
36973db86aabSstevel 		 * card type from the adapter socket present state register
36983db86aabSstevel 		 */
36993db86aabSstevel 		socket_present_state =
37003db86aabSstevel 			ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr +
37013db86aabSstevel 				PCIC_PRESENT_STATE_REG));
37023db86aabSstevel #if defined(PCIC_DEBUG)
37033db86aabSstevel 		if (pcic_debug) {
37043db86aabSstevel 			cmn_err(CE_CONT,
37053db86aabSstevel 				"socket present state = 0x%x\n",
37063db86aabSstevel 				socket_present_state);
37073db86aabSstevel 		}
37083db86aabSstevel #endif
37093db86aabSstevel 		switch (socket_present_state & PCIC_VCC_MASK) {
37103db86aabSstevel 			case PCIC_VCC_3VCARD:
37113db86aabSstevel 				/* fall through */
37123db86aabSstevel 			case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD:
37133db86aabSstevel 				socket->VccLevel = PCIC_VCC_3VLEVEL;
37143db86aabSstevel 				return
37153db86aabSstevel 				    (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE);
37163db86aabSstevel 			case PCIC_VCC_5VCARD:
37173db86aabSstevel 				socket->VccLevel = PCIC_VCC_5VLEVEL;
37183db86aabSstevel 				return
37193db86aabSstevel 				    (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37203db86aabSstevel 			default:
37213db86aabSstevel 				/*
37223db86aabSstevel 				 * if no card is present, this can be the
37233db86aabSstevel 				 * case of a client making a SetSocket call
37243db86aabSstevel 				 * after card removal. In this case we return
37253db86aabSstevel 				 * the current power level
37263db86aabSstevel 				 */
37273db86aabSstevel 				return ((unsigned)ddi_get8(pcic->handle,
37283db86aabSstevel 				    pcic->ioaddr + CB_R2_OFFSET +
37293db86aabSstevel 					PCIC_POWER_CONTROL));
37303db86aabSstevel 		}
37313db86aabSstevel 
37323db86aabSstevel 	default:
37333db86aabSstevel 
37343db86aabSstevel 		switch (socket->VccLevel) {
37353db86aabSstevel 		case PCIC_VCC_3VLEVEL:
37363db86aabSstevel 			return (BAD_VCC);
37373db86aabSstevel 		case PCIC_VCC_5VLEVEL:
37383db86aabSstevel 			/* enable Vcc */
37393db86aabSstevel 			return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37403db86aabSstevel 		default:
37413db86aabSstevel 			return (BAD_VCC);
37423db86aabSstevel 		}
37433db86aabSstevel 	}
37443db86aabSstevel }
37453db86aabSstevel 
37463db86aabSstevel 
37473db86aabSstevel /*
37483db86aabSstevel  * pcic_set_socket()
37493db86aabSstevel  *	Socket Services SetSocket call
37503db86aabSstevel  *	sets basic socket configuration
37513db86aabSstevel  */
37523db86aabSstevel static int
37533db86aabSstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket)
37543db86aabSstevel {
37553db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
37563db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
37573db86aabSstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket];
37583db86aabSstevel 	int irq, interrupt, mirq;
37593db86aabSstevel 	int powerlevel = 0;
37603db86aabSstevel 	int ind, value, orig_pwrctl;
37613db86aabSstevel 
37623db86aabSstevel #if defined(PCIC_DEBUG)
37633db86aabSstevel 	if (pcic_debug) {
37643db86aabSstevel 		cmn_err(CE_CONT,
37653db86aabSstevel 		    "pcic_set_socket(dip=%p, socket=%d)"
37663db86aabSstevel 		    " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip,
37673db86aabSstevel 		    socket->socket, socket->VccLevel, socket->Vpp1Level,
37683db86aabSstevel 		    socket->Vpp2Level);
37693db86aabSstevel 	}
37703db86aabSstevel #endif
37713db86aabSstevel 	/*
37723db86aabSstevel 	 * check VccLevel, etc. before setting mutex
37733db86aabSstevel 	 * if this is zero, power is being turned off
37743db86aabSstevel 	 * if it is non-zero, power is being turned on.
37753db86aabSstevel 	 * the default case is to assume Vcc only.
37763db86aabSstevel 	 */
37773db86aabSstevel 
37783db86aabSstevel 	/* this appears to be very implementation specific */
37793db86aabSstevel 
37803db86aabSstevel 	if (socket->Vpp1Level != socket->Vpp2Level)
37813db86aabSstevel 		return (BAD_VPP);
37823db86aabSstevel 
37833db86aabSstevel 	if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) {
37843db86aabSstevel 		powerlevel = 0;
37853db86aabSstevel 		sockp->pcs_vcc = 0;
37863db86aabSstevel 		sockp->pcs_vpp1 = 0;
37873db86aabSstevel 		sockp->pcs_vpp2 = 0;
37883db86aabSstevel 	} else {
37893db86aabSstevel #if defined(PCIC_DEBUG)
37903db86aabSstevel 		pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n",
37913db86aabSstevel 		    socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level);
37923db86aabSstevel #endif
37933db86aabSstevel 		/* valid Vcc power level? */
37943db86aabSstevel 		if (socket->VccLevel >= pcic->pc_numpower)
37953db86aabSstevel 			return (BAD_VCC);
37963db86aabSstevel 
37973db86aabSstevel 		switch (pcic_power[socket->VccLevel].PowerLevel) {
37983db86aabSstevel 		case 33:	/* 3.3V */
37993db86aabSstevel 		case 60:	/* for bad CIS in Option GPRS card */
38003db86aabSstevel 			if (!(pcic->pc_flags & PCF_33VCAP)) {
38013db86aabSstevel 				cmn_err(CE_WARN,
38023db86aabSstevel 				    "%s%d: Bad Request for 3.3V "
38033db86aabSstevel 				    "(Controller incapable)\n",
38043db86aabSstevel 				    ddi_get_name(pcic->dip),
38053db86aabSstevel 				    ddi_get_instance(pcic->dip));
38063db86aabSstevel 				return (BAD_VCC);
38073db86aabSstevel 			}
38083db86aabSstevel 			/* FALLTHROUGH */
38093db86aabSstevel 		case 50:	/* 5V */
38103db86aabSstevel 			if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) &&
38113db86aabSstevel 			    pcic_getcb(pcic, CB_PRESENT_STATE) &
38123db86aabSstevel 			    CB_PS_33VCARD) {
38133db86aabSstevel 				/*
38143db86aabSstevel 				 * This is actually a 3.3V card.
38153db86aabSstevel 				 * Solaris Card Services
38163db86aabSstevel 				 * doesn't understand 3.3V
38173db86aabSstevel 				 * so we cheat and change
38183db86aabSstevel 				 * the setting to the one appropriate to 3.3V.
38193db86aabSstevel 				 * Note that this is the entry number
38203db86aabSstevel 				 * in the pcic_power[] array.
38213db86aabSstevel 				 */
38223db86aabSstevel 				sockp->pcs_vcc = PCIC_VCC_3VLEVEL;
38233db86aabSstevel 			} else
38243db86aabSstevel 				sockp->pcs_vcc = socket->VccLevel;
38253db86aabSstevel 			break;
38263db86aabSstevel 		default:
38273db86aabSstevel 			return (BAD_VCC);
38283db86aabSstevel 		}
38293db86aabSstevel 
38303db86aabSstevel 		/* enable Vcc */
38313db86aabSstevel 		powerlevel = POWER_CARD_ENABLE;
38323db86aabSstevel 
38333db86aabSstevel #if defined(PCIC_DEBUG)
38343db86aabSstevel 		if (pcic_debug) {
38353db86aabSstevel 			cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n",
38363db86aabSstevel 			    socket->VccLevel, powerlevel);
38373db86aabSstevel 		}
38383db86aabSstevel #endif
38393db86aabSstevel 		ind = 0;		/* default index to 0 power */
38403db86aabSstevel 		if ((int)socket->Vpp1Level >= 0 &&
38413db86aabSstevel 		    socket->Vpp1Level < pcic->pc_numpower) {
38423db86aabSstevel 			if (!(pcic_power[socket->Vpp1Level].ValidSignals
38433db86aabSstevel 			    & VPP1)) {
38443db86aabSstevel 				return (BAD_VPP);
38453db86aabSstevel 			}
38463db86aabSstevel 			ind = pcic_power[socket->Vpp1Level].PowerLevel/10;
38473db86aabSstevel 			powerlevel |= pcic_vpp_levels[ind];
38483db86aabSstevel 			sockp->pcs_vpp1 = socket->Vpp1Level;
38493db86aabSstevel 		}
38503db86aabSstevel 		if ((int)socket->Vpp2Level >= 0 &&
38513db86aabSstevel 		    socket->Vpp2Level < pcic->pc_numpower) {
38523db86aabSstevel 			if (!(pcic_power[socket->Vpp2Level].ValidSignals
38533db86aabSstevel 			    & VPP2)) {
38543db86aabSstevel 				return (BAD_VPP);
38553db86aabSstevel 			}
38563db86aabSstevel 			ind = pcic_power[socket->Vpp2Level].PowerLevel/10;
38573db86aabSstevel 			powerlevel |= (pcic_vpp_levels[ind] << 2);
38583db86aabSstevel 			sockp->pcs_vpp2 = socket->Vpp2Level;
38593db86aabSstevel 		}
38603db86aabSstevel 
38613db86aabSstevel 		if (pcic->pc_flags & PCF_VPPX) {
38623db86aabSstevel 			/*
38633db86aabSstevel 			 * this adapter doesn't allow separate Vpp1/Vpp2
38643db86aabSstevel 			 * if one is turned on, both are turned on and only
38653db86aabSstevel 			 * the Vpp1 bits should be set
38663db86aabSstevel 			 */
38673db86aabSstevel 			if (sockp->pcs_vpp2 != sockp->pcs_vpp1) {
38683db86aabSstevel 				/* must be the same if one not zero */
38693db86aabSstevel 				if (sockp->pcs_vpp1 != 0 &&
38703db86aabSstevel 				    sockp->pcs_vpp2 != 0) {
38713db86aabSstevel 					cmn_err(CE_WARN,
38723db86aabSstevel 					    "%s%d: Bad Power Request "
38733db86aabSstevel 					    "(Vpp1/2 not the same)\n",
38743db86aabSstevel 					    ddi_get_name(pcic->dip),
38753db86aabSstevel 					    ddi_get_instance(pcic->dip));
38763db86aabSstevel 					return (BAD_VPP);
38773db86aabSstevel 				}
38783db86aabSstevel 			}
38793db86aabSstevel 			powerlevel &= ~(3<<2);
38803db86aabSstevel 		}
38813db86aabSstevel 
38823db86aabSstevel #if defined(PCIC_DEBUG)
38833db86aabSstevel 		if (pcic_debug) {
38843db86aabSstevel 			cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n",
38853db86aabSstevel 			    powerlevel, ind);
38863db86aabSstevel 		}
38873db86aabSstevel #endif
38883db86aabSstevel 	}
38893db86aabSstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
38903db86aabSstevel 
38913db86aabSstevel 	/* turn socket->IREQRouting off while programming */
38923db86aabSstevel 	interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
38933db86aabSstevel 	interrupt &= ~PCIC_INTR_MASK;
38943db86aabSstevel 	if (pcic->pc_flags & PCF_USE_SMI)
38953db86aabSstevel 		interrupt |= PCIC_INTR_ENABLE;
38963db86aabSstevel 	pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt);
38973db86aabSstevel 
38983db86aabSstevel 	switch (pcic->pc_type) {
38993db86aabSstevel 	    case PCIC_INTEL_i82092:
39003db86aabSstevel 		pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ,
39013db86aabSstevel 						PCIC_82092_INT_DISABLE);
39023db86aabSstevel 		break;
39033db86aabSstevel 	    default:
39043db86aabSstevel 		break;
39053db86aabSstevel 	} /* switch */
39063db86aabSstevel 
39073db86aabSstevel 	/* the SCIntMask specifies events to detect */
39083db86aabSstevel 	mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT);
39093db86aabSstevel 
39103db86aabSstevel #if defined(PCIC_DEBUG)
39113db86aabSstevel 	if (pcic_debug)
39123db86aabSstevel 		cmn_err(CE_CONT,
39133db86aabSstevel 			"\tSCIntMask=%x, interrupt=%x, mirq=%x\n",
39143db86aabSstevel 			socket->SCIntMask, interrupt, mirq);
39153db86aabSstevel #endif
39163db86aabSstevel 	mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT);
39173db86aabSstevel 	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT,
39183db86aabSstevel 	    mirq & ~PCIC_CHANGE_MASK);
39193db86aabSstevel 
39203db86aabSstevel 	/* save the mask we want to use */
39213db86aabSstevel 	sockp->pcs_intmask = socket->SCIntMask;
39223db86aabSstevel 
39233db86aabSstevel 	/*
39243db86aabSstevel 	 * Until there is a card present it's not worth enabling
39253db86aabSstevel 	 * any interrupts except "Card detect". This is done
39263db86aabSstevel 	 * elsewhere in the driver so don't change things if
39273db86aabSstevel 	 * there is no card!
39283db86aabSstevel 	 */
39293db86aabSstevel 	if (sockp->pcs_flags & PCS_CARD_PRESENT) {
39303db86aabSstevel 
39313db86aabSstevel 		/* now update the hardware to reflect events desired */
39323db86aabSstevel 		if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO)
39333db86aabSstevel 			mirq |= PCIC_BD_DETECT;
39343db86aabSstevel 
39353db86aabSstevel 		if (sockp->pcs_intmask & SBM_BVD2)
39363db86aabSstevel 			mirq |= PCIC_BW_DETECT;
39373db86aabSstevel 
39383db86aabSstevel 		if (sockp->pcs_intmask & SBM_RDYBSY)
39393db86aabSstevel 			mirq |= PCIC_RD_DETECT;
39403db86aabSstevel 
39413db86aabSstevel 		if (sockp->pcs_intmask & SBM_CD)
39423db86aabSstevel 			mirq |= PCIC_CD_DETECT;
39433db86aabSstevel 	}
39443db86aabSstevel 
39453db86aabSstevel 	if (sockp->pcs_flags & PCS_READY) {
39463db86aabSstevel 		/*
39473db86aabSstevel 		 * card just came ready.
39483db86aabSstevel 		 * make sure enough time elapses
39493db86aabSstevel 		 * before touching it.
39503db86aabSstevel 		 */
39513db86aabSstevel 		sockp->pcs_flags &= ~PCS_READY;
39523db86aabSstevel 		pcic_mswait(pcic, socket->socket, 10);
39533db86aabSstevel 	}
39543db86aabSstevel 
39553db86aabSstevel #if defined(PCIC_DEBUG)
39563db86aabSstevel 	if (pcic_debug) {
39573db86aabSstevel 		cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq);
39583db86aabSstevel 	}
39593db86aabSstevel #endif
39603db86aabSstevel 
39613db86aabSstevel 	switch (pcic->pc_type) {
39623db86aabSstevel 	    case PCIC_I82365SL:
39633db86aabSstevel 	    case PCIC_VADEM:
39643db86aabSstevel 	    case PCIC_VADEM_VG469:
39653db86aabSstevel 		/*
39663db86aabSstevel 		 * The Intel version has different options. This is a
39673db86aabSstevel 		 * special case of GPI which might be used for eject
39683db86aabSstevel 		 */
39693db86aabSstevel 
39703db86aabSstevel 		irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT);
39713db86aabSstevel 		if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) &&
39723db86aabSstevel 		    pcic->pc_flags & PCF_GPI_EJECT) {
39733db86aabSstevel 			irq |= PCIC_GPI_ENABLE;
39743db86aabSstevel 		} else {
39753db86aabSstevel 			irq &= ~PCIC_GPI_ENABLE;
39763db86aabSstevel 		}
39773db86aabSstevel 		pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq);
39783db86aabSstevel 		break;
39793db86aabSstevel 	    case PCIC_CL_PD6710:
39803db86aabSstevel 	    case PCIC_CL_PD6722:
39813db86aabSstevel 		if (socket->IFType == IF_IO) {
39823db86aabSstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0);
39833db86aabSstevel 			value = pcic_getb(pcic, socket->socket,
39843db86aabSstevel 						PCIC_MISC_CTL_1);
39853db86aabSstevel 			if (pcic->pc_flags & PCF_AUDIO)
39863db86aabSstevel 				value |= PCIC_MC_SPEAKER_ENB;
39873db86aabSstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
39883db86aabSstevel 					value);
39893db86aabSstevel 		} else {
39903db86aabSstevel 			value = pcic_getb(pcic, socket->socket,
39913db86aabSstevel 						PCIC_MISC_CTL_1);
39923db86aabSstevel 			value &= ~PCIC_MC_SPEAKER_ENB;
39933db86aabSstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
39943db86aabSstevel 					value);
39953db86aabSstevel 		}
39963db86aabSstevel 		break;
39973db86aabSstevel 	    case PCIC_CL_PD6729:
39983db86aabSstevel 	    case PCIC_CL_PD6730:
39993db86aabSstevel 	    case PCIC_CL_PD6832:
40003db86aabSstevel 		value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1);
40013db86aabSstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40023db86aabSstevel 		    value |= PCIC_MC_SPEAKER_ENB;
40033db86aabSstevel 		} else {
40043db86aabSstevel 		    value &= ~PCIC_MC_SPEAKER_ENB;
40053db86aabSstevel 		}
40063db86aabSstevel 
40073db86aabSstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40083db86aabSstevel 			value |= PCIC_MC_3VCC;
40093db86aabSstevel 		else
40103db86aabSstevel 			value &= ~PCIC_MC_3VCC;
40113db86aabSstevel 
40123db86aabSstevel 		pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value);
40133db86aabSstevel 		break;
40143db86aabSstevel 
40153db86aabSstevel 	    case PCIC_O2_OZ6912:
40163db86aabSstevel 		value = pcic_getcb(pcic, CB_MISCCTRL);
40173db86aabSstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO))
40183db86aabSstevel 			value |= (1<<25);
40193db86aabSstevel 		else
40203db86aabSstevel 			value &= ~(1<<25);
40213db86aabSstevel 		pcic_putcb(pcic, CB_MISCCTRL, value);
40223db86aabSstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40233db86aabSstevel 			powerlevel |= 0x08;
40243db86aabSstevel 		break;
40253db86aabSstevel 
40263db86aabSstevel 	    case PCIC_TI_PCI1250:
40273db86aabSstevel 	    case PCIC_TI_PCI1221:
40283db86aabSstevel 	    case PCIC_TI_PCI1225:
40293db86aabSstevel 	    case PCIC_TI_PCI1410:
40303db86aabSstevel 	    case PCIC_ENE_1410:
40313db86aabSstevel 	    case PCIC_TI_PCI1510:
40323db86aabSstevel 	    case PCIC_TI_PCI1520:
40333db86aabSstevel 	    case PCIC_TI_PCI1420:
40343db86aabSstevel 	    case PCIC_ENE_1420:
40353db86aabSstevel 		value = ddi_get8(pcic->cfg_handle,
40363db86aabSstevel 		    pcic->cfgaddr + PCIC_CRDCTL_REG);
40373db86aabSstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40383db86aabSstevel 			value |= PCIC_CRDCTL_SPKR_ENBL;
40393db86aabSstevel 		} else {
40403db86aabSstevel 			value &= ~PCIC_CRDCTL_SPKR_ENBL;
40413db86aabSstevel 		}
40423db86aabSstevel 		ddi_put8(pcic->cfg_handle,
40433db86aabSstevel 		    pcic->cfgaddr + PCIC_CRDCTL_REG, value);
40443db86aabSstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40453db86aabSstevel 			powerlevel |= 0x08;
40463db86aabSstevel 		break;
40473db86aabSstevel 	}
40483db86aabSstevel 
40493db86aabSstevel 	/*
40503db86aabSstevel 	 * ctlind processing -- we can ignore this
40513db86aabSstevel 	 * there aren't any outputs on the chip for this and
40523db86aabSstevel 	 * the GUI will display what it thinks is correct
40533db86aabSstevel 	 */
40543db86aabSstevel 
40553db86aabSstevel 	/*
40563db86aabSstevel 	 * If outputs are enabled and the power is going off
40573db86aabSstevel 	 * turn off outputs first.
40583db86aabSstevel 	 */
40593db86aabSstevel 
40603db86aabSstevel 	/* power setup -- if necessary */
40613db86aabSstevel 	orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40623db86aabSstevel 	if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) {
40633db86aabSstevel 		orig_pwrctl &= ~POWER_OUTPUT_ENABLE;
40643db86aabSstevel 		pcic_putb(pcic, socket->socket,
40653db86aabSstevel 		    PCIC_POWER_CONTROL, orig_pwrctl);
40663db86aabSstevel 		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40673db86aabSstevel 	}
40683db86aabSstevel 
40693db86aabSstevel 	if (pcic->pc_flags & PCF_CBPWRCTL) {
40703db86aabSstevel 		value = pcic_cbus_powerctl(pcic, socket->socket);
40713db86aabSstevel 		powerlevel = 0;
40723db86aabSstevel 	} else
40733db86aabSstevel 		value = pcic_exca_powerctl(pcic, socket->socket, powerlevel);
40743db86aabSstevel 
40753db86aabSstevel 	if (value != SUCCESS) {
40763db86aabSstevel 		mutex_exit(&pcic->pc_lock);
40773db86aabSstevel 		return (value);
40783db86aabSstevel 	}
40793db86aabSstevel 
40803db86aabSstevel 	/*
40813db86aabSstevel 	 * If outputs were disabled and the power is going on
40823db86aabSstevel 	 * turn on outputs afterwards.
40833db86aabSstevel 	 */
40843db86aabSstevel 	if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) {
40853db86aabSstevel 		orig_pwrctl = pcic_getb(pcic, socket->socket,
40863db86aabSstevel 		    PCIC_POWER_CONTROL);
40873db86aabSstevel 		orig_pwrctl |= POWER_OUTPUT_ENABLE;
40883db86aabSstevel 		pcic_putb(pcic, socket->socket,
40893db86aabSstevel 		    PCIC_POWER_CONTROL, orig_pwrctl);
40903db86aabSstevel 		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40913db86aabSstevel 	}
40923db86aabSstevel 
40933db86aabSstevel 	/*
40943db86aabSstevel 	 * Once we have done the power stuff can re-enable management
40953db86aabSstevel 	 * interrupts.
40963db86aabSstevel 	 */
40973db86aabSstevel 	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq);
40983db86aabSstevel 
40993db86aabSstevel #if defined(PCIC_DEBUG)
41003db86aabSstevel 	pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x "
41013db86aabSstevel 	    "cbctl 0x%x\n",
41023db86aabSstevel 	    mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL),
41033db86aabSstevel 	    pcic_getcb(pcic, CB_CONTROL));
41043db86aabSstevel #endif
41053db86aabSstevel 
41063db86aabSstevel 	/* irq processing */
41073db86aabSstevel 	if (socket->IFType == IF_IO) {
41083db86aabSstevel 		/* IRQ only for I/O */
41093db86aabSstevel 		irq = socket->IREQRouting & PCIC_INTR_MASK;
41103db86aabSstevel 		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41113db86aabSstevel 		value &= ~PCIC_INTR_MASK;
41123db86aabSstevel 
41133db86aabSstevel 		/* to enable I/O operation */
41143db86aabSstevel 		value |= PCIC_IO_CARD | PCIC_RESET;
41153db86aabSstevel 		sockp->pcs_flags |= PCS_CARD_IO;
41163db86aabSstevel 		if (irq != sockp->pcs_irq) {
41173db86aabSstevel 			if (sockp->pcs_irq != 0)
41183db86aabSstevel 				cmn_err(CE_CONT,
41193db86aabSstevel 					"SetSocket: IRQ mismatch %x != %x!\n",
41203db86aabSstevel 					irq, sockp->pcs_irq);
41213db86aabSstevel 			else
41223db86aabSstevel 				sockp->pcs_irq = irq;
41233db86aabSstevel 		}
41243db86aabSstevel 		irq = sockp->pcs_irq;
41253db86aabSstevel 
41263db86aabSstevel 		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41273db86aabSstevel 		if (socket->IREQRouting & IRQ_ENABLE) {
41283db86aabSstevel 			pcic_enable_io_intr(pcic, socket->socket, irq);
41293db86aabSstevel 			sockp->pcs_flags |= PCS_IRQ_ENABLED;
41303db86aabSstevel 		} else {
41313db86aabSstevel 			pcic_disable_io_intr(pcic, socket->socket);
41323db86aabSstevel 			sockp->pcs_flags &= ~PCS_IRQ_ENABLED;
41333db86aabSstevel 		}
41343db86aabSstevel #if defined(PCIC_DEBUG)
41353db86aabSstevel 		if (pcic_debug) {
41363db86aabSstevel 			cmn_err(CE_CONT,
41373db86aabSstevel 				"\tsocket type is I/O and irq %x is %s\n", irq,
41383db86aabSstevel 				(socket->IREQRouting & IRQ_ENABLE) ?
41393db86aabSstevel 				"enabled" : "not enabled");
41403db86aabSstevel 			xxdmp_all_regs(pcic, socket->socket, 20);
41413db86aabSstevel 		}
41423db86aabSstevel #endif
41433db86aabSstevel 	} else {
41443db86aabSstevel 		/* make sure I/O mode is off */
41453db86aabSstevel 
41463db86aabSstevel 		sockp->pcs_irq = 0;
41473db86aabSstevel 
41483db86aabSstevel 		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41493db86aabSstevel 		value &= ~PCIC_IO_CARD;
41503db86aabSstevel 		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41513db86aabSstevel 		pcic_disable_io_intr(pcic, socket->socket);
41523db86aabSstevel 		sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED);
41533db86aabSstevel 	}
41543db86aabSstevel 
41553db86aabSstevel 	sockp->pcs_state &= ~socket->State;
41563db86aabSstevel 
41573db86aabSstevel 	mutex_exit(&pcic->pc_lock);
41583db86aabSstevel 	return (SUCCESS);
41593db86aabSstevel }
41603db86aabSstevel 
41613db86aabSstevel /*
41623db86aabSstevel  * pcic_inquire_socket()
41633db86aabSstevel  *	SocketServices InquireSocket function
41643db86aabSstevel  *	returns basic characteristics of the socket
41653db86aabSstevel  */
41663db86aabSstevel /*ARGSUSED*/
41673db86aabSstevel static int
41683db86aabSstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
41693db86aabSstevel {
41703db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
41713db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
41723db86aabSstevel 	int value;
41733db86aabSstevel 
41743db86aabSstevel 	socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS;
41753db86aabSstevel 	socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS;
41763db86aabSstevel 	socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS;
41773db86aabSstevel 	value = pcic->pc_sockets[socket->socket].pcs_flags;
41783db86aabSstevel 	socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY;
41793db86aabSstevel 	socket->ActiveHigh = 0;
41803db86aabSstevel 	/* these are the usable IRQs */
41813db86aabSstevel 	socket->ActiveLow = 0xfff0;
41823db86aabSstevel 	return (SUCCESS);
41833db86aabSstevel }
41843db86aabSstevel 
41853db86aabSstevel /*
41863db86aabSstevel  * pcic_inquire_window()
41873db86aabSstevel  *	SocketServices InquireWindow function
41883db86aabSstevel  *	returns detailed characteristics of the window
41893db86aabSstevel  *	this is where windows get tied to sockets
41903db86aabSstevel  */
41913db86aabSstevel /*ARGSUSED*/
41923db86aabSstevel static int
41933db86aabSstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window)
41943db86aabSstevel {
41953db86aabSstevel 	int type, socket;
41963db86aabSstevel 
41973db86aabSstevel 	type = window->window % PCIC_NUMWINSOCK;
41983db86aabSstevel 	socket = window->window / PCIC_NUMWINSOCK;
41993db86aabSstevel 
42003db86aabSstevel #if defined(PCIC_DEBUG)
42013db86aabSstevel 	if (pcic_debug >= 8)
42023db86aabSstevel 		cmn_err(CE_CONT,
42033db86aabSstevel 			"pcic_inquire_window: window = %d/%d socket=%d\n",
42043db86aabSstevel 			window->window, type, socket);
42053db86aabSstevel #endif
42063db86aabSstevel 	if (type < PCIC_IOWINDOWS) {
42073db86aabSstevel 		window->WndCaps = WC_IO|WC_WAIT;
42083db86aabSstevel 		type = IF_IO;
42093db86aabSstevel 	} else {
42103db86aabSstevel 		window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT;
42113db86aabSstevel 		type = IF_MEMORY;
42123db86aabSstevel 	}
42133db86aabSstevel 
42143db86aabSstevel 	/* initialize the socket map - one socket per window */
42153db86aabSstevel 	PR_ZERO(window->Sockets);
42163db86aabSstevel 	PR_SET(window->Sockets, socket);
42173db86aabSstevel 
42183db86aabSstevel 	if (type == IF_IO) {
42193db86aabSstevel 		iowin_char_t *io;
42203db86aabSstevel 		io = &window->iowin_char;
42213db86aabSstevel 		io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42223db86aabSstevel 			WC_16BIT;
42233db86aabSstevel 		io->FirstByte = (baseaddr_t)IOMEM_FIRST;
42243db86aabSstevel 		io->LastByte = (baseaddr_t)IOMEM_LAST;
42253db86aabSstevel 		io->MinSize = IOMEM_MIN;
42263db86aabSstevel 		io->MaxSize = IOMEM_MAX;
42273db86aabSstevel 		io->ReqGran = IOMEM_GRAN;
42283db86aabSstevel 		io->AddrLines = IOMEM_DECODE;
42293db86aabSstevel 		io->EISASlot = 0;
42303db86aabSstevel 	} else {
42313db86aabSstevel 		mem_win_char_t *mem;
42323db86aabSstevel 		mem = &window->mem_win_char;
42333db86aabSstevel 		mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42343db86aabSstevel 			WC_16BIT|WC_WP;
42353db86aabSstevel 
42363db86aabSstevel 		mem->FirstByte = (baseaddr_t)MEM_FIRST;
42373db86aabSstevel 		mem->LastByte = (baseaddr_t)MEM_LAST;
42383db86aabSstevel 
42393db86aabSstevel 		mem->MinSize = MEM_MIN;
42403db86aabSstevel 		mem->MaxSize = MEM_MAX;
42413db86aabSstevel 		mem->ReqGran = PCIC_PAGE;
42423db86aabSstevel 		mem->ReqBase = 0;
42433db86aabSstevel 		mem->ReqOffset = PCIC_PAGE;
42443db86aabSstevel 		mem->Slowest = MEM_SPEED_MAX;
42453db86aabSstevel 		mem->Fastest = MEM_SPEED_MIN;
42463db86aabSstevel 	}
42473db86aabSstevel 	return (SUCCESS);
42483db86aabSstevel }
42493db86aabSstevel 
42503db86aabSstevel /*
42513db86aabSstevel  * pcic_get_adapter()
42523db86aabSstevel  *	SocketServices GetAdapter function
42533db86aabSstevel  *	this is nearly a no-op.
42543db86aabSstevel  */
42553db86aabSstevel /*ARGSUSED*/
42563db86aabSstevel static int
42573db86aabSstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
42583db86aabSstevel {
42593db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
42603db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
42613db86aabSstevel 
42623db86aabSstevel 	if (pcic->pc_flags & PCF_INTRENAB)
42633db86aabSstevel 		adapt->SCRouting = IRQ_ENABLE;
42643db86aabSstevel 	adapt->state = 0;
42653db86aabSstevel 	return (SUCCESS);
42663db86aabSstevel }
42673db86aabSstevel 
42683db86aabSstevel /*
42693db86aabSstevel  * pcic_get_page()
42703db86aabSstevel  *	SocketServices GetPage function
42713db86aabSstevel  *	returns info about the window
42723db86aabSstevel  */
42733db86aabSstevel /*ARGSUSED*/
42743db86aabSstevel static int
42753db86aabSstevel pcic_get_page(dev_info_t *dip, get_page_t *page)
42763db86aabSstevel {
42773db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
42783db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
42793db86aabSstevel 	int socket, window;
42803db86aabSstevel 	pcs_memwin_t *winp;
42813db86aabSstevel 
42823db86aabSstevel 	socket = page->window / PCIC_NUMWINSOCK;
42833db86aabSstevel 	window = page->window % PCIC_NUMWINSOCK;
42843db86aabSstevel 
42853db86aabSstevel 	/* I/O windows are the first two */
42863db86aabSstevel 	if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) {
42873db86aabSstevel 		return (BAD_WINDOW);
42883db86aabSstevel 	}
42893db86aabSstevel 
42903db86aabSstevel 	winp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
42913db86aabSstevel 
42923db86aabSstevel 	if (page->page != 0)
42933db86aabSstevel 		return (BAD_PAGE);
42943db86aabSstevel 
42953db86aabSstevel 	page->state = 0;
42963db86aabSstevel 	if (winp->pcw_status & PCW_ENABLED)
42973db86aabSstevel 		page->state |= PS_ENABLED;
42983db86aabSstevel 	if (winp->pcw_status & PCW_ATTRIBUTE)
42993db86aabSstevel 		page->state |= PS_ATTRIBUTE;
43003db86aabSstevel 	if (winp->pcw_status & PCW_WP)
43013db86aabSstevel 		page->state |= PS_WP;
43023db86aabSstevel 
43033db86aabSstevel 	page->offset = (off_t)winp->pcw_offset;
43043db86aabSstevel 
43053db86aabSstevel 	return (SUCCESS);
43063db86aabSstevel }
43073db86aabSstevel 
43083db86aabSstevel /*
43093db86aabSstevel  * pcic_get_socket()
43103db86aabSstevel  *	SocketServices GetSocket
43113db86aabSstevel  *	returns information about the current socket setting
43123db86aabSstevel  */
43133db86aabSstevel /*ARGSUSED*/
43143db86aabSstevel static int
43153db86aabSstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket)
43163db86aabSstevel {
43173db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
43183db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
43193db86aabSstevel 	int socknum, irq_enabled;
43203db86aabSstevel 	pcic_socket_t *sockp;
43213db86aabSstevel 
43223db86aabSstevel 	socknum = socket->socket;
43233db86aabSstevel 	sockp = &pcic->pc_sockets[socknum];
43243db86aabSstevel 
43253db86aabSstevel 	socket->SCIntMask = sockp->pcs_intmask;
43263db86aabSstevel 	sockp->pcs_state = pcic_card_state(pcic, sockp);
43273db86aabSstevel 
43283db86aabSstevel 	socket->state = sockp->pcs_state;
43293db86aabSstevel 	if (socket->state & SBM_CD) {
43303db86aabSstevel 		socket->VccLevel = sockp->pcs_vcc;
43313db86aabSstevel 		socket->Vpp1Level = sockp->pcs_vpp1;
43323db86aabSstevel 		socket->Vpp2Level = sockp->pcs_vpp2;
43333db86aabSstevel 		irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ?
43343db86aabSstevel 		    IRQ_ENABLE : 0;
43353db86aabSstevel 		socket->IRQRouting = sockp->pcs_irq | irq_enabled;
43363db86aabSstevel 		socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43373db86aabSstevel 		    IF_IO : IF_MEMORY;
43383db86aabSstevel 	} else {
43393db86aabSstevel 		socket->VccLevel = 0;
43403db86aabSstevel 		socket->Vpp1Level = 0;
43413db86aabSstevel 		socket->Vpp2Level = 0;
43423db86aabSstevel 		socket->IRQRouting = 0;
43433db86aabSstevel 		socket->IFType = IF_MEMORY;
43443db86aabSstevel 	}
43453db86aabSstevel 	socket->CtlInd = 0;	/* no indicators */
43463db86aabSstevel 
43473db86aabSstevel 	return (SUCCESS);
43483db86aabSstevel }
43493db86aabSstevel 
43503db86aabSstevel /*
43513db86aabSstevel  * pcic_get_status()
43523db86aabSstevel  *	SocketServices GetStatus
43533db86aabSstevel  *	returns status information about the PC Card in
43543db86aabSstevel  *	the selected socket
43553db86aabSstevel  */
43563db86aabSstevel /*ARGSUSED*/
43573db86aabSstevel static int
43583db86aabSstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status)
43593db86aabSstevel {
43603db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
43613db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
43623db86aabSstevel 	int socknum, irq_enabled;
43633db86aabSstevel 	pcic_socket_t *sockp;
43643db86aabSstevel 
43653db86aabSstevel 	socknum = status->socket;
43663db86aabSstevel 	sockp = &pcic->pc_sockets[socknum];
43673db86aabSstevel 
43683db86aabSstevel 	status->CardState = pcic_card_state(pcic, sockp);
43693db86aabSstevel 	status->SocketState = sockp->pcs_state;
43703db86aabSstevel 	status->CtlInd = 0;	/* no indicators */
43713db86aabSstevel 
43723db86aabSstevel 	if (sockp->pcs_flags & PCS_CARD_PRESENT)
43733db86aabSstevel 		status->SocketState |= SBM_CD;
43743db86aabSstevel 	if (status->CardState & SBM_CD) {
43753db86aabSstevel 		irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ?
43763db86aabSstevel 		    IRQ_ENABLE : 0;
43773db86aabSstevel 		status->IRQRouting = sockp->pcs_irq | irq_enabled;
43783db86aabSstevel 		status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43793db86aabSstevel 		    IF_IO : IF_MEMORY;
43803db86aabSstevel 	} else {
43813db86aabSstevel 		status->IRQRouting = 0;
43823db86aabSstevel 		status->IFType = IF_MEMORY;
43833db86aabSstevel 	}
43843db86aabSstevel 
43853db86aabSstevel #if defined(PCIC_DEBUG)
43863db86aabSstevel 	if (pcic_debug >= 8)
43873db86aabSstevel 		cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x,"
43883db86aabSstevel 			"SocketState=%x\n",
43893db86aabSstevel 			socknum, status->CardState, status->SocketState);
43903db86aabSstevel #endif
43913db86aabSstevel 	switch (pcic->pc_type) {
43923db86aabSstevel 	uint32_t present_state;
43933db86aabSstevel 	case PCIC_TI_PCI1410:
43943db86aabSstevel 	case PCIC_TI_PCI1520:
43953db86aabSstevel 	case PCIC_TI_PCI1420:
43963db86aabSstevel 	case PCIC_ENE_1420:
43973db86aabSstevel 	case PCIC_TOSHIBA_TOPIC100:
43983db86aabSstevel 	case PCIC_TOSHIBA_TOPIC95:
43993db86aabSstevel 	case PCIC_TOSHIBA_VENDOR:
44003db86aabSstevel 	case PCIC_O2MICRO_VENDOR:
44013db86aabSstevel 	case PCIC_TI_VENDOR:
44023db86aabSstevel 	case PCIC_RICOH_VENDOR:
44033db86aabSstevel 		present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
44043db86aabSstevel 		if (present_state & PCIC_CB_CARD)
44053db86aabSstevel 			status->IFType = IF_CARDBUS;
44063db86aabSstevel #if defined(PCIC_DEBUG)
44073db86aabSstevel 		if (pcic_debug >= 8)
44083db86aabSstevel 		    cmn_err(CE_CONT, "pcic_get_status: present_state=0x%x\n",
44093db86aabSstevel 			present_state);
44103db86aabSstevel #endif
44113db86aabSstevel 		break;
44123db86aabSstevel 	default:
44133db86aabSstevel 		break;
44143db86aabSstevel 	}
44153db86aabSstevel 
44163db86aabSstevel 	return (SUCCESS);
44173db86aabSstevel }
44183db86aabSstevel 
44193db86aabSstevel /*
44203db86aabSstevel  * pcic_get_window()
44213db86aabSstevel  *	SocketServices GetWindow function
44223db86aabSstevel  *	returns state information about the specified window
44233db86aabSstevel  */
44243db86aabSstevel /*ARGSUSED*/
44253db86aabSstevel static int
44263db86aabSstevel pcic_get_window(dev_info_t *dip, get_window_t *window)
44273db86aabSstevel {
44283db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
44293db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
44303db86aabSstevel 	int socket, win;
44313db86aabSstevel 	pcic_socket_t *sockp;
44323db86aabSstevel 	pcs_memwin_t *winp;
44333db86aabSstevel 
44343db86aabSstevel 	socket = window->window / PCIC_NUMWINSOCK;
44353db86aabSstevel 	win = window->window % PCIC_NUMWINSOCK;
44363db86aabSstevel #if defined(PCIC_DEBUG)
44373db86aabSstevel 	if (pcic_debug) {
44383db86aabSstevel 		cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n",
44393db86aabSstevel 			socket, win);
44403db86aabSstevel 	}
44413db86aabSstevel #endif
44423db86aabSstevel 
44433db86aabSstevel 	if (socket > pcic->pc_numsockets)
44443db86aabSstevel 		return (BAD_WINDOW);
44453db86aabSstevel 
44463db86aabSstevel 	sockp = &pcic->pc_sockets[socket];
44473db86aabSstevel 	winp = &sockp->pcs_windows[win].mem;
44483db86aabSstevel 
44493db86aabSstevel 	window->socket = socket;
44503db86aabSstevel 	window->size = winp->pcw_len;
44513db86aabSstevel 	window->speed = winp->pcw_speed;
44523db86aabSstevel 	window->handle = (ddi_acc_handle_t)winp->pcw_handle;
44533db86aabSstevel 	window->base = (uint32_t)winp->pcw_base + winp->pcw_offset;
44543db86aabSstevel 
44553db86aabSstevel 	if (win >= PCIC_IOWINDOWS) {
44563db86aabSstevel 		window->state = 0;
44573db86aabSstevel 	} else {
44583db86aabSstevel 		window->state = WS_IO;
44593db86aabSstevel 	}
44603db86aabSstevel 	if (winp->pcw_status & PCW_ENABLED)
44613db86aabSstevel 		window->state |= WS_ENABLED;
44623db86aabSstevel 
44633db86aabSstevel 	if (winp->pcw_status & PCS_CARD_16BIT)
44643db86aabSstevel 		window->state |= WS_16BIT;
44653db86aabSstevel #if defined(PCIC_DEBUG)
44663db86aabSstevel 	if (pcic_debug)
44673db86aabSstevel 		cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n",
44683db86aabSstevel 			window->size, (unsigned)window->speed,
44693db86aabSstevel 			(void *)window->handle, window->state);
44703db86aabSstevel #endif
44713db86aabSstevel 
44723db86aabSstevel 	return (SUCCESS);
44733db86aabSstevel }
44743db86aabSstevel 
44753db86aabSstevel /*
44763db86aabSstevel  * pcic_ll_reset
44773db86aabSstevel  *	low level reset
44783db86aabSstevel  *	separated out so it can be called when already locked
44793db86aabSstevel  *
44803db86aabSstevel  *	There are two variables that control the RESET timing:
44813db86aabSstevel  *		pcic_prereset_time - time in mS before asserting RESET
44823db86aabSstevel  *		pcic_reset_time - time in mS to assert RESET
44833db86aabSstevel  *
44843db86aabSstevel  */
44853db86aabSstevel int pcic_prereset_time = 1;
44863db86aabSstevel int pcic_reset_time = 10;
44873db86aabSstevel int pcic_postreset_time = 20;
44883db86aabSstevel int pcic_vpp_is_vcc_during_reset = 0;
44893db86aabSstevel 
44903db86aabSstevel static int
44913db86aabSstevel pcic_ll_reset(pcicdev_t *pcic, int socket)
44923db86aabSstevel {
44933db86aabSstevel 	int windowbits, iobits;
44943db86aabSstevel 	uint32_t pwr;
44953db86aabSstevel 
44963db86aabSstevel 	/* save windows that were on */
44973db86aabSstevel 	windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
44983db86aabSstevel 	if (pcic_reset_time == 0)
44993db86aabSstevel 	    return (windowbits);
45003db86aabSstevel 	/* turn all windows off */
45013db86aabSstevel 	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0);
45023db86aabSstevel 
45033db86aabSstevel #if defined(PCIC_DEBUG)
45043db86aabSstevel 	pcic_err(pcic->dip, 6,
45053db86aabSstevel 		"pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n",
45063db86aabSstevel 		socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
45073db86aabSstevel 		pcic_getcb(pcic, CB_CONTROL),
45083db86aabSstevel 		pcic_getcb(pcic, CB_PRESENT_STATE));
45093db86aabSstevel #endif
45103db86aabSstevel 
45113db86aabSstevel 	if (pcic_vpp_is_vcc_during_reset) {
45123db86aabSstevel 
45133db86aabSstevel 	/*
45143db86aabSstevel 	 * Set VPP to VCC for the duration of the reset - for aironet
45153db86aabSstevel 	 * card.
45163db86aabSstevel 	 */
45173db86aabSstevel 	    if (pcic->pc_flags & PCF_CBPWRCTL) {
45183db86aabSstevel 		pwr = pcic_getcb(pcic, CB_CONTROL);
45193db86aabSstevel 		pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC);
45203db86aabSstevel 		(void) pcic_getcb(pcic, CB_CONTROL);
45213db86aabSstevel 	    } else {
45223db86aabSstevel 		pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45233db86aabSstevel 		pcic_putb(pcic, socket, PCIC_POWER_CONTROL,
45243db86aabSstevel 		    pwr | 1);
45253db86aabSstevel 		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45263db86aabSstevel 	    }
45273db86aabSstevel 	}
45283db86aabSstevel 
45293db86aabSstevel 	if (pcic_prereset_time > 0) {
45303db86aabSstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n",
45313db86aabSstevel 		    pcic_prereset_time);
45323db86aabSstevel 		pcic_mswait(pcic, socket, pcic_prereset_time);
45333db86aabSstevel 	}
45343db86aabSstevel 
45353db86aabSstevel 	/* turn interrupts off and start a reset */
45363db86aabSstevel 	pcic_err(pcic->dip, 8,
45373db86aabSstevel 		"pcic_ll_reset turn interrupts off and start a reset\n");
45383db86aabSstevel 	iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
45393db86aabSstevel 	iobits &= ~(PCIC_INTR_MASK | PCIC_RESET);
45403db86aabSstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
45413db86aabSstevel 	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45423db86aabSstevel 
45433db86aabSstevel 	switch (pcic->pc_type) {
45443db86aabSstevel 	    case PCIC_INTEL_i82092:
45453db86aabSstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
45463db86aabSstevel 						PCIC_82092_INT_DISABLE);
45473db86aabSstevel 		break;
45483db86aabSstevel 	    default:
45493db86aabSstevel 		break;
45503db86aabSstevel 	} /* switch */
45513db86aabSstevel 
45523db86aabSstevel 	pcic->pc_sockets[socket].pcs_state = 0;
45533db86aabSstevel 
45543db86aabSstevel 	if (pcic_reset_time > 0) {
45553db86aabSstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n",
45563db86aabSstevel 		    pcic_reset_time);
45573db86aabSstevel 		pcic_mswait(pcic, socket, pcic_reset_time);
45583db86aabSstevel 	}
45593db86aabSstevel 
45603db86aabSstevel 	pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n");
45613db86aabSstevel 
45623db86aabSstevel 	/* take it out of RESET now */
45633db86aabSstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits);
45643db86aabSstevel 	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45653db86aabSstevel 
45663db86aabSstevel 	/*
45673db86aabSstevel 	 * can't access the card for 20ms, but we really don't
45683db86aabSstevel 	 * want to sit around that long. The pcic is still usable.
45693db86aabSstevel 	 * memory accesses must wait for RDY to come up.
45703db86aabSstevel 	 */
45713db86aabSstevel 	if (pcic_postreset_time > 0) {
45723db86aabSstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n",
45733db86aabSstevel 		    pcic_postreset_time);
45743db86aabSstevel 		pcic_mswait(pcic, socket, pcic_postreset_time);
45753db86aabSstevel 	}
45763db86aabSstevel 
45773db86aabSstevel 	if (pcic_vpp_is_vcc_during_reset > 1) {
45783db86aabSstevel 
45793db86aabSstevel 	/*
45803db86aabSstevel 	 * Return VPP power to whatever it was before.
45813db86aabSstevel 	 */
45823db86aabSstevel 	    if (pcic->pc_flags & PCF_CBPWRCTL) {
45833db86aabSstevel 		pcic_putcb(pcic, CB_CONTROL, pwr);
45843db86aabSstevel 		(void) pcic_getcb(pcic, CB_CONTROL);
45853db86aabSstevel 	    } else {
45863db86aabSstevel 		pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr);
45873db86aabSstevel 		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45883db86aabSstevel 	    }
45893db86aabSstevel 	}
45903db86aabSstevel 
45913db86aabSstevel 	pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits);
45923db86aabSstevel 
45933db86aabSstevel 	return (windowbits);
45943db86aabSstevel }
45953db86aabSstevel 
45963db86aabSstevel /*
45973db86aabSstevel  * pcic_reset_socket()
45983db86aabSstevel  *	SocketServices ResetSocket function
45993db86aabSstevel  *	puts the PC Card in the socket into the RESET state
46003db86aabSstevel  *	and then takes it out after the the cycle time
46013db86aabSstevel  *	The socket is back to initial state when done
46023db86aabSstevel  */
46033db86aabSstevel static int
46043db86aabSstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode)
46053db86aabSstevel {
46063db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
46073db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
46083db86aabSstevel 	int value;
46093db86aabSstevel 	int i, mint;
46103db86aabSstevel 	pcic_socket_t *sockp;
46113db86aabSstevel 
46123db86aabSstevel #if defined(PCIC_DEBUG)
46133db86aabSstevel 	if (pcic_debug >= 8)
46143db86aabSstevel 		cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n",
46153db86aabSstevel 		    (void *)dip, socket, mode,
46163db86aabSstevel 			mode == RESET_MODE_FULL ? "full" : "partial");
46173db86aabSstevel #endif
46183db86aabSstevel 
46193db86aabSstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
46203db86aabSstevel 
46213db86aabSstevel 	/* Turn off management interupts. */
46223db86aabSstevel 	mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT);
46233db86aabSstevel 	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK);
46243db86aabSstevel 
46253db86aabSstevel 	sockp = &pcic->pc_sockets[socket];
46263db86aabSstevel 
46273db86aabSstevel 	value = pcic_ll_reset(pcic, socket);
46283db86aabSstevel 	if (mode == RESET_MODE_FULL) {
46293db86aabSstevel 		/* disable and unmap all mapped windows */
46303db86aabSstevel 		for (i = 0; i < PCIC_NUMWINSOCK; i++) {
46313db86aabSstevel 			if (i < PCIC_IOWINDOWS) {
46323db86aabSstevel 				if (sockp->pcs_windows[i].io.pcw_status &
46333db86aabSstevel 				    PCW_MAPPED) {
46343db86aabSstevel 					pcs_iowin_t *io;
46353db86aabSstevel 					io = &sockp->pcs_windows[i].io;
46363db86aabSstevel 					io->pcw_status &= ~PCW_ENABLED;
46373db86aabSstevel 				}
46383db86aabSstevel 			} else {
46393db86aabSstevel 				if (sockp->pcs_windows[i].mem.pcw_status &
46403db86aabSstevel 				    PCW_MAPPED) {
46413db86aabSstevel 					pcs_memwin_t *mem;
46423db86aabSstevel 					mem = &sockp->pcs_windows[i].mem;
46433db86aabSstevel 					mem->pcw_status &= ~PCW_ENABLED;
46443db86aabSstevel 				}
46453db86aabSstevel 			}
46463db86aabSstevel 		}
46473db86aabSstevel 	} else {
46483db86aabSstevel 				/* turn windows back on */
46493db86aabSstevel 		pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value);
46503db86aabSstevel 		/* wait the rest of the time here */
46513db86aabSstevel 		pcic_mswait(pcic, socket, 10);
46523db86aabSstevel 	}
46533db86aabSstevel 	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint);
46543db86aabSstevel 	mutex_exit(&pcic->pc_lock);
46553db86aabSstevel 	return (SUCCESS);
46563db86aabSstevel }
46573db86aabSstevel 
46583db86aabSstevel /*
46593db86aabSstevel  * pcic_set_interrupt()
46603db86aabSstevel  *	SocketServices SetInterrupt function
46613db86aabSstevel  */
46623db86aabSstevel static int
46633db86aabSstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
46643db86aabSstevel {
46653db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
46663db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
46673db86aabSstevel 	int value = DDI_SUCCESS;
46683db86aabSstevel 	inthandler_t *intr;
46693db86aabSstevel 
46703db86aabSstevel #if defined(PCIC_DEBUG)
46713db86aabSstevel 	if (pcic_debug) {
46723db86aabSstevel 		cmn_err(CE_CONT,
46733db86aabSstevel 			"pcic_set_interrupt: entered pc_intr_mode=0x%x\n",
46743db86aabSstevel 			pcic->pc_intr_mode);
46753db86aabSstevel 		cmn_err(CE_CONT,
46763db86aabSstevel 			"\t irq_top=%p handler=%p handler_id=%x\n",
46773db86aabSstevel 			(void *)pcic->irq_top, (void *)handler->handler,
46783db86aabSstevel 			handler->handler_id);
46793db86aabSstevel 	}
46803db86aabSstevel #endif
46813db86aabSstevel 
46823db86aabSstevel 	/*
46833db86aabSstevel 	 * If we're on a PCI bus, we route all IO IRQs through a single
46843db86aabSstevel 	 *	PCI interrupt (typically INT A#) so we don't have to do
46853db86aabSstevel 	 *	much other than add the caller to general interrupt handler
46863db86aabSstevel 	 *	and set some state.
46873db86aabSstevel 	 */
46883db86aabSstevel 
46893db86aabSstevel 	intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
46903db86aabSstevel 	if (intr == NULL)
46913db86aabSstevel 		return (NO_RESOURCE);
46923db86aabSstevel 
46933db86aabSstevel 	switch (pcic->pc_intr_mode) {
46943db86aabSstevel 	case PCIC_INTR_MODE_PCI_1:
46953db86aabSstevel 		/*
46963db86aabSstevel 		 * We only allow above-lock-level IO IRQ handlers
46973db86aabSstevel 		 *	in the PCI bus case.
46983db86aabSstevel 		 */
46993db86aabSstevel 
47003db86aabSstevel 		mutex_enter(&pcic->intr_lock);
47013db86aabSstevel 
47023db86aabSstevel 		if (pcic->irq_top == NULL) {
47033db86aabSstevel 		    pcic->irq_top = intr;
47043db86aabSstevel 		    pcic->irq_current = pcic->irq_top;
47053db86aabSstevel 		} else {
47063db86aabSstevel 		    while (pcic->irq_current->next != NULL)
47073db86aabSstevel 			pcic->irq_current = pcic->irq_current->next;
47083db86aabSstevel 		    pcic->irq_current->next = intr;
47093db86aabSstevel 		    pcic->irq_current = pcic->irq_current->next;
47103db86aabSstevel 		}
47113db86aabSstevel 
47123db86aabSstevel 		pcic->irq_current->intr =
47133db86aabSstevel 		    (ddi_intr_handler_t *)handler->handler;
47143db86aabSstevel 		pcic->irq_current->handler_id = handler->handler_id;
47153db86aabSstevel 		pcic->irq_current->arg1 = handler->arg1;
47163db86aabSstevel 		pcic->irq_current->arg2 = handler->arg2;
47173db86aabSstevel 		pcic->irq_current->socket = handler->socket;
47183db86aabSstevel 
47193db86aabSstevel 		mutex_exit(&pcic->intr_lock);
47203db86aabSstevel 
47213db86aabSstevel 		handler->iblk_cookie = &pcic->pc_pri;
47223db86aabSstevel 		handler->idev_cookie = &pcic->pc_dcookie;
47233db86aabSstevel 		break;
47243db86aabSstevel 
47253db86aabSstevel 	default:
47263db86aabSstevel 		intr->intr = (ddi_intr_handler_t *)handler->handler;
47273db86aabSstevel 		intr->handler_id = handler->handler_id;
47283db86aabSstevel 		intr->arg1 = handler->arg1;
47293db86aabSstevel 		intr->arg2 = handler->arg2;
47303db86aabSstevel 		intr->socket = handler->socket;
47313db86aabSstevel 		intr->irq = handler->irq;
47323db86aabSstevel 
47333db86aabSstevel 		/*
47343db86aabSstevel 		 * need to revisit this to see if interrupts can be
47353db86aabSstevel 		 * shared someday. Note that IRQ is set in the common
47363db86aabSstevel 		 * code.
47373db86aabSstevel 		 */
47383db86aabSstevel 		mutex_enter(&pcic->pc_lock);
47393db86aabSstevel 		if (pcic->pc_handlers == NULL) {
47403db86aabSstevel 			pcic->pc_handlers = intr;
47413db86aabSstevel 			intr->next = intr->prev = intr;
47423db86aabSstevel 		} else {
47433db86aabSstevel 			insque(intr, pcic->pc_handlers);
47443db86aabSstevel 		}
47453db86aabSstevel 		mutex_exit(&pcic->pc_lock);
47463db86aabSstevel 
47473db86aabSstevel 		break;
47483db86aabSstevel 	}
47493db86aabSstevel 
47503db86aabSstevel 	/*
47513db86aabSstevel 	 * need to fill in cookies in event of multiple high priority
47523db86aabSstevel 	 * interrupt handlers on same IRQ
47533db86aabSstevel 	 */
47543db86aabSstevel 
47553db86aabSstevel #if defined(PCIC_DEBUG)
47563db86aabSstevel 	if (pcic_debug) {
47573db86aabSstevel 		cmn_err(CE_CONT,
47583db86aabSstevel 			"pcic_set_interrupt: exit irq_top=%p value=%d\n",
47593db86aabSstevel 			(void *)pcic->irq_top, value);
47603db86aabSstevel 	}
47613db86aabSstevel #endif
47623db86aabSstevel 
47633db86aabSstevel 	if (value == DDI_SUCCESS) {
47643db86aabSstevel 		return (SUCCESS);
47653db86aabSstevel 	} else {
47663db86aabSstevel 		return (BAD_IRQ);
47673db86aabSstevel 	}
47683db86aabSstevel }
47693db86aabSstevel 
47703db86aabSstevel /*
47713db86aabSstevel  * pcic_clear_interrupt()
47723db86aabSstevel  *	SocketServices ClearInterrupt function
47733db86aabSstevel  *
47743db86aabSstevel  *	Interrupts for PCIC are complicated by the fact that we must
47753db86aabSstevel  *	follow several different models for interrupts.
47763db86aabSstevel  *	ISA: there is an interrupt per adapter and per socket and
47773db86aabSstevel  *		they can't be shared.
47783db86aabSstevel  *	PCI: some adapters have one PCI interrupt available while others
47793db86aabSstevel  *		have up to 4.  Solaris may or may not allow us to use more
47803db86aabSstevel  *		than 1 so we essentially share them all at this point.
47813db86aabSstevel  *	Hybrid: PCI bridge but interrupts wired to host interrupt controller.
47823db86aabSstevel  *		This is like ISA but we have to fudge and create an intrspec
47833db86aabSstevel  *		that PCI's parent understands and bypass the PCI nexus.
47843db86aabSstevel  *	multifunction: this requires sharing the interrupts on a per-socket
47853db86aabSstevel  *		basis.
47863db86aabSstevel  */
47873db86aabSstevel static int
47883db86aabSstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
47893db86aabSstevel {
47903db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
47913db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
47923db86aabSstevel 	inthandler_t *intr, *prev, *current;
47933db86aabSstevel 	int i;
47943db86aabSstevel 
47953db86aabSstevel 	/*
47963db86aabSstevel 	 * If we're on a PCI bus, we route all IO IRQs through a single
47973db86aabSstevel 	 *	PCI interrupt (typically INT A#) so we don't have to do
47983db86aabSstevel 	 *	much other than remove the caller from the general
47993db86aabSstevel 	 *	interrupt handler callout list.
48003db86aabSstevel 	 */
48013db86aabSstevel 
48023db86aabSstevel #if defined(PCIC_DEBUG)
48033db86aabSstevel 	if (pcic_debug) {
48043db86aabSstevel 		cmn_err(CE_CONT,
48053db86aabSstevel 			"pcic_clear_interrupt: entered pc_intr_mode=0x%x\n",
48063db86aabSstevel 			pcic->pc_intr_mode);
48073db86aabSstevel 		cmn_err(CE_CONT,
48083db86aabSstevel 			"\t irq_top=%p handler=%p handler_id=%x\n",
48093db86aabSstevel 			(void *)pcic->irq_top, (void *)handler->handler,
48103db86aabSstevel 			handler->handler_id);
48113db86aabSstevel 	}
48123db86aabSstevel #endif
48133db86aabSstevel 
48143db86aabSstevel 	switch (pcic->pc_intr_mode) {
48153db86aabSstevel 	case PCIC_INTR_MODE_PCI_1:
48163db86aabSstevel 
48173db86aabSstevel 		mutex_enter(&pcic->intr_lock);
48183db86aabSstevel 		if (pcic->irq_top == NULL) {
48193db86aabSstevel 			mutex_exit(&pcic->intr_lock);
48203db86aabSstevel 			return (BAD_IRQ);
48213db86aabSstevel 		}
48223db86aabSstevel 
48233db86aabSstevel 		intr = NULL;
48243db86aabSstevel 		pcic->irq_current = pcic->irq_top;
48253db86aabSstevel 
48263db86aabSstevel 		while ((pcic->irq_current != NULL) &&
48273db86aabSstevel 				(pcic->irq_current->handler_id !=
48283db86aabSstevel 						handler->handler_id)) {
48293db86aabSstevel 			intr = pcic->irq_current;
48303db86aabSstevel 			pcic->irq_current = pcic->irq_current->next;
48313db86aabSstevel 		}
48323db86aabSstevel 
48333db86aabSstevel 		if (pcic->irq_current == NULL) {
48343db86aabSstevel 			mutex_exit(&pcic->intr_lock);
48353db86aabSstevel 			return (BAD_IRQ);
48363db86aabSstevel 		}
48373db86aabSstevel 
48383db86aabSstevel 		if (intr != NULL) {
48393db86aabSstevel 			intr->next = pcic->irq_current->next;
48403db86aabSstevel 		} else {
48413db86aabSstevel 			pcic->irq_top = pcic->irq_current->next;
48423db86aabSstevel 		}
48433db86aabSstevel 
48443db86aabSstevel 		current = pcic->irq_current;
48453db86aabSstevel 		pcic->irq_current = pcic->irq_top;
48463db86aabSstevel 		mutex_exit(&pcic->intr_lock);
48473db86aabSstevel 		kmem_free(current, sizeof (inthandler_t));
48483db86aabSstevel 
48493db86aabSstevel 		break;
48503db86aabSstevel 
48513db86aabSstevel 	default:
48523db86aabSstevel 
48533db86aabSstevel 		mutex_enter(&pcic->pc_lock);
48543db86aabSstevel 		intr = pcic_handlers;
48553db86aabSstevel 		prev = (inthandler_t *)&pcic_handlers;
48563db86aabSstevel 
48573db86aabSstevel 		while (intr != NULL) {
48583db86aabSstevel 		    if (intr->handler_id == handler->handler_id) {
48593db86aabSstevel 			i = intr->irq & PCIC_INTR_MASK;
48603db86aabSstevel 			if (--pcic_irq_map[i].count == 0) {
48613db86aabSstevel 				/* multi-handler form */
48623db86aabSstevel 				(void) ddi_intr_disable(pcic->pc_intr_htblp[i]);
48633db86aabSstevel 				(void) ddi_intr_remove_handler(
48643db86aabSstevel 				    pcic->pc_intr_htblp[i]);
48653db86aabSstevel 				(void) ddi_intr_free(pcic->pc_intr_htblp[i]);
48663db86aabSstevel 				(void) pcmcia_return_intr(pcic->dip, i);
48673db86aabSstevel #if defined(PCIC_DEBUG)
48683db86aabSstevel 				if (pcic_debug) {
48693db86aabSstevel 					cmn_err(CE_CONT,
48703db86aabSstevel 						"removing interrupt %d at %s "
48713db86aabSstevel 						"priority\n", i, "high");
48723db86aabSstevel 					cmn_err(CE_CONT,
48733db86aabSstevel 						"ddi_remove_intr(%p, %x, %p)\n",
48743db86aabSstevel 						(void *)dip,
48753db86aabSstevel 						0,
48763db86aabSstevel 						(void *)intr->iblk_cookie);
48773db86aabSstevel 				}
48783db86aabSstevel #endif
48793db86aabSstevel 			}
48803db86aabSstevel 			prev->next = intr->next;
48813db86aabSstevel 			kmem_free(intr, sizeof (inthandler_t));
48823db86aabSstevel 			intr = prev->next;
48833db86aabSstevel 		    } else {
48843db86aabSstevel 			prev = intr;
48853db86aabSstevel 			intr = intr->next;
48863db86aabSstevel 		    } /* if (handler_id) */
48873db86aabSstevel 		} /* while */
48883db86aabSstevel 
48893db86aabSstevel 		mutex_exit(&pcic->pc_lock);
48903db86aabSstevel 	}
48913db86aabSstevel 
48923db86aabSstevel #if defined(PCIC_DEBUG)
48933db86aabSstevel 	if (pcic_debug) {
48943db86aabSstevel 		cmn_err(CE_CONT,
48953db86aabSstevel 		"pcic_clear_interrupt: exit irq_top=%p\n",
48963db86aabSstevel 		(void *)pcic->irq_top);
48973db86aabSstevel 	}
48983db86aabSstevel #endif
48993db86aabSstevel 
49003db86aabSstevel 
49013db86aabSstevel 	return (SUCCESS);
49023db86aabSstevel }
49033db86aabSstevel 
49043db86aabSstevel struct intel_regs {
49053db86aabSstevel 	char *name;
49063db86aabSstevel 	int   off;
49073db86aabSstevel 	char *fmt;
49083db86aabSstevel } iregs[] = {
49093db86aabSstevel 	{"ident     ", 0},
49103db86aabSstevel 	{"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"},
49113db86aabSstevel 	{"power     ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO"
49123db86aabSstevel 		"\7DRD\10OE"},
49133db86aabSstevel 	{"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"},
49143db86aabSstevel 	{"enable    ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"},
49153db86aabSstevel 	{"cd-gcr    ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"},
49163db86aabSstevel 	{"GCR       ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"},
49173db86aabSstevel 	{"int-gcr   ", 3, "\020\5INTR\6IO\7~RST\10RI"},
49183db86aabSstevel 	{"management", 5, "\020\1BDE\2BWE\3RE\4CDE"},
49193db86aabSstevel 	{"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"},
49203db86aabSstevel 	{"volt-sel  ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"},
49213db86aabSstevel 	{"VG ext A  ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"},
49223db86aabSstevel 	{"io-ctrl   ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"},
49233db86aabSstevel 	{"io0-slow  ", 8},
49243db86aabSstevel 	{"io0-shi   ", 9},
49253db86aabSstevel 	{"io0-elow  ", 0xa},
49263db86aabSstevel 	{"io0-ehi   ", 0xb},
49273db86aabSstevel 	{"io1-slow  ", 0xc},
49283db86aabSstevel 	{"io1-shi   ", 0xd},
49293db86aabSstevel 	{"io1-elow  ", 0xe},
49303db86aabSstevel 	{"io1-ehi   ", 0xf},
49313db86aabSstevel 	{"mem0-slow ", 0x10},
49323db86aabSstevel 	{"mem0-shi  ", 0x11, "\020\7ZW\10DS"},
49333db86aabSstevel 	{"mem0-elow ", 0x12},
49343db86aabSstevel 	{"mem0-ehi  ", 0x13, "\020\7WS0\10WS1"},
49353db86aabSstevel 	{"card0-low ", 0x14},
49363db86aabSstevel 	{"card0-hi  ", 0x15, "\020\7AM\10WP"},
49373db86aabSstevel 	{"mem1-slow ", 0x18},
49383db86aabSstevel 	{"mem1-shi  ", 0x19, "\020\7ZW\10DS"},
49393db86aabSstevel 	{"mem1-elow ", 0x1a},
49403db86aabSstevel 	{"mem1-ehi  ", 0x1b, "\020\7WS0\10WS1"},
49413db86aabSstevel 	{"card1-low ", 0x1c},
49423db86aabSstevel 	{"card1-hi  ", 0x1d, "\020\7AM\10WP"},
49433db86aabSstevel 	{"mem2-slow ", 0x20},
49443db86aabSstevel 	{"mem2-shi  ", 0x21, "\020\7ZW\10DS"},
49453db86aabSstevel 	{"mem2-elow ", 0x22},
49463db86aabSstevel 	{"mem2-ehi  ", 0x23, "\020\7WS0\10WS1"},
49473db86aabSstevel 	{"card2-low ", 0x24},
49483db86aabSstevel 	{"card2-hi  ", 0x25, "\020\7AM\10WP"},
49493db86aabSstevel 	{"mem3-slow ", 0x28},
49503db86aabSstevel 	{"mem3-shi  ", 0x29, "\020\7ZW\10DS"},
49513db86aabSstevel 	{"mem3-elow ", 0x2a},
49523db86aabSstevel 	{"mem3-ehi  ", 0x2b, "\020\7WS0\10WS1"},
49533db86aabSstevel 	{"card3-low ", 0x2c},
49543db86aabSstevel 	{"card3-hi  ", 0x2d, "\020\7AM\10WP"},
49553db86aabSstevel 
49563db86aabSstevel 	{"mem4-slow ", 0x30},
49573db86aabSstevel 	{"mem4-shi  ", 0x31, "\020\7ZW\10DS"},
49583db86aabSstevel 	{"mem4-elow ", 0x32},
49593db86aabSstevel 	{"mem4-ehi  ", 0x33, "\020\7WS0\10WS1"},
49603db86aabSstevel 	{"card4-low ", 0x34},
49613db86aabSstevel 	{"card4-hi  ", 0x35, "\020\7AM\10WP"},
49623db86aabSstevel 	{"mpage0    ", 0x40},
49633db86aabSstevel 	{"mpage1    ", 0x41},
49643db86aabSstevel 	{"mpage2    ", 0x42},
49653db86aabSstevel 	{"mpage3    ", 0x43},
49663db86aabSstevel 	{"mpage4    ", 0x44},
49673db86aabSstevel 	{NULL},
49683db86aabSstevel };
49693db86aabSstevel 
49703db86aabSstevel static struct intel_regs cregs[] = {
49713db86aabSstevel 	{"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"},
49723db86aabSstevel 	{"fifo      ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"},
49733db86aabSstevel 	{"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"},
49743db86aabSstevel 	{"chip-info ", 0x1f, "\20\6DUAL"},
49753db86aabSstevel 	{"IO-offlow0", 0x36},
49763db86aabSstevel 	{"IO-offhi0 ", 0x37},
49773db86aabSstevel 	{"IO-offlow1", 0x38},
49783db86aabSstevel 	{"IO-offhi1 ", 0x39},
49793db86aabSstevel 	NULL,
49803db86aabSstevel };
49813db86aabSstevel 
49823db86aabSstevel static struct intel_regs cxregs[] = {
49833db86aabSstevel 	{"ext-ctl-1 ", 0x03,
49843db86aabSstevel 		"\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"},
49853db86aabSstevel 	{"misc-ctl3 ", 0x25, "\20\5HWSUSP"},
49863db86aabSstevel 	{"mem0-up   ", 0x05},
49873db86aabSstevel 	{"mem1-up   ", 0x06},
49883db86aabSstevel 	{"mem2-up   ", 0x07},
49893db86aabSstevel 	{"mem3-up   ", 0x08},
49903db86aabSstevel 	{"mem4-up   ", 0x09},
49913db86aabSstevel 	{NULL}
49923db86aabSstevel };
49933db86aabSstevel 
49943db86aabSstevel void
49953db86aabSstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len)
49963db86aabSstevel {
49973db86aabSstevel 	int i, value, j;
49983db86aabSstevel 	char buff[256];
49993db86aabSstevel 	char *fmt;
50003db86aabSstevel 
50013db86aabSstevel 	cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n");
50023db86aabSstevel 	for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) {
50033db86aabSstevel 		int sval;
50043db86aabSstevel 		if (cregs[i].off == PCIC_MISC_CTL_2)
50053db86aabSstevel 			sval = 0;
50063db86aabSstevel 		else
50073db86aabSstevel 			sval = socket;
50083db86aabSstevel 		value = pcic_getb(pcic, sval, cregs[i].off);
50093db86aabSstevel 		if (i & 1) {
50103db86aabSstevel 			if (cregs[i].fmt)
50113db86aabSstevel 				fmt = "%s\t%s\t%b\n";
50123db86aabSstevel 			else
50133db86aabSstevel 				fmt = "%s\t%s\t%x\n";
50143db86aabSstevel 			cmn_err(CE_CONT, fmt, buff,
50153db86aabSstevel 				cregs[i].name, value, cregs[i].fmt);
50163db86aabSstevel 			buff[0] = '\0';
50173db86aabSstevel 		} else {
50183db86aabSstevel 			if (cregs[i].fmt)
50193db86aabSstevel 				fmt = "\t%s\t%b";
50203db86aabSstevel 			else
50213db86aabSstevel 				fmt = "\t%s\t%x";
50223db86aabSstevel 			(void) sprintf(buff, fmt,
50233db86aabSstevel 				cregs[i].name, value, cregs[i].fmt);
50243db86aabSstevel 			for (j = strlen(buff); j < 40; j++)
50253db86aabSstevel 				buff[j] = ' ';
50263db86aabSstevel 			buff[40] = '\0';
50273db86aabSstevel 		}
50283db86aabSstevel 	}
50293db86aabSstevel 	cmn_err(CE_CONT, "%s\n", buff);
50303db86aabSstevel 
50313db86aabSstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0);
50323db86aabSstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1);
50333db86aabSstevel 	cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j);
50343db86aabSstevel 
50353db86aabSstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0);
50363db86aabSstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1);
50373db86aabSstevel 	cmn_err(CE_CONT, "\tcmd-tim0  \t%x\tcmd-tim1  \t%x\n", i, j);
50383db86aabSstevel 
50393db86aabSstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0);
50403db86aabSstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1);
50413db86aabSstevel 	cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j);
50423db86aabSstevel 
50433db86aabSstevel 	cmn_err(CE_CONT, "--------- Extended Registers  --------\n");
50443db86aabSstevel 
50453db86aabSstevel 	for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) {
50463db86aabSstevel 		value = clext_reg_read(pcic, socket, cxregs[i].off);
50473db86aabSstevel 		if (i & 1) {
50483db86aabSstevel 			if (cxregs[i].fmt)
50493db86aabSstevel 				fmt = "%s\t%s\t%b\n";
50503db86aabSstevel 			else
50513db86aabSstevel 				fmt = "%s\t%s\t%x\n";
50523db86aabSstevel 			cmn_err(CE_CONT, fmt, buff,
50533db86aabSstevel 				cxregs[i].name, value, cxregs[i].fmt);
50543db86aabSstevel 			buff[0] = '\0';
50553db86aabSstevel 		} else {
50563db86aabSstevel 			if (cxregs[i].fmt)
50573db86aabSstevel 				fmt = "\t%s\t%b";
50583db86aabSstevel 			else
50593db86aabSstevel 				fmt = "\t%s\t%x";
50603db86aabSstevel 			(void) sprintf(buff, fmt,
50613db86aabSstevel 				cxregs[i].name, value, cxregs[i].fmt);
50623db86aabSstevel 			for (j = strlen(buff); j < 40; j++)
50633db86aabSstevel 				buff[j] = ' ';
50643db86aabSstevel 			buff[40] = '\0';
50653db86aabSstevel 		}
50663db86aabSstevel 	}
50673db86aabSstevel }
50683db86aabSstevel 
50693db86aabSstevel #if defined(PCIC_DEBUG)
50703db86aabSstevel static void
50713db86aabSstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len)
50723db86aabSstevel {
50733db86aabSstevel 	int i, value, j;
50743db86aabSstevel 	char buff[256];
50753db86aabSstevel 	char *fmt;
50763db86aabSstevel 
50773db86aabSstevel #if defined(PCIC_DEBUG)
50783db86aabSstevel 	if (pcic_debug < 2)
50793db86aabSstevel 		return;
50803db86aabSstevel #endif
50813db86aabSstevel 	cmn_err(CE_CONT,
50823db86aabSstevel 		"----------- PCIC Registers for socket %d---------\n",
50833db86aabSstevel 		socket);
50843db86aabSstevel 	cmn_err(CE_CONT,
50853db86aabSstevel 		"\tname       value                        name       value\n");
50863db86aabSstevel 
50873db86aabSstevel 	for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) {
50883db86aabSstevel 		value = pcic_getb(pcic, socket, iregs[i].off);
50893db86aabSstevel 		if (i & 1) {
50903db86aabSstevel 			if (iregs[i].fmt)
50913db86aabSstevel 				fmt = "%s\t%s\t%b\n";
50923db86aabSstevel 			else
50933db86aabSstevel 				fmt = "%s\t%s\t%x\n";
50943db86aabSstevel 			cmn_err(CE_CONT, fmt, buff,
50953db86aabSstevel 				iregs[i].name, value, iregs[i].fmt);
50963db86aabSstevel 			buff[0] = '\0';
50973db86aabSstevel 		} else {
50983db86aabSstevel 			if (iregs[i].fmt)
50993db86aabSstevel 				fmt = "\t%s\t%b";
51003db86aabSstevel 			else
51013db86aabSstevel 				fmt = "\t%s\t%x";
51023db86aabSstevel 			(void) sprintf(buff, fmt,
51033db86aabSstevel 				iregs[i].name, value, iregs[i].fmt);
51043db86aabSstevel 			for (j = strlen(buff); j < 40; j++)
51053db86aabSstevel 				buff[j] = ' ';
51063db86aabSstevel 			buff[40] = '\0';
51073db86aabSstevel 		}
51083db86aabSstevel 	}
51093db86aabSstevel 	switch (pcic->pc_type) {
51103db86aabSstevel 	case PCIC_CL_PD6710:
51113db86aabSstevel 	case PCIC_CL_PD6722:
51123db86aabSstevel 	case PCIC_CL_PD6729:
51133db86aabSstevel 	case PCIC_CL_PD6832:
51143db86aabSstevel 		(void) xxdmp_cl_regs(pcic, socket, 0xFFFF);
51153db86aabSstevel 		break;
51163db86aabSstevel 	}
51173db86aabSstevel 	cmn_err(CE_CONT, "%s\n", buff);
51183db86aabSstevel }
51193db86aabSstevel #endif
51203db86aabSstevel 
51213db86aabSstevel /*
51223db86aabSstevel  * pcic_mswait(ms)
51233db86aabSstevel  *	sleep ms milliseconds
51243db86aabSstevel  *	call drv_usecwait once for each ms
51253db86aabSstevel  */
51263db86aabSstevel static void
51273db86aabSstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms)
51283db86aabSstevel {
51293db86aabSstevel 	if (ms) {
51303db86aabSstevel 		pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING;
51313db86aabSstevel 		pcic_mutex_exit(&pcic->pc_lock);
51323db86aabSstevel 		delay(drv_usectohz(ms*1000));
51333db86aabSstevel 		pcic_mutex_enter(&pcic->pc_lock);
51343db86aabSstevel 		pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING;
51353db86aabSstevel 	}
51363db86aabSstevel }
51373db86aabSstevel 
51383db86aabSstevel /*
51393db86aabSstevel  * pcic_check_ready(pcic, index, off)
51403db86aabSstevel  *      Wait for card to come ready
51413db86aabSstevel  *      We only wait if the card is NOT in RESET
51423db86aabSstevel  *      and power is on.
51433db86aabSstevel  */
51443db86aabSstevel static boolean_t
51453db86aabSstevel pcic_check_ready(pcicdev_t *pcic, int socket)
51463db86aabSstevel {
51473db86aabSstevel 	int ifstate, intstate;
51483db86aabSstevel 
51493db86aabSstevel 	intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT);
51503db86aabSstevel 	ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS);
51513db86aabSstevel 
51523db86aabSstevel 	if ((intstate & PCIC_RESET) &&
51533db86aabSstevel 	    ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) ==
51543db86aabSstevel 	    (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK)))
51553db86aabSstevel 		return (B_TRUE);
51563db86aabSstevel 
51573db86aabSstevel #ifdef  PCIC_DEBUG
51583db86aabSstevel 	pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, "
51593db86aabSstevel 	    "ifstate = 0x%x\n", intstate, ifstate);
51603db86aabSstevel 	if (pcic_debug) {
51613db86aabSstevel 		pcic_debug += 4;
51623db86aabSstevel 		xxdmp_all_regs(pcic, socket, -1);
51633db86aabSstevel 		pcic_debug -= 4;
51643db86aabSstevel 	}
51653db86aabSstevel #endif
51663db86aabSstevel 	return (B_FALSE);
51673db86aabSstevel }
51683db86aabSstevel 
51693db86aabSstevel /*
51703db86aabSstevel  * Cirrus Logic extended register read/write routines
51713db86aabSstevel  */
51723db86aabSstevel static int
51733db86aabSstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg)
51743db86aabSstevel {
51753db86aabSstevel 	int val;
51763db86aabSstevel 
51773db86aabSstevel 	switch (pcic->pc_io_type) {
51783db86aabSstevel 	case PCIC_IO_TYPE_YENTA:
51793db86aabSstevel 		val = ddi_get8(pcic->handle,
51803db86aabSstevel 		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg);
51813db86aabSstevel 		break;
51823db86aabSstevel 	default:
51833db86aabSstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
51843db86aabSstevel 		val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1);
51853db86aabSstevel 		break;
51863db86aabSstevel 	}
51873db86aabSstevel 
51883db86aabSstevel 	return (val);
51893db86aabSstevel }
51903db86aabSstevel 
51913db86aabSstevel static void
51923db86aabSstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value)
51933db86aabSstevel {
51943db86aabSstevel 	switch (pcic->pc_io_type) {
51953db86aabSstevel 	case PCIC_IO_TYPE_YENTA:
51963db86aabSstevel 		ddi_put8(pcic->handle,
51973db86aabSstevel 		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value);
51983db86aabSstevel 		break;
51993db86aabSstevel 	default:
52003db86aabSstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52013db86aabSstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value);
52023db86aabSstevel 		break;
52033db86aabSstevel 	}
52043db86aabSstevel }
52053db86aabSstevel 
52063db86aabSstevel /*
52073db86aabSstevel  * Misc PCI functions
52083db86aabSstevel  */
52093db86aabSstevel static void
52103db86aabSstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags)
52113db86aabSstevel {
52123db86aabSstevel 	unsigned cmd;
52133db86aabSstevel 
52143db86aabSstevel 	if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) {
52153db86aabSstevel 		cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4));
52163db86aabSstevel 		if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) ==
52173db86aabSstevel 		    (PCI_COMM_IO|PCI_COMM_MAE))
52183db86aabSstevel 			return;
52193db86aabSstevel 
52203db86aabSstevel 		if (flags & PCIC_ENABLE_IO)
52213db86aabSstevel 		    cmd |= PCI_COMM_IO;
52223db86aabSstevel 
52233db86aabSstevel 		if (flags & PCIC_ENABLE_MEM)
52243db86aabSstevel 		    cmd |= PCI_COMM_MAE;
52253db86aabSstevel 
52263db86aabSstevel 		ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd);
52273db86aabSstevel 	} /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */
52283db86aabSstevel }
52293db86aabSstevel 
52303db86aabSstevel /*
52313db86aabSstevel  * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type
52323db86aabSstevel  */
52333db86aabSstevel static int
52343db86aabSstevel pcic_find_pci_type(pcicdev_t *pcic)
52353db86aabSstevel {
52363db86aabSstevel 	uint32_t vend, device;
52373db86aabSstevel 
52383db86aabSstevel 	vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52393db86aabSstevel 				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52403db86aabSstevel 				"vendor-id", -1);
52413db86aabSstevel 	device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52423db86aabSstevel 				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52433db86aabSstevel 				"device-id", -1);
52443db86aabSstevel 
52453db86aabSstevel 	device = PCI_ID(vend, device);
52463db86aabSstevel 	pcic->pc_type = device;
52473db86aabSstevel 	pcic->pc_chipname = "PCI:unknown";
52483db86aabSstevel 
52493db86aabSstevel 	switch (device) {
52503db86aabSstevel 	case PCIC_INTEL_i82092:
52513db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_i82092;
52523db86aabSstevel 		break;
52533db86aabSstevel 	case PCIC_CL_PD6729:
52543db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PD6729;
52553db86aabSstevel 		/*
52563db86aabSstevel 		 * Some 6730's incorrectly identify themselves
52573db86aabSstevel 		 *	as a 6729, so we need to do some more tests
52583db86aabSstevel 		 *	here to see if the device that's claiming
52593db86aabSstevel 		 *	to be a 6729 is really a 6730.
52603db86aabSstevel 		 */
52613db86aabSstevel 		if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) &
52623db86aabSstevel 			PCIC_CLEXT_MISC_CTL_3_REV_MASK) ==
52633db86aabSstevel 				0) {
52643db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_PD6730;
52653db86aabSstevel 			pcic->pc_type = PCIC_CL_PD6730;
52663db86aabSstevel 		}
52673db86aabSstevel 		break;
52683db86aabSstevel 	case PCIC_CL_PD6730:
52693db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PD6730;
52703db86aabSstevel 		break;
52713db86aabSstevel 	case PCIC_CL_PD6832:
52723db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PD6832;
52733db86aabSstevel 		break;
52743db86aabSstevel 	case PCIC_SMC_34C90:
52753db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_34C90;
52763db86aabSstevel 		break;
52773db86aabSstevel 	case PCIC_TOSHIBA_TOPIC95:
52783db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_TOPIC95;
52793db86aabSstevel 		break;
52803db86aabSstevel 	case PCIC_TOSHIBA_TOPIC100:
52813db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_TOPIC100;
52823db86aabSstevel 		break;
52833db86aabSstevel 	case PCIC_TI_PCI1031:
52843db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1031;
52853db86aabSstevel 		break;
52863db86aabSstevel 	case PCIC_TI_PCI1130:
52873db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1130;
52883db86aabSstevel 		break;
52893db86aabSstevel 	case PCIC_TI_PCI1131:
52903db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1131;
52913db86aabSstevel 		break;
52923db86aabSstevel 	case PCIC_TI_PCI1250:
52933db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1250;
52943db86aabSstevel 		break;
52953db86aabSstevel 	case PCIC_TI_PCI1225:
52963db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1225;
52973db86aabSstevel 		break;
52983db86aabSstevel 	case PCIC_TI_PCI1410:
52993db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1410;
53003db86aabSstevel 		break;
53013db86aabSstevel 	case PCIC_TI_PCI1510:
53023db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1510;
53033db86aabSstevel 		break;
53043db86aabSstevel 	case PCIC_TI_PCI1520:
53053db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1520;
53063db86aabSstevel 		break;
53073db86aabSstevel 	case PCIC_TI_PCI1221:
53083db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1221;
53093db86aabSstevel 		break;
53103db86aabSstevel 	case PCIC_TI_PCI1050:
53113db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1050;
53123db86aabSstevel 		break;
53133db86aabSstevel 	case PCIC_ENE_1410:
53143db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_1410;
53153db86aabSstevel 		break;
53163db86aabSstevel 	case PCIC_O2_OZ6912:
53173db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_OZ6912;
53183db86aabSstevel 		break;
53193db86aabSstevel 	case PCIC_RICOH_RL5C466:
53203db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_RL5C466;
53213db86aabSstevel 		break;
53223db86aabSstevel 	case PCIC_TI_PCI1420:
53233db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1420;
53243db86aabSstevel 		break;
53253db86aabSstevel 	case PCIC_ENE_1420:
53263db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_1420;
53273db86aabSstevel 		break;
53283db86aabSstevel 	default:
53293db86aabSstevel 		switch (PCI_ID(vend, (uint32_t)0)) {
53303db86aabSstevel 		case PCIC_TOSHIBA_VENDOR:
53313db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_TOSHIBA;
53323db86aabSstevel 			pcic->pc_type = PCIC_TOSHIBA_VENDOR;
53333db86aabSstevel 			break;
53343db86aabSstevel 		case PCIC_TI_VENDOR:
53353db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_TI;
53363db86aabSstevel 			pcic->pc_type = PCIC_TI_VENDOR;
53373db86aabSstevel 			break;
53383db86aabSstevel 		case PCIC_O2MICRO_VENDOR:
53393db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_O2MICRO;
53403db86aabSstevel 			pcic->pc_type = PCIC_O2MICRO_VENDOR;
53413db86aabSstevel 			break;
53423db86aabSstevel 		case PCIC_RICOH_VENDOR:
53433db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_RICOH;
53443db86aabSstevel 			pcic->pc_type = PCIC_RICOH_VENDOR;
53453db86aabSstevel 			break;
53463db86aabSstevel 		default:
53473db86aabSstevel 			if (!(pcic->pc_flags & PCF_CARDBUS))
53483db86aabSstevel 				return (DDI_FAILURE);
53493db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_YENTA;
53503db86aabSstevel 			break;
53513db86aabSstevel 		}
53523db86aabSstevel 	}
53533db86aabSstevel 	return (DDI_SUCCESS);
53543db86aabSstevel }
53553db86aabSstevel 
53563db86aabSstevel static void
53573db86aabSstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state)
53583db86aabSstevel {
53593db86aabSstevel 	uchar_t ppirr = ddi_get8(pcic->cfg_handle,
53603db86aabSstevel 					pcic->cfgaddr + PCIC_82092_PPIRR);
53613db86aabSstevel 	uchar_t val;
53623db86aabSstevel 
53633db86aabSstevel 	if (intr == PCIC_82092_CTL_SMI) {
53643db86aabSstevel 		val = PCIC_82092_SMI_CTL(socket,
53653db86aabSstevel 						PCIC_82092_INT_DISABLE);
53663db86aabSstevel 		ppirr &= ~val;
53673db86aabSstevel 		val = PCIC_82092_SMI_CTL(socket, state);
53683db86aabSstevel 		ppirr |= val;
53693db86aabSstevel 	} else {
53703db86aabSstevel 		val = PCIC_82092_IRQ_CTL(socket,
53713db86aabSstevel 						PCIC_82092_INT_DISABLE);
53723db86aabSstevel 		ppirr &= ~val;
53733db86aabSstevel 		val = PCIC_82092_IRQ_CTL(socket, state);
53743db86aabSstevel 		ppirr |= val;
53753db86aabSstevel 	}
53763db86aabSstevel 	ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR,
53773db86aabSstevel 			ppirr);
53783db86aabSstevel }
53793db86aabSstevel 
53803db86aabSstevel static uint_t
53813db86aabSstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2)
53823db86aabSstevel {
53833db86aabSstevel 	pcic_socket_t *sockp = (pcic_socket_t *)arg1;
53843db86aabSstevel 	uint_t rc = DDI_INTR_UNCLAIMED;
53853db86aabSstevel 
53863db86aabSstevel 	_NOTE(ARGUNUSED(arg2))
53873db86aabSstevel 
53883db86aabSstevel 	mutex_enter(&sockp->pcs_pcic->pc_lock);
53893db86aabSstevel 	if (sockp->pcs_cd_softint_flg) {
53903db86aabSstevel 		uint8_t status;
53913db86aabSstevel 		sockp->pcs_cd_softint_flg = 0;
53923db86aabSstevel 		rc = DDI_INTR_CLAIMED;
53933db86aabSstevel 		status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket,
53943db86aabSstevel 			PCIC_INTERFACE_STATUS);
53953db86aabSstevel 		pcic_handle_cd_change(sockp->pcs_pcic, sockp, status);
53963db86aabSstevel 	}
53973db86aabSstevel 	mutex_exit(&sockp->pcs_pcic->pc_lock);
53983db86aabSstevel 	return (rc);
53993db86aabSstevel }
54003db86aabSstevel 
54013db86aabSstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT;
54023db86aabSstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME;
54033db86aabSstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT;
54043db86aabSstevel 
54053db86aabSstevel #ifdef CARDBUS
54063db86aabSstevel static uint32_t pcic_cbps_on = 0;
54073db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54083db86aabSstevel 				CB_PS_XVCARD | CB_PS_YVCARD;
54093db86aabSstevel #else
54103db86aabSstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD;
54113db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54123db86aabSstevel 				CB_PS_CBCARD |
54133db86aabSstevel 				CB_PS_XVCARD | CB_PS_YVCARD;
54143db86aabSstevel #endif
54153db86aabSstevel static void
54163db86aabSstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status)
54173db86aabSstevel {
54183db86aabSstevel 	boolean_t	do_debounce = B_FALSE;
54193db86aabSstevel 	int		debounce_time = drv_usectohz(pcic_debounce_time);
54203db86aabSstevel 	uint8_t		irq;
54213db86aabSstevel 	timeout_id_t	debounce;
54223db86aabSstevel 
54233db86aabSstevel 	/*
54243db86aabSstevel 	 * Always reset debounce but may need to check original state later.
54253db86aabSstevel 	 */
54263db86aabSstevel 	debounce = sockp->pcs_debounce_id;
54273db86aabSstevel 	sockp->pcs_debounce_id = 0;
54283db86aabSstevel 
54293db86aabSstevel 	/*
54303db86aabSstevel 	 * Check to see whether a card is present or not. There are
54313db86aabSstevel 	 *	only two states that we are concerned with - the state
54323db86aabSstevel 	 *	where both CD pins are asserted, which means that the
54333db86aabSstevel 	 *	card is fully seated, and the state where neither CD
54343db86aabSstevel 	 *	pin is asserted, which means that the card is not
54353db86aabSstevel 	 *	present.
54363db86aabSstevel 	 * The CD signals are generally very noisy and cause a lot of
54373db86aabSstevel 	 *	contact bounce as the card is being inserted and
54383db86aabSstevel 	 *	removed, so we need to do some software debouncing.
54393db86aabSstevel 	 */
54403db86aabSstevel 
54413db86aabSstevel #ifdef PCIC_DEBUG
54423db86aabSstevel 	    pcic_err(pcic->dip, 6,
54433db86aabSstevel 		    "pcic%d handle_cd_change: socket %d card status 0x%x"
54443db86aabSstevel 		    " deb 0x%p\n", ddi_get_instance(pcic->dip),
54453db86aabSstevel 		    sockp->pcs_socket, status, debounce);
54463db86aabSstevel #endif
54473db86aabSstevel 	switch (status & PCIC_ISTAT_CD_MASK) {
54483db86aabSstevel 	case PCIC_CD_PRESENT_OK:
54493db86aabSstevel 	    sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM);
54503db86aabSstevel 	    if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
54513db86aabSstevel 		uint32_t cbps;
54523db86aabSstevel #ifdef PCIC_DEBUG
54533db86aabSstevel 		pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags);
54543db86aabSstevel #endif
54553db86aabSstevel 		cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
54563db86aabSstevel #ifdef PCIC_DEBUG
54573db86aabSstevel 		pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps);
54583db86aabSstevel #endif
54593db86aabSstevel 		/*
54603db86aabSstevel 		 * Check the CB bits are sane.
54613db86aabSstevel 		 */
54623db86aabSstevel 		if ((cbps & pcic_cbps_on) != pcic_cbps_on ||
54633db86aabSstevel 		    cbps & pcic_cbps_off) {
54643db86aabSstevel 		    cmn_err(CE_WARN,
54653db86aabSstevel 			    "%s%d: Odd Cardbus Present State 0x%x\n",
54663db86aabSstevel 			    ddi_get_name(pcic->dip),
54673db86aabSstevel 			    ddi_get_instance(pcic->dip),
54683db86aabSstevel 			    cbps);
54693db86aabSstevel 		    pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST);
54703db86aabSstevel 		    debounce = 0;
54713db86aabSstevel 		    debounce_time = drv_usectohz(1000000);
54723db86aabSstevel 		}
54733db86aabSstevel 		if (debounce) {
54743db86aabSstevel 		    sockp->pcs_flags |= PCS_CARD_PRESENT;
54753db86aabSstevel 		    if (pcic_do_insertion) {
54763db86aabSstevel 
54773db86aabSstevel 			cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
54783db86aabSstevel 
54793db86aabSstevel 			if (cbps & CB_PS_16BITCARD) {
54803db86aabSstevel 			    pcic_err(pcic->dip, 8, "16 bit card inserted\n");
54813db86aabSstevel 			    sockp->pcs_flags |= PCS_CARD_IS16BIT;
54823db86aabSstevel 			    /* calls pcm_adapter_callback() */
54833db86aabSstevel 			    if (pcic->pc_callback) {
54843db86aabSstevel 
54853db86aabSstevel 				(void) ddi_prop_update_string(DDI_DEV_T_NONE,
54863db86aabSstevel 					pcic->dip, PCM_DEVICETYPE,
54873db86aabSstevel 					"pccard");
54883db86aabSstevel 				PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
54893db86aabSstevel 					    PCE_CARD_INSERT,
54903db86aabSstevel 					    sockp->pcs_socket);
54913db86aabSstevel 			    }
54923db86aabSstevel 			} else if (cbps & CB_PS_CBCARD) {
54933db86aabSstevel 			    pcic_err(pcic->dip, 8, "32 bit card inserted\n");
54943db86aabSstevel 
54953db86aabSstevel 			    if (pcic->pc_flags & PCF_CARDBUS) {
54963db86aabSstevel 				sockp->pcs_flags |= PCS_CARD_ISCARDBUS;
54973db86aabSstevel #ifdef CARDBUS
54983db86aabSstevel 				if (!pcic_load_cardbus(pcic, sockp)) {
54993db86aabSstevel 				    pcic_unload_cardbus(pcic, sockp);
55003db86aabSstevel 				}
55013db86aabSstevel 
55023db86aabSstevel #else
55033db86aabSstevel 				cmn_err(CE_NOTE,
55043db86aabSstevel 					"32 bit Cardbus not supported in"
55053db86aabSstevel 					" this device driver\n");
55063db86aabSstevel #endif
55073db86aabSstevel 			    } else {
55083db86aabSstevel 				/*
55093db86aabSstevel 				 * Ignore the card
55103db86aabSstevel 				 */
55113db86aabSstevel 				cmn_err(CE_NOTE,
55123db86aabSstevel 					"32 bit Cardbus not supported on this"
55133db86aabSstevel 					" device\n");
55143db86aabSstevel 			    }
55153db86aabSstevel 			} else {
55163db86aabSstevel 			    cmn_err(CE_NOTE,
55173db86aabSstevel 				"Unsupported PCMCIA card inserted\n");
55183db86aabSstevel 			}
55193db86aabSstevel 		    }
55203db86aabSstevel 		    syshw_send_signal(sockp->pcs_syshwsig);
55213db86aabSstevel 		} else {
55223db86aabSstevel 		    do_debounce = B_TRUE;
55233db86aabSstevel 		}
55243db86aabSstevel 	    } else {
55253db86aabSstevel 		/*
55263db86aabSstevel 		 * It is possible to come through here if the system
55273db86aabSstevel 		 * starts up with cards already inserted. Do nothing
55283db86aabSstevel 		 * and don't worry about it.
55293db86aabSstevel 		 */
55303db86aabSstevel #ifdef PCIC_DEBUG
55313db86aabSstevel 		pcic_err(pcic->dip, 5,
55323db86aabSstevel 			"pcic%d: Odd card insertion indication on socket %d\n",
55333db86aabSstevel 			ddi_get_instance(pcic->dip),
55343db86aabSstevel 			sockp->pcs_socket);
55353db86aabSstevel #endif
55363db86aabSstevel 	    }
55373db86aabSstevel 	    break;
55383db86aabSstevel 
55393db86aabSstevel 	default:
55403db86aabSstevel 	    if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
55413db86aabSstevel 		/*
55423db86aabSstevel 		 * Someone has started to insert a card so delay a while.
55433db86aabSstevel 		 */
55443db86aabSstevel 		do_debounce = B_TRUE;
55453db86aabSstevel 		break;
55463db86aabSstevel 	    }
55473db86aabSstevel 		/*
55483db86aabSstevel 		 * Otherwise this is basically the same as not present
55493db86aabSstevel 		 * so fall through.
55503db86aabSstevel 		 */
55513db86aabSstevel 
55523db86aabSstevel 		/* FALLTHRU */
55533db86aabSstevel 	case 0:
55543db86aabSstevel 	    if (sockp->pcs_flags & PCS_CARD_PRESENT) {
55553db86aabSstevel 		if (pcic->pc_flags & PCF_CBPWRCTL) {
55563db86aabSstevel 		    pcic_putcb(pcic, CB_CONTROL, 0);
55573db86aabSstevel 		} else {
55583db86aabSstevel 		    pcic_putb(pcic, sockp->pcs_socket, PCIC_POWER_CONTROL, 0);
55593db86aabSstevel 		    (void) pcic_getb(pcic, sockp->pcs_socket,
55603db86aabSstevel 			PCIC_POWER_CONTROL);
55613db86aabSstevel 		}
55623db86aabSstevel #ifdef PCIC_DEBUG
55633db86aabSstevel 		pcic_err(pcic->dip, 8, "Card removed\n");
55643db86aabSstevel #endif
55653db86aabSstevel 		sockp->pcs_flags &= ~PCS_CARD_PRESENT;
55663db86aabSstevel 
55673db86aabSstevel 		if (sockp->pcs_flags & PCS_CARD_IS16BIT) {
55683db86aabSstevel 		    sockp->pcs_flags &= ~PCS_CARD_IS16BIT;
55693db86aabSstevel 		    if (pcic_do_removal && pcic->pc_callback) {
55703db86aabSstevel 			PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
55713db86aabSstevel 				    PCE_CARD_REMOVAL, sockp->pcs_socket);
55723db86aabSstevel 		    }
55733db86aabSstevel 		}
55743db86aabSstevel 		if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) {
55753db86aabSstevel 		    sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS;
55763db86aabSstevel 		    sockp->pcs_flags |= PCS_CARD_CBREM;
55773db86aabSstevel 		}
55783db86aabSstevel 		sockp->pcs_flags |= PCS_CARD_REMOVED;
55793db86aabSstevel 
55803db86aabSstevel 		do_debounce = B_TRUE;
55813db86aabSstevel 	    }
55823db86aabSstevel 	    if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) {
55833db86aabSstevel 		if (sockp->pcs_flags & PCS_CARD_CBREM) {
55843db86aabSstevel 		/*
55853db86aabSstevel 		 * Ensure that we do the unloading in the
55863db86aabSstevel 		 * debounce handler, that way we're not doing
55873db86aabSstevel 		 * nasty things in an interrupt handler. e.g.
55883db86aabSstevel 		 * a USB device will wait for data which will
55893db86aabSstevel 		 * obviously never come because we've
55903db86aabSstevel 		 * unplugged the device, but the wait will
55913db86aabSstevel 		 * wait forever because no interrupts can
55923db86aabSstevel 		 * come in...
55933db86aabSstevel 		 */
55943db86aabSstevel #ifdef CARDBUS
55953db86aabSstevel 		    pcic_unload_cardbus(pcic, sockp);
55963db86aabSstevel 		    /* pcic_dump_all(pcic); */
55973db86aabSstevel #endif
55983db86aabSstevel 		    sockp->pcs_flags &= ~PCS_CARD_CBREM;
55993db86aabSstevel 		}
56003db86aabSstevel 		syshw_send_signal(sockp->pcs_syshwsig);
56013db86aabSstevel 		sockp->pcs_flags &= ~PCS_CARD_REMOVED;
56023db86aabSstevel 	    }
56033db86aabSstevel 	    break;
56043db86aabSstevel 	} /* switch */
56053db86aabSstevel 
56063db86aabSstevel 	if (do_debounce) {
56073db86aabSstevel 	/*
56083db86aabSstevel 	 * Delay doing
56093db86aabSstevel 	 * anything for a while so that things can settle
56103db86aabSstevel 	 * down a little. Interrupts are already disabled.
56113db86aabSstevel 	 * Reset the state and we'll reevaluate the
56123db86aabSstevel 	 * whole kit 'n kaboodle when the timeout fires
56133db86aabSstevel 	 */
56143db86aabSstevel #ifdef PCIC_DEBUG
56153db86aabSstevel 		pcic_err(pcic->dip, 8, "Queueing up debounce timeout for "
56163db86aabSstevel 			"socket %d.%d\n",
56173db86aabSstevel 			ddi_get_instance(pcic->dip),
56183db86aabSstevel 			sockp->pcs_socket);
56193db86aabSstevel #endif
56203db86aabSstevel 	    sockp->pcs_debounce_id = pcic_add_debqueue(sockp, debounce_time);
56213db86aabSstevel 
56223db86aabSstevel 	/*
56233db86aabSstevel 	 * We bug out here without re-enabling interrupts. They will
56243db86aabSstevel 	 * be re-enabled when the debounce timeout swings through
56253db86aabSstevel 	 * here.
56263db86aabSstevel 	 */
56273db86aabSstevel 	    return;
56283db86aabSstevel 	}
56293db86aabSstevel 
56303db86aabSstevel 	/*
56313db86aabSstevel 	 * Turn on Card detect interrupts. Other interrupts will be
56323db86aabSstevel 	 * enabled during set_socket calls.
56333db86aabSstevel 	 *
56343db86aabSstevel 	 * Note that set_socket only changes interrupt settings when there
56353db86aabSstevel 	 * is a card present.
56363db86aabSstevel 	 */
56373db86aabSstevel 	irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT);
56383db86aabSstevel 	irq |= PCIC_CD_DETECT;
56393db86aabSstevel 	pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq);
56400e995c33Srw148561 	pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK);
56413db86aabSstevel 
5642*0d282d13Srw148561 	/* Out from debouncing state */
5643*0d282d13Srw148561 	sockp->pcs_flags &= ~PCS_DEBOUNCING;
5644*0d282d13Srw148561 
56453db86aabSstevel 	pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n");
56463db86aabSstevel }
56473db86aabSstevel 
56483db86aabSstevel /*
56493db86aabSstevel  * pcic_getb()
56503db86aabSstevel  *	get an I/O byte based on the yardware decode method
56513db86aabSstevel  */
56523db86aabSstevel static uint8_t
56533db86aabSstevel pcic_getb(pcicdev_t *pcic, int socket, int reg)
56543db86aabSstevel {
56553db86aabSstevel 	int work;
56563db86aabSstevel 
56573db86aabSstevel #if defined(PCIC_DEBUG)
56583db86aabSstevel 	if (pcic_debug == 0x7fff) {
56593db86aabSstevel 		cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n",
56603db86aabSstevel 			(void *)pcic, socket, reg);
56613db86aabSstevel 		cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n",
56623db86aabSstevel 			pcic->pc_io_type, (void *)pcic->handle,
56633db86aabSstevel 			(void *)pcic->ioaddr);
56643db86aabSstevel 	}
56653db86aabSstevel #endif
56663db86aabSstevel 
56673db86aabSstevel 	switch (pcic->pc_io_type) {
56683db86aabSstevel 	case PCIC_IO_TYPE_YENTA:
56693db86aabSstevel 		return (ddi_get8(pcic->handle,
56703db86aabSstevel 		    pcic->ioaddr + CB_R2_OFFSET + reg));
56713db86aabSstevel 	default:
56723db86aabSstevel 		work = (socket * PCIC_SOCKET_1) | reg;
56733db86aabSstevel 		ddi_put8(pcic->handle, pcic->ioaddr, work);
56743db86aabSstevel 		return (ddi_get8(pcic->handle, pcic->ioaddr + 1));
56753db86aabSstevel 	}
56763db86aabSstevel }
56773db86aabSstevel 
56783db86aabSstevel static void
56793db86aabSstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value)
56803db86aabSstevel {
56813db86aabSstevel 	int work;
56823db86aabSstevel 
56833db86aabSstevel #if defined(PCIC_DEBUG)
56843db86aabSstevel 	if (pcic_debug == 0x7fff) {
56853db86aabSstevel 		cmn_err(CE_CONT,
56863db86aabSstevel 			"pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n",
56873db86aabSstevel 			(void *)pcic, socket, reg, value);
56883db86aabSstevel 		cmn_err(CE_CONT,
56893db86aabSstevel 			"pcic_putb1: type=%d handle=%p ioaddr=%p \n",
56903db86aabSstevel 			pcic->pc_io_type, (void *)pcic->handle,
56913db86aabSstevel 			(void *)pcic->ioaddr);
56923db86aabSstevel 	}
56933db86aabSstevel #endif
56943db86aabSstevel 
56953db86aabSstevel 
56963db86aabSstevel 	switch (pcic->pc_io_type) {
56973db86aabSstevel 	case PCIC_IO_TYPE_YENTA:
56983db86aabSstevel 		ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg,
56993db86aabSstevel 				value);
57003db86aabSstevel 		break;
57013db86aabSstevel 	default:
57023db86aabSstevel 		work = (socket * PCIC_SOCKET_1) | reg;
57033db86aabSstevel 		ddi_put8(pcic->handle, pcic->ioaddr, work);
57043db86aabSstevel 		ddi_put8(pcic->handle, pcic->ioaddr + 1, value);
57053db86aabSstevel 		break;
57063db86aabSstevel 	}
57073db86aabSstevel }
57083db86aabSstevel 
57093db86aabSstevel /*
57103db86aabSstevel  * chip identification functions
57113db86aabSstevel  */
57123db86aabSstevel 
57133db86aabSstevel /*
57143db86aabSstevel  * chip identification: Cirrus Logic PD6710/6720/6722
57153db86aabSstevel  */
57163db86aabSstevel static int
57173db86aabSstevel pcic_ci_cirrus(pcicdev_t *pcic)
57183db86aabSstevel {
57193db86aabSstevel 	int value1, value2;
57203db86aabSstevel 
57213db86aabSstevel 	/* Init the CL id mode */
57223db86aabSstevel 	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57233db86aabSstevel 	pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
57243db86aabSstevel 	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57253db86aabSstevel 	value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57263db86aabSstevel 
57273db86aabSstevel 	if ((value1 & PCIC_CI_ID) == PCIC_CI_ID &&
57283db86aabSstevel 	    (value2 & PCIC_CI_ID) == 0) {
57293db86aabSstevel 		/* chip is a Cirrus Logic and not Intel */
57303db86aabSstevel 		pcic->pc_type = PCIC_CL_PD6710;
57313db86aabSstevel 		if (value1 & PCIC_CI_SLOTS)
57323db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_PD6720;
57333db86aabSstevel 		else
57343db86aabSstevel 			pcic->pc_chipname = PCIC_TYPE_PD6710;
57353db86aabSstevel 		/* now fine tune things just in case a 6722 */
57363db86aabSstevel 		value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0);
57373db86aabSstevel 		if (value1 == 0) {
57383db86aabSstevel 			clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55);
57393db86aabSstevel 			value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH);
57403db86aabSstevel 			if (value1 == 0x55) {
57413db86aabSstevel 				pcic->pc_chipname = PCIC_TYPE_PD6722;
57423db86aabSstevel 				pcic->pc_type = PCIC_CL_PD6722;
57433db86aabSstevel 				clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0);
57443db86aabSstevel 			}
57453db86aabSstevel 		}
57463db86aabSstevel 		return (1);
57473db86aabSstevel 	}
57483db86aabSstevel 	return (0);
57493db86aabSstevel }
57503db86aabSstevel 
57513db86aabSstevel /*
57523db86aabSstevel  * chip identification: Vadem (VG365/465/468/469)
57533db86aabSstevel  */
57543db86aabSstevel 
57553db86aabSstevel static void
57563db86aabSstevel pcic_vadem_enable(pcicdev_t *pcic)
57573db86aabSstevel {
57583db86aabSstevel 	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1);
57593db86aabSstevel 	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2);
57603db86aabSstevel 	ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg);
57613db86aabSstevel }
57623db86aabSstevel 
57633db86aabSstevel static int
57643db86aabSstevel pcic_ci_vadem(pcicdev_t *pcic)
57653db86aabSstevel {
57663db86aabSstevel 	int value;
57673db86aabSstevel 
57683db86aabSstevel 	pcic_vadem_enable(pcic);
57693db86aabSstevel 	value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
57703db86aabSstevel 	pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF);
57713db86aabSstevel 	if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) ==
57723db86aabSstevel 	    (value | PCIC_VADEM_D3) ||
57733db86aabSstevel 	    (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) ==
57743db86aabSstevel 	    PCIC_VADEM_469) {
57753db86aabSstevel 		int vadem, new;
57763db86aabSstevel 		pcic_vadem_enable(pcic);
57773db86aabSstevel 		vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) &
57783db86aabSstevel 			~(PCIC_V_UNLOCK | PCIC_V_VADEMREV);
57793db86aabSstevel 		new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK);
57803db86aabSstevel 		pcic_putb(pcic, 0, PCIC_VG_DMA, new);
57813db86aabSstevel 		value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
57823db86aabSstevel 
57833db86aabSstevel 		/* want to lock but leave mouse or other on */
57843db86aabSstevel 		pcic_putb(pcic, 0, PCIC_VG_DMA, vadem);
57853db86aabSstevel 		switch (value & PCIC_REV_MASK) {
57863db86aabSstevel 		case PCIC_VADEM_365:
57873db86aabSstevel 			pcic->pc_chipname = PCIC_VG_365;
57883db86aabSstevel 			pcic->pc_type = PCIC_VADEM;
57893db86aabSstevel 			break;
57903db86aabSstevel 		case PCIC_VADEM_465:
57913db86aabSstevel 			pcic->pc_chipname = PCIC_VG_465;
57923db86aabSstevel 			pcic->pc_type = PCIC_VADEM;
57933db86aabSstevel 			pcic->pc_flags |= PCF_1SOCKET;
57943db86aabSstevel 			break;
57953db86aabSstevel 		case PCIC_VADEM_468:
57963db86aabSstevel 			pcic->pc_chipname = PCIC_VG_468;
57973db86aabSstevel 			pcic->pc_type = PCIC_VADEM;
57983db86aabSstevel 			break;
57993db86aabSstevel 		case PCIC_VADEM_469:
58003db86aabSstevel 			pcic->pc_chipname = PCIC_VG_469;
58013db86aabSstevel 			pcic->pc_type = PCIC_VADEM_VG469;
58023db86aabSstevel 			break;
58033db86aabSstevel 		}
58043db86aabSstevel 		return (1);
58053db86aabSstevel 	}
58063db86aabSstevel 	return (0);
58073db86aabSstevel }
58083db86aabSstevel 
58093db86aabSstevel /*
58103db86aabSstevel  * chip identification: Ricoh
58113db86aabSstevel  */
58123db86aabSstevel static int
58133db86aabSstevel pcic_ci_ricoh(pcicdev_t *pcic)
58143db86aabSstevel {
58153db86aabSstevel 	int value;
58163db86aabSstevel 
58173db86aabSstevel 	value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT);
58183db86aabSstevel 	switch (value) {
58193db86aabSstevel 	case PCIC_RF_296:
58203db86aabSstevel 		pcic->pc_type = PCIC_RICOH;
58213db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_RF5C296;
58223db86aabSstevel 		return (1);
58233db86aabSstevel 	case PCIC_RF_396:
58243db86aabSstevel 		pcic->pc_type = PCIC_RICOH;
58253db86aabSstevel 		pcic->pc_chipname = PCIC_TYPE_RF5C396;
58263db86aabSstevel 		return (1);
58273db86aabSstevel 	}
58283db86aabSstevel 	return (0);
58293db86aabSstevel }
58303db86aabSstevel 
58313db86aabSstevel 
58323db86aabSstevel /*
58333db86aabSstevel  * set up available address spaces in busra
58343db86aabSstevel  */
58353db86aabSstevel static void
58363db86aabSstevel pcic_init_assigned(dev_info_t *dip)
58373db86aabSstevel {
58383db86aabSstevel 	pcm_regs_t *pcic_avail_p;
58393db86aabSstevel 	pci_regspec_t *pci_avail_p, *regs;
58403db86aabSstevel 	int len, entries, rlen;
58413db86aabSstevel 	dev_info_t *pdip;
58423db86aabSstevel 
58433db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
58443db86aabSstevel 	    "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) {
58453db86aabSstevel 		/*
58463db86aabSstevel 		 * found "available" property at the cardbus/pcmcia node
58473db86aabSstevel 		 * need to translate address space entries from pcmcia
58483db86aabSstevel 		 * format to pci format
58493db86aabSstevel 		 */
58503db86aabSstevel 		entries = len / sizeof (pcm_regs_t);
58513db86aabSstevel 		pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries,
58523db86aabSstevel 			KM_SLEEP);
58533db86aabSstevel 		if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p,
58543db86aabSstevel 		    entries) == DDI_SUCCESS)
58553db86aabSstevel 			(void) pci_resource_setup_avail(dip, pci_avail_p,
58563db86aabSstevel 				entries);
58573db86aabSstevel 		kmem_free(pcic_avail_p, len);
58583db86aabSstevel 		kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t));
58593db86aabSstevel 		return;
58603db86aabSstevel 	}
58613db86aabSstevel 
58623db86aabSstevel 	/*
58633db86aabSstevel 	 * "legacy" platforms will have "available" property in pci node
58643db86aabSstevel 	 */
58653db86aabSstevel 	for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) {
58663db86aabSstevel 		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
58673db86aabSstevel 		    "available", (caddr_t)&pci_avail_p, &len) ==
58683db86aabSstevel 		    DDI_PROP_SUCCESS) {
58693db86aabSstevel 			/* (void) pci_resource_setup(pdip); */
58703db86aabSstevel 			kmem_free(pci_avail_p, len);
58713db86aabSstevel 			break;
58723db86aabSstevel 		}
58733db86aabSstevel 	}
58743db86aabSstevel 
58753db86aabSstevel 	if (pdip == NULL) {
58763db86aabSstevel 		int len;
58773db86aabSstevel 		char bus_type[16] = "(unknown)";
58783db86aabSstevel 		dev_info_t *par;
58793db86aabSstevel 
58803db86aabSstevel 		cmn_err(CE_CONT,
58813db86aabSstevel 		    "?pcic_init_assigned: no available property for pcmcia\n");
58823db86aabSstevel 
58833db86aabSstevel 		/*
58843db86aabSstevel 		 * This code is taken from pci_resource_setup() but does
58853db86aabSstevel 		 * not attempt to use the "available" property to populate
58863db86aabSstevel 		 * the ndi maps that are created.
58873db86aabSstevel 		 * The fact that we will actually
58883db86aabSstevel 		 * free some resource below (that was allocated by OBP)
58893db86aabSstevel 		 * should be enough to be going on with.
58903db86aabSstevel 		 */
58913db86aabSstevel 		for (par = dip; par != NULL; par = ddi_get_parent(par)) {
58923db86aabSstevel 			len = sizeof (bus_type);
58933db86aabSstevel 
58943db86aabSstevel 			if ((ddi_prop_op(DDI_DEV_T_ANY, par,
58953db86aabSstevel 			    PROP_LEN_AND_VAL_BUF,
58963db86aabSstevel 			    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
58973db86aabSstevel 			    "device_type",
58983db86aabSstevel 			    (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
58993db86aabSstevel 			    (strcmp(bus_type, "pci") == 0))
59003db86aabSstevel 				break;
59013db86aabSstevel 		}
59023db86aabSstevel 		if (par != NULL &&
59033db86aabSstevel 		    (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS ||
59043db86aabSstevel 		    ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS))
59053db86aabSstevel 			par = NULL;
59063db86aabSstevel 	} else {
59073db86aabSstevel #ifdef CARDBUS
59083db86aabSstevel 		cardbus_bus_range_t *bus_range;
59093db86aabSstevel 		int k;
59103db86aabSstevel 
59113db86aabSstevel 		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range",
59123db86aabSstevel 		    (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) {
59133db86aabSstevel 			if (bus_range->lo != bus_range->hi)
59143db86aabSstevel 				pcic_err(pdip, 9, "allowable bus range is "
59153db86aabSstevel 				    "%u->%u\n", bus_range->lo, bus_range->hi);
59163db86aabSstevel 			else {
59173db86aabSstevel 				pcic_err(pdip, 0,
59183db86aabSstevel 				    "!No spare PCI bus numbers, range is "
59193db86aabSstevel 				    "%u->%u, cardbus isn't usable\n",
59203db86aabSstevel 				    bus_range->lo, bus_range->hi);
59213db86aabSstevel 			}
59223db86aabSstevel 			kmem_free(bus_range, k);
59233db86aabSstevel 		} else
59243db86aabSstevel 			pcic_err(pdip, 0, "!No bus-range property seems to "
59253db86aabSstevel 			    "have been set up\n");
59263db86aabSstevel #endif
59273db86aabSstevel 		/*
59283db86aabSstevel 		 * Have a valid parent with the "available" property
59293db86aabSstevel 		 */
59303db86aabSstevel 		(void) pci_resource_setup(pdip);
59313db86aabSstevel 	}
59323db86aabSstevel 
59333db86aabSstevel 	if ((strcmp(ddi_get_name(dip), "pcma") == 0) &&
59343db86aabSstevel 	    ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
59353db86aabSstevel 	    "assigned-addresses",
59363db86aabSstevel 	    (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
59373db86aabSstevel 		ra_return_t ra;
59383db86aabSstevel 
59393db86aabSstevel 		/*
59403db86aabSstevel 		 * On the UltraBook IIi the ranges are assigned under
59413db86aabSstevel 		 * openboot. If we don't free them here the first I/O
59423db86aabSstevel 		 * space that can be used is up above 0x10000 which
59433db86aabSstevel 		 * doesn't work for this driver due to restrictions
59443db86aabSstevel 		 * on the PCI I/O addresses the controllers can cope with.
59453db86aabSstevel 		 * They are never going to be used by anything else
59463db86aabSstevel 		 * so free them up to the general pool. AG.
59473db86aabSstevel 		 */
59483db86aabSstevel 		pcic_err(dip, 1, "Free assigned addresses\n");
59493db86aabSstevel 
59503db86aabSstevel 		if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) ==
59513db86aabSstevel 		    PCI_REG_ADDR_G(PCI_ADDR_MEM32)) &&
59523db86aabSstevel 		    regs[0].pci_size_low == 0x1000000) {
59533db86aabSstevel 			ra.ra_addr_lo = regs[0].pci_phys_low;
59543db86aabSstevel 			ra.ra_len = regs[0].pci_size_low;
59553db86aabSstevel 			(void) pcmcia_free_mem(dip, &ra);
59563db86aabSstevel 		}
59573db86aabSstevel 		if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) ==
59583db86aabSstevel 		    PCI_REG_ADDR_G(PCI_ADDR_IO)) &&
59593db86aabSstevel 		    (regs[1].pci_size_low == 0x8000 ||
59603db86aabSstevel 		    regs[1].pci_size_low == 0x4000))   /* UB-IIi || UB-I */
59613db86aabSstevel 		{
59623db86aabSstevel 			ra.ra_addr_lo = regs[1].pci_phys_low;
59633db86aabSstevel 			ra.ra_len = regs[1].pci_size_low;
59643db86aabSstevel 			(void) pcmcia_free_io(dip, &ra);
59653db86aabSstevel 		}
59663db86aabSstevel 		kmem_free((caddr_t)regs, rlen);
59673db86aabSstevel 	}
59683db86aabSstevel }
59693db86aabSstevel 
59703db86aabSstevel /*
59713db86aabSstevel  * translate "available" from pcmcia format to pci format
59723db86aabSstevel  */
59733db86aabSstevel static int
59743db86aabSstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p,
59753db86aabSstevel     pci_regspec_t *pci_p, int entries)
59763db86aabSstevel {
59773db86aabSstevel 	int i, range_len, range_entries;
59783db86aabSstevel 	pcic_ranges_t *pcic_range_p;
59793db86aabSstevel 
59803db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
59813db86aabSstevel 		    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
59823db86aabSstevel 		cmn_err(CE_CONT, "?pcic_apply_avail_ranges: "
59833db86aabSstevel 			"no ranges property for pcmcia\n");
59843db86aabSstevel 		return (DDI_FAILURE);
59853db86aabSstevel 	}
59863db86aabSstevel 
59873db86aabSstevel 	range_entries = range_len / sizeof (pcic_ranges_t);
59883db86aabSstevel 
59893db86aabSstevel 	/* for each "available" entry to be translated */
59903db86aabSstevel 	for (i = 0; i < entries; i++, pcic_p++, pci_p++) {
59913db86aabSstevel 		int j;
59923db86aabSstevel 		pcic_ranges_t *range_p = pcic_range_p;
59933db86aabSstevel 		pci_p->pci_phys_hi = -1u; /* default invalid value */
59943db86aabSstevel 
59953db86aabSstevel 		/* for each "ranges" entry to be searched */
59963db86aabSstevel 		for (j = 0; j < range_entries; j++, range_p++) {
59973db86aabSstevel 			uint64_t range_end = range_p->pcic_range_caddrlo +
59983db86aabSstevel 				range_p->pcic_range_size;
59993db86aabSstevel 			uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len;
60003db86aabSstevel 
60013db86aabSstevel 			if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) ||
60023db86aabSstevel 			    (range_p->pcic_range_caddrlo > pcic_p->phys_lo) ||
60033db86aabSstevel 			    (range_end < avail_end))
60043db86aabSstevel 				continue;
60053db86aabSstevel 
60063db86aabSstevel 			pci_p->pci_phys_hi = range_p->pcic_range_paddrhi;
60073db86aabSstevel 			pci_p->pci_phys_mid = range_p->pcic_range_paddrmid;
60083db86aabSstevel 			pci_p->pci_phys_low = range_p->pcic_range_paddrlo
60093db86aabSstevel 			    + (pcic_p->phys_lo - range_p->pcic_range_caddrlo);
60103db86aabSstevel 			pci_p->pci_size_hi = 0;
60113db86aabSstevel 			pci_p->pci_size_low = pcic_p->phys_len;
60123db86aabSstevel 		}
60133db86aabSstevel 	}
60143db86aabSstevel 	kmem_free(pcic_range_p, range_len);
60153db86aabSstevel 	return (DDI_SUCCESS);
60163db86aabSstevel }
60173db86aabSstevel 
60183db86aabSstevel static int
60193db86aabSstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred)
60203db86aabSstevel {
60213db86aabSstevel 	if (getminor(*dev) == SYSHW_MINOR)
60223db86aabSstevel 		return (syshw_open(dev, flag, otyp, cred));
60233db86aabSstevel #ifdef CARDBUS
60243db86aabSstevel 	if (cardbus_is_cb_minor(*dev))
60253db86aabSstevel 		return (cardbus_open(dev, flag, otyp, cred));
60263db86aabSstevel #endif
60273db86aabSstevel 	return (EINVAL);
60283db86aabSstevel }
60293db86aabSstevel 
60303db86aabSstevel static int
60313db86aabSstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred)
60323db86aabSstevel {
60333db86aabSstevel 	if (getminor(dev) == SYSHW_MINOR)
60343db86aabSstevel 		return (syshw_close(dev, flag, otyp, cred));
60353db86aabSstevel #ifdef CARDBUS
60363db86aabSstevel 	if (cardbus_is_cb_minor(dev))
60373db86aabSstevel 		return (cardbus_close(dev, flag, otyp, cred));
60383db86aabSstevel #endif
60393db86aabSstevel 	return (EINVAL);
60403db86aabSstevel }
60413db86aabSstevel 
60423db86aabSstevel static int
60433db86aabSstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
60443db86aabSstevel 	int *rval)
60453db86aabSstevel {
60463db86aabSstevel 	if (getminor(dev) == SYSHW_MINOR)
60473db86aabSstevel 		return (syshw_ioctl(dev, cmd, arg, mode, cred, rval));
60483db86aabSstevel #ifdef CARDBUS
60493db86aabSstevel 	if (cardbus_is_cb_minor(dev))
60503db86aabSstevel 		return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval));
60513db86aabSstevel #endif
60523db86aabSstevel 	return (EINVAL);
60533db86aabSstevel }
60543db86aabSstevel 
60553db86aabSstevel 
60563db86aabSstevel static boolean_t
60573db86aabSstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
60583db86aabSstevel {
60593db86aabSstevel 	uint32_t present_state;
60603db86aabSstevel 	dev_info_t *dip = pcic->dip;
60613db86aabSstevel 	set_socket_t s;
60623db86aabSstevel 	get_socket_t g;
60633db86aabSstevel 	boolean_t retval;
60643db86aabSstevel 	unsigned vccLevel;
60653db86aabSstevel 
60663db86aabSstevel 	pcic_err(dip, 8, "entering pcic_load_cardbus\n");
60673db86aabSstevel 
60683db86aabSstevel 	pcic_mutex_exit(&pcic->pc_lock);
60693db86aabSstevel 
60703db86aabSstevel 	bzero(&s, sizeof (set_socket_t));
60713db86aabSstevel 	s.socket = sockp->pcs_socket;
60723db86aabSstevel 	s.SCIntMask = SBM_CD|SBM_RDYBSY;
60733db86aabSstevel 	s.IFType = IF_CARDBUS;
60743db86aabSstevel 	s.State = (unsigned)~0;
60753db86aabSstevel 
60763db86aabSstevel 	present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
60773db86aabSstevel 	if (present_state & PCIC_VCC_3VCARD)
60783db86aabSstevel 		s.VccLevel = PCIC_VCC_3VLEVEL;
60793db86aabSstevel 	else if (present_state & PCIC_VCC_5VCARD)
60803db86aabSstevel 		s.VccLevel = PCIC_VCC_5VLEVEL;
60813db86aabSstevel 	else {
60823db86aabSstevel 		cmn_err(CE_CONT,
60833db86aabSstevel 		    "pcic_load_cardbus: unsupported card voltage\n");
60843db86aabSstevel 		goto failure;
60853db86aabSstevel 	}
60863db86aabSstevel 	vccLevel = s.VccLevel;
60873db86aabSstevel 	s.Vpp1Level = s.Vpp2Level = 0;
60883db86aabSstevel 
60893db86aabSstevel 	if (pcic_set_socket(dip, &s) != SUCCESS)
60903db86aabSstevel 		goto failure;
60913db86aabSstevel 
60923db86aabSstevel 	if (pcic_reset_socket(dip, sockp->pcs_socket,
60933db86aabSstevel 	    RESET_MODE_CARD_ONLY) != SUCCESS)
60943db86aabSstevel 		goto failure;
60953db86aabSstevel 
60963db86aabSstevel 	bzero(&g, sizeof (get_socket_t));
60973db86aabSstevel 	g.socket = sockp->pcs_socket;
60983db86aabSstevel 	if (pcic_get_socket(dip, &g) != SUCCESS)
60993db86aabSstevel 		goto failure;
61003db86aabSstevel 
61013db86aabSstevel 	bzero(&s, sizeof (set_socket_t));
61023db86aabSstevel 	s.socket = sockp->pcs_socket;
61033db86aabSstevel 	s.SCIntMask = SBM_CD;
61043db86aabSstevel 	s.IREQRouting = g.IRQRouting;
61053db86aabSstevel 	s.IFType = g.IFType;
61063db86aabSstevel 	s.CtlInd = g.CtlInd;
61073db86aabSstevel 	s.State = (unsigned)~0;
61083db86aabSstevel 	s.VccLevel = vccLevel;
61093db86aabSstevel 	s.Vpp1Level = s.Vpp2Level = 0;
61103db86aabSstevel 
61113db86aabSstevel 	if (pcic_set_socket(dip, &s) != SUCCESS)
61123db86aabSstevel 		goto failure;
61133db86aabSstevel 
61143db86aabSstevel 	retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base);
61153db86aabSstevel 	goto exit;
61163db86aabSstevel 
61173db86aabSstevel failure:
61183db86aabSstevel 	retval = B_FALSE;
61193db86aabSstevel 
61203db86aabSstevel exit:
61213db86aabSstevel 	pcic_mutex_enter(&pcic->pc_lock);
61223db86aabSstevel 	pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n",
61233db86aabSstevel 	    retval ? "success" : "failure");
61243db86aabSstevel 	return (retval);
61253db86aabSstevel }
61263db86aabSstevel 
61273db86aabSstevel static void
61283db86aabSstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
61293db86aabSstevel {
61303db86aabSstevel 	dev_info_t *dip = pcic->dip;
61313db86aabSstevel 	set_socket_t s;
61323db86aabSstevel 
61333db86aabSstevel 	pcic_mutex_exit(&pcic->pc_lock);
61343db86aabSstevel 
61353db86aabSstevel 	cardbus_unload_cardbus(dip);
61363db86aabSstevel 
61373db86aabSstevel 	bzero(&s, sizeof (set_socket_t));
61383db86aabSstevel 	s.socket = sockp->pcs_socket;
61393db86aabSstevel 	s.SCIntMask = SBM_CD|SBM_RDYBSY;
61403db86aabSstevel 	s.IREQRouting = 0;
61413db86aabSstevel 	s.IFType = IF_MEMORY;
61423db86aabSstevel 	s.CtlInd = 0;
61433db86aabSstevel 	s.State = 0;
61443db86aabSstevel 	s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0;
61453db86aabSstevel 
61463db86aabSstevel 	(void) pcic_set_socket(dip, &s);
61473db86aabSstevel 
61483db86aabSstevel 	pcic_mutex_enter(&pcic->pc_lock);
61493db86aabSstevel }
61503db86aabSstevel 
61513db86aabSstevel static uint32_t
61523db86aabSstevel pcic_getcb(pcicdev_t *pcic, int reg)
61533db86aabSstevel {
61543db86aabSstevel 	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61553db86aabSstevel 
61563db86aabSstevel 	return (ddi_get32(pcic->handle,
61573db86aabSstevel 	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg)));
61583db86aabSstevel }
61593db86aabSstevel 
61603db86aabSstevel static void
61613db86aabSstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value)
61623db86aabSstevel {
61633db86aabSstevel 	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61643db86aabSstevel 
61653db86aabSstevel 	ddi_put32(pcic->handle,
61663db86aabSstevel 	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value);
61673db86aabSstevel }
61683db86aabSstevel 
61693db86aabSstevel static void
61703db86aabSstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq)
61713db86aabSstevel {
61723db86aabSstevel 	uint8_t value;
61733db86aabSstevel 	uint16_t brdgctl;
61743db86aabSstevel 
61753db86aabSstevel 	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
61763db86aabSstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq);
61773db86aabSstevel 
61783db86aabSstevel 	switch (pcic->pc_type) {
61793db86aabSstevel 	case PCIC_INTEL_i82092:
61803db86aabSstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
61813db86aabSstevel 		    PCIC_82092_INT_ENABLE);
61823db86aabSstevel 		break;
61833db86aabSstevel 	case PCIC_O2_OZ6912:
61843db86aabSstevel 		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
61853db86aabSstevel 		value |= 0x8;
61863db86aabSstevel 		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
61873db86aabSstevel 		break;
61883db86aabSstevel 	case PCIC_CL_PD6832:
61893db86aabSstevel 	case PCIC_TI_PCI1250:
61903db86aabSstevel 	case PCIC_TI_PCI1221:
61913db86aabSstevel 	case PCIC_TI_PCI1225:
61923db86aabSstevel 	case PCIC_TI_PCI1410:
61933db86aabSstevel 	case PCIC_ENE_1410:
61943db86aabSstevel 	case PCIC_TI_PCI1510:
61953db86aabSstevel 	case PCIC_TI_PCI1520:
61963db86aabSstevel 	case PCIC_TI_PCI1420:
61973db86aabSstevel 	case PCIC_ENE_1420:
61983db86aabSstevel 		/* route card functional interrupts to PCI interrupts */
61993db86aabSstevel 		brdgctl = ddi_get16(pcic->cfg_handle,
62003db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62013db86aabSstevel 		pcic_err(NULL, 1,
62023db86aabSstevel 		    "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n",
62033db86aabSstevel 		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
62043db86aabSstevel 		brdgctl &= ~PCIC_BRDGCTL_INTR_MASK;
62053db86aabSstevel 		ddi_put16(pcic->cfg_handle,
62063db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62073db86aabSstevel 		    brdgctl);
62083db86aabSstevel 		/* Flush the write */
62093db86aabSstevel 		(void) ddi_get16(pcic->cfg_handle,
62103db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62113db86aabSstevel 		break;
62123db86aabSstevel 	default:
62133db86aabSstevel 		break;
62143db86aabSstevel 	}
62153db86aabSstevel }
62163db86aabSstevel 
62173db86aabSstevel static void
62183db86aabSstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket)
62193db86aabSstevel {
62203db86aabSstevel 	uint8_t value;
62213db86aabSstevel 	uint16_t brdgctl;
62223db86aabSstevel 
62233db86aabSstevel 	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62243db86aabSstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, value);
62253db86aabSstevel 
62263db86aabSstevel 	switch (pcic->pc_type) {
62273db86aabSstevel 	case PCIC_INTEL_i82092:
62283db86aabSstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62293db86aabSstevel 		    PCIC_82092_INT_DISABLE);
62303db86aabSstevel 		break;
62313db86aabSstevel 	case PCIC_O2_OZ6912:
62323db86aabSstevel 		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62333db86aabSstevel 		value &= ~0x8;
62343db86aabSstevel 		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62353db86aabSstevel 		/* Flush the write */
62363db86aabSstevel 		(void) pcic_getb(pcic, 0, PCIC_CENTDMA);
62373db86aabSstevel 		break;
62383db86aabSstevel 	case PCIC_CL_PD6832:
62393db86aabSstevel 	case PCIC_TI_PCI1250:
62403db86aabSstevel 	case PCIC_TI_PCI1221:
62413db86aabSstevel 	case PCIC_TI_PCI1225:
62423db86aabSstevel 	case PCIC_TI_PCI1410:
62433db86aabSstevel 	case PCIC_ENE_1410:
62443db86aabSstevel 	case PCIC_TI_PCI1510:
62453db86aabSstevel 	case PCIC_TI_PCI1520:
62463db86aabSstevel 	case PCIC_TI_PCI1420:
62473db86aabSstevel 	case PCIC_ENE_1420:
62483db86aabSstevel 		/*
62493db86aabSstevel 		 * This maps I/O interrupts to ExCA which
62503db86aabSstevel 		 * have been turned off by the write to
62513db86aabSstevel 		 * PCIC_INTERRUPT above. It would appear to
62523db86aabSstevel 		 * be the only way to actually turn I/O Ints off
62533db86aabSstevel 		 * while retaining CS Ints.
62543db86aabSstevel 		 */
62553db86aabSstevel 		brdgctl = ddi_get16(pcic->cfg_handle,
62563db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62573db86aabSstevel 		pcic_err(NULL, 1,
62583db86aabSstevel 		    "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n",
62593db86aabSstevel 		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
62603db86aabSstevel 		brdgctl |= PCIC_BRDGCTL_INTR_MASK;
62613db86aabSstevel 		ddi_put16(pcic->cfg_handle,
62623db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62633db86aabSstevel 		    brdgctl);
62643db86aabSstevel 		/* Flush the write */
62653db86aabSstevel 		(void) ddi_get16(pcic->cfg_handle,
62663db86aabSstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62673db86aabSstevel 		break;
62683db86aabSstevel 	default:
62693db86aabSstevel 		break;
62703db86aabSstevel 	}
62713db86aabSstevel }
62723db86aabSstevel 
62733db86aabSstevel static void
62743db86aabSstevel pcic_cb_enable_intr(dev_info_t *dip)
62753db86aabSstevel {
62763db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
62773db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
62783db86aabSstevel 
62793db86aabSstevel 	mutex_enter(&pcic->pc_lock);
62803db86aabSstevel 	pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq);
62813db86aabSstevel 	mutex_exit(&pcic->pc_lock);
62823db86aabSstevel }
62833db86aabSstevel 
62843db86aabSstevel static void
62853db86aabSstevel pcic_cb_disable_intr(dev_info_t *dip)
62863db86aabSstevel {
62873db86aabSstevel 	anp_t *anp = ddi_get_driver_private(dip);
62883db86aabSstevel 	pcicdev_t *pcic = anp->an_private;
62893db86aabSstevel 
62903db86aabSstevel 	mutex_enter(&pcic->pc_lock);
62913db86aabSstevel 	pcic_disable_io_intr(pcic, 0);
62923db86aabSstevel 	mutex_exit(&pcic->pc_lock);
62933db86aabSstevel }
62943db86aabSstevel 
62953db86aabSstevel static int
62963db86aabSstevel log_pci_cfg_err(ushort_t e, int bridge_secondary)
62973db86aabSstevel {
62983db86aabSstevel 	int	nerr = 0;
62993db86aabSstevel 	if (e & PCI_STAT_PERROR) {
63003db86aabSstevel 		nerr++;
63013db86aabSstevel 		cmn_err(CE_CONT, "detected parity error.\n");
63023db86aabSstevel 	}
63033db86aabSstevel 	if (e & PCI_STAT_S_SYSERR) {
63043db86aabSstevel 		nerr++;
63053db86aabSstevel 		if (bridge_secondary)
63063db86aabSstevel 			cmn_err(CE_CONT, "received system error.\n");
63073db86aabSstevel 		else
63083db86aabSstevel 			cmn_err(CE_CONT, "signalled system error.\n");
63093db86aabSstevel 	}
63103db86aabSstevel 	if (e & PCI_STAT_R_MAST_AB) {
63113db86aabSstevel 		nerr++;
63123db86aabSstevel 		cmn_err(CE_CONT, "received master abort.\n");
63133db86aabSstevel 	}
63143db86aabSstevel 	if (e & PCI_STAT_R_TARG_AB)
63153db86aabSstevel 		cmn_err(CE_CONT, "received target abort.\n");
63163db86aabSstevel 	if (e & PCI_STAT_S_TARG_AB)
63173db86aabSstevel 		cmn_err(CE_CONT, "signalled target abort\n");
63183db86aabSstevel 	if (e & PCI_STAT_S_PERROR) {
63193db86aabSstevel 		nerr++;
63203db86aabSstevel 		cmn_err(CE_CONT, "signalled parity error\n");
63213db86aabSstevel 	}
63223db86aabSstevel 	return (nerr);
63233db86aabSstevel }
63243db86aabSstevel 
63253db86aabSstevel #if defined(__sparc)
63263db86aabSstevel static int
63273db86aabSstevel pcic_fault(enum pci_fault_ops op, void *arg)
63283db86aabSstevel {
63293db86aabSstevel 	pcicdev_t *pcic = (pcicdev_t *)arg;
63303db86aabSstevel 	ushort_t pci_cfg_stat =
63313db86aabSstevel 	    pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT);
63323db86aabSstevel 	ushort_t pci_cfg_sec_stat =
63333db86aabSstevel 	    pci_config_get16(pcic->cfg_handle, 0x16);
63343db86aabSstevel 	char	nm[24];
63353db86aabSstevel 	int	nerr = 0;
63363db86aabSstevel 
63373db86aabSstevel 	cardbus_dump_pci_config(pcic->dip);
63383db86aabSstevel 
63393db86aabSstevel 	switch (op) {
63403db86aabSstevel 	case FAULT_LOG:
63413db86aabSstevel 		(void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip),
63423db86aabSstevel 		    ddi_get_instance(pcic->dip));
63433db86aabSstevel 
63443db86aabSstevel 		cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm);
63453db86aabSstevel 		cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat);
63463db86aabSstevel 		nerr += log_pci_cfg_err(pci_cfg_stat, 0);
63473db86aabSstevel 		cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat);
63483db86aabSstevel 		nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1);
63493db86aabSstevel 		cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm);
63503db86aabSstevel 		return (nerr);
63513db86aabSstevel 	case FAULT_POKEFINI:
63523db86aabSstevel 	case FAULT_RESET:
63533db86aabSstevel 		pci_config_put16(pcic->cfg_handle,
63543db86aabSstevel 		    PCI_CONF_STAT, pci_cfg_stat);
63553db86aabSstevel 		pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat);
63563db86aabSstevel 		break;
63573db86aabSstevel 	case FAULT_POKEFLT:
63583db86aabSstevel 		if (!(pci_cfg_stat & PCI_STAT_S_SYSERR))
63593db86aabSstevel 			return (1);
63603db86aabSstevel 		if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB))
63613db86aabSstevel 			return (1);
63623db86aabSstevel 		break;
63633db86aabSstevel 	default:
63643db86aabSstevel 		break;
63653db86aabSstevel 	}
63663db86aabSstevel 	return (DDI_SUCCESS);
63673db86aabSstevel }
63683db86aabSstevel #endif
63693db86aabSstevel 
63703db86aabSstevel static void
63713db86aabSstevel pcic_delayed_resume(void *arg)
63723db86aabSstevel {
63733db86aabSstevel 	int	i, j, interrupt;
63743db86aabSstevel 	anp_t *pcic_nexus;
63753db86aabSstevel 	pcicdev_t *pcic;
63763db86aabSstevel 
63773db86aabSstevel 	_NOTE(ARGUNUSED(arg))
63783db86aabSstevel 
63793db86aabSstevel #if defined(PCIC_DEBUG)
63803db86aabSstevel 	pcic_err(NULL, 6, "pcic_delayed_resume(): entered\n");
63813db86aabSstevel #endif
63823db86aabSstevel 	for (j = 0; j <= pcic_maxinst; j++) {
63833db86aabSstevel 
63843db86aabSstevel 		pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, j);
63853db86aabSstevel 		if (!pcic_nexus)
63863db86aabSstevel 			continue;
63873db86aabSstevel 		pcic = (pcicdev_t *)pcic_nexus->an_private;
63883db86aabSstevel 		if (!pcic)
63893db86aabSstevel 			continue;
63903db86aabSstevel 
63913db86aabSstevel 		pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */
63923db86aabSstevel 		for (i = 0; i < pcic->pc_numsockets; i++) {
63933db86aabSstevel 			/* Enable interrupts  on PCI if needs be */
63943db86aabSstevel 			interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT);
63953db86aabSstevel 			if (pcic->pc_flags & PCF_USE_SMI)
63963db86aabSstevel 				interrupt |= PCIC_INTR_ENABLE;
63973db86aabSstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT,
63983db86aabSstevel 			    PCIC_RESET | interrupt);
63993db86aabSstevel 			pcic->pc_sockets[i].pcs_debounce_id =
64003db86aabSstevel 			    pcic_add_debqueue(&pcic->pc_sockets[i],
64013db86aabSstevel 			    drv_usectohz(pcic_debounce_time));
64023db86aabSstevel 		}
64033db86aabSstevel 		pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */
64043db86aabSstevel 		if (pcic_do_pcmcia_sr)
64053db86aabSstevel 			(void) pcmcia_wait_insert(pcic->dip);
64063db86aabSstevel 	}
64073db86aabSstevel }
64083db86aabSstevel 
64093db86aabSstevel static void
64103db86aabSstevel pcic_debounce(pcic_socket_t *pcs)
64113db86aabSstevel {
64123db86aabSstevel 	uint8_t status, stschng;
64133db86aabSstevel 
64143db86aabSstevel 	pcic_mutex_enter(&pcs->pcs_pcic->pc_lock);
64153db86aabSstevel 	pcs->pcs_flags &= ~PCS_STARTING;
64163db86aabSstevel 	stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64173db86aabSstevel 	    PCIC_CARD_STATUS_CHANGE);
64183db86aabSstevel 	status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64193db86aabSstevel 	    PCIC_INTERFACE_STATUS);
64203db86aabSstevel #ifdef PCIC_DEBUG
64213db86aabSstevel 	pcic_err(pcs->pcs_pcic->dip, 8,
64223db86aabSstevel 	    "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x "
64233db86aabSstevel 	    "chg 0x%x flg 0x%x\n",
64243db86aabSstevel 	    (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket,
64253db86aabSstevel 	    status, stschng, pcs->pcs_flags);
64263db86aabSstevel #endif
64273db86aabSstevel 
64283db86aabSstevel 	pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE,
64293db86aabSstevel 	    PCIC_CD_DETECT);
64303db86aabSstevel 	pcic_handle_cd_change(pcs->pcs_pcic, pcs, status);
64313db86aabSstevel 	pcic_mutex_exit(&pcs->pcs_pcic->pc_lock);
64323db86aabSstevel }
64333db86aabSstevel 
64343db86aabSstevel static void
64353db86aabSstevel pcic_deb_thread()
64363db86aabSstevel {
64373db86aabSstevel 	callb_cpr_t cprinfo;
64383db86aabSstevel 	struct debounce *debp;
64393db86aabSstevel 	clock_t lastt;
64403db86aabSstevel 
64413db86aabSstevel 	CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx,
64423db86aabSstevel 	    callb_generic_cpr, "pcic debounce thread");
64433db86aabSstevel 	mutex_enter(&pcic_deb_mtx);
64443db86aabSstevel 	while (pcic_deb_threadid) {
64453db86aabSstevel 		while (pcic_deb_queue) {
64463db86aabSstevel #ifdef PCIC_DEBUG
64473db86aabSstevel 			pcic_dump_debqueue("Thread");
64483db86aabSstevel #endif
64493db86aabSstevel 			debp = pcic_deb_queue;
64503db86aabSstevel 			(void) drv_getparm(LBOLT, &lastt);
64513db86aabSstevel 			if (lastt >= debp->expire) {
64523db86aabSstevel 				pcic_deb_queue = debp->next;
64533db86aabSstevel 				mutex_exit(&pcic_deb_mtx);
64543db86aabSstevel 				pcic_debounce(debp->pcs);
64553db86aabSstevel 				mutex_enter(&pcic_deb_mtx);
64563db86aabSstevel 				kmem_free(debp, sizeof (*debp));
64573db86aabSstevel 			} else {
64583db86aabSstevel 				(void) cv_timedwait(&pcic_deb_cv,
64593db86aabSstevel 				    &pcic_deb_mtx, debp->expire);
64603db86aabSstevel 			}
64613db86aabSstevel 		}
64623db86aabSstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
64633db86aabSstevel 		cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
64643db86aabSstevel 		CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx);
64653db86aabSstevel 	}
64663db86aabSstevel 	pcic_deb_threadid = (kthread_t *)1;
64673db86aabSstevel 	cv_signal(&pcic_deb_cv);
64683db86aabSstevel 	CALLB_CPR_EXIT(&cprinfo);	/* Also exits the mutex */
64693db86aabSstevel 	thread_exit();
64703db86aabSstevel }
64713db86aabSstevel 
64723db86aabSstevel static void *
64733db86aabSstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks)
64743db86aabSstevel {
64753db86aabSstevel 	clock_t lbolt;
64763db86aabSstevel 	struct debounce *dbp, **dbpp = &pcic_deb_queue;
64773db86aabSstevel 
64783db86aabSstevel 	(void) drv_getparm(LBOLT, &lbolt);
64793db86aabSstevel 	dbp = kmem_alloc(sizeof (struct debounce), KM_NOSLEEP);
64803db86aabSstevel 
64813db86aabSstevel 	dbp->expire = lbolt + clocks;
64823db86aabSstevel 	dbp->pcs = pcs;
64833db86aabSstevel 	mutex_enter(&pcic_deb_mtx);
64843db86aabSstevel 	while (*dbpp) {
64853db86aabSstevel 		if (dbp->expire > (*dbpp)->expire)
64863db86aabSstevel 			dbpp = &((*dbpp)->next);
64873db86aabSstevel 		else
64883db86aabSstevel 			break;
64893db86aabSstevel 	}
64903db86aabSstevel 	dbp->next = *dbpp;
64913db86aabSstevel 	*dbpp = dbp;
64923db86aabSstevel #ifdef PCIC_DEBUG
64933db86aabSstevel 	pcic_dump_debqueue("Add");
64943db86aabSstevel #endif
64953db86aabSstevel 	cv_signal(&pcic_deb_cv);
64963db86aabSstevel 	mutex_exit(&pcic_deb_mtx);
64973db86aabSstevel 	return (dbp);
64983db86aabSstevel }
64993db86aabSstevel 
65003db86aabSstevel static void
65013db86aabSstevel pcic_rm_debqueue(void *id)
65023db86aabSstevel {
65033db86aabSstevel 	struct debounce *dbp, **dbpp = &pcic_deb_queue;
65043db86aabSstevel 
65053db86aabSstevel 	dbp = (struct debounce *)id;
65063db86aabSstevel 	mutex_enter(&pcic_deb_mtx);
65073db86aabSstevel 	while (*dbpp) {
65083db86aabSstevel 		if (*dbpp == dbp) {
65093db86aabSstevel 			*dbpp = dbp->next;
65103db86aabSstevel 			kmem_free(dbp, sizeof (*dbp));
65113db86aabSstevel #ifdef PCIC_DEBUG
65123db86aabSstevel 			pcic_dump_debqueue("Remove");
65133db86aabSstevel #endif
65143db86aabSstevel 			cv_signal(&pcic_deb_cv);
65153db86aabSstevel 			mutex_exit(&pcic_deb_mtx);
65163db86aabSstevel 			return;
65173db86aabSstevel 		}
65183db86aabSstevel 		dbpp = &((*dbpp)->next);
65193db86aabSstevel 	}
65203db86aabSstevel 	pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id);
65213db86aabSstevel 	mutex_exit(&pcic_deb_mtx);
65223db86aabSstevel }
65233db86aabSstevel 
65243db86aabSstevel 
65253db86aabSstevel static int	pcic_powerdelay = 0;
65263db86aabSstevel 
65273db86aabSstevel static int
65283db86aabSstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel)
65293db86aabSstevel {
65303db86aabSstevel 	int	ind, value, orig_pwrctl;
65313db86aabSstevel 
65323db86aabSstevel 	/* power setup -- if necessary */
65333db86aabSstevel 	orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65343db86aabSstevel 
65353db86aabSstevel #if defined(PCIC_DEBUG)
65363db86aabSstevel 	pcic_err(pcic->dip, 6,
65373db86aabSstevel 	    "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n",
65383db86aabSstevel 	    socket, powerlevel, orig_pwrctl);
65393db86aabSstevel #endif
65403db86aabSstevel 	/* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */
65413db86aabSstevel 	powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) |
65423db86aabSstevel 	    (orig_pwrctl & POWER_OUTPUT_ENABLE);
65433db86aabSstevel 	if (powerlevel != orig_pwrctl) {
65443db86aabSstevel 		if (powerlevel & ~POWER_OUTPUT_ENABLE) {
65453db86aabSstevel 			int	ifs;
65463db86aabSstevel 			/*
65473db86aabSstevel 			 * set power to socket
65483db86aabSstevel 			 * note that the powerlevel was calculated earlier
65493db86aabSstevel 			 */
65503db86aabSstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
65513db86aabSstevel 			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65523db86aabSstevel 
65533db86aabSstevel 			/*
65543db86aabSstevel 			 * this second write to the power control register
65553db86aabSstevel 			 * is needed to resolve a problem on
65563db86aabSstevel 			 * the IBM ThinkPad 750
65573db86aabSstevel 			 * where the first write doesn't latch.
65583db86aabSstevel 			 * The second write appears to always work and
65593db86aabSstevel 			 * doesn't hurt the operation of other chips
65603db86aabSstevel 			 * so we can just use it -- this is good since we can't
65613db86aabSstevel 			 * determine what chip the 750 actually uses
65623db86aabSstevel 			 * (I suspect an early Ricoh).
65633db86aabSstevel 			 */
65643db86aabSstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
65653db86aabSstevel 
65663db86aabSstevel 			value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65673db86aabSstevel 			pcic_mswait(pcic, socket, pcic_powerdelay);
65683db86aabSstevel #if defined(PCIC_DEBUG)
65693db86aabSstevel 			pcic_err(pcic->dip, 8,
65703db86aabSstevel 			    "\tpowerlevel reg = %x (ifs %x)\n",
65713db86aabSstevel 			    value, pcic_getb(pcic, socket,
65723db86aabSstevel 			    PCIC_INTERFACE_STATUS));
65733db86aabSstevel 			pcic_err(pcic->dip, 8,
65743db86aabSstevel 			    "CBus regs: PS 0x%x, Control 0x%x\n",
65753db86aabSstevel 			    pcic_getcb(pcic, CB_PRESENT_STATE),
65763db86aabSstevel 			    pcic_getcb(pcic, CB_CONTROL));
65773db86aabSstevel #endif
65783db86aabSstevel 			/*
65793db86aabSstevel 			 * since power was touched, make sure it says it
65803db86aabSstevel 			 * is on.  This lets it become stable.
65813db86aabSstevel 			 */
65823db86aabSstevel 			for (ind = 0; ind < 20; ind++) {
65833db86aabSstevel 				ifs = pcic_getb(pcic, socket,
65843db86aabSstevel 				    PCIC_INTERFACE_STATUS);
65853db86aabSstevel 				if (ifs & PCIC_POWER_ON)
65863db86aabSstevel 					break;
65873db86aabSstevel 				else {
65883db86aabSstevel 					pcic_putb(pcic, socket,
65893db86aabSstevel 					    PCIC_POWER_CONTROL, 0);
65903db86aabSstevel 					(void) pcic_getb(pcic, socket,
65913db86aabSstevel 					    PCIC_POWER_CONTROL);
65923db86aabSstevel 					pcic_mswait(pcic, socket, 40);
65933db86aabSstevel 					if (ind == 10) {
65943db86aabSstevel 						pcic_putcb(pcic, CB_EVENT_FORCE,
65953db86aabSstevel 						    CB_EF_CVTEST);
65963db86aabSstevel 						pcic_mswait(pcic, socket, 100);
65973db86aabSstevel 					}
65983db86aabSstevel 					pcic_putb(pcic, socket,
65993db86aabSstevel 					    PCIC_POWER_CONTROL,
66003db86aabSstevel 					    powerlevel & ~POWER_OUTPUT_ENABLE);
66013db86aabSstevel 					(void) pcic_getb(pcic, socket,
66023db86aabSstevel 					    PCIC_POWER_CONTROL);
66033db86aabSstevel 					pcic_mswait(pcic, socket,
66043db86aabSstevel 					    pcic_powerdelay);
66053db86aabSstevel 					pcic_putb(pcic, socket,
66063db86aabSstevel 					    PCIC_POWER_CONTROL, powerlevel);
66073db86aabSstevel 					(void) pcic_getb(pcic, socket,
66083db86aabSstevel 					    PCIC_POWER_CONTROL);
66093db86aabSstevel 					pcic_mswait(pcic, socket,
66103db86aabSstevel 					    pcic_powerdelay);
66113db86aabSstevel 				}
66123db86aabSstevel 			}
66133db86aabSstevel 
66143db86aabSstevel 			if (!(ifs & PCIC_POWER_ON)) {
66153db86aabSstevel 				cmn_err(CE_WARN,
66163db86aabSstevel 				    "pcic socket %d: Power didn't get turned"
66173db86aabSstevel 				    "on!\nif status 0x%x pwrc 0x%x(x%x) "
66183db86aabSstevel 				    "misc1 0x%x igc 0x%x ind %d\n",
66193db86aabSstevel 				    socket, ifs,
66203db86aabSstevel 				    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66213db86aabSstevel 				    orig_pwrctl,
66223db86aabSstevel 				    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66233db86aabSstevel 				    pcic_getb(pcic, socket, PCIC_INTERRUPT),
66243db86aabSstevel 				    ind);
66253db86aabSstevel 				return (BAD_VCC);
66263db86aabSstevel 			}
66273db86aabSstevel #if defined(PCIC_DEBUG)
66283db86aabSstevel 			pcic_err(pcic->dip, 8,
66293db86aabSstevel 			    "\tind = %d, if status %x pwrc 0x%x "
66303db86aabSstevel 			    "misc1 0x%x igc 0x%x\n",
66313db86aabSstevel 			    ind, ifs,
66323db86aabSstevel 			    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66333db86aabSstevel 			    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66343db86aabSstevel 			    pcic_getb(pcic, socket, PCIC_INTERRUPT));
66353db86aabSstevel #endif
66363db86aabSstevel 		} else {
66373db86aabSstevel 			/* explicitly turned off the power */
66383db86aabSstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66393db86aabSstevel 			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66403db86aabSstevel 		}
66413db86aabSstevel 	}
66423db86aabSstevel 	return (SUCCESS);
66433db86aabSstevel }
66443db86aabSstevel 
66453db86aabSstevel static int pcic_cbdoreset_during_poweron = 1;
66463db86aabSstevel static int
66473db86aabSstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket)
66483db86aabSstevel {
66493db86aabSstevel 	uint32_t cbctl = 0, orig_cbctl, cbstev, cbps;
66503db86aabSstevel 	int ind, iobits;
66513db86aabSstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[socket];
66523db86aabSstevel 
66533db86aabSstevel 	pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE);
66543db86aabSstevel 
66553db86aabSstevel 	ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10;
66563db86aabSstevel 	cbctl |= pcic_cbv_levels[ind];
66573db86aabSstevel 
66583db86aabSstevel 	ind = pcic_power[sockp->pcs_vcc].PowerLevel/10;
66593db86aabSstevel 	cbctl |= (pcic_cbv_levels[ind]<<4);
66603db86aabSstevel 
66613db86aabSstevel 	orig_cbctl = pcic_getcb(pcic, CB_CONTROL);
66623db86aabSstevel 
66633db86aabSstevel #if defined(PCIC_DEBUG)
66643db86aabSstevel 	pcic_err(pcic->dip, 6,
66653db86aabSstevel 	    "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d "
66663db86aabSstevel 	    "cbctl 0x%x->0x%x\n",
66673db86aabSstevel 	    socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl);
66683db86aabSstevel #endif
66693db86aabSstevel 	if (cbctl != orig_cbctl) {
66703db86aabSstevel 	    if (pcic_cbdoreset_during_poweron &&
66713db86aabSstevel 		(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
66723db86aabSstevel 		iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
66733db86aabSstevel 		pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits & ~PCIC_RESET);
66743db86aabSstevel 	    }
66753db86aabSstevel 	    pcic_putcb(pcic, CB_CONTROL, cbctl);
66763db86aabSstevel 
66773db86aabSstevel 	    if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) {
66783db86aabSstevel 		pcic_mswait(pcic, socket, pcic_powerdelay);
66793db86aabSstevel 		return (SUCCESS);
66803db86aabSstevel 	    }
66813db86aabSstevel 	    for (ind = 0; ind < 20; ind++) {
66823db86aabSstevel 		cbstev = pcic_getcb(pcic, CB_STATUS_EVENT);
66833db86aabSstevel 
66843db86aabSstevel 		if (cbstev & CB_SE_POWER_CYCLE) {
66853db86aabSstevel 
66863db86aabSstevel 		/*
66873db86aabSstevel 		 * delay 400 ms: though the standard defines that the Vcc
66883db86aabSstevel 		 * set-up time is 20 ms, some PC-Card bridge requires longer
66893db86aabSstevel 		 * duration.
66903db86aabSstevel 		 * Note: We should check the status AFTER the delay to give time
66913db86aabSstevel 		 * for things to stabilize.
66923db86aabSstevel 		 */
66933db86aabSstevel 		    pcic_mswait(pcic, socket, 400);
66943db86aabSstevel 
66953db86aabSstevel 		    cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
66963db86aabSstevel 		    if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) {
66973db86aabSstevel 			/* break; */
66983db86aabSstevel 			cmn_err(CE_WARN, "cbus_powerctl: power off??\n");
66993db86aabSstevel 		    }
67003db86aabSstevel 		    if (cbctl & CB_PS_BADVCC) {
67013db86aabSstevel 			cmn_err(CE_WARN, "cbus_powerctl: bad power request\n");
67023db86aabSstevel 			break;
67033db86aabSstevel 		    }
67043db86aabSstevel 
67053db86aabSstevel #if defined(PCIC_DEBUG)
67063db86aabSstevel 		    pcic_err(pcic->dip, 8,
67073db86aabSstevel 			"cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)",
67083db86aabSstevel 			cbstev, pcic_getcb(pcic, CB_PRESENT_STATE),
67093db86aabSstevel 			cbctl, orig_cbctl);
67103db86aabSstevel #endif
67113db86aabSstevel 		    if (pcic_cbdoreset_during_poweron &&
67123db86aabSstevel 			(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67133db86aabSstevel 			pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67143db86aabSstevel 		    }
67153db86aabSstevel 		    return (SUCCESS);
67163db86aabSstevel 		}
67173db86aabSstevel 		pcic_mswait(pcic, socket, 40);
67183db86aabSstevel 	    }
67193db86aabSstevel 	    if (pcic_cbdoreset_during_poweron &&
67203db86aabSstevel 		(orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67213db86aabSstevel 		pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67223db86aabSstevel 	    }
67233db86aabSstevel 	    cmn_err(CE_WARN,
67243db86aabSstevel 		    "pcic socket %d: Power didn't get turned on/off!\n"
67253db86aabSstevel 		    "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) "
67263db86aabSstevel 		    "vcc %d vpp1 %d", socket, cbstev,
67273db86aabSstevel 		    pcic_getcb(pcic, CB_PRESENT_STATE),
67283db86aabSstevel 		    cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1);
67293db86aabSstevel 	    return (BAD_VCC);
67303db86aabSstevel 	}
67313db86aabSstevel 	return (SUCCESS);
67323db86aabSstevel }
67333db86aabSstevel 
67343db86aabSstevel static int	pcic_do_pprintf = 0;
67353db86aabSstevel 
67363db86aabSstevel static void
67373db86aabSstevel pcic_dump_debqueue(char *msg)
67383db86aabSstevel {
67393db86aabSstevel 	struct debounce *debp = pcic_deb_queue;
67403db86aabSstevel 	clock_t lbolt;
67413db86aabSstevel 
67423db86aabSstevel 	(void) drv_getparm(LBOLT, &lbolt);
67433db86aabSstevel 	pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" :
67443db86aabSstevel 	    "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt);
67453db86aabSstevel 	while (debp) {
67463db86aabSstevel 		pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n",
67473db86aabSstevel 		    (void *) debp, (int)debp->expire, (void *) debp->next,
67483db86aabSstevel 		    debp->pcs->pcs_debounce_id);
67493db86aabSstevel 		debp = debp->next;
67503db86aabSstevel 	}
67513db86aabSstevel }
67523db86aabSstevel 
67533db86aabSstevel 
67543db86aabSstevel /* PRINTFLIKE3 */
67553db86aabSstevel static void
67563db86aabSstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...)
67573db86aabSstevel {
67583db86aabSstevel 	if (pcic_debug && (level <= pcic_debug)) {
67593db86aabSstevel 		va_list adx;
67603db86aabSstevel 		int	instance;
67613db86aabSstevel 		char	buf[256];
67623db86aabSstevel 		const char	*name;
67633db86aabSstevel #if !defined(PCIC_DEBUG)
67643db86aabSstevel 		int	ce;
67653db86aabSstevel 		char	qmark = 0;
67663db86aabSstevel 
67673db86aabSstevel 		if (level <= 3)
67683db86aabSstevel 			ce = CE_WARN;
67693db86aabSstevel 		else
67703db86aabSstevel 			ce = CE_CONT;
67713db86aabSstevel 		if (level == 4)
67723db86aabSstevel 			qmark = 1;
67733db86aabSstevel #endif
67743db86aabSstevel 
67753db86aabSstevel 		if (dip) {
67763db86aabSstevel 			instance = ddi_get_instance(dip);
67773db86aabSstevel 			/* name = ddi_binding_name(dip); */
67783db86aabSstevel 			name = ddi_driver_name(dip);
67793db86aabSstevel 		} else {
67803db86aabSstevel 			instance = 0;
67813db86aabSstevel 			name = "";
67823db86aabSstevel 		}
67833db86aabSstevel 
67843db86aabSstevel 		va_start(adx, fmt);
67853db86aabSstevel 		(void) vsprintf(buf, fmt, adx);
67863db86aabSstevel 		va_end(adx);
67873db86aabSstevel 
67883db86aabSstevel #if defined(PCIC_DEBUG)
67893db86aabSstevel 		if (pcic_do_pprintf) {
67903db86aabSstevel 			if (dip) {
67913db86aabSstevel 				if (instance >= 0)
67923db86aabSstevel 					prom_printf("%s(%d),0x%p: %s", name,
67933db86aabSstevel 					    instance, dip, buf);
67943db86aabSstevel 				else
67953db86aabSstevel 					prom_printf("%s,0x%p: %s",
67963db86aabSstevel 					    name, dip, buf);
67973db86aabSstevel 			} else
67983db86aabSstevel 				prom_printf(buf);
67993db86aabSstevel 		} else {
68003db86aabSstevel 			if (dip) {
68013db86aabSstevel 				if (instance >= 0)
68023db86aabSstevel 					cmn_err(CE_CONT, "%s(%d),0x%p: %s",
68033db86aabSstevel 					    name, instance, (void *) dip, buf);
68043db86aabSstevel 				else
68053db86aabSstevel 					cmn_err(CE_CONT, "%s,0x%p: %s",
68063db86aabSstevel 					    name, (void *) dip, buf);
68073db86aabSstevel 			} else
68083db86aabSstevel 				cmn_err(CE_CONT, buf);
68093db86aabSstevel 		}
68103db86aabSstevel #else
68113db86aabSstevel 		if (dip)
68123db86aabSstevel 			cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name,
68133db86aabSstevel 			    instance, buf);
68143db86aabSstevel 		else
68153db86aabSstevel 			cmn_err(ce, qmark ? "?%s" : buf, buf);
68163db86aabSstevel #endif
68173db86aabSstevel 	}
68183db86aabSstevel }
68193db86aabSstevel 
68203db86aabSstevel 
68213db86aabSstevel static void
68223db86aabSstevel pcic_syshw_cardstate(syshw_t *item, void *arg)
68233db86aabSstevel {
68243db86aabSstevel 	pcic_socket_t *pcs = (pcic_socket_t *)arg;
68253db86aabSstevel 
68263db86aabSstevel 	if (pcs->pcs_flags & PCS_CARD_PRESENT) {
68273db86aabSstevel 		item->state = B_TRUE;
68283db86aabSstevel 		if (pcs->pcs_flags & PCS_CARD_IS16BIT)
68293db86aabSstevel 			item->values[0] = 1;
68303db86aabSstevel 		else if (pcs->pcs_flags & PCS_CARD_ISCARDBUS)
68313db86aabSstevel 			item->values[0] = 2;
68323db86aabSstevel 		else
68333db86aabSstevel 			item->values[0] = 0;
68343db86aabSstevel 	} else {
68353db86aabSstevel 		item->state = B_FALSE;
68363db86aabSstevel 		item->values[0] = 0;
68373db86aabSstevel 	}
68383db86aabSstevel }
68393db86aabSstevel 
68403db86aabSstevel /*
68413db86aabSstevel  * Tadpole additional for the syshw interface used to control the
68423db86aabSstevel  * start/stop switch which is physically linked to the GPIO1 pin
68433db86aabSstevel  * on the 1250a.
68443db86aabSstevel  */
68453db86aabSstevel 
68463db86aabSstevel #define	CLIENT_CALLED	0x8000000
68473db86aabSstevel #define	NCE_EVENT_MASK	0xffff
68483db86aabSstevel 
68493db86aabSstevel typedef struct _client {
68503db86aabSstevel 	pid_t	pid;		/* set by kernel */
68513db86aabSstevel 	int	flags;		/* NCE_REGISTER...  */
68523db86aabSstevel 	int	priority;	/* >100 unless root */
68533db86aabSstevel 	int	events;		/* pending event flags */
68543db86aabSstevel 	int	event_sig;	/* SIG... etc */
68553db86aabSstevel 	struct _client *next;	/* set by kernel */
68563db86aabSstevel 	struct _client *prev;	/* set by kernel */
68573db86aabSstevel } client_data;
68583db86aabSstevel 
68593db86aabSstevel static client_data	*cl_data;
68603db86aabSstevel static int	n_clients;
68613db86aabSstevel static kmutex_t	client_mtx, intr_mtx;
68623db86aabSstevel 
68633db86aabSstevel static void	delete_client(int);
68643db86aabSstevel 
68653db86aabSstevel #ifdef VOYAGER
68663db86aabSstevel static uint32_t	runstop_sig;
68673db86aabSstevel static ddi_softintr_t	softint_id;
68683db86aabSstevel static uchar_t	softint_flag;
68693db86aabSstevel static int	switch_debounce_time = 100;	/* in milliseconds */
68703db86aabSstevel static timeout_id_t	switch_to_id;
68713db86aabSstevel 
68723db86aabSstevel static syshw_t syshw_run_stop = {
68733db86aabSstevel 	    0, "Run/Stop", SH_SWITCH,
68743db86aabSstevel 	    SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID,
68753db86aabSstevel 	    B_FALSE, { 0 } };
68763db86aabSstevel 
68773db86aabSstevel static void
68783db86aabSstevel syshw_get_run_stop(syshw_t *item, void *arg)
68793db86aabSstevel {
68803db86aabSstevel 	pcicdev_t *pcic = (pcicdev_t *)arg;
68813db86aabSstevel 
68823db86aabSstevel 	if (ddi_get8(pcic->cfg_handle,
68833db86aabSstevel 	    pcic->cfgaddr + PCIC_GPIO1_REG) & PCIC_GPIO_DIN)
68843db86aabSstevel 		item->state = B_TRUE;
68853db86aabSstevel 	else
68863db86aabSstevel 		item->state = B_FALSE;
68873db86aabSstevel }
68883db86aabSstevel 
68893db86aabSstevel 
68903db86aabSstevel #endif
68913db86aabSstevel 
68923db86aabSstevel static void
68933db86aabSstevel syshw_attach(pcicdev_t *pcic)
68943db86aabSstevel {
68953db86aabSstevel 	if (ddi_get_instance(pcic->dip) != 0)
68963db86aabSstevel 		return;
68973db86aabSstevel 
68983db86aabSstevel #ifdef VOYAGER
68993db86aabSstevel 	if (pcic->pc_type == PCIC_TI_PCI1250) {
69003db86aabSstevel 
69013db86aabSstevel 		/*
69023db86aabSstevel 		 * Only setup run/stop on a Voyager.
69033db86aabSstevel 		 * This is currently defined as
69043db86aabSstevel 		 * a TI1250 on a SPARC architecture. May have to make this a
69053db86aabSstevel 		 * property definition in the future.
69063db86aabSstevel 		 */
69073db86aabSstevel 		if (ddi_add_softintr(pcic->dip,
69083db86aabSstevel 		    DDI_SOFTINT_LOW, &softint_id,
69093db86aabSstevel 		    NULL, NULL, syshw_intr,
69103db86aabSstevel 		    (caddr_t)pcic) == DDI_SUCCESS) {
69113db86aabSstevel 			runstop_sig = syshw_add2map(&syshw_run_stop,
69123db86aabSstevel 			    syshw_get_run_stop, pcic);
69133db86aabSstevel 			mutex_init(&intr_mtx, NULL, MUTEX_DRIVER,
69143db86aabSstevel 			    pcic->pc_pri);
69153db86aabSstevel 			ddi_put8(pcic->cfg_handle,
69163db86aabSstevel 			    pcic->cfgaddr + PCIC_GPIO1_REG,
69173db86aabSstevel 			    PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL |
69183db86aabSstevel 			    PCIC_GPIO_DELTA);
69193db86aabSstevel 		}
69203db86aabSstevel 	}
69213db86aabSstevel #endif
69223db86aabSstevel 	mutex_init(&client_mtx, "syshw client", MUTEX_DRIVER, NULL);
69233db86aabSstevel 	(void) ddi_create_minor_node(pcic->dip, "syshw", S_IFCHR,
69243db86aabSstevel 	    SYSHW_MINOR, NULL, NULL);
69253db86aabSstevel }
69263db86aabSstevel 
69273db86aabSstevel static void
69283db86aabSstevel syshw_detach(pcicdev_t *pcic)
69293db86aabSstevel {
69303db86aabSstevel #ifdef VOYAGER
69313db86aabSstevel 	if (pcic->pc_type == PCIC_TI_PCI1250) {
69323db86aabSstevel 		pcic_mutex_enter(&intr_mtx);
69333db86aabSstevel 
69343db86aabSstevel 		/*
69353db86aabSstevel 		 * Turn off this interrupt.
69363db86aabSstevel 		 */
69373db86aabSstevel 		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
69383db86aabSstevel 		    PCIC_GPIO_FINPUT);
69393db86aabSstevel 
69403db86aabSstevel 		if (switch_to_id)
69413db86aabSstevel 			(void) untimeout(switch_to_id);
69423db86aabSstevel 		switch_to_id = 0;
69433db86aabSstevel 		softint_flag = 0;
69443db86aabSstevel 
69453db86aabSstevel 		pcic_mutex_exit(&intr_mtx);
69463db86aabSstevel 		ddi_remove_softintr(softint_id);
69473db86aabSstevel 		mutex_destroy(&intr_mtx);
69483db86aabSstevel 	}
69493db86aabSstevel #endif
69503db86aabSstevel 
69513db86aabSstevel 	ddi_remove_minor_node(pcic->dip, NULL);
69523db86aabSstevel 	mutex_destroy(&client_mtx);
69533db86aabSstevel }
69543db86aabSstevel 
69553db86aabSstevel static void
69563db86aabSstevel syshw_resume(pcicdev_t *pcic)
69573db86aabSstevel {
69583db86aabSstevel #ifdef VOYAGER
69593db86aabSstevel 	if (pcic->pc_type == PCIC_TI_PCI1250) {
69603db86aabSstevel 		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
69613db86aabSstevel 		    PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | PCIC_GPIO_DELTA);
69623db86aabSstevel 	}
69633db86aabSstevel #else
69643db86aabSstevel 	_NOTE(ARGUNUSED(pcic))
69653db86aabSstevel #endif
69663db86aabSstevel }
69673db86aabSstevel 
69683db86aabSstevel #ifdef VOYAGER
69693db86aabSstevel static uint_t
69703db86aabSstevel syshw_intr_hi(pcicdev_t *pcic)
69713db86aabSstevel {
69723db86aabSstevel 	uchar_t regval;
69733db86aabSstevel 
69743db86aabSstevel 	if (pcic->pc_type != PCIC_TI_PCI1250)
69753db86aabSstevel 		return (DDI_INTR_UNCLAIMED);
69763db86aabSstevel 
69773db86aabSstevel 	regval = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG);
69783db86aabSstevel 	if (regval & PCIC_GPIO_DELTA) {
69793db86aabSstevel 		pcic_mutex_enter(&intr_mtx);
69803db86aabSstevel 		if (softint_flag == 0 && switch_to_id == 0) {
69813db86aabSstevel 			softint_flag = 1;
69823db86aabSstevel 			ddi_trigger_softintr(softint_id);
69833db86aabSstevel 		}
69843db86aabSstevel 		ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG,
69853db86aabSstevel 		    regval);
69863db86aabSstevel 		pcic_mutex_exit(&intr_mtx);
69873db86aabSstevel 		return (DDI_INTR_CLAIMED);
69883db86aabSstevel 	}
69893db86aabSstevel 
69903db86aabSstevel 	return (DDI_INTR_UNCLAIMED);
69913db86aabSstevel }
69923db86aabSstevel 
69933db86aabSstevel /*
69943db86aabSstevel  * Don't deliver the signal until the debounce period has expired.
69953db86aabSstevel  * Unfortuately this means it end up as a three tier interrupt just
69963db86aabSstevel  * to indicate a bit change.
69973db86aabSstevel  */
69983db86aabSstevel static void
69993db86aabSstevel syshw_debounce_to(void *arg)
70003db86aabSstevel {
70013db86aabSstevel 	_NOTE(ARGUNUSED(arg))
70023db86aabSstevel 
70033db86aabSstevel 	if (switch_to_id) {
70043db86aabSstevel 		pcic_mutex_enter(&intr_mtx);
70053db86aabSstevel 		switch_to_id = 0;
70063db86aabSstevel 		pcic_mutex_exit(&intr_mtx);
70073db86aabSstevel 		syshw_send_signal(runstop_sig);
70083db86aabSstevel 		return;
70093db86aabSstevel 	}
70103db86aabSstevel }
70113db86aabSstevel 
70123db86aabSstevel static uint_t
70133db86aabSstevel syshw_intr(caddr_t arg)
70143db86aabSstevel {
70153db86aabSstevel 	_NOTE(ARGUNUSED(arg))
70163db86aabSstevel 
70173db86aabSstevel 	if (softint_flag) {
70183db86aabSstevel 		pcic_mutex_enter(&intr_mtx);
70193db86aabSstevel 		softint_flag = 0;
70203db86aabSstevel 		if (!switch_to_id)
70213db86aabSstevel 			switch_to_id = timeout(syshw_debounce_to, arg,
70223db86aabSstevel 			    drv_usectohz(switch_debounce_time * 1000));
70233db86aabSstevel 		pcic_mutex_exit(&intr_mtx);
70243db86aabSstevel 		return (DDI_INTR_CLAIMED);
70253db86aabSstevel 	}
70263db86aabSstevel 	return (DDI_INTR_UNCLAIMED);
70273db86aabSstevel }
70283db86aabSstevel #endif
70293db86aabSstevel 
70303db86aabSstevel /*
70313db86aabSstevel  * Send signals to the registered clients
70323db86aabSstevel  */
70333db86aabSstevel static void
70343db86aabSstevel syshw_send_signal(int events)
70353db86aabSstevel {
70363db86aabSstevel 	client_data *ptr;
70373db86aabSstevel 	proc_t	*pr;
70383db86aabSstevel 	int	done_flag;
70393db86aabSstevel 
70403db86aabSstevel 	ptr = cl_data;
70413db86aabSstevel 	while (ptr != NULL) {
70423db86aabSstevel 		done_flag = CLIENT_CALLED;
70433db86aabSstevel 
70443db86aabSstevel 		if ((ptr->flags & events) &&
70453db86aabSstevel 		    (ptr->event_sig != 0) &&
70463db86aabSstevel 		    ((ptr->flags & done_flag) == 0)) {
70473db86aabSstevel 
70483db86aabSstevel 			/*
70493db86aabSstevel 			 * only call the process if:
70503db86aabSstevel 			 * it has not already received the nce signal
70513db86aabSstevel 			 * its signal was not zero (just in case)
70523db86aabSstevel 			 * and it is registered to receive this signal
70533db86aabSstevel 			 */
70543db86aabSstevel 			pcic_mutex_enter(&pidlock);
70553db86aabSstevel 			pr = prfind(ptr->pid);
70563db86aabSstevel 			pcic_mutex_exit(&pidlock);
70573db86aabSstevel 			if (pr == NULL) {
70583db86aabSstevel 				/*
70593db86aabSstevel 				 * This process has died,
70603db86aabSstevel 				 * so we free its memory and move on
70613db86aabSstevel 				 * start at the begining again:
70623db86aabSstevel 				 * a waste of cycles but it makes things easy..
70633db86aabSstevel 				 */
70643db86aabSstevel 				delete_client(ptr->pid);
70653db86aabSstevel 				ptr = cl_data;
70663db86aabSstevel 			} else {
70673db86aabSstevel 				ptr->events |= (events & ptr->flags &
70683db86aabSstevel 				    NCE_EVENT_MASK);
70693db86aabSstevel 				psignal(pr, ptr->event_sig);
70703db86aabSstevel 				ptr->flags |= done_flag;
70713db86aabSstevel 				ptr = ptr->next;
70723db86aabSstevel 			}
70733db86aabSstevel 		} else {
70743db86aabSstevel 			ptr = ptr->next;
70753db86aabSstevel 		}
70763db86aabSstevel 	}
70773db86aabSstevel 
70783db86aabSstevel 	ptr = cl_data;
70793db86aabSstevel 	while (ptr != NULL) {
70803db86aabSstevel 		ptr->flags &= ~done_flag;
70813db86aabSstevel 		ptr = ptr->next;
70823db86aabSstevel 	}
70833db86aabSstevel }
70843db86aabSstevel 
70853db86aabSstevel static int
70863db86aabSstevel syshw_open(dev_t *dev, int flag, int otyp, cred_t *cred)
70873db86aabSstevel {
70883db86aabSstevel 	_NOTE(ARGUNUSED(dev, flag, cred))
70893db86aabSstevel 
70903db86aabSstevel 	if (otyp != OTYP_CHR)
70913db86aabSstevel 		return (EINVAL);
70923db86aabSstevel 
70933db86aabSstevel 	return (0);
70943db86aabSstevel }
70953db86aabSstevel 
70963db86aabSstevel static int
70973db86aabSstevel syshw_close(dev_t dev, int flag, int otyp, cred_t *cred)
70983db86aabSstevel {
70993db86aabSstevel 	_NOTE(ARGUNUSED(dev, flag, otyp, cred))
71003db86aabSstevel 
71013db86aabSstevel 	return (0);
71023db86aabSstevel }
71033db86aabSstevel 
71043db86aabSstevel /*
71053db86aabSstevel  * Add a client to the list of interested processes
71063db86aabSstevel  */
71073db86aabSstevel static void
71083db86aabSstevel add_client(client_data *new)
71093db86aabSstevel {
71103db86aabSstevel 	client_data * ptr;
71113db86aabSstevel 
71123db86aabSstevel 	n_clients++;
71133db86aabSstevel 	if (cl_data == NULL) {
71143db86aabSstevel 		cl_data = new;
71153db86aabSstevel 		return;
71163db86aabSstevel 	}
71173db86aabSstevel 
71183db86aabSstevel 	ptr = cl_data;
71193db86aabSstevel 	while ((ptr->next != NULL) && (ptr->priority <= new->priority))
71203db86aabSstevel 		ptr = ptr->next;
71213db86aabSstevel 
71223db86aabSstevel 	if (ptr == cl_data) {
71233db86aabSstevel 		/* at head of the list */
71243db86aabSstevel 		cl_data = new;
71253db86aabSstevel 		new->next = ptr;
71263db86aabSstevel 		new->prev = NULL;
71273db86aabSstevel 		if (ptr != NULL)
71283db86aabSstevel 			ptr->prev = new;
71293db86aabSstevel 	} else {
71303db86aabSstevel 		/* somewhere else in the list - insert after */
71313db86aabSstevel 		new->next = ptr->next;
71323db86aabSstevel 		ptr->next = new;
71333db86aabSstevel 		new->prev = ptr;
71343db86aabSstevel 		if (new->next != NULL)
71353db86aabSstevel 			(new->next)->prev = new;
71363db86aabSstevel 	}
71373db86aabSstevel }
71383db86aabSstevel 
71393db86aabSstevel /*
71403db86aabSstevel  * Locate a client data structure in the client list by looking for a PID match.
71413db86aabSstevel  */
71423db86aabSstevel static client_data *
71433db86aabSstevel locate_client(pid_t pid)
71443db86aabSstevel {
71453db86aabSstevel 	client_data * ptr = cl_data;
71463db86aabSstevel 
71473db86aabSstevel 	while ((ptr != NULL) && (ptr->pid != pid))
71483db86aabSstevel 		ptr = ptr->next;
71493db86aabSstevel 
71503db86aabSstevel 	return (ptr);
71513db86aabSstevel }
71523db86aabSstevel 
71533db86aabSstevel /*
71543db86aabSstevel  * Remove a client record from the client list
71553db86aabSstevel  */
71563db86aabSstevel static void
71573db86aabSstevel delete_client(pid_t pid)
71583db86aabSstevel {
71593db86aabSstevel 	client_data * ptr;
71603db86aabSstevel 
71613db86aabSstevel 	ptr = locate_client(pid);
71623db86aabSstevel 	if (ptr == NULL)
71633db86aabSstevel 		return;	/* hmmm!! */
71643db86aabSstevel 
71653db86aabSstevel 	n_clients--;
71663db86aabSstevel 
71673db86aabSstevel 	if (ptr == cl_data) {
71683db86aabSstevel 		/* remove the head of the list */
71693db86aabSstevel 		cl_data = ptr->next;
71703db86aabSstevel 	}
71713db86aabSstevel 	if (ptr->prev != NULL)
71723db86aabSstevel 		(ptr->prev)->next = ptr->next;
71733db86aabSstevel 	if (ptr->next != NULL)
71743db86aabSstevel 		(ptr->next)->prev = ptr->prev;
71753db86aabSstevel 
71763db86aabSstevel 	kmem_free(ptr, sizeof (client_data));
71773db86aabSstevel }
71783db86aabSstevel 
71793db86aabSstevel static void
71803db86aabSstevel unregister_event_client()
71813db86aabSstevel {
71823db86aabSstevel 	pcic_mutex_enter(&client_mtx);
71833db86aabSstevel 	delete_client(ddi_get_pid());
71843db86aabSstevel 	pcic_mutex_exit(&client_mtx);
71853db86aabSstevel }
71863db86aabSstevel 
71873db86aabSstevel static int
71883db86aabSstevel register_event_client(client_data *u_client)
71893db86aabSstevel {
71903db86aabSstevel 	int	error;
71913db86aabSstevel 	client_data * client;
71923db86aabSstevel 
71933db86aabSstevel 	pcic_mutex_enter(&client_mtx);
71943db86aabSstevel 	client = locate_client(ddi_get_pid());
71953db86aabSstevel 	if (client) {
71963db86aabSstevel 		/*
71973db86aabSstevel 		 * we are re-registering ourself
71983db86aabSstevel 		 * so we delete the previous entry
71993db86aabSstevel 		 */
72003db86aabSstevel 		delete_client(ddi_get_pid());
72013db86aabSstevel 	}
72023db86aabSstevel 
72033db86aabSstevel 	client = (client_data *)kmem_alloc(sizeof (client_data), KM_SLEEP);
72043db86aabSstevel 
72053db86aabSstevel 	if (client) {
72063db86aabSstevel 		client->pid = ddi_get_pid();
72073db86aabSstevel 		client->priority = u_client->priority;
72083db86aabSstevel 		client->flags = u_client->flags & NCE_EVENT_MASK;
72093db86aabSstevel 		client->events = 0;
72103db86aabSstevel 		client->event_sig = u_client->event_sig;
72113db86aabSstevel 		client->next = NULL;
72123db86aabSstevel 		client->prev = NULL;
72133db86aabSstevel 		add_client(client);
72143db86aabSstevel 		error = 0;
72153db86aabSstevel 	} else
72163db86aabSstevel 		error = EIO;
72173db86aabSstevel 
72183db86aabSstevel 	pcic_mutex_exit(&client_mtx);
72193db86aabSstevel 	return (error);
72203db86aabSstevel }
72213db86aabSstevel 
72223db86aabSstevel /*
72233db86aabSstevel  * Read the currently pending event flags for the process in question
72243db86aabSstevel  */
72253db86aabSstevel static int
72263db86aabSstevel check_events_pending(caddr_t data)
72273db86aabSstevel {
72283db86aabSstevel 	client_data * client;
72293db86aabSstevel 	int	error = 0;
72303db86aabSstevel 
72313db86aabSstevel 	pcic_mutex_enter(&client_mtx);
72323db86aabSstevel 	client = locate_client(ddi_get_pid());
72333db86aabSstevel 	if (client) {
72343db86aabSstevel 		if (copyout((caddr_t)&client->events, data, sizeof (int)))
72353db86aabSstevel 			error = EFAULT;
72363db86aabSstevel 		else
72373db86aabSstevel 			client->events = 0;
72383db86aabSstevel 	} else
72393db86aabSstevel 		error = EINVAL;
72403db86aabSstevel 
72413db86aabSstevel 	pcic_mutex_exit(&client_mtx);
72423db86aabSstevel 	return (error);
72433db86aabSstevel }
72443db86aabSstevel 
72453db86aabSstevel 
72463db86aabSstevel #define	MAXITEMS	8
72473db86aabSstevel static syshw_t *syshw_map[MAXITEMS];
72483db86aabSstevel static void	(*syshw_getfuncs[MAXITEMS])(syshw_t *, void *);
72493db86aabSstevel static void	*syshw_getfunc_args[MAXITEMS];
72503db86aabSstevel static int	nsyshw_items = 0;
72513db86aabSstevel #define	NSYSHW_ITEMS	nsyshw_items
72523db86aabSstevel 
72533db86aabSstevel static uint32_t
72543db86aabSstevel syshw_add2map(syshw_t *item, void (*getfunc)(syshw_t *, void *), void *getarg)
72553db86aabSstevel {
72563db86aabSstevel 	uint32_t rval = (1 << nsyshw_items);
72573db86aabSstevel 	if (nsyshw_items == MAXITEMS)
72583db86aabSstevel 		return (0);
72593db86aabSstevel 	item->hw_id = nsyshw_items;
72603db86aabSstevel 	syshw_map[nsyshw_items] = item;
72613db86aabSstevel 	syshw_getfuncs[nsyshw_items] = getfunc;
72623db86aabSstevel 	syshw_getfunc_args[nsyshw_items] = getarg;
72633db86aabSstevel 	nsyshw_items++;
72643db86aabSstevel 	return (rval);
72653db86aabSstevel }
72663db86aabSstevel 
72673db86aabSstevel static int
72683db86aabSstevel syshw_ioctl(dev_t dev, int cmd, intptr_t ioctldata, int mode,
72693db86aabSstevel cred_t *cred, int *rval)
72703db86aabSstevel {
72713db86aabSstevel 	caddr_t data = (caddr_t)ioctldata;
72723db86aabSstevel 	syshw_t sh;
72733db86aabSstevel 	hwev_t hwev;
72743db86aabSstevel 	client_data dummy_client;
72753db86aabSstevel 	int	rc = 0, i;
72763db86aabSstevel 
72773db86aabSstevel 	_NOTE(ARGUNUSED(dev, mode, cred, rval))
72783db86aabSstevel 
72793db86aabSstevel 	switch (cmd) {
72803db86aabSstevel 	default:
72813db86aabSstevel 		rc = EINVAL;
72823db86aabSstevel 		break;
72833db86aabSstevel 
72843db86aabSstevel 	case SYSHW_GET_ITEM:
72853db86aabSstevel 	case SYSHW_GET_ITEM_MAXVALUES:
72863db86aabSstevel 		if (copyin(data, (caddr_t)&sh, sizeof (sh))) {
72873db86aabSstevel 			rc = EFAULT;
72883db86aabSstevel 			break;
72893db86aabSstevel 		}
72903db86aabSstevel 
72913db86aabSstevel 		if (sh.hw_id >= NSYSHW_ITEMS) {
72923db86aabSstevel 			rc = EINVAL;
72933db86aabSstevel 			break;
72943db86aabSstevel 		}
72953db86aabSstevel 
72963db86aabSstevel 		sh = *syshw_map[sh.hw_id];
72973db86aabSstevel 		if (!sh.id_string[0]) {
72983db86aabSstevel 			rc = ENOTTY;
72993db86aabSstevel 			break;
73003db86aabSstevel 		}
73013db86aabSstevel 		if (cmd == SYSHW_GET_ITEM) {
73023db86aabSstevel 			if (syshw_getfuncs[sh.hw_id])
73033db86aabSstevel 				syshw_getfuncs[sh.hw_id](&sh,
73043db86aabSstevel 				    syshw_getfunc_args[sh.hw_id]);
73053db86aabSstevel 			else
73063db86aabSstevel 				rc = ENOTTY;
73073db86aabSstevel 		}
73083db86aabSstevel 
73093db86aabSstevel 		if (copyout((caddr_t)&sh, data, sizeof (sh))) {
73103db86aabSstevel 			rc = EFAULT;
73113db86aabSstevel 			break;
73123db86aabSstevel 		}
73133db86aabSstevel 		break;
73143db86aabSstevel 
73153db86aabSstevel 	case SYSHW_SET_ITEM:
73163db86aabSstevel 		if (copyin(data, (caddr_t)&sh, sizeof (sh))) {
73173db86aabSstevel 			rc = EFAULT;
73183db86aabSstevel 			break;
73193db86aabSstevel 		}
73203db86aabSstevel 
73213db86aabSstevel 		if (sh.hw_id >= NSYSHW_ITEMS ||
73223db86aabSstevel 		    !syshw_map[sh.hw_id]->id_string[0] ||
73233db86aabSstevel 		    !(syshw_map[sh.hw_id]->capabilities &
73243db86aabSstevel 		    (SYSHW_STATE_MODIFY | SYSHW_VAL0_MODIFY |
73253db86aabSstevel 		    SYSHW_VAL1_MODIFY | SYSHW_VAL2_MODIFY |
73263db86aabSstevel 		    SYSHW_VAL3_MODIFY))) {
73273db86aabSstevel 			rc = EINVAL;
73283db86aabSstevel 			break;
73293db86aabSstevel 		}
73303db86aabSstevel 
73313db86aabSstevel 		switch (sh.hw_id) {
73323db86aabSstevel 		default:
73333db86aabSstevel 			rc = EINVAL;
73343db86aabSstevel 			break;
73353db86aabSstevel 		}
73363db86aabSstevel 		break;
73373db86aabSstevel 
73383db86aabSstevel 	case SYSHW_EVREG:
73393db86aabSstevel 		if (copyin(data, (caddr_t)&hwev, sizeof (hwev))) {
73403db86aabSstevel 			rc = EFAULT;
73413db86aabSstevel 			break;
73423db86aabSstevel 		}
73433db86aabSstevel 
73443db86aabSstevel 		for (i = 0; i < NSYSHW_ITEMS; i++) {
73453db86aabSstevel 			if (hwev.events & (1 << i) &&
73463db86aabSstevel 			    !(syshw_map[i]->capabilities &
73473db86aabSstevel 			    SYSHW_CAN_SIGNAL_CHANGE)) {
73483db86aabSstevel 				rc = EINVAL;
73493db86aabSstevel 				break;
73503db86aabSstevel 			}
73513db86aabSstevel 		}
73523db86aabSstevel 		if (hwev.event_sig != SIGUSR1 && hwev.event_sig != SIGUSR2)
73533db86aabSstevel 			rc = EINVAL;
73543db86aabSstevel 
73553db86aabSstevel 		if (!rc) {
73563db86aabSstevel 			dummy_client.priority = 100;
73573db86aabSstevel 			dummy_client.flags = hwev.events;
73583db86aabSstevel 			dummy_client.event_sig = hwev.event_sig;
73593db86aabSstevel 			rc = register_event_client(&dummy_client);
73603db86aabSstevel 		}
73613db86aabSstevel 		break;
73623db86aabSstevel 
73633db86aabSstevel 	case SYSHW_EVUNREG:
73643db86aabSstevel 		unregister_event_client();
73653db86aabSstevel 		break;
73663db86aabSstevel 
73673db86aabSstevel 	case SYSHW_CHKEV:
73683db86aabSstevel 		rc = check_events_pending(data);
73693db86aabSstevel 		break;
73703db86aabSstevel 	}
73713db86aabSstevel 	return (rc);
73723db86aabSstevel }
7373