xref: /onnv-gate/usr/src/uts/common/io/pcic.c (revision 7656:2621e50fdf4a)
12305Sstevel /*
22305Sstevel  * CDDL HEADER START
32305Sstevel  *
42305Sstevel  * The contents of this file are subject to the terms of the
52305Sstevel  * Common Development and Distribution License (the "License").
62305Sstevel  * You may not use this file except in compliance with the License.
72305Sstevel  *
82305Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel  * or http://www.opensolaris.org/os/licensing.
102305Sstevel  * See the License for the specific language governing permissions
112305Sstevel  * and limitations under the License.
122305Sstevel  *
132305Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel  * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel  *
192305Sstevel  * CDDL HEADER END
202305Sstevel  */
212305Sstevel 
222305Sstevel /*
237151Srw148561  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242305Sstevel  * Use is subject to license terms.
252305Sstevel  */
262305Sstevel 
272305Sstevel /*
282305Sstevel  * PCIC device/interrupt handler
292305Sstevel  *	The "pcic" driver handles the Intel 82365SL, Cirrus Logic
302305Sstevel  *	and Toshiba (and possibly other clones) PCMCIA adapter chip
312305Sstevel  *	sets.  It implements a subset of Socket Services as defined
322305Sstevel  *	in the Solaris PCMCIA design documents
332305Sstevel  */
342305Sstevel 
352305Sstevel /*
362305Sstevel  * currently defined "properties"
372305Sstevel  *
382305Sstevel  * clock-frequency		bus clock frequency
392305Sstevel  * smi				system management interrupt override
402305Sstevel  * need-mult-irq		need status IRQ for each pair of sockets
412305Sstevel  * disable-audio		don't route audio signal to speaker
422305Sstevel  */
432305Sstevel 
442305Sstevel 
452305Sstevel #include <sys/types.h>
462305Sstevel #include <sys/inttypes.h>
472305Sstevel #include <sys/param.h>
482305Sstevel #include <sys/systm.h>
492305Sstevel #include <sys/user.h>
502305Sstevel #include <sys/buf.h>
512305Sstevel #include <sys/file.h>
522305Sstevel #include <sys/uio.h>
532305Sstevel #include <sys/conf.h>
542305Sstevel #include <sys/stat.h>
552305Sstevel #include <sys/autoconf.h>
562305Sstevel #include <sys/vtoc.h>
572305Sstevel #include <sys/dkio.h>
582305Sstevel #include <sys/ddi.h>
592305Sstevel #include <sys/sunddi.h>
602305Sstevel #include <sys/sunndi.h>
612305Sstevel #include <sys/var.h>
622305Sstevel #include <sys/callb.h>
632305Sstevel #include <sys/open.h>
642305Sstevel #include <sys/ddidmareq.h>
652305Sstevel #include <sys/dma_engine.h>
662305Sstevel #include <sys/kstat.h>
672305Sstevel #include <sys/kmem.h>
682305Sstevel #include <sys/modctl.h>
692305Sstevel #include <sys/pci.h>
702305Sstevel #include <sys/pci_impl.h>
712305Sstevel 
722305Sstevel #include <sys/pctypes.h>
732305Sstevel #include <sys/pcmcia.h>
742305Sstevel #include <sys/sservice.h>
752305Sstevel 
762305Sstevel #include <sys/note.h>
772305Sstevel 
782305Sstevel #include <sys/pcic_reg.h>
792305Sstevel #include <sys/pcic_var.h>
802305Sstevel 
817493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
827493SVincent.Wang@Sun.COM #include <sys/pci_cfgspace.h>
837493SVincent.Wang@Sun.COM #endif
847493SVincent.Wang@Sun.COM 
852305Sstevel #if defined(__sparc)
862305Sstevel #include <sys/pci/pci_nexus.h>
872305Sstevel #endif
882305Sstevel 
892451Srw148561 #include <sys/hotplug/hpcsvc.h>
902305Sstevel #include "cardbus/cardbus.h"
912305Sstevel 
922305Sstevel #define	SOFTC_SIZE	(sizeof (anp_t))
932305Sstevel 
942305Sstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
952305Sstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t);
962305Sstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t);
972305Sstevel static uint_t pcic_intr(caddr_t, caddr_t);
982305Sstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t);
992305Sstevel static int pcic_probe(dev_info_t *);
1002305Sstevel 
1012305Sstevel static int pcic_open(dev_t *, int, int, cred_t *);
1022305Sstevel static int pcic_close(dev_t, int, int, cred_t *);
1032305Sstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1042305Sstevel 
1052305Sstevel typedef struct pcm_regs pcm_regs_t;
1062305Sstevel 
1072305Sstevel static void pcic_init_assigned(dev_info_t *);
1082305Sstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *,
1092305Sstevel 	pci_regspec_t *, int);
1102305Sstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int);
1112305Sstevel 
1122305Sstevel /*
1132305Sstevel  * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls
1142305Sstevel  * are xlated into DMA ctlops. To make this nexus work on x86, we
1152305Sstevel  * need to have the default ddi_dma_mctl ctlops in the bus_ops
1162305Sstevel  * structure, just to pass the request to the parent. The correct
1172305Sstevel  * ctlops should be ddi_no_dma_mctl because so far we don't do DMA.
1182305Sstevel  */
1192305Sstevel static
1202305Sstevel struct bus_ops pcmciabus_ops = {
1212305Sstevel 	BUSO_REV,
1222305Sstevel 	pcmcia_bus_map,
1232305Sstevel 	NULL,
1242305Sstevel 	NULL,
1252305Sstevel 	NULL,
1262305Sstevel 	i_ddi_map_fault,
1272305Sstevel 	ddi_no_dma_map,
1282305Sstevel 	ddi_no_dma_allochdl,
1292305Sstevel 	ddi_no_dma_freehdl,
1302305Sstevel 	ddi_no_dma_bindhdl,
1312305Sstevel 	ddi_no_dma_unbindhdl,
1322305Sstevel 	ddi_no_dma_flush,
1332305Sstevel 	ddi_no_dma_win,
1342305Sstevel 	ddi_dma_mctl,
1352305Sstevel 	pcmcia_ctlops,
1362305Sstevel 	pcmcia_prop_op,
1372305Sstevel 	NULL,				/* (*bus_get_eventcookie)();	*/
1382305Sstevel 	NULL,				/* (*bus_add_eventcall)();	*/
1392305Sstevel 	NULL,				/* (*bus_remove_eventcall)();	*/
1402305Sstevel 	NULL,				/* (*bus_post_event)();		*/
1412305Sstevel 	NULL,				/* (*bus_intr_ctl)();		*/
1422305Sstevel 	NULL,				/* (*bus_config)(); 		*/
1432305Sstevel 	NULL,				/* (*bus_unconfig)(); 		*/
1442305Sstevel 	NULL,				/* (*bus_fm_init)(); 		*/
1452305Sstevel 	NULL,				/* (*bus_fm_fini)(); 		*/
1462305Sstevel 	NULL,				/* (*bus_enter)()		*/
1472305Sstevel 	NULL,				/* (*bus_exit)()		*/
1482305Sstevel 	NULL,				/* (*bus_power)()		*/
1492305Sstevel 	pcmcia_intr_ops			/* (*bus_intr_op)(); 		*/
1502305Sstevel };
1512305Sstevel 
1522305Sstevel static struct cb_ops pcic_cbops = {
1532305Sstevel 	pcic_open,
1542305Sstevel 	pcic_close,
1552305Sstevel 	nodev,
1562305Sstevel 	nodev,
1572305Sstevel 	nodev,
1582305Sstevel 	nodev,
1592305Sstevel 	nodev,
1602305Sstevel 	pcic_ioctl,
1612305Sstevel 	nodev,
1622305Sstevel 	nodev,
1632305Sstevel 	nodev,
1642305Sstevel 	nochpoll,
1652305Sstevel 	ddi_prop_op,
1662305Sstevel 	NULL,
1672305Sstevel #ifdef CARDBUS
1682305Sstevel 	D_NEW | D_MP | D_HOTPLUG
1692305Sstevel #else
1702305Sstevel 	D_NEW | D_MP
1712305Sstevel #endif
1722305Sstevel };
1732305Sstevel 
1742305Sstevel static struct dev_ops pcic_devops = {
1752305Sstevel 	DEVO_REV,
1762305Sstevel 	0,
1772305Sstevel 	pcic_getinfo,
1782305Sstevel 	nulldev,
1792305Sstevel 	pcic_probe,
1802305Sstevel 	pcic_attach,
1812305Sstevel 	pcic_detach,
1822305Sstevel 	nulldev,
1832305Sstevel 	&pcic_cbops,
1842305Sstevel 	&pcmciabus_ops,
185*7656SSherry.Moore@Sun.COM 	NULL,
186*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1872305Sstevel };
1882305Sstevel 
1892305Sstevel void *pcic_soft_state_p = NULL;
1902305Sstevel static int pcic_maxinst = -1;
1912305Sstevel 
1922305Sstevel int pcic_do_insertion = 1;
1932305Sstevel int pcic_do_removal = 1;
1942305Sstevel 
1952305Sstevel struct irqmap {
1962305Sstevel 	int irq;
1972305Sstevel 	int count;
1982305Sstevel } pcic_irq_map[16];
1992305Sstevel 
2002305Sstevel 
2012305Sstevel int pcic_debug = 0x0;
2022305Sstevel static  void    pcic_err(dev_info_t *dip, int level, const char *fmt, ...);
2032305Sstevel extern void cardbus_dump_pci_config(dev_info_t *dip);
2042305Sstevel extern void cardbus_dump_socket(dev_info_t *dip);
2052305Sstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle);
2062305Sstevel static void pcic_dump_debqueue(char *msg);
2072305Sstevel 
2082305Sstevel #if defined(PCIC_DEBUG)
2092305Sstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t);
2102305Sstevel 
2112305Sstevel #define	pcic_mutex_enter(a)	\
2122305Sstevel 	{ \
2132305Sstevel 		pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \
2142305Sstevel 		mutex_enter(a); \
2152305Sstevel 	};
2162305Sstevel 
2172305Sstevel #define	pcic_mutex_exit(a)	\
2182305Sstevel 	{ \
2192305Sstevel 		pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \
2202305Sstevel 		mutex_exit(a); \
2212305Sstevel 	};
2222305Sstevel 
2232305Sstevel #else
2242305Sstevel #define	pcic_mutex_enter(a)	mutex_enter(a)
2252305Sstevel #define	pcic_mutex_exit(a)	mutex_exit(a)
2262305Sstevel #endif
2272305Sstevel 
2282305Sstevel #define	PCIC_VCC_3VLEVEL	1
2292305Sstevel #define	PCIC_VCC_5VLEVEL	2
2302305Sstevel #define	PCIC_VCC_12LEVEL	3
2312305Sstevel 
2322305Sstevel /* bit patterns to select voltage levels */
2332305Sstevel int pcic_vpp_levels[13] = {
2342305Sstevel 	0, 0, 0,
2352305Sstevel 	1,	/* 3.3V */
2362305Sstevel 	0,
2372305Sstevel 	1,	/* 5V */
2382305Sstevel 	0, 0, 0, 0, 0, 0,
2392305Sstevel 	2	/* 12V */
2402305Sstevel };
2412305Sstevel 
2422305Sstevel uint8_t pcic_cbv_levels[13] = {
2432305Sstevel 	0, 0, 0,
2442305Sstevel 	3,			/* 3.3V */
2452305Sstevel 	0,
2462305Sstevel 	2,			/* 5V */
2472305Sstevel 	0, 0, 0, 0, 0, 0,
2482305Sstevel 	1			/* 12V */
2492305Sstevel };
2502305Sstevel 
2512305Sstevel struct power_entry pcic_power[4] = {
2522305Sstevel 	{
2532305Sstevel 		0, VCC|VPP1|VPP2
2542305Sstevel 	},
2552305Sstevel 	{
2562305Sstevel 		33,		/* 3.3Volt */
2572305Sstevel 		VCC|VPP1|VPP2
2582305Sstevel 	},
2592305Sstevel 	{
2602305Sstevel 		5*10,		/* 5Volt */
2612305Sstevel 		VCC|VPP1|VPP2	/* currently only know about this */
2622305Sstevel 	},
2632305Sstevel 	{
2642305Sstevel 		12*10,		/* 12Volt */
2652305Sstevel 		VPP1|VPP2
2662305Sstevel 	}
2672305Sstevel };
2682305Sstevel 
2692305Sstevel /*
2702305Sstevel  * Base used to allocate ranges of PCI memory on x86 systems
2712305Sstevel  * Each instance gets a chunk above the base that is used to map
2722305Sstevel  * in the memory and I/O windows for that device.
2732305Sstevel  * Pages below the base are also allocated for the EXCA registers,
2742305Sstevel  * one per instance.
2752305Sstevel  */
2762305Sstevel #define	PCIC_PCI_MEMCHUNK	0x1000000
2772305Sstevel 
2782305Sstevel static int pcic_wait_insert_time = 5000000;	/* In micro-seconds */
2792305Sstevel static int pcic_debounce_time = 200000; /* In micro-seconds */
2802305Sstevel 
2812305Sstevel struct debounce {
2822305Sstevel 	pcic_socket_t *pcs;
2832305Sstevel 	clock_t expire;
2842305Sstevel 	struct debounce *next;
2852305Sstevel };
2862305Sstevel 
2872305Sstevel static struct debounce *pcic_deb_queue = NULL;
2882305Sstevel static kmutex_t pcic_deb_mtx;
2892305Sstevel static kcondvar_t pcic_deb_cv;
2902305Sstevel static kthread_t *pcic_deb_threadid;
2912305Sstevel 
2922305Sstevel static inthandler_t *pcic_handlers;
2932305Sstevel 
2942305Sstevel static void pcic_setup_adapter(pcicdev_t *);
2952305Sstevel static int pcic_change(pcicdev_t *, int);
2962305Sstevel static int pcic_ll_reset(pcicdev_t *, int);
2972305Sstevel static void pcic_mswait(pcicdev_t *, int, int);
2982305Sstevel static boolean_t pcic_check_ready(pcicdev_t *, int);
2992305Sstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int);
3002305Sstevel static void pcic_ready_wait(pcicdev_t *, int);
3012305Sstevel extern int pcmcia_get_intr(dev_info_t *, int);
3022305Sstevel extern int pcmcia_return_intr(dev_info_t *, int);
3037151Srw148561 extern void pcmcia_cb_suspended(int);
3047151Srw148561 extern void pcmcia_cb_resumed(int);
3052305Sstevel 
3062305Sstevel static int pcic_callback(dev_info_t *, int (*)(), int);
3072305Sstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *);
3082305Sstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *);
3092305Sstevel static int pcic_get_page(dev_info_t *, get_page_t *);
3102305Sstevel static int pcic_get_socket(dev_info_t *, get_socket_t *);
3112305Sstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *);
3122305Sstevel static int pcic_get_window(dev_info_t *, get_window_t *);
3132305Sstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *);
3142305Sstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *);
3152305Sstevel static int pcic_reset_socket(dev_info_t *, int, int);
3162305Sstevel static int pcic_set_page(dev_info_t *, set_page_t *);
3172305Sstevel static int pcic_set_window(dev_info_t *, set_window_t *);
3182305Sstevel static int pcic_set_socket(dev_info_t *, set_socket_t *);
3192305Sstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *);
3202305Sstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
3212305Sstevel static void pcic_pm_detection(void *);
3222305Sstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned);
3232305Sstevel static int clext_reg_read(pcicdev_t *, int, uchar_t);
3242305Sstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t);
3252305Sstevel static int pcic_calc_speed(pcicdev_t *, uint32_t);
3262305Sstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *);
3272305Sstevel static int pcic_find_pci_type(pcicdev_t *);
3282305Sstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int);
3292305Sstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t);
3302305Sstevel static uint_t pcic_cd_softint(caddr_t, caddr_t);
3312305Sstevel static uint8_t pcic_getb(pcicdev_t *, int, int);
3322305Sstevel static void pcic_putb(pcicdev_t *, int, int, int8_t);
3332305Sstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *);
3342305Sstevel static uint_t pcic_softintr(caddr_t, caddr_t);
3352305Sstevel 
3362305Sstevel static void pcic_debounce(pcic_socket_t *);
3377151Srw148561 static void pcic_do_resume(pcicdev_t *);
3382305Sstevel static void *pcic_add_debqueue(pcic_socket_t *, int);
3392305Sstevel static void pcic_rm_debqueue(void *);
3402305Sstevel static void pcic_deb_thread();
3412305Sstevel 
3422305Sstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3432305Sstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3442305Sstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg);
3452305Sstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value);
3462305Sstevel static void pcic_cb_enable_intr(dev_info_t *);
3472305Sstevel static void pcic_cb_disable_intr(dev_info_t *);
3482305Sstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq);
3492305Sstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket);
3502305Sstevel 
3512305Sstevel static cb_nexus_cb_t pcic_cbnexus_ops = {
3522305Sstevel 	pcic_cb_enable_intr,
3532305Sstevel 	pcic_cb_disable_intr
3542305Sstevel };
3552305Sstevel 
3562305Sstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel);
3572305Sstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket);
3582305Sstevel 
3592305Sstevel #if defined(__sparc)
3602305Sstevel static int pcic_fault(enum pci_fault_ops op, void *arg);
3612305Sstevel #endif
3622305Sstevel 
3632305Sstevel 
3642305Sstevel /*
3652305Sstevel  * pcmcia interface operations structure
3662305Sstevel  * this is the private interface that is exported to the nexus
3672305Sstevel  */
3682305Sstevel pcmcia_if_t pcic_if_ops = {
3692305Sstevel 	PCIF_MAGIC,
3702305Sstevel 	PCIF_VERSION,
3712305Sstevel 	pcic_callback,
3722305Sstevel 	pcic_get_adapter,
3732305Sstevel 	pcic_get_page,
3742305Sstevel 	pcic_get_socket,
3752305Sstevel 	pcic_get_status,
3762305Sstevel 	pcic_get_window,
3772305Sstevel 	pcic_inquire_adapter,
3782305Sstevel 	pcic_inquire_socket,
3792305Sstevel 	pcic_inquire_window,
3802305Sstevel 	pcic_reset_socket,
3812305Sstevel 	pcic_set_page,
3822305Sstevel 	pcic_set_window,
3832305Sstevel 	pcic_set_socket,
3842305Sstevel 	pcic_set_interrupt,
3852305Sstevel 	pcic_clear_interrupt,
3862305Sstevel 	NULL,
3872305Sstevel };
3882305Sstevel 
3892305Sstevel /*
3902305Sstevel  * chip type identification routines
3912305Sstevel  * this list of functions is searched until one of them succeeds
3922305Sstevel  * or all fail.  i82365SL is assumed if failed.
3932305Sstevel  */
3942305Sstevel static int pcic_ci_cirrus(pcicdev_t *);
3952305Sstevel static int pcic_ci_vadem(pcicdev_t *);
3962305Sstevel static int pcic_ci_ricoh(pcicdev_t *);
3972305Sstevel 
3982305Sstevel int (*pcic_ci_funcs[])(pcicdev_t *) = {
3992305Sstevel 	pcic_ci_cirrus,
4002305Sstevel 	pcic_ci_vadem,
4012305Sstevel 	pcic_ci_ricoh,
4022305Sstevel 	NULL
4032305Sstevel };
4042305Sstevel 
4052305Sstevel static struct modldrv modldrv = {
4062305Sstevel 	&mod_driverops,		/* Type of module. This one is a driver */
4077240Srh87107 	"PCIC PCMCIA adapter driver",	/* Name of the module. */
4082305Sstevel 	&pcic_devops,		/* driver ops */
4092305Sstevel };
4102305Sstevel 
4112305Sstevel static struct modlinkage modlinkage = {
4122305Sstevel 	MODREV_1, (void *)&modldrv, NULL
4132305Sstevel };
4142305Sstevel 
4152305Sstevel int
4162305Sstevel _init()
4172305Sstevel {
4182305Sstevel 	int stat;
4192305Sstevel 
4202305Sstevel 	/* Allocate soft state */
4212305Sstevel 	if ((stat = ddi_soft_state_init(&pcic_soft_state_p,
4222305Sstevel 	    SOFTC_SIZE, 2)) != DDI_SUCCESS)
4232305Sstevel 		return (stat);
4242305Sstevel 
4252305Sstevel 	if ((stat = mod_install(&modlinkage)) != 0)
4262305Sstevel 		ddi_soft_state_fini(&pcic_soft_state_p);
4272305Sstevel 
4282305Sstevel 	return (stat);
4292305Sstevel }
4302305Sstevel 
4312305Sstevel int
4322305Sstevel _fini()
4332305Sstevel {
4342305Sstevel 	int stat = 0;
4352305Sstevel 
4362305Sstevel 	if ((stat = mod_remove(&modlinkage)) != 0)
4372305Sstevel 		return (stat);
4382305Sstevel 
4392305Sstevel 	if (pcic_deb_threadid) {
4402305Sstevel 		mutex_enter(&pcic_deb_mtx);
4412305Sstevel 		pcic_deb_threadid = 0;
4422305Sstevel 		while (!pcic_deb_threadid)
4432305Sstevel 			cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
4442305Sstevel 		pcic_deb_threadid = 0;
4452305Sstevel 		mutex_exit(&pcic_deb_mtx);
4462305Sstevel 
4472305Sstevel 		mutex_destroy(&pcic_deb_mtx);
4482305Sstevel 		cv_destroy(&pcic_deb_cv);
4492305Sstevel 	}
4502305Sstevel 
4512305Sstevel 	ddi_soft_state_fini(&pcic_soft_state_p);
4522305Sstevel 
4532305Sstevel 	return (stat);
4542305Sstevel }
4552305Sstevel 
4562305Sstevel int
4572305Sstevel _info(struct modinfo *modinfop)
4582305Sstevel {
4592305Sstevel 	return (mod_info(&modlinkage, modinfop));
4602305Sstevel }
4612305Sstevel 
4622305Sstevel /*
4632305Sstevel  * pcic_getinfo()
4642305Sstevel  *	provide instance/device information about driver
4652305Sstevel  */
4662305Sstevel /*ARGSUSED*/
4672305Sstevel static int
4682305Sstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
4692305Sstevel {
4702305Sstevel 	anp_t *anp;
4712305Sstevel 	int error = DDI_SUCCESS;
4722305Sstevel 	minor_t minor;
4732305Sstevel 
4742305Sstevel 	switch (cmd) {
475*7656SSherry.Moore@Sun.COM 		case DDI_INFO_DEVT2DEVINFO:
4762305Sstevel 		minor = getminor((dev_t)arg);
4773981Sgd78059 		minor &= 0x7f;
4782305Sstevel 		if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor)))
4792305Sstevel 			*result = NULL;
4802305Sstevel 		else
4812305Sstevel 			*result = anp->an_dip;
4822305Sstevel 		break;
483*7656SSherry.Moore@Sun.COM 		case DDI_INFO_DEVT2INSTANCE:
4842305Sstevel 		minor = getminor((dev_t)arg);
4853981Sgd78059 		minor &= 0x7f;
4862305Sstevel 		*result = (void *)((long)minor);
4872305Sstevel 		break;
488*7656SSherry.Moore@Sun.COM 		default:
4892305Sstevel 		error = DDI_FAILURE;
4902305Sstevel 		break;
4912305Sstevel 	}
4922305Sstevel 	return (error);
4932305Sstevel }
4942305Sstevel 
4952305Sstevel static int
4962305Sstevel pcic_probe(dev_info_t *dip)
4972305Sstevel {
4982305Sstevel 	int value;
4992305Sstevel 	ddi_device_acc_attr_t attr;
5002305Sstevel 	ddi_acc_handle_t handle;
5012305Sstevel 	uchar_t *index, *data;
5022305Sstevel 
5032305Sstevel 	if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
504*7656SSherry.Moore@Sun.COM 		return (DDI_PROBE_DONTCARE);
5052305Sstevel 
5062305Sstevel 	/*
5072305Sstevel 	 * find a PCIC device (any vendor)
5082305Sstevel 	 * while there can be up to 4 such devices in
5092305Sstevel 	 * a system, we currently only look for 1
5102305Sstevel 	 * per probe.  There will be up to 2 chips per
5112305Sstevel 	 * instance since they share I/O space
5122305Sstevel 	 */
5132305Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5142305Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
5152305Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5162305Sstevel 
5172305Sstevel 	if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
518*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&index,
519*7656SSherry.Moore@Sun.COM 	    PCIC_ISA_CONTROL_REG_OFFSET,
520*7656SSherry.Moore@Sun.COM 	    PCIC_ISA_CONTROL_REG_LENGTH,
521*7656SSherry.Moore@Sun.COM 	    &attr, &handle) != DDI_SUCCESS)
522*7656SSherry.Moore@Sun.COM 		return (DDI_PROBE_FAILURE);
5232305Sstevel 
5242305Sstevel 	data = index + 1;
5252305Sstevel 
5262305Sstevel #if defined(PCIC_DEBUG)
5272305Sstevel 	if (pcic_debug)
5282305Sstevel 		cmn_err(CE_CONT, "pcic_probe: entered\n");
5292305Sstevel 	if (pcic_debug)
5302305Sstevel 		cmn_err(CE_CONT, "\tindex=%p\n", (void *)index);
5312305Sstevel #endif
5322305Sstevel 	ddi_put8(handle, index, PCIC_CHIP_REVISION);
5332305Sstevel 	ddi_put8(handle, data, 0);
5342305Sstevel 	value = ddi_get8(handle, data);
5352305Sstevel #if defined(PCIC_DEBUG)
5362305Sstevel 	if (pcic_debug)
5372305Sstevel 		cmn_err(CE_CONT, "\tchip revision register = %x\n", value);
5382305Sstevel #endif
5392305Sstevel 	if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW &&
5402305Sstevel 	    (value & 0x30) == 0) {
5412305Sstevel 		/*
5422305Sstevel 		 * we probably have a PCIC chip in the system
5432305Sstevel 		 * do a little more checking.  If we find one,
5442305Sstevel 		 * reset everything in case of softboot
5452305Sstevel 		 */
5462305Sstevel 		ddi_put8(handle, index, PCIC_MAPPING_ENABLE);
5472305Sstevel 		ddi_put8(handle, data, 0);
5482305Sstevel 		value = ddi_get8(handle, data);
5492305Sstevel #if defined(PCIC_DEBUG)
5502305Sstevel 		if (pcic_debug)
5512305Sstevel 			cmn_err(CE_CONT, "\tzero test = %x\n", value);
5522305Sstevel #endif
5532305Sstevel 		/* should read back as zero */
5542305Sstevel 		if (value == 0) {
5552305Sstevel 			/*
5562305Sstevel 			 * we do have one and it is off the bus
5572305Sstevel 			 */
5582305Sstevel #if defined(PCIC_DEBUG)
5592305Sstevel 			if (pcic_debug)
5602305Sstevel 				cmn_err(CE_CONT, "pcic_probe: success\n");
5612305Sstevel #endif
5622305Sstevel 			ddi_regs_map_free(&handle);
5632305Sstevel 			return (DDI_PROBE_SUCCESS);
5642305Sstevel 		}
5652305Sstevel 	}
5662305Sstevel #if defined(PCIC_DEBUG)
5672305Sstevel 	if (pcic_debug)
5682305Sstevel 		cmn_err(CE_CONT, "pcic_probe: failed\n");
5692305Sstevel #endif
5702305Sstevel 	ddi_regs_map_free(&handle);
5712305Sstevel 	return (DDI_PROBE_FAILURE);
5722305Sstevel }
5732305Sstevel 
5742305Sstevel /*
5752305Sstevel  * These are just defaults they can also be changed via a property in the
5762305Sstevel  * conf file.
5772305Sstevel  */
5782305Sstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM;
5792305Sstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM;
5807151Srw148561 static int pcic_do_pcmcia_sr = 1;
5812305Sstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL;
5822305Sstevel 
5832305Sstevel /*
5842305Sstevel  * enable insertion/removal interrupt for 32bit cards
5852305Sstevel  */
5862305Sstevel static int
5872305Sstevel cardbus_enable_cd_intr(dev_info_t *dip)
5882305Sstevel {
5892305Sstevel 	ddi_acc_handle_t	iohandle;
5902305Sstevel 	caddr_t	ioaddr;
5912305Sstevel 	ddi_device_acc_attr_t attr;
5922305Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5932305Sstevel 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5942305Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5952305Sstevel 	(void) ddi_regs_map_setup(dip, 1,
596*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&ioaddr,
597*7656SSherry.Moore@Sun.COM 	    0,
598*7656SSherry.Moore@Sun.COM 	    4096,
599*7656SSherry.Moore@Sun.COM 	    &attr, &iohandle);
6002305Sstevel 
6012305Sstevel 	/* CSC Interrupt: Card detect interrupt on */
6022305Sstevel 	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK),
603*7656SSherry.Moore@Sun.COM 	    ddi_get32(iohandle,
604*7656SSherry.Moore@Sun.COM 	    (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK);
6052305Sstevel 
6062305Sstevel 	ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT),
607*7656SSherry.Moore@Sun.COM 	    ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
6082305Sstevel 
6092305Sstevel 	ddi_regs_map_free(&iohandle);
6102305Sstevel 	return (1);
6112305Sstevel }
6122305Sstevel 
6132305Sstevel /*
6142305Sstevel  * pcic_attach()
6152305Sstevel  *	attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver
6162305Sstevel  *	to the system.  This is a child of "sysbus" since that is where
6172305Sstevel  *	the hardware lives, but it provides services to the "pcmcia"
6182305Sstevel  *	nexus driver.  It gives a pointer back via its private data
6192305Sstevel  *	structure which contains both the dip and socket services entry
6202305Sstevel  *	points
6212305Sstevel  */
6222305Sstevel static int
6232305Sstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6242305Sstevel {
6252305Sstevel 	anp_t *pcic_nexus;
6262305Sstevel 	pcicdev_t *pcic;
6272305Sstevel 	int irqlevel, value;
6282305Sstevel 	int pci_cfrn, pci_ctrn;
6292305Sstevel 	int i, j, smi, actual;
6302305Sstevel 	char *typename;
6312305Sstevel 	char bus_type[16] = "(unknown)";
6322305Sstevel 	int len = sizeof (bus_type);
6332305Sstevel 	ddi_device_acc_attr_t attr;
6342305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
6352305Sstevel 	uint_t	pri;
6362305Sstevel 
6372305Sstevel #if defined(PCIC_DEBUG)
6382305Sstevel 	if (pcic_debug) {
6392305Sstevel 		cmn_err(CE_CONT, "pcic_attach: entered\n");
6402305Sstevel 	}
6412305Sstevel #endif
6422305Sstevel 	switch (cmd) {
6432305Sstevel 	case DDI_ATTACH:
6442305Sstevel 		break;
6452305Sstevel 	case DDI_RESUME:
6462305Sstevel 		pcic = anp->an_private;
6472305Sstevel 		/*
6482305Sstevel 		 * for now, this is a simulated resume.
6492305Sstevel 		 * a real one may need different things.
6502305Sstevel 		 */
6512305Sstevel 		if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) {
6522305Sstevel 			mutex_enter(&pcic->pc_lock);
6532305Sstevel 			/* should probe for new sockets showing up */
6542305Sstevel 			pcic_setup_adapter(pcic);
6552305Sstevel 			pcic->pc_flags &= ~PCF_SUSPENDED;
6562305Sstevel 			mutex_exit(&pcic->pc_lock);
6572305Sstevel 			(void) pcmcia_begin_resume(dip);
6587151Srw148561 
6597151Srw148561 			pcic_do_resume(pcic);
6607151Srw148561 #ifdef CARDBUS
6617151Srw148561 			cardbus_restore_children(ddi_get_child(dip));
6627151Srw148561 #endif
6632305Sstevel 
6642305Sstevel 			/*
6652305Sstevel 			 * for complete implementation need END_RESUME (later)
6662305Sstevel 			 */
6672305Sstevel 			return (DDI_SUCCESS);
6682305Sstevel 
6692305Sstevel 		}
6702305Sstevel 		return (DDI_SUCCESS);
6712305Sstevel 	default:
6722305Sstevel 		return (DDI_FAILURE);
6732305Sstevel 	}
6742305Sstevel 
6752305Sstevel 	/*
6762305Sstevel 	 * Allocate soft state associated with this instance.
6772305Sstevel 	 */
6782305Sstevel 	if (ddi_soft_state_zalloc(pcic_soft_state_p,
679*7656SSherry.Moore@Sun.COM 	    ddi_get_instance(dip)) != DDI_SUCCESS) {
6802305Sstevel 		cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n",
681*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip));
6822305Sstevel 		return (DDI_FAILURE);
6832305Sstevel 	}
6842305Sstevel 
6852305Sstevel 	pcic_nexus = ddi_get_soft_state(pcic_soft_state_p,
6862305Sstevel 	    ddi_get_instance(dip));
6872305Sstevel 
6882305Sstevel 	pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP);
6892305Sstevel 
6902305Sstevel 	pcic->dip = dip;
6912305Sstevel 	pcic_nexus->an_dip = dip;
6922305Sstevel 	pcic_nexus->an_if = &pcic_if_ops;
6932305Sstevel 	pcic_nexus->an_private = pcic;
6942305Sstevel 	pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]);
6952305Sstevel 	pcic->pc_power = pcic_power;
6962305Sstevel 
6972305Sstevel 	pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
6982305Sstevel 	    "pci-control-reg-number", pci_control_reg_num);
6992305Sstevel 	pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7002305Sstevel 	    "pci-config-reg-number", pci_config_reg_num);
7012305Sstevel 
7022305Sstevel 	ddi_set_driver_private(dip, pcic_nexus);
7032305Sstevel 
7042305Sstevel 	/*
7052305Sstevel 	 * pcic->pc_irq is really the IPL level we want to run at
7062305Sstevel 	 * set the default values here and override from intr spec
7072305Sstevel 	 */
7082305Sstevel 	pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
709*7656SSherry.Moore@Sun.COM 	    "interrupt-priorities", -1);
7102305Sstevel 
7112305Sstevel 	if (pcic->pc_irq == -1) {
7122305Sstevel 		int			actual;
7132305Sstevel 		uint_t			pri;
7142305Sstevel 		ddi_intr_handle_t	hdl;
7152305Sstevel 
7162305Sstevel 		/* see if intrspec tells us different */
7172305Sstevel 		if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
7182305Sstevel 		    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) {
7192305Sstevel 			if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS)
7202305Sstevel 				pcic->pc_irq = pri;
7212305Sstevel 			else
7222305Sstevel 				pcic->pc_irq = LOCK_LEVEL + 1;
7232305Sstevel 			(void) ddi_intr_free(hdl);
7242305Sstevel 		}
7252305Sstevel 	}
7262305Sstevel 	pcic_nexus->an_ipl = pcic->pc_irq;
7272305Sstevel 
7282305Sstevel 	/*
7292305Sstevel 	 * Check our parent bus type. We do different things based on which
7302305Sstevel 	 * bus we're on.
7312305Sstevel 	 */
7322305Sstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
733*7656SSherry.Moore@Sun.COM 	    PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
734*7656SSherry.Moore@Sun.COM 	    "device_type", (caddr_t)&bus_type[0], &len) !=
735*7656SSherry.Moore@Sun.COM 	    DDI_PROP_SUCCESS) {
7362305Sstevel 		if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
737*7656SSherry.Moore@Sun.COM 		    PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
738*7656SSherry.Moore@Sun.COM 		    "bus-type", (caddr_t)&bus_type[0], &len) !=
739*7656SSherry.Moore@Sun.COM 		    DDI_PROP_SUCCESS) {
7402305Sstevel 
7412305Sstevel 			cmn_err(CE_CONT,
742*7656SSherry.Moore@Sun.COM 			    "pcic%d: can't find parent bus type\n",
743*7656SSherry.Moore@Sun.COM 			    ddi_get_instance(dip));
7442305Sstevel 
7452305Sstevel 			kmem_free(pcic, sizeof (pcicdev_t));
7463867Srw148561 			ddi_soft_state_free(pcic_soft_state_p,
747*7656SSherry.Moore@Sun.COM 			    ddi_get_instance(dip));
7482305Sstevel 			return (DDI_FAILURE);
7492305Sstevel 		}
7502305Sstevel 	} /* ddi_prop_op("device_type") */
7512305Sstevel 
7523664Srw148561 	if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
753*7656SSherry.Moore@Sun.COM 	    strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) {
7542305Sstevel 		pcic->pc_flags = PCF_PCIBUS;
7552305Sstevel 	} else {
7563867Srw148561 		cmn_err(CE_WARN, "!pcic%d: non-pci mode (%s) not supported, "
757*7656SSherry.Moore@Sun.COM 		    "set BIOS to yenta mode if applicable\n",
758*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip), bus_type);
7592305Sstevel 		kmem_free(pcic, sizeof (pcicdev_t));
7603867Srw148561 		ddi_soft_state_free(pcic_soft_state_p,
761*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip));
7622305Sstevel 		return (DDI_FAILURE);
7632305Sstevel 	}
7642305Sstevel 
7652305Sstevel 	if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
766*7656SSherry.Moore@Sun.COM 	    DDI_PROP_CANSLEEP,
767*7656SSherry.Moore@Sun.COM 	    "clock-frequency", 0)) == 0) {
7682305Sstevel 		if (pcic->pc_flags & PCF_PCIBUS)
7692305Sstevel 			pcic->bus_speed = PCIC_PCI_DEF_SYSCLK;
7702305Sstevel 		else
7712305Sstevel 			pcic->bus_speed = PCIC_ISA_DEF_SYSCLK;
7722305Sstevel 	} else {
7732305Sstevel 		/*
7742305Sstevel 		 * OBP can declare the speed in Hz...
7752305Sstevel 		 */
7762305Sstevel 		if (pcic->bus_speed > 1000000)
7772305Sstevel 			pcic->bus_speed /= 1000000;
7782305Sstevel 	} /* ddi_prop_op("clock-frequency") */
7792305Sstevel 
7802305Sstevel 	pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */
7812305Sstevel 
7822305Sstevel #ifdef	PCIC_DEBUG
7832305Sstevel 	if (pcic_debug) {
7842305Sstevel 		cmn_err(CE_CONT,
785*7656SSherry.Moore@Sun.COM 		    "pcic%d: parent bus type = [%s], speed = %d MHz\n",
786*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip),
787*7656SSherry.Moore@Sun.COM 		    bus_type, pcic->bus_speed);
7882305Sstevel 	}
7892305Sstevel #endif
7902305Sstevel 
7912305Sstevel 	/*
7922305Sstevel 	 * The reg properties on a PCI node are different than those
7932305Sstevel 	 *	on a non-PCI node. Handle that difference here.
7942305Sstevel 	 *	If it turns out to be a CardBus chip, we have even more
7952305Sstevel 	 *	differences.
7962305Sstevel 	 */
7972305Sstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
7982305Sstevel 		int class_code;
7992305Sstevel #if defined(__i386) || defined(__amd64)
8002305Sstevel 		pcic->pc_base = 0x1000000;
8012305Sstevel 		pcic->pc_bound = (uint32_t)~0;
8022305Sstevel 		pcic->pc_iobase = 0x1000;
8032305Sstevel 		pcic->pc_iobound = 0xefff;
8042305Sstevel #elif defined(__sparc)
8052305Sstevel 		pcic->pc_base = 0x0;
8062305Sstevel 		pcic->pc_bound = (uint32_t)~0;
8072305Sstevel 		pcic->pc_iobase = 0x00000;
8082305Sstevel 		pcic->pc_iobound = 0xffff;
8092305Sstevel #endif
8102305Sstevel 
8112305Sstevel 		/* usually need to get at config space so map first */
8122305Sstevel 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8132305Sstevel 		attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8142305Sstevel 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8152305Sstevel 
8162305Sstevel 		if (ddi_regs_map_setup(dip, pci_cfrn,
817*7656SSherry.Moore@Sun.COM 		    (caddr_t *)&pcic->cfgaddr,
818*7656SSherry.Moore@Sun.COM 		    PCIC_PCI_CONFIG_REG_OFFSET,
819*7656SSherry.Moore@Sun.COM 		    PCIC_PCI_CONFIG_REG_LENGTH,
820*7656SSherry.Moore@Sun.COM 		    &attr,
821*7656SSherry.Moore@Sun.COM 		    &pcic->cfg_handle) !=
8222305Sstevel 		    DDI_SUCCESS) {
8232305Sstevel 			cmn_err(CE_CONT,
824*7656SSherry.Moore@Sun.COM 			    "pcic%d: unable to map config space"
825*7656SSherry.Moore@Sun.COM 			    "regs\n",
826*7656SSherry.Moore@Sun.COM 			    ddi_get_instance(dip));
8272305Sstevel 
8282305Sstevel 			kmem_free(pcic, sizeof (pcicdev_t));
8292305Sstevel 			return (DDI_FAILURE);
8302305Sstevel 		} /* ddi_regs_map_setup */
8312305Sstevel 
8322305Sstevel 		class_code = ddi_getprop(DDI_DEV_T_ANY, dip,
833*7656SSherry.Moore@Sun.COM 		    DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
834*7656SSherry.Moore@Sun.COM 		    "class-code", -1);
8352305Sstevel #ifdef  PCIC_DEBUG
8362305Sstevel 		if (pcic_debug) {
8372305Sstevel 			cmn_err(CE_CONT, "pcic_attach class_code=%x\n",
8382305Sstevel 			    class_code);
8392305Sstevel 		}
8402305Sstevel #endif
8412305Sstevel 
8422305Sstevel 		switch (class_code) {
8432305Sstevel 		case PCIC_PCI_CARDBUS:
8442305Sstevel 			pcic->pc_flags |= PCF_CARDBUS;
8452305Sstevel 			pcic->pc_io_type = PCIC_IO_TYPE_YENTA;
8462305Sstevel 			/*
8472305Sstevel 			 * Get access to the adapter registers on the
8482305Sstevel 			 * PCI bus.  A 4K memory page
8492305Sstevel 			 */
8502305Sstevel #if defined(PCIC_DEBUG)
8512305Sstevel 			pcic_err(dip, 8, "Is Cardbus device\n");
8522305Sstevel 			if (pcic_debug) {
8532305Sstevel 				int nr;
8542305Sstevel 				long rs;
8552305Sstevel 				(void) ddi_dev_nregs(dip, &nr);
8562305Sstevel 				pcic_err(dip, 9, "\tdev, cfgaddr 0x%p,"
8572305Sstevel 				    "cfghndl 0x%p nregs %d",
8582305Sstevel 				    (void *)pcic->cfgaddr,
8592305Sstevel 				    (void *)pcic->cfg_handle, nr);
8602305Sstevel 
8612305Sstevel 				(void) ddi_dev_regsize(dip,
8622305Sstevel 				    PCIC_PCI_CONTROL_REG_NUM, &rs);
8632305Sstevel 
8642305Sstevel 				pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n",
8652305Sstevel 				    PCIC_PCI_CONTROL_REG_NUM, (int)rs);
8662305Sstevel 			}
8672305Sstevel #endif
8682305Sstevel 			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8692305Sstevel 			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8702305Sstevel 			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8712305Sstevel 
8722305Sstevel 			if (ddi_regs_map_setup(dip, pci_ctrn,
873*7656SSherry.Moore@Sun.COM 			    (caddr_t *)&pcic->ioaddr,
874*7656SSherry.Moore@Sun.COM 			    PCIC_PCI_CONTROL_REG_OFFSET,
875*7656SSherry.Moore@Sun.COM 			    PCIC_CB_CONTROL_REG_LENGTH,
876*7656SSherry.Moore@Sun.COM 			    &attr, &pcic->handle) !=
8772305Sstevel 			    DDI_SUCCESS) {
8782305Sstevel 				cmn_err(CE_CONT,
879*7656SSherry.Moore@Sun.COM 				    "pcic%d: unable to map PCI regs\n",
880*7656SSherry.Moore@Sun.COM 				    ddi_get_instance(dip));
8812305Sstevel 				ddi_regs_map_free(&pcic->cfg_handle);
8822305Sstevel 				kmem_free(pcic, sizeof (pcicdev_t));
8832305Sstevel 				return (DDI_FAILURE);
8842305Sstevel 			} /* ddi_regs_map_setup */
8852305Sstevel 
8862305Sstevel 			/*
8872305Sstevel 			 * Find out the chip type - If we're on a PCI bus,
8882305Sstevel 			 *	the adapter has that information in the PCI
8892305Sstevel 			 *	config space.
8902305Sstevel 			 * Note that we call pcic_find_pci_type here since
8912305Sstevel 			 *	it needs a valid mapped pcic->handle to
8922305Sstevel 			 *	access some of the adapter registers in
8932305Sstevel 			 *	some cases.
8942305Sstevel 			 */
8952305Sstevel 			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
8962305Sstevel 				ddi_regs_map_free(&pcic->handle);
8972305Sstevel 				ddi_regs_map_free(&pcic->cfg_handle);
8982305Sstevel 				kmem_free(pcic, sizeof (pcicdev_t));
8992305Sstevel 				cmn_err(CE_WARN, "pcic: %s: unsupported "
900*7656SSherry.Moore@Sun.COM 				    "bridge\n", ddi_get_name_addr(dip));
9012305Sstevel 				return (DDI_FAILURE);
9022305Sstevel 			}
9032305Sstevel 			break;
9042305Sstevel 
9052305Sstevel 		default:
9062305Sstevel 		case PCIC_PCI_PCMCIA:
9072305Sstevel 			/*
9082305Sstevel 			 * Get access to the adapter IO registers on the
9092305Sstevel 			 * PCI bus config space.
9102305Sstevel 			 */
9112305Sstevel 			attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9122305Sstevel 			attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9132305Sstevel 			attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9142305Sstevel 
9152305Sstevel 			/*
9162305Sstevel 			 * We need a default mapping to the adapter's IO
9172305Sstevel 			 *	control register space. For most adapters
9182305Sstevel 			 *	that are of class PCIC_PCI_PCMCIA (or of
9192305Sstevel 			 *	a default class) the control registers
9202305Sstevel 			 *	will be using the 82365-type control/data
9212305Sstevel 			 *	format.
9222305Sstevel 			 */
9232305Sstevel 			if (ddi_regs_map_setup(dip, pci_ctrn,
924*7656SSherry.Moore@Sun.COM 			    (caddr_t *)&pcic->ioaddr,
925*7656SSherry.Moore@Sun.COM 			    PCIC_PCI_CONTROL_REG_OFFSET,
926*7656SSherry.Moore@Sun.COM 			    PCIC_PCI_CONTROL_REG_LENGTH,
927*7656SSherry.Moore@Sun.COM 			    &attr,
928*7656SSherry.Moore@Sun.COM 			    &pcic->handle) != DDI_SUCCESS) {
9292305Sstevel 				cmn_err(CE_CONT,
930*7656SSherry.Moore@Sun.COM 				    "pcic%d: unable to map PCI regs\n",
931*7656SSherry.Moore@Sun.COM 				    ddi_get_instance(dip));
9322305Sstevel 				ddi_regs_map_free(&pcic->cfg_handle);
9332305Sstevel 				kmem_free(pcic, sizeof (pcicdev_t));
9342305Sstevel 				return (DDI_FAILURE);
9352305Sstevel 			} /* ddi_regs_map_setup */
9362305Sstevel 
9372305Sstevel 			/*
9382305Sstevel 			 * Find out the chip type - If we're on a PCI bus,
9392305Sstevel 			 *	the adapter has that information in the PCI
9402305Sstevel 			 *	config space.
9412305Sstevel 			 * Note that we call pcic_find_pci_type here since
9422305Sstevel 			 *	it needs a valid mapped pcic->handle to
9432305Sstevel 			 *	access some of the adapter registers in
9442305Sstevel 			 *	some cases.
9452305Sstevel 			 */
9462305Sstevel 			if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9472305Sstevel 				ddi_regs_map_free(&pcic->handle);
9482305Sstevel 				ddi_regs_map_free(&pcic->cfg_handle);
9492305Sstevel 				kmem_free(pcic, sizeof (pcicdev_t));
9502305Sstevel 				cmn_err(CE_WARN, "pcic: %s: unsupported "
951*7656SSherry.Moore@Sun.COM 				    "bridge\n",
952*7656SSherry.Moore@Sun.COM 				    ddi_get_name_addr(dip));
9532305Sstevel 				return (DDI_FAILURE);
9542305Sstevel 			}
9552305Sstevel 
9562305Sstevel 			/*
9572305Sstevel 			 * Some PCI-PCMCIA(R2) adapters are Yenta-compliant
9582305Sstevel 			 *	for extended registers even though they are
9592305Sstevel 			 *	not CardBus adapters. For those adapters,
9602305Sstevel 			 *	re-map pcic->handle to be large enough to
9612305Sstevel 			 *	encompass the Yenta registers.
9622305Sstevel 			 */
9632305Sstevel 			switch (pcic->pc_type) {
964*7656SSherry.Moore@Sun.COM 				case PCIC_TI_PCI1031:
9652305Sstevel 				ddi_regs_map_free(&pcic->handle);
9662305Sstevel 
9672305Sstevel 				if (ddi_regs_map_setup(dip,
968*7656SSherry.Moore@Sun.COM 				    PCIC_PCI_CONTROL_REG_NUM,
969*7656SSherry.Moore@Sun.COM 				    (caddr_t *)&pcic->ioaddr,
970*7656SSherry.Moore@Sun.COM 				    PCIC_PCI_CONTROL_REG_OFFSET,
971*7656SSherry.Moore@Sun.COM 				    PCIC_CB_CONTROL_REG_LENGTH,
972*7656SSherry.Moore@Sun.COM 				    &attr,
973*7656SSherry.Moore@Sun.COM 				    &pcic->handle) != DDI_SUCCESS) {
9742305Sstevel 					cmn_err(CE_CONT,
975*7656SSherry.Moore@Sun.COM 					    "pcic%d: unable to map "
976*7656SSherry.Moore@Sun.COM 					"PCI regs\n",
977*7656SSherry.Moore@Sun.COM 					    ddi_get_instance(dip));
9782305Sstevel 					ddi_regs_map_free(&pcic->cfg_handle);
9792305Sstevel 					kmem_free(pcic, sizeof (pcicdev_t));
9802305Sstevel 					return (DDI_FAILURE);
9812305Sstevel 				} /* ddi_regs_map_setup */
9822305Sstevel 				break;
983*7656SSherry.Moore@Sun.COM 				default:
9842305Sstevel 				break;
9852305Sstevel 			} /* switch (pcic->pc_type) */
9862305Sstevel 			break;
9872305Sstevel 		} /* switch (class_code) */
9882305Sstevel 	} else {
9892305Sstevel 		/*
9902305Sstevel 		 * We're not on a PCI bus, so assume an ISA bus type
9912305Sstevel 		 * register property. Get access to the adapter IO
9922305Sstevel 		 * registers on a non-PCI bus.
9932305Sstevel 		 */
9942305Sstevel 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9952305Sstevel 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
9962305Sstevel 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9972305Sstevel 		pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM;
9982305Sstevel 		pcic->io_reg_num = PCIC_ISA_IO_REG_NUM;
9992305Sstevel 
10002305Sstevel 		if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
1001*7656SSherry.Moore@Sun.COM 		    (caddr_t *)&pcic->ioaddr,
1002*7656SSherry.Moore@Sun.COM 		    PCIC_ISA_CONTROL_REG_OFFSET,
1003*7656SSherry.Moore@Sun.COM 		    PCIC_ISA_CONTROL_REG_LENGTH,
1004*7656SSherry.Moore@Sun.COM 		    &attr,
1005*7656SSherry.Moore@Sun.COM 		    &pcic->handle) != DDI_SUCCESS) {
10062305Sstevel 			cmn_err(CE_CONT,
1007*7656SSherry.Moore@Sun.COM 			    "pcic%d: unable to map ISA registers\n",
1008*7656SSherry.Moore@Sun.COM 			    ddi_get_instance(dip));
10092305Sstevel 
10102305Sstevel 			kmem_free(pcic, sizeof (pcicdev_t));
10112305Sstevel 			return (DDI_FAILURE);
10122305Sstevel 		} /* ddi_regs_map_setup */
10132305Sstevel 
10142305Sstevel 		/* ISA bus is limited to 24-bits, but not first 640K */
10152305Sstevel 		pcic->pc_base = 0xd0000;
10162305Sstevel 		pcic->pc_bound = (uint32_t)~0;
10172305Sstevel 		pcic->pc_iobase = 0x1000;
10182305Sstevel 		pcic->pc_iobound = 0xefff;
10192305Sstevel 	} /* !PCF_PCIBUS */
10202305Sstevel 
10212305Sstevel #ifdef  PCIC_DEBUG
10222305Sstevel 	if (pcic_debug) {
10232305Sstevel 		cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n",
10242305Sstevel 		    pcic->pc_flags, pcic->pc_type);
10252305Sstevel 	}
10262305Sstevel #endif
10272305Sstevel 
10282305Sstevel 	/*
10292305Sstevel 	 * Setup various adapter registers for the PCI case. For the
10302305Sstevel 	 * non-PCI case, find out the chip type.
10312305Sstevel 	 */
10322305Sstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
10332305Sstevel 		int iline;
10342305Sstevel #if defined(__sparc)
10352305Sstevel 		iline = 0;
10362305Sstevel #else
10372305Sstevel 		iline = cardbus_validate_iline(dip, pcic->cfg_handle);
10382305Sstevel #endif
10392305Sstevel 
10402305Sstevel 		/* set flags and socket counts based on chip type */
10412305Sstevel 		switch (pcic->pc_type) {
10422305Sstevel 			uint32_t cfg;
10432305Sstevel 		case PCIC_INTEL_i82092:
10442305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
1045*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_82092_PCICON);
10462305Sstevel 			/* we can only support 4 Socket version */
10472305Sstevel 			if (cfg & PCIC_82092_4_SOCKETS) {
1048*7656SSherry.Moore@Sun.COM 				pcic->pc_numsockets = 4;
1049*7656SSherry.Moore@Sun.COM 				pcic->pc_type = PCIC_INTEL_i82092;
1050*7656SSherry.Moore@Sun.COM 				if (iline != 0xFF)
1051*7656SSherry.Moore@Sun.COM 					pcic->pc_intr_mode =
1052*7656SSherry.Moore@Sun.COM 					    PCIC_INTR_MODE_PCI_1;
1053*7656SSherry.Moore@Sun.COM 				else
1054*7656SSherry.Moore@Sun.COM 					pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
10552305Sstevel 			} else {
1056*7656SSherry.Moore@Sun.COM 				cmn_err(CE_CONT,
10572305Sstevel 				    "pcic%d: Intel 82092 adapter "
10582305Sstevel 				    "in unsupported configuration: 0x%x",
10592305Sstevel 				    ddi_get_instance(pcic->dip), cfg);
1060*7656SSherry.Moore@Sun.COM 				pcic->pc_numsockets = 0;
10612305Sstevel 			} /* PCIC_82092_4_SOCKETS */
10622305Sstevel 			break;
10632305Sstevel 		case PCIC_CL_PD6730:
10642305Sstevel 		case PCIC_CL_PD6729:
10652305Sstevel 			pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
10662305Sstevel 			cfg = ddi_getprop(DDI_DEV_T_ANY, dip,
1067*7656SSherry.Moore@Sun.COM 			    DDI_PROP_CANSLEEP,
1068*7656SSherry.Moore@Sun.COM 			    "interrupts", 0);
10692305Sstevel 			/* if not interrupt pin then must use ISA style IRQs */
10702305Sstevel 			if (cfg == 0 || iline == 0xFF)
10712305Sstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
10722305Sstevel 			else {
10732305Sstevel 				/*
10742305Sstevel 				 * we have the option to use PCI interrupts.
10752305Sstevel 				 * this might not be optimal but in some cases
10762305Sstevel 				 * is the only thing possible (sparc case).
10772305Sstevel 				 * we now deterine what is possible.
10782305Sstevel 				 */
10792305Sstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
10802305Sstevel 			}
10812305Sstevel 			pcic->pc_numsockets = 2;
10822305Sstevel 			pcic->pc_flags |= PCF_IO_REMAP;
10832305Sstevel 			break;
10842305Sstevel 		case PCIC_TI_PCI1031:
10852305Sstevel 			/* this chip doesn't do CardBus but looks like one */
10862305Sstevel 			pcic->pc_flags &= ~PCF_CARDBUS;
10872305Sstevel 			/* FALLTHROUGH */
10882305Sstevel 		default:
10892305Sstevel 			pcic->pc_flags |= PCF_IO_REMAP;
10902305Sstevel 			/* FALLTHROUGH */
10912305Sstevel 			/* indicate feature even if not supported */
10922305Sstevel 			pcic->pc_flags |= PCF_DMA | PCF_ZV;
10932305Sstevel 			/* Not sure if these apply to all these chips */
10942305Sstevel 			pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP);
10952305Sstevel 			pcic->pc_flags |= pcic_use_cbpwrctl;
10962305Sstevel 
10972305Sstevel 			pcic->pc_numsockets = 1; /* one per function */
10982305Sstevel 			if (iline != 0xFF) {
10992305Sstevel 				uint8_t cfg;
11002305Sstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11012305Sstevel 
11022305Sstevel 				cfg = ddi_get8(pcic->cfg_handle,
1103*7656SSherry.Moore@Sun.COM 				    (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG));
11042305Sstevel 				cfg &= (~PCIC_FUN_INT_MOD_ISA);
11052305Sstevel 				ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
1106*7656SSherry.Moore@Sun.COM 				    PCIC_BRIDGE_CTL_REG), cfg);
11072305Sstevel 			}
11082305Sstevel 			else
11092305Sstevel 				pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11102305Sstevel 			pcic->pc_io_type = PCIC_IOTYPE_YENTA;
11112305Sstevel 			break;
11122305Sstevel 		}
11132305Sstevel 	} else {
11142305Sstevel 		/*
11152305Sstevel 		 * We're not on a PCI bus so do some more
11162305Sstevel 		 *	checking for adapter type here.
11172305Sstevel 		 * For the non-PCI bus case:
11182305Sstevel 		 * It could be any one of a number of different chips
11192305Sstevel 		 * If we can't determine anything else, it is assumed
11202305Sstevel 		 * to be an Intel 82365SL.  The Cirrus Logic PD6710
11212305Sstevel 		 * has an extension register that provides unique
11222305Sstevel 		 * identification. Toshiba chip isn't detailed as yet.
11232305Sstevel 		 */
11242305Sstevel 
11252305Sstevel 		/* Init the CL id mode */
11262305Sstevel 		pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
11272305Sstevel 		value = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
11282305Sstevel 
11292305Sstevel 		/* default to Intel i82365SL and then refine */
11302305Sstevel 		pcic->pc_type = PCIC_I82365SL;
11312305Sstevel 		pcic->pc_chipname = PCIC_TYPE_I82365SL;
11322305Sstevel 		for (value = 0; pcic_ci_funcs[value] != NULL; value++) {
11332305Sstevel 			/* go until one succeeds or none left */
11342305Sstevel 			if (pcic_ci_funcs[value](pcic))
11352305Sstevel 				break;
11362305Sstevel 		}
11372305Sstevel 
11382305Sstevel 		/* any chip specific flags get set here */
11392305Sstevel 		switch (pcic->pc_type) {
11402305Sstevel 		case PCIC_CL_PD6722:
11412305Sstevel 			pcic->pc_flags |= PCF_DMA;
11422305Sstevel 		}
11432305Sstevel 
11442305Sstevel 		for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
11452305Sstevel 			/*
11462305Sstevel 			 * look for total number of sockets.
11472305Sstevel 			 * basically check each possible socket for
11482305Sstevel 			 * presence like in probe
11492305Sstevel 			 */
11502305Sstevel 
11512305Sstevel 			/* turn all windows off */
11522305Sstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
11532305Sstevel 			value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE);
11542305Sstevel 
11552305Sstevel 			/*
11562305Sstevel 			 * if a zero is read back, then this socket
11572305Sstevel 			 * might be present. It would be except for
11582305Sstevel 			 * some systems that map the secondary PCIC
11592305Sstevel 			 * chip space back to the first.
11602305Sstevel 			 */
11612305Sstevel 			if (value != 0) {
11622305Sstevel 				/* definitely not so skip */
11632305Sstevel 				/* note: this is for Compaq support */
11642305Sstevel 				continue;
11652305Sstevel 			}
11662305Sstevel 
11672305Sstevel 			/* further tests */
11682305Sstevel 			value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) &
1169*7656SSherry.Moore@Sun.COM 			    PCIC_REV_MASK;
11702305Sstevel 			if (!(value >= PCIC_REV_LEVEL_LOW &&
1171*7656SSherry.Moore@Sun.COM 			    value <= PCIC_REV_LEVEL_HI))
11722305Sstevel 				break;
11732305Sstevel 
11742305Sstevel 			pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa);
11752305Sstevel 			pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55);
11762305Sstevel 			value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW);
11772305Sstevel 
11782305Sstevel 			j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW);
11792305Sstevel 			if (value != 0xaa || j != 0x55)
11802305Sstevel 				break;
11812305Sstevel 
11822305Sstevel 			/*
11832305Sstevel 			 * at this point we know if we have hardware
11842305Sstevel 			 * of some type and not just the bus holding
11852305Sstevel 			 * a pattern for us. We still have to determine
11862305Sstevel 			 * the case where more than 2 sockets are
11872305Sstevel 			 * really the same due to peculiar mappings of
11882305Sstevel 			 * hardware.
11892305Sstevel 			 */
11902305Sstevel 			j = pcic->pc_numsockets++;
11912305Sstevel 			pcic->pc_sockets[j].pcs_flags = 0;
11922305Sstevel 			pcic->pc_sockets[j].pcs_io = pcic->ioaddr;
11932305Sstevel 			pcic->pc_sockets[j].pcs_socket = i;
11942305Sstevel 
11952305Sstevel 			/* put PC Card into RESET, just in case */
11962305Sstevel 			value = pcic_getb(pcic, i, PCIC_INTERRUPT);
11972305Sstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT,
1198*7656SSherry.Moore@Sun.COM 			    value & ~PCIC_RESET);
11992305Sstevel 		}
12002305Sstevel 
12012305Sstevel #if defined(PCIC_DEBUG)
12022305Sstevel 		if (pcic_debug)
12032305Sstevel 			cmn_err(CE_CONT, "num sockets = %d\n",
1204*7656SSherry.Moore@Sun.COM 			    pcic->pc_numsockets);
12052305Sstevel #endif
12062305Sstevel 		if (pcic->pc_numsockets == 0) {
12072305Sstevel 			ddi_regs_map_free(&pcic->handle);
12082305Sstevel 			kmem_free(pcic, sizeof (pcicdev_t));
12092305Sstevel 			return (DDI_FAILURE);
12102305Sstevel 		}
12112305Sstevel 
12122305Sstevel 		/*
12132305Sstevel 		 * need to think this through again in light of
12142305Sstevel 		 * Compaq not following the model that all the
12152305Sstevel 		 * chip vendors recommend.  IBM 755 seems to be
12162305Sstevel 		 * afflicted as well.  Basically, if the vendor
12172305Sstevel 		 * wired things wrong, socket 0 responds for socket 2
12182305Sstevel 		 * accesses, etc.
12192305Sstevel 		 */
12202305Sstevel 		if (pcic->pc_numsockets > 2) {
12212305Sstevel 			int count = pcic->pc_numsockets / 4;
12222305Sstevel 			for (i = 0; i < count; i++) {
12232305Sstevel 				/* put pattern into socket 0 */
12242305Sstevel 				pcic_putb(pcic, i,
1225*7656SSherry.Moore@Sun.COM 				    PCIC_SYSMEM_0_STARTLOW, 0x11);
12262305Sstevel 
12272305Sstevel 				/* put pattern into socket 2 */
12282305Sstevel 				pcic_putb(pcic, i + 2,
1229*7656SSherry.Moore@Sun.COM 				    PCIC_SYSMEM_0_STARTLOW, 0x33);
12302305Sstevel 
12312305Sstevel 				/* read back socket 0 */
12322305Sstevel 				value = pcic_getb(pcic, i,
1233*7656SSherry.Moore@Sun.COM 				    PCIC_SYSMEM_0_STARTLOW);
12342305Sstevel 
12352305Sstevel 				/* read back chip 1 socket 0 */
12362305Sstevel 				j = pcic_getb(pcic, i + 2,
1237*7656SSherry.Moore@Sun.COM 				    PCIC_SYSMEM_0_STARTLOW);
12382305Sstevel 				if (j == value) {
12392305Sstevel 					pcic->pc_numsockets -= 2;
12402305Sstevel 				}
12412305Sstevel 			}
12422305Sstevel 		}
12432305Sstevel 
12442305Sstevel 		smi = 0xff;	/* no more override */
12452305Sstevel 
12462305Sstevel 		if (ddi_getprop(DDI_DEV_T_NONE, dip,
1247*7656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, "need-mult-irq",
1248*7656SSherry.Moore@Sun.COM 		    0xffff) != 0xffff)
12492305Sstevel 			pcic->pc_flags |= PCF_MULT_IRQ;
12502305Sstevel 
12512305Sstevel 	} /* !PCF_PCIBUS */
12522305Sstevel 
12532305Sstevel 	/*
12542305Sstevel 	 * some platforms/busses need to have resources setup
12552305Sstevel 	 * this is temporary until a real resource allocator is
12562305Sstevel 	 * implemented.
12572305Sstevel 	 */
12582305Sstevel 
12592305Sstevel 	pcic_init_assigned(dip);
12602305Sstevel 
12612305Sstevel 	typename = pcic->pc_chipname;
12622305Sstevel 
12632305Sstevel #ifdef	PCIC_DEBUG
12642305Sstevel 	if (pcic_debug) {
12652305Sstevel 		int nregs, nintrs;
12662305Sstevel 
12672305Sstevel 		if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
12682305Sstevel 			nregs = 0;
12692305Sstevel 
12702305Sstevel 		if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS)
12712305Sstevel 			nintrs = 0;
12722305Sstevel 
12732305Sstevel 		cmn_err(CE_CONT,
1274*7656SSherry.Moore@Sun.COM 		    "pcic%d: %d register sets, %d interrupts\n",
1275*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip), nregs, nintrs);
12762305Sstevel 
12772305Sstevel 		nintrs = 0;
12782305Sstevel 		while (nregs--) {
12792305Sstevel 			off_t size;
12802305Sstevel 
12812305Sstevel 			if (ddi_dev_regsize(dip, nintrs, &size) ==
12822305Sstevel 			    DDI_SUCCESS) {
12832305Sstevel 				cmn_err(CE_CONT,
1284*7656SSherry.Moore@Sun.COM 				    "\tregnum %d size %ld (0x%lx)"
1285*7656SSherry.Moore@Sun.COM 				    "bytes",
1286*7656SSherry.Moore@Sun.COM 				    nintrs, size, size);
12872305Sstevel 				if (nintrs ==
12882305Sstevel 				    (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ?
12892305Sstevel 				    PCIC_ISA_CONTROL_REG_NUM :
12902305Sstevel 				    PCIC_PCI_CONTROL_REG_NUM))
12912305Sstevel 					cmn_err(CE_CONT,
1292*7656SSherry.Moore@Sun.COM 					    " mapped at: 0x%p\n",
1293*7656SSherry.Moore@Sun.COM 					    (void *)pcic->ioaddr);
12942305Sstevel 				else
12952305Sstevel 					cmn_err(CE_CONT, "\n");
12962305Sstevel 			} else {
12972305Sstevel 				cmn_err(CE_CONT,
1298*7656SSherry.Moore@Sun.COM 				    "\tddi_dev_regsize(rnumber"
1299*7656SSherry.Moore@Sun.COM 				    "= %d) returns DDI_FAILURE\n",
1300*7656SSherry.Moore@Sun.COM 				    nintrs);
13012305Sstevel 			}
13022305Sstevel 			nintrs++;
13032305Sstevel 		} /* while */
13042305Sstevel 	} /* if (pcic_debug) */
13052305Sstevel #endif
13062305Sstevel 
13072305Sstevel 	cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL);
13082305Sstevel 
13092305Sstevel 	if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1310*7656SSherry.Moore@Sun.COM 	    "disable-audio", 0))
13112305Sstevel 		pcic->pc_flags |= PCF_AUDIO;
13122305Sstevel 
13132305Sstevel 	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
13142305Sstevel 	    "disable-cardbus", 0))
13152305Sstevel 		pcic->pc_flags &= ~PCF_CARDBUS;
13162305Sstevel 
13172305Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL,
13182305Sstevel 	    typename);
13192305Sstevel 
13202305Sstevel 	/*
13212305Sstevel 	 * Init all socket SMI levels to 0 (no SMI)
13222305Sstevel 	 */
13232305Sstevel 	for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
1324*7656SSherry.Moore@Sun.COM 		pcic->pc_sockets[i].pcs_smi = 0;
1325*7656SSherry.Moore@Sun.COM 		pcic->pc_sockets[i].pcs_debounce_id = 0;
1326*7656SSherry.Moore@Sun.COM 		pcic->pc_sockets[i].pcs_pcic = pcic;
13272305Sstevel 	}
13282305Sstevel 	pcic->pc_lastreg = -1; /* just to make sure we are in sync */
13292305Sstevel 
13302305Sstevel 	/*
13312305Sstevel 	 * Setup the IRQ handler(s)
13322305Sstevel 	 */
13332305Sstevel 	switch (pcic->pc_intr_mode) {
13342305Sstevel 		int xx;
13352305Sstevel 	case PCIC_INTR_MODE_ISA:
13362305Sstevel 	/*
13372305Sstevel 	 * On a non-PCI bus, we just use whatever SMI IRQ level was
13382305Sstevel 	 *	specified above, and the IO IRQ levels are allocated
13392305Sstevel 	 *	dynamically.
13402305Sstevel 	 */
13412305Sstevel 		for (xx = 15, smi = 0; xx >= 0; xx--) {
13422305Sstevel 			if (PCIC_IRQ(xx) &
13432305Sstevel 			    PCIC_AVAIL_IRQS) {
13442305Sstevel 				smi = pcmcia_get_intr(dip, xx);
13452305Sstevel 				if (smi >= 0)
13462305Sstevel 					break;
13472305Sstevel 			}
13482305Sstevel 		}
13492305Sstevel #if defined(PCIC_DEBUG)
13502305Sstevel 		if (pcic_debug)
13512305Sstevel 			cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi);
13522305Sstevel #endif
13532305Sstevel 		/* init to same so share is easy */
13542305Sstevel 		for (i = 0; i < pcic->pc_numsockets; i++)
13552305Sstevel 			pcic->pc_sockets[i].pcs_smi = smi;
13562305Sstevel 		/* any special handling of IRQ levels */
13572305Sstevel 		if (pcic->pc_flags & PCF_MULT_IRQ) {
13582305Sstevel 			for (i = 2; i < pcic->pc_numsockets; i++) {
13592305Sstevel 				if ((i & 1) == 0) {
13602305Sstevel 					int xx;
13612305Sstevel 					for (xx = 15, smi = 0; xx >= 0; xx--) {
13622305Sstevel 						if (PCIC_IRQ(xx) &
13632305Sstevel 						    PCIC_AVAIL_IRQS) {
13642305Sstevel 							smi =
13652305Sstevel 							    pcmcia_get_intr(dip,
1366*7656SSherry.Moore@Sun.COM 							    xx);
13672305Sstevel 							if (smi >= 0)
13682305Sstevel 								break;
13692305Sstevel 						}
13702305Sstevel 					}
13712305Sstevel 				}
13722305Sstevel 				if (smi >= 0)
13732305Sstevel 					pcic->pc_sockets[i].pcs_smi = smi;
13742305Sstevel 			}
13752305Sstevel 		}
13762305Sstevel 		pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets *
13772305Sstevel 		    sizeof (ddi_intr_handle_t), KM_SLEEP);
13782305Sstevel 		for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) {
13792305Sstevel 			struct intrspec *ispecp;
13802305Sstevel 			struct ddi_parent_private_data *pdp;
13812305Sstevel 
13822305Sstevel 			if (irqlevel == pcic->pc_sockets[i].pcs_smi)
13832305Sstevel 				continue;
13842305Sstevel 			else {
13852305Sstevel 				irqlevel = pcic->pc_sockets[i].pcs_smi;
13862305Sstevel 			}
13872305Sstevel 			/*
13882305Sstevel 			 * now convert the allocated IRQ into an intrspec
13892305Sstevel 			 * and ask our parent to add it.  Don't use
13902305Sstevel 			 * the ddi_add_intr since we don't have a
13912305Sstevel 			 * default intrspec in all cases.
13922305Sstevel 			 *
13932305Sstevel 			 * note: this sort of violates DDI but we don't
13942305Sstevel 			 *	 get hardware intrspecs for many of the devices.
13952305Sstevel 			 *	 at the same time, we know how to allocate them
13962305Sstevel 			 *	 so we do the right thing.
13972305Sstevel 			 */
13982305Sstevel 			if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i],
13992305Sstevel 			    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
14002305Sstevel 			    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
14012305Sstevel 				cmn_err(CE_WARN, "%s: ddi_intr_alloc failed",
14022305Sstevel 				    ddi_get_name(dip));
14032305Sstevel 				goto isa_exit1;
14042305Sstevel 			}
14052305Sstevel 
14062305Sstevel 			/*
14072305Sstevel 			 * See earlier note:
14082305Sstevel 			 * Since some devices don't have 'intrspec'
14092305Sstevel 			 * we make one up in rootnex.
14102305Sstevel 			 *
14112305Sstevel 			 * However, it is not properly initialized as
14122305Sstevel 			 * the data it needs is present in this driver
14132305Sstevel 			 * and there is no interface to pass that up.
14142305Sstevel 			 * Specially 'irqlevel' is very important and
14152305Sstevel 			 * it is part of pcic struct.
14162305Sstevel 			 *
14172305Sstevel 			 * Set 'intrspec' up here; otherwise adding the
14182305Sstevel 			 * interrupt will fail.
14192305Sstevel 			 */
14202305Sstevel 			pdp = ddi_get_parent_data(dip);
14212305Sstevel 			ispecp = (struct intrspec *)&pdp->par_intr[0];
14222305Sstevel 			ispecp->intrspec_vec = irqlevel;
14232305Sstevel 			ispecp->intrspec_pri = pcic->pc_irq;
14242305Sstevel 
14252305Sstevel 			/* Stay compatible w/ PCMCIA */
14262305Sstevel 			pcic->pc_pri = (ddi_iblock_cookie_t)
14272305Sstevel 			    (uintptr_t)pcic->pc_irq;
14282305Sstevel 			pcic->pc_dcookie.idev_priority =
14292305Sstevel 			    (uintptr_t)pcic->pc_pri;
14302305Sstevel 			pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel;
14312305Sstevel 
14322305Sstevel 			(void) ddi_intr_set_pri(pcic->pc_intr_htblp[i],
14332305Sstevel 			    pcic->pc_irq);
14342305Sstevel 
14352305Sstevel 			if (i == 0) {
14362305Sstevel 				mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER,
14372305Sstevel 				    DDI_INTR_PRI(pcic->pc_irq));
14382305Sstevel 				mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER,
14392305Sstevel 				    NULL);
14402305Sstevel 			}
14412305Sstevel 
14422305Sstevel 			if (ddi_intr_add_handler(pcic->pc_intr_htblp[i],
14432305Sstevel 			    pcic_intr, (caddr_t)pcic, NULL)) {
14442305Sstevel 				cmn_err(CE_WARN,
14452305Sstevel 				    "%s: ddi_intr_add_handler failed",
14462305Sstevel 				    ddi_get_name(dip));
14472305Sstevel 				goto isa_exit2;
14482305Sstevel 			}
14492305Sstevel 
14502305Sstevel 			if (ddi_intr_enable(pcic->pc_intr_htblp[i])) {
14512305Sstevel 				cmn_err(CE_WARN, "%s: ddi_intr_enable failed",
14522305Sstevel 				    ddi_get_name(dip));
14532305Sstevel 				for (j = i; j < 0; j--)
14542305Sstevel 					(void) ddi_intr_remove_handler(
14552305Sstevel 					    pcic->pc_intr_htblp[j]);
14562305Sstevel 				goto isa_exit2;
14572305Sstevel 			}
14582305Sstevel 		}
14592305Sstevel 		break;
14602305Sstevel 	case PCIC_INTR_MODE_PCI_1:
14612305Sstevel 	case PCIC_INTR_MODE_PCI:
14622305Sstevel 		/*
14632305Sstevel 		 * If we're on a PCI bus, we route all interrupts, both SMI
14642305Sstevel 		 * and IO interrupts, through a single interrupt line.
14652305Sstevel 		 * Assign the SMI IRQ level to the IO IRQ level here.
14662305Sstevel 		 */
14672305Sstevel 		pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t),
14682305Sstevel 		    KM_SLEEP);
14692305Sstevel 		if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp,
14702305Sstevel 		    DDI_INTR_TYPE_FIXED, 0, 1, &actual,
14712305Sstevel 		    DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS)
14722305Sstevel 			goto pci_exit1;
14732305Sstevel 
14742305Sstevel 		if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0],
14752305Sstevel 		    &pri) != DDI_SUCCESS) {
14762305Sstevel 			(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
14772305Sstevel 			goto pci_exit1;
14782305Sstevel 		}
14792305Sstevel 
14802305Sstevel 		pcic->pc_pri = (void *)(uintptr_t)pri;
14812305Sstevel 		mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri);
14822305Sstevel 		mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL);
14832305Sstevel 
14842305Sstevel 		if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0],
14852305Sstevel 		    pcic_intr, (caddr_t)pcic, NULL))
14862305Sstevel 			goto pci_exit2;
14872305Sstevel 
14882305Sstevel 		if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) {
14892305Sstevel 			(void) ddi_intr_remove_handler(
14902305Sstevel 			    pcic->pc_pci_intr_hdlp[0]);
14912305Sstevel 			goto pci_exit2;
14922305Sstevel 		}
14932305Sstevel 
14942305Sstevel 		/* Stay compatible w/ PCMCIA */
14952305Sstevel 		pcic->pc_dcookie.idev_priority = (ushort_t)pri;
14962305Sstevel 
14972305Sstevel 		/* init to same (PCI) so share is easy */
14982305Sstevel 		for (i = 0; i < pcic->pc_numsockets; i++)
14992305Sstevel 			pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */
15002305Sstevel 		break;
15012305Sstevel 	}
15022305Sstevel 
15032305Sstevel 	/*
15042305Sstevel 	 * Setup the adapter hardware to some reasonable defaults.
15052305Sstevel 	 */
15062305Sstevel 	mutex_enter(&pcic->pc_lock);
15072305Sstevel 	/* mark the driver state as attached */
15082305Sstevel 	pcic->pc_flags |= PCF_ATTACHED;
15092305Sstevel 	pcic_setup_adapter(pcic);
15102305Sstevel 
15112305Sstevel 	for (j = 0; j < pcic->pc_numsockets; j++)
15122305Sstevel 		if (ddi_intr_add_softint(dip,
15132305Sstevel 		    &pcic->pc_sockets[j].pcs_cd_softint_hdl,
15142305Sstevel 		    PCIC_SOFTINT_PRI_VAL, pcic_cd_softint,
15152305Sstevel 		    (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS)
15162305Sstevel 			goto pci_exit2;
15172305Sstevel 
15182305Sstevel #if defined(PCIC_DEBUG)
15192305Sstevel 	if (pcic_debug)
15202305Sstevel 		cmn_err(CE_CONT, "type = %s sockets = %d\n", typename,
1521*7656SSherry.Moore@Sun.COM 		    pcic->pc_numsockets);
15222305Sstevel #endif
15232305Sstevel 
15242305Sstevel 	pcic_nexus->an_iblock = &pcic->pc_pri;
15252305Sstevel 	pcic_nexus->an_idev = &pcic->pc_dcookie;
15262305Sstevel 
15272305Sstevel 	mutex_exit(&pcic->pc_lock);
15282305Sstevel 
15292305Sstevel #ifdef CARDBUS
15302305Sstevel 	(void) cardbus_enable_cd_intr(dip);
15312305Sstevel 	if (pcic_debug) {
15322305Sstevel 
15332305Sstevel 		cardbus_dump_pci_config(dip);
15342305Sstevel 		cardbus_dump_socket(dip);
15352305Sstevel 	}
15362305Sstevel 
15372305Sstevel 	/*
15382305Sstevel 	 * Give the Cardbus misc module a chance to do it's per-adapter
15392305Sstevel 	 * instance setup. Note that there is no corresponding detach()
15402305Sstevel 	 * call.
15412305Sstevel 	 */
15422305Sstevel 	if (pcic->pc_flags & PCF_CARDBUS)
15432305Sstevel 		if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) {
15442305Sstevel 			cmn_err(CE_CONT,
15452305Sstevel 			    "pcic_attach: cardbus_attach failed\n");
15462305Sstevel 			goto pci_exit2;
15472305Sstevel 		}
15482305Sstevel #endif
15492305Sstevel 
15502305Sstevel 	/*
15512305Sstevel 	 * Give the PCMCIA misc module a chance to do it's per-adapter
15522305Sstevel 	 *	instance setup.
15532305Sstevel 	 */
15542305Sstevel 	if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS)
15552305Sstevel 		goto pci_exit2;
15562305Sstevel 
15572305Sstevel 	if (pcic_maxinst == -1) {
15582305Sstevel 		/* This assumes that all instances run at the same IPL. */
15592305Sstevel 		mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL);
15602305Sstevel 		cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL);
15612305Sstevel 		pcic_deb_threadid = thread_create((caddr_t)NULL, 0,
15622305Sstevel 		    pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN,
15632305Sstevel 		    v.v_maxsyspri - 2);
15642305Sstevel 	}
15652305Sstevel 	pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip));
15662305Sstevel 	/*
15672305Sstevel 	 * Setup a debounce timeout to do an initial card detect
15682305Sstevel 	 * and enable interrupts.
15692305Sstevel 	 */
15702305Sstevel 	for (j = 0; j < pcic->pc_numsockets; j++) {
15712305Sstevel 		pcic->pc_sockets[j].pcs_debounce_id =
15722305Sstevel 		    pcic_add_debqueue(&pcic->pc_sockets[j],
1573*7656SSherry.Moore@Sun.COM 		    drv_usectohz(pcic_debounce_time));
15742305Sstevel 	}
15752305Sstevel 
15762305Sstevel 	return (i);
15772305Sstevel 
15782305Sstevel isa_exit2:
15792305Sstevel 	mutex_destroy(&pcic->intr_lock);
15802305Sstevel 	mutex_destroy(&pcic->pc_lock);
15812305Sstevel 	for (j = i; j < 0; j--)
15822305Sstevel 		(void) ddi_intr_free(pcic->pc_intr_htblp[j]);
15832305Sstevel isa_exit1:
15842305Sstevel 	(void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi);
15852305Sstevel 	ddi_regs_map_free(&pcic->handle);
15862305Sstevel 	if (pcic->pc_flags & PCF_PCIBUS)
15872305Sstevel 		ddi_regs_map_free(&pcic->cfg_handle);
15882305Sstevel 	kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets *
15892305Sstevel 	    sizeof (ddi_intr_handle_t));
15902305Sstevel 	kmem_free(pcic, sizeof (pcicdev_t));
15912305Sstevel 		return (DDI_FAILURE);
15922305Sstevel 
15932305Sstevel pci_exit2:
15942305Sstevel 	mutex_destroy(&pcic->intr_lock);
15952305Sstevel 	mutex_destroy(&pcic->pc_lock);
15962305Sstevel 	(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
15972305Sstevel pci_exit1:
15982305Sstevel 	ddi_regs_map_free(&pcic->handle);
15992305Sstevel 	if (pcic->pc_flags & PCF_PCIBUS)
16002305Sstevel 		ddi_regs_map_free(&pcic->cfg_handle);
16012305Sstevel 	kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16022305Sstevel 	kmem_free(pcic, sizeof (pcicdev_t));
16032305Sstevel 	return (DDI_FAILURE);
16042305Sstevel }
16052305Sstevel 
16062305Sstevel /*
16072305Sstevel  * pcic_detach()
16082305Sstevel  *	request to detach from the system
16092305Sstevel  */
16102305Sstevel static int
16112305Sstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
16122305Sstevel {
16132305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
16142305Sstevel 	pcicdev_t *pcic = anp->an_private;
16152305Sstevel 	int i;
16162305Sstevel 
16172305Sstevel 	switch (cmd) {
16182305Sstevel 	case DDI_DETACH:
16192305Sstevel 		/* don't detach if the nexus still talks to us */
16202305Sstevel 		if (pcic->pc_callback != NULL)
16212305Sstevel 			return (DDI_FAILURE);
16222305Sstevel 
16232305Sstevel 		/* kill off the pm simulation */
16242305Sstevel 		if (pcic->pc_pmtimer)
16252305Sstevel 			(void) untimeout(pcic->pc_pmtimer);
16262305Sstevel 
16272305Sstevel 		/* turn everything off for all sockets and chips */
16282305Sstevel 		for (i = 0; i < pcic->pc_numsockets; i++) {
16292305Sstevel 			if (pcic->pc_sockets[i].pcs_debounce_id)
16302305Sstevel 				pcic_rm_debqueue(
16312305Sstevel 				    pcic->pc_sockets[i].pcs_debounce_id);
16322305Sstevel 			pcic->pc_sockets[i].pcs_debounce_id = 0;
16332305Sstevel 
16342305Sstevel 			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
16352305Sstevel 			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
16362305Sstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
16372305Sstevel 			/* disable interrupts and put card into RESET */
16382305Sstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
16392305Sstevel 		}
16402305Sstevel 		(void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]);
16412305Sstevel 		(void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]);
16422305Sstevel 		(void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16432305Sstevel 		kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16442305Sstevel 		pcic->pc_flags = 0;
16452305Sstevel 		mutex_destroy(&pcic->pc_lock);
16462305Sstevel 		mutex_destroy(&pcic->intr_lock);
16472305Sstevel 		cv_destroy(&pcic->pm_cv);
16482305Sstevel 		if (pcic->pc_flags & PCF_PCIBUS)
1649*7656SSherry.Moore@Sun.COM 			ddi_regs_map_free(&pcic->cfg_handle);
16502305Sstevel 		if (pcic->handle)
1651*7656SSherry.Moore@Sun.COM 			ddi_regs_map_free(&pcic->handle);
16522305Sstevel 		kmem_free(pcic, sizeof (pcicdev_t));
16532305Sstevel 		ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip));
16542305Sstevel 		return (DDI_SUCCESS);
16552305Sstevel 
16562305Sstevel 	case DDI_SUSPEND:
16572305Sstevel 	case DDI_PM_SUSPEND:
16582305Sstevel 		/*
16592305Sstevel 		 * we got a suspend event (either real or imagined)
16602305Sstevel 		 * so notify the nexus proper that all existing cards
16612305Sstevel 		 * should go away.
16622305Sstevel 		 */
16632305Sstevel 		mutex_enter(&pcic->pc_lock);
16642305Sstevel #ifdef CARDBUS
16657151Srw148561 		if (pcic->pc_flags & PCF_CARDBUS) {
16667151Srw148561 			for (i = 0; i < pcic->pc_numsockets; i++) {
16672305Sstevel 				if ((pcic->pc_sockets[i].pcs_flags &
16682305Sstevel 				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) ==
16697151Srw148561 				    (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) {
16707151Srw148561 
16717151Srw148561 					pcmcia_cb_suspended(
1672*7656SSherry.Moore@Sun.COM 					    pcic->pc_sockets[i].pcs_socket);
16737151Srw148561 				}
16747151Srw148561 			}
16757151Srw148561 
16767151Srw148561 			cardbus_save_children(ddi_get_child(dip));
16777151Srw148561 		}
16782305Sstevel #endif
16792305Sstevel 		/* turn everything off for all sockets and chips */
16802305Sstevel 		for (i = 0; i < pcic->pc_numsockets; i++) {
16812305Sstevel 			if (pcic->pc_sockets[i].pcs_debounce_id)
16822305Sstevel 				pcic_rm_debqueue(
16832305Sstevel 				    pcic->pc_sockets[i].pcs_debounce_id);
16842305Sstevel 			pcic->pc_sockets[i].pcs_debounce_id = 0;
16852305Sstevel 
16862305Sstevel 			pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
16872305Sstevel 			pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
16882305Sstevel 			pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
16892305Sstevel 			/* disable interrupts and put card into RESET */
16902305Sstevel 			pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
16912305Sstevel 			pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
16922305Sstevel 			if (pcic->pc_flags & PCF_CBPWRCTL)
16932305Sstevel 				pcic_putcb(pcic, CB_CONTROL, 0);
16942305Sstevel 
16952305Sstevel 			if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) {
16962305Sstevel 				pcic->pc_sockets[i].pcs_flags = PCS_STARTING;
16972305Sstevel 				/*
16982305Sstevel 				 * Because we are half way through a save
16992305Sstevel 				 * all this does is schedule a removal event
17002305Sstevel 				 * to cs for when the system comes back.
17012305Sstevel 				 * This doesn't actually matter.
17022305Sstevel 				 */
17032305Sstevel 				if (!pcic_do_pcmcia_sr && pcic_do_removal &&
17042305Sstevel 				    pcic->pc_callback) {
17052305Sstevel 					PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
17062305Sstevel 					    PCE_CARD_REMOVAL,
17072305Sstevel 					    pcic->pc_sockets[i].pcs_socket);
17082305Sstevel 				}
17092305Sstevel 			}
17102305Sstevel 		}
17112305Sstevel 
17122305Sstevel 		pcic->pc_flags |= PCF_SUSPENDED;
17132305Sstevel 		mutex_exit(&pcic->pc_lock);
17142305Sstevel 
17152305Sstevel 		/*
17162305Sstevel 		 * when true power management exists, save the adapter
17172305Sstevel 		 * state here to enable a recovery.  For the emulation
17182305Sstevel 		 * condition, the state is gone
17192305Sstevel 		 */
17202305Sstevel 		return (DDI_SUCCESS);
17212305Sstevel 
17222305Sstevel 	default:
17232305Sstevel 		return (EINVAL);
17242305Sstevel 	}
17252305Sstevel }
17262305Sstevel 
17272305Sstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14));
17282305Sstevel static uint32_t pcic_tisysctl_offbits = 0;
17292305Sstevel static uint32_t pcic_default_latency = 0x40;
17302305Sstevel 
17312305Sstevel static void
17322305Sstevel pcic_setup_adapter(pcicdev_t *pcic)
17332305Sstevel {
17342305Sstevel 	int i;
17352305Sstevel 	int value, flags;
17362305Sstevel 
17377493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
17387493SVincent.Wang@Sun.COM 	pci_regspec_t *reg;
17397493SVincent.Wang@Sun.COM 	uchar_t bus, dev, func;
17407493SVincent.Wang@Sun.COM 	uint_t classcode;
17417493SVincent.Wang@Sun.COM 	int length;
17427493SVincent.Wang@Sun.COM #endif
17437493SVincent.Wang@Sun.COM 
17442305Sstevel 	if (pcic->pc_flags & PCF_PCIBUS) {
17452305Sstevel 		/*
17462305Sstevel 		 * all PCI-to-PCMCIA bus bridges need memory and I/O enabled
17472305Sstevel 		 */
17482305Sstevel 		flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM);
17492305Sstevel 		pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags);
17502305Sstevel 	}
17512305Sstevel 	/* enable each socket */
17522305Sstevel 	for (i = 0; i < pcic->pc_numsockets; i++) {
17532305Sstevel 		pcic->pc_sockets[i].pcs_flags = 0;
17542305Sstevel 		/* find out the socket capabilities (I/O vs memory) */
17552305Sstevel 		value = pcic_getb(pcic, i,
1756*7656SSherry.Moore@Sun.COM 		    PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK;
17572305Sstevel 		if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH)
17582305Sstevel 			pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO;
17592305Sstevel 
17602305Sstevel 		/* disable all windows just in case */
17612305Sstevel 		pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17622305Sstevel 
17632305Sstevel 		switch (pcic->pc_type) {
17642305Sstevel 			uint32_t cfg32;
17652305Sstevel 			uint16_t cfg16;
17662305Sstevel 			uint8_t cfg;
17672305Sstevel 
17682305Sstevel 		    /* enable extended registers for Vadem */
1769*7656SSherry.Moore@Sun.COM 			case PCIC_VADEM_VG469:
1770*7656SSherry.Moore@Sun.COM 			case PCIC_VADEM:
17712305Sstevel 
17722305Sstevel 			/* enable card status change interrupt for socket */
17732305Sstevel 			break;
17742305Sstevel 
1775*7656SSherry.Moore@Sun.COM 			case PCIC_I82365SL:
17762305Sstevel 			break;
17772305Sstevel 
1778*7656SSherry.Moore@Sun.COM 			case PCIC_CL_PD6710:
17792305Sstevel 			pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE);
17802305Sstevel 			break;
17812305Sstevel 
17822305Sstevel 			/*
17832305Sstevel 			 * On the CL_6730, we need to set up the interrupt
17842305Sstevel 			 * signalling mode (PCI mode) and set the SMI and
17852305Sstevel 			 * IRQ interrupt lines to PCI/level-mode.
17862305Sstevel 			 */
1787*7656SSherry.Moore@Sun.COM 			case PCIC_CL_PD6730:
17882305Sstevel 			switch (pcic->pc_intr_mode) {
17892305Sstevel 			case PCIC_INTR_MODE_PCI_1:
17902305Sstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3,
1791*7656SSherry.Moore@Sun.COM 				    ((clext_reg_read(pcic, i,
1792*7656SSherry.Moore@Sun.COM 				    PCIC_CLEXT_MISC_CTL_3) &
1793*7656SSherry.Moore@Sun.COM 				    ~PCIC_CLEXT_INT_PCI) |
1794*7656SSherry.Moore@Sun.COM 				    PCIC_CLEXT_INT_PCI));
17952305Sstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
1796*7656SSherry.Moore@Sun.COM 				    (PCIC_CLEXT_IRQ_LVL_MODE |
1797*7656SSherry.Moore@Sun.COM 				    PCIC_CLEXT_SMI_LVL_MODE));
17982305Sstevel 				cfg = PCIC_CL_LP_DYN_MODE;
17992305Sstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18002305Sstevel 				break;
18012305Sstevel 			case PCIC_INTR_MODE_ISA:
18022305Sstevel 				break;
18032305Sstevel 			}
18042305Sstevel 			break;
18052305Sstevel 			/*
18062305Sstevel 			 * On the CL_6729, we set the SMI and IRQ interrupt
18072305Sstevel 			 *	lines to PCI/level-mode. as well as program the
18082305Sstevel 			 *	correct clock speed divider bit.
18092305Sstevel 			 */
1810*7656SSherry.Moore@Sun.COM 			case PCIC_CL_PD6729:
18112305Sstevel 			switch (pcic->pc_intr_mode) {
18122305Sstevel 			case PCIC_INTR_MODE_PCI_1:
18132305Sstevel 				clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
1814*7656SSherry.Moore@Sun.COM 				    (PCIC_CLEXT_IRQ_LVL_MODE |
1815*7656SSherry.Moore@Sun.COM 				    PCIC_CLEXT_SMI_LVL_MODE));
18162305Sstevel 
18172305Sstevel 				break;
18182305Sstevel 			case PCIC_INTR_MODE_ISA:
18192305Sstevel 				break;
18202305Sstevel 			}
18212305Sstevel 			if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) {
18222305Sstevel 				cfg = 0;
18232305Sstevel 				cfg |= PCIC_CL_TIMER_CLK_DIV;
18242305Sstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18252305Sstevel 			}
18262305Sstevel 			break;
1827*7656SSherry.Moore@Sun.COM 			case PCIC_INTEL_i82092:
18282305Sstevel 			cfg = PCIC_82092_EN_TIMING;
18292305Sstevel 			if (pcic->bus_speed < PCIC_SYSCLK_33MHZ)
1830*7656SSherry.Moore@Sun.COM 				cfg |= PCIC_82092_PCICLK_25MHZ;
18312305Sstevel 			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
1832*7656SSherry.Moore@Sun.COM 			    PCIC_82092_PCICON, cfg);
18332305Sstevel 			break;
1834*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1130:
1835*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1131:
1836*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1250:
1837*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1031:
18382305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
1839*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_DEVCTL_REG);
18402305Sstevel 			cfg &= ~PCIC_DEVCTL_INTR_MASK;
18412305Sstevel 			switch (pcic->pc_intr_mode) {
18422305Sstevel 			case PCIC_INTR_MODE_ISA:
18432305Sstevel 				cfg |= PCIC_DEVCTL_INTR_ISA;
18442305Sstevel 				break;
18452305Sstevel 			}
18462305Sstevel #ifdef PCIC_DEBUG
18472305Sstevel 			if (pcic_debug) {
18482305Sstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
18492305Sstevel 				    "write reg 0x%x=%x \n",
18502305Sstevel 				    PCIC_DEVCTL_REG, cfg);
18512305Sstevel 			}
18522305Sstevel #endif
18532305Sstevel 			ddi_put8(pcic->cfg_handle,
1854*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_DEVCTL_REG,
1855*7656SSherry.Moore@Sun.COM 			    cfg);
18562305Sstevel 
18572305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
1858*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_CRDCTL_REG);
18592305Sstevel 			cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC|
1860*7656SSherry.Moore@Sun.COM 			    PCIC_CRDCTL_PCIFUNC);
18612305Sstevel 			switch (pcic->pc_intr_mode) {
18622305Sstevel 			case PCIC_INTR_MODE_PCI_1:
18632305Sstevel 				cfg |= PCIC_CRDCTL_PCIINTR |
1864*7656SSherry.Moore@Sun.COM 				    PCIC_CRDCTL_PCICSC |
1865*7656SSherry.Moore@Sun.COM 				    PCIC_CRDCTL_PCIFUNC;
18662305Sstevel 				pcic->pc_flags |= PCF_USE_SMI;
18672305Sstevel 				break;
18682305Sstevel 			}
18692305Sstevel #ifdef PCIC_DEBUG
18702305Sstevel 			if (pcic_debug) {
18712305Sstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
18722305Sstevel 				    " write reg 0x%x=%x \n",
18732305Sstevel 				    PCIC_CRDCTL_REG, cfg);
18742305Sstevel 			}
18752305Sstevel #endif
18762305Sstevel 			ddi_put8(pcic->cfg_handle,
1877*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_CRDCTL_REG,
1878*7656SSherry.Moore@Sun.COM 			    cfg);
18792305Sstevel 			break;
1880*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1221:
1881*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1225:
18822305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
18832305Sstevel 			    pcic->cfgaddr + PCIC_DEVCTL_REG);
18842305Sstevel 			cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE);
18852305Sstevel #ifdef PCIC_DEBUG
18862305Sstevel 			if (pcic_debug) {
18872305Sstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
18882305Sstevel 				    " write reg 0x%x=%x \n",
18892305Sstevel 				    PCIC_DEVCTL_REG, cfg);
18902305Sstevel 			}
18912305Sstevel #endif
18922305Sstevel 			ddi_put8(pcic->cfg_handle,
18932305Sstevel 			    pcic->cfgaddr + PCIC_DEVCTL_REG, cfg);
18942305Sstevel 
18952305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
18962305Sstevel 			    pcic->cfgaddr + PCIC_DIAG_REG);
18972305Sstevel 			if (pcic->pc_type == PCIC_TI_PCI1225) {
18982305Sstevel 				cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
18992305Sstevel 			} else {
19002305Sstevel 				cfg |= PCIC_DIAG_ASYNC;
19012305Sstevel 			}
19022305Sstevel 			pcic->pc_flags |= PCF_USE_SMI;
19032305Sstevel #ifdef PCIC_DEBUG
19042305Sstevel 			if (pcic_debug) {
19052305Sstevel 				cmn_err(CE_CONT, "pcic_setup_adapter: "
19062305Sstevel 				    " write reg 0x%x=%x \n",
19072305Sstevel 				    PCIC_DIAG_REG, cfg);
19082305Sstevel 			}
19092305Sstevel #endif
19102305Sstevel 			ddi_put8(pcic->cfg_handle,
19112305Sstevel 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19122305Sstevel 			break;
1913*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1520:
1914*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1510:
1915*7656SSherry.Moore@Sun.COM 			case PCIC_TI_VENDOR:
19162305Sstevel 			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
19177493SVincent.Wang@Sun.COM 				/* functional intr routed by ExCA register */
19182305Sstevel 				cfg = ddi_get8(pcic->cfg_handle,
1919*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
19202305Sstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
19212305Sstevel 				ddi_put8(pcic->cfg_handle,
1922*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
1923*7656SSherry.Moore@Sun.COM 				    cfg);
19247493SVincent.Wang@Sun.COM 
19257493SVincent.Wang@Sun.COM 				/* IRQ serialized interrupts */
19267493SVincent.Wang@Sun.COM 				cfg = ddi_get8(pcic->cfg_handle,
1927*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_DEVCTL_REG);
19287493SVincent.Wang@Sun.COM 				cfg &= ~PCIC_DEVCTL_INTR_MASK;
19297493SVincent.Wang@Sun.COM 				cfg |= PCIC_DEVCTL_INTR_ISA;
19307493SVincent.Wang@Sun.COM 				ddi_put8(pcic->cfg_handle,
1931*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_DEVCTL_REG,
1932*7656SSherry.Moore@Sun.COM 				    cfg);
19337493SVincent.Wang@Sun.COM 				break;
19342305Sstevel 			}
19357493SVincent.Wang@Sun.COM 
19367493SVincent.Wang@Sun.COM 			/* CSC interrupt routed to PCI */
19377493SVincent.Wang@Sun.COM 			cfg = ddi_get8(pcic->cfg_handle,
19387493SVincent.Wang@Sun.COM 			    pcic->cfgaddr + PCIC_DIAG_REG);
19397493SVincent.Wang@Sun.COM 			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
19407493SVincent.Wang@Sun.COM 			ddi_put8(pcic->cfg_handle,
19417493SVincent.Wang@Sun.COM 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19427493SVincent.Wang@Sun.COM 
19437493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
19447493SVincent.Wang@Sun.COM 			/*
19457493SVincent.Wang@Sun.COM 			 * Some TI chips have 2 cardbus slots(function0 and
19467493SVincent.Wang@Sun.COM 			 * function1), and others may have just 1 cardbus slot.
19477493SVincent.Wang@Sun.COM 			 * The interrupt routing register is shared between the
19487493SVincent.Wang@Sun.COM 			 * 2 functions and can only be accessed through
19497493SVincent.Wang@Sun.COM 			 * function0. Here we check the presence of the second
19507493SVincent.Wang@Sun.COM 			 * cardbus slot and do the right thing.
19517493SVincent.Wang@Sun.COM 			 */
19527493SVincent.Wang@Sun.COM 
19537493SVincent.Wang@Sun.COM 			if (ddi_getlongprop(DDI_DEV_T_ANY, pcic->dip,
19547493SVincent.Wang@Sun.COM 			    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
19557493SVincent.Wang@Sun.COM 			    &length) != DDI_PROP_SUCCESS) {
1956*7656SSherry.Moore@Sun.COM 				cmn_err(CE_WARN,
1957*7656SSherry.Moore@Sun.COM 				    "pcic_setup_adapter(), failed to"
1958*7656SSherry.Moore@Sun.COM 				    " read reg property\n");
19597493SVincent.Wang@Sun.COM 				break;
19607493SVincent.Wang@Sun.COM 			}
19617493SVincent.Wang@Sun.COM 
19627493SVincent.Wang@Sun.COM 			bus = PCI_REG_BUS_G(reg->pci_phys_hi);
19637493SVincent.Wang@Sun.COM 			dev = PCI_REG_DEV_G(reg->pci_phys_hi);
19647493SVincent.Wang@Sun.COM 			func = PCI_REG_FUNC_G(reg->pci_phys_hi);
19657493SVincent.Wang@Sun.COM 			kmem_free((caddr_t)reg, length);
19667493SVincent.Wang@Sun.COM 
19677493SVincent.Wang@Sun.COM 			if (func != 0) {
19687493SVincent.Wang@Sun.COM 				break;
19697493SVincent.Wang@Sun.COM 			}
19707493SVincent.Wang@Sun.COM 
19717493SVincent.Wang@Sun.COM 			classcode = (*pci_getl_func)(bus, dev, 1,
1972*7656SSherry.Moore@Sun.COM 			    PCI_CONF_REVID);
19737493SVincent.Wang@Sun.COM 			classcode >>= 8;
19747493SVincent.Wang@Sun.COM 			if (classcode != 0x060700 &&
19757493SVincent.Wang@Sun.COM 			    classcode != 0x060500) {
19767493SVincent.Wang@Sun.COM 				break;
19777493SVincent.Wang@Sun.COM 			}
19787493SVincent.Wang@Sun.COM 
19797493SVincent.Wang@Sun.COM 			/* Parallel PCI interrupts only */
19802305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
1981*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_DEVCTL_REG);
19822305Sstevel 			cfg &= ~PCIC_DEVCTL_INTR_MASK;
19832305Sstevel 			ddi_put8(pcic->cfg_handle,
1984*7656SSherry.Moore@Sun.COM 			    pcic->cfgaddr + PCIC_DEVCTL_REG,
1985*7656SSherry.Moore@Sun.COM 			    cfg);
19862305Sstevel 
19872305Sstevel 			/* tie INTA and INTB together */
19882305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
1989*7656SSherry.Moore@Sun.COM 			    (pcic->cfgaddr + PCIC_SYSCTL_REG + 3));
19902305Sstevel 			cfg |= PCIC_SYSCTL_INTRTIE;
19912305Sstevel 			ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
1992*7656SSherry.Moore@Sun.COM 			    PCIC_SYSCTL_REG + 3), cfg);
19937493SVincent.Wang@Sun.COM #endif
19947493SVincent.Wang@Sun.COM 
19952305Sstevel 			break;
1996*7656SSherry.Moore@Sun.COM 			case PCIC_TI_PCI1410:
19972305Sstevel 			cfg = ddi_get8(pcic->cfg_handle,
19982305Sstevel 			    pcic->cfgaddr + PCIC_DIAG_REG);
19992305Sstevel 			cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
20002305Sstevel 			ddi_put8(pcic->cfg_handle,
20012305Sstevel 			    pcic->cfgaddr + PCIC_DIAG_REG, cfg);
20022305Sstevel 			break;
2003*7656SSherry.Moore@Sun.COM 			case PCIC_TOSHIBA_TOPIC100:
2004*7656SSherry.Moore@Sun.COM 			case PCIC_TOSHIBA_TOPIC95:
2005*7656SSherry.Moore@Sun.COM 			case PCIC_TOSHIBA_VENDOR:
20062305Sstevel 			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
2007*7656SSherry.Moore@Sun.COM 			    PCIC_TOSHIBA_SLOT_CTL_REG);
20082305Sstevel 			cfg |= (PCIC_TOSHIBA_SCR_SLOTON |
2009*7656SSherry.Moore@Sun.COM 			    PCIC_TOSHIBA_SCR_SLOTEN);
20102305Sstevel 			cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK);
20112305Sstevel 			cfg |= PCIC_TOSHIBA_SCR_PRT_3E2;
20122305Sstevel 			ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
2013*7656SSherry.Moore@Sun.COM 			    PCIC_TOSHIBA_SLOT_CTL_REG, cfg);
20142305Sstevel 			cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
2015*7656SSherry.Moore@Sun.COM 			    PCIC_TOSHIBA_INTR_CTL_REG);
20162305Sstevel 			switch (pcic->pc_intr_mode) {
20172305Sstevel 			case PCIC_INTR_MODE_ISA:
20182305Sstevel 				cfg &= ~PCIC_TOSHIBA_ICR_SRC;
20192305Sstevel 				ddi_put8(pcic->cfg_handle,
2020*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr +
2021*7656SSherry.Moore@Sun.COM 				    PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20222305Sstevel 
20232305Sstevel 				cfg = ddi_get8(pcic->cfg_handle,
2024*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20252305Sstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
20262305Sstevel 				ddi_put8(pcic->cfg_handle,
2027*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
2028*7656SSherry.Moore@Sun.COM 				    cfg);
20292305Sstevel 				break;
20302305Sstevel 			case PCIC_INTR_MODE_PCI_1:
20312305Sstevel 				cfg |= PCIC_TOSHIBA_ICR_SRC;
20322305Sstevel 				cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK);
20332305Sstevel 				cfg |= PCIC_TOSHIBA_ICR_PIN_INTA;
20342305Sstevel 				ddi_put8(pcic->cfg_handle,
2035*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr +
2036*7656SSherry.Moore@Sun.COM 				    PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20372305Sstevel 				break;
20382305Sstevel 			}
20392305Sstevel 			break;
2040*7656SSherry.Moore@Sun.COM 			case PCIC_O2MICRO_VENDOR:
20412305Sstevel 			cfg32 = ddi_get32(pcic->cfg_handle,
2042*7656SSherry.Moore@Sun.COM 			    (uint32_t *)(pcic->cfgaddr +
2043*7656SSherry.Moore@Sun.COM 			    PCIC_O2MICRO_MISC_CTL));
20442305Sstevel 			switch (pcic->pc_intr_mode) {
20452305Sstevel 			case PCIC_INTR_MODE_ISA:
20462305Sstevel 				cfg32 |= (PCIC_O2MICRO_ISA_LEGACY |
2047*7656SSherry.Moore@Sun.COM 				    PCIC_O2MICRO_INT_MOD_PCI);
20482305Sstevel 				ddi_put32(pcic->cfg_handle,
2049*7656SSherry.Moore@Sun.COM 				    (uint32_t *)(pcic->cfgaddr +
2050*7656SSherry.Moore@Sun.COM 				    PCIC_O2MICRO_MISC_CTL),
2051*7656SSherry.Moore@Sun.COM 				    cfg32);
20522305Sstevel 				cfg = ddi_get8(pcic->cfg_handle,
2053*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20542305Sstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
20552305Sstevel 				ddi_put8(pcic->cfg_handle,
2056*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
2057*7656SSherry.Moore@Sun.COM 				    cfg);
20582305Sstevel 				break;
20592305Sstevel 			case PCIC_INTR_MODE_PCI_1:
20602305Sstevel 				cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY;
20612305Sstevel 				cfg32 |= PCIC_O2MICRO_INT_MOD_PCI;
20622305Sstevel 				ddi_put32(pcic->cfg_handle,
2063*7656SSherry.Moore@Sun.COM 				    (uint32_t *)(pcic->cfgaddr +
2064*7656SSherry.Moore@Sun.COM 				    PCIC_O2MICRO_MISC_CTL),
2065*7656SSherry.Moore@Sun.COM 				    cfg32);
20662305Sstevel 				break;
20672305Sstevel 			}
20682305Sstevel 			break;
2069*7656SSherry.Moore@Sun.COM 			case PCIC_RICOH_VENDOR:
20702305Sstevel 			if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
20712305Sstevel 				cfg16 = ddi_get16(pcic->cfg_handle,
2072*7656SSherry.Moore@Sun.COM 				    (uint16_t *)(pcic->cfgaddr +
2073*7656SSherry.Moore@Sun.COM 				    PCIC_RICOH_MISC_CTL_2));
20742305Sstevel 				cfg16 |= (PCIC_RICOH_CSC_INT_MOD |
2075*7656SSherry.Moore@Sun.COM 				    PCIC_RICOH_FUN_INT_MOD);
20762305Sstevel 				ddi_put16(pcic->cfg_handle,
2077*7656SSherry.Moore@Sun.COM 				    (uint16_t *)(pcic->cfgaddr +
2078*7656SSherry.Moore@Sun.COM 				    PCIC_RICOH_MISC_CTL_2),
2079*7656SSherry.Moore@Sun.COM 				    cfg16);
20802305Sstevel 
20812305Sstevel 				cfg16 = ddi_get16(pcic->cfg_handle,
2082*7656SSherry.Moore@Sun.COM 				    (uint16_t *)(pcic->cfgaddr +
2083*7656SSherry.Moore@Sun.COM 				    PCIC_RICOH_MISC_CTL));
20842305Sstevel 				cfg16 |= PCIC_RICOH_SIRQ_EN;
20852305Sstevel 				ddi_put16(pcic->cfg_handle,
2086*7656SSherry.Moore@Sun.COM 				    (uint16_t *)(pcic->cfgaddr +
2087*7656SSherry.Moore@Sun.COM 				    PCIC_RICOH_MISC_CTL),
2088*7656SSherry.Moore@Sun.COM 				    cfg16);
20892305Sstevel 
20902305Sstevel 				cfg = ddi_get8(pcic->cfg_handle,
2091*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20922305Sstevel 				cfg |= PCIC_FUN_INT_MOD_ISA;
20932305Sstevel 				ddi_put8(pcic->cfg_handle,
2094*7656SSherry.Moore@Sun.COM 				    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
2095*7656SSherry.Moore@Sun.COM 				    cfg);
20962305Sstevel 			}
20972305Sstevel 			break;
2098*7656SSherry.Moore@Sun.COM 			default:
20992305Sstevel 			break;
21002305Sstevel 		} /* switch */
21012305Sstevel 
21023097Srw148561 		/*
21033097Srw148561 		 * The default value in the EEPROM (loaded on reset) for
21043097Srw148561 		 * MFUNC0/MFUNC1 may be incorrect. Here we make sure that
21053097Srw148561 		 * MFUNC0 is connected to INTA, and MFUNC1 is connected to
21063097Srw148561 		 * INTB. This applies to all TI CardBus controllers.
21073097Srw148561 		 */
21083097Srw148561 		if ((pcic->pc_type >> 16) == PCIC_TI_VENDORID &&
2109*7656SSherry.Moore@Sun.COM 		    pcic->pc_intr_mode == PCIC_INTR_MODE_PCI_1) {
21103097Srw148561 			value = ddi_get32(pcic->cfg_handle,
21113097Srw148561 			    (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG));
21123097Srw148561 			value &= ~0xff;
21133097Srw148561 			ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr +
21143664Srw148561 			    PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL);
21153097Srw148561 		}
21163097Srw148561 
21172305Sstevel 		/* setup general card status change interrupt */
21182305Sstevel 		switch (pcic->pc_type) {
21192305Sstevel 			case PCIC_TI_PCI1225:
21202305Sstevel 			case PCIC_TI_PCI1221:
21212305Sstevel 			case PCIC_TI_PCI1031:
21222305Sstevel 			case PCIC_TI_PCI1520:
21232305Sstevel 			case PCIC_TI_PCI1410:
21242305Sstevel 				pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21252305Sstevel 				    PCIC_CHANGE_DEFAULT);
21262305Sstevel 				break;
21272305Sstevel 			default:
21282305Sstevel 				if (pcic->pc_intr_mode ==
2129*7656SSherry.Moore@Sun.COM 				    PCIC_INTR_MODE_PCI_1) {
21302305Sstevel 					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
2131*7656SSherry.Moore@Sun.COM 					    PCIC_CHANGE_DEFAULT);
21322305Sstevel 					break;
21332305Sstevel 				} else {
21342305Sstevel 					pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
2135*7656SSherry.Moore@Sun.COM 					    PCIC_CHANGE_DEFAULT |
2136*7656SSherry.Moore@Sun.COM 					    (pcic->pc_sockets[i].pcs_smi << 4));
21372305Sstevel 					break;
21382305Sstevel 				}
21392305Sstevel 		}
21402305Sstevel 
21412305Sstevel 		pcic->pc_flags |= PCF_INTRENAB;
21422305Sstevel 
21432305Sstevel 		/* take card out of RESET */
21442305Sstevel 		pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET);
21452305Sstevel 		/* turn power off and let CS do this */
21462305Sstevel 		pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
21472305Sstevel 
21482305Sstevel 		/* final chip specific initialization */
21492305Sstevel 		switch (pcic->pc_type) {
2150*7656SSherry.Moore@Sun.COM 			case PCIC_VADEM:
21512305Sstevel 			pcic_putb(pcic, i, PCIC_VG_CONTROL,
2152*7656SSherry.Moore@Sun.COM 			    PCIC_VC_DELAYENABLE);
21532305Sstevel 			pcic->pc_flags |= PCF_DEBOUNCE;
21542305Sstevel 			/* FALLTHROUGH */
2155*7656SSherry.Moore@Sun.COM 			case PCIC_I82365SL:
21562305Sstevel 			pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL,
2157*7656SSherry.Moore@Sun.COM 			    PCIC_GC_CSC_WRITE);
21582305Sstevel 			/* clear any pending interrupts */
21592305Sstevel 			value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE);
21602305Sstevel 			pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value);
21612305Sstevel 			break;
21622305Sstevel 		    /* The 82092 uses PCI config space to enable interrupts */
2163*7656SSherry.Moore@Sun.COM 			case PCIC_INTEL_i82092:
21642305Sstevel 			pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI,
2165*7656SSherry.Moore@Sun.COM 			    PCIC_82092_INT_ENABLE);
21662305Sstevel 			break;
2167*7656SSherry.Moore@Sun.COM 			case PCIC_CL_PD6729:
21682305Sstevel 			if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) {
21692305Sstevel 				value = pcic_getb(pcic, i, PCIC_MISC_CTL_2);
21702305Sstevel 				pcic_putb(pcic, i, PCIC_MISC_CTL_2,
2171*7656SSherry.Moore@Sun.COM 				    value | PCIC_CL_TIMER_CLK_DIV);
21722305Sstevel 			}
21732305Sstevel 			break;
21742305Sstevel 		} /* switch */
21752305Sstevel 
21762305Sstevel #if defined(PCIC_DEBUG)
21772305Sstevel 		if (pcic_debug)
21782305Sstevel 			cmn_err(CE_CONT,
2179*7656SSherry.Moore@Sun.COM 			    "socket %d value=%x, flags = %x (%s)\n",
2180*7656SSherry.Moore@Sun.COM 			    i, value, pcic->pc_sockets[i].pcs_flags,
2181*7656SSherry.Moore@Sun.COM 			    (pcic->pc_sockets[i].pcs_flags &
2182*7656SSherry.Moore@Sun.COM 			    PCS_CARD_PRESENT) ?
2183*7656SSherry.Moore@Sun.COM 			"card present" : "no card");
21842305Sstevel #endif
21852305Sstevel 	}
21862305Sstevel }
21872305Sstevel 
21882305Sstevel /*
21892305Sstevel  * pcic_intr(caddr_t, caddr_t)
21902305Sstevel  *	interrupt handler for the PCIC style adapter
21912305Sstevel  *	handles all basic interrupts and also checks
21922305Sstevel  *	for status changes and notifies the nexus if
21932305Sstevel  *	necessary
21942305Sstevel  *
21952305Sstevel  *	On PCI bus adapters, also handles all card
21962305Sstevel  *	IO interrupts.
21972305Sstevel  */
21982305Sstevel /*ARGSUSED*/
21992305Sstevel uint32_t
22002305Sstevel pcic_intr(caddr_t arg1, caddr_t arg2)
22012305Sstevel {
22022305Sstevel 	pcicdev_t *pcic = (pcicdev_t *)arg1;
22032305Sstevel 	int value = 0, i, ret = DDI_INTR_UNCLAIMED;
22042305Sstevel 	uint8_t status;
22052305Sstevel 	uint_t io_ints;
22062305Sstevel 
22072305Sstevel #if defined(PCIC_DEBUG)
22082305Sstevel 	pcic_err(pcic->dip, 0xf,
2209*7656SSherry.Moore@Sun.COM 	    "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x"
2210*7656SSherry.Moore@Sun.COM 	    " pc_numsockets=%d \n",
2211*7656SSherry.Moore@Sun.COM 	    pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets);
22122305Sstevel #endif
22132305Sstevel 
22142305Sstevel 	if (!(pcic->pc_flags & PCF_ATTACHED))
2215*7656SSherry.Moore@Sun.COM 		return (DDI_INTR_UNCLAIMED);
22162305Sstevel 
22172305Sstevel 	mutex_enter(&pcic->intr_lock);
22182305Sstevel 
22192305Sstevel 	if (pcic->pc_flags & PCF_SUSPENDED) {
22202305Sstevel 		mutex_exit(&pcic->intr_lock);
22212305Sstevel 		return (ret);
22222305Sstevel 	}
22232305Sstevel 
22242305Sstevel 	/*
22252305Sstevel 	 * need to change to only ACK and touch the slot that
22262305Sstevel 	 * actually caused the interrupt.  Currently everything
22272305Sstevel 	 * is acked
22282305Sstevel 	 *
22292305Sstevel 	 * we need to look at all known sockets to determine
22302305Sstevel 	 * what might have happened, so step through the list
22312305Sstevel 	 * of them
22322305Sstevel 	 */
22332305Sstevel 
22342305Sstevel 	/*
22352305Sstevel 	 * Set the bitmask for IO interrupts to initially include all sockets
22362305Sstevel 	 */
22372305Sstevel 	io_ints = (1 << pcic->pc_numsockets) - 1;
22382305Sstevel 
22392305Sstevel 	for (i = 0; i < pcic->pc_numsockets; i++) {
22402305Sstevel 		int card_type;
22412305Sstevel 		pcic_socket_t *sockp;
22422305Sstevel 		int value_cb = 0;
22432305Sstevel 
22442305Sstevel 		sockp = &pcic->pc_sockets[i];
22452305Sstevel 		/* get the socket's I/O addresses */
22462305Sstevel 
22472305Sstevel 		if (sockp->pcs_flags & PCS_WAITING) {
22482305Sstevel 			io_ints &= ~(1 << i);
22492305Sstevel 			continue;
22502305Sstevel 		}
22512305Sstevel 
22522305Sstevel 		if (sockp->pcs_flags & PCS_CARD_IO)
22532305Sstevel 			card_type = IF_IO;
22542305Sstevel 		else
22552305Sstevel 			card_type = IF_MEMORY;
22562305Sstevel 
22572305Sstevel 		if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA)
22582305Sstevel 			value_cb = pcic_getcb(pcic, CB_STATUS_EVENT);
22592305Sstevel 
22602305Sstevel 		value = pcic_change(pcic, i);
22612305Sstevel 
22622305Sstevel 		if ((value != 0) || (value_cb != 0)) {
22632305Sstevel 			int x = pcic->pc_cb_arg;
22642305Sstevel 
22652305Sstevel 			ret = DDI_INTR_CLAIMED;
22662305Sstevel 
22672305Sstevel #if defined(PCIC_DEBUG)
22682305Sstevel 			pcic_err(pcic->dip, 0x9,
22692305Sstevel 			    "card_type = %d, value_cb = 0x%x\n",
22702305Sstevel 			    card_type,
22712305Sstevel 			    value_cb ? value_cb :
2272*7656SSherry.Moore@Sun.COM 			    pcic_getcb(pcic, CB_STATUS_EVENT));
22732305Sstevel 			if (pcic_debug)
22742305Sstevel 				cmn_err(CE_CONT,
2275*7656SSherry.Moore@Sun.COM 				    "\tchange on socket %d (%x)\n", i,
2276*7656SSherry.Moore@Sun.COM 				    value);
22772305Sstevel #endif
22782305Sstevel 			/* find out what happened */
22792305Sstevel 			status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS);
22802305Sstevel 
22812305Sstevel 			/* acknowledge the interrupt */
22822305Sstevel 			if (value_cb)
22832305Sstevel 				pcic_putcb(pcic, CB_STATUS_EVENT, value_cb);
22842305Sstevel 
22852305Sstevel 			if (value)
22862305Sstevel 				pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE,
22872305Sstevel 				    value);
22882305Sstevel 
22892305Sstevel 			if (pcic->pc_callback == NULL) {
22902305Sstevel 				/* if not callback handler, nothing to do */
22912305Sstevel 				continue;
22922305Sstevel 			}
22932305Sstevel 
22942305Sstevel 			/* Card Detect */
22952305Sstevel 			if (value & PCIC_CD_DETECT ||
22962305Sstevel 			    value_cb & CB_PS_CCDMASK) {
22972305Sstevel 				uint8_t irq;
22982305Sstevel #if defined(PCIC_DEBUG)
22992305Sstevel 				if (pcic_debug)
23002305Sstevel 					cmn_err(CE_CONT,
2301*7656SSherry.Moore@Sun.COM 					    "\tcd_detect: status=%x,"
2302*7656SSherry.Moore@Sun.COM 					    " flags=%x\n",
2303*7656SSherry.Moore@Sun.COM 					    status, sockp->pcs_flags);
23042305Sstevel #else
23052305Sstevel #ifdef lint
23062305Sstevel 				if (status == 0)
2307*7656SSherry.Moore@Sun.COM 					status++;
23082305Sstevel #endif
23092305Sstevel #endif
23102305Sstevel 				/*
23112305Sstevel 				 * Turn off all interrupts for this socket here.
23122305Sstevel 				 */
23132305Sstevel 				irq = pcic_getb(pcic, sockp->pcs_socket,
23142305Sstevel 				    PCIC_MANAGEMENT_INT);
23152305Sstevel 				irq &= ~PCIC_CHANGE_MASK;
23162305Sstevel 				pcic_putb(pcic, sockp->pcs_socket,
23172305Sstevel 				    PCIC_MANAGEMENT_INT, irq);
23182305Sstevel 
23192305Sstevel 				pcic_putcb(pcic, CB_STATUS_MASK, 0x0);
23202305Sstevel 
23212451Srw148561 				/*
23222451Srw148561 				 * Put the socket in debouncing state so that
23232451Srw148561 				 * the leaf driver won't receive interrupts.
23242451Srw148561 				 * Crucial for handling surprise-removal.
23252451Srw148561 				 */
23262451Srw148561 				sockp->pcs_flags |= PCS_DEBOUNCING;
23272451Srw148561 
23282305Sstevel 				if (!sockp->pcs_cd_softint_flg) {
23292305Sstevel 					sockp->pcs_cd_softint_flg = 1;
23302305Sstevel 					(void) ddi_intr_trigger_softint(
23312305Sstevel 					    sockp->pcs_cd_softint_hdl, NULL);
23322305Sstevel 				}
23332305Sstevel 
23342305Sstevel 				io_ints &= ~(1 << i);
23352305Sstevel 			} /* PCIC_CD_DETECT */
23362305Sstevel 
23372305Sstevel 			/* Ready/Change Detect */
23382305Sstevel 			sockp->pcs_state ^= SBM_RDYBSY;
23392305Sstevel 			if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) {
23402305Sstevel 				sockp->pcs_flags |= PCS_READY;
23412305Sstevel 				PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i);
23422305Sstevel 			}
23432305Sstevel 
23442305Sstevel 			/* Battery Warn Detect */
23452305Sstevel 			if (card_type == IF_MEMORY &&
23462305Sstevel 			    value & PCIC_BW_DETECT &&
23472305Sstevel 			    !(sockp->pcs_state & SBM_BVD2)) {
23482305Sstevel 				sockp->pcs_state |= SBM_BVD2;
23492305Sstevel 				PC_CALLBACK(pcic->dip, x,
2350*7656SSherry.Moore@Sun.COM 				    PCE_CARD_BATTERY_WARN, i);
23512305Sstevel 			}
23522305Sstevel 
23532305Sstevel 			/* Battery Dead Detect */
23542305Sstevel 			if (value & PCIC_BD_DETECT) {
23552305Sstevel 				/*
23562305Sstevel 				 * need to work out event if RI not enabled
23572305Sstevel 				 * and card_type == IF_IO
23582305Sstevel 				 */
23592305Sstevel 				if (card_type == IF_MEMORY &&
2360*7656SSherry.Moore@Sun.COM 				    !(sockp->pcs_state & SBM_BVD1)) {
23612305Sstevel 					sockp->pcs_state |= SBM_BVD1;
23622305Sstevel 					PC_CALLBACK(pcic->dip, x,
2363*7656SSherry.Moore@Sun.COM 					    PCE_CARD_BATTERY_DEAD,
2364*7656SSherry.Moore@Sun.COM 					    i);
23652305Sstevel 				} else {
23662305Sstevel 					/*
23672305Sstevel 					 * information in pin replacement
23682305Sstevel 					 * register if one is available
23692305Sstevel 					 */
23702305Sstevel 					PC_CALLBACK(pcic->dip, x,
2371*7656SSherry.Moore@Sun.COM 					    PCE_CARD_STATUS_CHANGE,
2372*7656SSherry.Moore@Sun.COM 					    i);
23732305Sstevel 				} /* IF_MEMORY */
23742305Sstevel 			} /* PCIC_BD_DETECT */
23752305Sstevel 		} /* if pcic_change */
23762305Sstevel 		/*
23772305Sstevel 		 * for any controllers that we can detect whether a socket
23782305Sstevel 		 * had an interrupt for the PC Card, we should sort that out
23792305Sstevel 		 * here.
23802305Sstevel 		 */
23812305Sstevel 	} /* for pc_numsockets */
23822305Sstevel 
23832305Sstevel 	/*
23842305Sstevel 	 * If we're on a PCI bus, we may need to cycle through each IO
23852305Sstevel 	 *	interrupt handler that is registered since they all
23862305Sstevel 	 *	share the same interrupt line.
23872305Sstevel 	 */
23882305Sstevel 
23892305Sstevel 
23902305Sstevel #if defined(PCIC_DEBUG)
23912305Sstevel 	pcic_err(pcic->dip, 0xf,
23922305Sstevel 	    "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n",
23932305Sstevel 	    pcic->pc_intr_mode, pcic->pc_type, io_ints);
23942305Sstevel #endif
23952305Sstevel 
23962451Srw148561 	if (io_ints) {
23972451Srw148561 		if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED)
23982305Sstevel 			ret = DDI_INTR_CLAIMED;
23992305Sstevel 	}
24002305Sstevel 
24012305Sstevel 	mutex_exit(&pcic->intr_lock);
24022305Sstevel 
24032305Sstevel #if defined(PCIC_DEBUG)
24042305Sstevel 	pcic_err(pcic->dip, 0xf,
24052305Sstevel 	    "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n",
24062305Sstevel 	    ret, value, DDI_INTR_CLAIMED);
24072305Sstevel #endif
24082305Sstevel 
24092305Sstevel 	return (ret);
24102305Sstevel }
24112305Sstevel 
24122305Sstevel /*
24132305Sstevel  * pcic_change()
24142305Sstevel  *	check to see if this socket had a change in state
24152305Sstevel  *	by checking the status change register
24162305Sstevel  */
24172305Sstevel static int
24182305Sstevel pcic_change(pcicdev_t *pcic, int socket)
24192305Sstevel {
24202305Sstevel 	return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE));
24212305Sstevel }
24222305Sstevel 
24232305Sstevel /*
24242305Sstevel  * pcic_do_io_intr - calls client interrupt handlers
24252305Sstevel  */
24262305Sstevel static int
24272305Sstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets)
24282305Sstevel {
24292305Sstevel 	inthandler_t *tmp;
24302305Sstevel 	int ret = DDI_INTR_UNCLAIMED;
24312305Sstevel 
24322305Sstevel #if defined(PCIC_DEBUG)
24332305Sstevel 	pcic_err(pcic->dip, 0xf,
2434*7656SSherry.Moore@Sun.COM 	    "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n",
2435*7656SSherry.Moore@Sun.COM 	    (void *)pcic, (int)sockets, (void *)pcic->irq_top);
24362305Sstevel #endif
24372305Sstevel 
24382305Sstevel 	if (pcic->irq_top != NULL) {
2439*7656SSherry.Moore@Sun.COM 		tmp = pcic->irq_current;
2440*7656SSherry.Moore@Sun.COM 
2441*7656SSherry.Moore@Sun.COM 		do {
24422305Sstevel 		int cur = pcic->irq_current->socket;
24432305Sstevel 		pcic_socket_t *sockp =
2444*7656SSherry.Moore@Sun.COM 		    &pcic->pc_sockets[cur];
24452305Sstevel 
24462305Sstevel #if defined(PCIC_DEBUG)
24472305Sstevel 		pcic_err(pcic->dip, 0xf,
24482305Sstevel 		    "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n",
24492305Sstevel 		    sockp->pcs_flags, PCS_CARD_PRESENT);
24502305Sstevel 		pcic_err(pcic->dip, 0xf,
24512305Sstevel 		    "\t sockets=%d cur=%d intr=%p arg1=%p "
24522305Sstevel 		    "arg2=%p\n",
24532305Sstevel 		    sockets, cur, (void *)pcic->irq_current->intr,
24542305Sstevel 		    pcic->irq_current->arg1,
24552305Sstevel 		    pcic->irq_current->arg2);
24562305Sstevel #endif
24572451Srw148561 		if ((sockp->pcs_flags & PCS_CARD_PRESENT) &&
24582451Srw148561 		    !(sockp->pcs_flags & PCS_DEBOUNCING) &&
24592451Srw148561 		    (sockets & (1 << cur))) {
24602305Sstevel 
24612305Sstevel 			if ((*pcic->irq_current->intr)(pcic->irq_current->arg1,
24622305Sstevel 			    pcic->irq_current->arg2) == DDI_INTR_CLAIMED)
24632305Sstevel 				ret = DDI_INTR_CLAIMED;
24642305Sstevel 
24652305Sstevel #if defined(PCIC_DEBUG)
24662305Sstevel 			pcic_err(pcic->dip, 0xf,
24672305Sstevel 			    "\t ret=%d DDI_INTR_CLAIMED=%d\n",
24682305Sstevel 			    ret, DDI_INTR_CLAIMED);
24692305Sstevel #endif
24702305Sstevel 		}
24712305Sstevel 
24722305Sstevel 
24732305Sstevel 		if ((pcic->irq_current = pcic->irq_current->next) == NULL)
24742305Sstevel 					pcic->irq_current = pcic->irq_top;
24752305Sstevel 
2476*7656SSherry.Moore@Sun.COM 		} while (pcic->irq_current != tmp);
2477*7656SSherry.Moore@Sun.COM 
2478*7656SSherry.Moore@Sun.COM 		if ((pcic->irq_current = pcic->irq_current->next) == NULL)
24792305Sstevel 					pcic->irq_current = pcic->irq_top;
24802305Sstevel 
24812305Sstevel 	} else {
24822305Sstevel 		ret = DDI_INTR_UNCLAIMED;
24832305Sstevel 	}
24842305Sstevel 
24852305Sstevel #if defined(PCIC_DEBUG)
24862305Sstevel 	pcic_err(pcic->dip, 0xf,
2487*7656SSherry.Moore@Sun.COM 	    "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n",
2488*7656SSherry.Moore@Sun.COM 	    ret, DDI_INTR_CLAIMED);
24892305Sstevel #endif
24902305Sstevel 
24912305Sstevel 	return (ret);
24922305Sstevel 
24932305Sstevel }
24942305Sstevel 
24952305Sstevel /*
24962305Sstevel  * pcic_inquire_adapter()
24972305Sstevel  *	SocketServices InquireAdapter function
24982305Sstevel  *	get characteristics of the physical adapter
24992305Sstevel  */
25002305Sstevel /*ARGSUSED*/
25012305Sstevel static int
25022305Sstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
25032305Sstevel {
25042305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
25052305Sstevel 	pcicdev_t *pcic = anp->an_private;
25062305Sstevel 
25072305Sstevel 	config->NumSockets = pcic->pc_numsockets;
25082305Sstevel 	config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK;
25092305Sstevel 	config->NumEDCs = 0;
25102305Sstevel 	config->AdpCaps = 0;
25112305Sstevel 	config->ActiveHigh = 0;
25122305Sstevel 	config->ActiveLow = PCIC_AVAIL_IRQS;
25132305Sstevel 	config->NumPower = pcic->pc_numpower;
25142305Sstevel 	config->power_entry = pcic->pc_power; /* until we resolve this */
25152305Sstevel #if defined(PCIC_DEBUG)
25162305Sstevel 	if (pcic_debug) {
25172305Sstevel 		cmn_err(CE_CONT, "pcic_inquire_adapter:\n");
25182305Sstevel 		cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets);
25192305Sstevel 		cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows);
25202305Sstevel 	}
25212305Sstevel #endif
25222305Sstevel 	config->ResourceFlags = 0;
25232305Sstevel 	switch (pcic->pc_intr_mode) {
25242305Sstevel 	case PCIC_INTR_MODE_PCI_1:
25252305Sstevel 		config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS |
2526*7656SSherry.Moore@Sun.COM 		    RES_IRQ_SHAREABLE;
25272305Sstevel 		break;
25282305Sstevel 	}
25292305Sstevel 	return (SUCCESS);
25302305Sstevel }
25312305Sstevel 
25322305Sstevel /*
25332305Sstevel  * pcic_callback()
25342305Sstevel  *	The PCMCIA nexus calls us via this function
25352305Sstevel  *	in order to set the callback function we are
25362305Sstevel  *	to call the nexus with
25372305Sstevel  */
25382305Sstevel /*ARGSUSED*/
25392305Sstevel static int
25402305Sstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg)
25412305Sstevel {
25422305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
25432305Sstevel 	pcicdev_t *pcic = anp->an_private;
25442305Sstevel 
25452305Sstevel 	if (handler != NULL) {
25462305Sstevel 		pcic->pc_callback = handler;
25472305Sstevel 		pcic->pc_cb_arg  = arg;
25482305Sstevel 		pcic->pc_flags |= PCF_CALLBACK;
25492305Sstevel 	} else {
25502305Sstevel 		pcic->pc_callback = NULL;
25512305Sstevel 		pcic->pc_cb_arg = 0;
25522305Sstevel 		pcic->pc_flags &= ~PCF_CALLBACK;
25532305Sstevel 	}
25542305Sstevel 	/*
25552305Sstevel 	 * we're now registered with the nexus
25562305Sstevel 	 * it is acceptable to do callbacks at this point.
25572305Sstevel 	 * don't call back from here though since it could block
25582305Sstevel 	 */
25592305Sstevel 	return (PC_SUCCESS);
25602305Sstevel }
25612305Sstevel 
25622305Sstevel /*
25632305Sstevel  * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed)
25642305Sstevel  *	calculate the speed bits from the specified memory speed
25652305Sstevel  *	there may be more to do here
25662305Sstevel  */
25672305Sstevel 
25682305Sstevel static int
25692305Sstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed)
25702305Sstevel {
25712305Sstevel 	uint32_t wspeed = 1;	/* assume 1 wait state when unknown */
25722305Sstevel 	uint32_t bspeed = PCIC_ISA_DEF_SYSCLK;
25732305Sstevel 
25742305Sstevel 	switch (pcic->pc_type) {
2575*7656SSherry.Moore@Sun.COM 		case PCIC_I82365SL:
2576*7656SSherry.Moore@Sun.COM 		case PCIC_VADEM:
2577*7656SSherry.Moore@Sun.COM 		case PCIC_VADEM_VG469:
2578*7656SSherry.Moore@Sun.COM 		default:
25792305Sstevel 		/* Intel chip wants it in waitstates */
25802305Sstevel 		wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3;
25812305Sstevel 		if (speed <= wspeed)
25822305Sstevel 			wspeed = 0;
25832305Sstevel 		else if (speed <= (wspeed += mhztons(bspeed)))
25842305Sstevel 			wspeed = 1;
25852305Sstevel 		else if (speed <= (wspeed += mhztons(bspeed)))
25862305Sstevel 			wspeed = 2;
25872305Sstevel 		else
25882305Sstevel 			wspeed = 3;
25892305Sstevel 		wspeed <<= 6; /* put in right bit positions */
25902305Sstevel 		break;
25912305Sstevel 
2592*7656SSherry.Moore@Sun.COM 		case PCIC_INTEL_i82092:
25932305Sstevel 		wspeed = SYSMEM_82092_80NS;
25942305Sstevel 		if (speed > 80)
2595*7656SSherry.Moore@Sun.COM 			wspeed = SYSMEM_82092_100NS;
25962305Sstevel 		if (speed > 100)
2597*7656SSherry.Moore@Sun.COM 			wspeed = SYSMEM_82092_150NS;
25982305Sstevel 		if (speed > 150)
2599*7656SSherry.Moore@Sun.COM 			wspeed = SYSMEM_82092_200NS;
26002305Sstevel 		if (speed > 200)
2601*7656SSherry.Moore@Sun.COM 			wspeed = SYSMEM_82092_250NS;
26022305Sstevel 		if (speed > 250)
2603*7656SSherry.Moore@Sun.COM 			wspeed = SYSMEM_82092_600NS;
26042305Sstevel 		wspeed <<= 5;	/* put in right bit positions */
26052305Sstevel 		break;
26062305Sstevel 
26072305Sstevel 	} /* switch */
26082305Sstevel 
26092305Sstevel 	return (wspeed);
26102305Sstevel }
26112305Sstevel 
26122305Sstevel /*
26132305Sstevel  * These values are taken from the PC Card Standard Electrical Specification.
26142305Sstevel  * Generally the larger value is taken if 2 are possible.
26152305Sstevel  */
26162305Sstevel static struct pcic_card_times {
26172305Sstevel 	uint16_t cycle;	/* Speed as found in the atribute space of he card. */
26182305Sstevel 	uint16_t setup;	/* Corresponding address setup time. */
26192305Sstevel 	uint16_t width;	/* Corresponding width, OE or WE. */
26202305Sstevel 	uint16_t hold;	/* Corresponding data or address hold time. */
26212305Sstevel } pcic_card_times[] = {
26222305Sstevel 
26232305Sstevel /*
26242305Sstevel  * Note: The rounded up times for 250, 200 & 150 have been increased
26252305Sstevel  * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi.
26262305Sstevel  * See BugID 00663.
26272305Sstevel  */
26282305Sstevel 
26292305Sstevel /*
26302305Sstevel  * Rounded up times           Original times from
26312305Sstevel  * that add up to the         the PCMCIA Spec.
26322305Sstevel  * cycle time.
26332305Sstevel  */
26342305Sstevel 	{600, 180, 370, 140},	/* 100, 300,  70 */
26352305Sstevel 	{400, 120, 300, 90},	/* Made this one up */
26362305Sstevel 	{250, 100, 190, 70},	/*  30, 150,  30 */
26372305Sstevel 	{200, 80, 170, 70},	/*  20, 120,  30 */
26382305Sstevel 	{150, 50, 110, 40},	/*  20,  80,  20 */
26392305Sstevel 	{100, 40, 80, 40},	/*  10,  60,  15 */
26402305Sstevel 	{0, 10, 60, 15}		/*  10,  60,  15 */
26412305Sstevel };
26422305Sstevel 
26432305Sstevel /*
26442305Sstevel  * pcic_set_cdtimers
26452305Sstevel  *	This is specific to several Cirrus Logic chips
26462305Sstevel  */
26472305Sstevel static void
26482305Sstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset)
26492305Sstevel {
26502305Sstevel 	int cmd, set, rec, offset, clk_pulse;
26512305Sstevel 	struct pcic_card_times *ctp;
26522305Sstevel 
26532305Sstevel 	if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1))
26542305Sstevel 		offset = 3;
26552305Sstevel 	else
26562305Sstevel 		offset = 0;
26572305Sstevel 
26582305Sstevel 	clk_pulse = mhztons(pcic->bus_speed);
2659*7656SSherry.Moore@Sun.COM 	for (ctp = pcic_card_times; speed < ctp->cycle; ctp++)
2660*7656SSherry.Moore@Sun.COM 		;
26612305Sstevel 
26622305Sstevel 	/*
26632305Sstevel 	 * Add (clk_pulse/2) and an extra 1 to account for rounding errors.
26642305Sstevel 	 */
26652305Sstevel 	set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26662305Sstevel 	if (set < 0)
26672305Sstevel 		set = 0;
26682305Sstevel 
26692305Sstevel 	cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26702305Sstevel 	if (cmd < 0)
26712305Sstevel 		cmd = 0;
26722305Sstevel 
26732305Sstevel 	rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2;
26742305Sstevel 	if (rec < 0)
26752305Sstevel 		rec = 0;
26762305Sstevel 
26772305Sstevel #if defined(PCIC_DEBUG)
26782305Sstevel 	pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n"
26792305Sstevel 	    "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n",
26802305Sstevel 	    (unsigned)speed, offset == 3 ? 1 : 0,
26812305Sstevel 	    ctp->cycle, clk_pulse, cmd, set, rec);
26822305Sstevel #endif
26832305Sstevel 
26842305Sstevel 	pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd);
26852305Sstevel 	pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set);
26862305Sstevel 	pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec);
26872305Sstevel }
26882305Sstevel 
26892305Sstevel /*
26902305Sstevel  * pcic_set_window
26912305Sstevel  *	essentially the same as the Socket Services specification
26922305Sstevel  *	We use socket and not adapter since they are identifiable
26932305Sstevel  *	but the rest is the same
26942305Sstevel  *
26952305Sstevel  *	dip	pcic driver's device information
26962305Sstevel  *	window	parameters for the request
26972305Sstevel  */
26982305Sstevel static int
26992305Sstevel pcic_set_window(dev_info_t *dip, set_window_t *window)
27002305Sstevel {
27012305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
27022305Sstevel 	pcicdev_t *pcic = anp->an_private;
27032305Sstevel 	int select;
27042305Sstevel 	int socket, pages, which, ret;
27052305Sstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[window->socket];
27062305Sstevel 	ra_return_t res;
27072305Sstevel 	ndi_ra_request_t req;
27082305Sstevel 	uint32_t base = window->base;
27092305Sstevel 
27102305Sstevel #if defined(PCIC_DEBUG)
27112305Sstevel 	if (pcic_debug) {
27122305Sstevel 		cmn_err(CE_CONT, "pcic_set_window: entered\n");
27132305Sstevel 		cmn_err(CE_CONT,
2714*7656SSherry.Moore@Sun.COM 		    "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
2715*7656SSherry.Moore@Sun.COM 		    window->window, window->socket, window->WindowSize,
2716*7656SSherry.Moore@Sun.COM 		    window->speed);
27172305Sstevel 		cmn_err(CE_CONT,
2718*7656SSherry.Moore@Sun.COM 		    "\tbase=%x, state=%x\n", (unsigned)window->base,
2719*7656SSherry.Moore@Sun.COM 		    (unsigned)window->state);
27202305Sstevel 	}
27212305Sstevel #endif
27222305Sstevel 
27232305Sstevel 	/*
27242305Sstevel 	 * do some basic sanity checking on what we support
27252305Sstevel 	 * we don't do paged mode
27262305Sstevel 	 */
27272305Sstevel 	if (window->state & WS_PAGED) {
27282305Sstevel 		cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n");
27292305Sstevel 		return (BAD_ATTRIBUTE);
27302305Sstevel 	}
27312305Sstevel 
27322305Sstevel 	/*
27332305Sstevel 	 * we don't care about previous mappings.
27342305Sstevel 	 * Card Services will deal with that so don't
27352305Sstevel 	 * even check
27362305Sstevel 	 */
27372305Sstevel 
27382305Sstevel 	socket = window->socket;
27392305Sstevel 
27402305Sstevel 	if (!(window->state & WS_IO)) {
27412305Sstevel 		int win, tmp;
27422305Sstevel 		pcs_memwin_t *memp;
27432305Sstevel #if defined(PCIC_DEBUG)
27442305Sstevel 		if (pcic_debug)
27452305Sstevel 			cmn_err(CE_CONT, "\twindow type is memory\n");
27462305Sstevel #endif
27472305Sstevel 		/* this is memory window mapping */
27482305Sstevel 		win = window->window % PCIC_NUMWINSOCK;
27492305Sstevel 		tmp = window->window / PCIC_NUMWINSOCK;
27502305Sstevel 
27512305Sstevel 		/* only windows 2-6 can do memory mapping */
27522305Sstevel 		if (tmp != window->socket || win < PCIC_IOWINDOWS) {
27532305Sstevel 			cmn_err(CE_CONT,
2754*7656SSherry.Moore@Sun.COM 			    "\tattempt to map to non-mem window\n");
27552305Sstevel 			return (BAD_WINDOW);
27562305Sstevel 		}
27572305Sstevel 
27582305Sstevel 		if (window->WindowSize == 0)
27592305Sstevel 			window->WindowSize = MEM_MIN;
27602305Sstevel 		else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) {
27612305Sstevel 			cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n");
27622305Sstevel 			return (BAD_SIZE);
27632305Sstevel 		}
27642305Sstevel 
27652305Sstevel 		mutex_enter(&pcic->pc_lock); /* protect the registers */
27662305Sstevel 
27672305Sstevel 		memp = &sockp->pcs_windows[win].mem;
27682305Sstevel 		memp->pcw_speed = window->speed;
27692305Sstevel 
27702305Sstevel 		win -= PCIC_IOWINDOWS; /* put in right range */
27712305Sstevel 
27722305Sstevel 		if (window->WindowSize != memp->pcw_len)
27732305Sstevel 			which = memp->pcw_len;
27742305Sstevel 		else
27752305Sstevel 			which = 0;
27762305Sstevel 
27772305Sstevel 		if (window->state & WS_ENABLED) {
27782305Sstevel 			uint32_t wspeed;
27792305Sstevel #if defined(PCIC_DEBUG)
27802305Sstevel 			if (pcic_debug) {
27812305Sstevel 				cmn_err(CE_CONT,
2782*7656SSherry.Moore@Sun.COM 				    "\tbase=%x, win=%d\n", (unsigned)base,
2783*7656SSherry.Moore@Sun.COM 				    win);
27842305Sstevel 				if (which)
27852305Sstevel 					cmn_err(CE_CONT,
2786*7656SSherry.Moore@Sun.COM 					    "\tneed to remap window\n");
27872305Sstevel 			}
27882305Sstevel #endif
27892305Sstevel 
27902305Sstevel 			if (which && (memp->pcw_status & PCW_MAPPED)) {
27912305Sstevel 				ddi_regs_map_free(&memp->pcw_handle);
27922305Sstevel 				res.ra_addr_lo = memp->pcw_base;
27932305Sstevel 				res.ra_len = memp->pcw_len;
27943664Srw148561 				(void) pcmcia_free_mem(memp->res_dip, &res);
27952305Sstevel 				memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
27962305Sstevel 				memp->pcw_hostmem = NULL;
27972305Sstevel 				memp->pcw_base = NULL;
27982305Sstevel 				memp->pcw_len = 0;
27992305Sstevel 			}
28002305Sstevel 
28012305Sstevel 			which = window->WindowSize >> PAGE_SHIFT;
28022305Sstevel 
28032305Sstevel 			if (!(memp->pcw_status & PCW_MAPPED)) {
28042305Sstevel 				ret = 0;
28052305Sstevel 
28062305Sstevel 				memp->pcw_base = base;
28072305Sstevel 				bzero(&req, sizeof (req));
28082305Sstevel 				req.ra_len = which << PAGE_SHIFT;
28092305Sstevel 				req.ra_addr = (uint64_t)memp->pcw_base;
28102305Sstevel 				req.ra_boundbase = pcic->pc_base;
28112305Sstevel 				req.ra_boundlen  = pcic->pc_bound;
28122305Sstevel 				req.ra_flags = (memp->pcw_base ?
2813*7656SSherry.Moore@Sun.COM 				    NDI_RA_ALLOC_SPECIFIED : 0) |
2814*7656SSherry.Moore@Sun.COM 				    NDI_RA_ALLOC_BOUNDED;
28152305Sstevel 				req.ra_align_mask =
2816*7656SSherry.Moore@Sun.COM 				    (PAGESIZE - 1) | (PCIC_PAGE - 1);
28172305Sstevel #if defined(PCIC_DEBUG)
2818*7656SSherry.Moore@Sun.COM 					pcic_err(dip, 8,
28192305Sstevel 					    "\tlen 0x%"PRIx64
28202305Sstevel 					    "addr 0x%"PRIx64"bbase 0x%"PRIx64
28212305Sstevel 					    " blen 0x%"PRIx64" flags 0x%x"
28222305Sstevel 					    " algn 0x%"PRIx64"\n",
28232305Sstevel 					    req.ra_len, req.ra_addr,
28242305Sstevel 					    req.ra_boundbase,
28252305Sstevel 					    req.ra_boundlen, req.ra_flags,
28262305Sstevel 					    req.ra_align_mask);
28272305Sstevel #endif
28282305Sstevel 
28293664Srw148561 				ret = pcmcia_alloc_mem(dip, &req, &res,
2830*7656SSherry.Moore@Sun.COM 				    &memp->res_dip);
28312305Sstevel 				if (ret == DDI_FAILURE) {
28322305Sstevel 					mutex_exit(&pcic->pc_lock);
28332305Sstevel 					cmn_err(CE_WARN,
28342305Sstevel 					"\tpcmcia_alloc_mem() failed\n");
28352305Sstevel 					return (BAD_SIZE);
28362305Sstevel 				}
28372305Sstevel 				memp->pcw_base = res.ra_addr_lo;
28382305Sstevel 				base = memp->pcw_base;
28392305Sstevel 
28402305Sstevel #if defined(PCIC_DEBUG)
28412305Sstevel 				if (pcic_debug)
28422305Sstevel 					cmn_err(CE_CONT,
2843*7656SSherry.Moore@Sun.COM 					    "\tsetwindow: new base=%x\n",
2844*7656SSherry.Moore@Sun.COM 					    (unsigned)memp->pcw_base);
28452305Sstevel #endif
28462305Sstevel 				memp->pcw_len = window->WindowSize;
28472305Sstevel 
28482305Sstevel 				which = pcmcia_map_reg(pcic->dip,
2849*7656SSherry.Moore@Sun.COM 				    window->child,
2850*7656SSherry.Moore@Sun.COM 				    &res,
2851*7656SSherry.Moore@Sun.COM 				    (uint32_t)(window->state &
2852*7656SSherry.Moore@Sun.COM 				    0xffff) |
2853*7656SSherry.Moore@Sun.COM 				    (window->socket << 16),
2854*7656SSherry.Moore@Sun.COM 				    (caddr_t *)&memp->pcw_hostmem,
2855*7656SSherry.Moore@Sun.COM 				    &memp->pcw_handle,
2856*7656SSherry.Moore@Sun.COM 				    &window->attr, NULL);
28572305Sstevel 
28582305Sstevel 				if (which != DDI_SUCCESS) {
28592305Sstevel 
28602305Sstevel 					cmn_err(CE_WARN, "\tpcmcia_map_reg() "
2861*7656SSherry.Moore@Sun.COM 					    "failed\n");
2862*7656SSherry.Moore@Sun.COM 
2863*7656SSherry.Moore@Sun.COM 					res.ra_addr_lo = memp->pcw_base;
2864*7656SSherry.Moore@Sun.COM 					res.ra_len = memp->pcw_len;
2865*7656SSherry.Moore@Sun.COM 					(void) pcmcia_free_mem(memp->res_dip,
2866*7656SSherry.Moore@Sun.COM 					    &res);
2867*7656SSherry.Moore@Sun.COM 
2868*7656SSherry.Moore@Sun.COM 					mutex_exit(&pcic->pc_lock);
2869*7656SSherry.Moore@Sun.COM 
2870*7656SSherry.Moore@Sun.COM 					return (BAD_WINDOW);
28712305Sstevel 				}
28722305Sstevel 				memp->pcw_status |= PCW_MAPPED;
28732305Sstevel #if defined(PCIC_DEBUG)
28742305Sstevel 				if (pcic_debug)
28752305Sstevel 					cmn_err(CE_CONT,
2876*7656SSherry.Moore@Sun.COM 					    "\tmap=%x, hostmem=%p\n",
2877*7656SSherry.Moore@Sun.COM 					    which,
2878*7656SSherry.Moore@Sun.COM 					    (void *)memp->pcw_hostmem);
28792305Sstevel #endif
28802305Sstevel 			} else {
28812305Sstevel 				base = memp->pcw_base;
28822305Sstevel 			}
28832305Sstevel 
28842305Sstevel 			/* report the handle back to caller */
28852305Sstevel 			window->handle = memp->pcw_handle;
28862305Sstevel 
28872305Sstevel #if defined(PCIC_DEBUG)
28882305Sstevel 			if (pcic_debug) {
28892305Sstevel 				cmn_err(CE_CONT,
2890*7656SSherry.Moore@Sun.COM 				    "\twindow mapped to %x@%x len=%d\n",
2891*7656SSherry.Moore@Sun.COM 				    (unsigned)window->base,
2892*7656SSherry.Moore@Sun.COM 				    (unsigned)memp->pcw_base,
2893*7656SSherry.Moore@Sun.COM 				    memp->pcw_len);
28942305Sstevel 			}
28952305Sstevel #endif
28962305Sstevel 
28972305Sstevel 			/* find the register set offset */
28982305Sstevel 			select = win * PCIC_MEM_1_OFFSET;
28992305Sstevel #if defined(PCIC_DEBUG)
29002305Sstevel 			if (pcic_debug)
29012305Sstevel 				cmn_err(CE_CONT, "\tselect=%x\n", select);
29022305Sstevel #endif
29032305Sstevel 
29042305Sstevel 			/*
29052305Sstevel 			 * at this point, the register window indicator has
29062305Sstevel 			 * been converted to be an offset from the first
29072305Sstevel 			 * set of registers that are used for programming
29082305Sstevel 			 * the window mapping and the offset used to select
29092305Sstevel 			 * the correct set of registers to access the
29102305Sstevel 			 * specified socket.  This allows basing everything
29112305Sstevel 			 * off the _0 window
29122305Sstevel 			 */
29132305Sstevel 
29142305Sstevel 			/* map the physical page base address */
29152305Sstevel 			which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0;
29162305Sstevel 			which |= (window->speed <= MEM_SPEED_MIN) ?
2917*7656SSherry.Moore@Sun.COM 			    SYSMEM_ZERO_WAIT : 0;
29182305Sstevel 
29192305Sstevel 			/* need to select register set */
29202305Sstevel 			select = PCIC_MEM_1_OFFSET * win;
29212305Sstevel 
29222305Sstevel 			pcic_putb(pcic, socket,
2923*7656SSherry.Moore@Sun.COM 			    PCIC_SYSMEM_0_STARTLOW + select,
2924*7656SSherry.Moore@Sun.COM 			    SYSMEM_LOW(base));
29252305Sstevel 			pcic_putb(pcic, socket,
2926*7656SSherry.Moore@Sun.COM 			    PCIC_SYSMEM_0_STARTHI + select,
2927*7656SSherry.Moore@Sun.COM 			    SYSMEM_HIGH(base) | which);
29282305Sstevel 
29292305Sstevel 			/*
29302305Sstevel 			 * Some adapters can decode window addresses greater
29312305Sstevel 			 * than 16-bits worth, so handle them here.
29322305Sstevel 			 */
29332305Sstevel 			switch (pcic->pc_type) {
29342305Sstevel 			case PCIC_INTEL_i82092:
29352305Sstevel 				pcic_putb(pcic, socket,
2936*7656SSherry.Moore@Sun.COM 				    PCIC_82092_CPAGE,
2937*7656SSherry.Moore@Sun.COM 				    SYSMEM_EXT(base));
29382305Sstevel 				break;
29392305Sstevel 			case PCIC_CL_PD6729:
29402305Sstevel 			case PCIC_CL_PD6730:
29412305Sstevel 				clext_reg_write(pcic, socket,
2942*7656SSherry.Moore@Sun.COM 				    PCIC_CLEXT_MMAP0_UA + win,
2943*7656SSherry.Moore@Sun.COM 				    SYSMEM_EXT(base));
29442305Sstevel 				break;
29452305Sstevel 			case PCIC_TI_PCI1130:
29462305Sstevel 				/*
29472305Sstevel 				 * Note that the TI chip has one upper byte
29482305Sstevel 				 * per socket so all windows get bound to a
29492305Sstevel 				 * 16MB segment.  This must be detected and
29502305Sstevel 				 * handled appropriately.  We can detect that
29512305Sstevel 				 * it is done by seeing if the pc_base has
29522305Sstevel 				 * changed and changing when the register
29532305Sstevel 				 * is first set.  This will force the bounds
29542305Sstevel 				 * to be correct.
29552305Sstevel 				 */
29562305Sstevel 				if (pcic->pc_bound == 0xffffffff) {
29572305Sstevel 					pcic_putb(pcic, socket,
2958*7656SSherry.Moore@Sun.COM 					    PCIC_TI_WINDOW_PAGE_PCI,
2959*7656SSherry.Moore@Sun.COM 					    SYSMEM_EXT(base));
29602305Sstevel 					pcic->pc_base = SYSMEM_EXT(base) << 24;
29612305Sstevel 					pcic->pc_bound = 0x1000000;
29622305Sstevel 				}
29632305Sstevel 				break;
29642305Sstevel 			case PCIC_TI_PCI1031:
29652305Sstevel 			case PCIC_TI_PCI1131:
29662305Sstevel 			case PCIC_TI_PCI1250:
29672305Sstevel 			case PCIC_TI_PCI1225:
29682305Sstevel 			case PCIC_TI_PCI1221:
29692305Sstevel 			case PCIC_SMC_34C90:
29702305Sstevel 			case PCIC_CL_PD6832:
29712305Sstevel 			case PCIC_RICOH_RL5C466:
29722305Sstevel 			case PCIC_TI_PCI1410:
29732305Sstevel 			case PCIC_ENE_1410:
29742305Sstevel 			case PCIC_TI_PCI1510:
29752305Sstevel 			case PCIC_TI_PCI1520:
29762305Sstevel 			case PCIC_O2_OZ6912:
29772305Sstevel 			case PCIC_TI_PCI1420:
29782305Sstevel 			case PCIC_ENE_1420:
29792305Sstevel 			case PCIC_TI_VENDOR:
29802305Sstevel 			case PCIC_TOSHIBA_TOPIC100:
29812305Sstevel 			case PCIC_TOSHIBA_TOPIC95:
29822305Sstevel 			case PCIC_TOSHIBA_VENDOR:
29832305Sstevel 			case PCIC_RICOH_VENDOR:
29842305Sstevel 			case PCIC_O2MICRO_VENDOR:
29852305Sstevel 				pcic_putb(pcic, socket,
2986*7656SSherry.Moore@Sun.COM 				    PCIC_YENTA_MEM_PAGE + win,
2987*7656SSherry.Moore@Sun.COM 				    SYSMEM_EXT(base));
29882305Sstevel 				break;
29892305Sstevel 			default:
29902305Sstevel 				cmn_err(CE_NOTE, "pcic_set_window: unknown "
2991*7656SSherry.Moore@Sun.COM 				    "cardbus vendor:0x%X\n",
2992*7656SSherry.Moore@Sun.COM 				    pcic->pc_type);
29932305Sstevel 				pcic_putb(pcic, socket,
2994*7656SSherry.Moore@Sun.COM 				    PCIC_YENTA_MEM_PAGE + win,
2995*7656SSherry.Moore@Sun.COM 				    SYSMEM_EXT(base));
29962305Sstevel 
29972305Sstevel 				break;
29982305Sstevel 			} /* switch */
29992305Sstevel 
30002305Sstevel 			/*
30012305Sstevel 			 * specify the length of the mapped range
30022305Sstevel 			 * we convert to pages (rounding up) so that
30032305Sstevel 			 * the hardware gets the right thing
30042305Sstevel 			 */
30052305Sstevel 			pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE;
30062305Sstevel 
30072305Sstevel 			/*
30082305Sstevel 			 * Setup this window's timing.
30092305Sstevel 			 */
30102305Sstevel 			switch (pcic->pc_type) {
30112305Sstevel 			case PCIC_CL_PD6729:
30122305Sstevel 			case PCIC_CL_PD6730:
30132305Sstevel 			case PCIC_CL_PD6710:
30142305Sstevel 			case PCIC_CL_PD6722:
30152305Sstevel 				wspeed = SYSMEM_CLTIMER_SET_0;
30162305Sstevel 				pcic_set_cdtimers(pcic, socket,
3017*7656SSherry.Moore@Sun.COM 				    window->speed,
3018*7656SSherry.Moore@Sun.COM 				    wspeed);
30192305Sstevel 				break;
30202305Sstevel 
30212305Sstevel 			case PCIC_INTEL_i82092:
30222305Sstevel 			default:
30232305Sstevel 				wspeed = pcic_calc_speed(pcic, window->speed);
30242305Sstevel 				break;
30252305Sstevel 			} /* switch */
30262305Sstevel 
30272305Sstevel #if defined(PCIC_DEBUG)
30282305Sstevel 			if (pcic_debug)
30292305Sstevel 				cmn_err(CE_CONT,
3030*7656SSherry.Moore@Sun.COM 				    "\twindow %d speed bits = %x for "
3031*7656SSherry.Moore@Sun.COM 				    "%dns\n",
3032*7656SSherry.Moore@Sun.COM 				    win, (unsigned)wspeed, window->speed);
30332305Sstevel #endif
30342305Sstevel 
30352305Sstevel 			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select,
3036*7656SSherry.Moore@Sun.COM 			    SYSMEM_LOW(base +
3037*7656SSherry.Moore@Sun.COM 			    (pages * PCIC_PAGE)-1));
30382305Sstevel 
30392305Sstevel 			wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1);
30402305Sstevel 			pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select,
3041*7656SSherry.Moore@Sun.COM 			    wspeed);
30422305Sstevel 
30432305Sstevel 			/*
30442305Sstevel 			 * now map the card's memory pages - we start with page
30452305Sstevel 			 * 0
30462305Sstevel 			 * we also default to AM -- set page might change it
30472305Sstevel 			 */
30482305Sstevel 			base = memp->pcw_base;
30492305Sstevel 			pcic_putb(pcic, socket,
3050*7656SSherry.Moore@Sun.COM 			    PCIC_CARDMEM_0_LOW + select,
3051*7656SSherry.Moore@Sun.COM 			    CARDMEM_LOW(0 - (uint32_t)base));
30522305Sstevel 
30532305Sstevel 			pcic_putb(pcic, socket,
3054*7656SSherry.Moore@Sun.COM 			    PCIC_CARDMEM_0_HI + select,
3055*7656SSherry.Moore@Sun.COM 			    CARDMEM_HIGH(0 - (uint32_t)base) |
3056*7656SSherry.Moore@Sun.COM 			    CARDMEM_REG_ACTIVE);
30572305Sstevel 
30582305Sstevel 			/*
30592305Sstevel 			 * enable the window even though redundant
30602305Sstevel 			 * and SetPage may do it again.
30612305Sstevel 			 */
30622305Sstevel 			select = pcic_getb(pcic, socket,
3063*7656SSherry.Moore@Sun.COM 			    PCIC_MAPPING_ENABLE);
30642305Sstevel 			select |= SYSMEM_WINDOW(win);
30652305Sstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30662305Sstevel 			memp->pcw_offset = 0;
30672305Sstevel 			memp->pcw_status |= PCW_ENABLED;
30682305Sstevel 		} else {
30692305Sstevel 			/*
30702305Sstevel 			 * not only do we unmap the memory, the
30712305Sstevel 			 * window has been turned off.
30722305Sstevel 			 */
30732305Sstevel 			if (which && memp->pcw_status & PCW_MAPPED) {
30742305Sstevel 				ddi_regs_map_free(&memp->pcw_handle);
30752305Sstevel 				res.ra_addr_lo = memp->pcw_base;
30762305Sstevel 				res.ra_len = memp->pcw_len;
30773664Srw148561 				(void) pcmcia_free_mem(memp->res_dip, &res);
30782305Sstevel 				memp->pcw_hostmem = NULL;
30792305Sstevel 				memp->pcw_status &= ~PCW_MAPPED;
30802305Sstevel 			}
30812305Sstevel 
30822305Sstevel 			/* disable current mapping */
30832305Sstevel 			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
30842305Sstevel 			select &= ~SYSMEM_WINDOW(win);
30852305Sstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30862305Sstevel 			memp->pcw_status &= ~PCW_ENABLED;
30872305Sstevel 		}
30882305Sstevel 		memp->pcw_len = window->WindowSize;
30892305Sstevel 		window->handle = memp->pcw_handle;
30902305Sstevel #if defined(PCIC_DEBUG)
30912305Sstevel 		if (pcic_debug)
30922305Sstevel 			xxdmp_all_regs(pcic, window->socket, -1);
30932305Sstevel #endif
30942305Sstevel 	} else {
30952305Sstevel 		/*
30962305Sstevel 		 * This is a request for an IO window
30972305Sstevel 		 */
30982305Sstevel 		int win, tmp;
30992305Sstevel 		pcs_iowin_t *winp;
31002305Sstevel 				/* I/O windows */
31012305Sstevel #if defined(PCIC_DEBUG)
31022305Sstevel 		if (pcic_debug)
31032305Sstevel 			cmn_err(CE_CONT, "\twindow type is I/O\n");
31042305Sstevel #endif
31052305Sstevel 
31062305Sstevel 		/* only windows 0 and 1 can do I/O */
31072305Sstevel 		win = window->window % PCIC_NUMWINSOCK;
31082305Sstevel 		tmp = window->window / PCIC_NUMWINSOCK;
31092305Sstevel 
31102305Sstevel 		if (win >= PCIC_IOWINDOWS || tmp != window->socket) {
31112305Sstevel 			cmn_err(CE_WARN,
3112*7656SSherry.Moore@Sun.COM 			    "\twindow is out of range (%d)\n",
3113*7656SSherry.Moore@Sun.COM 			    window->window);
31142305Sstevel 			return (BAD_WINDOW);
31152305Sstevel 		}
31162305Sstevel 
31172305Sstevel 		mutex_enter(&pcic->pc_lock); /* protect the registers */
31182305Sstevel 
31192305Sstevel 		winp = &sockp->pcs_windows[win].io;
31202305Sstevel 		winp->pcw_speed = window->speed;
31212305Sstevel 		if (window->WindowSize != 1 && window->WindowSize & 1) {
31222305Sstevel 			/* we don't want an odd-size window */
31232305Sstevel 			window->WindowSize++;
31242305Sstevel 		}
31252305Sstevel 		winp->pcw_len = window->WindowSize;
31262305Sstevel 
31272305Sstevel 		if (window->state & WS_ENABLED) {
31282305Sstevel 			if (winp->pcw_status & PCW_MAPPED) {
31292305Sstevel 				ddi_regs_map_free(&winp->pcw_handle);
31302305Sstevel 				res.ra_addr_lo = winp->pcw_base;
31312305Sstevel 				res.ra_len = winp->pcw_len;
31323664Srw148561 				(void) pcmcia_free_io(winp->res_dip, &res);
31332305Sstevel 				winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
31342305Sstevel 			}
31352305Sstevel 
31362305Sstevel 			/*
31372305Sstevel 			 * if the I/O address wasn't allocated, allocate
31382305Sstevel 			 *	it now. If it was allocated, it better
31392305Sstevel 			 *	be free to use.
31402305Sstevel 			 * The winp->pcw_offset value is set and used
31412305Sstevel 			 *	later on if the particular adapter
31422305Sstevel 			 *	that we're running on has the ability
31432305Sstevel 			 *	to translate IO accesses to the card
31442305Sstevel 			 *	(such as some adapters  in the Cirrus
31452305Sstevel 			 *	Logic family).
31462305Sstevel 			 */
31472305Sstevel 			winp->pcw_offset = 0;
31482305Sstevel 
31492305Sstevel 			/*
31502305Sstevel 			 * Setup the request parameters for the
31512305Sstevel 			 *	requested base and length. If
31522305Sstevel 			 *	we're on an adapter that has
31532305Sstevel 			 *	IO window offset registers, then
31542305Sstevel 			 *	we don't need a specific base
31552305Sstevel 			 *	address, just a length, and then
31562305Sstevel 			 *	we'll cause the correct IO address
31572305Sstevel 			 *	to be generated on the socket by
31582305Sstevel 			 *	setting up the IO window offset
31592305Sstevel 			 *	registers.
31602305Sstevel 			 * For adapters that support this capability, we
31612305Sstevel 			 *	always use the IO window offset registers,
31622305Sstevel 			 *	even if the passed base/length would be in
31632305Sstevel 			 *	range.
31642305Sstevel 			 */
31652305Sstevel 			base = window->base;
31662305Sstevel 			bzero(&req, sizeof (req));
31672305Sstevel 			req.ra_len = window->WindowSize;
31682305Sstevel 
31692305Sstevel 			req.ra_addr = (uint64_t)
3170*7656SSherry.Moore@Sun.COM 			    ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base);
31712305Sstevel 			req.ra_flags = (req.ra_addr) ?
3172*7656SSherry.Moore@Sun.COM 			    NDI_RA_ALLOC_SPECIFIED : 0;
31732305Sstevel 
31742305Sstevel 			req.ra_flags |= NDI_RA_ALIGN_SIZE;
31752305Sstevel 			/* need to rethink this */
31762305Sstevel 			req.ra_boundbase = pcic->pc_iobase;
31772305Sstevel 			req.ra_boundlen = pcic->pc_iobound;
31782305Sstevel 			req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
31792305Sstevel 
31802305Sstevel #if defined(PCIC_DEBUG)
3181*7656SSherry.Moore@Sun.COM 				pcic_err(dip, 8,
3182*7656SSherry.Moore@Sun.COM 				    "\tlen 0x%"PRIx64" addr 0x%"PRIx64
3183*7656SSherry.Moore@Sun.COM 				    "bbase 0x%"PRIx64
3184*7656SSherry.Moore@Sun.COM 				    "blen 0x%"PRIx64" flags 0x%x algn 0x%"
3185*7656SSherry.Moore@Sun.COM 				    PRIx64"\n",
3186*7656SSherry.Moore@Sun.COM 				    req.ra_len, (uint64_t)req.ra_addr,
3187*7656SSherry.Moore@Sun.COM 				    req.ra_boundbase,
3188*7656SSherry.Moore@Sun.COM 				    req.ra_boundlen, req.ra_flags,
3189*7656SSherry.Moore@Sun.COM 				    req.ra_align_mask);
31902305Sstevel #endif
31912305Sstevel 
31922305Sstevel 			/*
31932305Sstevel 			 * Try to allocate the space. If we fail this,
31942305Sstevel 			 *	return the appropriate error depending
31952305Sstevel 			 *	on whether the caller specified a
31962305Sstevel 			 *	specific base address or not.
31972305Sstevel 			 */
31983664Srw148561 			if (pcmcia_alloc_io(dip, &req, &res,
3199*7656SSherry.Moore@Sun.COM 			    &winp->res_dip) == DDI_FAILURE) {
32002305Sstevel 				winp->pcw_status &= ~PCW_ENABLED;
32012305Sstevel 				mutex_exit(&pcic->pc_lock);
32022305Sstevel 				cmn_err(CE_WARN, "Failed to alloc I/O:\n"
3203*7656SSherry.Moore@Sun.COM 				    "\tlen 0x%" PRIx64 " addr 0x%" PRIx64
3204*7656SSherry.Moore@Sun.COM 				    "bbase 0x%" PRIx64
3205*7656SSherry.Moore@Sun.COM 				    "blen 0x%" PRIx64 "flags 0x%x"
3206*7656SSherry.Moore@Sun.COM 				    "algn 0x%" PRIx64 "\n",
3207*7656SSherry.Moore@Sun.COM 				    req.ra_len, req.ra_addr,
3208*7656SSherry.Moore@Sun.COM 				    req.ra_boundbase,
3209*7656SSherry.Moore@Sun.COM 				    req.ra_boundlen, req.ra_flags,
3210*7656SSherry.Moore@Sun.COM 				    req.ra_align_mask);
32112305Sstevel 
32122305Sstevel 				return (base?BAD_BASE:BAD_SIZE);
32132305Sstevel 			} /* pcmcia_alloc_io */
32142305Sstevel 
32152305Sstevel 			/*
32162305Sstevel 			 * Don't change the original base. Either we use
32172305Sstevel 			 * the offset registers below (PCF_IO_REMAP is set)
32182305Sstevel 			 * or it was allocated correctly anyway.
32192305Sstevel 			 */
32202305Sstevel 			winp->pcw_base = res.ra_addr_lo;
32212305Sstevel 
32222305Sstevel #if defined(PCIC_DEBUG)
3223*7656SSherry.Moore@Sun.COM 				pcic_err(dip, 8,
32242305Sstevel 				    "\tsetwindow: new base=%x orig base 0x%x\n",
32252305Sstevel 				    (unsigned)winp->pcw_base, base);
32262305Sstevel #endif
32272305Sstevel 
32282305Sstevel 			if ((which = pcmcia_map_reg(pcic->dip,
3229*7656SSherry.Moore@Sun.COM 			    window->child,
3230*7656SSherry.Moore@Sun.COM 			    &res,
3231*7656SSherry.Moore@Sun.COM 			    (uint32_t)(window->state &
3232*7656SSherry.Moore@Sun.COM 			    0xffff) |
3233*7656SSherry.Moore@Sun.COM 			    (window->socket << 16),
3234*7656SSherry.Moore@Sun.COM 			    (caddr_t *)&winp->pcw_hostmem,
3235*7656SSherry.Moore@Sun.COM 			    &winp->pcw_handle,
3236*7656SSherry.Moore@Sun.COM 			    &window->attr,
3237*7656SSherry.Moore@Sun.COM 			    base)) != DDI_SUCCESS) {
3238*7656SSherry.Moore@Sun.COM 
3239*7656SSherry.Moore@Sun.COM 				cmn_err(CE_WARN, "pcmcia_map_reg()"
3240*7656SSherry.Moore@Sun.COM 				    "failed\n");
3241*7656SSherry.Moore@Sun.COM 
3242*7656SSherry.Moore@Sun.COM 					res.ra_addr_lo = winp->pcw_base;
3243*7656SSherry.Moore@Sun.COM 					res.ra_len = winp->pcw_len;
3244*7656SSherry.Moore@Sun.COM 					(void) pcmcia_free_io(winp->res_dip,
3245*7656SSherry.Moore@Sun.COM 					    &res);
3246*7656SSherry.Moore@Sun.COM 
3247*7656SSherry.Moore@Sun.COM 					mutex_exit(&pcic->pc_lock);
3248*7656SSherry.Moore@Sun.COM 					return (BAD_WINDOW);
32492305Sstevel 			}
32502305Sstevel 
32512305Sstevel 			window->handle = winp->pcw_handle;
32522305Sstevel 			winp->pcw_status |= PCW_MAPPED;
32532305Sstevel 
32542305Sstevel 			/* find the register set offset */
32552305Sstevel 			select = win * PCIC_IO_OFFSET;
32562305Sstevel 
32572305Sstevel #if defined(PCIC_DEBUG)
32582305Sstevel 			if (pcic_debug) {
32592305Sstevel 				cmn_err(CE_CONT,
3260*7656SSherry.Moore@Sun.COM 				    "\tenable: window=%d, select=%x, "
3261*7656SSherry.Moore@Sun.COM 				    "base=%x, handle=%p\n",
3262*7656SSherry.Moore@Sun.COM 				    win, select,
3263*7656SSherry.Moore@Sun.COM 				    (unsigned)window->base,
3264*7656SSherry.Moore@Sun.COM 				    (void *)window->handle);
32652305Sstevel 			}
32662305Sstevel #endif
32672305Sstevel 			/*
32682305Sstevel 			 * at this point, the register window indicator has
32692305Sstevel 			 * been converted to be an offset from the first
32702305Sstevel 			 * set of registers that are used for programming
32712305Sstevel 			 * the window mapping and the offset used to select
32722305Sstevel 			 * the correct set of registers to access the
32732305Sstevel 			 * specified socket.  This allows basing everything
32742305Sstevel 			 * off the _0 window
32752305Sstevel 			 */
32762305Sstevel 
32772305Sstevel 			/* map the I/O base in */
32782305Sstevel 			pcic_putb(pcic, socket,
3279*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STARTLOW + select,
3280*7656SSherry.Moore@Sun.COM 			    LOW_BYTE((uint32_t)winp->pcw_base));
32812305Sstevel 			pcic_putb(pcic, socket,
3282*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STARTHI + select,
3283*7656SSherry.Moore@Sun.COM 			    HIGH_BYTE((uint32_t)winp->pcw_base));
32842305Sstevel 
32852305Sstevel 			pcic_putb(pcic, socket,
3286*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STOPLOW + select,
3287*7656SSherry.Moore@Sun.COM 			    LOW_BYTE((uint32_t)winp->pcw_base +
3288*7656SSherry.Moore@Sun.COM 			    window->WindowSize - 1));
32892305Sstevel 			pcic_putb(pcic, socket,
3290*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STOPHI + select,
3291*7656SSherry.Moore@Sun.COM 			    HIGH_BYTE((uint32_t)winp->pcw_base +
3292*7656SSherry.Moore@Sun.COM 			    window->WindowSize - 1));
32932305Sstevel 
32942305Sstevel 			/*
32952305Sstevel 			 * We've got the requested IO space, now see if we
32962305Sstevel 			 *	need to adjust the IO window offset registers
32972305Sstevel 			 *	so that the correct IO address is generated
32982305Sstevel 			 *	at the socket. If this window doesn't have
32992305Sstevel 			 *	this capability, then we're all done setting
33002305Sstevel 			 *	up the IO resources.
33012305Sstevel 			 */
33022305Sstevel 			if (pcic->pc_flags & PCF_IO_REMAP) {
33032305Sstevel 
33042305Sstevel 
33052305Sstevel 				/*
33062305Sstevel 				 * Note that only 16 bits are used to program
33072305Sstevel 				 * the registers but leave 32 bits on pcw_offset
33082305Sstevel 				 * so that we can generate the original base
33092305Sstevel 				 * in get_window()
33102305Sstevel 				 */
33112305Sstevel 				winp->pcw_offset = (base - winp->pcw_base);
33122305Sstevel 
33132305Sstevel 				pcic_putb(pcic, socket,
3314*7656SSherry.Moore@Sun.COM 				    PCIC_IO_OFFSET_LOW +
3315*7656SSherry.Moore@Sun.COM 				    (win * PCIC_IO_OFFSET_OFFSET),
3316*7656SSherry.Moore@Sun.COM 				    winp->pcw_offset & 0x0ff);
33172305Sstevel 				pcic_putb(pcic, socket,
3318*7656SSherry.Moore@Sun.COM 				    PCIC_IO_OFFSET_HI +
3319*7656SSherry.Moore@Sun.COM 				    (win * PCIC_IO_OFFSET_OFFSET),
3320*7656SSherry.Moore@Sun.COM 				    (winp->pcw_offset >> 8) & 0x0ff);
33212305Sstevel 
33222305Sstevel 			} /* PCF_IO_REMAP */
33232305Sstevel 
33242305Sstevel 			/* now get the other details (size, etc) right */
33252305Sstevel 
33262305Sstevel 			/*
33272305Sstevel 			 * Set the data size control bits here. Most of the
33282305Sstevel 			 *	adapters will ignore IOMEM_16BIT when
33292305Sstevel 			 *	IOMEM_IOCS16 is set, except for the Intel
33302305Sstevel 			 *	82092, which only pays attention to the
33312305Sstevel 			 *	IOMEM_16BIT bit. Sigh... Intel can't even
33322305Sstevel 			 *	make a proper clone of their own chip.
33332305Sstevel 			 * The 82092 also apparently can't set the timing
33342305Sstevel 			 *	of I/O windows.
33352305Sstevel 			 */
33362305Sstevel 			which = (window->state & WS_16BIT) ?
3337*7656SSherry.Moore@Sun.COM 			    (IOMEM_16BIT | IOMEM_IOCS16) : 0;
33382305Sstevel 
33392305Sstevel 			switch (pcic->pc_type) {
33402305Sstevel 			case PCIC_CL_PD6729:
33412305Sstevel 			case PCIC_CL_PD6730:
33422305Sstevel 			case PCIC_CL_PD6710:
33432305Sstevel 			case PCIC_CL_PD6722:
33442305Sstevel 			case PCIC_CL_PD6832:
33452305Sstevel 				/*
33462305Sstevel 				 * Select Timer Set 1 - this will take
33472305Sstevel 				 *	effect when the PCIC_IO_CONTROL
33482305Sstevel 				 *	register is written to later on;
33492305Sstevel 				 *	the call to pcic_set_cdtimers
33502305Sstevel 				 *	just sets up the timer itself.
33512305Sstevel 				 */
33522305Sstevel 				which |= IOMEM_CLTIMER_SET_1;
33532305Sstevel 				pcic_set_cdtimers(pcic, socket,
3354*7656SSherry.Moore@Sun.COM 				    window->speed,
3355*7656SSherry.Moore@Sun.COM 				    IOMEM_CLTIMER_SET_1);
33562305Sstevel 				which |= IOMEM_IOCS16;
33572305Sstevel 				break;
33582305Sstevel 			case PCIC_TI_PCI1031:
33592305Sstevel 
33602305Sstevel 				if (window->state & WS_16BIT)
3361*7656SSherry.Moore@Sun.COM 					which |= IOMEM_WAIT16;
33622305Sstevel 
33632305Sstevel 				break;
33642305Sstevel 			case PCIC_TI_PCI1130:
33652305Sstevel 
33662305Sstevel 				if (window->state & WS_16BIT)
3367*7656SSherry.Moore@Sun.COM 					which |= IOMEM_WAIT16;
33682305Sstevel 
33692305Sstevel 				break;
33702305Sstevel 			case PCIC_INTEL_i82092:
33712305Sstevel 				break;
33722305Sstevel 			default:
33732305Sstevel 				if (window->speed >
3374*7656SSherry.Moore@Sun.COM 				    mhztons(pcic->bus_speed) * 3)
3375*7656SSherry.Moore@Sun.COM 					which |= IOMEM_WAIT16;
33762305Sstevel #ifdef notdef
33772305Sstevel 				if (window->speed <
3378*7656SSherry.Moore@Sun.COM 				    mhztons(pcic->bus_speed) * 6)
3379*7656SSherry.Moore@Sun.COM 					which |= IOMEM_ZERO_WAIT;
33802305Sstevel #endif
33812305Sstevel 				break;
33822305Sstevel 			} /* switch (pc_type) */
33832305Sstevel 
33842305Sstevel 			/*
33852305Sstevel 			 * Setup the data width and timing
33862305Sstevel 			 */
33872305Sstevel 			select = pcic_getb(pcic, socket, PCIC_IO_CONTROL);
33882305Sstevel 			select &= ~(PCIC_IO_WIN_MASK << (win * 4));
33892305Sstevel 			select |= IOMEM_SETWIN(win, which);
33902305Sstevel 			pcic_putb(pcic, socket, PCIC_IO_CONTROL, select);
33912305Sstevel 
33922305Sstevel 			/*
33932305Sstevel 			 * Enable the IO window
33942305Sstevel 			 */
33952305Sstevel 			select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
33962305Sstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
3397*7656SSherry.Moore@Sun.COM 			    select | IOMEM_WINDOW(win));
33982305Sstevel 
33992305Sstevel 			winp->pcw_status |= PCW_ENABLED;
34002305Sstevel 
34012305Sstevel #if defined(PCIC_DEBUG)
34022305Sstevel 			if (pcic_debug) {
34032305Sstevel 				cmn_err(CE_CONT,
3404*7656SSherry.Moore@Sun.COM 				    "\twhich = %x, select = %x (%x)\n",
3405*7656SSherry.Moore@Sun.COM 				    which, select,
3406*7656SSherry.Moore@Sun.COM 				    IOMEM_SETWIN(win, which));
34072305Sstevel 				xxdmp_all_regs(pcic, window->socket * 0x40, 24);
34082305Sstevel 			}
34092305Sstevel #endif
34102305Sstevel 		} else {
34112305Sstevel 			/*
34122305Sstevel 			 * not only do we unmap the IO space, the
34132305Sstevel 			 * window has been turned off.
34142305Sstevel 			 */
34152305Sstevel 			if (winp->pcw_status & PCW_MAPPED) {
34162305Sstevel 				ddi_regs_map_free(&winp->pcw_handle);
34172305Sstevel 				res.ra_addr_lo = winp->pcw_base;
34182305Sstevel 				res.ra_len = winp->pcw_len;
34193664Srw148561 				(void) pcmcia_free_io(winp->res_dip, &res);
34202305Sstevel 				winp->pcw_status &= ~PCW_MAPPED;
34212305Sstevel 			}
34222305Sstevel 
34232305Sstevel 			/* disable current mapping */
34242305Sstevel 			select = pcic_getb(pcic, socket,
3425*7656SSherry.Moore@Sun.COM 			    PCIC_MAPPING_ENABLE);
34262305Sstevel 			pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
3427*7656SSherry.Moore@Sun.COM 			    select &= ~IOMEM_WINDOW(win));
34282305Sstevel 			winp->pcw_status &= ~PCW_ENABLED;
34292305Sstevel 
34302305Sstevel 			winp->pcw_base = 0;
34312305Sstevel 			winp->pcw_len = 0;
34322305Sstevel 			winp->pcw_offset = 0;
34332305Sstevel 			window->base = 0;
34342305Sstevel 			/* now make sure we don't accidentally re-enable */
34352305Sstevel 			/* find the register set offset */
34362305Sstevel 			select = win * PCIC_IO_OFFSET;
34372305Sstevel 			pcic_putb(pcic, socket,
3438*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STARTLOW + select, 0);
34392305Sstevel 			pcic_putb(pcic, socket,
3440*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STARTHI + select, 0);
34412305Sstevel 			pcic_putb(pcic, socket,
3442*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STOPLOW + select, 0);
34432305Sstevel 			pcic_putb(pcic, socket,
3444*7656SSherry.Moore@Sun.COM 			    PCIC_IO_ADDR_0_STOPHI + select, 0);
34452305Sstevel 		}
34462305Sstevel 	}
34472305Sstevel 	mutex_exit(&pcic->pc_lock);
34482305Sstevel 
34492305Sstevel 	return (SUCCESS);
34502305Sstevel }
34512305Sstevel 
34522305Sstevel /*
34532305Sstevel  * pcic_card_state()
34542305Sstevel  *	compute the instantaneous Card State information
34552305Sstevel  */
34562305Sstevel static int
34572305Sstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp)
34582305Sstevel {
34592305Sstevel 	int value, result;
34602305Sstevel #if defined(PCIC_DEBUG)
34612305Sstevel 	int orig_value;
34622305Sstevel #endif
34632305Sstevel 
34642305Sstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
34652305Sstevel 
34662305Sstevel 	value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS);
34672305Sstevel 
34682305Sstevel #if defined(PCIC_DEBUG)
34692305Sstevel 	orig_value = value;
34702305Sstevel 	if (pcic_debug >= 8)
34712305Sstevel 		cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n",
3472*7656SSherry.Moore@Sun.COM 		    (void *)sockp,
3473*7656SSherry.Moore@Sun.COM 		    value,
3474*7656SSherry.Moore@Sun.COM 		    "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
3475*7656SSherry.Moore@Sun.COM 		    sockp->pcs_socket);
34762305Sstevel #endif
34772305Sstevel 	/*
34782305Sstevel 	 * Lie to socket services if we are not ready.
34792305Sstevel 	 * This is when we are starting up or during debounce timeouts
34802305Sstevel 	 * or if the card is a cardbus card.
34812305Sstevel 	 */
34822305Sstevel 	if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) &&
34832305Sstevel 	    !sockp->pcs_debounce_id &&
34842305Sstevel 	    (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) {
34852305Sstevel 		result = SBM_CD;
34862305Sstevel 
34872305Sstevel 		if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON))
34882305Sstevel 			result |= SBM_WP;
34892305Sstevel 		if (value & PCIC_POWER_ON) {
34902305Sstevel 			if (value & PCIC_READY)
34912305Sstevel 				result |= SBM_RDYBSY;
34922305Sstevel 			value = (~value) & (PCIC_BVD1 | PCIC_BVD2);
34932305Sstevel 			if (value & PCIC_BVD1)
34942305Sstevel 				result |= SBM_BVD1;
34952305Sstevel 			if (value & PCIC_BVD2)
34962305Sstevel 				result |= SBM_BVD2;
34972305Sstevel 		}
34982305Sstevel 	} else
34992305Sstevel 		result = 0;
35002305Sstevel 
35012305Sstevel 	mutex_exit(&pcic->pc_lock);
35022305Sstevel 
35032305Sstevel #if defined(PCIC_DEBUG)
35042305Sstevel 	pcic_err(pcic->dip, 8,
35052305Sstevel 	    "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n",
35062305Sstevel 	    (void *) sockp, orig_value,
35072305Sstevel 	    "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35082305Sstevel 	    sockp->pcs_socket, result);
35092305Sstevel #endif
35102305Sstevel 
35112305Sstevel 	return (result);
35122305Sstevel }
35132305Sstevel 
35142305Sstevel /*
35152305Sstevel  * pcic_set_page()
35162305Sstevel  *	SocketServices SetPage function
35172305Sstevel  *	set the page of PC Card memory that should be in the mapped
35182305Sstevel  *	window
35192305Sstevel  */
35202305Sstevel /*ARGSUSED*/
35212305Sstevel static int
35222305Sstevel pcic_set_page(dev_info_t *dip, set_page_t *page)
35232305Sstevel {
35242305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
35252305Sstevel 	pcicdev_t *pcic = anp->an_private;
35262305Sstevel 	int select;
35272305Sstevel 	int which, socket, window;
35282305Sstevel 	uint32_t base;
35292305Sstevel 	pcs_memwin_t *memp;
35302305Sstevel 
35312305Sstevel 	/* get real socket/window numbers */
35322305Sstevel 	window = page->window % PCIC_NUMWINSOCK;
35332305Sstevel 	socket = page->window / PCIC_NUMWINSOCK;
35342305Sstevel 
35352305Sstevel #if defined(PCIC_DEBUG)
35362305Sstevel 	if (pcic_debug) {
35372305Sstevel 		cmn_err(CE_CONT,
3538*7656SSherry.Moore@Sun.COM 		    "pcic_set_page: window=%d, socket=%d, page=%d\n",
3539*7656SSherry.Moore@Sun.COM 		    window, socket, page->page);
35402305Sstevel 	}
35412305Sstevel #endif
35422305Sstevel 	/* only windows 2-6 work on memory */
35432305Sstevel 	if (window < PCIC_IOWINDOWS)
35442305Sstevel 		return (BAD_WINDOW);
35452305Sstevel 
35462305Sstevel 	/* only one page supported (but any size) */
35472305Sstevel 	if (page->page != 0)
35482305Sstevel 		return (BAD_PAGE);
35492305Sstevel 
35502305Sstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
35512305Sstevel 
35522305Sstevel 	memp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
35532305Sstevel 	window -= PCIC_IOWINDOWS;
35542305Sstevel 
35552305Sstevel #if defined(PCIC_DEBUG)
35562305Sstevel 	if (pcic_debug)
35572305Sstevel 		cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n",
3558*7656SSherry.Moore@Sun.COM 		    (uint32_t)memp->pcw_base,
3559*7656SSherry.Moore@Sun.COM 		    (void *)memp->pcw_hostmem, memp->pcw_len);
35602305Sstevel #endif
35612305Sstevel 
35622305Sstevel 	/* window must be enabled */
35632305Sstevel 	if (!(memp->pcw_status & PCW_ENABLED))
35642305Sstevel 		return (BAD_ATTRIBUTE);
35652305Sstevel 
35662305Sstevel 	/* find the register set offset */
35672305Sstevel 	select = window * PCIC_MEM_1_OFFSET;
35682305Sstevel #if defined(PCIC_DEBUG)
35692305Sstevel 	if (pcic_debug)
35702305Sstevel 		cmn_err(CE_CONT, "\tselect=%x\n", select);
35712305Sstevel #endif
35722305Sstevel 
35732305Sstevel 	/*
35742305Sstevel 	 * now map the card's memory pages - we start with page 0
35752305Sstevel 	 */
35762305Sstevel 
35772305Sstevel 	which = 0;		/* assume simple case */
35782305Sstevel 	if (page->state & PS_ATTRIBUTE) {
35792305Sstevel 		which |= CARDMEM_REG_ACTIVE;
35802305Sstevel 		memp->pcw_status |= PCW_ATTRIBUTE;
35812305Sstevel 	} else {
35822305Sstevel 		memp->pcw_status &= ~PCW_ATTRIBUTE;
35832305Sstevel 	}
35842305Sstevel 
35852305Sstevel 	/*
35862305Sstevel 	 * if caller says Write Protect, enforce it.
35872305Sstevel 	 */
35882305Sstevel 	if (page->state & PS_WP) {
35892305Sstevel 		which |= CARDMEM_WRITE_PROTECT;
35902305Sstevel 		memp->pcw_status |= PCW_WP;
35912305Sstevel 	} else {
35922305Sstevel 		memp->pcw_status &= ~PCW_WP;
35932305Sstevel 	}
35942305Sstevel #if defined(PCIC_DEBUG)
35952305Sstevel 	if (pcic_debug) {
35962305Sstevel 		cmn_err(CE_CONT, "\tmemory type = %s\n",
3597*7656SSherry.Moore@Sun.COM 		    (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common");
35982305Sstevel 		if (which & CARDMEM_WRITE_PROTECT)
35992305Sstevel 			cmn_err(CE_CONT, "\twrite protect\n");
36002305Sstevel 		cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n",
3601*7656SSherry.Moore@Sun.COM 		    (unsigned)page->offset,
3602*7656SSherry.Moore@Sun.COM 		    (unsigned)memp->pcw_base,
3603*7656SSherry.Moore@Sun.COM 		    (int)page->offset - (int)memp->pcw_base & 0xffffff);
36042305Sstevel 	}
36052305Sstevel #endif
36062305Sstevel 	/* address computation based on 64MB range and not larger */
36072305Sstevel 	base = (uint32_t)memp->pcw_base & 0x3ffffff;
36082305Sstevel 	pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select,
36092305Sstevel 	    CARDMEM_LOW((int)page->offset - (int)base));
36102305Sstevel 	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select);
36112305Sstevel 	pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select,
36122305Sstevel 	    CARDMEM_HIGH((int)page->offset - base) | which);
36132305Sstevel 	(void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select);
36142305Sstevel 
36152305Sstevel 	/*
36162305Sstevel 	 * while not really necessary, this just makes sure
36172305Sstevel 	 * nothing turned the window off behind our backs
36182305Sstevel 	 */
36192305Sstevel 	which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36202305Sstevel 	which |= SYSMEM_WINDOW(window);
36212305Sstevel 	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which);
36222305Sstevel 	(void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36232305Sstevel 
36242305Sstevel 	memp->pcw_offset = (off_t)page->offset;
36252305Sstevel 
36262305Sstevel #if defined(PCIC_DEBUG)
36272305Sstevel 	if (pcic_debug) {
36282305Sstevel 		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
3629*7656SSherry.Moore@Sun.COM 		    (void *)memp->pcw_hostmem,
3630*7656SSherry.Moore@Sun.COM 		    (uint32_t)*memp->pcw_hostmem);
36312305Sstevel 
36322305Sstevel 		xxdmp_all_regs(pcic, socket, -1);
36332305Sstevel 
36342305Sstevel 		cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
3635*7656SSherry.Moore@Sun.COM 		    (void *)memp->pcw_hostmem,
3636*7656SSherry.Moore@Sun.COM 		    (uint32_t)*memp->pcw_hostmem);
36372305Sstevel 	}
36382305Sstevel #endif
36392305Sstevel 
36402305Sstevel 	if (which & PCW_ATTRIBUTE)
36412305Sstevel 		pcic_mswait(pcic, socket, 2);
36422305Sstevel 
36432305Sstevel 	mutex_exit(&pcic->pc_lock);
36442305Sstevel 
36452305Sstevel 	return (SUCCESS);
36462305Sstevel }
36472305Sstevel 
36482305Sstevel /*
36492305Sstevel  * pcic_set_vcc_level()
36502305Sstevel  *
36512305Sstevel  *	set voltage based on adapter information
36522305Sstevel  *
36532305Sstevel  *	this routine implements a limited solution for support of 3.3v cards.
36542305Sstevel  *	the general solution, which would fully support the pcmcia spec
36552305Sstevel  *	as far as allowing client drivers to request which voltage levels
36562305Sstevel  *	to be set, requires more framework support and driver changes - ess
36572305Sstevel  */
36582305Sstevel static int
36592305Sstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket)
36602305Sstevel {
36612305Sstevel 	uint32_t socket_present_state;
36622305Sstevel 
36632305Sstevel #if defined(PCIC_DEBUG)
36642305Sstevel 	if (pcic_debug) {
36652305Sstevel 		cmn_err(CE_CONT,
3666*7656SSherry.Moore@Sun.COM 		    "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n",
3667*7656SSherry.Moore@Sun.COM 		    (void *)pcic, socket->VccLevel);
36682305Sstevel 	}
36692305Sstevel #endif
36702305Sstevel 
36712305Sstevel 	/*
36722305Sstevel 	 * check VccLevel
36732305Sstevel 	 * if this is zero, power is being turned off
36742305Sstevel 	 * if it is non-zero, power is being turned on.
36752305Sstevel 	 */
36762305Sstevel 	if (socket->VccLevel == 0) {
36772305Sstevel 		return (0);
36782305Sstevel 	}
36792305Sstevel 
36802305Sstevel 	/*
36812305Sstevel 	 * range checking for sanity's sake
36822305Sstevel 	 */
36832305Sstevel 	if (socket->VccLevel >= pcic->pc_numpower) {
36842305Sstevel 		return (BAD_VCC);
36852305Sstevel 	}
36862305Sstevel 
36872305Sstevel 	switch (pcic->pc_io_type) {
36882305Sstevel 	/*
36892305Sstevel 	 * Yenta-compliant adapters have vcc info in the extended registers
36902305Sstevel 	 * Other adapters can be added as needed, but the 'default' case
36912305Sstevel 	 * has been left as it was previously so as not to break existing
36922305Sstevel 	 * adapters.
36932305Sstevel 	 */
36942305Sstevel 	case PCIC_IO_TYPE_YENTA:
36952305Sstevel 		/*
36962305Sstevel 		 * Here we ignore the VccLevel passed in and read the
36972305Sstevel 		 * card type from the adapter socket present state register
36982305Sstevel 		 */
36992305Sstevel 		socket_present_state =
3700*7656SSherry.Moore@Sun.COM 		    ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr +
3701*7656SSherry.Moore@Sun.COM 		    PCIC_PRESENT_STATE_REG));
37022305Sstevel #if defined(PCIC_DEBUG)
37032305Sstevel 		if (pcic_debug) {
37042305Sstevel 			cmn_err(CE_CONT,
3705*7656SSherry.Moore@Sun.COM 			    "socket present state = 0x%x\n",
3706*7656SSherry.Moore@Sun.COM 			    socket_present_state);
37072305Sstevel 		}
37082305Sstevel #endif
37092305Sstevel 		switch (socket_present_state & PCIC_VCC_MASK) {
37102305Sstevel 			case PCIC_VCC_3VCARD:
37112305Sstevel 				/* fall through */
37122305Sstevel 			case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD:
37132305Sstevel 				socket->VccLevel = PCIC_VCC_3VLEVEL;
37142305Sstevel 				return
37152305Sstevel 				    (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE);
37162305Sstevel 			case PCIC_VCC_5VCARD:
37172305Sstevel 				socket->VccLevel = PCIC_VCC_5VLEVEL;
37182305Sstevel 				return
37192305Sstevel 				    (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37202305Sstevel 			default:
37212305Sstevel 				/*
37222305Sstevel 				 * if no card is present, this can be the
37232305Sstevel 				 * case of a client making a SetSocket call
37242305Sstevel 				 * after card removal. In this case we return
37252305Sstevel 				 * the current power level
37262305Sstevel 				 */
37272305Sstevel 				return ((unsigned)ddi_get8(pcic->handle,
37282305Sstevel 				    pcic->ioaddr + CB_R2_OFFSET +
3729*7656SSherry.Moore@Sun.COM 				    PCIC_POWER_CONTROL));
37302305Sstevel 		}
37312305Sstevel 
37322305Sstevel 	default:
37332305Sstevel 
37342305Sstevel 		switch (socket->VccLevel) {
37352305Sstevel 		case PCIC_VCC_3VLEVEL:
37362305Sstevel 			return (BAD_VCC);
37372305Sstevel 		case PCIC_VCC_5VLEVEL:
37382305Sstevel 			/* enable Vcc */
37392305Sstevel 			return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37402305Sstevel 		default:
37412305Sstevel 			return (BAD_VCC);
37422305Sstevel 		}
37432305Sstevel 	}
37442305Sstevel }
37452305Sstevel 
37462305Sstevel 
37472305Sstevel /*
37482305Sstevel  * pcic_set_socket()
37492305Sstevel  *	Socket Services SetSocket call
37502305Sstevel  *	sets basic socket configuration
37512305Sstevel  */
37522305Sstevel static int
37532305Sstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket)
37542305Sstevel {
37552305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
37562305Sstevel 	pcicdev_t *pcic = anp->an_private;
37572305Sstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket];
37582305Sstevel 	int irq, interrupt, mirq;
37592305Sstevel 	int powerlevel = 0;
37602305Sstevel 	int ind, value, orig_pwrctl;
37612305Sstevel 
37622305Sstevel #if defined(PCIC_DEBUG)
37632305Sstevel 	if (pcic_debug) {
37642305Sstevel 		cmn_err(CE_CONT,
37652305Sstevel 		    "pcic_set_socket(dip=%p, socket=%d)"
37662305Sstevel 		    " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip,
37672305Sstevel 		    socket->socket, socket->VccLevel, socket->Vpp1Level,
37682305Sstevel 		    socket->Vpp2Level);
37692305Sstevel 	}
37702305Sstevel #endif
37712305Sstevel 	/*
37722305Sstevel 	 * check VccLevel, etc. before setting mutex
37732305Sstevel 	 * if this is zero, power is being turned off
37742305Sstevel 	 * if it is non-zero, power is being turned on.
37752305Sstevel 	 * the default case is to assume Vcc only.
37762305Sstevel 	 */
37772305Sstevel 
37782305Sstevel 	/* this appears to be very implementation specific */
37792305Sstevel 
37802305Sstevel 	if (socket->Vpp1Level != socket->Vpp2Level)
37812305Sstevel 		return (BAD_VPP);
37822305Sstevel 
37832305Sstevel 	if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) {
37842305Sstevel 		powerlevel = 0;
37852305Sstevel 		sockp->pcs_vcc = 0;
37862305Sstevel 		sockp->pcs_vpp1 = 0;
37872305Sstevel 		sockp->pcs_vpp2 = 0;
37882305Sstevel 	} else {
37892305Sstevel #if defined(PCIC_DEBUG)
37902305Sstevel 		pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n",
37912305Sstevel 		    socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level);
37922305Sstevel #endif
37932305Sstevel 		/* valid Vcc power level? */
37942305Sstevel 		if (socket->VccLevel >= pcic->pc_numpower)
37952305Sstevel 			return (BAD_VCC);
37962305Sstevel 
37972305Sstevel 		switch (pcic_power[socket->VccLevel].PowerLevel) {
37982305Sstevel 		case 33:	/* 3.3V */
37992305Sstevel 		case 60:	/* for bad CIS in Option GPRS card */
38002305Sstevel 			if (!(pcic->pc_flags & PCF_33VCAP)) {
38012305Sstevel 				cmn_err(CE_WARN,
38022305Sstevel 				    "%s%d: Bad Request for 3.3V "
38032305Sstevel 				    "(Controller incapable)\n",
38042305Sstevel 				    ddi_get_name(pcic->dip),
38052305Sstevel 				    ddi_get_instance(pcic->dip));
38062305Sstevel 				return (BAD_VCC);
38072305Sstevel 			}
38082305Sstevel 			/* FALLTHROUGH */
38092305Sstevel 		case 50:	/* 5V */
38102305Sstevel 			if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) &&
38112305Sstevel 			    pcic_getcb(pcic, CB_PRESENT_STATE) &
38122305Sstevel 			    CB_PS_33VCARD) {
38132305Sstevel 				/*
38142305Sstevel 				 * This is actually a 3.3V card.
38152305Sstevel 				 * Solaris Card Services
38162305Sstevel 				 * doesn't understand 3.3V
38172305Sstevel 				 * so we cheat and change
38182305Sstevel 				 * the setting to the one appropriate to 3.3V.
38192305Sstevel 				 * Note that this is the entry number
38202305Sstevel 				 * in the pcic_power[] array.
38212305Sstevel 				 */
38222305Sstevel 				sockp->pcs_vcc = PCIC_VCC_3VLEVEL;
38232305Sstevel 			} else
38242305Sstevel 				sockp->pcs_vcc = socket->VccLevel;
38252305Sstevel 			break;
38262305Sstevel 		default:
38272305Sstevel 			return (BAD_VCC);
38282305Sstevel 		}
38292305Sstevel 
38302305Sstevel 		/* enable Vcc */
38312305Sstevel 		powerlevel = POWER_CARD_ENABLE;
38322305Sstevel 
38332305Sstevel #if defined(PCIC_DEBUG)
38342305Sstevel 		if (pcic_debug) {
38352305Sstevel 			cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n",
38362305Sstevel 			    socket->VccLevel, powerlevel);
38372305Sstevel 		}
38382305Sstevel #endif
38392305Sstevel 		ind = 0;		/* default index to 0 power */
38402305Sstevel 		if ((int)socket->Vpp1Level >= 0 &&
38412305Sstevel 		    socket->Vpp1Level < pcic->pc_numpower) {
38422305Sstevel 			if (!(pcic_power[socket->Vpp1Level].ValidSignals
38432305Sstevel 			    & VPP1)) {
38442305Sstevel 				return (BAD_VPP);
38452305Sstevel 			}
38462305Sstevel 			ind = pcic_power[socket->Vpp1Level].PowerLevel/10;
38472305Sstevel 			powerlevel |= pcic_vpp_levels[ind];
38482305Sstevel 			sockp->pcs_vpp1 = socket->Vpp1Level;
38492305Sstevel 		}
38502305Sstevel 		if ((int)socket->Vpp2Level >= 0 &&
38512305Sstevel 		    socket->Vpp2Level < pcic->pc_numpower) {
38522305Sstevel 			if (!(pcic_power[socket->Vpp2Level].ValidSignals
38532305Sstevel 			    & VPP2)) {
38542305Sstevel 				return (BAD_VPP);
38552305Sstevel 			}
38562305Sstevel 			ind = pcic_power[socket->Vpp2Level].PowerLevel/10;
38572305Sstevel 			powerlevel |= (pcic_vpp_levels[ind] << 2);
38582305Sstevel 			sockp->pcs_vpp2 = socket->Vpp2Level;
38592305Sstevel 		}
38602305Sstevel 
38612305Sstevel 		if (pcic->pc_flags & PCF_VPPX) {
38622305Sstevel 			/*
38632305Sstevel 			 * this adapter doesn't allow separate Vpp1/Vpp2
38642305Sstevel 			 * if one is turned on, both are turned on and only
38652305Sstevel 			 * the Vpp1 bits should be set
38662305Sstevel 			 */
38672305Sstevel 			if (sockp->pcs_vpp2 != sockp->pcs_vpp1) {
38682305Sstevel 				/* must be the same if one not zero */
38692305Sstevel 				if (sockp->pcs_vpp1 != 0 &&
38702305Sstevel 				    sockp->pcs_vpp2 != 0) {
38712305Sstevel 					cmn_err(CE_WARN,
38722305Sstevel 					    "%s%d: Bad Power Request "
38732305Sstevel 					    "(Vpp1/2 not the same)\n",
38742305Sstevel 					    ddi_get_name(pcic->dip),
38752305Sstevel 					    ddi_get_instance(pcic->dip));
38762305Sstevel 					return (BAD_VPP);
38772305Sstevel 				}
38782305Sstevel 			}
38792305Sstevel 			powerlevel &= ~(3<<2);
38802305Sstevel 		}
38812305Sstevel 
38822305Sstevel #if defined(PCIC_DEBUG)
38832305Sstevel 		if (pcic_debug) {
38842305Sstevel 			cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n",
38852305Sstevel 			    powerlevel, ind);
38862305Sstevel 		}
38872305Sstevel #endif
38882305Sstevel 	}
38892305Sstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
38902305Sstevel 
38912305Sstevel 	/* turn socket->IREQRouting off while programming */
38922305Sstevel 	interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
38932305Sstevel 	interrupt &= ~PCIC_INTR_MASK;
38942305Sstevel 	if (pcic->pc_flags & PCF_USE_SMI)
38952305Sstevel 		interrupt |= PCIC_INTR_ENABLE;
38962305Sstevel 	pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt);
38972305Sstevel 
38982305Sstevel 	switch (pcic->pc_type) {
3899*7656SSherry.Moore@Sun.COM 		case PCIC_INTEL_i82092:
39002305Sstevel 		pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ,
3901*7656SSherry.Moore@Sun.COM 		    PCIC_82092_INT_DISABLE);
39022305Sstevel 		break;
3903*7656SSherry.Moore@Sun.COM 		default:
39042305Sstevel 		break;
39052305Sstevel 	} /* switch */
39062305Sstevel 
39072305Sstevel 	/* the SCIntMask specifies events to detect */
39082305Sstevel 	mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT);
39092305Sstevel 
39102305Sstevel #if defined(PCIC_DEBUG)
39112305Sstevel 	if (pcic_debug)
39122305Sstevel 		cmn_err(CE_CONT,
3913*7656SSherry.Moore@Sun.COM 		    "\tSCIntMask=%x, interrupt=%x, mirq=%x\n",
3914*7656SSherry.Moore@Sun.COM 		    socket->SCIntMask, interrupt, mirq);
39152305Sstevel #endif
39162305Sstevel 	mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT);
39172305Sstevel 	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT,
39182305Sstevel 	    mirq & ~PCIC_CHANGE_MASK);
39192305Sstevel 
39202305Sstevel 	/* save the mask we want to use */
39212305Sstevel 	sockp->pcs_intmask = socket->SCIntMask;
39222305Sstevel 
39232305Sstevel 	/*
39242305Sstevel 	 * Until there is a card present it's not worth enabling
39252305Sstevel 	 * any interrupts except "Card detect". This is done
39262305Sstevel 	 * elsewhere in the driver so don't change things if
39272305Sstevel 	 * there is no card!
39282305Sstevel 	 */
39292305Sstevel 	if (sockp->pcs_flags & PCS_CARD_PRESENT) {
39302305Sstevel 
39312305Sstevel 		/* now update the hardware to reflect events desired */
39322305Sstevel 		if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO)
39332305Sstevel 			mirq |= PCIC_BD_DETECT;
39342305Sstevel 
39352305Sstevel 		if (sockp->pcs_intmask & SBM_BVD2)
39362305Sstevel 			mirq |= PCIC_BW_DETECT;
39372305Sstevel 
39382305Sstevel 		if (sockp->pcs_intmask & SBM_RDYBSY)
39392305Sstevel 			mirq |= PCIC_RD_DETECT;
39402305Sstevel 
39412305Sstevel 		if (sockp->pcs_intmask & SBM_CD)
39422305Sstevel 			mirq |= PCIC_CD_DETECT;
39432305Sstevel 	}
39442305Sstevel 
39452305Sstevel 	if (sockp->pcs_flags & PCS_READY) {
39462305Sstevel 		/*
39472305Sstevel 		 * card just came ready.
39482305Sstevel 		 * make sure enough time elapses
39492305Sstevel 		 * before touching it.
39502305Sstevel 		 */
39512305Sstevel 		sockp->pcs_flags &= ~PCS_READY;
39522305Sstevel 		pcic_mswait(pcic, socket->socket, 10);
39532305Sstevel 	}
39542305Sstevel 
39552305Sstevel #if defined(PCIC_DEBUG)
39562305Sstevel 	if (pcic_debug) {
39572305Sstevel 		cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq);
39582305Sstevel 	}
39592305Sstevel #endif
39602305Sstevel 
39612305Sstevel 	switch (pcic->pc_type) {
3962*7656SSherry.Moore@Sun.COM 		case PCIC_I82365SL:
3963*7656SSherry.Moore@Sun.COM 		case PCIC_VADEM:
3964*7656SSherry.Moore@Sun.COM 		case PCIC_VADEM_VG469:
39652305Sstevel 		/*
39662305Sstevel 		 * The Intel version has different options. This is a
39672305Sstevel 		 * special case of GPI which might be used for eject
39682305Sstevel 		 */
39692305Sstevel 
39702305Sstevel 		irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT);
39712305Sstevel 		if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) &&
39722305Sstevel 		    pcic->pc_flags & PCF_GPI_EJECT) {
39732305Sstevel 			irq |= PCIC_GPI_ENABLE;
39742305Sstevel 		} else {
39752305Sstevel 			irq &= ~PCIC_GPI_ENABLE;
39762305Sstevel 		}
39772305Sstevel 		pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq);
39782305Sstevel 		break;
3979*7656SSherry.Moore@Sun.COM 		case PCIC_CL_PD6710:
3980*7656SSherry.Moore@Sun.COM 		case PCIC_CL_PD6722:
39812305Sstevel 		if (socket->IFType == IF_IO) {
39822305Sstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0);
39832305Sstevel 			value = pcic_getb(pcic, socket->socket,
3984*7656SSherry.Moore@Sun.COM 			    PCIC_MISC_CTL_1);
39852305Sstevel 			if (pcic->pc_flags & PCF_AUDIO)
39862305Sstevel 				value |= PCIC_MC_SPEAKER_ENB;
39872305Sstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
3988*7656SSherry.Moore@Sun.COM 			    value);
39892305Sstevel 		} else {
39902305Sstevel 			value = pcic_getb(pcic, socket->socket,
3991*7656SSherry.Moore@Sun.COM 			    PCIC_MISC_CTL_1);
39922305Sstevel 			value &= ~PCIC_MC_SPEAKER_ENB;
39932305Sstevel 			pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
3994*7656SSherry.Moore@Sun.COM 			    value);
39952305Sstevel 		}
39962305Sstevel 		break;
3997*7656SSherry.Moore@Sun.COM 		case PCIC_CL_PD6729:
3998*7656SSherry.Moore@Sun.COM 		case PCIC_CL_PD6730:
3999*7656SSherry.Moore@Sun.COM 		case PCIC_CL_PD6832:
40002305Sstevel 		value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1);
40012305Sstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
4002*7656SSherry.Moore@Sun.COM 			value |= PCIC_MC_SPEAKER_ENB;
40032305Sstevel 		} else {
4004*7656SSherry.Moore@Sun.COM 			value &= ~PCIC_MC_SPEAKER_ENB;
40052305Sstevel 		}
40062305Sstevel 
40072305Sstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40082305Sstevel 			value |= PCIC_MC_3VCC;
40092305Sstevel 		else
40102305Sstevel 			value &= ~PCIC_MC_3VCC;
40112305Sstevel 
40122305Sstevel 		pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value);
40132305Sstevel 		break;
40142305Sstevel 
4015*7656SSherry.Moore@Sun.COM 		case PCIC_O2_OZ6912:
40162305Sstevel 		value = pcic_getcb(pcic, CB_MISCCTRL);
40172305Sstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO))
40182305Sstevel 			value |= (1<<25);
40192305Sstevel 		else
40202305Sstevel 			value &= ~(1<<25);
40212305Sstevel 		pcic_putcb(pcic, CB_MISCCTRL, value);
40222305Sstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40232305Sstevel 			powerlevel |= 0x08;
40242305Sstevel 		break;
40252305Sstevel 
4026*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1250:
4027*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1221:
4028*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1225:
4029*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1410:
4030*7656SSherry.Moore@Sun.COM 		case PCIC_ENE_1410:
4031*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1510:
4032*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1520:
4033*7656SSherry.Moore@Sun.COM 		case PCIC_TI_PCI1420:
4034*7656SSherry.Moore@Sun.COM 		case PCIC_ENE_1420:
40352305Sstevel 		value = ddi_get8(pcic->cfg_handle,
40362305Sstevel 		    pcic->cfgaddr + PCIC_CRDCTL_REG);
40372305Sstevel 		if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40382305Sstevel 			value |= PCIC_CRDCTL_SPKR_ENBL;
40392305Sstevel 		} else {
40402305Sstevel 			value &= ~PCIC_CRDCTL_SPKR_ENBL;
40412305Sstevel 		}
40422305Sstevel 		ddi_put8(pcic->cfg_handle,
40432305Sstevel 		    pcic->cfgaddr + PCIC_CRDCTL_REG, value);
40442305Sstevel 		if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40452305Sstevel 			powerlevel |= 0x08;
40462305Sstevel 		break;
40472305Sstevel 	}
40482305Sstevel 
40492305Sstevel 	/*
40502305Sstevel 	 * ctlind processing -- we can ignore this
40512305Sstevel 	 * there aren't any outputs on the chip for this and
40522305Sstevel 	 * the GUI will display what it thinks is correct
40532305Sstevel 	 */
40542305Sstevel 
40552305Sstevel 	/*
40562305Sstevel 	 * If outputs are enabled and the power is going off
40572305Sstevel 	 * turn off outputs first.
40582305Sstevel 	 */
40592305Sstevel 
40602305Sstevel 	/* power setup -- if necessary */
40612305Sstevel 	orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40622305Sstevel 	if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) {
40632305Sstevel 		orig_pwrctl &= ~POWER_OUTPUT_ENABLE;
40642305Sstevel 		pcic_putb(pcic, socket->socket,
40652305Sstevel 		    PCIC_POWER_CONTROL, orig_pwrctl);
40662305Sstevel 		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40672305Sstevel 	}
40682305Sstevel 
40692305Sstevel 	if (pcic->pc_flags & PCF_CBPWRCTL) {
40702305Sstevel 		value = pcic_cbus_powerctl(pcic, socket->socket);
40712305Sstevel 		powerlevel = 0;
40722305Sstevel 	} else
40732305Sstevel 		value = pcic_exca_powerctl(pcic, socket->socket, powerlevel);
40742305Sstevel 
40752305Sstevel 	if (value != SUCCESS) {
40762305Sstevel 		mutex_exit(&pcic->pc_lock);
40772305Sstevel 		return (value);
40782305Sstevel 	}
40792305Sstevel 
40802305Sstevel 	/*
40812305Sstevel 	 * If outputs were disabled and the power is going on
40822305Sstevel 	 * turn on outputs afterwards.
40832305Sstevel 	 */
40842305Sstevel 	if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) {
40852305Sstevel 		orig_pwrctl = pcic_getb(pcic, socket->socket,
40862305Sstevel 		    PCIC_POWER_CONTROL);
40872305Sstevel 		orig_pwrctl |= POWER_OUTPUT_ENABLE;
40882305Sstevel 		pcic_putb(pcic, socket->socket,
40892305Sstevel 		    PCIC_POWER_CONTROL, orig_pwrctl);
40902305Sstevel 		(void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40912305Sstevel 	}
40922305Sstevel 
40932305Sstevel 	/*
40942305Sstevel 	 * Once we have done the power stuff can re-enable management
40952305Sstevel 	 * interrupts.
40962305Sstevel 	 */
40972305Sstevel 	pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq);
40982305Sstevel 
40992305Sstevel #if defined(PCIC_DEBUG)
41002305Sstevel 	pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x "
41012305Sstevel 	    "cbctl 0x%x\n",
41022305Sstevel 	    mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL),
41032305Sstevel 	    pcic_getcb(pcic, CB_CONTROL));
41042305Sstevel #endif
41052305Sstevel 
41062305Sstevel 	/* irq processing */
41072305Sstevel 	if (socket->IFType == IF_IO) {
41082305Sstevel 		/* IRQ only for I/O */
41092305Sstevel 		irq = socket->IREQRouting & PCIC_INTR_MASK;
41102305Sstevel 		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41112305Sstevel 		value &= ~PCIC_INTR_MASK;
41122305Sstevel 
41132305Sstevel 		/* to enable I/O operation */
41142305Sstevel 		value |= PCIC_IO_CARD | PCIC_RESET;
41152305Sstevel 		sockp->pcs_flags |= PCS_CARD_IO;
41162305Sstevel 		if (irq != sockp->pcs_irq) {
41172305Sstevel 			if (sockp->pcs_irq != 0)
41182305Sstevel 				cmn_err(CE_CONT,
4119*7656SSherry.Moore@Sun.COM 				    "SetSocket: IRQ mismatch %x != %x!\n",
4120*7656SSherry.Moore@Sun.COM 				    irq, sockp->pcs_irq);
41212305Sstevel 			else
41222305Sstevel 				sockp->pcs_irq = irq;
41232305Sstevel 		}
41242305Sstevel 		irq = sockp->pcs_irq;
41252305Sstevel 
41262305Sstevel 		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41272305Sstevel 		if (socket->IREQRouting & IRQ_ENABLE) {
41282305Sstevel 			pcic_enable_io_intr(pcic, socket->socket, irq);
41292305Sstevel 			sockp->pcs_flags |= PCS_IRQ_ENABLED;
41302305Sstevel 		} else {
41312305Sstevel 			pcic_disable_io_intr(pcic, socket->socket);
41322305Sstevel 			sockp->pcs_flags &= ~PCS_IRQ_ENABLED;
41332305Sstevel 		}
41342305Sstevel #if defined(PCIC_DEBUG)
41352305Sstevel 		if (pcic_debug) {
41362305Sstevel 			cmn_err(CE_CONT,
4137*7656SSherry.Moore@Sun.COM 			    "\tsocket type is I/O and irq %x is %s\n", irq,
4138*7656SSherry.Moore@Sun.COM 			    (socket->IREQRouting & IRQ_ENABLE) ?
4139*7656SSherry.Moore@Sun.COM 			    "enabled" : "not enabled");
41402305Sstevel 			xxdmp_all_regs(pcic, socket->socket, 20);
41412305Sstevel 		}
41422305Sstevel #endif
41432305Sstevel 	} else {
41442305Sstevel 		/* make sure I/O mode is off */
41452305Sstevel 
41462305Sstevel 		sockp->pcs_irq = 0;
41472305Sstevel 
41482305Sstevel 		value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41492305Sstevel 		value &= ~PCIC_IO_CARD;
41502305Sstevel 		pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41512305Sstevel 		pcic_disable_io_intr(pcic, socket->socket);
41522305Sstevel 		sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED);
41532305Sstevel 	}
41542305Sstevel 
41552305Sstevel 	sockp->pcs_state &= ~socket->State;
41562305Sstevel 
41572305Sstevel 	mutex_exit(&pcic->pc_lock);
41582305Sstevel 	return (SUCCESS);
41592305Sstevel }
41602305Sstevel 
41612305Sstevel /*
41622305Sstevel  * pcic_inquire_socket()
41632305Sstevel  *	SocketServices InquireSocket function
41642305Sstevel  *	returns basic characteristics of the socket
41652305Sstevel  */
41662305Sstevel /*ARGSUSED*/
41672305Sstevel static int
41682305Sstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
41692305Sstevel {
41702305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
41712305Sstevel 	pcicdev_t *pcic = anp->an_private;
41722305Sstevel 	int value;
41732305Sstevel 
41742305Sstevel 	socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS;
41752305Sstevel 	socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS;
41762305Sstevel 	socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS;
41772305Sstevel 	value = pcic->pc_sockets[socket->socket].pcs_flags;
41782305Sstevel 	socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY;
41792305Sstevel 	socket->ActiveHigh = 0;
41802305Sstevel 	/* these are the usable IRQs */
41812305Sstevel 	socket->ActiveLow = 0xfff0;
41822305Sstevel 	return (SUCCESS);
41832305Sstevel }
41842305Sstevel 
41852305Sstevel /*
41862305Sstevel  * pcic_inquire_window()
41872305Sstevel  *	SocketServices InquireWindow function
41882305Sstevel  *	returns detailed characteristics of the window
41892305Sstevel  *	this is where windows get tied to sockets
41902305Sstevel  */
41912305Sstevel /*ARGSUSED*/
41922305Sstevel static int
41932305Sstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window)
41942305Sstevel {
41952305Sstevel 	int type, socket;
41962305Sstevel 
41972305Sstevel 	type = window->window % PCIC_NUMWINSOCK;
41982305Sstevel 	socket = window->window / PCIC_NUMWINSOCK;
41992305Sstevel 
42002305Sstevel #if defined(PCIC_DEBUG)
42012305Sstevel 	if (pcic_debug >= 8)
42022305Sstevel 		cmn_err(CE_CONT,
4203*7656SSherry.Moore@Sun.COM 		    "pcic_inquire_window: window = %d/%d socket=%d\n",
4204*7656SSherry.Moore@Sun.COM 		    window->window, type, socket);
42052305Sstevel #endif
42062305Sstevel 	if (type < PCIC_IOWINDOWS) {
42072305Sstevel 		window->WndCaps = WC_IO|WC_WAIT;
42082305Sstevel 		type = IF_IO;
42092305Sstevel 	} else {
42102305Sstevel 		window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT;
42112305Sstevel 		type = IF_MEMORY;
42122305Sstevel 	}
42132305Sstevel 
42142305Sstevel 	/* initialize the socket map - one socket per window */
42152305Sstevel 	PR_ZERO(window->Sockets);
42162305Sstevel 	PR_SET(window->Sockets, socket);
42172305Sstevel 
42182305Sstevel 	if (type == IF_IO) {
42192305Sstevel 		iowin_char_t *io;
42202305Sstevel 		io = &window->iowin_char;
42212305Sstevel 		io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
4222*7656SSherry.Moore@Sun.COM 		    WC_16BIT;
42232305Sstevel 		io->FirstByte = (baseaddr_t)IOMEM_FIRST;
42242305Sstevel 		io->LastByte = (baseaddr_t)IOMEM_LAST;
42252305Sstevel 		io->MinSize = IOMEM_MIN;
42262305Sstevel 		io->MaxSize = IOMEM_MAX;
42272305Sstevel 		io->ReqGran = IOMEM_GRAN;
42282305Sstevel 		io->AddrLines = IOMEM_DECODE;
42292305Sstevel 		io->EISASlot = 0;
42302305Sstevel 	} else {
42312305Sstevel 		mem_win_char_t *mem;
42322305Sstevel 		mem = &window->mem_win_char;
42332305Sstevel 		mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
4234*7656SSherry.Moore@Sun.COM 		    WC_16BIT|WC_WP;
42352305Sstevel 
42362305Sstevel 		mem->FirstByte = (baseaddr_t)MEM_FIRST;
42372305Sstevel 		mem->LastByte = (baseaddr_t)MEM_LAST;
42382305Sstevel 
42392305Sstevel 		mem->MinSize = MEM_MIN;
42402305Sstevel 		mem->MaxSize = MEM_MAX;
42412305Sstevel 		mem->ReqGran = PCIC_PAGE;
42422305Sstevel 		mem->ReqBase = 0;
42432305Sstevel 		mem->ReqOffset = PCIC_PAGE;
42442305Sstevel 		mem->Slowest = MEM_SPEED_MAX;
42452305Sstevel 		mem->Fastest = MEM_SPEED_MIN;
42462305Sstevel 	}
42472305Sstevel 	return (SUCCESS);
42482305Sstevel }
42492305Sstevel 
42502305Sstevel /*
42512305Sstevel  * pcic_get_adapter()
42522305Sstevel  *	SocketServices GetAdapter function
42532305Sstevel  *	this is nearly a no-op.
42542305Sstevel  */
42552305Sstevel /*ARGSUSED*/
42562305Sstevel static int
42572305Sstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
42582305Sstevel {
42592305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
42602305Sstevel 	pcicdev_t *pcic = anp->an_private;
42612305Sstevel 
42622305Sstevel 	if (pcic->pc_flags & PCF_INTRENAB)
42632305Sstevel 		adapt->SCRouting = IRQ_ENABLE;
42642305Sstevel 	adapt->state = 0;
42652305Sstevel 	return (SUCCESS);
42662305Sstevel }
42672305Sstevel 
42682305Sstevel /*
42692305Sstevel  * pcic_get_page()
42702305Sstevel  *	SocketServices GetPage function
42712305Sstevel  *	returns info about the window
42722305Sstevel  */
42732305Sstevel /*ARGSUSED*/
42742305Sstevel static int
42752305Sstevel pcic_get_page(dev_info_t *dip, get_page_t *page)
42762305Sstevel {
42772305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
42782305Sstevel 	pcicdev_t *pcic = anp->an_private;
42792305Sstevel 	int socket, window;
42802305Sstevel 	pcs_memwin_t *winp;
42812305Sstevel 
42822305Sstevel 	socket = page->window / PCIC_NUMWINSOCK;
42832305Sstevel 	window = page->window % PCIC_NUMWINSOCK;
42842305Sstevel 
42852305Sstevel 	/* I/O windows are the first two */
42862305Sstevel 	if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) {
42872305Sstevel 		return (BAD_WINDOW);
42882305Sstevel 	}
42892305Sstevel 
42902305Sstevel 	winp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
42912305Sstevel 
42922305Sstevel 	if (page->page != 0)
42932305Sstevel 		return (BAD_PAGE);
42942305Sstevel 
42952305Sstevel 	page->state = 0;
42962305Sstevel 	if (winp->pcw_status & PCW_ENABLED)
42972305Sstevel 		page->state |= PS_ENABLED;
42982305Sstevel 	if (winp->pcw_status & PCW_ATTRIBUTE)
42992305Sstevel 		page->state |= PS_ATTRIBUTE;
43002305Sstevel 	if (winp->pcw_status & PCW_WP)
43012305Sstevel 		page->state |= PS_WP;
43022305Sstevel 
43032305Sstevel 	page->offset = (off_t)winp->pcw_offset;
43042305Sstevel 
43052305Sstevel 	return (SUCCESS);
43062305Sstevel }
43072305Sstevel 
43082305Sstevel /*
43092305Sstevel  * pcic_get_socket()
43102305Sstevel  *	SocketServices GetSocket
43112305Sstevel  *	returns information about the current socket setting
43122305Sstevel  */
43132305Sstevel /*ARGSUSED*/
43142305Sstevel static int
43152305Sstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket)
43162305Sstevel {
43172305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
43182305Sstevel 	pcicdev_t *pcic = anp->an_private;
43192305Sstevel 	int socknum, irq_enabled;
43202305Sstevel 	pcic_socket_t *sockp;
43212305Sstevel 
43222305Sstevel 	socknum = socket->socket;
43232305Sstevel 	sockp = &pcic->pc_sockets[socknum];
43242305Sstevel 
43252305Sstevel 	socket->SCIntMask = sockp->pcs_intmask;
43262305Sstevel 	sockp->pcs_state = pcic_card_state(pcic, sockp);
43272305Sstevel 
43282305Sstevel 	socket->state = sockp->pcs_state;
43292305Sstevel 	if (socket->state & SBM_CD) {
43302305Sstevel 		socket->VccLevel = sockp->pcs_vcc;
43312305Sstevel 		socket->Vpp1Level = sockp->pcs_vpp1;
43322305Sstevel 		socket->Vpp2Level = sockp->pcs_vpp2;
43332305Sstevel 		irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ?
43342305Sstevel 		    IRQ_ENABLE : 0;
43352305Sstevel 		socket->IRQRouting = sockp->pcs_irq | irq_enabled;
43362305Sstevel 		socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43372305Sstevel 		    IF_IO : IF_MEMORY;
43382305Sstevel 	} else {
43392305Sstevel 		socket->VccLevel = 0;
43402305Sstevel 		socket->Vpp1Level = 0;
43412305Sstevel 		socket->Vpp2Level = 0;
43422305Sstevel 		socket->IRQRouting = 0;
43432305Sstevel 		socket->IFType = IF_MEMORY;
43442305Sstevel 	}
43452305Sstevel 	socket->CtlInd = 0;	/* no indicators */
43462305Sstevel 
43472305Sstevel 	return (SUCCESS);
43482305Sstevel }
43492305Sstevel 
43502305Sstevel /*
43512305Sstevel  * pcic_get_status()
43522305Sstevel  *	SocketServices GetStatus
43532305Sstevel  *	returns status information about the PC Card in
43542305Sstevel  *	the selected socket
43552305Sstevel  */
43562305Sstevel /*ARGSUSED*/
43572305Sstevel static int
43582305Sstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status)
43592305Sstevel {
43602305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
43612305Sstevel 	pcicdev_t *pcic = anp->an_private;
43622305Sstevel 	int socknum, irq_enabled;
43632305Sstevel 	pcic_socket_t *sockp;
43642305Sstevel 
43652305Sstevel 	socknum = status->socket;
43662305Sstevel 	sockp = &pcic->pc_sockets[socknum];
43672305Sstevel 
43682305Sstevel 	status->CardState = pcic_card_state(pcic, sockp);
43692305Sstevel 	status->SocketState = sockp->pcs_state;
43702305Sstevel 	status->CtlInd = 0;	/* no indicators */
43712305Sstevel 
43722305Sstevel 	if (sockp->pcs_flags & PCS_CARD_PRESENT)
43732305Sstevel 		status->SocketState |= SBM_CD;
43742305Sstevel 	if (status->CardState & SBM_CD) {
43752305Sstevel 		irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ?
43762305Sstevel 		    IRQ_ENABLE : 0;
43772305Sstevel 		status->IRQRouting = sockp->pcs_irq | irq_enabled;
43782305Sstevel 		status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43792305Sstevel 		    IF_IO : IF_MEMORY;
43802305Sstevel 	} else {
43812305Sstevel 		status->IRQRouting = 0;
43822305Sstevel 		status->IFType = IF_MEMORY;
43832305Sstevel 	}
43842305Sstevel 
43852305Sstevel #if defined(PCIC_DEBUG)
43862305Sstevel 	if (pcic_debug >= 8)
43872305Sstevel 		cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x,"
4388*7656SSherry.Moore@Sun.COM 		    "SocketState=%x\n",
4389*7656SSherry.Moore@Sun.COM 		    socknum, status->CardState, status->SocketState);
43902305Sstevel #endif
43912305Sstevel 	switch (pcic->pc_type) {
43922305Sstevel 	uint32_t present_state;
43932305Sstevel 	case PCIC_TI_PCI1410:
43942305Sstevel 	case PCIC_TI_PCI1520:
43952305Sstevel 	case PCIC_TI_PCI1420:
43962305Sstevel 	case PCIC_ENE_1420:
43972305Sstevel 	case PCIC_TOSHIBA_TOPIC100:
43982305Sstevel 	case PCIC_TOSHIBA_TOPIC95:
43992305Sstevel 	case PCIC_TOSHIBA_VENDOR:
44002305Sstevel 	case PCIC_O2MICRO_VENDOR:
44012305Sstevel 	case PCIC_TI_VENDOR:
44022305Sstevel 	case PCIC_RICOH_VENDOR:
44032305Sstevel 		present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
44042305Sstevel 		if (present_state & PCIC_CB_CARD)
44052305Sstevel 			status->IFType = IF_CARDBUS;
44062305Sstevel #if defined(PCIC_DEBUG)
44072305Sstevel 		if (pcic_debug >= 8)
4408*7656SSherry.Moore@Sun.COM 			cmn_err(CE_CONT,
4409*7656SSherry.Moore@Sun.COM 			    "pcic_get_status: present_state=0x%x\n",
4410*7656SSherry.Moore@Sun.COM 			    present_state);
44112305Sstevel #endif
44122305Sstevel 		break;
44132305Sstevel 	default:
44142305Sstevel 		break;
44152305Sstevel 	}
44162305Sstevel 
44172305Sstevel 	return (SUCCESS);
44182305Sstevel }
44192305Sstevel 
44202305Sstevel /*
44212305Sstevel  * pcic_get_window()
44222305Sstevel  *	SocketServices GetWindow function
44232305Sstevel  *	returns state information about the specified window
44242305Sstevel  */
44252305Sstevel /*ARGSUSED*/
44262305Sstevel static int
44272305Sstevel pcic_get_window(dev_info_t *dip, get_window_t *window)
44282305Sstevel {
44292305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
44302305Sstevel 	pcicdev_t *pcic = anp->an_private;
44312305Sstevel 	int socket, win;
44322305Sstevel 	pcic_socket_t *sockp;
44332305Sstevel 	pcs_memwin_t *winp;
44342305Sstevel 
44352305Sstevel 	socket = window->window / PCIC_NUMWINSOCK;
44362305Sstevel 	win = window->window % PCIC_NUMWINSOCK;
44372305Sstevel #if defined(PCIC_DEBUG)
44382305Sstevel 	if (pcic_debug) {
44392305Sstevel 		cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n",
4440*7656SSherry.Moore@Sun.COM 		    socket, win);
44412305Sstevel 	}
44422305Sstevel #endif
44432305Sstevel 
44442305Sstevel 	if (socket > pcic->pc_numsockets)
44452305Sstevel 		return (BAD_WINDOW);
44462305Sstevel 
44472305Sstevel 	sockp = &pcic->pc_sockets[socket];
44482305Sstevel 	winp = &sockp->pcs_windows[win].mem;
44492305Sstevel 
44502305Sstevel 	window->socket = socket;
44512305Sstevel 	window->size = winp->pcw_len;
44522305Sstevel 	window->speed = winp->pcw_speed;
44532305Sstevel 	window->handle = (ddi_acc_handle_t)winp->pcw_handle;
44542305Sstevel 	window->base = (uint32_t)winp->pcw_base + winp->pcw_offset;
44552305Sstevel 
44562305Sstevel 	if (win >= PCIC_IOWINDOWS) {
44572305Sstevel 		window->state = 0;
44582305Sstevel 	} else {
44592305Sstevel 		window->state = WS_IO;
44602305Sstevel 	}
44612305Sstevel 	if (winp->pcw_status & PCW_ENABLED)
44622305Sstevel 		window->state |= WS_ENABLED;
44632305Sstevel 
44642305Sstevel 	if (winp->pcw_status & PCS_CARD_16BIT)
44652305Sstevel 		window->state |= WS_16BIT;
44662305Sstevel #if defined(PCIC_DEBUG)
44672305Sstevel 	if (pcic_debug)
44682305Sstevel 		cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n",
4469*7656SSherry.Moore@Sun.COM 		    window->size, (unsigned)window->speed,
4470*7656SSherry.Moore@Sun.COM 		    (void *)window->handle, window->state);
44712305Sstevel #endif
44722305Sstevel 
44732305Sstevel 	return (SUCCESS);
44742305Sstevel }
44752305Sstevel 
44762305Sstevel /*
44772305Sstevel  * pcic_ll_reset
44782305Sstevel  *	low level reset
44792305Sstevel  *	separated out so it can be called when already locked
44802305Sstevel  *
44812305Sstevel  *	There are two variables that control the RESET timing:
44822305Sstevel  *		pcic_prereset_time - time in mS before asserting RESET
44832305Sstevel  *		pcic_reset_time - time in mS to assert RESET
44842305Sstevel  *
44852305Sstevel  */
44862305Sstevel int pcic_prereset_time = 1;
44872305Sstevel int pcic_reset_time = 10;
44882305Sstevel int pcic_postreset_time = 20;
44892305Sstevel int pcic_vpp_is_vcc_during_reset = 0;
44902305Sstevel 
44912305Sstevel static int
44922305Sstevel pcic_ll_reset(pcicdev_t *pcic, int socket)
44932305Sstevel {
44942305Sstevel 	int windowbits, iobits;
44952305Sstevel 	uint32_t pwr;
44962305Sstevel 
44972305Sstevel 	/* save windows that were on */
44982305Sstevel 	windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
44992305Sstevel 	if (pcic_reset_time == 0)
4500*7656SSherry.Moore@Sun.COM 		return (windowbits);
45012305Sstevel 	/* turn all windows off */
45022305Sstevel 	pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0);
45032305Sstevel 
45042305Sstevel #if defined(PCIC_DEBUG)
45052305Sstevel 	pcic_err(pcic->dip, 6,
4506*7656SSherry.Moore@Sun.COM 	    "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n",
4507*7656SSherry.Moore@Sun.COM 	    socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
4508*7656SSherry.Moore@Sun.COM 	    pcic_getcb(pcic, CB_CONTROL),
4509*7656SSherry.Moore@Sun.COM 	    pcic_getcb(pcic, CB_PRESENT_STATE));
45102305Sstevel #endif
45112305Sstevel 
45122305Sstevel 	if (pcic_vpp_is_vcc_during_reset) {
45132305Sstevel 
45142305Sstevel 	/*
45152305Sstevel 	 * Set VPP to VCC for the duration of the reset - for aironet
45162305Sstevel 	 * card.
45172305Sstevel 	 */
4518*7656SSherry.Moore@Sun.COM 		if (pcic->pc_flags & PCF_CBPWRCTL) {
45192305Sstevel 		pwr = pcic_getcb(pcic, CB_CONTROL);
45202305Sstevel 		pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC);
45212305Sstevel 		(void) pcic_getcb(pcic, CB_CONTROL);
4522*7656SSherry.Moore@Sun.COM 		} else {
45232305Sstevel 		pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45242305Sstevel 		pcic_putb(pcic, socket, PCIC_POWER_CONTROL,
45252305Sstevel 		    pwr | 1);
45262305Sstevel 		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
4527*7656SSherry.Moore@Sun.COM 		}
45282305Sstevel 	}
45292305Sstevel 
45302305Sstevel 	if (pcic_prereset_time > 0) {
45312305Sstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n",
45322305Sstevel 		    pcic_prereset_time);
45332305Sstevel 		pcic_mswait(pcic, socket, pcic_prereset_time);
45342305Sstevel 	}
45352305Sstevel 
45362305Sstevel 	/* turn interrupts off and start a reset */
45372305Sstevel 	pcic_err(pcic->dip, 8,
4538*7656SSherry.Moore@Sun.COM 	    "pcic_ll_reset turn interrupts off and start a reset\n");
45392305Sstevel 	iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
45402305Sstevel 	iobits &= ~(PCIC_INTR_MASK | PCIC_RESET);
45412305Sstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
45422305Sstevel 	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45432305Sstevel 
45442305Sstevel 	switch (pcic->pc_type) {
4545*7656SSherry.Moore@Sun.COM 		case PCIC_INTEL_i82092:
45462305Sstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
4547*7656SSherry.Moore@Sun.COM 		    PCIC_82092_INT_DISABLE);
45482305Sstevel 		break;
4549*7656SSherry.Moore@Sun.COM 		default:
45502305Sstevel 		break;
45512305Sstevel 	} /* switch */
45522305Sstevel 
45532305Sstevel 	pcic->pc_sockets[socket].pcs_state = 0;
45542305Sstevel 
45552305Sstevel 	if (pcic_reset_time > 0) {
45562305Sstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n",
45572305Sstevel 		    pcic_reset_time);
45582305Sstevel 		pcic_mswait(pcic, socket, pcic_reset_time);
45592305Sstevel 	}
45602305Sstevel 
45612305Sstevel 	pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n");
45622305Sstevel 
45632305Sstevel 	/* take it out of RESET now */
45642305Sstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits);
45652305Sstevel 	(void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45662305Sstevel 
45672305Sstevel 	/*
45682305Sstevel 	 * can't access the card for 20ms, but we really don't
45692305Sstevel 	 * want to sit around that long. The pcic is still usable.
45702305Sstevel 	 * memory accesses must wait for RDY to come up.
45712305Sstevel 	 */
45722305Sstevel 	if (pcic_postreset_time > 0) {
45732305Sstevel 		pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n",
45742305Sstevel 		    pcic_postreset_time);
45752305Sstevel 		pcic_mswait(pcic, socket, pcic_postreset_time);
45762305Sstevel 	}
45772305Sstevel 
45782305Sstevel 	if (pcic_vpp_is_vcc_during_reset > 1) {
45792305Sstevel 
45802305Sstevel 	/*
45812305Sstevel 	 * Return VPP power to whatever it was before.
45822305Sstevel 	 */
4583*7656SSherry.Moore@Sun.COM 		if (pcic->pc_flags & PCF_CBPWRCTL) {
45842305Sstevel 		pcic_putcb(pcic, CB_CONTROL, pwr);
45852305Sstevel 		(void) pcic_getcb(pcic, CB_CONTROL);
4586*7656SSherry.Moore@Sun.COM 		} else {
45872305Sstevel 		pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr);
45882305Sstevel 		(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
4589*7656SSherry.Moore@Sun.COM 		}
45902305Sstevel 	}
45912305Sstevel 
45922305Sstevel 	pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits);
45932305Sstevel 
45942305Sstevel 	return (windowbits);
45952305Sstevel }
45962305Sstevel 
45972305Sstevel /*
45982305Sstevel  * pcic_reset_socket()
45992305Sstevel  *	SocketServices ResetSocket function
46002305Sstevel  *	puts the PC Card in the socket into the RESET state
46012305Sstevel  *	and then takes it out after the the cycle time
46022305Sstevel  *	The socket is back to initial state when done
46032305Sstevel  */
46042305Sstevel static int
46052305Sstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode)
46062305Sstevel {
46072305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
46082305Sstevel 	pcicdev_t *pcic = anp->an_private;
46092305Sstevel 	int value;
46102305Sstevel 	int i, mint;
46112305Sstevel 	pcic_socket_t *sockp;
46122305Sstevel 
46132305Sstevel #if defined(PCIC_DEBUG)
46142305Sstevel 	if (pcic_debug >= 8)
46152305Sstevel 		cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n",
46162305Sstevel 		    (void *)dip, socket, mode,
4617*7656SSherry.Moore@Sun.COM 		    mode == RESET_MODE_FULL ? "full" : "partial");
46182305Sstevel #endif
46192305Sstevel 
46202305Sstevel 	mutex_enter(&pcic->pc_lock); /* protect the registers */
46212305Sstevel 
46222305Sstevel 	/* Turn off management interupts. */
46232305Sstevel 	mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT);
46242305Sstevel 	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK);
46252305Sstevel 
46262305Sstevel 	sockp = &pcic->pc_sockets[socket];
46272305Sstevel 
46282305Sstevel 	value = pcic_ll_reset(pcic, socket);
46292305Sstevel 	if (mode == RESET_MODE_FULL) {
46302305Sstevel 		/* disable and unmap all mapped windows */
46312305Sstevel 		for (i = 0; i < PCIC_NUMWINSOCK; i++) {
46322305Sstevel 			if (i < PCIC_IOWINDOWS) {
46332305Sstevel 				if (sockp->pcs_windows[i].io.pcw_status &
46342305Sstevel 				    PCW_MAPPED) {
46352305Sstevel 					pcs_iowin_t *io;
46362305Sstevel 					io = &sockp->pcs_windows[i].io;
46372305Sstevel 					io->pcw_status &= ~PCW_ENABLED;
46382305Sstevel 				}
46392305Sstevel 			} else {
46402305Sstevel 				if (sockp->pcs_windows[i].mem.pcw_status &
46412305Sstevel 				    PCW_MAPPED) {
46422305Sstevel 					pcs_memwin_t *mem;
46432305Sstevel 					mem = &sockp->pcs_windows[i].mem;
46442305Sstevel 					mem->pcw_status &= ~PCW_ENABLED;
46452305Sstevel 				}
46462305Sstevel 			}
46472305Sstevel 		}
46482305Sstevel 	} else {
46492305Sstevel 				/* turn windows back on */
46502305Sstevel 		pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value);
46512305Sstevel 		/* wait the rest of the time here */
46522305Sstevel 		pcic_mswait(pcic, socket, 10);
46532305Sstevel 	}
46542305Sstevel 	pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint);
46552305Sstevel 	mutex_exit(&pcic->pc_lock);
46562305Sstevel 	return (SUCCESS);
46572305Sstevel }
46582305Sstevel 
46592305Sstevel /*
46602305Sstevel  * pcic_set_interrupt()
46612305Sstevel  *	SocketServices SetInterrupt function
46622305Sstevel  */
46632305Sstevel static int
46642305Sstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
46652305Sstevel {
46662305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
46672305Sstevel 	pcicdev_t *pcic = anp->an_private;
46682305Sstevel 	int value = DDI_SUCCESS;
46692305Sstevel 	inthandler_t *intr;
46702305Sstevel 
46712305Sstevel #if defined(PCIC_DEBUG)
46722305Sstevel 	if (pcic_debug) {
46732305Sstevel 		cmn_err(CE_CONT,
4674*7656SSherry.Moore@Sun.COM 		    "pcic_set_interrupt: entered pc_intr_mode=0x%x\n",
4675*7656SSherry.Moore@Sun.COM 		    pcic->pc_intr_mode);
46762305Sstevel 		cmn_err(CE_CONT,
4677*7656SSherry.Moore@Sun.COM 		    "\t irq_top=%p handler=%p handler_id=%x\n",
4678*7656SSherry.Moore@Sun.COM 		    (void *)pcic->irq_top, (void *)handler->handler,
4679*7656SSherry.Moore@Sun.COM 		    handler->handler_id);
46802305Sstevel 	}
46812305Sstevel #endif
46822305Sstevel 
46832305Sstevel 	/*
46842305Sstevel 	 * If we're on a PCI bus, we route all IO IRQs through a single
46852305Sstevel 	 *	PCI interrupt (typically INT A#) so we don't have to do
46862305Sstevel 	 *	much other than add the caller to general interrupt handler
46872305Sstevel 	 *	and set some state.
46882305Sstevel 	 */
46892305Sstevel 
46902305Sstevel 	intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
46912305Sstevel 	if (intr == NULL)
46922305Sstevel 		return (NO_RESOURCE);
46932305Sstevel 
46942305Sstevel 	switch (pcic->pc_intr_mode) {
46952305Sstevel 	case PCIC_INTR_MODE_PCI_1:
46962305Sstevel 		/*
46972305Sstevel 		 * We only allow above-lock-level IO IRQ handlers
46982305Sstevel 		 *	in the PCI bus case.
46992305Sstevel 		 */
47002305Sstevel 
47012305Sstevel 		mutex_enter(&pcic->intr_lock);
47022305Sstevel 
47032305Sstevel 		if (pcic->irq_top == NULL) {
4704*7656SSherry.Moore@Sun.COM 			pcic->irq_top = intr;
4705*7656SSherry.Moore@Sun.COM 			pcic->irq_current = pcic->irq_top;
47062305Sstevel 		} else {
4707*7656SSherry.Moore@Sun.COM 			while (pcic->irq_current->next != NULL)
47082305Sstevel 			pcic->irq_current = pcic->irq_current->next;
4709*7656SSherry.Moore@Sun.COM 			pcic->irq_current->next = intr;
4710*7656SSherry.Moore@Sun.COM 			pcic->irq_current = pcic->irq_current->next;
47112305Sstevel 		}
47122305Sstevel 
47132305Sstevel 		pcic->irq_current->intr =
47142305Sstevel 		    (ddi_intr_handler_t *)handler->handler;
47152305Sstevel 		pcic->irq_current->handler_id = handler->handler_id;
47162305Sstevel 		pcic->irq_current->arg1 = handler->arg1;
47172305Sstevel 		pcic->irq_current->arg2 = handler->arg2;
47182305Sstevel 		pcic->irq_current->socket = handler->socket;
47192305Sstevel 
47202305Sstevel 		mutex_exit(&pcic->intr_lock);
47212305Sstevel 
47222305Sstevel 		handler->iblk_cookie = &pcic->pc_pri;
47232305Sstevel 		handler->idev_cookie = &pcic->pc_dcookie;
47242305Sstevel 		break;
47252305Sstevel 
47262305Sstevel 	default:
47272305Sstevel 		intr->intr = (ddi_intr_handler_t *)handler->handler;
47282305Sstevel 		intr->handler_id = handler->handler_id;
47292305Sstevel 		intr->arg1 = handler->arg1;
47302305Sstevel 		intr->arg2 = handler->arg2;
47312305Sstevel 		intr->socket = handler->socket;
47322305Sstevel 		intr->irq = handler->irq;
47332305Sstevel 
47342305Sstevel 		/*
47352305Sstevel 		 * need to revisit this to see if interrupts can be
47362305Sstevel 		 * shared someday. Note that IRQ is set in the common
47372305Sstevel 		 * code.
47382305Sstevel 		 */
47392305Sstevel 		mutex_enter(&pcic->pc_lock);
47402305Sstevel 		if (pcic->pc_handlers == NULL) {
47412305Sstevel 			pcic->pc_handlers = intr;
47422305Sstevel 			intr->next = intr->prev = intr;
47432305Sstevel 		} else {
47442305Sstevel 			insque(intr, pcic->pc_handlers);
47452305Sstevel 		}
47462305Sstevel 		mutex_exit(&pcic->pc_lock);
47472305Sstevel 
47482305Sstevel 		break;
47492305Sstevel 	}
47502305Sstevel 
47512305Sstevel 	/*
47522305Sstevel 	 * need to fill in cookies in event of multiple high priority
47532305Sstevel 	 * interrupt handlers on same IRQ
47542305Sstevel 	 */
47552305Sstevel 
47562305Sstevel #if defined(PCIC_DEBUG)
47572305Sstevel 	if (pcic_debug) {
47582305Sstevel 		cmn_err(CE_CONT,
4759*7656SSherry.Moore@Sun.COM 		    "pcic_set_interrupt: exit irq_top=%p value=%d\n",
4760*7656SSherry.Moore@Sun.COM 		    (void *)pcic->irq_top, value);
47612305Sstevel 	}
47622305Sstevel #endif
47632305Sstevel 
47642305Sstevel 	if (value == DDI_SUCCESS) {
47652305Sstevel 		return (SUCCESS);
47662305Sstevel 	} else {
47672305Sstevel 		return (BAD_IRQ);
47682305Sstevel 	}
47692305Sstevel }
47702305Sstevel 
47712305Sstevel /*
47722305Sstevel  * pcic_clear_interrupt()
47732305Sstevel  *	SocketServices ClearInterrupt function
47742305Sstevel  *
47752305Sstevel  *	Interrupts for PCIC are complicated by the fact that we must
47762305Sstevel  *	follow several different models for interrupts.
47772305Sstevel  *	ISA: there is an interrupt per adapter and per socket and
47782305Sstevel  *		they can't be shared.
47792305Sstevel  *	PCI: some adapters have one PCI interrupt available while others
47802305Sstevel  *		have up to 4.  Solaris may or may not allow us to use more
47812305Sstevel  *		than 1 so we essentially share them all at this point.
47822305Sstevel  *	Hybrid: PCI bridge but interrupts wired to host interrupt controller.
47832305Sstevel  *		This is like ISA but we have to fudge and create an intrspec
47842305Sstevel  *		that PCI's parent understands and bypass the PCI nexus.
47852305Sstevel  *	multifunction: this requires sharing the interrupts on a per-socket
47862305Sstevel  *		basis.
47872305Sstevel  */
47882305Sstevel static int
47892305Sstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
47902305Sstevel {
47912305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
47922305Sstevel 	pcicdev_t *pcic = anp->an_private;
47932305Sstevel 	inthandler_t *intr, *prev, *current;
47942305Sstevel 	int i;
47952305Sstevel 
47962305Sstevel 	/*
47972305Sstevel 	 * If we're on a PCI bus, we route all IO IRQs through a single
47982305Sstevel 	 *	PCI interrupt (typically INT A#) so we don't have to do
47992305Sstevel 	 *	much other than remove the caller from the general
48002305Sstevel 	 *	interrupt handler callout list.
48012305Sstevel 	 */
48022305Sstevel 
48032305Sstevel #if defined(PCIC_DEBUG)
48042305Sstevel 	if (pcic_debug) {
48052305Sstevel 		cmn_err(CE_CONT,
4806*7656SSherry.Moore@Sun.COM 		    "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n",
4807*7656SSherry.Moore@Sun.COM 		    pcic->pc_intr_mode);
48082305Sstevel 		cmn_err(CE_CONT,
4809*7656SSherry.Moore@Sun.COM 		    "\t irq_top=%p handler=%p handler_id=%x\n",
4810*7656SSherry.Moore@Sun.COM 		    (void *)pcic->irq_top, (void *)handler->handler,
4811*7656SSherry.Moore@Sun.COM 		    handler->handler_id);
48122305Sstevel 	}
48132305Sstevel #endif
48142305Sstevel 
48152305Sstevel 	switch (pcic->pc_intr_mode) {
48162305Sstevel 	case PCIC_INTR_MODE_PCI_1:
48172305Sstevel 
48182305Sstevel 		mutex_enter(&pcic->intr_lock);
48192305Sstevel 		if (pcic->irq_top == NULL) {
48202305Sstevel 			mutex_exit(&pcic->intr_lock);
48212305Sstevel 			return (BAD_IRQ);
48222305Sstevel 		}
48232305Sstevel 
48242305Sstevel 		intr = NULL;
48252305Sstevel 		pcic->irq_current = pcic->irq_top;
48262305Sstevel 
48272305Sstevel 		while ((pcic->irq_current != NULL) &&
4828*7656SSherry.Moore@Sun.COM 		    (pcic->irq_current->handler_id !=
4829*7656SSherry.Moore@Sun.COM 		    handler->handler_id)) {
48302305Sstevel 			intr = pcic->irq_current;
48312305Sstevel 			pcic->irq_current = pcic->irq_current->next;
48322305Sstevel 		}
48332305Sstevel 
48342305Sstevel 		if (pcic->irq_current == NULL) {
48352305Sstevel 			mutex_exit(&pcic->intr_lock);
48362305Sstevel 			return (BAD_IRQ);
48372305Sstevel 		}
48382305Sstevel 
48392305Sstevel 		if (intr != NULL) {
48402305Sstevel 			intr->next = pcic->irq_current->next;
48412305Sstevel 		} else {
48422305Sstevel 			pcic->irq_top = pcic->irq_current->next;
48432305Sstevel 		}
48442305Sstevel 
48452305Sstevel 		current = pcic->irq_current;
48462305Sstevel 		pcic->irq_current = pcic->irq_top;
48472305Sstevel 		mutex_exit(&pcic->intr_lock);
48482305Sstevel 		kmem_free(current, sizeof (inthandler_t));
48492305Sstevel 
48502305Sstevel 		break;
48512305Sstevel 
48522305Sstevel 	default:
48532305Sstevel 
48542305Sstevel 		mutex_enter(&pcic->pc_lock);
48552305Sstevel 		intr = pcic_handlers;
48562305Sstevel 		prev = (inthandler_t *)&pcic_handlers;
48572305Sstevel 
48582305Sstevel 		while (intr != NULL) {
4859*7656SSherry.Moore@Sun.COM 			if (intr->handler_id == handler->handler_id) {
48602305Sstevel 			i = intr->irq & PCIC_INTR_MASK;
48612305Sstevel 			if (--pcic_irq_map[i].count == 0) {
48622305Sstevel 				/* multi-handler form */
48632305Sstevel 				(void) ddi_intr_disable(pcic->pc_intr_htblp[i]);
48642305Sstevel 				(void) ddi_intr_remove_handler(
48652305Sstevel 				    pcic->pc_intr_htblp[i]);
48662305Sstevel 				(void) ddi_intr_free(pcic->pc_intr_htblp[i]);
48672305Sstevel 				(void) pcmcia_return_intr(pcic->dip, i);
48682305Sstevel #if defined(PCIC_DEBUG)
48692305Sstevel 				if (pcic_debug) {
48702305Sstevel 					cmn_err(CE_CONT,
4871*7656SSherry.Moore@Sun.COM 					    "removing interrupt %d at %s "
4872*7656SSherry.Moore@Sun.COM 					    "priority\n", i, "high");
48732305Sstevel 					cmn_err(CE_CONT,
4874*7656SSherry.Moore@Sun.COM 					    "ddi_remove_intr(%p, %x, %p)\n",
4875*7656SSherry.Moore@Sun.COM 					    (void *)dip,
4876*7656SSherry.Moore@Sun.COM 					    0,
4877*7656SSherry.Moore@Sun.COM 					    (void *)intr->iblk_cookie);
48782305Sstevel 				}
48792305Sstevel #endif
48802305Sstevel 			}
48812305Sstevel 			prev->next = intr->next;
48822305Sstevel 			kmem_free(intr, sizeof (inthandler_t));
48832305Sstevel 			intr = prev->next;
4884*7656SSherry.Moore@Sun.COM 			} else {
48852305Sstevel 			prev = intr;
48862305Sstevel 			intr = intr->next;
4887*7656SSherry.Moore@Sun.COM 			} /* if (handler_id) */
48882305Sstevel 		} /* while */
48892305Sstevel 
48902305Sstevel 		mutex_exit(&pcic->pc_lock);
48912305Sstevel 	}
48922305Sstevel 
48932305Sstevel #if defined(PCIC_DEBUG)
48942305Sstevel 	if (pcic_debug) {
48952305Sstevel 		cmn_err(CE_CONT,
4896*7656SSherry.Moore@Sun.COM 		    "pcic_clear_interrupt: exit irq_top=%p\n",
4897*7656SSherry.Moore@Sun.COM 		    (void *)pcic->irq_top);
48982305Sstevel 	}
48992305Sstevel #endif
49002305Sstevel 
49012305Sstevel 
49022305Sstevel 	return (SUCCESS);
49032305Sstevel }
49042305Sstevel 
49052305Sstevel struct intel_regs {
49062305Sstevel 	char *name;
49072305Sstevel 	int   off;
49082305Sstevel 	char *fmt;
49092305Sstevel } iregs[] = {
49102305Sstevel 	{"ident     ", 0},
49112305Sstevel 	{"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"},
49122305Sstevel 	{"power     ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO"
49132305Sstevel 		"\7DRD\10OE"},
49142305Sstevel 	{"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"},
49152305Sstevel 	{"enable    ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"},
49162305Sstevel 	{"cd-gcr    ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"},
49172305Sstevel 	{"GCR       ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"},
49182305Sstevel 	{"int-gcr   ", 3, "\020\5INTR\6IO\7~RST\10RI"},
49192305Sstevel 	{"management", 5, "\020\1BDE\2BWE\3RE\4CDE"},
49202305Sstevel 	{"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"},
49212305Sstevel 	{"volt-sel  ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"},
49222305Sstevel 	{"VG ext A  ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"},
49232305Sstevel 	{"io-ctrl   ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"},
49242305Sstevel 	{"io0-slow  ", 8},
49252305Sstevel 	{"io0-shi   ", 9},
49262305Sstevel 	{"io0-elow  ", 0xa},
49272305Sstevel 	{"io0-ehi   ", 0xb},
49282305Sstevel 	{"io1-slow  ", 0xc},
49292305Sstevel 	{"io1-shi   ", 0xd},
49302305Sstevel 	{"io1-elow  ", 0xe},
49312305Sstevel 	{"io1-ehi   ", 0xf},
49322305Sstevel 	{"mem0-slow ", 0x10},
49332305Sstevel 	{"mem0-shi  ", 0x11, "\020\7ZW\10DS"},
49342305Sstevel 	{"mem0-elow ", 0x12},
49352305Sstevel 	{"mem0-ehi  ", 0x13, "\020\7WS0\10WS1"},
49362305Sstevel 	{"card0-low ", 0x14},
49372305Sstevel 	{"card0-hi  ", 0x15, "\020\7AM\10WP"},
49382305Sstevel 	{"mem1-slow ", 0x18},
49392305Sstevel 	{"mem1-shi  ", 0x19, "\020\7ZW\10DS"},
49402305Sstevel 	{"mem1-elow ", 0x1a},
49412305Sstevel 	{"mem1-ehi  ", 0x1b, "\020\7WS0\10WS1"},
49422305Sstevel 	{"card1-low ", 0x1c},
49432305Sstevel 	{"card1-hi  ", 0x1d, "\020\7AM\10WP"},
49442305Sstevel 	{"mem2-slow ", 0x20},
49452305Sstevel 	{"mem2-shi  ", 0x21, "\020\7ZW\10DS"},
49462305Sstevel 	{"mem2-elow ", 0x22},
49472305Sstevel 	{"mem2-ehi  ", 0x23, "\020\7WS0\10WS1"},
49482305Sstevel 	{"card2-low ", 0x24},
49492305Sstevel 	{"card2-hi  ", 0x25, "\020\7AM\10WP"},
49502305Sstevel 	{"mem3-slow ", 0x28},
49512305Sstevel 	{"mem3-shi  ", 0x29, "\020\7ZW\10DS"},
49522305Sstevel 	{"mem3-elow ", 0x2a},
49532305Sstevel 	{"mem3-ehi  ", 0x2b, "\020\7WS0\10WS1"},
49542305Sstevel 	{"card3-low ", 0x2c},
49552305Sstevel 	{"card3-hi  ", 0x2d, "\020\7AM\10WP"},
49562305Sstevel 
49572305Sstevel 	{"mem4-slow ", 0x30},
49582305Sstevel 	{"mem4-shi  ", 0x31, "\020\7ZW\10DS"},
49592305Sstevel 	{"mem4-elow ", 0x32},
49602305Sstevel 	{"mem4-ehi  ", 0x33, "\020\7WS0\10WS1"},
49612305Sstevel 	{"card4-low ", 0x34},
49622305Sstevel 	{"card4-hi  ", 0x35, "\020\7AM\10WP"},
49632305Sstevel 	{"mpage0    ", 0x40},
49642305Sstevel 	{"mpage1    ", 0x41},
49652305Sstevel 	{"mpage2    ", 0x42},
49662305Sstevel 	{"mpage3    ", 0x43},
49672305Sstevel 	{"mpage4    ", 0x44},
49682305Sstevel 	{NULL},
49692305Sstevel };
49702305Sstevel 
49712305Sstevel static struct intel_regs cregs[] = {
49722305Sstevel 	{"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"},
49732305Sstevel 	{"fifo      ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"},
49742305Sstevel 	{"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"},
49752305Sstevel 	{"chip-info ", 0x1f, "\20\6DUAL"},
49762305Sstevel 	{"IO-offlow0", 0x36},
49772305Sstevel 	{"IO-offhi0 ", 0x37},
49782305Sstevel 	{"IO-offlow1", 0x38},
49792305Sstevel 	{"IO-offhi1 ", 0x39},
49802305Sstevel 	NULL,
49812305Sstevel };
49822305Sstevel 
49832305Sstevel static struct intel_regs cxregs[] = {
49842305Sstevel 	{"ext-ctl-1 ", 0x03,
49852305Sstevel 		"\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"},
49862305Sstevel 	{"misc-ctl3 ", 0x25, "\20\5HWSUSP"},
49872305Sstevel 	{"mem0-up   ", 0x05},
49882305Sstevel 	{"mem1-up   ", 0x06},
49892305Sstevel 	{"mem2-up   ", 0x07},
49902305Sstevel 	{"mem3-up   ", 0x08},
49912305Sstevel 	{"mem4-up   ", 0x09},
49922305Sstevel 	{NULL}
49932305Sstevel };
49942305Sstevel 
49952305Sstevel void
49962305Sstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len)
49972305Sstevel {
49982305Sstevel 	int i, value, j;
49992305Sstevel 	char buff[256];
50002305Sstevel 	char *fmt;
50012305Sstevel 
50022305Sstevel 	cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n");
50032305Sstevel 	for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) {
50042305Sstevel 		int sval;
50052305Sstevel 		if (cregs[i].off == PCIC_MISC_CTL_2)
50062305Sstevel 			sval = 0;
50072305Sstevel 		else
50082305Sstevel 			sval = socket;
50092305Sstevel 		value = pcic_getb(pcic, sval, cregs[i].off);
50102305Sstevel 		if (i & 1) {
50112305Sstevel 			if (cregs[i].fmt)
50122305Sstevel 				fmt = "%s\t%s\t%b\n";
50132305Sstevel 			else
50142305Sstevel 				fmt = "%s\t%s\t%x\n";
50152305Sstevel 			cmn_err(CE_CONT, fmt, buff,
5016*7656SSherry.Moore@Sun.COM 			    cregs[i].name, value, cregs[i].fmt);
50172305Sstevel 			buff[0] = '\0';
50182305Sstevel 		} else {
50192305Sstevel 			if (cregs[i].fmt)
50202305Sstevel 				fmt = "\t%s\t%b";
50212305Sstevel 			else
50222305Sstevel 				fmt = "\t%s\t%x";
50232305Sstevel 			(void) sprintf(buff, fmt,
5024*7656SSherry.Moore@Sun.COM 			    cregs[i].name, value, cregs[i].fmt);
50252305Sstevel 			for (j = strlen(buff); j < 40; j++)
50262305Sstevel 				buff[j] = ' ';
50272305Sstevel 			buff[40] = '\0';
50282305Sstevel 		}
50292305Sstevel 	}
50302305Sstevel 	cmn_err(CE_CONT, "%s\n", buff);
50312305Sstevel 
50322305Sstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0);
50332305Sstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1);
50342305Sstevel 	cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j);
50352305Sstevel 
50362305Sstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0);
50372305Sstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1);
50382305Sstevel 	cmn_err(CE_CONT, "\tcmd-tim0  \t%x\tcmd-tim1  \t%x\n", i, j);
50392305Sstevel 
50402305Sstevel 	i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0);
50412305Sstevel 	j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1);
50422305Sstevel 	cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j);
50432305Sstevel 
50442305Sstevel 	cmn_err(CE_CONT, "--------- Extended Registers  --------\n");
50452305Sstevel 
50462305Sstevel 	for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) {
50472305Sstevel 		value = clext_reg_read(pcic, socket, cxregs[i].off);
50482305Sstevel 		if (i & 1) {
50492305Sstevel 			if (cxregs[i].fmt)
50502305Sstevel 				fmt = "%s\t%s\t%b\n";
50512305Sstevel 			else
50522305Sstevel 				fmt = "%s\t%s\t%x\n";
50532305Sstevel 			cmn_err(CE_CONT, fmt, buff,
5054*7656SSherry.Moore@Sun.COM 			    cxregs[i].name, value, cxregs[i].fmt);
50552305Sstevel 			buff[0] = '\0';
50562305Sstevel 		} else {
50572305Sstevel 			if (cxregs[i].fmt)
50582305Sstevel 				fmt = "\t%s\t%b";
50592305Sstevel 			else
50602305Sstevel 				fmt = "\t%s\t%x";
50612305Sstevel 			(void) sprintf(buff, fmt,
5062*7656SSherry.Moore@Sun.COM 			    cxregs[i].name, value, cxregs[i].fmt);
50632305Sstevel 			for (j = strlen(buff); j < 40; j++)
50642305Sstevel 				buff[j] = ' ';
50652305Sstevel 			buff[40] = '\0';
50662305Sstevel 		}
50672305Sstevel 	}
50682305Sstevel }
50692305Sstevel 
50702305Sstevel #if defined(PCIC_DEBUG)
50712305Sstevel static void
50722305Sstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len)
50732305Sstevel {
50742305Sstevel 	int i, value, j;
50752305Sstevel 	char buff[256];
50762305Sstevel 	char *fmt;
50772305Sstevel 
50782305Sstevel #if defined(PCIC_DEBUG)
50792305Sstevel 	if (pcic_debug < 2)
50802305Sstevel 		return;
50812305Sstevel #endif
50822305Sstevel 	cmn_err(CE_CONT,
5083*7656SSherry.Moore@Sun.COM 	    "----------- PCIC Registers for socket %d---------\n",
5084*7656SSherry.Moore@Sun.COM 	    socket);
50852305Sstevel 	cmn_err(CE_CONT,
5086*7656SSherry.Moore@Sun.COM 	    "\tname       value	                name       value\n");
50872305Sstevel 
50882305Sstevel 	for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) {
50892305Sstevel 		value = pcic_getb(pcic, socket, iregs[i].off);
50902305Sstevel 		if (i & 1) {
50912305Sstevel 			if (iregs[i].fmt)
50922305Sstevel 				fmt = "%s\t%s\t%b\n";
50932305Sstevel 			else
50942305Sstevel 				fmt = "%s\t%s\t%x\n";
50952305Sstevel 			cmn_err(CE_CONT, fmt, buff,
5096*7656SSherry.Moore@Sun.COM 			    iregs[i].name, value, iregs[i].fmt);
50972305Sstevel 			buff[0] = '\0';
50982305Sstevel 		} else {
50992305Sstevel 			if (iregs[i].fmt)
51002305Sstevel 				fmt = "\t%s\t%b";
51012305Sstevel 			else
51022305Sstevel 				fmt = "\t%s\t%x";
51032305Sstevel 			(void) sprintf(buff, fmt,
5104*7656SSherry.Moore@Sun.COM 			    iregs[i].name, value, iregs[i].fmt);
51052305Sstevel 			for (j = strlen(buff); j < 40; j++)
51062305Sstevel 				buff[j] = ' ';
51072305Sstevel 			buff[40] = '\0';
51082305Sstevel 		}
51092305Sstevel 	}
51102305Sstevel 	switch (pcic->pc_type) {
51112305Sstevel 	case PCIC_CL_PD6710:
51122305Sstevel 	case PCIC_CL_PD6722:
51132305Sstevel 	case PCIC_CL_PD6729:
51142305Sstevel 	case PCIC_CL_PD6832:
51152305Sstevel 		(void) xxdmp_cl_regs(pcic, socket, 0xFFFF);
51162305Sstevel 		break;
51172305Sstevel 	}
51182305Sstevel 	cmn_err(CE_CONT, "%s\n", buff);
51192305Sstevel }
51202305Sstevel #endif
51212305Sstevel 
51222305Sstevel /*
51232305Sstevel  * pcic_mswait(ms)
51242305Sstevel  *	sleep ms milliseconds
51252305Sstevel  *	call drv_usecwait once for each ms
51262305Sstevel  */
51272305Sstevel static void
51282305Sstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms)
51292305Sstevel {
51302305Sstevel 	if (ms) {
51312305Sstevel 		pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING;
51322305Sstevel 		pcic_mutex_exit(&pcic->pc_lock);
51332305Sstevel 		delay(drv_usectohz(ms*1000));
51342305Sstevel 		pcic_mutex_enter(&pcic->pc_lock);
51352305Sstevel 		pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING;
51362305Sstevel 	}
51372305Sstevel }
51382305Sstevel 
51392305Sstevel /*
51402305Sstevel  * pcic_check_ready(pcic, index, off)
51412305Sstevel  *      Wait for card to come ready
51422305Sstevel  *      We only wait if the card is NOT in RESET
51432305Sstevel  *      and power is on.
51442305Sstevel  */
51452305Sstevel static boolean_t
51462305Sstevel pcic_check_ready(pcicdev_t *pcic, int socket)
51472305Sstevel {
51482305Sstevel 	int ifstate, intstate;
51492305Sstevel 
51502305Sstevel 	intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT);
51512305Sstevel 	ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS);
51522305Sstevel 
51532305Sstevel 	if ((intstate & PCIC_RESET) &&
51542305Sstevel 	    ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) ==
51552305Sstevel 	    (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK)))
51562305Sstevel 		return (B_TRUE);
51572305Sstevel 
51582305Sstevel #ifdef  PCIC_DEBUG
51592305Sstevel 	pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, "
51602305Sstevel 	    "ifstate = 0x%x\n", intstate, ifstate);
51612305Sstevel 	if (pcic_debug) {
51622305Sstevel 		pcic_debug += 4;
51632305Sstevel 		xxdmp_all_regs(pcic, socket, -1);
51642305Sstevel 		pcic_debug -= 4;
51652305Sstevel 	}
51662305Sstevel #endif
51672305Sstevel 	return (B_FALSE);
51682305Sstevel }
51692305Sstevel 
51702305Sstevel /*
51712305Sstevel  * Cirrus Logic extended register read/write routines
51722305Sstevel  */
51732305Sstevel static int
51742305Sstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg)
51752305Sstevel {
51762305Sstevel 	int val;
51772305Sstevel 
51782305Sstevel 	switch (pcic->pc_io_type) {
51792305Sstevel 	case PCIC_IO_TYPE_YENTA:
51802305Sstevel 		val = ddi_get8(pcic->handle,
51812305Sstevel 		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg);
51822305Sstevel 		break;
51832305Sstevel 	default:
51842305Sstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
51852305Sstevel 		val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1);
51862305Sstevel 		break;
51872305Sstevel 	}
51882305Sstevel 
51892305Sstevel 	return (val);
51902305Sstevel }
51912305Sstevel 
51922305Sstevel static void
51932305Sstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value)
51942305Sstevel {
51952305Sstevel 	switch (pcic->pc_io_type) {
51962305Sstevel 	case PCIC_IO_TYPE_YENTA:
51972305Sstevel 		ddi_put8(pcic->handle,
51982305Sstevel 		    pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value);
51992305Sstevel 		break;
52002305Sstevel 	default:
52012305Sstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52022305Sstevel 		pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value);
52032305Sstevel 		break;
52042305Sstevel 	}
52052305Sstevel }
52062305Sstevel 
52072305Sstevel /*
52082305Sstevel  * Misc PCI functions
52092305Sstevel  */
52102305Sstevel static void
52112305Sstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags)
52122305Sstevel {
52132305Sstevel 	unsigned cmd;
52142305Sstevel 
52152305Sstevel 	if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) {
52162305Sstevel 		cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4));
52172305Sstevel 		if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) ==
52182305Sstevel 		    (PCI_COMM_IO|PCI_COMM_MAE))
52192305Sstevel 			return;
52202305Sstevel 
52212305Sstevel 		if (flags & PCIC_ENABLE_IO)
5222*7656SSherry.Moore@Sun.COM 			cmd |= PCI_COMM_IO;
52232305Sstevel 
52242305Sstevel 		if (flags & PCIC_ENABLE_MEM)
5225*7656SSherry.Moore@Sun.COM 			cmd |= PCI_COMM_MAE;
52262305Sstevel 
52272305Sstevel 		ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd);
52282305Sstevel 	} /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */
52292305Sstevel }
52302305Sstevel 
52312305Sstevel /*
52322305Sstevel  * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type
52332305Sstevel  */
52342305Sstevel static int
52352305Sstevel pcic_find_pci_type(pcicdev_t *pcic)
52362305Sstevel {
52372305Sstevel 	uint32_t vend, device;
52382305Sstevel 
52392305Sstevel 	vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
5240*7656SSherry.Moore@Sun.COM 	    DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
5241*7656SSherry.Moore@Sun.COM 	    "vendor-id", -1);
52422305Sstevel 	device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
5243*7656SSherry.Moore@Sun.COM 	    DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
5244*7656SSherry.Moore@Sun.COM 	    "device-id", -1);
52452305Sstevel 
52462305Sstevel 	device = PCI_ID(vend, device);
52472305Sstevel 	pcic->pc_type = device;
52482305Sstevel 	pcic->pc_chipname = "PCI:unknown";
52492305Sstevel 
52502305Sstevel 	switch (device) {
52512305Sstevel 	case PCIC_INTEL_i82092:
52522305Sstevel 		pcic->pc_chipname = PCIC_TYPE_i82092;
52532305Sstevel 		break;
52542305Sstevel 	case PCIC_CL_PD6729:
52552305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PD6729;
52562305Sstevel 		/*
52572305Sstevel 		 * Some 6730's incorrectly identify themselves
52582305Sstevel 		 *	as a 6729, so we need to do some more tests
52592305Sstevel 		 *	here to see if the device that's claiming
52602305Sstevel 		 *	to be a 6729 is really a 6730.
52612305Sstevel 		 */
52622305Sstevel 		if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) &
5263*7656SSherry.Moore@Sun.COM 		    PCIC_CLEXT_MISC_CTL_3_REV_MASK) ==
5264*7656SSherry.Moore@Sun.COM 		    0) {
52652305Sstevel 			pcic->pc_chipname = PCIC_TYPE_PD6730;
52662305Sstevel 			pcic->pc_type = PCIC_CL_PD6730;
52672305Sstevel 		}
52682305Sstevel 		break;
52692305Sstevel 	case PCIC_CL_PD6730:
52702305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PD6730;
52712305Sstevel 		break;
52722305Sstevel 	case PCIC_CL_PD6832:
52732305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PD6832;
52742305Sstevel 		break;
52752305Sstevel 	case PCIC_SMC_34C90:
52762305Sstevel 		pcic->pc_chipname = PCIC_TYPE_34C90;
52772305Sstevel 		break;
52782305Sstevel 	case PCIC_TOSHIBA_TOPIC95:
52792305Sstevel 		pcic->pc_chipname = PCIC_TYPE_TOPIC95;
52802305Sstevel 		break;
52812305Sstevel 	case PCIC_TOSHIBA_TOPIC100:
52822305Sstevel 		pcic->pc_chipname = PCIC_TYPE_TOPIC100;
52832305Sstevel 		break;
52842305Sstevel 	case PCIC_TI_PCI1031:
52852305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1031;
52862305Sstevel 		break;
52872305Sstevel 	case PCIC_TI_PCI1130:
52882305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1130;
52892305Sstevel 		break;
52902305Sstevel 	case PCIC_TI_PCI1131:
52912305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1131;
52922305Sstevel 		break;
52932305Sstevel 	case PCIC_TI_PCI1250:
52942305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1250;
52952305Sstevel 		break;
52962305Sstevel 	case PCIC_TI_PCI1225:
52972305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1225;
52982305Sstevel 		break;
52992305Sstevel 	case PCIC_TI_PCI1410:
53002305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1410;
53012305Sstevel 		break;
53022305Sstevel 	case PCIC_TI_PCI1510:
53032305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1510;
53042305Sstevel 		break;
53052305Sstevel 	case PCIC_TI_PCI1520:
53062305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1520;
53072305Sstevel 		break;
53082305Sstevel 	case PCIC_TI_PCI1221:
53092305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1221;
53102305Sstevel 		break;
53112305Sstevel 	case PCIC_TI_PCI1050:
53122305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1050;
53132305Sstevel 		break;
53142305Sstevel 	case PCIC_ENE_1410:
53152305Sstevel 		pcic->pc_chipname = PCIC_TYPE_1410;
53162305Sstevel 		break;
53172305Sstevel 	case PCIC_O2_OZ6912:
53182305Sstevel 		pcic->pc_chipname = PCIC_TYPE_OZ6912;
53192305Sstevel 		break;
53202305Sstevel 	case PCIC_RICOH_RL5C466:
53212305Sstevel 		pcic->pc_chipname = PCIC_TYPE_RL5C466;
53222305Sstevel 		break;
53232305Sstevel 	case PCIC_TI_PCI1420:
53242305Sstevel 		pcic->pc_chipname = PCIC_TYPE_PCI1420;
53252305Sstevel 		break;
53262305Sstevel 	case PCIC_ENE_1420:
53272305Sstevel 		pcic->pc_chipname = PCIC_TYPE_1420;
53282305Sstevel 		break;
53292305Sstevel 	default:
53302305Sstevel 		switch (PCI_ID(vend, (uint32_t)0)) {
53312305Sstevel 		case PCIC_TOSHIBA_VENDOR:
53322305Sstevel 			pcic->pc_chipname = PCIC_TYPE_TOSHIBA;
53332305Sstevel 			pcic->pc_type = PCIC_TOSHIBA_VENDOR;
53342305Sstevel 			break;
53352305Sstevel 		case PCIC_TI_VENDOR:
53362305Sstevel 			pcic->pc_chipname = PCIC_TYPE_TI;
53372305Sstevel 			pcic->pc_type = PCIC_TI_VENDOR;
53382305Sstevel 			break;
53392305Sstevel 		case PCIC_O2MICRO_VENDOR:
53402305Sstevel 			pcic->pc_chipname = PCIC_TYPE_O2MICRO;
53412305Sstevel 			pcic->pc_type = PCIC_O2MICRO_VENDOR;
53422305Sstevel 			break;
53432305Sstevel 		case PCIC_RICOH_VENDOR:
53442305Sstevel 			pcic->pc_chipname = PCIC_TYPE_RICOH;
53452305Sstevel 			pcic->pc_type = PCIC_RICOH_VENDOR;
53462305Sstevel 			break;
53472305Sstevel 		default:
53482305Sstevel 			if (!(pcic->pc_flags & PCF_CARDBUS))
53492305Sstevel 				return (DDI_FAILURE);
53502305Sstevel 			pcic->pc_chipname = PCIC_TYPE_YENTA;
53512305Sstevel 			break;
53522305Sstevel 		}
53532305Sstevel 	}
53542305Sstevel 	return (DDI_SUCCESS);
53552305Sstevel }
53562305Sstevel 
53572305Sstevel static void
53582305Sstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state)
53592305Sstevel {
53602305Sstevel 	uchar_t ppirr = ddi_get8(pcic->cfg_handle,
5361*7656SSherry.Moore@Sun.COM 	    pcic->cfgaddr + PCIC_82092_PPIRR);
53622305Sstevel 	uchar_t val;
53632305Sstevel 
53642305Sstevel 	if (intr == PCIC_82092_CTL_SMI) {
53652305Sstevel 		val = PCIC_82092_SMI_CTL(socket,
5366*7656SSherry.Moore@Sun.COM 		    PCIC_82092_INT_DISABLE);
53672305Sstevel 		ppirr &= ~val;
53682305Sstevel 		val = PCIC_82092_SMI_CTL(socket, state);
53692305Sstevel 		ppirr |= val;
53702305Sstevel 	} else {
53712305Sstevel 		val = PCIC_82092_IRQ_CTL(socket,
5372*7656SSherry.Moore@Sun.COM 		    PCIC_82092_INT_DISABLE);
53732305Sstevel 		ppirr &= ~val;
53742305Sstevel 		val = PCIC_82092_IRQ_CTL(socket, state);
53752305Sstevel 		ppirr |= val;
53762305Sstevel 	}
53772305Sstevel 	ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR,
5378*7656SSherry.Moore@Sun.COM 	    ppirr);
53792305Sstevel }
53802305Sstevel 
53812305Sstevel static uint_t
53822305Sstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2)
53832305Sstevel {
53842305Sstevel 	pcic_socket_t *sockp = (pcic_socket_t *)arg1;
53852305Sstevel 	uint_t rc = DDI_INTR_UNCLAIMED;
53862305Sstevel 
53872305Sstevel 	_NOTE(ARGUNUSED(arg2))
53882305Sstevel 
53892305Sstevel 	mutex_enter(&sockp->pcs_pcic->pc_lock);
53902305Sstevel 	if (sockp->pcs_cd_softint_flg) {
53912305Sstevel 		uint8_t status;
53922305Sstevel 		sockp->pcs_cd_softint_flg = 0;
53932305Sstevel 		rc = DDI_INTR_CLAIMED;
53942305Sstevel 		status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket,
5395*7656SSherry.Moore@Sun.COM 		    PCIC_INTERFACE_STATUS);
53962305Sstevel 		pcic_handle_cd_change(sockp->pcs_pcic, sockp, status);
53972305Sstevel 	}
53982305Sstevel 	mutex_exit(&sockp->pcs_pcic->pc_lock);
53992305Sstevel 	return (rc);
54002305Sstevel }
54012305Sstevel 
54022305Sstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT;
54032305Sstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME;
54042305Sstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT;
54052305Sstevel 
54062305Sstevel #ifdef CARDBUS
54072305Sstevel static uint32_t pcic_cbps_on = 0;
54082305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54092305Sstevel 				CB_PS_XVCARD | CB_PS_YVCARD;
54102305Sstevel #else
54112305Sstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD;
54122305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54132305Sstevel 				CB_PS_CBCARD |
54142305Sstevel 				CB_PS_XVCARD | CB_PS_YVCARD;
54152305Sstevel #endif
54162305Sstevel static void
54172305Sstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status)
54182305Sstevel {
54192305Sstevel 	boolean_t	do_debounce = B_FALSE;
54202305Sstevel 	int		debounce_time = drv_usectohz(pcic_debounce_time);
54212305Sstevel 	uint8_t		irq;
54222305Sstevel 	timeout_id_t	debounce;
54232305Sstevel 
54242305Sstevel 	/*
54252305Sstevel 	 * Always reset debounce but may need to check original state later.
54262305Sstevel 	 */
54272305Sstevel 	debounce = sockp->pcs_debounce_id;
54282305Sstevel 	sockp->pcs_debounce_id = 0;
54292305Sstevel 
54302305Sstevel 	/*
54312305Sstevel 	 * Check to see whether a card is present or not. There are
54322305Sstevel 	 *	only two states that we are concerned with - the state
54332305Sstevel 	 *	where both CD pins are asserted, which means that the
54342305Sstevel 	 *	card is fully seated, and the state where neither CD
54352305Sstevel 	 *	pin is asserted, which means that the card is not
54362305Sstevel 	 *	present.
54372305Sstevel 	 * The CD signals are generally very noisy and cause a lot of
54382305Sstevel 	 *	contact bounce as the card is being inserted and
54392305Sstevel 	 *	removed, so we need to do some software debouncing.
54402305Sstevel 	 */
54412305Sstevel 
54422305Sstevel #ifdef PCIC_DEBUG
5443*7656SSherry.Moore@Sun.COM 		pcic_err(pcic->dip, 6,
54442305Sstevel 		    "pcic%d handle_cd_change: socket %d card status 0x%x"
54452305Sstevel 		    " deb 0x%p\n", ddi_get_instance(pcic->dip),
54462305Sstevel 		    sockp->pcs_socket, status, debounce);
54472305Sstevel #endif
54482305Sstevel 	switch (status & PCIC_ISTAT_CD_MASK) {
54492305Sstevel 	case PCIC_CD_PRESENT_OK:
5450*7656SSherry.Moore@Sun.COM 		sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM);
5451*7656SSherry.Moore@Sun.COM 		if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
54522305Sstevel 		uint32_t cbps;
54532305Sstevel #ifdef PCIC_DEBUG
54542305Sstevel 		pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags);
54552305Sstevel #endif
54562305Sstevel 		cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
54572305Sstevel #ifdef PCIC_DEBUG
54582305Sstevel 		pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps);
54592305Sstevel #endif
54602305Sstevel 		/*
54612305Sstevel 		 * Check the CB bits are sane.
54622305Sstevel 		 */
54632305Sstevel 		if ((cbps & pcic_cbps_on) != pcic_cbps_on ||
54642305Sstevel 		    cbps & pcic_cbps_off) {
5465*7656SSherry.Moore@Sun.COM 			cmn_err(CE_WARN,
54662305Sstevel 			    "%s%d: Odd Cardbus Present State 0x%x\n",
54672305Sstevel 			    ddi_get_name(pcic->dip),
54682305Sstevel 			    ddi_get_instance(pcic->dip),
54692305Sstevel 			    cbps);
5470*7656SSherry.Moore@Sun.COM 			pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST);
5471*7656SSherry.Moore@Sun.COM 			debounce = 0;
5472*7656SSherry.Moore@Sun.COM 			debounce_time = drv_usectohz(1000000);
54732305Sstevel 		}
54742305Sstevel 		if (debounce) {
5475*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags |= PCS_CARD_PRESENT;
5476*7656SSherry.Moore@Sun.COM 			if (pcic_do_insertion) {
5477*7656SSherry.Moore@Sun.COM 
5478*7656SSherry.Moore@Sun.COM 				cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
5479*7656SSherry.Moore@Sun.COM 
5480*7656SSherry.Moore@Sun.COM 				if (cbps & CB_PS_16BITCARD) {
5481*7656SSherry.Moore@Sun.COM 					pcic_err(pcic->dip,
5482*7656SSherry.Moore@Sun.COM 					    8, "16 bit card inserted\n");
5483*7656SSherry.Moore@Sun.COM 					sockp->pcs_flags |= PCS_CARD_IS16BIT;
5484*7656SSherry.Moore@Sun.COM 					/* calls pcm_adapter_callback() */
5485*7656SSherry.Moore@Sun.COM 					if (pcic->pc_callback) {
5486*7656SSherry.Moore@Sun.COM 
5487*7656SSherry.Moore@Sun.COM 						(void) ddi_prop_update_string(
5488*7656SSherry.Moore@Sun.COM 						    DDI_DEV_T_NONE,
5489*7656SSherry.Moore@Sun.COM 						    pcic->dip, PCM_DEVICETYPE,
5490*7656SSherry.Moore@Sun.COM 						    "pccard");
5491*7656SSherry.Moore@Sun.COM 						PC_CALLBACK(pcic->dip,
5492*7656SSherry.Moore@Sun.COM 						    pcic->pc_cb_arg,
5493*7656SSherry.Moore@Sun.COM 						    PCE_CARD_INSERT,
5494*7656SSherry.Moore@Sun.COM 						    sockp->pcs_socket);
5495*7656SSherry.Moore@Sun.COM 					}
5496*7656SSherry.Moore@Sun.COM 				} else if (cbps & CB_PS_CBCARD) {
5497*7656SSherry.Moore@Sun.COM 					pcic_err(pcic->dip,
5498*7656SSherry.Moore@Sun.COM 					    8, "32 bit card inserted\n");
5499*7656SSherry.Moore@Sun.COM 
5500*7656SSherry.Moore@Sun.COM 					if (pcic->pc_flags & PCF_CARDBUS) {
5501*7656SSherry.Moore@Sun.COM 						sockp->pcs_flags |=
5502*7656SSherry.Moore@Sun.COM 						    PCS_CARD_ISCARDBUS;
55032305Sstevel #ifdef CARDBUS
5504*7656SSherry.Moore@Sun.COM 						if (!pcic_load_cardbus(pcic,
5505*7656SSherry.Moore@Sun.COM 						    sockp)) {
5506*7656SSherry.Moore@Sun.COM 							pcic_unload_cardbus(
5507*7656SSherry.Moore@Sun.COM 							    pcic, sockp);
5508*7656SSherry.Moore@Sun.COM 						}
55092305Sstevel 
55102305Sstevel #else
5511*7656SSherry.Moore@Sun.COM 						cmn_err(CE_NOTE,
5512*7656SSherry.Moore@Sun.COM 						    "32 bit Cardbus not"
5513*7656SSherry.Moore@Sun.COM 						    " supported in"
5514*7656SSherry.Moore@Sun.COM 						    " this device driver\n");
55152305Sstevel #endif
5516*7656SSherry.Moore@Sun.COM 					} else {
5517*7656SSherry.Moore@Sun.COM 						/*
5518*7656SSherry.Moore@Sun.COM 						 * Ignore the card
5519*7656SSherry.Moore@Sun.COM 						 */
5520*7656SSherry.Moore@Sun.COM 						cmn_err(CE_NOTE,
5521*7656SSherry.Moore@Sun.COM 						    "32 bit Cardbus not"
5522*7656SSherry.Moore@Sun.COM 						    " supported on this"
5523*7656SSherry.Moore@Sun.COM 						    " device\n");
5524*7656SSherry.Moore@Sun.COM 					}
5525*7656SSherry.Moore@Sun.COM 				} else {
5526*7656SSherry.Moore@Sun.COM 					cmn_err(CE_NOTE,
5527*7656SSherry.Moore@Sun.COM 					    "Unsupported PCMCIA card"
5528*7656SSherry.Moore@Sun.COM 					    " inserted\n");
5529*7656SSherry.Moore@Sun.COM 				}
55302305Sstevel 			}
55312305Sstevel 		} else {
5532*7656SSherry.Moore@Sun.COM 			do_debounce = B_TRUE;
55332305Sstevel 		}
5534*7656SSherry.Moore@Sun.COM 		} else {
55352305Sstevel 		/*
55362305Sstevel 		 * It is possible to come through here if the system
55372305Sstevel 		 * starts up with cards already inserted. Do nothing
55382305Sstevel 		 * and don't worry about it.
55392305Sstevel 		 */
55402305Sstevel #ifdef PCIC_DEBUG
55412305Sstevel 		pcic_err(pcic->dip, 5,
5542*7656SSherry.Moore@Sun.COM 		    "pcic%d: Odd card insertion indication on socket %d\n",
5543*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(pcic->dip),
5544*7656SSherry.Moore@Sun.COM 		    sockp->pcs_socket);
55452305Sstevel #endif
5546*7656SSherry.Moore@Sun.COM 		}
5547*7656SSherry.Moore@Sun.COM 		break;
55482305Sstevel 
55492305Sstevel 	default:
5550*7656SSherry.Moore@Sun.COM 		if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
55512305Sstevel 		/*
55522305Sstevel 		 * Someone has started to insert a card so delay a while.
55532305Sstevel 		 */
55542305Sstevel 		do_debounce = B_TRUE;
55552305Sstevel 		break;
5556*7656SSherry.Moore@Sun.COM 		}
55572305Sstevel 		/*
55582305Sstevel 		 * Otherwise this is basically the same as not present
55592305Sstevel 		 * so fall through.
55602305Sstevel 		 */
55612305Sstevel 
55622305Sstevel 		/* FALLTHRU */
55632305Sstevel 	case 0:
5564*7656SSherry.Moore@Sun.COM 		if (sockp->pcs_flags & PCS_CARD_PRESENT) {
5565*7656SSherry.Moore@Sun.COM 			if (pcic->pc_flags & PCF_CBPWRCTL) {
5566*7656SSherry.Moore@Sun.COM 				pcic_putcb(pcic, CB_CONTROL, 0);
5567*7656SSherry.Moore@Sun.COM 			} else {
5568*7656SSherry.Moore@Sun.COM 				pcic_putb(pcic, sockp->pcs_socket,
5569*7656SSherry.Moore@Sun.COM 				    PCIC_POWER_CONTROL, 0);
5570*7656SSherry.Moore@Sun.COM 			(void) pcic_getb(pcic, sockp->pcs_socket,
5571*7656SSherry.Moore@Sun.COM 			    PCIC_POWER_CONTROL);
55722305Sstevel 		}
55732305Sstevel #ifdef PCIC_DEBUG
55742305Sstevel 		pcic_err(pcic->dip, 8, "Card removed\n");
55752305Sstevel #endif
55762305Sstevel 		sockp->pcs_flags &= ~PCS_CARD_PRESENT;
55772305Sstevel 
55782305Sstevel 		if (sockp->pcs_flags & PCS_CARD_IS16BIT) {
5579*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags &= ~PCS_CARD_IS16BIT;
5580*7656SSherry.Moore@Sun.COM 			if (pcic_do_removal && pcic->pc_callback) {
5581*7656SSherry.Moore@Sun.COM 				PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
55822305Sstevel 				    PCE_CARD_REMOVAL, sockp->pcs_socket);
5583*7656SSherry.Moore@Sun.COM 			}
55842305Sstevel 		}
55852305Sstevel 		if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) {
5586*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS;
5587*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags |= PCS_CARD_CBREM;
55882305Sstevel 		}
55892305Sstevel 		sockp->pcs_flags |= PCS_CARD_REMOVED;
55902305Sstevel 
55912305Sstevel 		do_debounce = B_TRUE;
5592*7656SSherry.Moore@Sun.COM 		}
5593*7656SSherry.Moore@Sun.COM 		if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) {
5594*7656SSherry.Moore@Sun.COM 			if (sockp->pcs_flags & PCS_CARD_CBREM) {
55952305Sstevel 		/*
55962305Sstevel 		 * Ensure that we do the unloading in the
55972305Sstevel 		 * debounce handler, that way we're not doing
55982305Sstevel 		 * nasty things in an interrupt handler. e.g.
55992305Sstevel 		 * a USB device will wait for data which will
56002305Sstevel 		 * obviously never come because we've
56012305Sstevel 		 * unplugged the device, but the wait will
56022305Sstevel 		 * wait forever because no interrupts can
56032305Sstevel 		 * come in...
56042305Sstevel 		 */
56052305Sstevel #ifdef CARDBUS
5606*7656SSherry.Moore@Sun.COM 			pcic_unload_cardbus(pcic, sockp);
5607*7656SSherry.Moore@Sun.COM 			/* pcic_dump_all(pcic); */
56082305Sstevel #endif
5609*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags &= ~PCS_CARD_CBREM;
5610*7656SSherry.Moore@Sun.COM 			}
5611*7656SSherry.Moore@Sun.COM 			sockp->pcs_flags &= ~PCS_CARD_REMOVED;
56122305Sstevel 		}
5613*7656SSherry.Moore@Sun.COM 		break;
56142305Sstevel 	} /* switch */
56152305Sstevel 
56162305Sstevel 	if (do_debounce) {
56172305Sstevel 	/*
56182305Sstevel 	 * Delay doing
56192305Sstevel 	 * anything for a while so that things can settle
56202305Sstevel 	 * down a little. Interrupts are already disabled.
56212305Sstevel 	 * Reset the state and we'll reevaluate the
56222305Sstevel 	 * whole kit 'n kaboodle when the timeout fires
56232305Sstevel 	 */
56242305Sstevel #ifdef PCIC_DEBUG
56252305Sstevel 		pcic_err(pcic->dip, 8, "Queueing up debounce timeout for "
5626*7656SSherry.Moore@Sun.COM 		    "socket %d.%d\n",
5627*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(pcic->dip),
5628*7656SSherry.Moore@Sun.COM 		    sockp->pcs_socket);
56292305Sstevel #endif
5630*7656SSherry.Moore@Sun.COM 		sockp->pcs_debounce_id =
5631*7656SSherry.Moore@Sun.COM 		    pcic_add_debqueue(sockp, debounce_time);
56322305Sstevel 
56332305Sstevel 	/*
56342305Sstevel 	 * We bug out here without re-enabling interrupts. They will
56352305Sstevel 	 * be re-enabled when the debounce timeout swings through
56362305Sstevel 	 * here.
56372305Sstevel 	 */
5638*7656SSherry.Moore@Sun.COM 		return;
56392305Sstevel 	}
56402305Sstevel 
56412305Sstevel 	/*
56422305Sstevel 	 * Turn on Card detect interrupts. Other interrupts will be
56432305Sstevel 	 * enabled during set_socket calls.
56442305Sstevel 	 *
56452305Sstevel 	 * Note that set_socket only changes interrupt settings when there
56462305Sstevel 	 * is a card present.
56472305Sstevel 	 */
56482305Sstevel 	irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT);
56492305Sstevel 	irq |= PCIC_CD_DETECT;
56502305Sstevel 	pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq);
56512325Srw148561 	pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK);
56522305Sstevel 
56532451Srw148561 	/* Out from debouncing state */
56542451Srw148561 	sockp->pcs_flags &= ~PCS_DEBOUNCING;
56552451Srw148561 
56562305Sstevel 	pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n");
56572305Sstevel }
56582305Sstevel 
56592305Sstevel /*
56602305Sstevel  * pcic_getb()
56612305Sstevel  *	get an I/O byte based on the yardware decode method
56622305Sstevel  */
56632305Sstevel static uint8_t
56642305Sstevel pcic_getb(pcicdev_t *pcic, int socket, int reg)
56652305Sstevel {
56662305Sstevel 	int work;
56672305Sstevel 
56682305Sstevel #if defined(PCIC_DEBUG)
56692305Sstevel 	if (pcic_debug == 0x7fff) {
56702305Sstevel 		cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n",
5671*7656SSherry.Moore@Sun.COM 		    (void *)pcic, socket, reg);
56722305Sstevel 		cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n",
5673*7656SSherry.Moore@Sun.COM 		    pcic->pc_io_type, (void *)pcic->handle,
5674*7656SSherry.Moore@Sun.COM 		    (void *)pcic->ioaddr);
56752305Sstevel 	}
56762305Sstevel #endif
56772305Sstevel 
56782305Sstevel 	switch (pcic->pc_io_type) {
56792305Sstevel 	case PCIC_IO_TYPE_YENTA:
56802305Sstevel 		return (ddi_get8(pcic->handle,
56812305Sstevel 		    pcic->ioaddr + CB_R2_OFFSET + reg));
56822305Sstevel 	default:
56832305Sstevel 		work = (socket * PCIC_SOCKET_1) | reg;
56842305Sstevel 		ddi_put8(pcic->handle, pcic->ioaddr, work);
56852305Sstevel 		return (ddi_get8(pcic->handle, pcic->ioaddr + 1));
56862305Sstevel 	}
56872305Sstevel }
56882305Sstevel 
56892305Sstevel static void
56902305Sstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value)
56912305Sstevel {
56922305Sstevel 	int work;
56932305Sstevel 
56942305Sstevel #if defined(PCIC_DEBUG)
56952305Sstevel 	if (pcic_debug == 0x7fff) {
56962305Sstevel 		cmn_err(CE_CONT,
5697*7656SSherry.Moore@Sun.COM 		    "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n",
5698*7656SSherry.Moore@Sun.COM 		    (void *)pcic, socket, reg, value);
56992305Sstevel 		cmn_err(CE_CONT,
5700*7656SSherry.Moore@Sun.COM 		    "pcic_putb1: type=%d handle=%p ioaddr=%p \n",
5701*7656SSherry.Moore@Sun.COM 		    pcic->pc_io_type, (void *)pcic->handle,
5702*7656SSherry.Moore@Sun.COM 		    (void *)pcic->ioaddr);
57032305Sstevel 	}
57042305Sstevel #endif
57052305Sstevel 
57062305Sstevel 
57072305Sstevel 	switch (pcic->pc_io_type) {
57082305Sstevel 	case PCIC_IO_TYPE_YENTA:
57092305Sstevel 		ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg,
5710*7656SSherry.Moore@Sun.COM 		    value);
57112305Sstevel 		break;
57122305Sstevel 	default:
57132305Sstevel 		work = (socket * PCIC_SOCKET_1) | reg;
57142305Sstevel 		ddi_put8(pcic->handle, pcic->ioaddr, work);
57152305Sstevel 		ddi_put8(pcic->handle, pcic->ioaddr + 1, value);
57162305Sstevel 		break;
57172305Sstevel 	}
57182305Sstevel }
57192305Sstevel 
57202305Sstevel /*
57212305Sstevel  * chip identification functions
57222305Sstevel  */
57232305Sstevel 
57242305Sstevel /*
57252305Sstevel  * chip identification: Cirrus Logic PD6710/6720/6722
57262305Sstevel  */
57272305Sstevel static int
57282305Sstevel pcic_ci_cirrus(pcicdev_t *pcic)
57292305Sstevel {
57302305Sstevel 	int value1, value2;
57312305Sstevel 
57322305Sstevel 	/* Init the CL id mode */
57332305Sstevel 	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57342305Sstevel 	pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
57352305Sstevel 	value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57362305Sstevel 	value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57372305Sstevel 
57382305Sstevel 	if ((value1 & PCIC_CI_ID) == PCIC_CI_ID &&
57392305Sstevel 	    (value2 & PCIC_CI_ID) == 0) {
57402305Sstevel 		/* chip is a Cirrus Logic and not Intel */
57412305Sstevel 		pcic->pc_type = PCIC_CL_PD6710;
57422305Sstevel 		if (value1 & PCIC_CI_SLOTS)
57432305Sstevel 			pcic->pc_chipname = PCIC_TYPE_PD6720;
57442305Sstevel 		else
57452305Sstevel 			pcic->pc_chipname = PCIC_TYPE_PD6710;
57462305Sstevel 		/* now fine tune things just in case a 6722 */
57472305Sstevel 		value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0);
57482305Sstevel 		if (value1 == 0) {
57492305Sstevel 			clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55);
57502305Sstevel 			value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH);
57512305Sstevel 			if (value1 == 0x55) {
57522305Sstevel 				pcic->pc_chipname = PCIC_TYPE_PD6722;
57532305Sstevel 				pcic->pc_type = PCIC_CL_PD6722;
57542305Sstevel 				clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0);
57552305Sstevel 			}
57562305Sstevel 		}
57572305Sstevel 		return (1);
57582305Sstevel 	}
57592305Sstevel 	return (0);
57602305Sstevel }
57612305Sstevel 
57622305Sstevel /*
57632305Sstevel  * chip identification: Vadem (VG365/465/468/469)
57642305Sstevel  */
57652305Sstevel 
57662305Sstevel static void
57672305Sstevel pcic_vadem_enable(pcicdev_t *pcic)
57682305Sstevel {
57692305Sstevel 	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1);
57702305Sstevel 	ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2);
57712305Sstevel 	ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg);
57722305Sstevel }
57732305Sstevel 
57742305Sstevel static int
57752305Sstevel pcic_ci_vadem(pcicdev_t *pcic)
57762305Sstevel {
57772305Sstevel 	int value;
57782305Sstevel 
57792305Sstevel 	pcic_vadem_enable(pcic);
57802305Sstevel 	value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
57812305Sstevel 	pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF);
57822305Sstevel 	if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) ==
57832305Sstevel 	    (value | PCIC_VADEM_D3) ||
57842305Sstevel 	    (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) ==
57852305Sstevel 	    PCIC_VADEM_469) {
57862305Sstevel 		int vadem, new;
57872305Sstevel 		pcic_vadem_enable(pcic);
57882305Sstevel 		vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) &
5789*7656SSherry.Moore@Sun.COM 		    ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV);
57902305Sstevel 		new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK);
57912305Sstevel 		pcic_putb(pcic, 0, PCIC_VG_DMA, new);
57922305Sstevel 		value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
57932305Sstevel 
57942305Sstevel 		/* want to lock but leave mouse or other on */
57952305Sstevel 		pcic_putb(pcic, 0, PCIC_VG_DMA, vadem);
57962305Sstevel 		switch (value & PCIC_REV_MASK) {
57972305Sstevel 		case PCIC_VADEM_365:
57982305Sstevel 			pcic->pc_chipname = PCIC_VG_365;
57992305Sstevel 			pcic->pc_type = PCIC_VADEM;
58002305Sstevel 			break;
58012305Sstevel 		case PCIC_VADEM_465:
58022305Sstevel 			pcic->pc_chipname = PCIC_VG_465;
58032305Sstevel 			pcic->pc_type = PCIC_VADEM;
58042305Sstevel 			pcic->pc_flags |= PCF_1SOCKET;
58052305Sstevel 			break;
58062305Sstevel 		case PCIC_VADEM_468:
58072305Sstevel 			pcic->pc_chipname = PCIC_VG_468;
58082305Sstevel 			pcic->pc_type = PCIC_VADEM;
58092305Sstevel 			break;
58102305Sstevel 		case PCIC_VADEM_469:
58112305Sstevel 			pcic->pc_chipname = PCIC_VG_469;
58122305Sstevel 			pcic->pc_type = PCIC_VADEM_VG469;
58132305Sstevel 			break;
58142305Sstevel 		}
58152305Sstevel 		return (1);
58162305Sstevel 	}
58172305Sstevel 	return (0);
58182305Sstevel }
58192305Sstevel 
58202305Sstevel /*
58212305Sstevel  * chip identification: Ricoh
58222305Sstevel  */
58232305Sstevel static int
58242305Sstevel pcic_ci_ricoh(pcicdev_t *pcic)
58252305Sstevel {
58262305Sstevel 	int value;
58272305Sstevel 
58282305Sstevel 	value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT);
58292305Sstevel 	switch (value) {
58302305Sstevel 	case PCIC_RF_296:
58312305Sstevel 		pcic->pc_type = PCIC_RICOH;
58322305Sstevel 		pcic->pc_chipname = PCIC_TYPE_RF5C296;
58332305Sstevel 		return (1);
58342305Sstevel 	case PCIC_RF_396:
58352305Sstevel 		pcic->pc_type = PCIC_RICOH;
58362305Sstevel 		pcic->pc_chipname = PCIC_TYPE_RF5C396;
58372305Sstevel 		return (1);
58382305Sstevel 	}
58392305Sstevel 	return (0);
58402305Sstevel }
58412305Sstevel 
58422305Sstevel 
58432305Sstevel /*
58442305Sstevel  * set up available address spaces in busra
58452305Sstevel  */
58462305Sstevel static void
58472305Sstevel pcic_init_assigned(dev_info_t *dip)
58482305Sstevel {
58492305Sstevel 	pcm_regs_t *pcic_avail_p;
58502305Sstevel 	pci_regspec_t *pci_avail_p, *regs;
58512305Sstevel 	int len, entries, rlen;
58522305Sstevel 	dev_info_t *pdip;
58532305Sstevel 
58542305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
58552305Sstevel 	    "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) {
58562305Sstevel 		/*
58572305Sstevel 		 * found "available" property at the cardbus/pcmcia node
58582305Sstevel 		 * need to translate address space entries from pcmcia
58592305Sstevel 		 * format to pci format
58602305Sstevel 		 */
58612305Sstevel 		entries = len / sizeof (pcm_regs_t);
58622305Sstevel 		pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries,
5863*7656SSherry.Moore@Sun.COM 		    KM_SLEEP);
58642305Sstevel 		if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p,
58652305Sstevel 		    entries) == DDI_SUCCESS)
58662305Sstevel 			(void) pci_resource_setup_avail(dip, pci_avail_p,
5867*7656SSherry.Moore@Sun.COM 			    entries);
58682305Sstevel 		kmem_free(pcic_avail_p, len);
58692305Sstevel 		kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t));
58702305Sstevel 		return;
58712305Sstevel 	}
58722305Sstevel 
58732305Sstevel 	/*
58742305Sstevel 	 * "legacy" platforms will have "available" property in pci node
58752305Sstevel 	 */
58762305Sstevel 	for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) {
58772305Sstevel 		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
58782305Sstevel 		    "available", (caddr_t)&pci_avail_p, &len) ==
58792305Sstevel 		    DDI_PROP_SUCCESS) {
58802305Sstevel 			/* (void) pci_resource_setup(pdip); */
58812305Sstevel 			kmem_free(pci_avail_p, len);
58822305Sstevel 			break;
58832305Sstevel 		}
58842305Sstevel 	}
58852305Sstevel 
58862305Sstevel 	if (pdip == NULL) {
58872305Sstevel 		int len;
58882305Sstevel 		char bus_type[16] = "(unknown)";
58892305Sstevel 		dev_info_t *par;
58902305Sstevel 
58912305Sstevel 		cmn_err(CE_CONT,
58922305Sstevel 		    "?pcic_init_assigned: no available property for pcmcia\n");
58932305Sstevel 
58942305Sstevel 		/*
58952305Sstevel 		 * This code is taken from pci_resource_setup() but does
58962305Sstevel 		 * not attempt to use the "available" property to populate
58972305Sstevel 		 * the ndi maps that are created.
58982305Sstevel 		 * The fact that we will actually
58992305Sstevel 		 * free some resource below (that was allocated by OBP)
59002305Sstevel 		 * should be enough to be going on with.
59012305Sstevel 		 */
59022305Sstevel 		for (par = dip; par != NULL; par = ddi_get_parent(par)) {
59032305Sstevel 			len = sizeof (bus_type);
59042305Sstevel 
59052305Sstevel 			if ((ddi_prop_op(DDI_DEV_T_ANY, par,
59062305Sstevel 			    PROP_LEN_AND_VAL_BUF,
59072305Sstevel 			    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
59082305Sstevel 			    "device_type",
59092305Sstevel 			    (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
59103664Srw148561 			    (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
5911*7656SSherry.Moore@Sun.COM 			    strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0))
59122305Sstevel 				break;
59132305Sstevel 		}
59142305Sstevel 		if (par != NULL &&
59152305Sstevel 		    (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS ||
59162305Sstevel 		    ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS))
59172305Sstevel 			par = NULL;
59182305Sstevel 	} else {
59192305Sstevel #ifdef CARDBUS
59202305Sstevel 		cardbus_bus_range_t *bus_range;
59212305Sstevel 		int k;
59222305Sstevel 
59232305Sstevel 		if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range",
59242305Sstevel 		    (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) {
59252305Sstevel 			if (bus_range->lo != bus_range->hi)
59262305Sstevel 				pcic_err(pdip, 9, "allowable bus range is "
59272305Sstevel 				    "%u->%u\n", bus_range->lo, bus_range->hi);
59282305Sstevel 			else {
59292305Sstevel 				pcic_err(pdip, 0,
59302305Sstevel 				    "!No spare PCI bus numbers, range is "
59312305Sstevel 				    "%u->%u, cardbus isn't usable\n",
59322305Sstevel 				    bus_range->lo, bus_range->hi);
59332305Sstevel 			}
59342305Sstevel 			kmem_free(bus_range, k);
59352305Sstevel 		} else
59362305Sstevel 			pcic_err(pdip, 0, "!No bus-range property seems to "
59372305Sstevel 			    "have been set up\n");
59382305Sstevel #endif
59392305Sstevel 		/*
59402305Sstevel 		 * Have a valid parent with the "available" property
59412305Sstevel 		 */
59422305Sstevel 		(void) pci_resource_setup(pdip);
59432305Sstevel 	}
59442305Sstevel 
59452305Sstevel 	if ((strcmp(ddi_get_name(dip), "pcma") == 0) &&
59462305Sstevel 	    ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
59472305Sstevel 	    "assigned-addresses",
59482305Sstevel 	    (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
59492305Sstevel 		ra_return_t ra;
59502305Sstevel 
59512305Sstevel 		/*
59522305Sstevel 		 * On the UltraBook IIi the ranges are assigned under
59532305Sstevel 		 * openboot. If we don't free them here the first I/O
59542305Sstevel 		 * space that can be used is up above 0x10000 which
59552305Sstevel 		 * doesn't work for this driver due to restrictions
59562305Sstevel 		 * on the PCI I/O addresses the controllers can cope with.
59572305Sstevel 		 * They are never going to be used by anything else
59582305Sstevel 		 * so free them up to the general pool. AG.
59592305Sstevel 		 */
59602305Sstevel 		pcic_err(dip, 1, "Free assigned addresses\n");
59612305Sstevel 
59622305Sstevel 		if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) ==
59632305Sstevel 		    PCI_REG_ADDR_G(PCI_ADDR_MEM32)) &&
59642305Sstevel 		    regs[0].pci_size_low == 0x1000000) {
59652305Sstevel 			ra.ra_addr_lo = regs[0].pci_phys_low;
59662305Sstevel 			ra.ra_len = regs[0].pci_size_low;
59672305Sstevel 			(void) pcmcia_free_mem(dip, &ra);
59682305Sstevel 		}
59692305Sstevel 		if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) ==
59702305Sstevel 		    PCI_REG_ADDR_G(PCI_ADDR_IO)) &&
59712305Sstevel 		    (regs[1].pci_size_low == 0x8000 ||
59722305Sstevel 		    regs[1].pci_size_low == 0x4000))   /* UB-IIi || UB-I */
59732305Sstevel 		{
59742305Sstevel 			ra.ra_addr_lo = regs[1].pci_phys_low;
59752305Sstevel 			ra.ra_len = regs[1].pci_size_low;
59762305Sstevel 			(void) pcmcia_free_io(dip, &ra);
59772305Sstevel 		}
59782305Sstevel 		kmem_free((caddr_t)regs, rlen);
59792305Sstevel 	}
59802305Sstevel }
59812305Sstevel 
59822305Sstevel /*
59832305Sstevel  * translate "available" from pcmcia format to pci format
59842305Sstevel  */
59852305Sstevel static int
59862305Sstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p,
59872305Sstevel     pci_regspec_t *pci_p, int entries)
59882305Sstevel {
59892305Sstevel 	int i, range_len, range_entries;
59902305Sstevel 	pcic_ranges_t *pcic_range_p;
59912305Sstevel 
59922305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
5993*7656SSherry.Moore@Sun.COM 	    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
59942305Sstevel 		cmn_err(CE_CONT, "?pcic_apply_avail_ranges: "
5995*7656SSherry.Moore@Sun.COM 		    "no ranges property for pcmcia\n");
59962305Sstevel 		return (DDI_FAILURE);
59972305Sstevel 	}
59982305Sstevel 
59992305Sstevel 	range_entries = range_len / sizeof (pcic_ranges_t);
60002305Sstevel 
60012305Sstevel 	/* for each "available" entry to be translated */
60022305Sstevel 	for (i = 0; i < entries; i++, pcic_p++, pci_p++) {
60032305Sstevel 		int j;
60042305Sstevel 		pcic_ranges_t *range_p = pcic_range_p;
60052305Sstevel 		pci_p->pci_phys_hi = -1u; /* default invalid value */
60062305Sstevel 
60072305Sstevel 		/* for each "ranges" entry to be searched */
60082305Sstevel 		for (j = 0; j < range_entries; j++, range_p++) {
60092305Sstevel 			uint64_t range_end = range_p->pcic_range_caddrlo +
6010*7656SSherry.Moore@Sun.COM 			    range_p->pcic_range_size;
60112305Sstevel 			uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len;
60122305Sstevel 
60132305Sstevel 			if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) ||
60142305Sstevel 			    (range_p->pcic_range_caddrlo > pcic_p->phys_lo) ||
60152305Sstevel 			    (range_end < avail_end))
60162305Sstevel 				continue;
60172305Sstevel 
60182305Sstevel 			pci_p->pci_phys_hi = range_p->pcic_range_paddrhi;
60192305Sstevel 			pci_p->pci_phys_mid = range_p->pcic_range_paddrmid;
60202305Sstevel 			pci_p->pci_phys_low = range_p->pcic_range_paddrlo
60212305Sstevel 			    + (pcic_p->phys_lo - range_p->pcic_range_caddrlo);
60222305Sstevel 			pci_p->pci_size_hi = 0;
60232305Sstevel 			pci_p->pci_size_low = pcic_p->phys_len;
60242305Sstevel 		}
60252305Sstevel 	}
60262305Sstevel 	kmem_free(pcic_range_p, range_len);
60272305Sstevel 	return (DDI_SUCCESS);
60282305Sstevel }
60292305Sstevel 
60302305Sstevel static int
60312305Sstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred)
60322305Sstevel {
60332305Sstevel #ifdef CARDBUS
60342305Sstevel 	if (cardbus_is_cb_minor(*dev))
60352305Sstevel 		return (cardbus_open(dev, flag, otyp, cred));
60362305Sstevel #endif
60372305Sstevel 	return (EINVAL);
60382305Sstevel }
60392305Sstevel 
60402305Sstevel static int
60412305Sstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred)
60422305Sstevel {
60432305Sstevel #ifdef CARDBUS
60442305Sstevel 	if (cardbus_is_cb_minor(dev))
60452305Sstevel 		return (cardbus_close(dev, flag, otyp, cred));
60462305Sstevel #endif
60472305Sstevel 	return (EINVAL);
60482305Sstevel }
60492305Sstevel 
60502305Sstevel static int
60512305Sstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
60522305Sstevel 	int *rval)
60532305Sstevel {
60542305Sstevel #ifdef CARDBUS
60552305Sstevel 	if (cardbus_is_cb_minor(dev))
60562305Sstevel 		return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval));
60572305Sstevel #endif
60582305Sstevel 	return (EINVAL);
60592305Sstevel }
60602305Sstevel 
60612305Sstevel 
60622305Sstevel static boolean_t
60632305Sstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
60642305Sstevel {
60652305Sstevel 	uint32_t present_state;
60662305Sstevel 	dev_info_t *dip = pcic->dip;
60672305Sstevel 	set_socket_t s;
60682305Sstevel 	get_socket_t g;
60692305Sstevel 	boolean_t retval;
60702305Sstevel 	unsigned vccLevel;
60712305Sstevel 
60722305Sstevel 	pcic_err(dip, 8, "entering pcic_load_cardbus\n");
60732305Sstevel 
60742305Sstevel 	pcic_mutex_exit(&pcic->pc_lock);
60752305Sstevel 
60762305Sstevel 	bzero(&s, sizeof (set_socket_t));
60772305Sstevel 	s.socket = sockp->pcs_socket;
60782305Sstevel 	s.SCIntMask = SBM_CD|SBM_RDYBSY;
60792305Sstevel 	s.IFType = IF_CARDBUS;
60802305Sstevel 	s.State = (unsigned)~0;
60812305Sstevel 
60822305Sstevel 	present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
60832305Sstevel 	if (present_state & PCIC_VCC_3VCARD)
60842305Sstevel 		s.VccLevel = PCIC_VCC_3VLEVEL;
60852305Sstevel 	else if (present_state & PCIC_VCC_5VCARD)
60862305Sstevel 		s.VccLevel = PCIC_VCC_5VLEVEL;
60872305Sstevel 	else {
60882305Sstevel 		cmn_err(CE_CONT,
60892305Sstevel 		    "pcic_load_cardbus: unsupported card voltage\n");
60902305Sstevel 		goto failure;
60912305Sstevel 	}
60922305Sstevel 	vccLevel = s.VccLevel;
60932305Sstevel 	s.Vpp1Level = s.Vpp2Level = 0;
60942305Sstevel 
60952305Sstevel 	if (pcic_set_socket(dip, &s) != SUCCESS)
60962305Sstevel 		goto failure;
60972305Sstevel 
60982305Sstevel 	if (pcic_reset_socket(dip, sockp->pcs_socket,
60992305Sstevel 	    RESET_MODE_CARD_ONLY) != SUCCESS)
61002305Sstevel 		goto failure;
61012305Sstevel 
61022305Sstevel 	bzero(&g, sizeof (get_socket_t));
61032305Sstevel 	g.socket = sockp->pcs_socket;
61042305Sstevel 	if (pcic_get_socket(dip, &g) != SUCCESS)
61052305Sstevel 		goto failure;
61062305Sstevel 
61072305Sstevel 	bzero(&s, sizeof (set_socket_t));
61082305Sstevel 	s.socket = sockp->pcs_socket;
61092305Sstevel 	s.SCIntMask = SBM_CD;
61102305Sstevel 	s.IREQRouting = g.IRQRouting;
61112305Sstevel 	s.IFType = g.IFType;
61122305Sstevel 	s.CtlInd = g.CtlInd;
61132305Sstevel 	s.State = (unsigned)~0;
61142305Sstevel 	s.VccLevel = vccLevel;
61152305Sstevel 	s.Vpp1Level = s.Vpp2Level = 0;
61162305Sstevel 
61177151Srw148561 	retval = pcic_set_socket(dip, &s);
61187151Srw148561 	pcmcia_cb_resumed(s.socket);
61197151Srw148561 	if (retval != SUCCESS)
61202305Sstevel 		goto failure;
61212305Sstevel 
61222305Sstevel 	retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base);
61232305Sstevel 	goto exit;
61242305Sstevel 
61252305Sstevel failure:
61262305Sstevel 	retval = B_FALSE;
61272305Sstevel 
61282305Sstevel exit:
61292305Sstevel 	pcic_mutex_enter(&pcic->pc_lock);
61302305Sstevel 	pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n",
61312305Sstevel 	    retval ? "success" : "failure");
61322305Sstevel 	return (retval);
61332305Sstevel }
61342305Sstevel 
61352305Sstevel static void
61362305Sstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
61372305Sstevel {
61382305Sstevel 	dev_info_t *dip = pcic->dip;
61392305Sstevel 	set_socket_t s;
61402305Sstevel 
61412305Sstevel 	pcic_mutex_exit(&pcic->pc_lock);
61422305Sstevel 
61432305Sstevel 	cardbus_unload_cardbus(dip);
61442305Sstevel 
61452305Sstevel 	bzero(&s, sizeof (set_socket_t));
61462305Sstevel 	s.socket = sockp->pcs_socket;
61472305Sstevel 	s.SCIntMask = SBM_CD|SBM_RDYBSY;
61482305Sstevel 	s.IREQRouting = 0;
61492305Sstevel 	s.IFType = IF_MEMORY;
61502305Sstevel 	s.CtlInd = 0;
61512305Sstevel 	s.State = 0;
61522305Sstevel 	s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0;
61532305Sstevel 
61542305Sstevel 	(void) pcic_set_socket(dip, &s);
61552305Sstevel 
61562305Sstevel 	pcic_mutex_enter(&pcic->pc_lock);
61572305Sstevel }
61582305Sstevel 
61592305Sstevel static uint32_t
61602305Sstevel pcic_getcb(pcicdev_t *pcic, int reg)
61612305Sstevel {
61622305Sstevel 	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61632305Sstevel 
61642305Sstevel 	return (ddi_get32(pcic->handle,
61652305Sstevel 	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg)));
61662305Sstevel }
61672305Sstevel 
61682305Sstevel static void
61692305Sstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value)
61702305Sstevel {
61712305Sstevel 	ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61722305Sstevel 
61732305Sstevel 	ddi_put32(pcic->handle,
61742305Sstevel 	    (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value);
61752305Sstevel }
61762305Sstevel 
61772305Sstevel static void
61782305Sstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq)
61792305Sstevel {
61802305Sstevel 	uint8_t value;
61812305Sstevel 	uint16_t brdgctl;
61822305Sstevel 
61832305Sstevel 	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
61842305Sstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq);
61852305Sstevel 
61862305Sstevel 	switch (pcic->pc_type) {
61872305Sstevel 	case PCIC_INTEL_i82092:
61882305Sstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
61892305Sstevel 		    PCIC_82092_INT_ENABLE);
61902305Sstevel 		break;
61912305Sstevel 	case PCIC_O2_OZ6912:
61922305Sstevel 		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
61932305Sstevel 		value |= 0x8;
61942305Sstevel 		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
61952305Sstevel 		break;
61962305Sstevel 	case PCIC_CL_PD6832:
61972305Sstevel 	case PCIC_TI_PCI1250:
61982305Sstevel 	case PCIC_TI_PCI1221:
61992305Sstevel 	case PCIC_TI_PCI1225:
62002305Sstevel 	case PCIC_TI_PCI1410:
62012305Sstevel 	case PCIC_ENE_1410:
62022305Sstevel 	case PCIC_TI_PCI1510:
62032305Sstevel 	case PCIC_TI_PCI1520:
62042305Sstevel 	case PCIC_TI_PCI1420:
62052305Sstevel 	case PCIC_ENE_1420:
62062305Sstevel 		/* route card functional interrupts to PCI interrupts */
62072305Sstevel 		brdgctl = ddi_get16(pcic->cfg_handle,
62082305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62092305Sstevel 		pcic_err(NULL, 1,
62102305Sstevel 		    "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n",
62112305Sstevel 		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
62122305Sstevel 		brdgctl &= ~PCIC_BRDGCTL_INTR_MASK;
62132305Sstevel 		ddi_put16(pcic->cfg_handle,
62142305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62152305Sstevel 		    brdgctl);
62162305Sstevel 		/* Flush the write */
62172305Sstevel 		(void) ddi_get16(pcic->cfg_handle,
62182305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62192305Sstevel 		break;
62202305Sstevel 	default:
62212305Sstevel 		break;
62222305Sstevel 	}
62232305Sstevel }
62242305Sstevel 
62252305Sstevel static void
62262305Sstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket)
62272305Sstevel {
62282305Sstevel 	uint8_t value;
62292305Sstevel 	uint16_t brdgctl;
62302305Sstevel 
62312305Sstevel 	value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62322305Sstevel 	pcic_putb(pcic, socket, PCIC_INTERRUPT, value);
62332305Sstevel 
62342305Sstevel 	switch (pcic->pc_type) {
62352305Sstevel 	case PCIC_INTEL_i82092:
62362305Sstevel 		pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62372305Sstevel 		    PCIC_82092_INT_DISABLE);
62382305Sstevel 		break;
62392305Sstevel 	case PCIC_O2_OZ6912:
62402305Sstevel 		value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62412305Sstevel 		value &= ~0x8;
62422305Sstevel 		pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62432305Sstevel 		/* Flush the write */
62442305Sstevel 		(void) pcic_getb(pcic, 0, PCIC_CENTDMA);
62452305Sstevel 		break;
62462305Sstevel 	case PCIC_CL_PD6832:
62472305Sstevel 	case PCIC_TI_PCI1250:
62482305Sstevel 	case PCIC_TI_PCI1221:
62492305Sstevel 	case PCIC_TI_PCI1225:
62502305Sstevel 	case PCIC_TI_PCI1410:
62512305Sstevel 	case PCIC_ENE_1410:
62522305Sstevel 	case PCIC_TI_PCI1510:
62532305Sstevel 	case PCIC_TI_PCI1520:
62542305Sstevel 	case PCIC_TI_PCI1420:
62552305Sstevel 	case PCIC_ENE_1420:
62562305Sstevel 		/*
62572305Sstevel 		 * This maps I/O interrupts to ExCA which
62582305Sstevel 		 * have been turned off by the write to
62592305Sstevel 		 * PCIC_INTERRUPT above. It would appear to
62602305Sstevel 		 * be the only way to actually turn I/O Ints off
62612305Sstevel 		 * while retaining CS Ints.
62622305Sstevel 		 */
62632305Sstevel 		brdgctl = ddi_get16(pcic->cfg_handle,
62642305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62652305Sstevel 		pcic_err(NULL, 1,
62662305Sstevel 		    "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n",
62672305Sstevel 		    PCI_CBUS_BRIDGE_CTRL, brdgctl);
62682305Sstevel 		brdgctl |= PCIC_BRDGCTL_INTR_MASK;
62692305Sstevel 		ddi_put16(pcic->cfg_handle,
62702305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62712305Sstevel 		    brdgctl);
62722305Sstevel 		/* Flush the write */
62732305Sstevel 		(void) ddi_get16(pcic->cfg_handle,
62742305Sstevel 		    (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62752305Sstevel 		break;
62762305Sstevel 	default:
62772305Sstevel 		break;
62782305Sstevel 	}
62792305Sstevel }
62802305Sstevel 
62812305Sstevel static void
62822305Sstevel pcic_cb_enable_intr(dev_info_t *dip)
62832305Sstevel {
62842305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
62852305Sstevel 	pcicdev_t *pcic = anp->an_private;
62862305Sstevel 
62872305Sstevel 	mutex_enter(&pcic->pc_lock);
62882305Sstevel 	pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq);
62892305Sstevel 	mutex_exit(&pcic->pc_lock);
62902305Sstevel }
62912305Sstevel 
62922305Sstevel static void
62932305Sstevel pcic_cb_disable_intr(dev_info_t *dip)
62942305Sstevel {
62952305Sstevel 	anp_t *anp = ddi_get_driver_private(dip);
62962305Sstevel 	pcicdev_t *pcic = anp->an_private;
62972305Sstevel 
62982305Sstevel 	mutex_enter(&pcic->pc_lock);
62992305Sstevel 	pcic_disable_io_intr(pcic, 0);
63002305Sstevel 	mutex_exit(&pcic->pc_lock);
63012305Sstevel }
63022305Sstevel 
63032305Sstevel static int
63042305Sstevel log_pci_cfg_err(ushort_t e, int bridge_secondary)
63052305Sstevel {
63062305Sstevel 	int	nerr = 0;
63072305Sstevel 	if (e & PCI_STAT_PERROR) {
63082305Sstevel 		nerr++;
63092305Sstevel 		cmn_err(CE_CONT, "detected parity error.\n");
63102305Sstevel 	}
63112305Sstevel 	if (e & PCI_STAT_S_SYSERR) {
63122305Sstevel 		nerr++;
63132305Sstevel 		if (bridge_secondary)
63142305Sstevel 			cmn_err(CE_CONT, "received system error.\n");
63152305Sstevel 		else
63162305Sstevel 			cmn_err(CE_CONT, "signalled system error.\n");
63172305Sstevel 	}
63182305Sstevel 	if (e & PCI_STAT_R_MAST_AB) {
63192305Sstevel 		nerr++;
63202305Sstevel 		cmn_err(CE_CONT, "received master abort.\n");
63212305Sstevel 	}
63222305Sstevel 	if (e & PCI_STAT_R_TARG_AB)
63232305Sstevel 		cmn_err(CE_CONT, "received target abort.\n");
63242305Sstevel 	if (e & PCI_STAT_S_TARG_AB)
63252305Sstevel 		cmn_err(CE_CONT, "signalled target abort\n");
63262305Sstevel 	if (e & PCI_STAT_S_PERROR) {
63272305Sstevel 		nerr++;
63282305Sstevel 		cmn_err(CE_CONT, "signalled parity error\n");
63292305Sstevel 	}
63302305Sstevel 	return (nerr);
63312305Sstevel }
63322305Sstevel 
63332305Sstevel #if defined(__sparc)
63342305Sstevel static int
63352305Sstevel pcic_fault(enum pci_fault_ops op, void *arg)
63362305Sstevel {
63372305Sstevel 	pcicdev_t *pcic = (pcicdev_t *)arg;
63382305Sstevel 	ushort_t pci_cfg_stat =
63392305Sstevel 	    pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT);
63402305Sstevel 	ushort_t pci_cfg_sec_stat =
63412305Sstevel 	    pci_config_get16(pcic->cfg_handle, 0x16);
63422305Sstevel 	char	nm[24];
63432305Sstevel 	int	nerr = 0;
63442305Sstevel 
63452305Sstevel 	cardbus_dump_pci_config(pcic->dip);
63462305Sstevel 
63472305Sstevel 	switch (op) {
63482305Sstevel 	case FAULT_LOG:
63492305Sstevel 		(void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip),
63502305Sstevel 		    ddi_get_instance(pcic->dip));
63512305Sstevel 
63522305Sstevel 		cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm);
63532305Sstevel 		cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat);
63542305Sstevel 		nerr += log_pci_cfg_err(pci_cfg_stat, 0);
63552305Sstevel 		cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat);
63562305Sstevel 		nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1);
63572305Sstevel 		cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm);
63582305Sstevel 		return (nerr);
63592305Sstevel 	case FAULT_POKEFINI:
63602305Sstevel 	case FAULT_RESET:
63612305Sstevel 		pci_config_put16(pcic->cfg_handle,
63622305Sstevel 		    PCI_CONF_STAT, pci_cfg_stat);
63632305Sstevel 		pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat);
63642305Sstevel 		break;
63652305Sstevel 	case FAULT_POKEFLT:
63662305Sstevel 		if (!(pci_cfg_stat & PCI_STAT_S_SYSERR))
63672305Sstevel 			return (1);
63682305Sstevel 		if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB))
63692305Sstevel 			return (1);
63702305Sstevel 		break;
63712305Sstevel 	default:
63722305Sstevel 		break;
63732305Sstevel 	}
63742305Sstevel 	return (DDI_SUCCESS);
63752305Sstevel }
63762305Sstevel #endif
63772305Sstevel 
63782305Sstevel static void
63797151Srw148561 pcic_do_resume(pcicdev_t *pcic)
63802305Sstevel {
63817151Srw148561 	int	i, interrupt;
63827151Srw148561 	uint8_t cfg;
63837151Srw148561 
63842305Sstevel 
63852305Sstevel #if defined(PCIC_DEBUG)
63867151Srw148561 	pcic_err(NULL, 6, "pcic_do_resume(): entered\n");
63872305Sstevel #endif
63887151Srw148561 
63897151Srw148561 	pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */
63907151Srw148561 	for (i = 0; i < pcic->pc_numsockets; i++) {
63917151Srw148561 		/* Enable interrupts  on PCI if needs be */
63927151Srw148561 		interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT);
63937151Srw148561 		if (pcic->pc_flags & PCF_USE_SMI)
63947151Srw148561 			interrupt |= PCIC_INTR_ENABLE;
63957151Srw148561 		pcic_putb(pcic, i, PCIC_INTERRUPT,
63967151Srw148561 		    PCIC_RESET | interrupt);
63977151Srw148561 		pcic->pc_sockets[i].pcs_debounce_id =
63987151Srw148561 		    pcic_add_debqueue(&pcic->pc_sockets[i],
63997151Srw148561 		    drv_usectohz(pcic_debounce_time));
64007151Srw148561 	}
64017151Srw148561 	pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */
64027151Srw148561 	if (pcic_do_pcmcia_sr)
64037151Srw148561 		(void) pcmcia_wait_insert(pcic->dip);
64047151Srw148561 	/*
64057151Srw148561 	 * The CardBus controller may be in RESET state after the
64067151Srw148561 	 * system is resumed from sleeping. The RESET bit is in
64077151Srw148561 	 * the Bridge Control register. This is true for all(TI,
64087151Srw148561 	 * Toshiba ToPIC95/97, RICOH, and O2Micro) CardBus
64097151Srw148561 	 * controllers. Need to clear the RESET bit explicitly.
64107151Srw148561 	 */
64117151Srw148561 	cfg = ddi_get8(pcic->cfg_handle,
6412*7656SSherry.Moore@Sun.COM 	    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
64137151Srw148561 	if (cfg & (1<<6)) {
64147151Srw148561 		cfg &= ~(1<<6);
64157151Srw148561 		ddi_put8(pcic->cfg_handle,
6416*7656SSherry.Moore@Sun.COM 		    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
6417*7656SSherry.Moore@Sun.COM 		    cfg);
64187151Srw148561 		cfg = ddi_get8(pcic->cfg_handle,
6419*7656SSherry.Moore@Sun.COM 		    pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
64207151Srw148561 		if (cfg & (1<<6)) {
6421*7656SSherry.Moore@Sun.COM 			pcic_err(pcic->dip, 1,
6422*7656SSherry.Moore@Sun.COM 			    "Failed to take pcic out of reset");
64232305Sstevel 		}
64242305Sstevel 	}
64257151Srw148561 
64262305Sstevel }
64272305Sstevel 
64282305Sstevel static void
64292305Sstevel pcic_debounce(pcic_socket_t *pcs)
64302305Sstevel {
64312305Sstevel 	uint8_t status, stschng;
64322305Sstevel 
64332305Sstevel 	pcic_mutex_enter(&pcs->pcs_pcic->pc_lock);
64342305Sstevel 	pcs->pcs_flags &= ~PCS_STARTING;
64352305Sstevel 	stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64362305Sstevel 	    PCIC_CARD_STATUS_CHANGE);
64372305Sstevel 	status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64382305Sstevel 	    PCIC_INTERFACE_STATUS);
64392305Sstevel #ifdef PCIC_DEBUG
64402305Sstevel 	pcic_err(pcs->pcs_pcic->dip, 8,
64412305Sstevel 	    "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x "
64422305Sstevel 	    "chg 0x%x flg 0x%x\n",
64432305Sstevel 	    (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket,
64442305Sstevel 	    status, stschng, pcs->pcs_flags);
64452305Sstevel #endif
64462305Sstevel 
64472305Sstevel 	pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE,
64482305Sstevel 	    PCIC_CD_DETECT);
64492305Sstevel 	pcic_handle_cd_change(pcs->pcs_pcic, pcs, status);
64502305Sstevel 	pcic_mutex_exit(&pcs->pcs_pcic->pc_lock);
64512305Sstevel }
64522305Sstevel 
64532305Sstevel static void
64542305Sstevel pcic_deb_thread()
64552305Sstevel {
64562305Sstevel 	callb_cpr_t cprinfo;
64572305Sstevel 	struct debounce *debp;
64582305Sstevel 	clock_t lastt;
64592305Sstevel 
64602305Sstevel 	CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx,
64612305Sstevel 	    callb_generic_cpr, "pcic debounce thread");
64622305Sstevel 	mutex_enter(&pcic_deb_mtx);
64632305Sstevel 	while (pcic_deb_threadid) {
64642305Sstevel 		while (pcic_deb_queue) {
64652305Sstevel #ifdef PCIC_DEBUG
64662305Sstevel 			pcic_dump_debqueue("Thread");
64672305Sstevel #endif
64682305Sstevel 			debp = pcic_deb_queue;
64692305Sstevel 			(void) drv_getparm(LBOLT, &lastt);
64702305Sstevel 			if (lastt >= debp->expire) {
64712305Sstevel 				pcic_deb_queue = debp->next;
64722305Sstevel 				mutex_exit(&pcic_deb_mtx);
64732305Sstevel 				pcic_debounce(debp->pcs);
64742305Sstevel 				mutex_enter(&pcic_deb_mtx);
64752305Sstevel 				kmem_free(debp, sizeof (*debp));
64762305Sstevel 			} else {
64772305Sstevel 				(void) cv_timedwait(&pcic_deb_cv,
64782305Sstevel 				    &pcic_deb_mtx, debp->expire);
64792305Sstevel 			}
64802305Sstevel 		}
64812305Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
64822305Sstevel 		cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
64832305Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx);
64842305Sstevel 	}
64852305Sstevel 	pcic_deb_threadid = (kthread_t *)1;
64862305Sstevel 	cv_signal(&pcic_deb_cv);
64872305Sstevel 	CALLB_CPR_EXIT(&cprinfo);	/* Also exits the mutex */
64882305Sstevel 	thread_exit();
64892305Sstevel }
64902305Sstevel 
64912305Sstevel static void *
64922305Sstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks)
64932305Sstevel {
64942305Sstevel 	clock_t lbolt;
64952305Sstevel 	struct debounce *dbp, **dbpp = &pcic_deb_queue;
64962305Sstevel 
64972305Sstevel 	(void) drv_getparm(LBOLT, &lbolt);
64983664Srw148561 	dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP);
64992305Sstevel 
65002305Sstevel 	dbp->expire = lbolt + clocks;
65012305Sstevel 	dbp->pcs = pcs;
65022305Sstevel 	mutex_enter(&pcic_deb_mtx);
65032305Sstevel 	while (*dbpp) {
65042305Sstevel 		if (dbp->expire > (*dbpp)->expire)
65052305Sstevel 			dbpp = &((*dbpp)->next);
65062305Sstevel 		else
65072305Sstevel 			break;
65082305Sstevel 	}
65092305Sstevel 	dbp->next = *dbpp;
65102305Sstevel 	*dbpp = dbp;
65112305Sstevel #ifdef PCIC_DEBUG
65122305Sstevel 	pcic_dump_debqueue("Add");
65132305Sstevel #endif
65142305Sstevel 	cv_signal(&pcic_deb_cv);
65152305Sstevel 	mutex_exit(&pcic_deb_mtx);
65162305Sstevel 	return (dbp);
65172305Sstevel }
65182305Sstevel 
65192305Sstevel static void
65202305Sstevel pcic_rm_debqueue(void *id)
65212305Sstevel {
65222305Sstevel 	struct debounce *dbp, **dbpp = &pcic_deb_queue;
65232305Sstevel 
65242305Sstevel 	dbp = (struct debounce *)id;
65252305Sstevel 	mutex_enter(&pcic_deb_mtx);
65262305Sstevel 	while (*dbpp) {
65272305Sstevel 		if (*dbpp == dbp) {
65282305Sstevel 			*dbpp = dbp->next;
65292305Sstevel 			kmem_free(dbp, sizeof (*dbp));
65302305Sstevel #ifdef PCIC_DEBUG
65312305Sstevel 			pcic_dump_debqueue("Remove");
65322305Sstevel #endif
65332305Sstevel 			cv_signal(&pcic_deb_cv);
65342305Sstevel 			mutex_exit(&pcic_deb_mtx);
65352305Sstevel 			return;
65362305Sstevel 		}
65372305Sstevel 		dbpp = &((*dbpp)->next);
65382305Sstevel 	}
65392305Sstevel 	pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id);
65402305Sstevel 	mutex_exit(&pcic_deb_mtx);
65412305Sstevel }
65422305Sstevel 
65432305Sstevel 
65442305Sstevel static int	pcic_powerdelay = 0;
65452305Sstevel 
65462305Sstevel static int
65472305Sstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel)
65482305Sstevel {
65492305Sstevel 	int	ind, value, orig_pwrctl;
65502305Sstevel 
65512305Sstevel 	/* power setup -- if necessary */
65522305Sstevel 	orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65532305Sstevel 
65542305Sstevel #if defined(PCIC_DEBUG)
65552305Sstevel 	pcic_err(pcic->dip, 6,
65562305Sstevel 	    "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n",
65572305Sstevel 	    socket, powerlevel, orig_pwrctl);
65582305Sstevel #endif
65592305Sstevel 	/* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */
65602305Sstevel 	powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) |
65612305Sstevel 	    (orig_pwrctl & POWER_OUTPUT_ENABLE);
65622305Sstevel 	if (powerlevel != orig_pwrctl) {
65632305Sstevel 		if (powerlevel & ~POWER_OUTPUT_ENABLE) {
65642305Sstevel 			int	ifs;
65652305Sstevel 			/*
65662305Sstevel 			 * set power to socket
65672305Sstevel 			 * note that the powerlevel was calculated earlier
65682305Sstevel 			 */
65692305Sstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
65702305Sstevel 			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65712305Sstevel 
65722305Sstevel 			/*
65732305Sstevel 			 * this second write to the power control register
65742305Sstevel 			 * is needed to resolve a problem on
65752305Sstevel 			 * the IBM ThinkPad 750
65762305Sstevel 			 * where the first write doesn't latch.
65772305Sstevel 			 * The second write appears to always work and
65782305Sstevel 			 * doesn't hurt the operation of other chips
65792305Sstevel 			 * so we can just use it -- this is good since we can't
65802305Sstevel 			 * determine what chip the 750 actually uses
65812305Sstevel 			 * (I suspect an early Ricoh).
65822305Sstevel 			 */
65832305Sstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
65842305Sstevel 
65852305Sstevel 			value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65862305Sstevel 			pcic_mswait(pcic, socket, pcic_powerdelay);
65872305Sstevel #if defined(PCIC_DEBUG)
65882305Sstevel 			pcic_err(pcic->dip, 8,
65892305Sstevel 			    "\tpowerlevel reg = %x (ifs %x)\n",
65902305Sstevel 			    value, pcic_getb(pcic, socket,
65912305Sstevel 			    PCIC_INTERFACE_STATUS));
65922305Sstevel 			pcic_err(pcic->dip, 8,
65932305Sstevel 			    "CBus regs: PS 0x%x, Control 0x%x\n",
65942305Sstevel 			    pcic_getcb(pcic, CB_PRESENT_STATE),
65952305Sstevel 			    pcic_getcb(pcic, CB_CONTROL));
65962305Sstevel #endif
65972305Sstevel 			/*
65982305Sstevel 			 * since power was touched, make sure it says it
65992305Sstevel 			 * is on.  This lets it become stable.
66002305Sstevel 			 */
66012305Sstevel 			for (ind = 0; ind < 20; ind++) {
66022305Sstevel 				ifs = pcic_getb(pcic, socket,
66032305Sstevel 				    PCIC_INTERFACE_STATUS);
66042305Sstevel 				if (ifs & PCIC_POWER_ON)
66052305Sstevel 					break;
66062305Sstevel 				else {
66072305Sstevel 					pcic_putb(pcic, socket,
66082305Sstevel 					    PCIC_POWER_CONTROL, 0);
66092305Sstevel 					(void) pcic_getb(pcic, socket,
66102305Sstevel 					    PCIC_POWER_CONTROL);
66112305Sstevel 					pcic_mswait(pcic, socket, 40);
66122305Sstevel 					if (ind == 10) {
66132305Sstevel 						pcic_putcb(pcic, CB_EVENT_FORCE,
66142305Sstevel 						    CB_EF_CVTEST);
66152305Sstevel 						pcic_mswait(pcic, socket, 100);
66162305Sstevel 					}
66172305Sstevel 					pcic_putb(pcic, socket,
66182305Sstevel 					    PCIC_POWER_CONTROL,
66192305Sstevel 					    powerlevel & ~POWER_OUTPUT_ENABLE);
66202305Sstevel 					(void) pcic_getb(pcic, socket,
66212305Sstevel 					    PCIC_POWER_CONTROL);
66222305Sstevel 					pcic_mswait(pcic, socket,
66232305Sstevel 					    pcic_powerdelay);
66242305Sstevel 					pcic_putb(pcic, socket,
66252305Sstevel 					    PCIC_POWER_CONTROL, powerlevel);
66262305Sstevel 					(void) pcic_getb(pcic, socket,
66272305Sstevel 					    PCIC_POWER_CONTROL);
66282305Sstevel 					pcic_mswait(pcic, socket,
66292305Sstevel 					    pcic_powerdelay);
66302305Sstevel 				}
66312305Sstevel 			}
66322305Sstevel 
66332305Sstevel 			if (!(ifs & PCIC_POWER_ON)) {
66342305Sstevel 				cmn_err(CE_WARN,
66352305Sstevel 				    "pcic socket %d: Power didn't get turned"
66362305Sstevel 				    "on!\nif status 0x%x pwrc 0x%x(x%x) "
66372305Sstevel 				    "misc1 0x%x igc 0x%x ind %d\n",
66382305Sstevel 				    socket, ifs,
66392305Sstevel 				    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66402305Sstevel 				    orig_pwrctl,
66412305Sstevel 				    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66422305Sstevel 				    pcic_getb(pcic, socket, PCIC_INTERRUPT),
66432305Sstevel 				    ind);
66442305Sstevel 				return (BAD_VCC);
66452305Sstevel 			}
66462305Sstevel #if defined(PCIC_DEBUG)
66472305Sstevel 			pcic_err(pcic->dip, 8,
66482305Sstevel 			    "\tind = %d, if status %x pwrc 0x%x "
66492305Sstevel 			    "misc1 0x%x igc 0x%x\n",
66502305Sstevel 			    ind, ifs,
66512305Sstevel 			    pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66522305Sstevel 			    pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66532305Sstevel 			    pcic_getb(pcic, socket, PCIC_INTERRUPT));
66542305Sstevel #endif
66552305Sstevel 		} else {
66562305Sstevel 			/* explicitly turned off the power */
66572305Sstevel 			pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66582305Sstevel 			(void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66592305Sstevel 		}
66602305Sstevel 	}
66612305Sstevel 	return (SUCCESS);
66622305Sstevel }
66632305Sstevel 
66642305Sstevel static int pcic_cbdoreset_during_poweron = 1;
66652305Sstevel static int
66662305Sstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket)
66672305Sstevel {
66682305Sstevel 	uint32_t cbctl = 0, orig_cbctl, cbstev, cbps;
66692305Sstevel 	int ind, iobits;
66702305Sstevel 	pcic_socket_t *sockp = &pcic->pc_sockets[socket];
66712305Sstevel 
66722305Sstevel 	pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE);
66732305Sstevel 
66742305Sstevel 	ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10;
66752305Sstevel 	cbctl |= pcic_cbv_levels[ind];
66762305Sstevel 
66772305Sstevel 	ind = pcic_power[sockp->pcs_vcc].PowerLevel/10;
66782305Sstevel 	cbctl |= (pcic_cbv_levels[ind]<<4);
66792305Sstevel 
66802305Sstevel 	orig_cbctl = pcic_getcb(pcic, CB_CONTROL);
66812305Sstevel 
66822305Sstevel #if defined(PCIC_DEBUG)
66832305Sstevel 	pcic_err(pcic->dip, 6,
66842305Sstevel 	    "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d "
66852305Sstevel 	    "cbctl 0x%x->0x%x\n",
66862305Sstevel 	    socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl);
66872305Sstevel #endif
66882305Sstevel 	if (cbctl != orig_cbctl) {
6689*7656SSherry.Moore@Sun.COM 		if (pcic_cbdoreset_during_poweron &&
6690*7656SSherry.Moore@Sun.COM 		    (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
6691*7656SSherry.Moore@Sun.COM 			iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
6692*7656SSherry.Moore@Sun.COM 			pcic_putb(pcic, socket, PCIC_INTERRUPT,
6693*7656SSherry.Moore@Sun.COM 			    iobits & ~PCIC_RESET);
6694*7656SSherry.Moore@Sun.COM 		}
6695*7656SSherry.Moore@Sun.COM 		pcic_putcb(pcic, CB_CONTROL, cbctl);
6696*7656SSherry.Moore@Sun.COM 
6697*7656SSherry.Moore@Sun.COM 		if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) {
66982305Sstevel 		pcic_mswait(pcic, socket, pcic_powerdelay);
66992305Sstevel 		return (SUCCESS);
6700*7656SSherry.Moore@Sun.COM 		}
6701*7656SSherry.Moore@Sun.COM 		for (ind = 0; ind < 20; ind++) {
67022305Sstevel 		cbstev = pcic_getcb(pcic, CB_STATUS_EVENT);
67032305Sstevel 
67042305Sstevel 		if (cbstev & CB_SE_POWER_CYCLE) {
67052305Sstevel 
67062305Sstevel 		/*
67072305Sstevel 		 * delay 400 ms: though the standard defines that the Vcc
67082305Sstevel 		 * set-up time is 20 ms, some PC-Card bridge requires longer
67092305Sstevel 		 * duration.
67102305Sstevel 		 * Note: We should check the status AFTER the delay to give time
67112305Sstevel 		 * for things to stabilize.
67122305Sstevel 		 */
6713*7656SSherry.Moore@Sun.COM 			pcic_mswait(pcic, socket, 400);
6714*7656SSherry.Moore@Sun.COM 
6715*7656SSherry.Moore@Sun.COM 			cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
6716*7656SSherry.Moore@Sun.COM 			if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) {
67172305Sstevel 			/* break; */
67182305Sstevel 			cmn_err(CE_WARN, "cbus_powerctl: power off??\n");
6719*7656SSherry.Moore@Sun.COM 			}
6720*7656SSherry.Moore@Sun.COM 			if (cbctl & CB_PS_BADVCC) {
67212305Sstevel 			cmn_err(CE_WARN, "cbus_powerctl: bad power request\n");
67222305Sstevel 			break;
6723*7656SSherry.Moore@Sun.COM 			}
67242305Sstevel 
67252305Sstevel #if defined(PCIC_DEBUG)
6726*7656SSherry.Moore@Sun.COM 			pcic_err(pcic->dip, 8,
6727*7656SSherry.Moore@Sun.COM 			    "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)",
6728*7656SSherry.Moore@Sun.COM 			    cbstev, pcic_getcb(pcic, CB_PRESENT_STATE),
6729*7656SSherry.Moore@Sun.COM 			    cbctl, orig_cbctl);
67302305Sstevel #endif
6731*7656SSherry.Moore@Sun.COM 			if (pcic_cbdoreset_during_poweron &&
6732*7656SSherry.Moore@Sun.COM 			    (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
6733*7656SSherry.Moore@Sun.COM 				pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
6734*7656SSherry.Moore@Sun.COM 			}
6735*7656SSherry.Moore@Sun.COM 			return (SUCCESS);
67362305Sstevel 		}
67372305Sstevel 		pcic_mswait(pcic, socket, 40);
6738*7656SSherry.Moore@Sun.COM 		}
6739*7656SSherry.Moore@Sun.COM 		if (pcic_cbdoreset_during_poweron &&
6740*7656SSherry.Moore@Sun.COM 		    (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
6741*7656SSherry.Moore@Sun.COM 			pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
6742*7656SSherry.Moore@Sun.COM 		}
6743*7656SSherry.Moore@Sun.COM 		cmn_err(CE_WARN,
67442305Sstevel 		    "pcic socket %d: Power didn't get turned on/off!\n"
67452305Sstevel 		    "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) "
67462305Sstevel 		    "vcc %d vpp1 %d", socket, cbstev,
67472305Sstevel 		    pcic_getcb(pcic, CB_PRESENT_STATE),
67482305Sstevel 		    cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1);
6749*7656SSherry.Moore@Sun.COM 		return (BAD_VCC);
67502305Sstevel 	}
67512305Sstevel 	return (SUCCESS);
67522305Sstevel }
67532305Sstevel 
67542305Sstevel static int	pcic_do_pprintf = 0;
67552305Sstevel 
67562305Sstevel static void
67572305Sstevel pcic_dump_debqueue(char *msg)
67582305Sstevel {
67592305Sstevel 	struct debounce *debp = pcic_deb_queue;
67602305Sstevel 	clock_t lbolt;
67612305Sstevel 
67622305Sstevel 	(void) drv_getparm(LBOLT, &lbolt);
67632305Sstevel 	pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" :
67642305Sstevel 	    "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt);
67652305Sstevel 	while (debp) {
67662305Sstevel 		pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n",
67672305Sstevel 		    (void *) debp, (int)debp->expire, (void *) debp->next,
67682305Sstevel 		    debp->pcs->pcs_debounce_id);
67692305Sstevel 		debp = debp->next;
67702305Sstevel 	}
67712305Sstevel }
67722305Sstevel 
67732305Sstevel 
67742305Sstevel /* PRINTFLIKE3 */
67752305Sstevel static void
67762305Sstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...)
67772305Sstevel {
67782305Sstevel 	if (pcic_debug && (level <= pcic_debug)) {
67792305Sstevel 		va_list adx;
67802305Sstevel 		int	instance;
67812305Sstevel 		char	buf[256];
67822305Sstevel 		const char	*name;
67832305Sstevel #if !defined(PCIC_DEBUG)
67842305Sstevel 		int	ce;
67852305Sstevel 		char	qmark = 0;
67862305Sstevel 
67872305Sstevel 		if (level <= 3)
67882305Sstevel 			ce = CE_WARN;
67892305Sstevel 		else
67902305Sstevel 			ce = CE_CONT;
67912305Sstevel 		if (level == 4)
67922305Sstevel 			qmark = 1;
67932305Sstevel #endif
67942305Sstevel 
67952305Sstevel 		if (dip) {
67962305Sstevel 			instance = ddi_get_instance(dip);
67972305Sstevel 			/* name = ddi_binding_name(dip); */
67982305Sstevel 			name = ddi_driver_name(dip);
67992305Sstevel 		} else {
68002305Sstevel 			instance = 0;
68012305Sstevel 			name = "";
68022305Sstevel 		}
68032305Sstevel 
68042305Sstevel 		va_start(adx, fmt);
68052305Sstevel 		(void) vsprintf(buf, fmt, adx);
68062305Sstevel 		va_end(adx);
68072305Sstevel 
68082305Sstevel #if defined(PCIC_DEBUG)
68092305Sstevel 		if (pcic_do_pprintf) {
68102305Sstevel 			if (dip) {
68112305Sstevel 				if (instance >= 0)
68122305Sstevel 					prom_printf("%s(%d),0x%p: %s", name,
68137240Srh87107 					    instance, (void *)dip, buf);
68142305Sstevel 				else
68152305Sstevel 					prom_printf("%s,0x%p: %s",
68167240Srh87107 					    name, (void *)dip, buf);
68172305Sstevel 			} else
68182305Sstevel 				prom_printf(buf);
68192305Sstevel 		} else {
68202305Sstevel 			if (dip) {
68212305Sstevel 				if (instance >= 0)
68222305Sstevel 					cmn_err(CE_CONT, "%s(%d),0x%p: %s",
68232305Sstevel 					    name, instance, (void *) dip, buf);
68242305Sstevel 				else
68252305Sstevel 					cmn_err(CE_CONT, "%s,0x%p: %s",
68262305Sstevel 					    name, (void *) dip, buf);
68272305Sstevel 			} else
68282305Sstevel 				cmn_err(CE_CONT, buf);
68292305Sstevel 		}
68302305Sstevel #else
68312305Sstevel 		if (dip)
68322305Sstevel 			cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name,
68332305Sstevel 			    instance, buf);
68342305Sstevel 		else
68352305Sstevel 			cmn_err(ce, qmark ? "?%s" : buf, buf);
68362305Sstevel #endif
68372305Sstevel 	}
68382305Sstevel }
6839