xref: /illumos-gate/usr/src/uts/common/pcmcia/nexus/pcmcia.c (revision 39b361b2ebefcef5612a54ae5cbd2179e19be296)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a9fb0ae8Srw  * Common Development and Distribution License (the "License").
6a9fb0ae8Srw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2211c2b4c0Srw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * PCMCIA NEXUS
287c478bd9Sstevel@tonic-gate  *	The PCMCIA module is a generalized interface for
297c478bd9Sstevel@tonic-gate  *	implementing PCMCIA nexus drivers.  It preserves
307c478bd9Sstevel@tonic-gate  *	the logical socket name space while allowing multiple
317c478bd9Sstevel@tonic-gate  *	instances of the hardware to be properly represented
327c478bd9Sstevel@tonic-gate  *	in the device tree.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  *	The nexus also exports events to an event manager
357c478bd9Sstevel@tonic-gate  *	driver if it has registered.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/user.h>
417c478bd9Sstevel@tonic-gate #include <sys/buf.h>
427c478bd9Sstevel@tonic-gate #include <sys/file.h>
437c478bd9Sstevel@tonic-gate #include <sys/uio.h>
447c478bd9Sstevel@tonic-gate #include <sys/conf.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
477c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
487c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
497c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
507c478bd9Sstevel@tonic-gate #include <sys/debug.h>
517c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
527c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
537c478bd9Sstevel@tonic-gate #include <sys/cred.h>
547c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
557c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
567c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
577c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
587c478bd9Sstevel@tonic-gate #include <sys/callb.h>
597c478bd9Sstevel@tonic-gate #include <sys/param.h>
607c478bd9Sstevel@tonic-gate #include <sys/thread.h>
617c478bd9Sstevel@tonic-gate #include <sys/proc.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #include <sys/pctypes.h>
647c478bd9Sstevel@tonic-gate #include <sys/pcmcia.h>
657c478bd9Sstevel@tonic-gate #include <sys/sservice.h>
667c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
677c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
687c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
697c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
707c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #ifdef sparc
737c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
747a364d25Sschwartz 
757a364d25Sschwartz #elif defined(__x86) || defined(__amd64)
767a364d25Sschwartz #include <sys/mach_intr.h>
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #undef SocketServices
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* some bus specific stuff */
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* need PCI regspec size for worst case at present */
847c478bd9Sstevel@tonic-gate #include <sys/pci.h>
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate typedef struct pcmcia_logical_socket {
877c478bd9Sstevel@tonic-gate 	int			ls_socket; /* adapter's socket number */
887c478bd9Sstevel@tonic-gate 	uint32_t		ls_flags;
897c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter	*ls_adapter;
907c478bd9Sstevel@tonic-gate 	pcmcia_if_t		*ls_if;
917c478bd9Sstevel@tonic-gate 	dev_info_t		*ls_sockdrv;
927c478bd9Sstevel@tonic-gate 	dev_info_t		*ls_dip[PCMCIA_MAX_FUNCTIONS];
937c478bd9Sstevel@tonic-gate 	dev_info_t		*ls_mfintr_dip;
947c478bd9Sstevel@tonic-gate 	int			ls_functions;
957c478bd9Sstevel@tonic-gate 	uint32_t		ls_cs_events;
967c478bd9Sstevel@tonic-gate 	uint32_t		ls_intr_pri;
977c478bd9Sstevel@tonic-gate 	uint32_t		ls_intr_vec;
987c478bd9Sstevel@tonic-gate 	int			ls_intrrefs;
997c478bd9Sstevel@tonic-gate 	struct intrspec		ls_intrspec; /* MFC intrspec */
1007c478bd9Sstevel@tonic-gate 	inthandler_t		*ls_inthandlers; /* for multifunction cards */
1017c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t	ls_iblk;
1027c478bd9Sstevel@tonic-gate 	ddi_idevice_cookie_t	ls_idev;
1037c478bd9Sstevel@tonic-gate 	kmutex_t		ls_ilock;
1047c478bd9Sstevel@tonic-gate 	int			ls_error; /* error for CS return */
1057c478bd9Sstevel@tonic-gate } pcmcia_logical_socket_t;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * entry points used by the true nexus
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate int pcmcia_detach(dev_info_t *, ddi_detach_cmd_t);
1117c478bd9Sstevel@tonic-gate int pcmcia_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
1127c478bd9Sstevel@tonic-gate int pcmcia_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t,
1137c478bd9Sstevel@tonic-gate 			int, char *, caddr_t, int *);
1147c478bd9Sstevel@tonic-gate void pcmcia_set_assigned(dev_info_t *, int, ra_return_t *);
1157c478bd9Sstevel@tonic-gate int pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1167c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * prototypes used internally by the nexus and sometimes Card Services
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate int SocketServices(int function, ...);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate void *CISParser(int function, ...);
1257c478bd9Sstevel@tonic-gate extern void *(*cis_parser)(int, ...);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate struct regspec *pcmcia_cons_regspec(dev_info_t *, int, uchar_t *,
1287c478bd9Sstevel@tonic-gate 					ra_return_t *);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static int (*pcmcia_card_services)(int, ...) = NULL;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * variables used in the logical/physical mappings
1347c478bd9Sstevel@tonic-gate  * that the nexus common code maintains.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate struct pcmcia_adapter *pcmcia_adapters[PCMCIA_MAX_ADAPTERS];
1377c478bd9Sstevel@tonic-gate int    pcmcia_num_adapters;
1387c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *pcmcia_sockets[PCMCIA_MAX_SOCKETS];
1397c478bd9Sstevel@tonic-gate int    pcmcia_num_sockets;
1407c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *pcmcia_windows[PCMCIA_MAX_WINDOWS];
1417c478bd9Sstevel@tonic-gate int    pcmcia_num_windows;
1427c478bd9Sstevel@tonic-gate struct power_entry pcmcia_power_table[PCMCIA_MAX_POWER];
1437c478bd9Sstevel@tonic-gate int	pcmcia_num_power;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate struct pcmcia_mif *pcmcia_mif_handlers = NULL;
1467c478bd9Sstevel@tonic-gate pcm_dev_node_t *pcmcia_devnodes = NULL;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate kmutex_t pcmcia_global_lock;
1497c478bd9Sstevel@tonic-gate kcondvar_t pcmcia_condvar;
1507c478bd9Sstevel@tonic-gate kmutex_t pcmcia_enum_lock;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * Mapping of the device "type" to names acceptable to
1547c478bd9Sstevel@tonic-gate  * the DDI
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate static char *pcmcia_dev_type[] = {
1577c478bd9Sstevel@tonic-gate 	"multifunction",
1587c478bd9Sstevel@tonic-gate 	"byte",
1597c478bd9Sstevel@tonic-gate 	"serial",
1607c478bd9Sstevel@tonic-gate 	"parallel",
1617c478bd9Sstevel@tonic-gate 	"block",
1627c478bd9Sstevel@tonic-gate 	"display",
1637c478bd9Sstevel@tonic-gate 	"network",
1647c478bd9Sstevel@tonic-gate 	"block",
1657c478bd9Sstevel@tonic-gate 	"byte"
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate char *pcmcia_default_pm_mode = "parental-suspend-resume";
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * generic names from the approved list:
1727c478bd9Sstevel@tonic-gate  *	disk tape pci sbus scsi token-ring isa keyboard display mouse
1737c478bd9Sstevel@tonic-gate  *	audio ethernet timer memory parallel serial rtc nvram scanner
1747c478bd9Sstevel@tonic-gate  *	floppy(controller) fddi isdn atm ide pccard video-in video-out
1757c478bd9Sstevel@tonic-gate  * in some cases there will need to be device class dependent names.
1767c478bd9Sstevel@tonic-gate  * network -> ethernet, token-ring, etc.
1777c478bd9Sstevel@tonic-gate  * this list is a first guess and is used when all else fails.
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate char *pcmcia_generic_names[] = {
1817c478bd9Sstevel@tonic-gate 	"multifunction",
1827c478bd9Sstevel@tonic-gate 	"memory",
1837c478bd9Sstevel@tonic-gate 	"serial",
1847c478bd9Sstevel@tonic-gate 	"parallel",
1857c478bd9Sstevel@tonic-gate 	"disk",
1867c478bd9Sstevel@tonic-gate 	"video",		/* no spec for video-out yet */
1877c478bd9Sstevel@tonic-gate 	"network",
1887c478bd9Sstevel@tonic-gate 	"aims",
1897c478bd9Sstevel@tonic-gate 	"scsi",
1907c478bd9Sstevel@tonic-gate 	"security"
1917c478bd9Sstevel@tonic-gate };
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate #define	PCM_GENNAME_SIZE	(sizeof (pcmcia_generic_names) / \
1947c478bd9Sstevel@tonic-gate 					sizeof (char *))
1957c478bd9Sstevel@tonic-gate #define	PCMCIA_MAP_IO	0x0
1967c478bd9Sstevel@tonic-gate #define	PCMCIA_MAP_MEM	0x1
1978134ee03Srw #define	PPB_SUBTRACTIVE	((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \
1988134ee03Srw 		(PCI_BRIDGE_PCI_IF_SUBDECODE))
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * The following should be 2^^n - 1
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate #define	PCMCIA_SOCKET_BITS	0x7f
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG
2067c478bd9Sstevel@tonic-gate int pcmcia_debug = 0x0;
2077c478bd9Sstevel@tonic-gate static void pcmcia_dump_minors(dev_info_t *);
2087c478bd9Sstevel@tonic-gate #endif
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static f_tt *pcmcia_cs_event = NULL;
2117c478bd9Sstevel@tonic-gate int pcmcia_timer_id;
2127c478bd9Sstevel@tonic-gate dev_info_t	*pcmcia_dip;
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * XXX - See comments in cs.c
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate static f_tt *pcmcia_cis_parser = NULL;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate extern struct pc_socket_services pc_socket_services;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /* some function declarations */
2217c478bd9Sstevel@tonic-gate static int pcm_adapter_callback(dev_info_t *, int, int, int);
2227c478bd9Sstevel@tonic-gate extern void pcmcia_init_adapter(anp_t *, dev_info_t *);
2237c478bd9Sstevel@tonic-gate extern void pcmcia_find_cards(anp_t *);
2247c478bd9Sstevel@tonic-gate extern void pcmcia_merge_power(struct power_entry *);
2257c478bd9Sstevel@tonic-gate extern void pcmcia_do_resume(int, pcmcia_logical_socket_t *);
2267c478bd9Sstevel@tonic-gate extern void pcmcia_resume(int, pcmcia_logical_socket_t *);
2277c478bd9Sstevel@tonic-gate extern void pcmcia_do_suspend(int, pcmcia_logical_socket_t *);
2287c478bd9Sstevel@tonic-gate extern void pcm_event_manager(int, int, void *);
2297c478bd9Sstevel@tonic-gate static void pcmcia_create_dev_info(int);
2307c478bd9Sstevel@tonic-gate static int pcmcia_create_device(ss_make_device_node_t *);
2317c478bd9Sstevel@tonic-gate static void pcmcia_init_devinfo(dev_info_t *, struct pcm_device_info *);
2327c478bd9Sstevel@tonic-gate void pcmcia_fix_string(char *str);
2337c478bd9Sstevel@tonic-gate dev_info_t *pcmcia_number_socket(dev_info_t *, int);
2347c478bd9Sstevel@tonic-gate static int pcmcia_merge_conf(dev_info_t *);
2357c478bd9Sstevel@tonic-gate static uint32_t pcmcia_mfc_intr(caddr_t, caddr_t);
2367c478bd9Sstevel@tonic-gate void pcmcia_free_resources(dev_info_t *);
2377c478bd9Sstevel@tonic-gate static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd);
2387c478bd9Sstevel@tonic-gate int pcmcia_get_intr(dev_info_t *, int);
2397c478bd9Sstevel@tonic-gate int pcmcia_return_intr(dev_info_t *, int);
2408134ee03Srw int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *,
2418134ee03Srw 		dev_info_t **);
2427c478bd9Sstevel@tonic-gate int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate extern int cs_init(void);
2457c478bd9Sstevel@tonic-gate extern int cs_deinit(void);
2467c478bd9Sstevel@tonic-gate extern void cisp_init(void);
2477c478bd9Sstevel@tonic-gate extern void cis_deinit(void);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate  * non-DDI compliant functions are listed here
2517c478bd9Sstevel@tonic-gate  * some will be declared while others that have
2527c478bd9Sstevel@tonic-gate  * entries in .h files. All will be commented on.
2537c478bd9Sstevel@tonic-gate  *
2547c478bd9Sstevel@tonic-gate  * with declarations:
2557c478bd9Sstevel@tonic-gate  *	ddi_add_child
2567c478bd9Sstevel@tonic-gate  *	ddi_binding_name
2577c478bd9Sstevel@tonic-gate  *	ddi_bus_prop_op
2587c478bd9Sstevel@tonic-gate  *	ddi_ctlops
2597c478bd9Sstevel@tonic-gate  *	ddi_find_devinfo
2607c478bd9Sstevel@tonic-gate  *	ddi_get_name_addr
2617c478bd9Sstevel@tonic-gate  *	ddi_get_parent_data
2627c478bd9Sstevel@tonic-gate  *	ddi_hold_installed_driver
2637c478bd9Sstevel@tonic-gate  *	ddi_name_to_major
2647c478bd9Sstevel@tonic-gate  *	ddi_node_name
2657c478bd9Sstevel@tonic-gate  *	ddi_pathname
2667c478bd9Sstevel@tonic-gate  *	ddi_rele_driver
2677c478bd9Sstevel@tonic-gate  *	ddi_set_name_addr
2687c478bd9Sstevel@tonic-gate  *	ddi_set_parent_data
2697c478bd9Sstevel@tonic-gate  *	ddi_unorphan_devs
2707c478bd9Sstevel@tonic-gate  *	i_ddi_bind_node_to_driver
2717c478bd9Sstevel@tonic-gate  *	i_ddi_bind_node_to_driver
2727c478bd9Sstevel@tonic-gate  *	i_ddi_bus_map
2737c478bd9Sstevel@tonic-gate  *	i_ddi_map_fault
2747c478bd9Sstevel@tonic-gate  *	i_ddi_mem_alloc
2757c478bd9Sstevel@tonic-gate  *	i_ddi_mem_alloc
2767c478bd9Sstevel@tonic-gate  *	i_ddi_mem_free
2777c478bd9Sstevel@tonic-gate  *	i_ddi_mem_free
2787c478bd9Sstevel@tonic-gate  *	modload
2797c478bd9Sstevel@tonic-gate  *	modunload
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate extern void ddi_unorphan_devs(major_t);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /* Card&Socket Services entry points */
2857c478bd9Sstevel@tonic-gate static int GetCookiesAndDip(sservice_t *);
2867c478bd9Sstevel@tonic-gate static int SSGetAdapter(get_adapter_t *);
2877c478bd9Sstevel@tonic-gate static int SSGetPage(get_page_t *);
2887c478bd9Sstevel@tonic-gate static int SSGetSocket(get_socket_t *);
2897c478bd9Sstevel@tonic-gate static int SSGetStatus(get_ss_status_t *);
2907c478bd9Sstevel@tonic-gate static int SSGetWindow(get_window_t *);
2917c478bd9Sstevel@tonic-gate static int SSInquireAdapter(inquire_adapter_t *);
2927c478bd9Sstevel@tonic-gate static int SSInquireSocket(inquire_socket_t *);
2937c478bd9Sstevel@tonic-gate static int SSInquireWindow(inquire_window_t *);
2947c478bd9Sstevel@tonic-gate static int SSResetSocket(int, int);
2957c478bd9Sstevel@tonic-gate static int SSSetPage(set_page_t *);
2967c478bd9Sstevel@tonic-gate static int SSSetSocket(set_socket_t *);
2977c478bd9Sstevel@tonic-gate static int SSSetWindow(set_window_t *);
2987c478bd9Sstevel@tonic-gate static int SSSetIRQHandler(set_irq_handler_t *);
2997c478bd9Sstevel@tonic-gate static int SSClearIRQHandler(clear_irq_handler_t *);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate static struct modldrv modlmisc = {
3027c478bd9Sstevel@tonic-gate 	&mod_miscops,		/* Type of module. This one is a driver */
303*39b361b2SRichard Bean 	"PCMCIA Nexus Support", /* Name of the module. */
3047c478bd9Sstevel@tonic-gate };
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3077c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
3087c478bd9Sstevel@tonic-gate };
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate int
3117c478bd9Sstevel@tonic-gate _init()
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate 	int	ret;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	cisp_init();
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (cs_init() != CS_SUCCESS) {
3187c478bd9Sstevel@tonic-gate 	    if (cs_deinit() != CS_SUCCESS)
3197c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia: _init cs_deinit error\n");
3207c478bd9Sstevel@tonic-gate 	    return (-1);
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	mutex_init(&pcmcia_global_lock, NULL, MUTEX_DEFAULT, NULL);
3247c478bd9Sstevel@tonic-gate 	cv_init(&pcmcia_condvar, NULL, CV_DRIVER, NULL);
3257c478bd9Sstevel@tonic-gate 	mutex_init(&pcmcia_enum_lock, NULL, MUTEX_DEFAULT, NULL);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if ((ret = mod_install(&modlinkage)) != 0) {
3287c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcmcia_global_lock);
3297c478bd9Sstevel@tonic-gate 		cv_destroy(&pcmcia_condvar);
3307c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcmcia_enum_lock);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 	return (ret);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate int
3367c478bd9Sstevel@tonic-gate _fini()
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	int	ret;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if ((ret = mod_remove(&modlinkage)) == 0) {
3417c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcmcia_global_lock);
3427c478bd9Sstevel@tonic-gate 		cv_destroy(&pcmcia_condvar);
3437c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcmcia_enum_lock);
3447c478bd9Sstevel@tonic-gate 		cis_deinit();
3457c478bd9Sstevel@tonic-gate 		if (cs_deinit() != CS_SUCCESS) {
3467c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia: _fini cs_deinit error\n");
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 	return (ret);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate int
3537c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate extern pri_t minclsyspri;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * pcmcia_attach()
3627c478bd9Sstevel@tonic-gate  *	the attach routine must make sure that everything needed is present
3637c478bd9Sstevel@tonic-gate  *	including real hardware.  The sequence of events is:
3647c478bd9Sstevel@tonic-gate  *		attempt to load all adapter drivers
3657c478bd9Sstevel@tonic-gate  *		attempt to load Card Services (which _depends_on pcmcia)
3667c478bd9Sstevel@tonic-gate  *		initialize logical sockets
3677c478bd9Sstevel@tonic-gate  *		report the nexus exists
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate int
3717c478bd9Sstevel@tonic-gate pcmcia_attach(dev_info_t *dip, anp_t *adapter)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	int count, done, i;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
3767c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
3777c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_attach: dip=0x%p adapter=0x%p\n",
3787c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)adapter);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate #endif
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	pcmcia_dip = dip;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	mutex_enter(&pcmcia_enum_lock);
3857c478bd9Sstevel@tonic-gate 	mutex_enter(&pcmcia_global_lock);
3867c478bd9Sstevel@tonic-gate 	if (pcmcia_num_adapters == 0) {
3877c478bd9Sstevel@tonic-gate 		pcmcia_cis_parser = (f_tt *)CISParser;
3887c478bd9Sstevel@tonic-gate 		cis_parser = (void *(*)(int, ...)) CISParser;
3897c478bd9Sstevel@tonic-gate 		pcmcia_cs_event = (f_tt *)cs_event;
3907c478bd9Sstevel@tonic-gate 		cs_socket_services = SocketServices;
3917c478bd9Sstevel@tonic-gate 		/* tell CS we are up with basic init level */
3927c478bd9Sstevel@tonic-gate 		(void) cs_event(PCE_SS_INIT_STATE, PCE_SS_STATE_INIT, 0);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
3967c478bd9Sstevel@tonic-gate 	    PCM_DEVICETYPE, "pccard");
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);	/* directory/device naming */
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/*
4017c478bd9Sstevel@tonic-gate 	 * now setup any power management stuff necessary.
4027c478bd9Sstevel@tonic-gate 	 * we do it here in order to ensure that all PC Card nexi
4037c478bd9Sstevel@tonic-gate 	 * implement it.
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	if (pm_create_components(dip, 1) != DDI_SUCCESS) {
4077c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: not power managed\n",
4087c478bd9Sstevel@tonic-gate 			ddi_get_name_addr(dip));
4097c478bd9Sstevel@tonic-gate 	} else {
4107c478bd9Sstevel@tonic-gate 		pm_set_normal_power(dip, 0, 1);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * setup the info necessary for Card Services/SocketServices
4157c478bd9Sstevel@tonic-gate 	 * and notify CS when ready.
4167c478bd9Sstevel@tonic-gate 	 */
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	pcmcia_free_resources(dip);
4197c478bd9Sstevel@tonic-gate 	pcmcia_init_adapter(adapter, dip);
4207c478bd9Sstevel@tonic-gate 	/* exit mutex so CS can run for any cards found */
4217c478bd9Sstevel@tonic-gate 	mutex_exit(&pcmcia_global_lock);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/*
4247c478bd9Sstevel@tonic-gate 	 * make sure the devices are identified before
4257c478bd9Sstevel@tonic-gate 	 * returning.  We do this by checking each socket to see if
4267c478bd9Sstevel@tonic-gate 	 * a card is present.  If there is one, and there isn't a dip,
4277c478bd9Sstevel@tonic-gate 	 * we can't be done.  We scan the list of sockets doing the
4287c478bd9Sstevel@tonic-gate 	 * check. if we aren't done, wait for a condition variable to
4297c478bd9Sstevel@tonic-gate 	 * wakeup.
4307c478bd9Sstevel@tonic-gate 	 * Because we can miss a wakeup and because things can
4317c478bd9Sstevel@tonic-gate 	 * take time, we do eventually give up and have a timeout.
4327c478bd9Sstevel@tonic-gate 	 */
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	for (count = 0, done = 0;
4357c478bd9Sstevel@tonic-gate 	    done == 0 && count < max(pcmcia_num_sockets, 16);
4367c478bd9Sstevel@tonic-gate 	    count++) {
4377c478bd9Sstevel@tonic-gate 		done = 1;
4387c478bd9Sstevel@tonic-gate 		/* block CS while checking so we don't miss anything */
4397c478bd9Sstevel@tonic-gate 		mutex_enter(&pcmcia_global_lock);
4407c478bd9Sstevel@tonic-gate 		for (i = 0; i < pcmcia_num_sockets; i++) {
4417c478bd9Sstevel@tonic-gate 			get_ss_status_t status;
4427c478bd9Sstevel@tonic-gate 			if (pcmcia_sockets[i] == NULL)
4437c478bd9Sstevel@tonic-gate 				continue;
4447c478bd9Sstevel@tonic-gate 			bzero(&status, sizeof (status));
4457c478bd9Sstevel@tonic-gate 			status.socket = i;
4467c478bd9Sstevel@tonic-gate 			if (SSGetStatus(&status) == SUCCESS) {
4477c478bd9Sstevel@tonic-gate 				if (status.CardState & SBM_CD &&
4487c478bd9Sstevel@tonic-gate 				    pcmcia_sockets[i]->ls_dip[0] == NULL) {
4497c478bd9Sstevel@tonic-gate 					done = 0;
4507c478bd9Sstevel@tonic-gate 				}
4517c478bd9Sstevel@tonic-gate 			}
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 		/* only wait if we aren't done with this set */
4547c478bd9Sstevel@tonic-gate 		if (!done) {
4557c478bd9Sstevel@tonic-gate 			mutex_exit(&pcmcia_global_lock);
4567c478bd9Sstevel@tonic-gate 			delay(10); /* give up CPU for a time */
4577c478bd9Sstevel@tonic-gate 			mutex_enter(&pcmcia_global_lock);
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 		mutex_exit(&pcmcia_global_lock);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	mutex_exit(&pcmcia_enum_lock);
4637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * pcmcia_detach
4687c478bd9Sstevel@tonic-gate  *	unload everything and then detach the nexus
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate /* ARGSUSED */
4717c478bd9Sstevel@tonic-gate int
4727c478bd9Sstevel@tonic-gate pcmcia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	switch (cmd) {
4757c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4767c478bd9Sstevel@tonic-gate 		pm_destroy_components(dip);
4777c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/*
4807c478bd9Sstevel@tonic-gate 	 * resume from a checkpoint
4817c478bd9Sstevel@tonic-gate 	 * We don't do anything special here since the adapter
4827c478bd9Sstevel@tonic-gate 	 * driver will generate resume events that we intercept
4837c478bd9Sstevel@tonic-gate 	 * and convert to insert events.
4847c478bd9Sstevel@tonic-gate 	 */
4857c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4867c478bd9Sstevel@tonic-gate 	case DDI_PM_SUSPEND:
4877c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	default:
4907c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * card_services_error()
4967c478bd9Sstevel@tonic-gate  *	used to make 2.4/2.5 drivers get an error when
4977c478bd9Sstevel@tonic-gate  *	they try to initialize.
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate static int
5007c478bd9Sstevel@tonic-gate card_services_error()
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	return (CS_BAD_VERSION);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate static int (*cs_error_ptr)() = card_services_error;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate  * pcmcia_ctlops
5087c478bd9Sstevel@tonic-gate  *	handle the nexus control operations for the cases where
5097c478bd9Sstevel@tonic-gate  *	a PC Card driver gets called and we need to modify the
5107c478bd9Sstevel@tonic-gate  *	devinfo structure or otherwise do bus specific operations
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate int
5137c478bd9Sstevel@tonic-gate pcmcia_ctlops(dev_info_t *dip, dev_info_t *rdip,
5147c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	int e;
5177c478bd9Sstevel@tonic-gate 	char name[64];
5187c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
5197c478bd9Sstevel@tonic-gate 	power_req_t *pm;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
5227c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
5237c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_ctlops(%p, %p, %d, %p, %p)\n",
5247c478bd9Sstevel@tonic-gate 			(void *)dip, (void *)rdip, ctlop, (void *)arg,
5257c478bd9Sstevel@tonic-gate 			(void *)result);
5267c478bd9Sstevel@tonic-gate 		if (rdip != NULL && ddi_get_name(rdip) != NULL)
5277c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\t[%s]\n", ddi_get_name(rdip));
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate #endif
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	switch (ctlop) {
5327c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
5337c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
5347c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 		if (strcmp("pcs", ddi_node_name(rdip)) == 0)
5377c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "?PCCard socket %d at %s@%s\n",
5387c478bd9Sstevel@tonic-gate 				ddi_get_instance(rdip),
5397c478bd9Sstevel@tonic-gate 				ddi_driver_name(dip), ddi_get_name_addr(dip));
5407c478bd9Sstevel@tonic-gate 		else
5417c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "?%s%d at %s@%s in socket %d\n",
5427c478bd9Sstevel@tonic-gate 				ddi_driver_name(rdip),
5437c478bd9Sstevel@tonic-gate 				ddi_get_instance(rdip),
5447c478bd9Sstevel@tonic-gate 				ddi_driver_name(dip),
5457c478bd9Sstevel@tonic-gate 				ddi_get_name_addr(dip),
5467c478bd9Sstevel@tonic-gate 				CS_GET_SOCKET_NUMBER(
5477c478bd9Sstevel@tonic-gate 				    ddi_getprop(DDI_DEV_T_NONE, rdip,
5487c478bd9Sstevel@tonic-gate 				    DDI_PROP_DONTPASS,
5497c478bd9Sstevel@tonic-gate 				    PCM_DEV_SOCKET, -1)));
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
5547c478bd9Sstevel@tonic-gate 		/*
5557c478bd9Sstevel@tonic-gate 		 * we get control here before the child is called.
5567c478bd9Sstevel@tonic-gate 		 * we can change things if necessary.  This is where
5577c478bd9Sstevel@tonic-gate 		 * the CardServices hook gets planted.
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
5607c478bd9Sstevel@tonic-gate 		if (pcmcia_debug) {
5617c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia: init child: %s(%d) @%p\n",
5627c478bd9Sstevel@tonic-gate 				ddi_node_name(arg), ddi_get_instance(arg),
5637c478bd9Sstevel@tonic-gate 				(void *)arg);
5647c478bd9Sstevel@tonic-gate 			if (DEVI(arg)->devi_binding_name != NULL)
5657c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "\tbinding_name=%s\n",
5667c478bd9Sstevel@tonic-gate 					DEVI(arg)->devi_binding_name);
5677c478bd9Sstevel@tonic-gate 			if (DEVI(arg)->devi_node_name != NULL)
5687c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "\tnode_name=%s\n",
5697c478bd9Sstevel@tonic-gate 					DEVI(arg)->devi_node_name);
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate #endif
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
5747c478bd9Sstevel@tonic-gate 			ddi_get_parent_data((dev_info_t *)arg);
5757c478bd9Sstevel@tonic-gate 		if (ppd == NULL)
5767c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		if (strcmp("pcs", ddi_node_name((dev_info_t *)arg)) == 0) {
5797c478bd9Sstevel@tonic-gate 			if (ppd == NULL)
5807c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
5817c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x",
5827c478bd9Sstevel@tonic-gate 			    (int)ppd->ppd_reg[0].phys_hi);
5837c478bd9Sstevel@tonic-gate 			ddi_set_name_addr((dev_info_t *)arg, name);
5847c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		/*
5887c478bd9Sstevel@tonic-gate 		 * We don't want driver.conf files that stay in
5897c478bd9Sstevel@tonic-gate 		 * pseudo device form.	It is acceptable to have
5907c478bd9Sstevel@tonic-gate 		 * .conf files add properties only.
5917c478bd9Sstevel@tonic-gate 		 */
5927c478bd9Sstevel@tonic-gate 		if (ndi_dev_is_persistent_node((dev_info_t *)arg) == 0) {
5937c478bd9Sstevel@tonic-gate 			(void) pcmcia_merge_conf((dev_info_t *)arg);
5947c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: %s.conf invalid",
5957c478bd9Sstevel@tonic-gate 				ddi_get_name((dev_info_t *)arg),
5967c478bd9Sstevel@tonic-gate 				ddi_get_instance((dev_info_t *)arg),
5977c478bd9Sstevel@tonic-gate 				ddi_get_name((dev_info_t *)arg));
5987c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5997c478bd9Sstevel@tonic-gate 		}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
6037c478bd9Sstevel@tonic-gate 		if (pcmcia_debug && ppd != NULL) {
6047c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tnreg=%x, intr=%x, socket=%x,"
6057c478bd9Sstevel@tonic-gate 				" function=%x, active=%x, flags=%x\n",
6067c478bd9Sstevel@tonic-gate 				ppd->ppd_nreg, ppd->ppd_intr,
6077c478bd9Sstevel@tonic-gate 				ppd->ppd_socket, ppd->ppd_function,
6087c478bd9Sstevel@tonic-gate 				ppd->ppd_active, ppd->ppd_flags);
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate #endif
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		/*
6137c478bd9Sstevel@tonic-gate 		 * make sure names are relative to socket number
6147c478bd9Sstevel@tonic-gate 		 */
6157c478bd9Sstevel@tonic-gate 		if (ppd->ppd_function > 0) {
6167c478bd9Sstevel@tonic-gate 			int sock;
6177c478bd9Sstevel@tonic-gate 			int func;
6187c478bd9Sstevel@tonic-gate 			sock = ppd->ppd_socket;
6197c478bd9Sstevel@tonic-gate 			func = ppd->ppd_function;
6207c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x,%x", sock, func);
6217c478bd9Sstevel@tonic-gate 		} else {
6227c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x", ppd->ppd_socket);
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, name);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
6277c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
6287c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia: system init done for %s [%s] "
6297c478bd9Sstevel@tonic-gate 				"nodeid: %x @%s\n",
6307c478bd9Sstevel@tonic-gate 				ddi_get_name(arg), ddi_get_name_addr(arg),
6317c478bd9Sstevel@tonic-gate 				DEVI(arg)->devi_nodeid, name);
6327c478bd9Sstevel@tonic-gate 		if (pcmcia_debug > 1)
6337c478bd9Sstevel@tonic-gate 			pcmcia_dump_minors((dev_info_t *)arg);
6347c478bd9Sstevel@tonic-gate #endif
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
6417c478bd9Sstevel@tonic-gate 		if (pcmcia_debug) {
6427c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia: uninit child: %s(%d) @%p\n",
6437c478bd9Sstevel@tonic-gate 				ddi_node_name(arg), ddi_get_instance(arg),
6447c478bd9Sstevel@tonic-gate 				(void *)arg);
6457c478bd9Sstevel@tonic-gate 			if (DEVI(arg)->devi_binding_name != NULL)
6467c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "\tbinding_name=%s\n",
6477c478bd9Sstevel@tonic-gate 					DEVI(arg)->devi_binding_name);
6487c478bd9Sstevel@tonic-gate 			if (DEVI(arg)->devi_node_name != NULL)
6497c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "\tnode_name=%s\n",
6507c478bd9Sstevel@tonic-gate 					DEVI(arg)->devi_node_name);
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate #endif
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
6557c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
6567c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
6597c478bd9Sstevel@tonic-gate 		/* PCMCIA devices can't ever be busmaster until CardBus */
6607c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
6617c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(rdip);
6627c478bd9Sstevel@tonic-gate 		if (ppd != NULL && ppd->ppd_flags & PPD_CB_BUSMASTER)
6637c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE); /* at most */
6647c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
6677c478bd9Sstevel@tonic-gate 		/* in general this is true. */
6687c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
6717c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
6727c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(rdip);
6737c478bd9Sstevel@tonic-gate 		if (ppd != NULL)
6747c478bd9Sstevel@tonic-gate 			*((uint32_t *)result) = (ppd->ppd_nreg);
6757c478bd9Sstevel@tonic-gate 		else
6767c478bd9Sstevel@tonic-gate 			*((uint32_t *)result) = 0;
6777c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
6807c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
6817c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(rdip);
6827c478bd9Sstevel@tonic-gate 		if (ppd != NULL && ppd->ppd_nreg > 0)
6837c478bd9Sstevel@tonic-gate 			*((off_t *)result) =  sizeof (struct pcm_regs);
6847c478bd9Sstevel@tonic-gate 		else
6857c478bd9Sstevel@tonic-gate 			*((off_t *)result) = 0;
6867c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POWER:
6897c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
6907c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(rdip);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 		if (ppd == NULL)
6937c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6947c478bd9Sstevel@tonic-gate 		/*
6957c478bd9Sstevel@tonic-gate 		 * if this is not present, don't bother (claim success)
6967c478bd9Sstevel@tonic-gate 		 * since it is already in the right state.  Don't
6977c478bd9Sstevel@tonic-gate 		 * do any resume either since the card insertion will
6987c478bd9Sstevel@tonic-gate 		 * happen independently.
6997c478bd9Sstevel@tonic-gate 		 */
7007c478bd9Sstevel@tonic-gate 		if (!ppd->ppd_active)
7017c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
7027c478bd9Sstevel@tonic-gate 		for (e = 0; e < pcmcia_num_adapters; e++)
7037c478bd9Sstevel@tonic-gate 			if (pcmcia_adapters[e] ==
7047c478bd9Sstevel@tonic-gate 			    pcmcia_sockets[ppd->ppd_socket]->ls_adapter)
7057c478bd9Sstevel@tonic-gate 				break;
7067c478bd9Sstevel@tonic-gate 		if (e == pcmcia_num_adapters)
7077c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7087c478bd9Sstevel@tonic-gate 		pm = (power_req_t *)arg;
7097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
7107c478bd9Sstevel@tonic-gate 		if (pcmcia_debug) {
7117c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "power: %d: %p, %d, %d [%s]\n",
7127c478bd9Sstevel@tonic-gate 				pm->request_type,
7137c478bd9Sstevel@tonic-gate 				(void *)pm->req.set_power_req.who,
7147c478bd9Sstevel@tonic-gate 				pm->req.set_power_req.cmpt,
7157c478bd9Sstevel@tonic-gate 				pm->req.set_power_req.level,
7167c478bd9Sstevel@tonic-gate 				ddi_get_name_addr(rdip));
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate #endif
7197c478bd9Sstevel@tonic-gate 		e = ppd->ppd_socket;
7207c478bd9Sstevel@tonic-gate 		switch (pm->request_type) {
7217c478bd9Sstevel@tonic-gate 		case PMR_SUSPEND:
7227c478bd9Sstevel@tonic-gate 			if (!(pcmcia_sockets[e]->ls_flags &
7237c478bd9Sstevel@tonic-gate 			    PCS_SUSPENDED)) {
7247c478bd9Sstevel@tonic-gate 				pcmcia_do_suspend(ppd->ppd_socket,
7257c478bd9Sstevel@tonic-gate 				    pcmcia_sockets[e]);
7267c478bd9Sstevel@tonic-gate 			}
7277c478bd9Sstevel@tonic-gate 			ppd->ppd_flags |= PPD_SUSPENDED;
7287c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
7297c478bd9Sstevel@tonic-gate 		case PMR_RESUME:
7307c478bd9Sstevel@tonic-gate 			/* for now, we just succeed since the rest is done */
7317c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
7327c478bd9Sstevel@tonic-gate 		case PMR_SET_POWER:
7337c478bd9Sstevel@tonic-gate 			/*
7347c478bd9Sstevel@tonic-gate 			 * not sure how to handle power control
7357c478bd9Sstevel@tonic-gate 			 * for now, we let the child handle it itself
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			(void) pcmcia_power(pm->req.set_power_req.who,
7387c478bd9Sstevel@tonic-gate 				pm->req.set_power_req.cmpt,
7397c478bd9Sstevel@tonic-gate 				pm->req.set_power_req.level);
7407c478bd9Sstevel@tonic-gate 			break;
7417c478bd9Sstevel@tonic-gate 		default:
7427c478bd9Sstevel@tonic-gate 			break;
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7457c478bd9Sstevel@tonic-gate 		/* These CTLOPS will need to be implemented for new form */
7467c478bd9Sstevel@tonic-gate 		/* let CardServices know about this */
74711c2b4c0Srw 	case DDI_CTLOPS_DETACH:
74811c2b4c0Srw 		return (DDI_SUCCESS);
74911c2b4c0Srw 	case DDI_CTLOPS_ATTACH:
75011c2b4c0Srw 		return (DDI_SUCCESS);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	default:
7537c478bd9Sstevel@tonic-gate 		/* if we don't understand, pass up the tree */
7547c478bd9Sstevel@tonic-gate 		/* most things default to general ops */
7557c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate struct pcmcia_props {
7607c478bd9Sstevel@tonic-gate 	char *name;
7617c478bd9Sstevel@tonic-gate 	int   len;
7627c478bd9Sstevel@tonic-gate 	int   prop;
7637c478bd9Sstevel@tonic-gate } pcmcia_internal_props[] = {
7647c478bd9Sstevel@tonic-gate 	{ PCM_DEV_ACTIVE, 0, PCMCIA_PROP_ACTIVE },
7657c478bd9Sstevel@tonic-gate 	{ PCM_DEV_R2TYPE, 0, PCMCIA_PROP_R2TYPE },
7667c478bd9Sstevel@tonic-gate 	{ PCM_DEV_CARDBUS, 0, PCMCIA_PROP_CARDBUS },
7677c478bd9Sstevel@tonic-gate 	{ CS_PROP, sizeof (void *), PCMCIA_PROP_OLDCS },
7687c478bd9Sstevel@tonic-gate 	{ "reg", 0, PCMCIA_PROP_REG },
7697c478bd9Sstevel@tonic-gate 	{ "interrupts", sizeof (int), PCMCIA_PROP_INTR },
7707c478bd9Sstevel@tonic-gate 	{ "pm-hardware-state", 0, PCMCIA_PROP_DEFAULT_PM },
7717c478bd9Sstevel@tonic-gate };
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate /*
7747c478bd9Sstevel@tonic-gate  * pcmcia_prop_decode(name)
7757c478bd9Sstevel@tonic-gate  *	decode the name and determine if this is a property
7767c478bd9Sstevel@tonic-gate  *	we construct on the fly, one we have on the prop list
7777c478bd9Sstevel@tonic-gate  *	or one that requires calling the CIS code.
7787c478bd9Sstevel@tonic-gate  */
7797c478bd9Sstevel@tonic-gate static int
7807c478bd9Sstevel@tonic-gate pcmcia_prop_decode(char *name)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	int i;
7837c478bd9Sstevel@tonic-gate 	if (strncmp(name, "cistpl_", 7) == 0)
7847c478bd9Sstevel@tonic-gate 		return (PCMCIA_PROP_CIS);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	for (i = 0; i < (sizeof (pcmcia_internal_props) /
7877c478bd9Sstevel@tonic-gate 	    sizeof (struct pcmcia_props)); i++) {
7887c478bd9Sstevel@tonic-gate 		if (strcmp(name, pcmcia_internal_props[i].name) == 0)
7897c478bd9Sstevel@tonic-gate 			return (i);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	return (PCMCIA_PROP_UNKNOWN);
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*
7967c478bd9Sstevel@tonic-gate  * pcmcia_prop_op()
7977c478bd9Sstevel@tonic-gate  *	we don't have properties in PROM per se so look for them
7987c478bd9Sstevel@tonic-gate  *	only in the devinfo node.  Future may allow us to find
7997c478bd9Sstevel@tonic-gate  *	certain CIS tuples via this interface if a user asks for
8007c478bd9Sstevel@tonic-gate  *	a property of the form "cistpl-<tuplename>" but not yet.
8017c478bd9Sstevel@tonic-gate  *
8027c478bd9Sstevel@tonic-gate  *	The addition of 1275 properties adds to the necessity.
8037c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate int
8057c478bd9Sstevel@tonic-gate pcmcia_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
8067c478bd9Sstevel@tonic-gate     ddi_prop_op_t prop_op, int mod_flags,
8077c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate 	int len, proplen, which, flags;
8107c478bd9Sstevel@tonic-gate 	caddr_t buff, propptr;
8117c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	len = *lengthp;
8147c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(ch_dip);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	switch (which = pcmcia_prop_decode(name)) {
8177c478bd9Sstevel@tonic-gate 	default:
8187c478bd9Sstevel@tonic-gate 		if (ppd == NULL)
8197c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NOT_FOUND);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		/* note that proplen may get modified */
8227c478bd9Sstevel@tonic-gate 		proplen = pcmcia_internal_props[which].len;
8237c478bd9Sstevel@tonic-gate 		switch (pcmcia_internal_props[which].prop) {
8247c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_DEFAULT_PM:
8257c478bd9Sstevel@tonic-gate 			propptr = pcmcia_default_pm_mode;
8267c478bd9Sstevel@tonic-gate 			proplen = strlen(propptr) + 1;
8277c478bd9Sstevel@tonic-gate 			break;
8287c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_OLDCS:
8297c478bd9Sstevel@tonic-gate 			propptr = (caddr_t)&cs_error_ptr;
8307c478bd9Sstevel@tonic-gate 			break;
8317c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_REG:
8327c478bd9Sstevel@tonic-gate 			propptr = (caddr_t)ppd->ppd_reg;
8337c478bd9Sstevel@tonic-gate 			proplen = ppd->ppd_nreg * sizeof (struct pcm_regs);
8347c478bd9Sstevel@tonic-gate 			break;
8357c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_INTR:
8367c478bd9Sstevel@tonic-gate 			propptr = (caddr_t)&ppd->ppd_intr;
8377c478bd9Sstevel@tonic-gate 			break;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		/* the next set are boolean values */
8407c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_ACTIVE:
8417c478bd9Sstevel@tonic-gate 			propptr = NULL;
8427c478bd9Sstevel@tonic-gate 			if (!ppd->ppd_active) {
8437c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NOT_FOUND);
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 			break;
8467c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_R2TYPE:
8477c478bd9Sstevel@tonic-gate 			propptr = NULL;
8487c478bd9Sstevel@tonic-gate 			if (ppd->ppd_flags & PPD_CARD_CARDBUS)
8497c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NOT_FOUND);
8507c478bd9Sstevel@tonic-gate 			break;
8517c478bd9Sstevel@tonic-gate 		case PCMCIA_PROP_CARDBUS:
8527c478bd9Sstevel@tonic-gate 			propptr = NULL;
8537c478bd9Sstevel@tonic-gate 			if (!(ppd->ppd_flags * PPD_CARD_CARDBUS))
8547c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NOT_FOUND);
8557c478bd9Sstevel@tonic-gate 			break;
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 		break;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	case PCMCIA_PROP_CIS:
8617c478bd9Sstevel@tonic-gate 		/*
8627c478bd9Sstevel@tonic-gate 		 * once we have the lookup code in place
8637c478bd9Sstevel@tonic-gate 		 * it is sufficient to break out of the switch
8647c478bd9Sstevel@tonic-gate 		 * once proplen and propptr are set.
8657c478bd9Sstevel@tonic-gate 		 * The common prop_op code deals with the rest.
8667c478bd9Sstevel@tonic-gate 		 */
8677c478bd9Sstevel@tonic-gate 	case PCMCIA_PROP_UNKNOWN:
8687c478bd9Sstevel@tonic-gate 		return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
8697c478bd9Sstevel@tonic-gate 		    mod_flags | DDI_PROP_NOTPROM,
8707c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp));
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if (prop_op == PROP_LEN) {
8747c478bd9Sstevel@tonic-gate 		/* just the length */
8757c478bd9Sstevel@tonic-gate 		*lengthp = proplen;
8767c478bd9Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 	switch (prop_op) {
8797c478bd9Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_ALLOC:
8807c478bd9Sstevel@tonic-gate 		if (mod_flags & DDI_PROP_CANSLEEP)
8817c478bd9Sstevel@tonic-gate 			flags = KM_SLEEP;
8827c478bd9Sstevel@tonic-gate 		else
8837c478bd9Sstevel@tonic-gate 			flags = KM_NOSLEEP;
8847c478bd9Sstevel@tonic-gate 		buff = kmem_alloc((size_t)proplen, flags);
8857c478bd9Sstevel@tonic-gate 		if (buff == NULL)
8867c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NO_MEMORY);
8877c478bd9Sstevel@tonic-gate 		*(caddr_t *)valuep = (caddr_t)buff;
8887c478bd9Sstevel@tonic-gate 		break;
8897c478bd9Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_BUF:
8907c478bd9Sstevel@tonic-gate 		buff = (caddr_t)valuep;
8917c478bd9Sstevel@tonic-gate 		if (len < proplen)
8927c478bd9Sstevel@tonic-gate 			return (DDI_PROP_BUF_TOO_SMALL);
8937c478bd9Sstevel@tonic-gate 		break;
8947c478bd9Sstevel@tonic-gate 	default:
8957c478bd9Sstevel@tonic-gate 		break;
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	if (proplen > 0)
8997c478bd9Sstevel@tonic-gate 		bcopy(propptr, buff, proplen);
9007c478bd9Sstevel@tonic-gate 	*lengthp = proplen;
9017c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate struct regspec *
9067c478bd9Sstevel@tonic-gate pcmcia_rnum_to_regspec(dev_info_t *dip, int rnumber)
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
9097c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
9107c478bd9Sstevel@tonic-gate 	if (ppd->ppd_nreg < rnumber)
9117c478bd9Sstevel@tonic-gate 		return (NULL);
9127c478bd9Sstevel@tonic-gate 	return ((struct regspec *)&ppd->ppd_reg[rnumber]);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate struct regspec *
9167c478bd9Sstevel@tonic-gate pcmcia_rnum_to_mapped(dev_info_t *dip, int rnumber)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
9197c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
9207c478bd9Sstevel@tonic-gate 	if (ppd->ppd_nreg < rnumber)
9217c478bd9Sstevel@tonic-gate 		return (NULL);
9220d282d13Srw 	if (ppd->ppd_assigned == NULL)
9230d282d13Srw 		return (NULL);
9247c478bd9Sstevel@tonic-gate 	if (ppd->ppd_assigned[rnumber].phys_len == 0)
9257c478bd9Sstevel@tonic-gate 		return (NULL);
9267c478bd9Sstevel@tonic-gate 	else
9277c478bd9Sstevel@tonic-gate 		return ((struct regspec *)&ppd->ppd_assigned[rnumber]);
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate int
9317c478bd9Sstevel@tonic-gate pcmcia_find_rnum(dev_info_t *dip, struct regspec *reg)
9327c478bd9Sstevel@tonic-gate {
9337c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
9347c478bd9Sstevel@tonic-gate 	struct regspec *regp;
9357c478bd9Sstevel@tonic-gate 	int i;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
9387c478bd9Sstevel@tonic-gate 	if (ppd == NULL)
9397c478bd9Sstevel@tonic-gate 		return (-1);
9407c478bd9Sstevel@tonic-gate 	for (regp = (struct regspec *)ppd->ppd_reg, i = 0;
9417c478bd9Sstevel@tonic-gate 	    i < ppd->ppd_nreg; i++, regp++) {
9427c478bd9Sstevel@tonic-gate 		if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
9437c478bd9Sstevel@tonic-gate 			return (i);
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 	for (regp = (struct regspec *)ppd->ppd_assigned, i = 0;
9467c478bd9Sstevel@tonic-gate 	    i < ppd->ppd_nreg; i++, regp++) {
9477c478bd9Sstevel@tonic-gate 		if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
9487c478bd9Sstevel@tonic-gate 			return (i);
9497c478bd9Sstevel@tonic-gate 	}
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	return (-1);
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate int
9557c478bd9Sstevel@tonic-gate pcmcia_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
9567c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	struct pcm_regs *regs, *mregs = NULL, tmp_reg;
9597c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr = *mp;
9607c478bd9Sstevel@tonic-gate 	ra_return_t ret;
9617c478bd9Sstevel@tonic-gate 	int check, rnum = -1;
9627c478bd9Sstevel@tonic-gate 	uint32_t base;
9637c478bd9Sstevel@tonic-gate 	uchar_t regbuf[sizeof (pci_regspec_t)];
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	mp = &mr;		/* a copy of original request */
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	/* check for register number */
9687c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
9697c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
9707c478bd9Sstevel@tonic-gate 		regs = (struct pcm_regs *)mp->map_obj.rp;
9717c478bd9Sstevel@tonic-gate 		mregs = (struct pcm_regs *)mp->map_obj.rp;
9727c478bd9Sstevel@tonic-gate 		/*
9737c478bd9Sstevel@tonic-gate 		 * when using regspec, must not be relocatable
9747c478bd9Sstevel@tonic-gate 		 * and should be from assigned space.
9757c478bd9Sstevel@tonic-gate 		 */
9767c478bd9Sstevel@tonic-gate 		if (!PC_REG_RELOC(regs->phys_hi))
9777c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9787c478bd9Sstevel@tonic-gate 		rnum = pcmcia_find_rnum(rdip, (struct regspec *)mregs);
9797c478bd9Sstevel@tonic-gate 		break;
9807c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
9817c478bd9Sstevel@tonic-gate 		regs = (struct pcm_regs *)
9827c478bd9Sstevel@tonic-gate 			pcmcia_rnum_to_regspec(rdip, mp->map_obj.rnumber);
9837c478bd9Sstevel@tonic-gate 		mregs = (struct pcm_regs *)
9847c478bd9Sstevel@tonic-gate 			pcmcia_rnum_to_mapped(rdip, mp->map_obj.rnumber);
9857c478bd9Sstevel@tonic-gate 		rnum = mp->map_obj.rnumber;
9867c478bd9Sstevel@tonic-gate 		if (regs == NULL)
9877c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9887c478bd9Sstevel@tonic-gate 		mp->map_type = DDI_MT_REGSPEC;
9897c478bd9Sstevel@tonic-gate 		mp->map_obj.rp = (struct regspec *)mregs;
9907c478bd9Sstevel@tonic-gate 		break;
9917c478bd9Sstevel@tonic-gate 	default:
9927c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	/* basic sanity checks */
9967c478bd9Sstevel@tonic-gate 	switch (mp->map_op) {
9977c478bd9Sstevel@tonic-gate 	default:
9987c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNIMPLEMENTED);
9997c478bd9Sstevel@tonic-gate 	case DDI_MO_UNMAP:
10007c478bd9Sstevel@tonic-gate 		if (mregs == NULL)
10017c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10027c478bd9Sstevel@tonic-gate 		regs = mregs;
10037c478bd9Sstevel@tonic-gate 		break;
10047c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_LOCKED:
10057c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_HANDLE:
10067c478bd9Sstevel@tonic-gate 		panic("unsupported bus operation");
10077c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	/*
10117c478bd9Sstevel@tonic-gate 	 * we need a private copy for manipulation and
10127c478bd9Sstevel@tonic-gate 	 * calculation of the correct ranges
10137c478bd9Sstevel@tonic-gate 	 */
10147c478bd9Sstevel@tonic-gate 	tmp_reg = *regs;
10157c478bd9Sstevel@tonic-gate 	mp->map_obj.rp = (struct regspec *)(regs = &tmp_reg);
10167c478bd9Sstevel@tonic-gate 	base = regs->phys_lo;
10177c478bd9Sstevel@tonic-gate 	if (base == 0 && offset != 0) {
10187c478bd9Sstevel@tonic-gate 		/*
10197c478bd9Sstevel@tonic-gate 		 * for now this is an error.  What does it really mean
10207c478bd9Sstevel@tonic-gate 		 * to ask for an offset from an address that hasn't
10217c478bd9Sstevel@tonic-gate 		 * been allocated yet.
10227c478bd9Sstevel@tonic-gate 		 */
10237c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 	regs->phys_lo += (uint32_t)offset;
10267c478bd9Sstevel@tonic-gate 	if (len != 0) {
10277c478bd9Sstevel@tonic-gate 		if (len > regs->phys_len) {
10287c478bd9Sstevel@tonic-gate 			return (DDI_ME_INVAL);
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 		regs->phys_len = len;
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/*
10347c478bd9Sstevel@tonic-gate 	 * basic sanity is checked so now make sure
10357c478bd9Sstevel@tonic-gate 	 * we can actually allocate something for this
10367c478bd9Sstevel@tonic-gate 	 * request and then convert to a "standard"
10377c478bd9Sstevel@tonic-gate 	 * regspec for the next layer up (pci/isa/rootnex/etc.)
10387c478bd9Sstevel@tonic-gate 	 */
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	switch (PC_GET_REG_TYPE(regs->phys_hi)) {
10417c478bd9Sstevel@tonic-gate 	case PC_REG_SPACE_IO:
10427c478bd9Sstevel@tonic-gate 		check = PCA_RES_NEED_IO;
10437c478bd9Sstevel@tonic-gate 		break;
10447c478bd9Sstevel@tonic-gate 	case PC_REG_SPACE_MEMORY:
10457c478bd9Sstevel@tonic-gate 		check = PCA_RES_NEED_MEM;
10467c478bd9Sstevel@tonic-gate 		break;
10477c478bd9Sstevel@tonic-gate 	default:
10487c478bd9Sstevel@tonic-gate 		/* not a valid register type */
10497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
10537c478bd9Sstevel@tonic-gate 	ret.ra_addr_hi = 0;
10547c478bd9Sstevel@tonic-gate 	ret.ra_addr_lo = regs->phys_lo;
10557c478bd9Sstevel@tonic-gate 	ret.ra_len = regs->phys_len;
10567c478bd9Sstevel@tonic-gate 	mr.map_obj.rp = pcmcia_cons_regspec(dip,
10577c478bd9Sstevel@tonic-gate 	    (check == PCA_RES_NEED_IO) ?
10587c478bd9Sstevel@tonic-gate 	    PCMCIA_MAP_IO : PCMCIA_MAP_MEM,
10597c478bd9Sstevel@tonic-gate 	    regbuf, &ret);
10607c478bd9Sstevel@tonic-gate 	switch (mp->map_op) {
10617c478bd9Sstevel@tonic-gate 	case DDI_MO_UNMAP:
10627c478bd9Sstevel@tonic-gate 		pcmcia_set_assigned(rdip, rnum, NULL);
10637c478bd9Sstevel@tonic-gate 		break;
10647c478bd9Sstevel@tonic-gate 	default:
10657c478bd9Sstevel@tonic-gate 		break;
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 	return (ddi_map(dip, &mr, (off_t)0, (off_t)0, vaddrp));
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate  * pcmcia_cons_regspec()
10727c478bd9Sstevel@tonic-gate  * based on parent's bus type, construct a regspec that is usable
10737c478bd9Sstevel@tonic-gate  * by that parent to map the resource into the system.
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate #define	PTYPE_PCI	1
10767c478bd9Sstevel@tonic-gate #define	PTYPE_ISA	0
10777c478bd9Sstevel@tonic-gate struct regspec *
10787c478bd9Sstevel@tonic-gate pcmcia_cons_regspec(dev_info_t *dip, int type, uchar_t *buff, ra_return_t *ret)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	int ptype = -1, len, bus;
10817c478bd9Sstevel@tonic-gate 	char device_type[MODMAXNAMELEN + 1];
10827c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
10837c478bd9Sstevel@tonic-gate 	struct regspec *defreg;
10847c478bd9Sstevel@tonic-gate 	pci_regspec_t *pcireg;
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
10877c478bd9Sstevel@tonic-gate 	if (pdip != ddi_root_node()) {
10887c478bd9Sstevel@tonic-gate 		/* we're not a child of root so find out what */
10897c478bd9Sstevel@tonic-gate 		len = sizeof (device_type);
10907c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_ANY, pdip, PROP_LEN_AND_VAL_BUF, 0,
10917c478bd9Sstevel@tonic-gate 			"device_type", (caddr_t)device_type, &len) ==
10927c478bd9Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
10937c478bd9Sstevel@tonic-gate 			/* check things out */
10947c478bd9Sstevel@tonic-gate 			if (strcmp(device_type, "pci") == 0)
10957c478bd9Sstevel@tonic-gate 				ptype = PTYPE_PCI;
10967c478bd9Sstevel@tonic-gate 			else if (strcmp(device_type, "isa") == 0)
10977c478bd9Sstevel@tonic-gate 				ptype = PTYPE_ISA;
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 	switch (ptype) {
11017c478bd9Sstevel@tonic-gate 	case PTYPE_PCI:
11027c478bd9Sstevel@tonic-gate 		/* XXX need to look at carefully */
1103a3282898Scth 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
11047c478bd9Sstevel@tonic-gate 			"reg", (caddr_t)&pcireg, &len) == DDI_SUCCESS) {
11057c478bd9Sstevel@tonic-gate 			bus = PCI_REG_BUS_G(pcireg->pci_phys_hi);
11067c478bd9Sstevel@tonic-gate 			kmem_free(pcireg, len);
11077c478bd9Sstevel@tonic-gate 		} else {
11087c478bd9Sstevel@tonic-gate 			bus = 0;
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 		pcireg = (pci_regspec_t *)buff;
11117c478bd9Sstevel@tonic-gate 		pcireg->pci_phys_hi = (type == PCMCIA_MAP_IO ? PCI_ADDR_IO :
11127c478bd9Sstevel@tonic-gate 			PCI_ADDR_MEM32) | PCI_RELOCAT_B | (bus << 16);
11137c478bd9Sstevel@tonic-gate 		pcireg->pci_phys_mid = ret->ra_addr_hi;
11147c478bd9Sstevel@tonic-gate 		pcireg->pci_phys_low = ret->ra_addr_lo;
11157c478bd9Sstevel@tonic-gate 		if (type == PCMCIA_MAP_IO)
11167c478bd9Sstevel@tonic-gate 			pcireg->pci_phys_low &= 0xFFFF;
11177c478bd9Sstevel@tonic-gate 		pcireg->pci_size_hi = 0;
11187c478bd9Sstevel@tonic-gate 		pcireg->pci_size_low = ret->ra_len;
11197c478bd9Sstevel@tonic-gate 		break;
11207c478bd9Sstevel@tonic-gate 	default:
11217c478bd9Sstevel@tonic-gate 		/* default case is to use struct regspec */
11227c478bd9Sstevel@tonic-gate 		defreg = (struct regspec *)buff;
11237c478bd9Sstevel@tonic-gate 		defreg->regspec_bustype = type == PCMCIA_MAP_IO ? 1 : 0;
11247c478bd9Sstevel@tonic-gate 		defreg->regspec_addr = ret->ra_addr_lo;
11257c478bd9Sstevel@tonic-gate 		defreg->regspec_size = ret->ra_len;
11267c478bd9Sstevel@tonic-gate 		break;
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 	return ((struct regspec *)buff);
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate /*
11327c478bd9Sstevel@tonic-gate  * pcmcia_init_adapter
11337c478bd9Sstevel@tonic-gate  *	Initialize the per-adapter structures and check to see if
11347c478bd9Sstevel@tonic-gate  *	there are possible other instances coming.
11357c478bd9Sstevel@tonic-gate  */
11367c478bd9Sstevel@tonic-gate void
11377c478bd9Sstevel@tonic-gate pcmcia_init_adapter(anp_t *adapter, dev_info_t *dip)
11387c478bd9Sstevel@tonic-gate {
11397c478bd9Sstevel@tonic-gate 	int i, n;
11407c478bd9Sstevel@tonic-gate 	pcmcia_if_t *ls_if;
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	i = pcmcia_num_adapters++;
11437c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i] = kmem_zalloc(sizeof (struct pcmcia_adapter),
11447c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
11457c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_dip = dip;
11467c478bd9Sstevel@tonic-gate 	/* should this be pca_winshift??? */
11477c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_module = ddi_name_to_major(ddi_get_name(dip));
11487c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_unit = ddi_get_instance(dip);
11497c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_iblock = adapter->an_iblock;
11507c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_idev = adapter->an_idev;
11517c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_if = ls_if = adapter->an_if;
11527c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->pca_number = i;
11537c478bd9Sstevel@tonic-gate 	(void) strcpy(pcmcia_adapters[i]->pca_name, ddi_get_name(dip));
11547c478bd9Sstevel@tonic-gate 	pcmcia_adapters[i]->
11557c478bd9Sstevel@tonic-gate 		pca_name[sizeof (pcmcia_adapters[i]->pca_name) - 1] = NULL;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	if (ls_if != NULL) {
11587c478bd9Sstevel@tonic-gate 		inquire_adapter_t conf;
11597c478bd9Sstevel@tonic-gate 		int sock, win;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 		if (ls_if->pcif_inquire_adapter != NULL)
11627c478bd9Sstevel@tonic-gate 			GET_CONFIG(ls_if, dip, &conf);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		/* resources - assume worst case and fix from there */
11657c478bd9Sstevel@tonic-gate 		pcmcia_adapters[i]->pca_flags = PCA_RES_NEED_IRQ |
11667c478bd9Sstevel@tonic-gate 			PCA_RES_NEED_IO | PCA_RES_NEED_MEM;
11677c478bd9Sstevel@tonic-gate 		/* indicate first socket not initialized */
11687c478bd9Sstevel@tonic-gate 		pcmcia_adapters[i]->pca_first_socket = -1;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 		if (conf.ResourceFlags & RES_OWN_IRQ)
11717c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IRQ;
11727c478bd9Sstevel@tonic-gate 		if (conf.ResourceFlags & RES_OWN_IO)
11737c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IO;
11747c478bd9Sstevel@tonic-gate 		if (conf.ResourceFlags & RES_OWN_MEM)
11757c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_MEM;
11767c478bd9Sstevel@tonic-gate 		if (conf.ResourceFlags & RES_IRQ_SHAREABLE)
11777c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SHAREABLE;
11787c478bd9Sstevel@tonic-gate 		if (conf.ResourceFlags & RES_IRQ_NEXUS)
11797c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SMI_SHARE;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		/* need to know interrupt limitations */
11827c478bd9Sstevel@tonic-gate 		if (conf.ActiveLow) {
11837c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_avail_intr = conf.ActiveLow;
11847c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_ISA;
11857c478bd9Sstevel@tonic-gate 		} else
11867c478bd9Sstevel@tonic-gate 			pcmcia_adapters[i]->pca_avail_intr = conf.ActiveHigh;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 		/* power entries for adapter */
11897c478bd9Sstevel@tonic-gate 		pcmcia_adapters[i]->pca_power =
11907c478bd9Sstevel@tonic-gate 			conf.power_entry;
11917c478bd9Sstevel@tonic-gate 		pcmcia_adapters[i]->pca_numpower =
11927c478bd9Sstevel@tonic-gate 			conf.NumPower;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 		for (n = 0; n < conf.NumPower; n++)
11957c478bd9Sstevel@tonic-gate 			pcmcia_merge_power(&conf.power_entry[n]);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 		/* now setup the per socket info */
11987c478bd9Sstevel@tonic-gate 		for (sock = 0; sock < conf.NumSockets;
11997c478bd9Sstevel@tonic-gate 		    sock++) {
12007c478bd9Sstevel@tonic-gate 			dev_info_t *sockdrv = NULL;
12017c478bd9Sstevel@tonic-gate 			sockdrv = pcmcia_number_socket(dip, sock);
12027c478bd9Sstevel@tonic-gate 			if (sockdrv == NULL)
12037c478bd9Sstevel@tonic-gate 				n = sock + pcmcia_num_sockets;
12047c478bd9Sstevel@tonic-gate 			else {
12057c478bd9Sstevel@tonic-gate 				n = ddi_get_instance(sockdrv);
12067c478bd9Sstevel@tonic-gate 			}
12077c478bd9Sstevel@tonic-gate 			/* make sure we know first socket on adapter */
12087c478bd9Sstevel@tonic-gate 			if (pcmcia_adapters[i]->pca_first_socket == -1)
12097c478bd9Sstevel@tonic-gate 				pcmcia_adapters[i]->pca_first_socket = n;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 			/*
12127c478bd9Sstevel@tonic-gate 			 * the number of sockets is weird.
12137c478bd9Sstevel@tonic-gate 			 * we might have only two sockets but
12147c478bd9Sstevel@tonic-gate 			 * due to persistence of instances we
12157c478bd9Sstevel@tonic-gate 			 * will need to call them something other
12167c478bd9Sstevel@tonic-gate 			 * than 0 and 1.  So, we use the largest
12177c478bd9Sstevel@tonic-gate 			 * instance number as the number and
12187c478bd9Sstevel@tonic-gate 			 * have some that just don't get used.
12197c478bd9Sstevel@tonic-gate 			 */
12207c478bd9Sstevel@tonic-gate 			if (n >= pcmcia_num_sockets)
12217c478bd9Sstevel@tonic-gate 				pcmcia_num_sockets = n + 1;
12227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
12237c478bd9Sstevel@tonic-gate 			if (pcmcia_debug) {
12247c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
12257c478bd9Sstevel@tonic-gate 					"pcmcia_init: new socket added %d "
12267c478bd9Sstevel@tonic-gate 					"(%d)\n",
12277c478bd9Sstevel@tonic-gate 					n, pcmcia_num_sockets);
12287c478bd9Sstevel@tonic-gate 			}
12297c478bd9Sstevel@tonic-gate #endif
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n] =
12327c478bd9Sstevel@tonic-gate 				kmem_zalloc(sizeof (pcmcia_logical_socket_t),
12337c478bd9Sstevel@tonic-gate 				KM_SLEEP);
12347c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_socket = sock;
12357c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_if = ls_if;
12367c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_adapter =
12377c478bd9Sstevel@tonic-gate 				pcmcia_adapters[i];
12387c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_cs_events = 0L;
12397c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_sockdrv = sockdrv;
12407c478bd9Sstevel@tonic-gate 			/* Prototype of intrspec */
12417c478bd9Sstevel@tonic-gate 			pcmcia_sockets[n]->ls_intr_pri =
12427c478bd9Sstevel@tonic-gate 				adapter->an_ipl;
12437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
12447c478bd9Sstevel@tonic-gate 			if (pcmcia_debug)
12457c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
12467c478bd9Sstevel@tonic-gate 					"phys sock %d, log sock %d\n",
12477c478bd9Sstevel@tonic-gate 					sock, n);
12487c478bd9Sstevel@tonic-gate #endif
12497c478bd9Sstevel@tonic-gate 			mutex_init(&pcmcia_sockets[n]->ls_ilock, NULL,
12507c478bd9Sstevel@tonic-gate 				MUTEX_DRIVER, *adapter->an_iblock);
12517c478bd9Sstevel@tonic-gate 		}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 		pcmcia_adapters[i]->pca_numsockets = conf.NumSockets;
12547c478bd9Sstevel@tonic-gate 		/* now setup the per window information */
12557c478bd9Sstevel@tonic-gate 		for (win = 0; win < conf.NumWindows; win++) {
12567c478bd9Sstevel@tonic-gate 			n = win + pcmcia_num_windows;
12577c478bd9Sstevel@tonic-gate 			pcmcia_windows[n] =
12587c478bd9Sstevel@tonic-gate 				kmem_zalloc(sizeof (pcmcia_logical_window_t),
12597c478bd9Sstevel@tonic-gate 				    KM_SLEEP);
12607c478bd9Sstevel@tonic-gate 			pcmcia_windows[n]->lw_window = win;
12617c478bd9Sstevel@tonic-gate 			pcmcia_windows[n]->lw_if = ls_if;
12627c478bd9Sstevel@tonic-gate 			pcmcia_windows[n]->lw_adapter =
12637c478bd9Sstevel@tonic-gate 				pcmcia_adapters[i];
12647c478bd9Sstevel@tonic-gate 		}
12657c478bd9Sstevel@tonic-gate 		pcmcia_num_windows += conf.NumWindows;
12667c478bd9Sstevel@tonic-gate 		SET_CALLBACK(ls_if, dip,
12677c478bd9Sstevel@tonic-gate 		    pcm_adapter_callback, i);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		/* now tell CS about each socket */
12707c478bd9Sstevel@tonic-gate 		for (sock = 0; sock < pcmcia_num_sockets; sock++) {
12717c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
12727c478bd9Sstevel@tonic-gate 			if (pcmcia_debug) {
12737c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
12747c478bd9Sstevel@tonic-gate 					"pcmcia_init: notify CS socket %d "
12757c478bd9Sstevel@tonic-gate 					"sockp=%p\n",
12767c478bd9Sstevel@tonic-gate 					sock, (void *)pcmcia_sockets[sock]);
12777c478bd9Sstevel@tonic-gate 			}
12787c478bd9Sstevel@tonic-gate #endif
12797c478bd9Sstevel@tonic-gate 			if (pcmcia_sockets[sock] == NULL ||
12807c478bd9Sstevel@tonic-gate 			    (pcmcia_sockets[sock]->ls_flags &
12817c478bd9Sstevel@tonic-gate 				PCS_SOCKET_ADDED)) {
12827c478bd9Sstevel@tonic-gate 				/* skip the ones that are done already */
12837c478bd9Sstevel@tonic-gate 				continue;
12847c478bd9Sstevel@tonic-gate 			}
12857c478bd9Sstevel@tonic-gate 			pcmcia_sockets[sock]->ls_flags |= PCS_SOCKET_ADDED;
12867c478bd9Sstevel@tonic-gate 			if (cs_event(PCE_ADD_SOCKET, sock, 0) !=
12877c478bd9Sstevel@tonic-gate 			    CS_SUCCESS) {
12887c478bd9Sstevel@tonic-gate 				/* flag socket as broken */
12897c478bd9Sstevel@tonic-gate 				pcmcia_sockets[sock]->ls_flags = 0;
12907c478bd9Sstevel@tonic-gate 			} else {
12917c478bd9Sstevel@tonic-gate 				pcm_event_manager(PCE_ADD_SOCKET,
12927c478bd9Sstevel@tonic-gate 				    sock, NULL);
12937c478bd9Sstevel@tonic-gate 			}
12947c478bd9Sstevel@tonic-gate 		}
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
12987c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
12997c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "logical sockets:\n");
13007c478bd9Sstevel@tonic-gate 		for (i = 0; i < pcmcia_num_sockets; i++) {
13017c478bd9Sstevel@tonic-gate 			if (pcmcia_sockets[i] == NULL)
13027c478bd9Sstevel@tonic-gate 				continue;
13037c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
13047c478bd9Sstevel@tonic-gate 				"\t%d: phys sock=%d, if=%p, adapt=%p\n",
13057c478bd9Sstevel@tonic-gate 				i, pcmcia_sockets[i]->ls_socket,
13067c478bd9Sstevel@tonic-gate 				(void *)pcmcia_sockets[i]->ls_if,
13077c478bd9Sstevel@tonic-gate 				(void *)pcmcia_sockets[i]->ls_adapter);
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "logical windows:\n");
13107c478bd9Sstevel@tonic-gate 		for (i = 0; i < pcmcia_num_windows; i++) {
13117c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
13127c478bd9Sstevel@tonic-gate 				"\t%d: phys_window=%d, if=%p, adapt=%p\n",
13137c478bd9Sstevel@tonic-gate 				i, pcmcia_windows[i]->lw_window,
13147c478bd9Sstevel@tonic-gate 				(void *)pcmcia_windows[i]->lw_if,
13157c478bd9Sstevel@tonic-gate 				(void *)pcmcia_windows[i]->lw_adapter);
13167c478bd9Sstevel@tonic-gate 		}
13177c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\tpcmcia_num_power=%d\n", pcmcia_num_power);
13187c478bd9Sstevel@tonic-gate 		for (n = 0; n < pcmcia_num_power; n++)
13197c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
13207c478bd9Sstevel@tonic-gate 				"\t\tPowerLevel: %d\tValidSignals: %x\n",
13217c478bd9Sstevel@tonic-gate 				pcmcia_power_table[n].PowerLevel,
13227c478bd9Sstevel@tonic-gate 				pcmcia_power_table[n].ValidSignals);
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate #endif
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate /*
13287c478bd9Sstevel@tonic-gate  * pcmcia_find_cards()
13297c478bd9Sstevel@tonic-gate  *	check the adapter to see if there are cards present at
13307c478bd9Sstevel@tonic-gate  *	driver attach time.  If there are, generate an artificial
13317c478bd9Sstevel@tonic-gate  *	card insertion event to get CS running and the PC Card ultimately
13327c478bd9Sstevel@tonic-gate  *	identified.
13337c478bd9Sstevel@tonic-gate  */
13347c478bd9Sstevel@tonic-gate void
13357c478bd9Sstevel@tonic-gate pcmcia_find_cards(anp_t *adapt)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate 	int i;
13387c478bd9Sstevel@tonic-gate 	get_ss_status_t status;
13397c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_sockets; i++) {
13407c478bd9Sstevel@tonic-gate 		if (pcmcia_sockets[i] &&
13417c478bd9Sstevel@tonic-gate 		    pcmcia_sockets[i]->ls_if == adapt->an_if) {
13427c478bd9Sstevel@tonic-gate 			/* check the status */
13437c478bd9Sstevel@tonic-gate 			status.socket = i;
13447c478bd9Sstevel@tonic-gate 			if (SSGetStatus(&status) == SUCCESS &&
1345a9fb0ae8Srw 			    status.IFType != IF_CARDBUS &&
13467c478bd9Sstevel@tonic-gate 			    status.CardState & SBM_CD &&
13477c478bd9Sstevel@tonic-gate 			    pcmcia_sockets[i]->ls_dip[0] == NULL) {
13487c478bd9Sstevel@tonic-gate 				(void) cs_event(PCE_CARD_INSERT, i, 0);
13497c478bd9Sstevel@tonic-gate 				delay(1);
13507c478bd9Sstevel@tonic-gate 			}
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate /*
13567c478bd9Sstevel@tonic-gate  * pcmcia_number_socket(dip, adapt)
13577c478bd9Sstevel@tonic-gate  *	we determine socket number by creating a driver for each
13587c478bd9Sstevel@tonic-gate  *	socket on the adapter and then forcing it to attach.  This
13597c478bd9Sstevel@tonic-gate  *	results in an instance being assigned which becomes the
13607c478bd9Sstevel@tonic-gate  *	logical socket number.	If it fails, then we are the first
13617c478bd9Sstevel@tonic-gate  *	set of sockets and renumbering occurs later.  We do this
13627c478bd9Sstevel@tonic-gate  *	one socket at a time and return the dev_info_t so the
13637c478bd9Sstevel@tonic-gate  *	instance number can be used.
13647c478bd9Sstevel@tonic-gate  */
13657c478bd9Sstevel@tonic-gate dev_info_t *
13667c478bd9Sstevel@tonic-gate pcmcia_number_socket(dev_info_t *dip, int localsocket)
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate 	dev_info_t *child = NULL;
13697c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
13707c478bd9Sstevel@tonic-gate 
1371fa9e4066Sahrens 	if (ndi_devi_alloc(dip, "pcs", (pnode_t)DEVI_SID_NODEID,
13727c478bd9Sstevel@tonic-gate 	    &child) == NDI_SUCCESS) {
13737c478bd9Sstevel@tonic-gate 		ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
13747c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
13757c478bd9Sstevel@tonic-gate 		ppd->ppd_reg = kmem_zalloc(sizeof (struct pcm_regs), KM_SLEEP);
13767c478bd9Sstevel@tonic-gate 		ppd->ppd_nreg = 1;
13777c478bd9Sstevel@tonic-gate 		ppd->ppd_reg[0].phys_hi = localsocket;
13787c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, (caddr_t)ppd);
13797c478bd9Sstevel@tonic-gate 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
1380981012acSrw 			kmem_free(ppd->ppd_reg, sizeof (struct pcm_regs));
1381981012acSrw 			kmem_free(ppd, sizeof (struct pcmcia_parent_private));
13827c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(child);
13837c478bd9Sstevel@tonic-gate 			child = NULL;
13847c478bd9Sstevel@tonic-gate 		}
13857c478bd9Sstevel@tonic-gate 	}
13867c478bd9Sstevel@tonic-gate 	return (child);
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate /*
13907c478bd9Sstevel@tonic-gate  * pcm_phys_to_log_socket()
13917c478bd9Sstevel@tonic-gate  *	from an adapter and socket number return the logical socket
13927c478bd9Sstevel@tonic-gate  */
13937c478bd9Sstevel@tonic-gate int
13947c478bd9Sstevel@tonic-gate pcm_phys_to_log_socket(struct pcmcia_adapter *adapt, int socket)
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate 	register pcmcia_logical_socket_t *sockp;
13977c478bd9Sstevel@tonic-gate 	int i;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	for (i = 0, sockp = pcmcia_sockets[0];
14007c478bd9Sstevel@tonic-gate 		i < pcmcia_num_sockets; i++, sockp = pcmcia_sockets[i]) {
14017c478bd9Sstevel@tonic-gate 		if (sockp == NULL)
14027c478bd9Sstevel@tonic-gate 			continue;
14037c478bd9Sstevel@tonic-gate 		if (sockp->ls_socket == socket && sockp->ls_adapter == adapt)
14047c478bd9Sstevel@tonic-gate 			break;
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 	if (i >= pcmcia_num_sockets) {
14077c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
14087c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
14097c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
14107c478bd9Sstevel@tonic-gate 				"\tbad socket/adapter: %x/%p != %x/%x\n",
14117c478bd9Sstevel@tonic-gate 				socket, (void *)adapt, pcmcia_num_sockets,
14127c478bd9Sstevel@tonic-gate 				pcmcia_num_adapters);
14137c478bd9Sstevel@tonic-gate #endif
14147c478bd9Sstevel@tonic-gate 		return (-1);
14157c478bd9Sstevel@tonic-gate 	}
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	return (i);		/* want logical socket */
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate  * pcm_adapter_callback()
14227c478bd9Sstevel@tonic-gate  *	this function is called back by the adapter driver at interrupt time.
14237c478bd9Sstevel@tonic-gate  *	It is here that events should get generated for the event manager if it
14247c478bd9Sstevel@tonic-gate  *	is present.  It would also be the time where a device information
14257c478bd9Sstevel@tonic-gate  *	tree could be constructed for a card that was added in if we
14267c478bd9Sstevel@tonic-gate  *	choose to create them dynamically.
14277c478bd9Sstevel@tonic-gate  */
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
14307c478bd9Sstevel@tonic-gate char *cblist[] = {
14317c478bd9Sstevel@tonic-gate 	"removal",
14327c478bd9Sstevel@tonic-gate 	"insert",
14337c478bd9Sstevel@tonic-gate 	"ready",
14347c478bd9Sstevel@tonic-gate 	"battery-warn",
14357c478bd9Sstevel@tonic-gate 	"battery-dead",
14367c478bd9Sstevel@tonic-gate 	"status-change",
14377c478bd9Sstevel@tonic-gate 	"write-protect", "reset", "unlock", "client-info", "eject-complete",
14387c478bd9Sstevel@tonic-gate 	"eject-request", "erase-complete", "exclusive-complete",
14397c478bd9Sstevel@tonic-gate 	"exclusive-request", "insert-complete", "insert-request",
14407c478bd9Sstevel@tonic-gate 	"reset-complete", "reset-request", "timer-expired",
14417c478bd9Sstevel@tonic-gate 	"resume", "suspend"
14427c478bd9Sstevel@tonic-gate };
14437c478bd9Sstevel@tonic-gate #endif
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14467c478bd9Sstevel@tonic-gate static int
14477c478bd9Sstevel@tonic-gate pcm_adapter_callback(dev_info_t *dip, int adapter, int event, int socket)
14487c478bd9Sstevel@tonic-gate {
14497c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
14527c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
14537c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcm_adapter_callback: %p %x %x %x: ",
14547c478bd9Sstevel@tonic-gate 			(void *)dip, adapter, event, socket);
14557c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "[%s]\n", cblist[event]);
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate #endif
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	if (adapter >= pcmcia_num_adapters || adapter < 0) {
14607c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
14617c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
14627c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tbad adapter number: %d : %d\n",
14637c478bd9Sstevel@tonic-gate 				adapter, pcmcia_num_adapters);
14647c478bd9Sstevel@tonic-gate #endif
14657c478bd9Sstevel@tonic-gate 		return (1);
14667c478bd9Sstevel@tonic-gate 	}
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	/* get the logical socket since that is what CS knows */
14697c478bd9Sstevel@tonic-gate 	socket = pcm_phys_to_log_socket(pcmcia_adapters[adapter], socket);
14707c478bd9Sstevel@tonic-gate 	if (socket == -1) {
14717c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pcmcia callback - bad logical socket\n");
14727c478bd9Sstevel@tonic-gate 		return (0);
14737c478bd9Sstevel@tonic-gate 	}
14747c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
14757c478bd9Sstevel@tonic-gate 	switch (event) {
14767c478bd9Sstevel@tonic-gate 	case -1:		/* special case of adapter going away */
14777c478bd9Sstevel@tonic-gate 	case PCE_CARD_INSERT:
14787c478bd9Sstevel@tonic-gate 		sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
14797c478bd9Sstevel@tonic-gate 			PCE_E2M(PCE_CARD_REMOVAL);
14807c478bd9Sstevel@tonic-gate 		break;
14817c478bd9Sstevel@tonic-gate 	case PCE_CARD_REMOVAL:
14827c478bd9Sstevel@tonic-gate 				/* disable interrupts at this point */
14837c478bd9Sstevel@tonic-gate 		sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
14847c478bd9Sstevel@tonic-gate 			PCE_E2M(PCE_CARD_REMOVAL);
14857c478bd9Sstevel@tonic-gate 		/* remove children that never attached */
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 		break;
14887c478bd9Sstevel@tonic-gate 	case PCE_PM_RESUME:
14897c478bd9Sstevel@tonic-gate 		pcmcia_do_resume(socket, sockp);
14907c478bd9Sstevel@tonic-gate 		/* event = PCE_CARD_INSERT; */
14917c478bd9Sstevel@tonic-gate 		break;
14927c478bd9Sstevel@tonic-gate 	case PCE_PM_SUSPEND:
14937c478bd9Sstevel@tonic-gate 		pcmcia_do_suspend(socket, sockp);
14947c478bd9Sstevel@tonic-gate 		/* event = PCE_CARD_REMOVAL; */
14957c478bd9Sstevel@tonic-gate 		break;
14967c478bd9Sstevel@tonic-gate 	default:
14977c478bd9Sstevel@tonic-gate 		/* nothing to do */
14987c478bd9Sstevel@tonic-gate 		break;
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15027c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
15037c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
15047c478bd9Sstevel@tonic-gate 			"\tevent %d, event mask=%x, match=%x (log socket=%d)\n",
15057c478bd9Sstevel@tonic-gate 			event,
15067c478bd9Sstevel@tonic-gate 			(int)sockp->ls_cs_events,
15077c478bd9Sstevel@tonic-gate 			(int)(sockp->ls_cs_events & PCE_E2M(event)), socket);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate #endif
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	if (pcmcia_cs_event && sockp->ls_cs_events & (1 << event)) {
15127c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15137c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
15147c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tcalling CS event handler (%p) "
15157c478bd9Sstevel@tonic-gate 				"with event=%d\n",
15167c478bd9Sstevel@tonic-gate 				(void *)pcmcia_cs_event, event);
15177c478bd9Sstevel@tonic-gate #endif
15187c478bd9Sstevel@tonic-gate 		CS_EVENT(event, socket, 0);
15197c478bd9Sstevel@tonic-gate 	}
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	/* let the event manager(s) know about the event */
15227c478bd9Sstevel@tonic-gate 	pcm_event_manager(event, socket, NULL);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	return (0);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate  * pcm_event_manager()
15297c478bd9Sstevel@tonic-gate  *	checks for registered management driver callback handlers
15307c478bd9Sstevel@tonic-gate  *	if there are any, call them if the event warrants it
15317c478bd9Sstevel@tonic-gate  */
15327c478bd9Sstevel@tonic-gate void
15337c478bd9Sstevel@tonic-gate pcm_event_manager(int event, int socket, void *arg)
15347c478bd9Sstevel@tonic-gate {
15357c478bd9Sstevel@tonic-gate 	struct pcmcia_mif *mif;
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	for (mif = pcmcia_mif_handlers; mif != NULL; mif = mif->mif_next) {
15387c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15397c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
15407c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
15417c478bd9Sstevel@tonic-gate 				"pcm_event_manager: event=%d, mif_events=%x"
15427c478bd9Sstevel@tonic-gate 				" (tst:%d)\n",
15437c478bd9Sstevel@tonic-gate 				event, (int)*(uint32_t *)mif->mif_events,
15447c478bd9Sstevel@tonic-gate 				PR_GET(mif->mif_events, event));
15457c478bd9Sstevel@tonic-gate #endif
15467c478bd9Sstevel@tonic-gate 		if (PR_GET(mif->mif_events, event)) {
15477c478bd9Sstevel@tonic-gate 			mif->mif_function(mif->mif_id, event, socket, arg);
15487c478bd9Sstevel@tonic-gate 		}
15497c478bd9Sstevel@tonic-gate 	}
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate /*
15547c478bd9Sstevel@tonic-gate  * pcm_search_devinfo(dev_info_t *, pcm_device_info *, int)
15557c478bd9Sstevel@tonic-gate  * search for an immediate child node to the nexus and not siblings of nexus
15567c478bd9Sstevel@tonic-gate  * and not grandchildren.  We follow the same sequence that name binding
15577c478bd9Sstevel@tonic-gate  * follows so we match same class of device (modem == modem) and don't
15587c478bd9Sstevel@tonic-gate  * have to depend on features that might not exist.
15597c478bd9Sstevel@tonic-gate  */
15607c478bd9Sstevel@tonic-gate dev_info_t *
15617c478bd9Sstevel@tonic-gate pcm_search_devinfo(dev_info_t *self, struct pcm_device_info *info, int socket)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	char bf[256];
15647c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
15657c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
1566b9ccdc5aScth 	int circ;
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15697c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
15707c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
15717c478bd9Sstevel@tonic-gate 		    "pcm_search_devinfo: socket=%x [%s|%s|%s] pd_flags=%x\n",
15727c478bd9Sstevel@tonic-gate 		    socket, info->pd_bind_name, info->pd_generic_name,
15737c478bd9Sstevel@tonic-gate 		    info->pd_vers1_name, info->pd_flags);
15747c478bd9Sstevel@tonic-gate #endif
15757c478bd9Sstevel@tonic-gate 
1576b9ccdc5aScth 	ndi_devi_enter(self, &circ);
15777c478bd9Sstevel@tonic-gate 	/* do searches in compatible property order */
15787c478bd9Sstevel@tonic-gate 	for (dip = (dev_info_t *)DEVI(self)->devi_child;
15797c478bd9Sstevel@tonic-gate 	    dip != NULL;
15807c478bd9Sstevel@tonic-gate 	    dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
15817c478bd9Sstevel@tonic-gate 		int ppd_socket;
15827c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
15837c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(dip);
15847c478bd9Sstevel@tonic-gate 		if (ppd == NULL) {
15857c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15867c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "No parent private data\n");
15877c478bd9Sstevel@tonic-gate #endif
15887c478bd9Sstevel@tonic-gate 			continue;
15897c478bd9Sstevel@tonic-gate 		}
15907c478bd9Sstevel@tonic-gate 		ppd_socket = CS_MAKE_SOCKET_NUMBER(ppd->ppd_socket,
15917c478bd9Sstevel@tonic-gate 		    ppd->ppd_function);
15927c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
15937c478bd9Sstevel@tonic-gate 		if (pcmcia_debug) {
15947c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tbind=[%s], node=[%s]\n",
15957c478bd9Sstevel@tonic-gate 				DEVI(dip)->devi_binding_name,
15967c478bd9Sstevel@tonic-gate 				DEVI(dip)->devi_node_name);
15977c478bd9Sstevel@tonic-gate 		}
15987c478bd9Sstevel@tonic-gate #endif
15997c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NAME_VERS1) {
16007c478bd9Sstevel@tonic-gate 			(void) strcpy(bf, info->pd_vers1_name);
16017c478bd9Sstevel@tonic-gate 			pcmcia_fix_string(bf);
16027c478bd9Sstevel@tonic-gate 			if (DEVI(dip)->devi_binding_name &&
16037c478bd9Sstevel@tonic-gate 			    strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
16047c478bd9Sstevel@tonic-gate 			    socket == ppd_socket)
16057c478bd9Sstevel@tonic-gate 				break;
16067c478bd9Sstevel@tonic-gate 		}
16077c478bd9Sstevel@tonic-gate 		if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
16087c478bd9Sstevel@tonic-gate 		    (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
16097c478bd9Sstevel@tonic-gate 			(void) sprintf(bf, "%s,%x", info->pd_bind_name,
16107c478bd9Sstevel@tonic-gate 				info->pd_function);
16117c478bd9Sstevel@tonic-gate 			if (strcmp(bf, DEVI(dip)->devi_binding_name) == 0 &&
16127c478bd9Sstevel@tonic-gate 			    socket == ppd->ppd_socket)
16137c478bd9Sstevel@tonic-gate 				break;
16147c478bd9Sstevel@tonic-gate 		}
16157c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NAME_1275) {
16167c478bd9Sstevel@tonic-gate 			if (DEVI(dip)->devi_binding_name &&
16177c478bd9Sstevel@tonic-gate 			    strcmp(DEVI(dip)->devi_binding_name,
16187c478bd9Sstevel@tonic-gate 				info->pd_bind_name) == 0 &&
16197c478bd9Sstevel@tonic-gate 			    socket == ppd_socket)
16207c478bd9Sstevel@tonic-gate 				break;
16217c478bd9Sstevel@tonic-gate 		}
16227c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NAME_GENERIC) {
16237c478bd9Sstevel@tonic-gate 			(void) sprintf(bf, "%s,%s", PCMDEV_NAMEPREF,
16247c478bd9Sstevel@tonic-gate 				info->pd_generic_name);
16257c478bd9Sstevel@tonic-gate 			if (DEVI(dip)->devi_binding_name &&
16267c478bd9Sstevel@tonic-gate 			    strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
16277c478bd9Sstevel@tonic-gate 			    socket == ppd_socket)
16287c478bd9Sstevel@tonic-gate 				break;
16297c478bd9Sstevel@tonic-gate 		}
16307c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NAME_GENERIC) {
16317c478bd9Sstevel@tonic-gate 			if (DEVI(dip)->devi_binding_name &&
16327c478bd9Sstevel@tonic-gate 			    strcmp(DEVI(dip)->devi_binding_name,
16337c478bd9Sstevel@tonic-gate 				info->pd_generic_name) == 0 &&
16347c478bd9Sstevel@tonic-gate 			    socket == ppd_socket)
16357c478bd9Sstevel@tonic-gate 				break;
16367c478bd9Sstevel@tonic-gate 		}
16377c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NO_CONFIG) {
16387c478bd9Sstevel@tonic-gate 			if (DEVI(dip)->devi_binding_name &&
16397c478bd9Sstevel@tonic-gate 			    strcmp(DEVI(dip)->devi_binding_name,
16407c478bd9Sstevel@tonic-gate 					"pccard,memory") == 0 &&
16417c478bd9Sstevel@tonic-gate 			    socket == ppd_socket)
16427c478bd9Sstevel@tonic-gate 				break;
16437c478bd9Sstevel@tonic-gate 		}
16447c478bd9Sstevel@tonic-gate 	}
1645b9ccdc5aScth 	ndi_devi_exit(self, circ);
16467c478bd9Sstevel@tonic-gate 	return (dip);
16477c478bd9Sstevel@tonic-gate }
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate /*
16507c478bd9Sstevel@tonic-gate  * pcm_find_devinfo()
16517c478bd9Sstevel@tonic-gate  *	this is a wrapper around DDI calls to "find" any
16527c478bd9Sstevel@tonic-gate  *	devinfo node and then from there find the one associated
16537c478bd9Sstevel@tonic-gate  *	with the socket
16547c478bd9Sstevel@tonic-gate  */
16557c478bd9Sstevel@tonic-gate dev_info_t *
16567c478bd9Sstevel@tonic-gate pcm_find_devinfo(dev_info_t *pdip, struct pcm_device_info *info, int socket)
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	dip = pcm_search_devinfo(pdip, info, socket);
16617c478bd9Sstevel@tonic-gate 	if (dip == NULL)
16627c478bd9Sstevel@tonic-gate 		return (NULL);
16637c478bd9Sstevel@tonic-gate 	/*
16647c478bd9Sstevel@tonic-gate 	 * we have at least a base level dip
16657c478bd9Sstevel@tonic-gate 	 * see if there is one (this or a sibling)
16667c478bd9Sstevel@tonic-gate 	 * that has the correct socket number
16677c478bd9Sstevel@tonic-gate 	 * if there is, return that one else
16687c478bd9Sstevel@tonic-gate 	 * NULL so a new one is created
16697c478bd9Sstevel@tonic-gate 	 */
16707c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
16717c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
16727c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "find: initial dip = %p, socket=%d, name=%s "
16737c478bd9Sstevel@tonic-gate 			"(instance=%d, socket=%d, name=%s)\n",
16747c478bd9Sstevel@tonic-gate 			(void *)dip, socket, info->pd_bind_name,
16757c478bd9Sstevel@tonic-gate 			ddi_get_instance(dip),
16767c478bd9Sstevel@tonic-gate 			ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
16777c478bd9Sstevel@tonic-gate 			PCM_DEV_SOCKET, -1),
16787c478bd9Sstevel@tonic-gate 			ddi_get_name(dip));
16797c478bd9Sstevel@tonic-gate #endif
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
16827c478bd9Sstevel@tonic-gate 	if (pcmcia_debug && dip != NULL)
16837c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\treturning non-NULL dip (%s)\n",
16847c478bd9Sstevel@tonic-gate 			ddi_get_name(dip));
16857c478bd9Sstevel@tonic-gate #endif
16867c478bd9Sstevel@tonic-gate 	return (dip);
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate /*
16907c478bd9Sstevel@tonic-gate  * pcm_find_parent_dip(socket)
16917c478bd9Sstevel@tonic-gate  *	find the correct parent dip for this logical socket
16927c478bd9Sstevel@tonic-gate  */
16937c478bd9Sstevel@tonic-gate dev_info_t *
16947c478bd9Sstevel@tonic-gate pcm_find_parent_dip(int socket)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	if ((socket < 0 || socket >= pcmcia_num_sockets) ||
16977c478bd9Sstevel@tonic-gate 	    pcmcia_sockets[socket] == NULL)
16987c478bd9Sstevel@tonic-gate 		return (NULL);
16997c478bd9Sstevel@tonic-gate 	return (pcmcia_sockets[socket]->ls_adapter->pca_dip);
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate /*
17037c478bd9Sstevel@tonic-gate  * pcmcia_set_em_handler()
17047c478bd9Sstevel@tonic-gate  *	This is called by the management and event driver to tell
17057c478bd9Sstevel@tonic-gate  *	the nexus what to call.	 Multiple drivers are allowed
17067c478bd9Sstevel@tonic-gate  *	but normally only one will exist.
17077c478bd9Sstevel@tonic-gate  */
17087c478bd9Sstevel@tonic-gate int
17097c478bd9Sstevel@tonic-gate pcmcia_set_em_handler(int (*handler)(), caddr_t events, int elen,
17107c478bd9Sstevel@tonic-gate 			uint32_t id, void **cs, void **ss)
17117c478bd9Sstevel@tonic-gate {
17127c478bd9Sstevel@tonic-gate 	struct pcmcia_mif *mif, *tmp;
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	if (handler == NULL) {
17157c478bd9Sstevel@tonic-gate 		/* NULL means remove the handler based on the ID */
17167c478bd9Sstevel@tonic-gate 		if (pcmcia_mif_handlers == NULL)
17177c478bd9Sstevel@tonic-gate 			return (0);
17187c478bd9Sstevel@tonic-gate 		mutex_enter(&pcmcia_global_lock);
17197c478bd9Sstevel@tonic-gate 		if (pcmcia_mif_handlers->mif_id == id) {
17207c478bd9Sstevel@tonic-gate 			mif = pcmcia_mif_handlers;
17217c478bd9Sstevel@tonic-gate 			pcmcia_mif_handlers = mif->mif_next;
17227c478bd9Sstevel@tonic-gate 			kmem_free(mif, sizeof (struct pcmcia_mif));
17237c478bd9Sstevel@tonic-gate 		} else {
17247c478bd9Sstevel@tonic-gate 			for (mif = pcmcia_mif_handlers;
17257c478bd9Sstevel@tonic-gate 			    mif->mif_next != NULL &&
17267c478bd9Sstevel@tonic-gate 			    mif->mif_next->mif_id != id;
17277c478bd9Sstevel@tonic-gate 			    mif = mif->mif_next)
17287c478bd9Sstevel@tonic-gate 				;
17297c478bd9Sstevel@tonic-gate 			if (mif->mif_next != NULL &&
17307c478bd9Sstevel@tonic-gate 			    mif->mif_next->mif_id == id) {
17317c478bd9Sstevel@tonic-gate 				tmp = mif->mif_next;
17327c478bd9Sstevel@tonic-gate 				mif->mif_next = tmp->mif_next;
17337c478bd9Sstevel@tonic-gate 				kmem_free(tmp, sizeof (struct pcmcia_mif));
17347c478bd9Sstevel@tonic-gate 			}
17357c478bd9Sstevel@tonic-gate 		}
17367c478bd9Sstevel@tonic-gate 		mutex_exit(&pcmcia_global_lock);
17377c478bd9Sstevel@tonic-gate 	} else {
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 		if (pcmcia_num_adapters == 0) {
17407c478bd9Sstevel@tonic-gate 			return (ENXIO);
17417c478bd9Sstevel@tonic-gate 		}
17427c478bd9Sstevel@tonic-gate 		if (elen > EM_EVENTSIZE)
17437c478bd9Sstevel@tonic-gate 			return (EINVAL);
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 		mif = (struct pcmcia_mif *)
17467c478bd9Sstevel@tonic-gate 			kmem_zalloc(sizeof (struct pcmcia_mif),
17477c478bd9Sstevel@tonic-gate 			    KM_NOSLEEP);
17487c478bd9Sstevel@tonic-gate 		if (mif == NULL)
17497c478bd9Sstevel@tonic-gate 			return (ENOSPC);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 		mif->mif_function = (void (*)())handler;
17527c478bd9Sstevel@tonic-gate 		bcopy(events, mif->mif_events, elen);
17537c478bd9Sstevel@tonic-gate 		mif->mif_id = id;
17547c478bd9Sstevel@tonic-gate 		mutex_enter(&pcmcia_global_lock);
17557c478bd9Sstevel@tonic-gate 		mif->mif_next = pcmcia_mif_handlers;
17567c478bd9Sstevel@tonic-gate 		pcmcia_mif_handlers = mif;
17577c478bd9Sstevel@tonic-gate 		if (cs != NULL)
17587c478bd9Sstevel@tonic-gate 			*cs = (void *)pcmcia_card_services;
17597c478bd9Sstevel@tonic-gate 		if (ss != NULL) {
17607c478bd9Sstevel@tonic-gate 			*ss = (void *)SocketServices;
17617c478bd9Sstevel@tonic-gate 		}
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 		mutex_exit(&pcmcia_global_lock);
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate 	return (0);
17667c478bd9Sstevel@tonic-gate }
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate /*
17697c478bd9Sstevel@tonic-gate  * pcm_fix_bits(uchar_t *data, int num, int dir)
17707c478bd9Sstevel@tonic-gate  *	shift socket bits left(0) or right(0)
17717c478bd9Sstevel@tonic-gate  *	This is used when mapping logical and physical
17727c478bd9Sstevel@tonic-gate  */
17737c478bd9Sstevel@tonic-gate void
17747c478bd9Sstevel@tonic-gate pcm_fix_bits(socket_enum_t src, socket_enum_t dst, int num, int dir)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate 	int i;
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	PR_ZERO(dst);
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	if (dir == 0) {
17817c478bd9Sstevel@tonic-gate 				/* LEFT */
17827c478bd9Sstevel@tonic-gate 		for (i = 0; i <= (sizeof (dst) * PR_WORDSIZE) - num; i++) {
17837c478bd9Sstevel@tonic-gate 			if (PR_GET(src, i))
17847c478bd9Sstevel@tonic-gate 				PR_SET(dst, i + num);
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 	} else {
17877c478bd9Sstevel@tonic-gate 				/* RIGHT */
17887c478bd9Sstevel@tonic-gate 		for (i = num; i < sizeof (dst) * PR_WORDSIZE; i++) {
17897c478bd9Sstevel@tonic-gate 			if (PR_GET(src, i))
17907c478bd9Sstevel@tonic-gate 			    PR_SET(dst, i - num);
17917c478bd9Sstevel@tonic-gate 		}
17927c478bd9Sstevel@tonic-gate 	}
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate uint32_t
17967c478bd9Sstevel@tonic-gate genmask(int len)
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate 	uint32_t mask;
17997c478bd9Sstevel@tonic-gate 	for (mask = 0; len > 0; len--) {
18007c478bd9Sstevel@tonic-gate 		mask |= 1 << (len - 1);
18017c478bd9Sstevel@tonic-gate 	}
18027c478bd9Sstevel@tonic-gate 	return (mask);
18037c478bd9Sstevel@tonic-gate }
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate int
18067c478bd9Sstevel@tonic-gate genp2(int val)
18077c478bd9Sstevel@tonic-gate {
18087c478bd9Sstevel@tonic-gate 	int i;
18097c478bd9Sstevel@tonic-gate 	if (val == 0)
18107c478bd9Sstevel@tonic-gate 		return (0);
18117c478bd9Sstevel@tonic-gate 	for (i = 0; i < 32; i++)
18127c478bd9Sstevel@tonic-gate 		if (val > (1 << i))
18137c478bd9Sstevel@tonic-gate 			return (i);
18147c478bd9Sstevel@tonic-gate 	return (0);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
18187c478bd9Sstevel@tonic-gate char *ssfuncs[128] = {
18197c478bd9Sstevel@tonic-gate 	"GetAdapter", "GetPage", "GetSocket", "GetStatus", "GetWindow",
18207c478bd9Sstevel@tonic-gate 	"InquireAdapter", "InquireSocket", "InquireWindow", "ResetSocket",
18217c478bd9Sstevel@tonic-gate 	"SetPage", "SetAdapter", "SetSocket", "SetWindow", "SetIRQHandler",
18227c478bd9Sstevel@tonic-gate 	"ClearIRQHandler",
18237c478bd9Sstevel@tonic-gate 	/* 15 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18247c478bd9Sstevel@tonic-gate 	/* 25 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18257c478bd9Sstevel@tonic-gate 	/* 35 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18267c478bd9Sstevel@tonic-gate 	/* 45 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18277c478bd9Sstevel@tonic-gate 	/* 55 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18287c478bd9Sstevel@tonic-gate 	/* 65 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18297c478bd9Sstevel@tonic-gate 	/* 75 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18307c478bd9Sstevel@tonic-gate 	/* 85 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18317c478bd9Sstevel@tonic-gate 	/* 95 */ NULL, NULL, NULL,
18327c478bd9Sstevel@tonic-gate 	"CSIsActiveDip",
18337c478bd9Sstevel@tonic-gate 	"CSInitDev", "CSRegister", "CSCISInit", "CSUnregister",
18347c478bd9Sstevel@tonic-gate 	"CISGetAddress", "CISSetAddress", "CSCardRemoved", "CSGetCookiesAndDip"
18357c478bd9Sstevel@tonic-gate };
18367c478bd9Sstevel@tonic-gate #endif
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate /*
18397c478bd9Sstevel@tonic-gate  * SocketServices
18407c478bd9Sstevel@tonic-gate  *	general entrypoint for Card Services to find
18417c478bd9Sstevel@tonic-gate  *	Socket Services.  Finding the entry requires
18427c478bd9Sstevel@tonic-gate  *	a _depends_on[] relationship.
18437c478bd9Sstevel@tonic-gate  *
18447c478bd9Sstevel@tonic-gate  *	In some cases, the work is done locally but usually
18457c478bd9Sstevel@tonic-gate  *	the parameters are adjusted and the adapter driver
18467c478bd9Sstevel@tonic-gate  *	code asked to do the work.
18477c478bd9Sstevel@tonic-gate  */
18487c478bd9Sstevel@tonic-gate int
18497c478bd9Sstevel@tonic-gate SocketServices(int function, ...)
18507c478bd9Sstevel@tonic-gate {
18517c478bd9Sstevel@tonic-gate 	va_list arglist;
18527c478bd9Sstevel@tonic-gate 	uint32_t args[16];
18537c478bd9Sstevel@tonic-gate 	csregister_t *reg;
18547c478bd9Sstevel@tonic-gate 	sservice_t *serv;
18557c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
18567c478bd9Sstevel@tonic-gate 	int socket, func;
18577c478bd9Sstevel@tonic-gate 	int error = SUCCESS;
18587c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	va_start(arglist, function);
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
18637c478bd9Sstevel@tonic-gate 	if (pcmcia_debug > 1)
18647c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "SocketServices called for function %d [%s]\n",
18657c478bd9Sstevel@tonic-gate 			function,
18667c478bd9Sstevel@tonic-gate 			((function < 128) && ssfuncs[function] != NULL) ?
18677c478bd9Sstevel@tonic-gate 			ssfuncs[function] : "UNKNOWN");
18687c478bd9Sstevel@tonic-gate #endif
18697c478bd9Sstevel@tonic-gate 	switch (function) {
18707c478bd9Sstevel@tonic-gate 	case CSRegister:
18717c478bd9Sstevel@tonic-gate 	case CISGetAddress:
18727c478bd9Sstevel@tonic-gate 	case CISSetAddress:
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 		reg = va_arg(arglist, csregister_t *);
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 		if (reg->cs_magic != PCCS_MAGIC ||
18777c478bd9Sstevel@tonic-gate 		    reg->cs_version != PCCS_VERSION) {
18787c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
18797c478bd9Sstevel@tonic-gate 				"pcmcia: CSRegister (%x, %x, %p, %p) *ERROR*",
18807c478bd9Sstevel@tonic-gate 				reg->cs_magic, reg->cs_version,
18817c478bd9Sstevel@tonic-gate 				(void *)reg->cs_card_services,
18827c478bd9Sstevel@tonic-gate 				(void *)reg->cs_event);
18837c478bd9Sstevel@tonic-gate 			error = BAD_FUNCTION;
18847c478bd9Sstevel@tonic-gate 			break;
18857c478bd9Sstevel@tonic-gate 		}
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 		switch (function) {
18887c478bd9Sstevel@tonic-gate 		case CISGetAddress:
18897c478bd9Sstevel@tonic-gate 			reg->cs_event = pcmcia_cis_parser;
18907c478bd9Sstevel@tonic-gate 			break;
18917c478bd9Sstevel@tonic-gate 		case CISSetAddress:
18927c478bd9Sstevel@tonic-gate 			pcmcia_cis_parser = reg->cs_event;
18937c478bd9Sstevel@tonic-gate 			break;
18947c478bd9Sstevel@tonic-gate 		case CSRegister:
18957c478bd9Sstevel@tonic-gate 			break;
18967c478bd9Sstevel@tonic-gate 		}
18977c478bd9Sstevel@tonic-gate 		break;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	case CSUnregister:
19007c478bd9Sstevel@tonic-gate 		break;
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	case CSCISInit:
19037c478bd9Sstevel@tonic-gate 		args[0] = va_arg(arglist, int);
19047c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
19057c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
19067c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
19077c478bd9Sstevel@tonic-gate 				"CSCISInit: CIS is initialized on socket %d\n",
19087c478bd9Sstevel@tonic-gate 				(int)args[0]);
19097c478bd9Sstevel@tonic-gate #endif
19107c478bd9Sstevel@tonic-gate 		/*
19117c478bd9Sstevel@tonic-gate 		 * now that the CIS has been parsed (there may not
19127c478bd9Sstevel@tonic-gate 		 * be one but the work is done) we can create the
19137c478bd9Sstevel@tonic-gate 		 * device information structures.
19147c478bd9Sstevel@tonic-gate 		 *
19157c478bd9Sstevel@tonic-gate 		 * we serialize the node creation to avoid problems
19167c478bd9Sstevel@tonic-gate 		 * with initial probe/attach of nexi.
19177c478bd9Sstevel@tonic-gate 		 */
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 		mutex_enter(&pcmcia_global_lock);
19207c478bd9Sstevel@tonic-gate 		pcmcia_create_dev_info(args[0]);
19217c478bd9Sstevel@tonic-gate 		cv_broadcast(&pcmcia_condvar); /* wakeup the nexus attach */
19227c478bd9Sstevel@tonic-gate 		mutex_exit(&pcmcia_global_lock);
19237c478bd9Sstevel@tonic-gate 		break;
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	case CSInitDev:
19267c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
19277c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
19287c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "CSInitDev: initialize device\n");
19297c478bd9Sstevel@tonic-gate #endif
19307c478bd9Sstevel@tonic-gate 		/*
19317c478bd9Sstevel@tonic-gate 		 * this is where we create the /devices entries
19327c478bd9Sstevel@tonic-gate 		 * that let us out into the world
19337c478bd9Sstevel@tonic-gate 		 */
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 		(void) pcmcia_create_device(va_arg(arglist,
19367c478bd9Sstevel@tonic-gate 		    ss_make_device_node_t *));
19377c478bd9Sstevel@tonic-gate 		break;
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	case CSCardRemoved:
19407c478bd9Sstevel@tonic-gate 		args[0] = va_arg(arglist, uint32_t);
19417c478bd9Sstevel@tonic-gate 		socket = CS_GET_SOCKET_NUMBER(args[0]);
19427c478bd9Sstevel@tonic-gate 		func = CS_GET_FUNCTION_NUMBER(args[0]);
19437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
19447c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
19457c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
19467c478bd9Sstevel@tonic-gate 				"CSCardRemoved! (socket=%d)\n", (int)args[0]);
19477c478bd9Sstevel@tonic-gate #endif
19487c478bd9Sstevel@tonic-gate 		if (socket >= pcmcia_num_sockets)
19497c478bd9Sstevel@tonic-gate 			break;
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 		sockp = pcmcia_sockets[socket];
19527c478bd9Sstevel@tonic-gate 		if (sockp == NULL) {
19537c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
19547c478bd9Sstevel@tonic-gate 			    "pcmcia: bad socket = %x", socket);
19557c478bd9Sstevel@tonic-gate 			break;
19567c478bd9Sstevel@tonic-gate 		}
19577c478bd9Sstevel@tonic-gate 
195811c2b4c0Srw 		if (!(sockp->ls_flags & PCS_SUSPENDED)) {
195911c2b4c0Srw 			for (func = 0; func < sockp->ls_functions; func++) {
196011c2b4c0Srw 				/*
196111c2b4c0Srw 				 * break the association of dip and socket
196211c2b4c0Srw 				 * for all functions on that socket
196311c2b4c0Srw 				 */
196411c2b4c0Srw 				dip = sockp->ls_dip[func];
196511c2b4c0Srw 				sockp->ls_dip[func] = NULL;
196611c2b4c0Srw 				if (dip != NULL) {
196711c2b4c0Srw 					struct pcmcia_parent_private *ppd;
196811c2b4c0Srw 					ppd = (struct pcmcia_parent_private *)
196911c2b4c0Srw 					    ddi_get_parent_data(dip);
197011c2b4c0Srw 					ppd->ppd_active = 0;
197111c2b4c0Srw 					(void) ndi_devi_offline(dip,
197211c2b4c0Srw 					    NDI_DEVI_REMOVE);
197311c2b4c0Srw 
197411c2b4c0Srw 					pcmcia_ppd_free(ppd);
197511c2b4c0Srw 				}
19767c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
197711c2b4c0Srw 				else {
197811c2b4c0Srw 					if (pcmcia_debug)
197911c2b4c0Srw 						cmn_err(CE_CONT,
198011c2b4c0Srw 						    "CardRemoved: no "
198111c2b4c0Srw 						    "dip present "
198211c2b4c0Srw 						    "on socket %d!\n",
198311c2b4c0Srw 						    (int)args[0]);
198411c2b4c0Srw 				}
19857c478bd9Sstevel@tonic-gate #endif
198611c2b4c0Srw 			}
198711c2b4c0Srw 		} else {
19887c478bd9Sstevel@tonic-gate 			mutex_enter(&pcmcia_global_lock);
19897c478bd9Sstevel@tonic-gate 			sockp->ls_flags &= ~PCS_SUSPENDED;
19907c478bd9Sstevel@tonic-gate 			cv_broadcast(&pcmcia_condvar);
19917c478bd9Sstevel@tonic-gate 			mutex_exit(&pcmcia_global_lock);
19927c478bd9Sstevel@tonic-gate 		}
19937c478bd9Sstevel@tonic-gate 		break;
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	case CSGetCookiesAndDip:
19967c478bd9Sstevel@tonic-gate 		serv = va_arg(arglist, sservice_t *);
19977c478bd9Sstevel@tonic-gate 		if (serv != NULL)
19987c478bd9Sstevel@tonic-gate 			error = GetCookiesAndDip(serv);
19997c478bd9Sstevel@tonic-gate 		else
20007c478bd9Sstevel@tonic-gate 			error = BAD_SOCKET;
20017c478bd9Sstevel@tonic-gate 		break;
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	case CSGetActiveDip:
20047c478bd9Sstevel@tonic-gate 		/*
20057c478bd9Sstevel@tonic-gate 		 * get the dip associated with the card currently
20067c478bd9Sstevel@tonic-gate 		 * in the specified socket
20077c478bd9Sstevel@tonic-gate 		 */
20087c478bd9Sstevel@tonic-gate 		args[0] = va_arg(arglist, uint32_t);
20097c478bd9Sstevel@tonic-gate 		socket = CS_GET_SOCKET_NUMBER(args[0]);
20107c478bd9Sstevel@tonic-gate 		func = CS_GET_FUNCTION_NUMBER(args[0]);
20117c478bd9Sstevel@tonic-gate 		error = (long)pcmcia_sockets[socket]->ls_dip[func];
20127c478bd9Sstevel@tonic-gate 		break;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 		/*
20157c478bd9Sstevel@tonic-gate 		 * the remaining entries are SocketServices calls
20167c478bd9Sstevel@tonic-gate 		 */
20177c478bd9Sstevel@tonic-gate 	case SS_GetAdapter:
20187c478bd9Sstevel@tonic-gate 		error = SSGetAdapter(va_arg(arglist, get_adapter_t *));
20197c478bd9Sstevel@tonic-gate 		break;
20207c478bd9Sstevel@tonic-gate 	case SS_GetPage:
20217c478bd9Sstevel@tonic-gate 		error = SSGetPage(va_arg(arglist, get_page_t *));
20227c478bd9Sstevel@tonic-gate 		break;
20237c478bd9Sstevel@tonic-gate 	case SS_GetSocket:
20247c478bd9Sstevel@tonic-gate 		error = SSGetSocket(va_arg(arglist, get_socket_t *));
20257c478bd9Sstevel@tonic-gate 		break;
20267c478bd9Sstevel@tonic-gate 	case SS_GetStatus:
20277c478bd9Sstevel@tonic-gate 		error = SSGetStatus(va_arg(arglist, get_ss_status_t *));
20287c478bd9Sstevel@tonic-gate 		break;
20297c478bd9Sstevel@tonic-gate 	case SS_GetWindow:
20307c478bd9Sstevel@tonic-gate 		error = SSGetWindow(va_arg(arglist, get_window_t *));
20317c478bd9Sstevel@tonic-gate 		break;
20327c478bd9Sstevel@tonic-gate 	case SS_InquireAdapter:
20337c478bd9Sstevel@tonic-gate 		error = SSInquireAdapter(va_arg(arglist, inquire_adapter_t *));
20347c478bd9Sstevel@tonic-gate 		break;
20357c478bd9Sstevel@tonic-gate 	case SS_InquireSocket:
20367c478bd9Sstevel@tonic-gate 		error = SSInquireSocket(va_arg(arglist, inquire_socket_t *));
20377c478bd9Sstevel@tonic-gate 		break;
20387c478bd9Sstevel@tonic-gate 	case SS_InquireWindow:
20397c478bd9Sstevel@tonic-gate 		error = SSInquireWindow(va_arg(arglist, inquire_window_t *));
20407c478bd9Sstevel@tonic-gate 		break;
20417c478bd9Sstevel@tonic-gate 	case SS_ResetSocket:
20427c478bd9Sstevel@tonic-gate 		args[0] = va_arg(arglist, uint32_t);
20437c478bd9Sstevel@tonic-gate 		args[1] = va_arg(arglist, int);
20447c478bd9Sstevel@tonic-gate 		error = SSResetSocket(args[0], args[1]);
20457c478bd9Sstevel@tonic-gate 		break;
20467c478bd9Sstevel@tonic-gate 	case SS_SetPage:
20477c478bd9Sstevel@tonic-gate 		error = SSSetPage(va_arg(arglist, set_page_t *));
20487c478bd9Sstevel@tonic-gate 		break;
20497c478bd9Sstevel@tonic-gate 	case SS_SetSocket:
20507c478bd9Sstevel@tonic-gate 		error = SSSetSocket(va_arg(arglist, set_socket_t *));
20517c478bd9Sstevel@tonic-gate 		break;
20527c478bd9Sstevel@tonic-gate 	case SS_SetWindow:
20537c478bd9Sstevel@tonic-gate 		error = SSSetWindow(va_arg(arglist, set_window_t *));
20547c478bd9Sstevel@tonic-gate 		break;
20557c478bd9Sstevel@tonic-gate 	case SS_SetIRQHandler:
20567c478bd9Sstevel@tonic-gate 		error = SSSetIRQHandler(va_arg(arglist, set_irq_handler_t *));
20577c478bd9Sstevel@tonic-gate 		break;
20587c478bd9Sstevel@tonic-gate 	case SS_ClearIRQHandler:
20597c478bd9Sstevel@tonic-gate 		error = SSClearIRQHandler(va_arg(arglist,
20607c478bd9Sstevel@tonic-gate 		    clear_irq_handler_t *));
20617c478bd9Sstevel@tonic-gate 		break;
20627c478bd9Sstevel@tonic-gate 	default:
20637c478bd9Sstevel@tonic-gate 		error = BAD_FUNCTION;
20647c478bd9Sstevel@tonic-gate 		break;
20657c478bd9Sstevel@tonic-gate 	}
20667c478bd9Sstevel@tonic-gate 	va_end(arglist);
20677c478bd9Sstevel@tonic-gate 	return (error);
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate /*
20717c478bd9Sstevel@tonic-gate  * pcmcia_merge_power()
20727c478bd9Sstevel@tonic-gate  *	The adapters may have different power tables so it
20737c478bd9Sstevel@tonic-gate  *	is necessary to construct a single power table that
20747c478bd9Sstevel@tonic-gate  *	can be used throughout the system.  The result is
20757c478bd9Sstevel@tonic-gate  *	a merger of all capabilities.  The nexus adds
20767c478bd9Sstevel@tonic-gate  *	power table entries one at a time.
20777c478bd9Sstevel@tonic-gate  */
20787c478bd9Sstevel@tonic-gate void
20797c478bd9Sstevel@tonic-gate pcmcia_merge_power(struct power_entry *power)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate 	int i;
20827c478bd9Sstevel@tonic-gate 	struct power_entry pwr;
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	pwr = *power;
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_power; i++) {
20877c478bd9Sstevel@tonic-gate 		if (pwr.PowerLevel == pcmcia_power_table[i].PowerLevel) {
20887c478bd9Sstevel@tonic-gate 			if (pwr.ValidSignals ==
20897c478bd9Sstevel@tonic-gate 				pcmcia_power_table[i].ValidSignals) {
20907c478bd9Sstevel@tonic-gate 				return;
20917c478bd9Sstevel@tonic-gate 			} else {
20927c478bd9Sstevel@tonic-gate 				/* partial match */
20937c478bd9Sstevel@tonic-gate 				pwr.ValidSignals &=
20947c478bd9Sstevel@tonic-gate 					~pcmcia_power_table[i].ValidSignals;
20957c478bd9Sstevel@tonic-gate 			}
20967c478bd9Sstevel@tonic-gate 		}
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 	/* what's left becomes a new entry */
20997c478bd9Sstevel@tonic-gate 	if (pcmcia_num_power == PCMCIA_MAX_POWER)
21007c478bd9Sstevel@tonic-gate 		return;
21017c478bd9Sstevel@tonic-gate 	pcmcia_power_table[pcmcia_num_power++] = pwr;
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate /*
21057c478bd9Sstevel@tonic-gate  * pcmcia_do_suspend()
21067c478bd9Sstevel@tonic-gate  *	tell CS that a suspend has happened by passing a
21077c478bd9Sstevel@tonic-gate  *	card removal event.  Then cleanup the socket state
21087c478bd9Sstevel@tonic-gate  *	to fake the cards being removed so resume works
21097c478bd9Sstevel@tonic-gate  */
21107c478bd9Sstevel@tonic-gate void
21117c478bd9Sstevel@tonic-gate pcmcia_do_suspend(int socket, pcmcia_logical_socket_t *sockp)
21127c478bd9Sstevel@tonic-gate {
21137c478bd9Sstevel@tonic-gate 	get_ss_status_t stat;
21147c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter *adapt;
21157c478bd9Sstevel@tonic-gate 	pcmcia_if_t *ls_if;
21167c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
21177c478bd9Sstevel@tonic-gate 	int i;
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate #ifdef	XXX
21207c478bd9Sstevel@tonic-gate 	if (pcmcia_cs_event == NULL) {
21217c478bd9Sstevel@tonic-gate 		return;
21227c478bd9Sstevel@tonic-gate 	}
21237c478bd9Sstevel@tonic-gate #endif
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	ls_if = sockp->ls_if;
21267c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
21297c478bd9Sstevel@tonic-gate 		return;
21307c478bd9Sstevel@tonic-gate 	}
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	stat.socket = socket;
21337c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
21347c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
21357c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
21367c478bd9Sstevel@tonic-gate 			"pcmcia_do_suspend(%d, %p)\n", socket, (void *)sockp);
21377c478bd9Sstevel@tonic-gate 	}
21387c478bd9Sstevel@tonic-gate #endif
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	if (GET_STATUS(ls_if, adapt->pca_dip, &stat) != SUCCESS)
21417c478bd9Sstevel@tonic-gate 		return;
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	/*
21447c478bd9Sstevel@tonic-gate 	 * If there is a card in the socket, then we need to send
21457c478bd9Sstevel@tonic-gate 	 *	everyone a PCE_CARD_REMOVAL event, and remove the
21467c478bd9Sstevel@tonic-gate 	 *	card active property.
21477c478bd9Sstevel@tonic-gate 	 */
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	for (i = 0; i < sockp->ls_functions; i++) {
21507c478bd9Sstevel@tonic-gate 		struct pcmcia_parent_private *ppd;
21517c478bd9Sstevel@tonic-gate 		dip = sockp->ls_dip[i];
21527c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
21537c478bd9Sstevel@tonic-gate 			ppd = (struct pcmcia_parent_private *)
21547c478bd9Sstevel@tonic-gate 				ddi_get_parent_data(dip);
21557c478bd9Sstevel@tonic-gate 			ppd->ppd_flags |= PPD_SUSPENDED;
21567c478bd9Sstevel@tonic-gate 		}
21577c478bd9Sstevel@tonic-gate #if 0
21587c478bd9Sstevel@tonic-gate 		sockp->ls_dip[i] = NULL;
21597c478bd9Sstevel@tonic-gate #endif
21607c478bd9Sstevel@tonic-gate 	}
21617c478bd9Sstevel@tonic-gate 	sockp->ls_flags |= PCS_SUSPENDED;
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	if (pcmcia_cs_event &&
21647c478bd9Sstevel@tonic-gate 	    (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
21657c478bd9Sstevel@tonic-gate 		CS_EVENT(PCE_PM_SUSPEND, socket, 0);
21667c478bd9Sstevel@tonic-gate 	}
21677c478bd9Sstevel@tonic-gate 	pcm_event_manager(PCE_PM_SUSPEND, socket, NULL);
21687c478bd9Sstevel@tonic-gate }
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate /*
21717c478bd9Sstevel@tonic-gate  * pcmcia_do_resume()
21727c478bd9Sstevel@tonic-gate  *	tell CS that a suspend has happened by passing a
21737c478bd9Sstevel@tonic-gate  *	card removal event.  Then cleanup the socket state
21747c478bd9Sstevel@tonic-gate  *	to fake the cards being removed so resume works
21757c478bd9Sstevel@tonic-gate  */
21767c478bd9Sstevel@tonic-gate void
21777c478bd9Sstevel@tonic-gate pcmcia_do_resume(int socket, pcmcia_logical_socket_t *sockp)
21787c478bd9Sstevel@tonic-gate {
21797c478bd9Sstevel@tonic-gate 	get_ss_status_t stat;
21807c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter *adapt;
21817c478bd9Sstevel@tonic-gate 	pcmcia_if_t *ls_if;
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate #ifdef	XXX
21847c478bd9Sstevel@tonic-gate 	if (pcmcia_cs_event == NULL) {
21857c478bd9Sstevel@tonic-gate 		return;
21867c478bd9Sstevel@tonic-gate 	}
21877c478bd9Sstevel@tonic-gate #endif
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	ls_if = sockp->ls_if;
21907c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
21937c478bd9Sstevel@tonic-gate 		return;
21947c478bd9Sstevel@tonic-gate 	}
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	stat.socket = socket;
21977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
21987c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
21997c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
22007c478bd9Sstevel@tonic-gate 			"pcmcia_do_resume(%d, %p)\n", socket, (void *)sockp);
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate #endif
22037c478bd9Sstevel@tonic-gate 	if (GET_STATUS(ls_if, adapt->pca_dip, &stat) ==
22047c478bd9Sstevel@tonic-gate 	    SUCCESS) {
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
22077c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
22087c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tsocket=%x, CardState=%x\n",
22097c478bd9Sstevel@tonic-gate 				socket, stat.CardState);
22107c478bd9Sstevel@tonic-gate #endif
22117c478bd9Sstevel@tonic-gate #if 0
22127c478bd9Sstevel@tonic-gate 		/* now have socket info -- do we have events? */
22137c478bd9Sstevel@tonic-gate 		if ((stat.CardState & SBM_CD) == SBM_CD) {
22147c478bd9Sstevel@tonic-gate 			if (pcmcia_cs_event &&
22157c478bd9Sstevel@tonic-gate 			    (sockp->ls_cs_events & (1 << PCE_CARD_INSERT))) {
22167c478bd9Sstevel@tonic-gate 				CS_EVENT(PCE_CARD_INSERT, socket, 0);
22177c478bd9Sstevel@tonic-gate 			}
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 			/* we should have card removed from CS soon */
22207c478bd9Sstevel@tonic-gate 			pcm_event_manager(PCE_CARD_INSERT, socket, NULL);
22217c478bd9Sstevel@tonic-gate 		}
22227c478bd9Sstevel@tonic-gate #else
22237c478bd9Sstevel@tonic-gate 		if (pcmcia_cs_event &&
22247c478bd9Sstevel@tonic-gate 		    (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
22257c478bd9Sstevel@tonic-gate 			CS_EVENT(PCE_PM_RESUME, socket, 0);
22267c478bd9Sstevel@tonic-gate 			CS_EVENT(PCE_CARD_REMOVAL, socket, 0);
22277c478bd9Sstevel@tonic-gate 			if ((stat.CardState & SBM_CD) == SBM_CD)
22287c478bd9Sstevel@tonic-gate 				CS_EVENT(PCE_CARD_INSERT, socket, 0);
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate #endif
22317c478bd9Sstevel@tonic-gate 	}
22327c478bd9Sstevel@tonic-gate }
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate /*
22357c478bd9Sstevel@tonic-gate  * pcmcia_map_power_set()
22367c478bd9Sstevel@tonic-gate  *	Given a power table entry and level, find it in the
22377c478bd9Sstevel@tonic-gate  *	master table and return the index in the adapter table.
22387c478bd9Sstevel@tonic-gate  */
22397c478bd9Sstevel@tonic-gate static int
22407c478bd9Sstevel@tonic-gate pcmcia_map_power_set(struct pcmcia_adapter *adapt, int level, int which)
22417c478bd9Sstevel@tonic-gate {
22427c478bd9Sstevel@tonic-gate 	int plevel, i;
22437c478bd9Sstevel@tonic-gate 	struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
22447c478bd9Sstevel@tonic-gate 	plevel = pcmcia_power_table[level].PowerLevel;
22457c478bd9Sstevel@tonic-gate 	/* mask = pcmcia_power_table[level].ValidSignals; */
22467c478bd9Sstevel@tonic-gate 	for (i = 0; i < adapt->pca_numpower; i++)
22477c478bd9Sstevel@tonic-gate 		if (plevel == pwr[i].PowerLevel &&
22487c478bd9Sstevel@tonic-gate 		    pwr[i].ValidSignals & which)
22497c478bd9Sstevel@tonic-gate 			return (i);
22507c478bd9Sstevel@tonic-gate 	return (0);
22517c478bd9Sstevel@tonic-gate }
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate /*
22547c478bd9Sstevel@tonic-gate  * pcmcia_map_power_get()
22557c478bd9Sstevel@tonic-gate  *	Given an adapter power entry, find the appropriate index
22567c478bd9Sstevel@tonic-gate  *	in the master table.
22577c478bd9Sstevel@tonic-gate  */
22587c478bd9Sstevel@tonic-gate static int
22597c478bd9Sstevel@tonic-gate pcmcia_map_power_get(struct pcmcia_adapter *adapt, int level, int which)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	int plevel, i;
22627c478bd9Sstevel@tonic-gate 	struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
22637c478bd9Sstevel@tonic-gate 	plevel = pwr[level].PowerLevel;
22647c478bd9Sstevel@tonic-gate 	/* mask = pwr[level].ValidSignals; */
22657c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_power; i++)
22667c478bd9Sstevel@tonic-gate 		if (plevel == pcmcia_power_table[i].PowerLevel &&
22677c478bd9Sstevel@tonic-gate 		    pcmcia_power_table[i].ValidSignals & which)
22687c478bd9Sstevel@tonic-gate 			return (i);
22697c478bd9Sstevel@tonic-gate 	return (0);
22707c478bd9Sstevel@tonic-gate }
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate /*
22737c478bd9Sstevel@tonic-gate  * XXX - SS really needs a way to allow the caller to express
22747c478bd9Sstevel@tonic-gate  *	interest in PCE_CARD_STATUS_CHANGE events.
22757c478bd9Sstevel@tonic-gate  */
22767c478bd9Sstevel@tonic-gate static uint32_t
22777c478bd9Sstevel@tonic-gate pcm_event_map[32] = {
22787c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_WRITE_PROTECT)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22797c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_UNLOCK)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22807c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_EJECTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22817c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_INSERTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22827c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_BATTERY_WARN)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22837c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_BATTERY_DEAD)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22847c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_READY)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
22857c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_CARD_REMOVAL)|PCE_E2M(PCE_CARD_INSERT)|
22867c478bd9Sstevel@tonic-gate 					PCE_E2M(PCE_CARD_STATUS_CHANGE),
22877c478bd9Sstevel@tonic-gate 	PCE_E2M(PCE_PM_SUSPEND)|PCE_E2M(PCE_PM_RESUME),
22887c478bd9Sstevel@tonic-gate };
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate static int
22917c478bd9Sstevel@tonic-gate pcm_mapevents(uint32_t eventmask)
22927c478bd9Sstevel@tonic-gate {
22937c478bd9Sstevel@tonic-gate 	uint32_t mask;
22947c478bd9Sstevel@tonic-gate 	int i;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	for (i = 0, mask = 0; eventmask && i < 32; i++) {
22977c478bd9Sstevel@tonic-gate 		if (eventmask & (1 << i)) {
22987c478bd9Sstevel@tonic-gate 			mask |= pcm_event_map[i];
22997c478bd9Sstevel@tonic-gate 			eventmask &= ~(1 << i);
23007c478bd9Sstevel@tonic-gate 		}
23017c478bd9Sstevel@tonic-gate 	}
23027c478bd9Sstevel@tonic-gate 	return (mask);
23037c478bd9Sstevel@tonic-gate }
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate /*
23077c478bd9Sstevel@tonic-gate  * PCMCIA Generic Naming Support
23087c478bd9Sstevel@tonic-gate  *
23097c478bd9Sstevel@tonic-gate  * With 2.6, PCMCIA naming moves to the 1275 and generic naming model.
23107c478bd9Sstevel@tonic-gate  * Consequently, the whole naming mechanism is to be changed.  This is
23117c478bd9Sstevel@tonic-gate  * not backward compatible with the current names but that isn't a problem
23127c478bd9Sstevel@tonic-gate  * due to so few drivers existing.
23137c478bd9Sstevel@tonic-gate  *
23147c478bd9Sstevel@tonic-gate  * For cards with a device_id tuple, a generic name will be used.
23157c478bd9Sstevel@tonic-gate  * if there is no device_id, then the 1275 name will be used if possible.
23167c478bd9Sstevel@tonic-gate  * The 1275 name is of the form pccardNNNN,MMMM from the manfid tuple.
23177c478bd9Sstevel@tonic-gate  * if there is not manfid tuple, an attempt will be made to bind the
23187c478bd9Sstevel@tonic-gate  * node to the version_1 strings.
23197c478bd9Sstevel@tonic-gate  *
23207c478bd9Sstevel@tonic-gate  * In all cases, a "compatible" property is created with a number
23217c478bd9Sstevel@tonic-gate  * of names.  The most generic name will be last in the list.
23227c478bd9Sstevel@tonic-gate  */
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate /*
23257c478bd9Sstevel@tonic-gate  * pcmcia_fix_string()
23267c478bd9Sstevel@tonic-gate  * want to avoid special characters in alias strings so convert
23277c478bd9Sstevel@tonic-gate  * to something innocuous
23287c478bd9Sstevel@tonic-gate  */
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate void
23317c478bd9Sstevel@tonic-gate pcmcia_fix_string(char *str)
23327c478bd9Sstevel@tonic-gate {
23337c478bd9Sstevel@tonic-gate 	for (; str && *str; str++) {
23347c478bd9Sstevel@tonic-gate 		switch (*str) {
23357c478bd9Sstevel@tonic-gate 			case ' ':
23367c478bd9Sstevel@tonic-gate 			case '\t':
23377c478bd9Sstevel@tonic-gate 				*str = '_';
23387c478bd9Sstevel@tonic-gate 				break;
23397c478bd9Sstevel@tonic-gate 		}
23407c478bd9Sstevel@tonic-gate 	}
23417c478bd9Sstevel@tonic-gate }
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate void
23447c478bd9Sstevel@tonic-gate pcmcia_1275_name(int socket, struct pcm_device_info *info,
23457c478bd9Sstevel@tonic-gate 			client_handle_t handle)
23467c478bd9Sstevel@tonic-gate {
23477c478bd9Sstevel@tonic-gate 	cistpl_manfid_t manfid;
23487c478bd9Sstevel@tonic-gate 	cistpl_jedec_t jedec;
23497c478bd9Sstevel@tonic-gate 	tuple_t tuple;
23507c478bd9Sstevel@tonic-gate 	int i;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	tuple.Socket = socket;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	/* get MANFID if it exists -- this is most important form */
23557c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_MANFID;
23567c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
23577c478bd9Sstevel@tonic-gate 	if ((i = csx_GetFirstTuple(handle, &tuple)) ==
23587c478bd9Sstevel@tonic-gate 	    SUCCESS) {
23597c478bd9Sstevel@tonic-gate 		i = csx_Parse_CISTPL_MANFID(handle, &tuple,
23607c478bd9Sstevel@tonic-gate 		    &manfid);
23617c478bd9Sstevel@tonic-gate 		if (i == SUCCESS) {
23627c478bd9Sstevel@tonic-gate 			(void) sprintf(info->pd_bind_name, "%s%x,%x",
23637c478bd9Sstevel@tonic-gate 				PCMDEV_NAMEPREF,
23647c478bd9Sstevel@tonic-gate 				manfid.manf, manfid.card);
23657c478bd9Sstevel@tonic-gate 			info->pd_flags |= PCM_NAME_1275;
23667c478bd9Sstevel@tonic-gate 		}
23677c478bd9Sstevel@tonic-gate 	} else {
23687c478bd9Sstevel@tonic-gate 		tuple.Attributes = 0;
23697c478bd9Sstevel@tonic-gate 		tuple.DesiredTuple = CISTPL_JEDEC_A;
23707c478bd9Sstevel@tonic-gate 		if ((i = csx_GetFirstTuple(handle, &tuple)) ==
23717c478bd9Sstevel@tonic-gate 		    SUCCESS) {
23727c478bd9Sstevel@tonic-gate 			i = csx_Parse_CISTPL_JEDEC_A(handle, &tuple,
23737c478bd9Sstevel@tonic-gate 			    &jedec);
23747c478bd9Sstevel@tonic-gate 			if (i == SUCCESS) {
23757c478bd9Sstevel@tonic-gate 				(void) sprintf(info->pd_bind_name, "%s%x,%x",
23767c478bd9Sstevel@tonic-gate 					PCMDEV_NAMEPREF,
23777c478bd9Sstevel@tonic-gate 					jedec.jid[0].id, jedec.jid[0].info);
23787c478bd9Sstevel@tonic-gate 				info->pd_flags |= PCM_NAME_1275;
23797c478bd9Sstevel@tonic-gate 			}
23807c478bd9Sstevel@tonic-gate 		}
23817c478bd9Sstevel@tonic-gate 	}
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate void
23857c478bd9Sstevel@tonic-gate pcmcia_vers1_name(int socket, struct pcm_device_info *info,
23867c478bd9Sstevel@tonic-gate 			client_handle_t handle)
23877c478bd9Sstevel@tonic-gate {
23887c478bd9Sstevel@tonic-gate 	cistpl_vers_1_t vers1;
23897c478bd9Sstevel@tonic-gate 	tuple_t tuple;
23907c478bd9Sstevel@tonic-gate 	int which = 0;
23917c478bd9Sstevel@tonic-gate 	int i, len, space;
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	tuple.Socket = socket;
23947c478bd9Sstevel@tonic-gate 	info->pd_vers1_name[0] = '\0';
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	/* Version 1 strings */
23977c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_VERS_1;
23987c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
23997c478bd9Sstevel@tonic-gate 	if (!which &&
24007c478bd9Sstevel@tonic-gate 	    (i = csx_GetFirstTuple(handle, &tuple)) ==
24017c478bd9Sstevel@tonic-gate 		SUCCESS) {
24027c478bd9Sstevel@tonic-gate 		i = csx_Parse_CISTPL_VERS_1(handle, &tuple, &vers1);
24037c478bd9Sstevel@tonic-gate 		if (i == SUCCESS) {
24047c478bd9Sstevel@tonic-gate 			for (i = 0, len = 0, space = 0; i < vers1.ns; i++) {
24057c478bd9Sstevel@tonic-gate 			    if ((space + len + strlen(info->pd_vers1_name)) >=
24067c478bd9Sstevel@tonic-gate 				sizeof (info->pd_vers1_name))
24077c478bd9Sstevel@tonic-gate 				    break;
24087c478bd9Sstevel@tonic-gate 			    if (space) {
24097c478bd9Sstevel@tonic-gate 				    info->pd_vers1_name[len++] = ',';
24107c478bd9Sstevel@tonic-gate 			    }
24117c478bd9Sstevel@tonic-gate 			    (void) strcpy(info->pd_vers1_name + len,
24127c478bd9Sstevel@tonic-gate 				(char *)vers1.pi[i]);
24137c478bd9Sstevel@tonic-gate 			    len += strlen((char *)vers1.pi[i]);
24147c478bd9Sstevel@tonic-gate 			    /* strip trailing spaces off of string */
24157c478bd9Sstevel@tonic-gate 			    while (info->pd_vers1_name[len - 1] == ' ' &&
24167c478bd9Sstevel@tonic-gate 				    len > 0)
24177c478bd9Sstevel@tonic-gate 				    len--;
24187c478bd9Sstevel@tonic-gate 			    space = 1;
24197c478bd9Sstevel@tonic-gate 			}
24207c478bd9Sstevel@tonic-gate 			info->pd_vers1_name[len] = '\0';
24217c478bd9Sstevel@tonic-gate 			info->pd_flags |= PCM_NAME_VERS1;
24227c478bd9Sstevel@tonic-gate 		}
24237c478bd9Sstevel@tonic-gate 	}
24247c478bd9Sstevel@tonic-gate }
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate int
24287c478bd9Sstevel@tonic-gate pcmcia_get_funce(client_handle_t handle, tuple_t *tuple)
24297c478bd9Sstevel@tonic-gate {
24307c478bd9Sstevel@tonic-gate 	int ret = 0;
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 	tuple->Attributes = 0;
24337c478bd9Sstevel@tonic-gate 	while (csx_GetNextTuple(handle, tuple) == SUCCESS) {
24347c478bd9Sstevel@tonic-gate 		if (tuple->TupleCode == CISTPL_FUNCID) {
24357c478bd9Sstevel@tonic-gate 			break;
24367c478bd9Sstevel@tonic-gate 		}
24377c478bd9Sstevel@tonic-gate 		if (tuple->TupleCode == CISTPL_FUNCE) {
24387c478bd9Sstevel@tonic-gate 			ret = 1;
24397c478bd9Sstevel@tonic-gate 			break;
24407c478bd9Sstevel@tonic-gate 		}
24417c478bd9Sstevel@tonic-gate 		tuple->Attributes = 0;
24427c478bd9Sstevel@tonic-gate 	}
24437c478bd9Sstevel@tonic-gate 	return (ret);
24447c478bd9Sstevel@tonic-gate }
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate char *pcmcia_lan_types[] = {
24477c478bd9Sstevel@tonic-gate 	"arcnet",
24487c478bd9Sstevel@tonic-gate 	"ethernet",
24497c478bd9Sstevel@tonic-gate 	"token-ring",
24507c478bd9Sstevel@tonic-gate 	"localtalk",
24517c478bd9Sstevel@tonic-gate 	"fddi",
24527c478bd9Sstevel@tonic-gate 	"atm",
24537c478bd9Sstevel@tonic-gate 	"wireless",
24547c478bd9Sstevel@tonic-gate 	"reserved"
24557c478bd9Sstevel@tonic-gate };
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate void
24587c478bd9Sstevel@tonic-gate pcmcia_generic_name(int socket, struct pcm_device_info *info,
24597c478bd9Sstevel@tonic-gate 			client_handle_t handle)
24607c478bd9Sstevel@tonic-gate {
24617c478bd9Sstevel@tonic-gate 	cistpl_funcid_t funcid;
24627c478bd9Sstevel@tonic-gate 	cistpl_funce_t funce;
24637c478bd9Sstevel@tonic-gate 	tuple_t tuple;
24647c478bd9Sstevel@tonic-gate 	int which = 0;
24657c478bd9Sstevel@tonic-gate 	int i;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	tuple.Socket = socket;
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_FUNCID;
24707c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
24717c478bd9Sstevel@tonic-gate 	if ((i = csx_GetFirstTuple(handle, &tuple)) ==
24727c478bd9Sstevel@tonic-gate 	    SUCCESS) {
24737c478bd9Sstevel@tonic-gate 		/*
24747c478bd9Sstevel@tonic-gate 		 * need to make sure that CISTPL_FUNCID is not
24757c478bd9Sstevel@tonic-gate 		 * present in both a global and local CIS for MF
24767c478bd9Sstevel@tonic-gate 		 * cards.  3COM seems to do this erroneously
24777c478bd9Sstevel@tonic-gate 		 */
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_MULTI_FUNCTION &&
24807c478bd9Sstevel@tonic-gate 		    tuple.Flags & CISTPLF_GLOBAL_CIS) {
24817c478bd9Sstevel@tonic-gate 			tuple_t ltuple;
24827c478bd9Sstevel@tonic-gate 			ltuple = tuple;
24837c478bd9Sstevel@tonic-gate 			ltuple.DesiredTuple = CISTPL_FUNCID;
24847c478bd9Sstevel@tonic-gate 			ltuple.Attributes = 0;
24857c478bd9Sstevel@tonic-gate 			if ((i = csx_GetNextTuple(handle, &ltuple)) ==
24867c478bd9Sstevel@tonic-gate 			    SUCCESS) {
24877c478bd9Sstevel@tonic-gate 				/* this is the per-function funcid */
24887c478bd9Sstevel@tonic-gate 				tuple = ltuple;
24897c478bd9Sstevel@tonic-gate 			}
24907c478bd9Sstevel@tonic-gate 		}
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 		i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid);
24937c478bd9Sstevel@tonic-gate 		if (i == SUCCESS) {
24947c478bd9Sstevel@tonic-gate 			/* in case no function extension */
24957c478bd9Sstevel@tonic-gate 			if (funcid.function < PCM_GENNAME_SIZE)
24967c478bd9Sstevel@tonic-gate 				(void) strcpy(info->pd_generic_name,
24977c478bd9Sstevel@tonic-gate 				    pcmcia_generic_names[funcid.function]);
24987c478bd9Sstevel@tonic-gate 			else
24997c478bd9Sstevel@tonic-gate 				(void) sprintf(info->pd_generic_name,
25007c478bd9Sstevel@tonic-gate 					"class,%x",
25017c478bd9Sstevel@tonic-gate 					funcid.function);
25027c478bd9Sstevel@tonic-gate 		}
25037c478bd9Sstevel@tonic-gate 		info->pd_type = funcid.function;
25047c478bd9Sstevel@tonic-gate 		switch (funcid.function) {
25057c478bd9Sstevel@tonic-gate 		case TPLFUNC_LAN:
25067c478bd9Sstevel@tonic-gate 			which = pcmcia_get_funce(handle, &tuple);
25077c478bd9Sstevel@tonic-gate 			if (which) {
25087c478bd9Sstevel@tonic-gate 				i = csx_Parse_CISTPL_FUNCE(handle,
25097c478bd9Sstevel@tonic-gate 				    &tuple,
25107c478bd9Sstevel@tonic-gate 				    &funce, TPLFUNC_LAN);
25117c478bd9Sstevel@tonic-gate 				if (i == SUCCESS) {
25127c478bd9Sstevel@tonic-gate 					i = funce.data.lan.tech;
25137c478bd9Sstevel@tonic-gate 					if (i > sizeof (pcmcia_lan_types) /
25147c478bd9Sstevel@tonic-gate 					    sizeof (char *)) {
25157c478bd9Sstevel@tonic-gate 						break;
25167c478bd9Sstevel@tonic-gate 					}
25177c478bd9Sstevel@tonic-gate 					(void) strcpy(info->pd_generic_name,
25187c478bd9Sstevel@tonic-gate 						pcmcia_lan_types[i]);
25197c478bd9Sstevel@tonic-gate 				}
25207c478bd9Sstevel@tonic-gate 			}
25217c478bd9Sstevel@tonic-gate 			break;
25227c478bd9Sstevel@tonic-gate 		case TPLFUNC_VIDEO:
25237c478bd9Sstevel@tonic-gate #ifdef future_pcmcia_spec
25247c478bd9Sstevel@tonic-gate 			which = pcmcia_get_funce(handle, &tuple);
25257c478bd9Sstevel@tonic-gate 			if (which) {
25267c478bd9Sstevel@tonic-gate 				i = csx_Parse_CISTPL_FUNCE(handle,
25277c478bd9Sstevel@tonic-gate 				    &tuple,
25287c478bd9Sstevel@tonic-gate 				    &funce, TPLFUNC_VIDEO);
25297c478bd9Sstevel@tonic-gate 				if (i == SUCCESS) {
25307c478bd9Sstevel@tonic-gate 					i = funce.video.tech;
25317c478bd9Sstevel@tonic-gate 					if (i > sizeof (pcmcia_lan_types) /
25327c478bd9Sstevel@tonic-gate 					    sizeof (char *)) {
25337c478bd9Sstevel@tonic-gate 						break;
25347c478bd9Sstevel@tonic-gate 					}
25357c478bd9Sstevel@tonic-gate 					(void) strcpy(info->pd_generic_names,
25367c478bd9Sstevel@tonic-gate 						pcmcia_lan_types[i]);
25377c478bd9Sstevel@tonic-gate 				}
25387c478bd9Sstevel@tonic-gate 			}
25397c478bd9Sstevel@tonic-gate #endif
25407c478bd9Sstevel@tonic-gate 			break;
25417c478bd9Sstevel@tonic-gate 		}
25427c478bd9Sstevel@tonic-gate 		info->pd_flags |= PCM_NAME_GENERIC;
25437c478bd9Sstevel@tonic-gate 	} else {
25447c478bd9Sstevel@tonic-gate 		/* if no FUNCID, do we have CONFIG */
25457c478bd9Sstevel@tonic-gate 		tuple.DesiredTuple = CISTPL_CONFIG;
25467c478bd9Sstevel@tonic-gate 		tuple.Attributes = 0;
25477c478bd9Sstevel@tonic-gate 		if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) {
25487c478bd9Sstevel@tonic-gate 			info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC;
25497c478bd9Sstevel@tonic-gate 			(void) strcpy(info->pd_generic_name,
25507c478bd9Sstevel@tonic-gate 				pcmcia_generic_names[PCM_TYPE_MEMORY]);
25517c478bd9Sstevel@tonic-gate 			info->pd_type = PCM_TYPE_MEMORY;
25527c478bd9Sstevel@tonic-gate 		}
25537c478bd9Sstevel@tonic-gate 	}
25547c478bd9Sstevel@tonic-gate }
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate /*
25587c478bd9Sstevel@tonic-gate  * pcmcia_add_compatible()
25597c478bd9Sstevel@tonic-gate  * add the cached compatible property list.
25607c478bd9Sstevel@tonic-gate  */
25617c478bd9Sstevel@tonic-gate void
25627c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info)
25637c478bd9Sstevel@tonic-gate {
25647c478bd9Sstevel@tonic-gate 	int length = 0, i;
25657c478bd9Sstevel@tonic-gate 	char buff[MAXNAMELEN];
25667c478bd9Sstevel@tonic-gate 	char *compat_name[8];
25677c478bd9Sstevel@tonic-gate 	int ci = 0;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	bzero(compat_name, sizeof (compat_name));
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate 	if (info->pd_flags & PCM_NAME_VERS1) {
25727c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
25737c478bd9Sstevel@tonic-gate 		    info->pd_vers1_name);
25747c478bd9Sstevel@tonic-gate 		pcmcia_fix_string(buff); /* don't want spaces */
25757c478bd9Sstevel@tonic-gate 		length = strlen(buff) + 1;
25767c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
25777c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], buff);
25787c478bd9Sstevel@tonic-gate 	}
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
25817c478bd9Sstevel@tonic-gate 	    (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
25827c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "%s,%x", info->pd_bind_name,
25837c478bd9Sstevel@tonic-gate 		    info->pd_function);
25847c478bd9Sstevel@tonic-gate 		length = strlen(buff) + 1;
25857c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
25867c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], buff);
25877c478bd9Sstevel@tonic-gate 	}
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	if (info->pd_flags & PCM_NAME_1275) {
25907c478bd9Sstevel@tonic-gate 		length = strlen(info->pd_bind_name) + 1;
25917c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
25927c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], info->pd_bind_name);
25937c478bd9Sstevel@tonic-gate 	}
25947c478bd9Sstevel@tonic-gate 
25957c478bd9Sstevel@tonic-gate 	if (info->pd_flags & PCM_NAME_GENERIC) {
25967c478bd9Sstevel@tonic-gate 		if (strncmp(info->pd_generic_name, "class,", 6) == 0) {
25977c478bd9Sstevel@tonic-gate 			/* no generic without "pccard" */
25987c478bd9Sstevel@tonic-gate 			(void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF,
25997c478bd9Sstevel@tonic-gate 				info->pd_generic_name);
26007c478bd9Sstevel@tonic-gate 		} else {
26017c478bd9Sstevel@tonic-gate 			/* first pccard,generic-name */
26027c478bd9Sstevel@tonic-gate 			(void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
26037c478bd9Sstevel@tonic-gate 				info->pd_generic_name);
26047c478bd9Sstevel@tonic-gate 		}
26057c478bd9Sstevel@tonic-gate 		length = strlen(buff) + 1;
26067c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
26077c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], buff);
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 		/* now the simple generic name */
26107c478bd9Sstevel@tonic-gate 		length = strlen(info->pd_generic_name) + 1;
26117c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
26127c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], info->pd_generic_name);
26137c478bd9Sstevel@tonic-gate 	}
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 	if (info->pd_flags & PCM_NO_CONFIG) {
26167c478bd9Sstevel@tonic-gate 		char *mem = "pccard,memory";
26177c478bd9Sstevel@tonic-gate 		/*
26187c478bd9Sstevel@tonic-gate 		 * I/O cards are required to have a config tuple.
26197c478bd9Sstevel@tonic-gate 		 * there are some that violate the spec and don't
26207c478bd9Sstevel@tonic-gate 		 * but it is most likely that this is a memory card
26217c478bd9Sstevel@tonic-gate 		 * so tag it as such.  "memory" is more general
26227c478bd9Sstevel@tonic-gate 		 * than other things so needs to come last.
26237c478bd9Sstevel@tonic-gate 		 */
26247c478bd9Sstevel@tonic-gate 		length = strlen(mem) + 1;
26257c478bd9Sstevel@tonic-gate 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
26267c478bd9Sstevel@tonic-gate 		(void) strcpy(compat_name[ci++], mem);
26277c478bd9Sstevel@tonic-gate 	}
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	if (ci == 0)
26307c478bd9Sstevel@tonic-gate 		return;
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
26337c478bd9Sstevel@tonic-gate 	    "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS)
26347c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pcmcia: unable to create compatible prop");
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 	for (i = 0; i < ci; i++)
26377c478bd9Sstevel@tonic-gate 		kmem_free(compat_name[i], strlen(compat_name[i]) + 1);
26387c478bd9Sstevel@tonic-gate }
26397c478bd9Sstevel@tonic-gate /*
26407c478bd9Sstevel@tonic-gate  * CIS parsing and other PC Card specific code
26417c478bd9Sstevel@tonic-gate  */
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate /*
26447c478bd9Sstevel@tonic-gate  * pcmcia_get_mem_regs()
26457c478bd9Sstevel@tonic-gate  */
26467c478bd9Sstevel@tonic-gate static int
26477c478bd9Sstevel@tonic-gate pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info,
26487c478bd9Sstevel@tonic-gate 			int type, int pctype)
26497c478bd9Sstevel@tonic-gate {
26507c478bd9Sstevel@tonic-gate 	int num_regs = 0;
26517c478bd9Sstevel@tonic-gate 	tuple_t tuple;
26527c478bd9Sstevel@tonic-gate 	cistpl_device_t device;
26537c478bd9Sstevel@tonic-gate 	uint32_t curr_base;
26547c478bd9Sstevel@tonic-gate 	int ret, len;
26557c478bd9Sstevel@tonic-gate 	int space;
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 	/*
26587c478bd9Sstevel@tonic-gate 	 * current plan for reg spec:
26597c478bd9Sstevel@tonic-gate 	 * device_a will be accumulated to determine max size of
26607c478bd9Sstevel@tonic-gate 	 * attribute memory.  device for common.  Then config
26617c478bd9Sstevel@tonic-gate 	 * tuples to get a worst case I/O size.
26627c478bd9Sstevel@tonic-gate 	 */
26637c478bd9Sstevel@tonic-gate 	bzero(&tuple, sizeof (tuple));
26647c478bd9Sstevel@tonic-gate 	tuple.Socket = info->pd_socket;
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = (cisdata_t)type;
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE :
26697c478bd9Sstevel@tonic-gate 		PC_REG_SPACE_MEMORY;
26707c478bd9Sstevel@tonic-gate 	if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) {
26717c478bd9Sstevel@tonic-gate 		bzero(&device, sizeof (device));
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate 		if (type == CISTPL_DEVICE)
26747c478bd9Sstevel@tonic-gate 			ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple,
26757c478bd9Sstevel@tonic-gate 			    &device);
26767c478bd9Sstevel@tonic-gate 		else
26777c478bd9Sstevel@tonic-gate 			ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple,
26787c478bd9Sstevel@tonic-gate 			    &device);
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 		if (ret == CS_SUCCESS) {
26817c478bd9Sstevel@tonic-gate 		    curr_base = 0;
26827c478bd9Sstevel@tonic-gate 		    for (ret = 0; ret < device.num_devices;
26837c478bd9Sstevel@tonic-gate 			ret++) {
26847c478bd9Sstevel@tonic-gate 			    /* need to order these for real mem first */
26857c478bd9Sstevel@tonic-gate 			    if (device.devnode[ret].type !=
26867c478bd9Sstevel@tonic-gate 				CISTPL_DEVICE_DTYPE_NULL) {
26877c478bd9Sstevel@tonic-gate 				    /* how to represent types??? */
26887c478bd9Sstevel@tonic-gate 				    regs[num_regs].phys_hi =
26897c478bd9Sstevel@tonic-gate 					PC_REG_PHYS_HI(0, 0,
26907c478bd9Sstevel@tonic-gate 					    pctype,
26917c478bd9Sstevel@tonic-gate 					    space,
26927c478bd9Sstevel@tonic-gate 					    info->pd_socket,
26937c478bd9Sstevel@tonic-gate 					    info->pd_function,
26947c478bd9Sstevel@tonic-gate 					    0);
26957c478bd9Sstevel@tonic-gate 				    regs[num_regs].phys_lo = curr_base;
26967c478bd9Sstevel@tonic-gate 				    len = device.devnode[ret].size_in_bytes;
26977c478bd9Sstevel@tonic-gate 				    curr_base += len;
26987c478bd9Sstevel@tonic-gate 				    regs[num_regs].phys_len = len;
26997c478bd9Sstevel@tonic-gate 				    num_regs++;
27007c478bd9Sstevel@tonic-gate 			    } else {
27017c478bd9Sstevel@tonic-gate 				/*
27027c478bd9Sstevel@tonic-gate 				 * NULL device is a "hole"
27037c478bd9Sstevel@tonic-gate 				 */
27047c478bd9Sstevel@tonic-gate 				    curr_base +=
27057c478bd9Sstevel@tonic-gate 					    device.devnode[ret].size_in_bytes;
27067c478bd9Sstevel@tonic-gate 			    }
27077c478bd9Sstevel@tonic-gate 			}
27087c478bd9Sstevel@tonic-gate 	    }
27097c478bd9Sstevel@tonic-gate 	}
27107c478bd9Sstevel@tonic-gate 	return (num_regs);
27117c478bd9Sstevel@tonic-gate }
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate /*
27147c478bd9Sstevel@tonic-gate  *
27157c478bd9Sstevel@tonic-gate  */
27167c478bd9Sstevel@tonic-gate static int
27177c478bd9Sstevel@tonic-gate pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info,
27187c478bd9Sstevel@tonic-gate 		    int pctype)
27197c478bd9Sstevel@tonic-gate {
27207c478bd9Sstevel@tonic-gate 	int num_regs = 0;
27217c478bd9Sstevel@tonic-gate 	tuple_t tuple;
27227c478bd9Sstevel@tonic-gate 	uint32_t curr_base;
27237c478bd9Sstevel@tonic-gate 	int len, curr, i, curr_len;
27247c478bd9Sstevel@tonic-gate 	cistpl_config_t config;
27257c478bd9Sstevel@tonic-gate 	cistpl_cftable_entry_t cftable;
27267c478bd9Sstevel@tonic-gate 	struct pcm_regs tmp[16];
27277c478bd9Sstevel@tonic-gate 	int found = 0;
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 	bzero(&tuple, sizeof (tuple));
27307c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_CONFIG;
27317c478bd9Sstevel@tonic-gate 	tuple.Socket = info->pd_socket;
27327c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
27337c478bd9Sstevel@tonic-gate 	curr_base = 0;
27347c478bd9Sstevel@tonic-gate 	len = 0;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) {
27377c478bd9Sstevel@tonic-gate 	    if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
27387c478bd9Sstevel@tonic-gate 					&tuple, &config) != CS_SUCCESS) {
27397c478bd9Sstevel@tonic-gate 		info->pd_flags |= PCM_NO_CONFIG; /* must be memory */
27407c478bd9Sstevel@tonic-gate 		return (0);
27417c478bd9Sstevel@tonic-gate 	}
27427c478bd9Sstevel@tonic-gate 	curr = 0;
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
27457c478bd9Sstevel@tonic-gate 	tuple.Socket = info->pd_socket;
27467c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
27477c478bd9Sstevel@tonic-gate 	bzero(tmp, sizeof (tmp));
27487c478bd9Sstevel@tonic-gate 	while (csx_GetNextTuple(info->pd_handle,
27497c478bd9Sstevel@tonic-gate 				&tuple) == CS_SUCCESS) {
27507c478bd9Sstevel@tonic-gate 	    bzero(&cftable, sizeof (cftable));
27517c478bd9Sstevel@tonic-gate 	    if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
27527c478bd9Sstevel@tonic-gate 						&tuple, &cftable) ==
27537c478bd9Sstevel@tonic-gate 		CS_SUCCESS) {
27547c478bd9Sstevel@tonic-gate 		if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) {
27557c478bd9Sstevel@tonic-gate 		    /* we have an I/O entry */
27567c478bd9Sstevel@tonic-gate 		    if (cftable.io.flags &
27577c478bd9Sstevel@tonic-gate 			CISTPL_CFTABLE_TPCE_FS_IO_RANGE) {
27587c478bd9Sstevel@tonic-gate 			len = cftable.io.addr_lines;
27597c478bd9Sstevel@tonic-gate 			if (len != 0)
27607c478bd9Sstevel@tonic-gate 				len = 1 << len;
27617c478bd9Sstevel@tonic-gate 			for (i = 0; i < cftable.io.ranges && curr < 16; i++) {
27627c478bd9Sstevel@tonic-gate 			    curr_base = cftable.io.range[i].addr;
27637c478bd9Sstevel@tonic-gate 			    curr_len = cftable.io.range[i].length;
27647c478bd9Sstevel@tonic-gate 			    if (curr_len == 0)
27657c478bd9Sstevel@tonic-gate 				    curr_len = len;
27667c478bd9Sstevel@tonic-gate 			    if (len != 0 || cftable.io.addr_lines == 0) {
27677c478bd9Sstevel@tonic-gate 				/* we have potential relocation */
27687c478bd9Sstevel@tonic-gate 				int mask;
27697c478bd9Sstevel@tonic-gate 				mask = cftable.io.addr_lines ?
27707c478bd9Sstevel@tonic-gate 						cftable.io.addr_lines :
27717c478bd9Sstevel@tonic-gate 							genp2(len);
27727c478bd9Sstevel@tonic-gate 				mask = genmask(mask);
27737c478bd9Sstevel@tonic-gate 				if ((mask & curr_base) == 0) {
27747c478bd9Sstevel@tonic-gate 					/* more accurate length */
27757c478bd9Sstevel@tonic-gate 					regs->phys_len = curr_len;
27767c478bd9Sstevel@tonic-gate 					regs->phys_lo = 0;
27777c478bd9Sstevel@tonic-gate 					regs->phys_hi =
27787c478bd9Sstevel@tonic-gate 					    PC_REG_PHYS_HI(0,
27797c478bd9Sstevel@tonic-gate 						0,
27807c478bd9Sstevel@tonic-gate 						pctype,
27817c478bd9Sstevel@tonic-gate 						PC_REG_SPACE_IO,
27827c478bd9Sstevel@tonic-gate 						info->pd_socket,
27837c478bd9Sstevel@tonic-gate 						info->pd_function,
27847c478bd9Sstevel@tonic-gate 						0);
27857c478bd9Sstevel@tonic-gate 					num_regs++;
27867c478bd9Sstevel@tonic-gate 					found = 2;
27877c478bd9Sstevel@tonic-gate 					break;
27887c478bd9Sstevel@tonic-gate 				}
27897c478bd9Sstevel@tonic-gate 			    }
27907c478bd9Sstevel@tonic-gate 			    tmp[curr].phys_len = curr_len;
27917c478bd9Sstevel@tonic-gate 			    tmp[curr].phys_lo = curr_base;
27927c478bd9Sstevel@tonic-gate 			    curr++;
27937c478bd9Sstevel@tonic-gate 			    found = 1;
27947c478bd9Sstevel@tonic-gate 			}
27957c478bd9Sstevel@tonic-gate 			if (found == 2)
27967c478bd9Sstevel@tonic-gate 				break;
27977c478bd9Sstevel@tonic-gate 		    } else {
27987c478bd9Sstevel@tonic-gate 			/* no I/O range so just a mask */
27997c478bd9Sstevel@tonic-gate 			regs->phys_len = 1 << cftable.io.addr_lines;
28007c478bd9Sstevel@tonic-gate 			regs->phys_hi =
28017c478bd9Sstevel@tonic-gate 				PC_REG_PHYS_HI(0,
28027c478bd9Sstevel@tonic-gate 						0,
28037c478bd9Sstevel@tonic-gate 						pctype,
28047c478bd9Sstevel@tonic-gate 						PC_REG_SPACE_IO,
28057c478bd9Sstevel@tonic-gate 						info->pd_socket,
28067c478bd9Sstevel@tonic-gate 						info->pd_function,
28077c478bd9Sstevel@tonic-gate 						0);
28087c478bd9Sstevel@tonic-gate 			regs->phys_lo = 0;
28097c478bd9Sstevel@tonic-gate 			num_regs++;
28107c478bd9Sstevel@tonic-gate 			regs++;
28117c478bd9Sstevel@tonic-gate 			/* quit on "good" entry */
28127c478bd9Sstevel@tonic-gate 			break;
28137c478bd9Sstevel@tonic-gate 		    }
28147c478bd9Sstevel@tonic-gate 		    /* was this the last CFTABLE Entry? */
28157c478bd9Sstevel@tonic-gate 		    if (config.last == cftable.index)
28167c478bd9Sstevel@tonic-gate 			    break;
28177c478bd9Sstevel@tonic-gate 		}
28187c478bd9Sstevel@tonic-gate 	    }
28197c478bd9Sstevel@tonic-gate 	}
28207c478bd9Sstevel@tonic-gate 	if (found == 1) {
28217c478bd9Sstevel@tonic-gate 		/*
28227c478bd9Sstevel@tonic-gate 		 * have some non-relocatable values
28237c478bd9Sstevel@tonic-gate 		 * so we include them all for now
28247c478bd9Sstevel@tonic-gate 		 */
28257c478bd9Sstevel@tonic-gate 		for (i = 0; i < curr && num_regs < 8; i++) {
28267c478bd9Sstevel@tonic-gate 		    regs->phys_len = tmp[i].phys_len;
28277c478bd9Sstevel@tonic-gate 		    regs->phys_lo = tmp[i].phys_lo;
28287c478bd9Sstevel@tonic-gate 		    regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype,
28297c478bd9Sstevel@tonic-gate 			    PC_REG_SPACE_IO, info->pd_socket,
28307c478bd9Sstevel@tonic-gate 			    info->pd_function, 0);
28317c478bd9Sstevel@tonic-gate 		    regs++;
28327c478bd9Sstevel@tonic-gate 		    num_regs++;
28337c478bd9Sstevel@tonic-gate 		}
28347c478bd9Sstevel@tonic-gate 	    }
28357c478bd9Sstevel@tonic-gate 	}
28367c478bd9Sstevel@tonic-gate 	return (num_regs);
28377c478bd9Sstevel@tonic-gate }
28387c478bd9Sstevel@tonic-gate 
28397c478bd9Sstevel@tonic-gate /*
28407c478bd9Sstevel@tonic-gate  * pcmcia_create_regs()
28417c478bd9Sstevel@tonic-gate  *	create a valid set of regspecs for the card
28427c478bd9Sstevel@tonic-gate  *	The first one is always for CIS access and naming
28437c478bd9Sstevel@tonic-gate  */
28447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28457c478bd9Sstevel@tonic-gate static void
28467c478bd9Sstevel@tonic-gate pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info,
28477c478bd9Sstevel@tonic-gate 			struct pcmcia_parent_private *ppd)
28487c478bd9Sstevel@tonic-gate {
28497c478bd9Sstevel@tonic-gate 	struct pcm_regs regs[32]; /* assume worst case */
28507c478bd9Sstevel@tonic-gate 	int num_regs = 0;
28517c478bd9Sstevel@tonic-gate 	int len;
28527c478bd9Sstevel@tonic-gate 	int bustype;
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	if (ppd->ppd_flags & PPD_CARD_CARDBUS) {
28557c478bd9Sstevel@tonic-gate 		/* always have a CIS map */
28567c478bd9Sstevel@tonic-gate 		regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS,
28577c478bd9Sstevel@tonic-gate 						PC_REG_SPACE_CONFIG,
28587c478bd9Sstevel@tonic-gate 						info->pd_socket,
28597c478bd9Sstevel@tonic-gate 						info->pd_function, 0);
28607c478bd9Sstevel@tonic-gate 		bustype = PC_REG_TYPE_CARDBUS;
28617c478bd9Sstevel@tonic-gate 	} else {
28627c478bd9Sstevel@tonic-gate 		/* always have a CIS map */
28637c478bd9Sstevel@tonic-gate 		regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
28647c478bd9Sstevel@tonic-gate 						PC_REG_SPACE_ATTRIBUTE,
28657c478bd9Sstevel@tonic-gate 						info->pd_socket,
28667c478bd9Sstevel@tonic-gate 						info->pd_function, 0);
28677c478bd9Sstevel@tonic-gate 		bustype = PC_REG_TYPE_16BIT;
28687c478bd9Sstevel@tonic-gate 	}
28697c478bd9Sstevel@tonic-gate 	regs[0].phys_lo = 0;	/* always starts at zero */
28707c478bd9Sstevel@tonic-gate 	regs[0].phys_len = 0;
28717c478bd9Sstevel@tonic-gate 	num_regs++;
28727c478bd9Sstevel@tonic-gate 	/*
28737c478bd9Sstevel@tonic-gate 	 * need to search CIS for other memory instances
28747c478bd9Sstevel@tonic-gate 	 */
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 	if (info->pd_flags & PCM_OTHER_NOCIS) {
28777c478bd9Sstevel@tonic-gate 		/* special case of memory only card without CIS */
28787c478bd9Sstevel@tonic-gate 		regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
28797c478bd9Sstevel@tonic-gate 						PC_REG_SPACE_MEMORY,
28807c478bd9Sstevel@tonic-gate 						info->pd_socket,
28817c478bd9Sstevel@tonic-gate 						info->pd_function, 0);
28827c478bd9Sstevel@tonic-gate 		regs[1].phys_lo = 0;
28837c478bd9Sstevel@tonic-gate 		regs[1].phys_len = PCM_MAX_R2_MEM;
28847c478bd9Sstevel@tonic-gate 		num_regs++;
28857c478bd9Sstevel@tonic-gate 	} else {
28867c478bd9Sstevel@tonic-gate 		/*
28877c478bd9Sstevel@tonic-gate 		 * want to get any other memory and/or I/O regions
28887c478bd9Sstevel@tonic-gate 		 * on the card and represent them here.
28897c478bd9Sstevel@tonic-gate 		 */
28907c478bd9Sstevel@tonic-gate 		num_regs += pcmcia_get_mem_regs(&regs[num_regs], info,
28917c478bd9Sstevel@tonic-gate 						CISTPL_DEVICE_A, bustype);
28927c478bd9Sstevel@tonic-gate 		num_regs += pcmcia_get_mem_regs(&regs[num_regs], info,
28937c478bd9Sstevel@tonic-gate 						CISTPL_DEVICE, bustype);
28947c478bd9Sstevel@tonic-gate 
28957c478bd9Sstevel@tonic-gate 		/* now look for an I/O space to configure */
28967c478bd9Sstevel@tonic-gate 		num_regs += pcmcia_get_io_regs(&regs[num_regs], info,
28977c478bd9Sstevel@tonic-gate 						bustype);
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	}
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	len = num_regs * sizeof (uint32_t) * 3;
29027c478bd9Sstevel@tonic-gate 	ppd->ppd_nreg = num_regs;
29037c478bd9Sstevel@tonic-gate 	ppd->ppd_reg = kmem_alloc(len, KM_SLEEP);
29047c478bd9Sstevel@tonic-gate 	bcopy(regs, ppd->ppd_reg, len);
29057c478bd9Sstevel@tonic-gate 	len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
29067c478bd9Sstevel@tonic-gate 	ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP);
29077c478bd9Sstevel@tonic-gate }
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate /*
29117c478bd9Sstevel@tonic-gate  * pcmcia_need_intr()
29127c478bd9Sstevel@tonic-gate  *	check to see if an interrupt tuple exists.
29137c478bd9Sstevel@tonic-gate  *	existence means we need one in the intrspec.
29147c478bd9Sstevel@tonic-gate  */
29157c478bd9Sstevel@tonic-gate static int
29167c478bd9Sstevel@tonic-gate pcmcia_need_intr(int socket, struct pcm_device_info *info)
29177c478bd9Sstevel@tonic-gate {
29187c478bd9Sstevel@tonic-gate 	cistpl_config_t config;
29197c478bd9Sstevel@tonic-gate 	cistpl_cftable_entry_t cftable;
29207c478bd9Sstevel@tonic-gate 	tuple_t tuple;
29217c478bd9Sstevel@tonic-gate 	int i;
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 	bzero(&tuple, sizeof (tuple));
29247c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_CONFIG;
29257c478bd9Sstevel@tonic-gate 	tuple.Socket = socket;
29267c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
29277c478bd9Sstevel@tonic-gate 	if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) {
29287c478bd9Sstevel@tonic-gate 		return (0);
29297c478bd9Sstevel@tonic-gate 	}
29307c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
29317c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
29327c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n");
29337c478bd9Sstevel@tonic-gate 	}
29347c478bd9Sstevel@tonic-gate #endif
29357c478bd9Sstevel@tonic-gate 	bzero(&config, sizeof (config));
29367c478bd9Sstevel@tonic-gate 	if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
29377c478bd9Sstevel@tonic-gate 	    &tuple, &config) != CS_SUCCESS) {
29387c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pcmcia: config failed to parse\n");
29397c478bd9Sstevel@tonic-gate 		return (0);
29407c478bd9Sstevel@tonic-gate 	}
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	for (cftable.index = (int)-1, i = -1;
29437c478bd9Sstevel@tonic-gate 		i != config.last; i = cftable.index) {
29447c478bd9Sstevel@tonic-gate 		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
29457c478bd9Sstevel@tonic-gate 		tuple.Attributes = 0;
29467c478bd9Sstevel@tonic-gate 		if (csx_GetNextTuple(info->pd_handle,
29477c478bd9Sstevel@tonic-gate 		    &tuple) != CS_SUCCESS) {
29487c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pcmcia: get cftable failed\n");
29497c478bd9Sstevel@tonic-gate 			break;
29507c478bd9Sstevel@tonic-gate 		}
29517c478bd9Sstevel@tonic-gate 		bzero(&cftable, sizeof (cftable));
29527c478bd9Sstevel@tonic-gate 		if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
29537c478bd9Sstevel@tonic-gate 		    &tuple, &cftable) !=
29547c478bd9Sstevel@tonic-gate 		    CS_SUCCESS) {
29557c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pcmcia: parse cftable failed\n");
29567c478bd9Sstevel@tonic-gate 			break;
29577c478bd9Sstevel@tonic-gate 		}
29587c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
29597c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
29607c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n",
29617c478bd9Sstevel@tonic-gate 				i, cftable.flags,
29627c478bd9Sstevel@tonic-gate 				cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ);
29637c478bd9Sstevel@tonic-gate #endif
29647c478bd9Sstevel@tonic-gate 		if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ)
29657c478bd9Sstevel@tonic-gate 			return (1);
29667c478bd9Sstevel@tonic-gate 	}
29677c478bd9Sstevel@tonic-gate 	return (0);
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate }
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate /*
29727c478bd9Sstevel@tonic-gate  * pcmcia_num_funcs()
29737c478bd9Sstevel@tonic-gate  *	look for a CISTPL_LONGLINK_MFC
29747c478bd9Sstevel@tonic-gate  *	if there is one, return the number of functions
29757c478bd9Sstevel@tonic-gate  *	if there isn't one, then there is one function
29767c478bd9Sstevel@tonic-gate  */
29777c478bd9Sstevel@tonic-gate static int
29787c478bd9Sstevel@tonic-gate pcmcia_num_funcs(int socket, client_handle_t handle)
29797c478bd9Sstevel@tonic-gate {
29807c478bd9Sstevel@tonic-gate 	int count = 1;
29817c478bd9Sstevel@tonic-gate 	cistpl_longlink_mfc_t mfc;
29827c478bd9Sstevel@tonic-gate 	tuple_t tuple;
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate 	bzero(&tuple, sizeof (tuple_t));
29857c478bd9Sstevel@tonic-gate 	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
29867c478bd9Sstevel@tonic-gate 	tuple.Socket = socket;
29877c478bd9Sstevel@tonic-gate 	tuple.Attributes = 0;
29887c478bd9Sstevel@tonic-gate 	if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) {
29897c478bd9Sstevel@tonic-gate 		/* this is a multifunction card */
29907c478bd9Sstevel@tonic-gate 		if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc,
29917c478bd9Sstevel@tonic-gate 		    CISTPL_LONGLINK_MFC) == CS_SUCCESS) {
29927c478bd9Sstevel@tonic-gate 			count = mfc.nfuncs;
29937c478bd9Sstevel@tonic-gate 		}
29947c478bd9Sstevel@tonic-gate 	}
29957c478bd9Sstevel@tonic-gate 	return (count);
29967c478bd9Sstevel@tonic-gate }
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate client_handle_t pcmcia_cs_handle;
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate /*
30017c478bd9Sstevel@tonic-gate  * pcmcia_create_dev_info(socket)
30027c478bd9Sstevel@tonic-gate  *	either find or create the device information structure
30037c478bd9Sstevel@tonic-gate  *	for the card(s) just inserted.	We don't care about removal yet.
30047c478bd9Sstevel@tonic-gate  *	In any case, we will only do this at CS request
30057c478bd9Sstevel@tonic-gate  */
30067c478bd9Sstevel@tonic-gate static void
30077c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(int socket)
30087c478bd9Sstevel@tonic-gate {
30097c478bd9Sstevel@tonic-gate 	struct pcm_device_info card_info;
30107c478bd9Sstevel@tonic-gate 	client_reg_t reg;
30117c478bd9Sstevel@tonic-gate 	cisinfo_t cisinfo;
30127c478bd9Sstevel@tonic-gate 	int i;
30137c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
30147c478bd9Sstevel@tonic-gate 	static int handle_def = 0;
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
30177c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
30187c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n",
30197c478bd9Sstevel@tonic-gate 			socket);
30207c478bd9Sstevel@tonic-gate #endif
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate 	/*
30237c478bd9Sstevel@tonic-gate 	 * before we can do anything else, we need the parent
30247c478bd9Sstevel@tonic-gate 	 * devinfo of the socket.  This gets things in the right
30257c478bd9Sstevel@tonic-gate 	 * place in the device tree.
30267c478bd9Sstevel@tonic-gate 	 */
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	pdip = pcm_find_parent_dip(socket);
30297c478bd9Sstevel@tonic-gate 	if (pdip == NULL)
30307c478bd9Sstevel@tonic-gate 		return;
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate 	/* Card Services calls needed to get CIS info */
30337c478bd9Sstevel@tonic-gate 	reg.dip = NULL;
30347c478bd9Sstevel@tonic-gate 	reg.Attributes = INFO_SOCKET_SERVICES;
30357c478bd9Sstevel@tonic-gate 	reg.EventMask = 0;
30367c478bd9Sstevel@tonic-gate 	reg.event_handler = NULL;
30377c478bd9Sstevel@tonic-gate 	reg.Version = CS_VERSION;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	bzero(&card_info, sizeof (card_info));
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	if (handle_def == 0) {
30427c478bd9Sstevel@tonic-gate 		if (csx_RegisterClient(&pcmcia_cs_handle,
30437c478bd9Sstevel@tonic-gate 		    &reg) != CS_SUCCESS) {
30447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
30457c478bd9Sstevel@tonic-gate 			if (pcmcia_debug)
30467c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
30477c478bd9Sstevel@tonic-gate 					"pcmcia: RegisterClient failed\n");
30487c478bd9Sstevel@tonic-gate #endif
30497c478bd9Sstevel@tonic-gate 			return;
30507c478bd9Sstevel@tonic-gate 		}
30517c478bd9Sstevel@tonic-gate 		handle_def++;
30527c478bd9Sstevel@tonic-gate 	}
30537c478bd9Sstevel@tonic-gate 	card_info.pd_handle = pcmcia_cs_handle;
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
30567c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
30577c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
30587c478bd9Sstevel@tonic-gate 			"pcmcia_create_dev_info: handle = %x\n",
30597c478bd9Sstevel@tonic-gate 			(int)card_info.pd_handle);
30607c478bd9Sstevel@tonic-gate #endif
30617c478bd9Sstevel@tonic-gate 	card_info.pd_type = -1; /* no type to start */
30627c478bd9Sstevel@tonic-gate 	card_info.pd_socket = socket;
30637c478bd9Sstevel@tonic-gate 	card_info.pd_function = 0;
30647c478bd9Sstevel@tonic-gate 	pcmcia_sockets[socket]->ls_functions = 1; /* default */
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 	cisinfo.Socket = socket;
30677c478bd9Sstevel@tonic-gate 
30687c478bd9Sstevel@tonic-gate 	if ((i = csx_ValidateCIS(card_info.pd_handle,
30697c478bd9Sstevel@tonic-gate 	    &cisinfo)) != SUCCESS ||
30707c478bd9Sstevel@tonic-gate 	    cisinfo.Tuples == 0) {
30717c478bd9Sstevel@tonic-gate 		/* no CIS means memory */
30727c478bd9Sstevel@tonic-gate 		(void) strcpy(card_info.pd_generic_name, "memory");
30737c478bd9Sstevel@tonic-gate 		card_info.pd_flags |= PCM_NAME_GENERIC |
30747c478bd9Sstevel@tonic-gate 			PCM_OTHER_NOCIS | PCM_NAME_1275;
30757c478bd9Sstevel@tonic-gate 		(void) strcpy(card_info.pd_bind_name, "pccard,memory");
30767c478bd9Sstevel@tonic-gate 		(void) strcpy(card_info.pd_generic_name, "memory");
30777c478bd9Sstevel@tonic-gate 		card_info.pd_type = PCM_TYPE_MEMORY;
30787c478bd9Sstevel@tonic-gate 	} else {
30797c478bd9Sstevel@tonic-gate 		int functions, lsocket;
30807c478bd9Sstevel@tonic-gate 		card_info.pd_tuples = cisinfo.Tuples;
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 		/*
30837c478bd9Sstevel@tonic-gate 		 * how many functions on the card?
30847c478bd9Sstevel@tonic-gate 		 * we need to know and then we do one
30857c478bd9Sstevel@tonic-gate 		 * child node for each function using
30867c478bd9Sstevel@tonic-gate 		 * the function specific tuples.
30877c478bd9Sstevel@tonic-gate 		 */
30887c478bd9Sstevel@tonic-gate 		lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS);
30897c478bd9Sstevel@tonic-gate 		functions = pcmcia_num_funcs(lsocket,
30907c478bd9Sstevel@tonic-gate 		    card_info.pd_handle);
30917c478bd9Sstevel@tonic-gate 		pcmcia_sockets[socket]->ls_functions = functions;
30927c478bd9Sstevel@tonic-gate 		if (functions > 1) {
30937c478bd9Sstevel@tonic-gate 			card_info.pd_flags |= PCM_MULTI_FUNCTION;
30947c478bd9Sstevel@tonic-gate 		}
30957c478bd9Sstevel@tonic-gate 		for (i = 0; i < functions; i++) {
30967c478bd9Sstevel@tonic-gate 		    register int flags;
30977c478bd9Sstevel@tonic-gate 		    lsocket = CS_MAKE_SOCKET_NUMBER(socket, i);
30987c478bd9Sstevel@tonic-gate 		    card_info.pd_socket = socket;
30997c478bd9Sstevel@tonic-gate 		    card_info.pd_function = i;
31007c478bd9Sstevel@tonic-gate 			/*
31017c478bd9Sstevel@tonic-gate 			 * new name construction
31027c478bd9Sstevel@tonic-gate 			 */
31037c478bd9Sstevel@tonic-gate 		    if (functions != 1) {
31047c478bd9Sstevel@tonic-gate 			    /* need per function handle */
31057c478bd9Sstevel@tonic-gate 			    card_info.pd_function = i;
31067c478bd9Sstevel@tonic-gate 			    /* get new handle */
31077c478bd9Sstevel@tonic-gate 		    }
31087c478bd9Sstevel@tonic-gate 		    pcmcia_1275_name(lsocket, &card_info,
31097c478bd9Sstevel@tonic-gate 			card_info.pd_handle);
31107c478bd9Sstevel@tonic-gate 		    pcmcia_vers1_name(lsocket, &card_info,
31117c478bd9Sstevel@tonic-gate 			card_info.pd_handle);
31127c478bd9Sstevel@tonic-gate 		    pcmcia_generic_name(lsocket, &card_info,
31137c478bd9Sstevel@tonic-gate 			card_info.pd_handle);
31147c478bd9Sstevel@tonic-gate 		    flags = card_info.pd_flags;
31157c478bd9Sstevel@tonic-gate 		    if (!(flags & PCM_NAME_1275)) {
31167c478bd9Sstevel@tonic-gate 			if (flags & PCM_NAME_VERS1) {
31177c478bd9Sstevel@tonic-gate 			    (void) strcpy(card_info.pd_bind_name,
31187c478bd9Sstevel@tonic-gate 				PCMDEV_NAMEPREF);
31197c478bd9Sstevel@tonic-gate 			    card_info.pd_bind_name[sizeof (PCMDEV_NAMEPREF)] =
31207c478bd9Sstevel@tonic-gate 				',';
31217c478bd9Sstevel@tonic-gate 			    (void) strncpy(card_info.pd_bind_name +
31227c478bd9Sstevel@tonic-gate 				sizeof (PCMDEV_NAMEPREF),
31237c478bd9Sstevel@tonic-gate 				card_info.pd_vers1_name,
31247c478bd9Sstevel@tonic-gate 				MODMAXNAMELEN -
31257c478bd9Sstevel@tonic-gate 				sizeof (PCMDEV_NAMEPREF));
31267c478bd9Sstevel@tonic-gate 			    pcmcia_fix_string(card_info.pd_bind_name);
31277c478bd9Sstevel@tonic-gate 			} else {
31287c478bd9Sstevel@tonic-gate 				/*
31297c478bd9Sstevel@tonic-gate 				 * have a CIS but not the right info
31307c478bd9Sstevel@tonic-gate 				 * so treat as generic "pccard"
31317c478bd9Sstevel@tonic-gate 				 */
31327c478bd9Sstevel@tonic-gate 				(void) strcpy(card_info.pd_generic_name,
31337c478bd9Sstevel@tonic-gate 					"pccard,memory");
31347c478bd9Sstevel@tonic-gate 				card_info.pd_flags |= PCM_NAME_GENERIC;
31357c478bd9Sstevel@tonic-gate 				(void) strcpy(card_info.pd_bind_name,
31367c478bd9Sstevel@tonic-gate 					"pccard,memory");
31377c478bd9Sstevel@tonic-gate 			}
31387c478bd9Sstevel@tonic-gate 		    }
31397c478bd9Sstevel@tonic-gate 		    pcmcia_init_devinfo(pdip, &card_info);
31407c478bd9Sstevel@tonic-gate 		}
31417c478bd9Sstevel@tonic-gate 		return;
31427c478bd9Sstevel@tonic-gate 	}
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate 	pcmcia_init_devinfo(pdip, &card_info);
31457c478bd9Sstevel@tonic-gate }
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate /*
31487c478bd9Sstevel@tonic-gate  * pcmcia_init_devinfo()
31497c478bd9Sstevel@tonic-gate  *	if there isn't a device info structure, create one
31507c478bd9Sstevel@tonic-gate  *	if there is, we don't do much.
31517c478bd9Sstevel@tonic-gate  *
31527c478bd9Sstevel@tonic-gate  *	Note: this will need updating as 1275 finalizes their spec.
31537c478bd9Sstevel@tonic-gate  */
31547c478bd9Sstevel@tonic-gate static void
31557c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info)
31567c478bd9Sstevel@tonic-gate {
31577c478bd9Sstevel@tonic-gate 	int unit;
31587c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
31597c478bd9Sstevel@tonic-gate 	char *name;
31607c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
31637c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
31647c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name,
31657c478bd9Sstevel@tonic-gate 			info->pd_socket);
31667c478bd9Sstevel@tonic-gate #endif
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 	/*
31697c478bd9Sstevel@tonic-gate 	 * find out if there is already an instance of this
31707c478bd9Sstevel@tonic-gate 	 * device.  We don't want to create a new one unnecessarily
31717c478bd9Sstevel@tonic-gate 	 */
31727c478bd9Sstevel@tonic-gate 	unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function);
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate 	dip = pcm_find_devinfo(pdip, info, unit);
31757c478bd9Sstevel@tonic-gate 	if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip,
31767c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) {
31777c478bd9Sstevel@tonic-gate 		/* it already exist but isn't a .conf file */
31787c478bd9Sstevel@tonic-gate 
31797c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
31807c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
31817c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tfound existing device node (%s)\n",
31827c478bd9Sstevel@tonic-gate 				ddi_get_name(dip));
31837c478bd9Sstevel@tonic-gate #endif
31847c478bd9Sstevel@tonic-gate 		if (strlen(info->pd_vers1_name) > 0)
31857c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
31867c478bd9Sstevel@tonic-gate 			    dip, PCM_DEV_MODEL, info->pd_vers1_name);
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)
31897c478bd9Sstevel@tonic-gate 			ddi_get_parent_data(dip);
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 		pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
31927c478bd9Sstevel@tonic-gate 		    dip;
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 		ppd->ppd_active = 1;
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 		if (ndi_devi_online(dip, 0) == NDI_FAILURE) {
31977c478bd9Sstevel@tonic-gate 			pcmcia_sockets[info->pd_socket]-> \
31987c478bd9Sstevel@tonic-gate 			    ls_dip[info->pd_function] = NULL;
31997c478bd9Sstevel@tonic-gate 			ppd->ppd_active = 0;
32007c478bd9Sstevel@tonic-gate 		}
32017c478bd9Sstevel@tonic-gate 	} else {
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 		char *dtype;
32047c478bd9Sstevel@tonic-gate 
32057c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
32067c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
32077c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n",
32087c478bd9Sstevel@tonic-gate 			    info->pd_bind_name, info->pd_socket,
32097c478bd9Sstevel@tonic-gate 			    info->pd_generic_name);
32107c478bd9Sstevel@tonic-gate #endif
32117c478bd9Sstevel@tonic-gate 
32127c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_NAME_GENERIC)
32137c478bd9Sstevel@tonic-gate 			name = info->pd_generic_name;
32147c478bd9Sstevel@tonic-gate 		else
32157c478bd9Sstevel@tonic-gate 			name = info->pd_bind_name;
32167c478bd9Sstevel@tonic-gate 
3217fa9e4066Sahrens 		if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID,
32187c478bd9Sstevel@tonic-gate 		    &dip) !=
32197c478bd9Sstevel@tonic-gate 		    NDI_SUCCESS) {
32207c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
32217c478bd9Sstevel@tonic-gate 			    "pcmcia: unable to create device [%s](%d)\n",
32227c478bd9Sstevel@tonic-gate 			    name, info->pd_socket);
32237c478bd9Sstevel@tonic-gate 			return;
32247c478bd9Sstevel@tonic-gate 		}
32257c478bd9Sstevel@tonic-gate 		/*
32267c478bd9Sstevel@tonic-gate 		 * construct the "compatible" property if the device
32277c478bd9Sstevel@tonic-gate 		 * has a generic name
32287c478bd9Sstevel@tonic-gate 		 */
32297c478bd9Sstevel@tonic-gate 		pcmcia_add_compatible(dip, info);
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 		ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
32327c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 		ppd->ppd_socket = info->pd_socket;
32357c478bd9Sstevel@tonic-gate 		ppd->ppd_function = info->pd_function;
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 		/*
32387c478bd9Sstevel@tonic-gate 		 * add the "socket" property
32397c478bd9Sstevel@tonic-gate 		 * the value of this property contains the logical PCMCIA
32407c478bd9Sstevel@tonic-gate 		 * socket number the device has been inserted in, along
32417c478bd9Sstevel@tonic-gate 		 * with the function # if the device is part of a
32427c478bd9Sstevel@tonic-gate 		 * multi-function device.
32437c478bd9Sstevel@tonic-gate 		 */
32447c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
32457c478bd9Sstevel@tonic-gate 		    PCM_DEV_SOCKET, unit);
32467c478bd9Sstevel@tonic-gate 
32477c478bd9Sstevel@tonic-gate 		if (info->pd_flags & PCM_MULTI_FUNCTION)
32487c478bd9Sstevel@tonic-gate 			ppd->ppd_flags |= PPD_CARD_MULTI;
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 		/*
32517c478bd9Sstevel@tonic-gate 		 * determine all the properties we need for PPD
32527c478bd9Sstevel@tonic-gate 		 * then create the properties
32537c478bd9Sstevel@tonic-gate 		 */
32547c478bd9Sstevel@tonic-gate 		/* socket is unique */
32557c478bd9Sstevel@tonic-gate 		pcmcia_find_regs(dip, info, ppd);
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 		ppd->ppd_intr = pcmcia_need_intr(unit, info);
32587c478bd9Sstevel@tonic-gate 
32597c478bd9Sstevel@tonic-gate 		if (ppd->ppd_nreg > 0)
32607c478bd9Sstevel@tonic-gate 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
32617c478bd9Sstevel@tonic-gate 			    "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg *
32627c478bd9Sstevel@tonic-gate 			    sizeof (struct pcm_regs) / sizeof (int));
32637c478bd9Sstevel@tonic-gate 		if (ppd->ppd_intr) {
32647c478bd9Sstevel@tonic-gate 			(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
32657c478bd9Sstevel@tonic-gate 			    "interrupts", ppd->ppd_intr);
32667c478bd9Sstevel@tonic-gate 			ppd->ppd_intrspec =
32677c478bd9Sstevel@tonic-gate 			    kmem_zalloc(sizeof (struct intrspec), KM_SLEEP);
32687c478bd9Sstevel@tonic-gate 		}
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 		/* set parent private - our own format */
32717c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(dip, (caddr_t)ppd);
32727c478bd9Sstevel@tonic-gate 
32737c478bd9Sstevel@tonic-gate 		/* init the device type */
32747c478bd9Sstevel@tonic-gate 		if (info->pd_type >= 0 &&
32757c478bd9Sstevel@tonic-gate 		    info->pd_type < (sizeof (pcmcia_dev_type) /
32767c478bd9Sstevel@tonic-gate 		    (sizeof (char *))))
32777c478bd9Sstevel@tonic-gate 			dtype = pcmcia_dev_type[info->pd_type];
32787c478bd9Sstevel@tonic-gate 		else
32797c478bd9Sstevel@tonic-gate 			dtype = "unknown";
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 		if (strlen(info->pd_vers1_name) > 0)
32827c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
32837c478bd9Sstevel@tonic-gate 			    dip, PCM_DEV_MODEL, info->pd_vers1_name);
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
32867c478bd9Sstevel@tonic-gate 		    PCM_DEVICETYPE, dtype);
32877c478bd9Sstevel@tonic-gate 
32887c478bd9Sstevel@tonic-gate 		/* set PC Card as active and present in socket */
32897c478bd9Sstevel@tonic-gate 		pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
32907c478bd9Sstevel@tonic-gate 			dip;
32917c478bd9Sstevel@tonic-gate 
32927c478bd9Sstevel@tonic-gate 		ppd->ppd_active = 1;
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate 		/*
32957c478bd9Sstevel@tonic-gate 		 * We should not call ndi_devi_online here if
32967c478bd9Sstevel@tonic-gate 		 * pcmcia attach is in progress. This causes a deadlock.
32977c478bd9Sstevel@tonic-gate 		 */
32987c478bd9Sstevel@tonic-gate 		if (pcmcia_dip != dip) {
32997c478bd9Sstevel@tonic-gate 			if (ndi_devi_online_async(dip, 0)
33007c478bd9Sstevel@tonic-gate 			    != NDI_SUCCESS) {
33017c478bd9Sstevel@tonic-gate 				pcmcia_sockets[info->pd_socket]->\
33027c478bd9Sstevel@tonic-gate 				ls_dip[info->pd_function] = NULL;
33037c478bd9Sstevel@tonic-gate 				pcmcia_ppd_free(ppd);
33047c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(dip);
33057c478bd9Sstevel@tonic-gate 				return;
33067c478bd9Sstevel@tonic-gate 			}
33077c478bd9Sstevel@tonic-gate 		}
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
33107c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
33117c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n",
33127c478bd9Sstevel@tonic-gate 			ddi_get_name(dip), info->pd_socket);
33137c478bd9Sstevel@tonic-gate #endif
33147c478bd9Sstevel@tonic-gate 	}
33157c478bd9Sstevel@tonic-gate 
33167c478bd9Sstevel@tonic-gate 	/*
33177c478bd9Sstevel@tonic-gate 	 * inform the event manager that a child was added
33187c478bd9Sstevel@tonic-gate 	 * to the device tree.
33197c478bd9Sstevel@tonic-gate 	 */
33207c478bd9Sstevel@tonic-gate 	pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip));
33217c478bd9Sstevel@tonic-gate 
33227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
33237c478bd9Sstevel@tonic-gate 	if (pcmcia_debug > 1) {
33247c478bd9Sstevel@tonic-gate 		pcmcia_dump_minors(dip);
33257c478bd9Sstevel@tonic-gate 	}
33267c478bd9Sstevel@tonic-gate #endif
33277c478bd9Sstevel@tonic-gate }
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate /*
33307c478bd9Sstevel@tonic-gate  * free any allocated parent-private data
33317c478bd9Sstevel@tonic-gate  */
33327c478bd9Sstevel@tonic-gate static void
33337c478bd9Sstevel@tonic-gate pcmcia_ppd_free(struct pcmcia_parent_private *ppd)
33347c478bd9Sstevel@tonic-gate {
33357c478bd9Sstevel@tonic-gate 	size_t len;
33367c478bd9Sstevel@tonic-gate 
33377c478bd9Sstevel@tonic-gate 	if (ppd->ppd_nreg != 0) {
33387c478bd9Sstevel@tonic-gate 		len = ppd->ppd_nreg * sizeof (uint32_t) * 3;
33397c478bd9Sstevel@tonic-gate 		kmem_free(ppd->ppd_reg, len);
33407c478bd9Sstevel@tonic-gate 		len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
33417c478bd9Sstevel@tonic-gate 		kmem_free(ppd->ppd_assigned, len);
33427c478bd9Sstevel@tonic-gate 	}
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	/*
33457c478bd9Sstevel@tonic-gate 	 * pcmcia only allocates 1 intrspec today
33467c478bd9Sstevel@tonic-gate 	 */
33477c478bd9Sstevel@tonic-gate 	if (ppd->ppd_intr != 0) {
33487c478bd9Sstevel@tonic-gate 		len = sizeof (struct intrspec) * ppd->ppd_intr;
33497c478bd9Sstevel@tonic-gate 		kmem_free(ppd->ppd_intrspec, len);
33507c478bd9Sstevel@tonic-gate 	}
33517c478bd9Sstevel@tonic-gate 
33527c478bd9Sstevel@tonic-gate 	kmem_free(ppd, sizeof (*ppd));
33537c478bd9Sstevel@tonic-gate }
33547c478bd9Sstevel@tonic-gate 
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate /*
33577c478bd9Sstevel@tonic-gate  * pcmcia_get_devinfo(socket)
33587c478bd9Sstevel@tonic-gate  *	entry point to allow finding the device info structure
33597c478bd9Sstevel@tonic-gate  *	for a given logical socket.  Used by event manager
33607c478bd9Sstevel@tonic-gate  */
33617c478bd9Sstevel@tonic-gate dev_info_t *
33627c478bd9Sstevel@tonic-gate pcmcia_get_devinfo(int socket)
33637c478bd9Sstevel@tonic-gate {
33647c478bd9Sstevel@tonic-gate 	int func = CS_GET_FUNCTION_NUMBER(socket);
33657c478bd9Sstevel@tonic-gate 	socket = CS_GET_SOCKET_NUMBER(socket);
33667c478bd9Sstevel@tonic-gate 	if (pcmcia_sockets[socket])
33677c478bd9Sstevel@tonic-gate 		return (pcmcia_sockets[socket]->ls_dip[func]);
33687c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)NULL);
33697c478bd9Sstevel@tonic-gate }
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate /*
33727c478bd9Sstevel@tonic-gate  * CSGetCookiesAndDip()
33737c478bd9Sstevel@tonic-gate  *	get info needed by CS to setup soft interrupt handler and provide
33747c478bd9Sstevel@tonic-gate  *		socket-specific adapter information
33757c478bd9Sstevel@tonic-gate  */
33767c478bd9Sstevel@tonic-gate static int
33777c478bd9Sstevel@tonic-gate GetCookiesAndDip(sservice_t *serv)
33787c478bd9Sstevel@tonic-gate {
33797c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *socket;
33807c478bd9Sstevel@tonic-gate 	csss_adapter_info_t *ai;
33817c478bd9Sstevel@tonic-gate 	int sock;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket);
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate 	if (sock >= pcmcia_num_sockets ||
33867c478bd9Sstevel@tonic-gate 	    (int)serv->get_cookies.socket < 0)
33877c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
33887c478bd9Sstevel@tonic-gate 
33897c478bd9Sstevel@tonic-gate 	socket = pcmcia_sockets[sock];
33907c478bd9Sstevel@tonic-gate 	ai = &serv->get_cookies.adapter_info;
33917c478bd9Sstevel@tonic-gate 	serv->get_cookies.dip = socket->ls_adapter->pca_dip;
33927c478bd9Sstevel@tonic-gate 	serv->get_cookies.iblock = socket->ls_adapter->pca_iblock;
33937c478bd9Sstevel@tonic-gate 	serv->get_cookies.idevice = socket->ls_adapter->pca_idev;
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate 	/*
33967c478bd9Sstevel@tonic-gate 	 * Setup the adapter info for Card Services
33977c478bd9Sstevel@tonic-gate 	 */
33987c478bd9Sstevel@tonic-gate 	(void) strcpy(ai->name, socket->ls_adapter->pca_name);
33997c478bd9Sstevel@tonic-gate 	ai->major = socket->ls_adapter->pca_module;
34007c478bd9Sstevel@tonic-gate 	ai->minor = socket->ls_adapter->pca_unit;
34017c478bd9Sstevel@tonic-gate 	ai->number = socket->ls_adapter->pca_number;
34027c478bd9Sstevel@tonic-gate 	ai->num_sockets = socket->ls_adapter->pca_numsockets;
34037c478bd9Sstevel@tonic-gate 	ai->first_socket = socket->ls_adapter->pca_first_socket;
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate 	return (SUCCESS);
34067c478bd9Sstevel@tonic-gate }
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate /*
34097c478bd9Sstevel@tonic-gate  * Note:
34107c478bd9Sstevel@tonic-gate  *	The following functions that start with 'SS'
34117c478bd9Sstevel@tonic-gate  *	implement SocketServices interfaces.  They
34127c478bd9Sstevel@tonic-gate  *	simply map the socket and/or window number to
34137c478bd9Sstevel@tonic-gate  *	the adapter specific number based on the general
34147c478bd9Sstevel@tonic-gate  *	value that CardServices uses.
34157c478bd9Sstevel@tonic-gate  *
34167c478bd9Sstevel@tonic-gate  *	See the descriptions in SocketServices for
34177c478bd9Sstevel@tonic-gate  *	details.  Also refer to specific adapter drivers
34187c478bd9Sstevel@tonic-gate  *	for implementation reference.
34197c478bd9Sstevel@tonic-gate  */
34207c478bd9Sstevel@tonic-gate 
34217c478bd9Sstevel@tonic-gate static int
34227c478bd9Sstevel@tonic-gate SSGetAdapter(get_adapter_t *adapter)
34237c478bd9Sstevel@tonic-gate {
34247c478bd9Sstevel@tonic-gate 	int n;
34257c478bd9Sstevel@tonic-gate 	get_adapter_t info;
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	adapter->state = (unsigned)0xFFFFFFFF;
34287c478bd9Sstevel@tonic-gate 	adapter->SCRouting = 0xFFFFFFFF;
34297c478bd9Sstevel@tonic-gate 
34307c478bd9Sstevel@tonic-gate 	for (n = 0; n < pcmcia_num_adapters; n++) {
34317c478bd9Sstevel@tonic-gate 		GET_ADAPTER(pcmcia_adapters[n]->pca_if,
34327c478bd9Sstevel@tonic-gate 			pcmcia_adapters[n]->pca_dip, &info);
34337c478bd9Sstevel@tonic-gate 		adapter->state &= info.state;
34347c478bd9Sstevel@tonic-gate 		adapter->SCRouting &= info.SCRouting;
34357c478bd9Sstevel@tonic-gate 	}
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	return (SUCCESS);
34387c478bd9Sstevel@tonic-gate }
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate static int
34417c478bd9Sstevel@tonic-gate SSGetPage(get_page_t *page)
34427c478bd9Sstevel@tonic-gate {
34437c478bd9Sstevel@tonic-gate 	pcmcia_logical_window_t *window;
34447c478bd9Sstevel@tonic-gate 	get_page_t newpage;
34457c478bd9Sstevel@tonic-gate 	int retval, win;
34467c478bd9Sstevel@tonic-gate 
34477c478bd9Sstevel@tonic-gate 	if (page->window > pcmcia_num_windows) {
34487c478bd9Sstevel@tonic-gate 		return (BAD_WINDOW);
34497c478bd9Sstevel@tonic-gate 	}
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate 	window = pcmcia_windows[page->window];
34527c478bd9Sstevel@tonic-gate 	newpage = *page;
34537c478bd9Sstevel@tonic-gate 	win = newpage.window = window->lw_window; /* real window */
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip,
34567c478bd9Sstevel@tonic-gate 		&newpage);
34577c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
34587c478bd9Sstevel@tonic-gate 		*page = newpage;
34597c478bd9Sstevel@tonic-gate 		page->window = win;
34607c478bd9Sstevel@tonic-gate 	}
34617c478bd9Sstevel@tonic-gate 	return (retval);
34627c478bd9Sstevel@tonic-gate }
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate static int
34657c478bd9Sstevel@tonic-gate SSGetSocket(get_socket_t *socket)
34667c478bd9Sstevel@tonic-gate {
34677c478bd9Sstevel@tonic-gate 	int retval, sock;
34687c478bd9Sstevel@tonic-gate 	get_socket_t newsocket;
34697c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate 	sock = socket->socket;
34727c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
34737c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL) {
34747c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
34757c478bd9Sstevel@tonic-gate 	}
34767c478bd9Sstevel@tonic-gate 
34777c478bd9Sstevel@tonic-gate 	newsocket = *socket;
34787c478bd9Sstevel@tonic-gate 	newsocket.socket = sockp->ls_socket;
34797c478bd9Sstevel@tonic-gate 	retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
34807c478bd9Sstevel@tonic-gate 	    &newsocket);
34817c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
34827c478bd9Sstevel@tonic-gate 		newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
34837c478bd9Sstevel@tonic-gate 		    newsocket.VccLevel,
34847c478bd9Sstevel@tonic-gate 		    VCC);
34857c478bd9Sstevel@tonic-gate 		newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
34867c478bd9Sstevel@tonic-gate 		    newsocket.Vpp1Level,
34877c478bd9Sstevel@tonic-gate 		    VPP1);
34887c478bd9Sstevel@tonic-gate 		newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
34897c478bd9Sstevel@tonic-gate 		    newsocket.Vpp2Level,
34907c478bd9Sstevel@tonic-gate 		    VPP2);
34917c478bd9Sstevel@tonic-gate 		*socket = newsocket;
34927c478bd9Sstevel@tonic-gate 		socket->socket = sock;
34937c478bd9Sstevel@tonic-gate 	}
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate 	return (retval);
34967c478bd9Sstevel@tonic-gate }
34977c478bd9Sstevel@tonic-gate 
34987c478bd9Sstevel@tonic-gate static int
34997c478bd9Sstevel@tonic-gate SSGetStatus(get_ss_status_t *status)
35007c478bd9Sstevel@tonic-gate {
35017c478bd9Sstevel@tonic-gate 	get_ss_status_t newstat;
35027c478bd9Sstevel@tonic-gate 	int sock, retval;
35037c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	sock = status->socket;
35067c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
35077c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL) {
35087c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
35097c478bd9Sstevel@tonic-gate 	}
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 	newstat = *status;
35127c478bd9Sstevel@tonic-gate 	newstat.socket = sockp->ls_socket;
35137c478bd9Sstevel@tonic-gate 	retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip,
35147c478bd9Sstevel@tonic-gate 	    &newstat);
35157c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
35167c478bd9Sstevel@tonic-gate 		*status = newstat;
35177c478bd9Sstevel@tonic-gate 		status->socket = sock;
35187c478bd9Sstevel@tonic-gate 	}
35197c478bd9Sstevel@tonic-gate 
35207c478bd9Sstevel@tonic-gate 	return (retval);
35217c478bd9Sstevel@tonic-gate }
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate static int
35247c478bd9Sstevel@tonic-gate SSGetWindow(get_window_t *window)
35257c478bd9Sstevel@tonic-gate {
35267c478bd9Sstevel@tonic-gate 	int win, retval;
35277c478bd9Sstevel@tonic-gate 	get_window_t newwin;
35287c478bd9Sstevel@tonic-gate 	pcmcia_logical_window_t *winp;
35297c478bd9Sstevel@tonic-gate 
35307c478bd9Sstevel@tonic-gate 	win = window->window;
35317c478bd9Sstevel@tonic-gate 	winp = pcmcia_windows[win];
35327c478bd9Sstevel@tonic-gate 	newwin = *window;
35337c478bd9Sstevel@tonic-gate 	newwin.window = winp->lw_window;
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate 	retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
35367c478bd9Sstevel@tonic-gate 	    &newwin);
35377c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
35387c478bd9Sstevel@tonic-gate 		newwin.socket = winp->lw_socket;
35397c478bd9Sstevel@tonic-gate 		newwin.window = win;
35407c478bd9Sstevel@tonic-gate 		*window = newwin;
35417c478bd9Sstevel@tonic-gate 	}
35427c478bd9Sstevel@tonic-gate 	return (retval);
35437c478bd9Sstevel@tonic-gate }
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate /*
35467c478bd9Sstevel@tonic-gate  * SSInquireAdapter()
35477c478bd9Sstevel@tonic-gate  *	Get the capabilities of the "generic" adapter
35487c478bd9Sstevel@tonic-gate  *	we are exporting to CS.
35497c478bd9Sstevel@tonic-gate  */
35507c478bd9Sstevel@tonic-gate static int
35517c478bd9Sstevel@tonic-gate SSInquireAdapter(inquire_adapter_t *adapter)
35527c478bd9Sstevel@tonic-gate {
35537c478bd9Sstevel@tonic-gate 	adapter->NumSockets = pcmcia_num_sockets;
35547c478bd9Sstevel@tonic-gate 	adapter->NumWindows = pcmcia_num_windows;
35557c478bd9Sstevel@tonic-gate 	adapter->NumEDCs = 0;
35567c478bd9Sstevel@tonic-gate 	/*
35577c478bd9Sstevel@tonic-gate 	 * notes: Adapter Capabilities are going to be difficult to
35587c478bd9Sstevel@tonic-gate 	 * determine with reliability.	Fortunately, most of them
35597c478bd9Sstevel@tonic-gate 	 * don't matter under Solaris or can be handled transparently
35607c478bd9Sstevel@tonic-gate 	 */
35617c478bd9Sstevel@tonic-gate 	adapter->AdpCaps = 0;	/* need to fix these */
35627c478bd9Sstevel@tonic-gate 	/*
35637c478bd9Sstevel@tonic-gate 	 * interrupts need a little work.  For x86, the valid IRQs will
35647c478bd9Sstevel@tonic-gate 	 * be restricted to those that the system has exported to the nexus.
35657c478bd9Sstevel@tonic-gate 	 * for SPARC, it will be the DoRight values.
35667c478bd9Sstevel@tonic-gate 	 */
35677c478bd9Sstevel@tonic-gate 	adapter->ActiveHigh = 0;
35687c478bd9Sstevel@tonic-gate 	adapter->ActiveLow = 0;
35697c478bd9Sstevel@tonic-gate 	adapter->power_entry = pcmcia_power_table; /* until we resolve this */
35707c478bd9Sstevel@tonic-gate 	adapter->NumPower = pcmcia_num_power;
35717c478bd9Sstevel@tonic-gate 	return (SUCCESS);
35727c478bd9Sstevel@tonic-gate }
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate static int
35757c478bd9Sstevel@tonic-gate SSInquireSocket(inquire_socket_t *socket)
35767c478bd9Sstevel@tonic-gate {
35777c478bd9Sstevel@tonic-gate 	int retval, sock;
35787c478bd9Sstevel@tonic-gate 	inquire_socket_t newsocket;
35797c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate 	sock = socket->socket;
35827c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
35837c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL)
35847c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
35857c478bd9Sstevel@tonic-gate 	newsocket = *socket;
35867c478bd9Sstevel@tonic-gate 	newsocket.socket = sockp->ls_socket;
35877c478bd9Sstevel@tonic-gate 	retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
35887c478bd9Sstevel@tonic-gate 	    &newsocket);
35897c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
35907c478bd9Sstevel@tonic-gate 		*socket = newsocket;
35917c478bd9Sstevel@tonic-gate 		socket->socket = sock;
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 	return (retval);
35947c478bd9Sstevel@tonic-gate }
35957c478bd9Sstevel@tonic-gate 
35967c478bd9Sstevel@tonic-gate static int
35977c478bd9Sstevel@tonic-gate SSInquireWindow(inquire_window_t *window)
35987c478bd9Sstevel@tonic-gate {
35997c478bd9Sstevel@tonic-gate 	int retval, win;
36007c478bd9Sstevel@tonic-gate 	pcmcia_logical_window_t *winp;
36017c478bd9Sstevel@tonic-gate 	inquire_window_t newwin;
36027c478bd9Sstevel@tonic-gate 	int slide;
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate 	win = window->window;
36057c478bd9Sstevel@tonic-gate 	if (win > pcmcia_num_windows)
36067c478bd9Sstevel@tonic-gate 		return (BAD_WINDOW);
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate 	winp = pcmcia_windows[win];
36097c478bd9Sstevel@tonic-gate 	newwin = *window;
36107c478bd9Sstevel@tonic-gate 	newwin.window = winp->lw_window;
36117c478bd9Sstevel@tonic-gate 	retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
36127c478bd9Sstevel@tonic-gate 	    &newwin);
36137c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
36147c478bd9Sstevel@tonic-gate 		if (pcmcia_debug > 1)
36157c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n",
36167c478bd9Sstevel@tonic-gate 				win, newwin.window);
36177c478bd9Sstevel@tonic-gate #endif
36187c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
36197c478bd9Sstevel@tonic-gate 		*window = newwin;
36207c478bd9Sstevel@tonic-gate 		/* just in case */
36217c478bd9Sstevel@tonic-gate 		window->iowin_char.IOWndCaps &= ~WC_BASE;
36227c478bd9Sstevel@tonic-gate 		slide = winp->lw_adapter->pca_first_socket;
36237c478bd9Sstevel@tonic-gate 		/*
36247c478bd9Sstevel@tonic-gate 		 * note that sockets are relative to the adapter.
36257c478bd9Sstevel@tonic-gate 		 * we have to adjust the bits to show a logical
36267c478bd9Sstevel@tonic-gate 		 * version.
36277c478bd9Sstevel@tonic-gate 		 */
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate 		pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0);
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
36327c478bd9Sstevel@tonic-gate 		if (pcmcia_debug > 1) {
36337c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n",
36347c478bd9Sstevel@tonic-gate 				(int)*(uint32_t *)newwin.Sockets,
36357c478bd9Sstevel@tonic-gate 				(int)*(uint32_t *)window->Sockets);
36367c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps,
36377c478bd9Sstevel@tonic-gate 				window->mem_win_char.MemWndCaps,
36387c478bd9Sstevel@tonic-gate 				window->mem_win_char.MinSize);
36397c478bd9Sstevel@tonic-gate 		}
36407c478bd9Sstevel@tonic-gate #endif
36417c478bd9Sstevel@tonic-gate 		window->window = win;
36427c478bd9Sstevel@tonic-gate 	}
36437c478bd9Sstevel@tonic-gate 	return (retval);
36447c478bd9Sstevel@tonic-gate }
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate static int
36477c478bd9Sstevel@tonic-gate SSResetSocket(int socket, int mode)
36487c478bd9Sstevel@tonic-gate {
36497c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate 	if (socket >= pcmcia_num_sockets ||
36527c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[socket]) == NULL)
36537c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
36567c478bd9Sstevel@tonic-gate 	    sockp->ls_socket, mode));
36577c478bd9Sstevel@tonic-gate }
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate static int
36607c478bd9Sstevel@tonic-gate SSSetPage(set_page_t *page)
36617c478bd9Sstevel@tonic-gate {
36627c478bd9Sstevel@tonic-gate 	int window, retval;
36637c478bd9Sstevel@tonic-gate 	set_page_t newpage;
36647c478bd9Sstevel@tonic-gate 	pcmcia_logical_window_t *winp;
36657c478bd9Sstevel@tonic-gate 
36667c478bd9Sstevel@tonic-gate 	window = page->window;
36677c478bd9Sstevel@tonic-gate 	if (window > pcmcia_num_windows) {
36687c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
36697c478bd9Sstevel@tonic-gate 		if (pcmcia_debug > 1)
36707c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n",
36717c478bd9Sstevel@tonic-gate 				window, pcmcia_num_windows);
36727c478bd9Sstevel@tonic-gate #endif
36737c478bd9Sstevel@tonic-gate 		return (BAD_WINDOW);
36747c478bd9Sstevel@tonic-gate 	}
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	winp = pcmcia_windows[window];
36777c478bd9Sstevel@tonic-gate 	newpage = *page;
36787c478bd9Sstevel@tonic-gate 	newpage.window = winp->lw_window;
36797c478bd9Sstevel@tonic-gate 	retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage);
36807c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
36817c478bd9Sstevel@tonic-gate 		newpage.window = window;
36827c478bd9Sstevel@tonic-gate 		*page = newpage;
36837c478bd9Sstevel@tonic-gate 	}
36847c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
36857c478bd9Sstevel@tonic-gate 	if ((pcmcia_debug > 1) && retval != SUCCESS)
36867c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval);
36877c478bd9Sstevel@tonic-gate #endif
36887c478bd9Sstevel@tonic-gate 	return (retval);
36897c478bd9Sstevel@tonic-gate }
36907c478bd9Sstevel@tonic-gate 
36917c478bd9Sstevel@tonic-gate static int
36927c478bd9Sstevel@tonic-gate SSSetWindow(set_window_t *win)
36937c478bd9Sstevel@tonic-gate {
36947c478bd9Sstevel@tonic-gate 	int socket, window, retval, func;
36957c478bd9Sstevel@tonic-gate 	set_window_t newwin;
36967c478bd9Sstevel@tonic-gate 	pcmcia_logical_window_t *winp;
36977c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
36987c478bd9Sstevel@tonic-gate 
36997c478bd9Sstevel@tonic-gate 	window = win->window;
37007c478bd9Sstevel@tonic-gate 	if (window > pcmcia_num_windows)
37017c478bd9Sstevel@tonic-gate 		return (BAD_WINDOW);
37027c478bd9Sstevel@tonic-gate 
37037c478bd9Sstevel@tonic-gate 	socket = CS_GET_SOCKET_NUMBER(win->socket);
37047c478bd9Sstevel@tonic-gate 	func = CS_GET_FUNCTION_NUMBER(win->socket);
37057c478bd9Sstevel@tonic-gate 
37067c478bd9Sstevel@tonic-gate 	if (socket > pcmcia_num_sockets ||
37077c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[socket]) == NULL) {
37087c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
37097c478bd9Sstevel@tonic-gate 	}
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate 	winp = pcmcia_windows[window];
37127c478bd9Sstevel@tonic-gate 	winp->lw_socket = win->socket; /* reverse map */
37137c478bd9Sstevel@tonic-gate 	newwin = *win;
37147c478bd9Sstevel@tonic-gate 	newwin.window = winp->lw_window;
37157c478bd9Sstevel@tonic-gate 	newwin.socket = sockp->ls_socket;
37167c478bd9Sstevel@tonic-gate 	newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin);
37197c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
37207c478bd9Sstevel@tonic-gate 		newwin.window = window;
37217c478bd9Sstevel@tonic-gate 		newwin.socket = winp->lw_socket;
37227c478bd9Sstevel@tonic-gate 		*win = newwin;
37237c478bd9Sstevel@tonic-gate 	}
37247c478bd9Sstevel@tonic-gate 	return (retval);
37257c478bd9Sstevel@tonic-gate }
37267c478bd9Sstevel@tonic-gate 
37277c478bd9Sstevel@tonic-gate static int
37287c478bd9Sstevel@tonic-gate SSSetSocket(set_socket_t *socket)
37297c478bd9Sstevel@tonic-gate {
37307c478bd9Sstevel@tonic-gate 	int sock, retval;
37317c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
37327c478bd9Sstevel@tonic-gate 	set_socket_t newsock;
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 	sock = socket->socket;
37357c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
37367c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL) {
37377c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
37387c478bd9Sstevel@tonic-gate 	}
37397c478bd9Sstevel@tonic-gate 
37407c478bd9Sstevel@tonic-gate 	newsock = *socket;
37417c478bd9Sstevel@tonic-gate 	/* note: we force CS to always get insert/removal events */
37427c478bd9Sstevel@tonic-gate 	sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) |
37437c478bd9Sstevel@tonic-gate 		PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL);
37447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
37457c478bd9Sstevel@tonic-gate 	if (pcmcia_debug > 1)
37467c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
37477c478bd9Sstevel@tonic-gate 			"SetSocket: SCIntMask = %x\n", newsock.SCIntMask);
37487c478bd9Sstevel@tonic-gate #endif
37497c478bd9Sstevel@tonic-gate 	newsock.socket = sockp->ls_socket;
37507c478bd9Sstevel@tonic-gate 	newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter,
37517c478bd9Sstevel@tonic-gate 	    newsock.VccLevel, VCC);
37527c478bd9Sstevel@tonic-gate 	newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter,
37537c478bd9Sstevel@tonic-gate 	    newsock.Vpp1Level, VPP1);
37547c478bd9Sstevel@tonic-gate 	newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter,
37557c478bd9Sstevel@tonic-gate 	    newsock.Vpp2Level, VPP2);
37567c478bd9Sstevel@tonic-gate 	retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
37577c478bd9Sstevel@tonic-gate 	    &newsock);
37587c478bd9Sstevel@tonic-gate 	if (retval == SUCCESS) {
37597c478bd9Sstevel@tonic-gate 		newsock.socket = sock;
37607c478bd9Sstevel@tonic-gate 		newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
37617c478bd9Sstevel@tonic-gate 		    newsock.VccLevel,
37627c478bd9Sstevel@tonic-gate 		    VCC);
37637c478bd9Sstevel@tonic-gate 		newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
37647c478bd9Sstevel@tonic-gate 		    newsock.Vpp1Level,
37657c478bd9Sstevel@tonic-gate 		    VPP1);
37667c478bd9Sstevel@tonic-gate 		newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
37677c478bd9Sstevel@tonic-gate 		    newsock.Vpp2Level,
37687c478bd9Sstevel@tonic-gate 		    VPP2);
37697c478bd9Sstevel@tonic-gate 		*socket = newsock;
37707c478bd9Sstevel@tonic-gate 		if (socket->IREQRouting & IRQ_ENABLE) {
37717c478bd9Sstevel@tonic-gate 			sockp->ls_flags |= PCS_IRQ_ENABLED;
37727c478bd9Sstevel@tonic-gate 		} else {
37737c478bd9Sstevel@tonic-gate 			sockp->ls_flags &= ~PCS_IRQ_ENABLED;
37747c478bd9Sstevel@tonic-gate 		}
37757c478bd9Sstevel@tonic-gate 	}
37767c478bd9Sstevel@tonic-gate 	return (retval);
37777c478bd9Sstevel@tonic-gate }
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate /*
37807c478bd9Sstevel@tonic-gate  * SSSetIRQHandler()
37817c478bd9Sstevel@tonic-gate  *	arrange for IRQ to be allocated if appropriate and always
37827c478bd9Sstevel@tonic-gate  *	arrange that PC Card interrupt handlers get called.
37837c478bd9Sstevel@tonic-gate  */
37847c478bd9Sstevel@tonic-gate static int
37857c478bd9Sstevel@tonic-gate SSSetIRQHandler(set_irq_handler_t *handler)
37867c478bd9Sstevel@tonic-gate {
37877c478bd9Sstevel@tonic-gate 	int sock, retval, func;
37887c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
37897c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
37907c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
37917c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t iblk;
37927c478bd9Sstevel@tonic-gate 	ddi_idevice_cookie_t idev;
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 	sock = CS_GET_SOCKET_NUMBER(handler->socket);
37957c478bd9Sstevel@tonic-gate 	func = CS_GET_FUNCTION_NUMBER(handler->socket);
37967c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
37977c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL) {
37987c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
37997c478bd9Sstevel@tonic-gate 	}
38007c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
38017c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n",
38047c478bd9Sstevel@tonic-gate 			sock, func);
38057c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n",
38067c478bd9Sstevel@tonic-gate 			(void *)handler->handler, handler->socket, handler->irq,
38077c478bd9Sstevel@tonic-gate 			handler->handler_id);
38087c478bd9Sstevel@tonic-gate 	}
38097c478bd9Sstevel@tonic-gate #endif
38107c478bd9Sstevel@tonic-gate 	dip = sockp->ls_dip[func];
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	handler->iblk_cookie = &iblk;
38157c478bd9Sstevel@tonic-gate 	handler->idev_cookie = &idev;
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 	retval = ddi_add_intr(dip, 0, handler->iblk_cookie,
38187c478bd9Sstevel@tonic-gate 	    handler->idev_cookie,
38197c478bd9Sstevel@tonic-gate 	    (uint32_t(*)(caddr_t)) handler->handler,
38207c478bd9Sstevel@tonic-gate 	    handler->arg1);
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 	if (retval == DDI_SUCCESS) {
38237c478bd9Sstevel@tonic-gate 		handler->iblk_cookie = &sockp->ls_iblk;
38247c478bd9Sstevel@tonic-gate 		handler->idev_cookie = &sockp->ls_idev;
38257c478bd9Sstevel@tonic-gate 		handler->irq = ppd->ppd_intrspec->intrspec_vec;
38267c478bd9Sstevel@tonic-gate 		retval = SUCCESS;
38277c478bd9Sstevel@tonic-gate 	} else {
38287c478bd9Sstevel@tonic-gate 		retval = sockp->ls_error;
38297c478bd9Sstevel@tonic-gate 	}
38307c478bd9Sstevel@tonic-gate 	return (retval);
38317c478bd9Sstevel@tonic-gate }
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate /*
38347c478bd9Sstevel@tonic-gate  * SSClearIRQHandler()
38357c478bd9Sstevel@tonic-gate  *	Arrange to have the interrupt handler specified removed
38367c478bd9Sstevel@tonic-gate  *	from the interrupt list.
38377c478bd9Sstevel@tonic-gate  */
38387c478bd9Sstevel@tonic-gate static int
38397c478bd9Sstevel@tonic-gate SSClearIRQHandler(clear_irq_handler_t *handler)
38407c478bd9Sstevel@tonic-gate {
38417c478bd9Sstevel@tonic-gate 	int sock, func;
38427c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
38437c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	sock = CS_GET_SOCKET_NUMBER(handler->socket);
38467c478bd9Sstevel@tonic-gate 	func = CS_GET_FUNCTION_NUMBER(handler->socket);
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
38497c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
38527c478bd9Sstevel@tonic-gate 			"SSClearIRQHandler: socket=%x, function=%x\n",
38537c478bd9Sstevel@tonic-gate 			sock, func);
38547c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
38557c478bd9Sstevel@tonic-gate 			"\thandler(%p): socket=%x, id=%x\n",
38567c478bd9Sstevel@tonic-gate 			(void *)handler, handler->socket,
38577c478bd9Sstevel@tonic-gate 			handler->handler_id);
38587c478bd9Sstevel@tonic-gate 	}
38597c478bd9Sstevel@tonic-gate #endif
38607c478bd9Sstevel@tonic-gate 
38617c478bd9Sstevel@tonic-gate 	if (sock > pcmcia_num_sockets ||
38627c478bd9Sstevel@tonic-gate 		(sockp = pcmcia_sockets[sock]) == NULL) {
38637c478bd9Sstevel@tonic-gate 		return (BAD_SOCKET);
38647c478bd9Sstevel@tonic-gate 	}
38657c478bd9Sstevel@tonic-gate 	dip = sockp->ls_dip[func];
38667c478bd9Sstevel@tonic-gate 	if (dip) {
38677c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dip, 0, NULL);
38687c478bd9Sstevel@tonic-gate 		return (SUCCESS);
38697c478bd9Sstevel@tonic-gate 	}
38707c478bd9Sstevel@tonic-gate 	return (BAD_SOCKET);
38717c478bd9Sstevel@tonic-gate }
38727c478bd9Sstevel@tonic-gate 
38737c478bd9Sstevel@tonic-gate 
38747c478bd9Sstevel@tonic-gate /*
38757c478bd9Sstevel@tonic-gate  * pcm_pathname()
38767c478bd9Sstevel@tonic-gate  *	make a partial path from dip.
38777c478bd9Sstevel@tonic-gate  *	used to mknods relative to /devices/pcmcia/
38787c478bd9Sstevel@tonic-gate  *
38797c478bd9Sstevel@tonic-gate  * XXX - we now use ddi_get_name_addr to get the "address" portion
38807c478bd9Sstevel@tonic-gate  *	of the name; that way, we only have to modify the name creation
38817c478bd9Sstevel@tonic-gate  *	algorithm in one place
38827c478bd9Sstevel@tonic-gate  */
38837c478bd9Sstevel@tonic-gate static void
38847c478bd9Sstevel@tonic-gate pcm_pathname(dev_info_t *dip, char *name, char *path)
38857c478bd9Sstevel@tonic-gate {
38867c478bd9Sstevel@tonic-gate 	(void) sprintf(path, "%s@%s:%s", ddi_node_name(dip),
38877c478bd9Sstevel@tonic-gate 	    ddi_get_name_addr(dip), name);
38887c478bd9Sstevel@tonic-gate }
38897c478bd9Sstevel@tonic-gate 
38907c478bd9Sstevel@tonic-gate /*
38917c478bd9Sstevel@tonic-gate  * pcmcia_create_device()
38927c478bd9Sstevel@tonic-gate  *	create the /devices entries for the driver
38937c478bd9Sstevel@tonic-gate  *	it is assumed that the PC Card driver will do a
38947c478bd9Sstevel@tonic-gate  *	RegisterClient for each subdevice.
38957c478bd9Sstevel@tonic-gate  *	The device type string is encoded here to match
38967c478bd9Sstevel@tonic-gate  *	the standardized names when possible.
38977c478bd9Sstevel@tonic-gate  * XXX - note that we may need to provide a way for the
38987c478bd9Sstevel@tonic-gate  *	caller to specify the complete name string that
38997c478bd9Sstevel@tonic-gate  *	we pass to ddi_set_name_addr
39007c478bd9Sstevel@tonic-gate  */
39017c478bd9Sstevel@tonic-gate static int
39027c478bd9Sstevel@tonic-gate pcmcia_create_device(ss_make_device_node_t *init)
39037c478bd9Sstevel@tonic-gate {
39047c478bd9Sstevel@tonic-gate 	int err = SUCCESS;
39057c478bd9Sstevel@tonic-gate 	struct pcm_make_dev device;
39067c478bd9Sstevel@tonic-gate 	struct dev_ops *ops;
39077c478bd9Sstevel@tonic-gate 	major_t major;
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate 	/*
39107c478bd9Sstevel@tonic-gate 	 * Now that we have the name, create it.
39117c478bd9Sstevel@tonic-gate 	 */
39127c478bd9Sstevel@tonic-gate 
39137c478bd9Sstevel@tonic-gate 	bzero(&device, sizeof (device));
39147c478bd9Sstevel@tonic-gate 	if (init->flags & SS_CSINITDEV_CREATE_DEVICE) {
39157c478bd9Sstevel@tonic-gate 		if ((err = ddi_create_minor_node(init->dip,
39167c478bd9Sstevel@tonic-gate 		    init->name,
39177c478bd9Sstevel@tonic-gate 		    init->spec_type,
39187c478bd9Sstevel@tonic-gate 		    init->minor_num,
39197c478bd9Sstevel@tonic-gate 		    init->node_type,
39207c478bd9Sstevel@tonic-gate 		    0)) != DDI_SUCCESS) {
39217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
39227c478bd9Sstevel@tonic-gate 			if (pcmcia_debug)
39237c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
39247c478bd9Sstevel@tonic-gate 					"pcmcia_create_device: failed "
39257c478bd9Sstevel@tonic-gate 					"create\n");
39267c478bd9Sstevel@tonic-gate #endif
39277c478bd9Sstevel@tonic-gate 			return (BAD_ATTRIBUTE);
39287c478bd9Sstevel@tonic-gate 		}
39297c478bd9Sstevel@tonic-gate 
39307c478bd9Sstevel@tonic-gate 		major = ddi_name_to_major(ddi_binding_name(init->dip));
39317c478bd9Sstevel@tonic-gate 		ops = ddi_get_driver(init->dip);
39327c478bd9Sstevel@tonic-gate 		LOCK_DEV_OPS(&devnamesp[major].dn_lock);
39337c478bd9Sstevel@tonic-gate 		INCR_DEV_OPS_REF(ops);
39347c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(init->dip, device.path);
39357c478bd9Sstevel@tonic-gate 		DECR_DEV_OPS_REF(ops);
39367c478bd9Sstevel@tonic-gate 		UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
39377c478bd9Sstevel@tonic-gate 		(void) sprintf(device.path + strlen(device.path), ":%s",
39387c478bd9Sstevel@tonic-gate 		    init->name);
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 		(void) strcpy(device.driver, ddi_binding_name(init->dip));
39417c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
39427c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
39437c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
39447c478bd9Sstevel@tonic-gate 				"pcmcia_create_device: created %s "
39457c478bd9Sstevel@tonic-gate 				"from %s [%s]\n",
39467c478bd9Sstevel@tonic-gate 				device.path, init->name, device.driver);
39477c478bd9Sstevel@tonic-gate #endif
39487c478bd9Sstevel@tonic-gate 		device.dev =
39497c478bd9Sstevel@tonic-gate 		    makedevice(ddi_name_to_major(ddi_get_name(init->dip)),
39507c478bd9Sstevel@tonic-gate 		    init->minor_num);
39517c478bd9Sstevel@tonic-gate 		device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ?
39527c478bd9Sstevel@tonic-gate 		    PCM_EVENT_MORE : 0;
39537c478bd9Sstevel@tonic-gate 		device.type = init->spec_type;
39547c478bd9Sstevel@tonic-gate 		device.op = SS_CSINITDEV_CREATE_DEVICE;
39557c478bd9Sstevel@tonic-gate 		device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
39567c478bd9Sstevel@tonic-gate 		    DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
39577c478bd9Sstevel@tonic-gate 		    -1);
39587c478bd9Sstevel@tonic-gate 	} else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) {
39597c478bd9Sstevel@tonic-gate 		device.op = SS_CSINITDEV_REMOVE_DEVICE;
39607c478bd9Sstevel@tonic-gate 		device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
39617c478bd9Sstevel@tonic-gate 		    DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
39627c478bd9Sstevel@tonic-gate 		    -1);
39637c478bd9Sstevel@tonic-gate 		if (init->name != NULL)
39647c478bd9Sstevel@tonic-gate 			(void) strcpy(device.path, init->name);
39657c478bd9Sstevel@tonic-gate 		device.dev =
39667c478bd9Sstevel@tonic-gate 		    makedevice(ddi_name_to_major(ddi_get_name(init->dip)),
39677c478bd9Sstevel@tonic-gate 		    0);
39687c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(init->dip, init->name);
39697c478bd9Sstevel@tonic-gate 	}
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate 	/*
39727c478bd9Sstevel@tonic-gate 	 *	we send an event for ALL devices created.
39737c478bd9Sstevel@tonic-gate 	 *	To do otherwise ties us to using drvconfig
39747c478bd9Sstevel@tonic-gate 	 *	forever.  There are relatively few devices
39757c478bd9Sstevel@tonic-gate 	 *	ever created so no need to do otherwise.
39767c478bd9Sstevel@tonic-gate 	 *	The existence of the event manager must never
39777c478bd9Sstevel@tonic-gate 	 *	be visible to a PCMCIA device driver.
39787c478bd9Sstevel@tonic-gate 	 */
39797c478bd9Sstevel@tonic-gate 	pcm_event_manager(PCE_INIT_DEV, device.socket, &device);
39807c478bd9Sstevel@tonic-gate 
39817c478bd9Sstevel@tonic-gate 	return (err);
39827c478bd9Sstevel@tonic-gate }
39837c478bd9Sstevel@tonic-gate 
39847c478bd9Sstevel@tonic-gate /*
39857c478bd9Sstevel@tonic-gate  * pcmcia_get_minors()
39867c478bd9Sstevel@tonic-gate  *	We need to traverse the minor node list of the
39877c478bd9Sstevel@tonic-gate  *	dip if there are any.  This takes two passes;
39887c478bd9Sstevel@tonic-gate  *	one to get the count and buffer size and the
39897c478bd9Sstevel@tonic-gate  *	other to actually copy the data into the buffer.
39907c478bd9Sstevel@tonic-gate  *	The framework requires that the dip be locked
39917c478bd9Sstevel@tonic-gate  *	during this time to avoid breakage as well as the
39927c478bd9Sstevel@tonic-gate  *	driver being locked.
39937c478bd9Sstevel@tonic-gate  */
39947c478bd9Sstevel@tonic-gate int
39957c478bd9Sstevel@tonic-gate pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors)
39967c478bd9Sstevel@tonic-gate {
3997b9ccdc5aScth 	int circ;
39987c478bd9Sstevel@tonic-gate 	int count = 0;
39997c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *dp;
40007c478bd9Sstevel@tonic-gate 	struct pcm_make_dev *md;
40017c478bd9Sstevel@tonic-gate 	int socket;
40027c478bd9Sstevel@tonic-gate 	major_t major;
40037c478bd9Sstevel@tonic-gate 	struct dev_ops *ops;
40047c478bd9Sstevel@tonic-gate 
40057c478bd9Sstevel@tonic-gate 	socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
40067c478bd9Sstevel@tonic-gate 	    PCM_DEV_SOCKET, -1);
4007b9ccdc5aScth 	ndi_devi_enter(dip, &circ);
40087c478bd9Sstevel@tonic-gate 	if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) {
40097c478bd9Sstevel@tonic-gate 		for (dp = DEVI(dip)->devi_minor;
40107c478bd9Sstevel@tonic-gate 			dp != (struct ddi_minor_data *)NULL;
40117c478bd9Sstevel@tonic-gate 			dp = dp->next) {
40127c478bd9Sstevel@tonic-gate 			count++; /* have one more */
40137c478bd9Sstevel@tonic-gate 		}
40147c478bd9Sstevel@tonic-gate 		/* we now know how many nodes to allocate */
40157c478bd9Sstevel@tonic-gate 		md = kmem_zalloc(count * sizeof (struct pcm_make_dev),
40167c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP);
40177c478bd9Sstevel@tonic-gate 		if (md != NULL) {
40187c478bd9Sstevel@tonic-gate 			*minors = md;
40197c478bd9Sstevel@tonic-gate 			for (dp = DEVI(dip)->devi_minor;
40207c478bd9Sstevel@tonic-gate 				dp != (struct ddi_minor_data *)NULL;
40217c478bd9Sstevel@tonic-gate 				dp = dp->next, md++) {
40227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
40237c478bd9Sstevel@tonic-gate 				if (pcmcia_debug > 1) {
40247c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT,
40257c478bd9Sstevel@tonic-gate 						"pcmcia_get_minors: name=%s,"
40267c478bd9Sstevel@tonic-gate 						"socket=%d, stype=%x, "
40277c478bd9Sstevel@tonic-gate 						"ntype=%s, dev_t=%x",
40287c478bd9Sstevel@tonic-gate 						dp->ddm_name,
40297c478bd9Sstevel@tonic-gate 						socket,
40307c478bd9Sstevel@tonic-gate 						dp->ddm_spec_type,
40317c478bd9Sstevel@tonic-gate 						dp->ddm_node_type,
40327c478bd9Sstevel@tonic-gate 						(int)dp->ddm_dev);
40337c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT,
40347c478bd9Sstevel@tonic-gate 						"\tbind name = %s\n",
40357c478bd9Sstevel@tonic-gate 						ddi_binding_name(dip));
40367c478bd9Sstevel@tonic-gate 				}
40377c478bd9Sstevel@tonic-gate #endif
40387c478bd9Sstevel@tonic-gate 				md->socket = socket;
40397c478bd9Sstevel@tonic-gate 				md->op = SS_CSINITDEV_CREATE_DEVICE;
40407c478bd9Sstevel@tonic-gate 				md->dev = dp->ddm_dev;
40417c478bd9Sstevel@tonic-gate 				md->type = dp->ddm_spec_type;
40427c478bd9Sstevel@tonic-gate 				(void) strcpy(md->driver,
40437c478bd9Sstevel@tonic-gate 				    ddi_binding_name(dip));
40447c478bd9Sstevel@tonic-gate 				major = ddi_name_to_major(md->driver);
40457c478bd9Sstevel@tonic-gate 				ops = ddi_get_driver(dip);
40467c478bd9Sstevel@tonic-gate 				LOCK_DEV_OPS(&devnamesp[major].dn_lock);
40477c478bd9Sstevel@tonic-gate 				pcm_pathname(dip, dp->ddm_name, md->path);
40487c478bd9Sstevel@tonic-gate 				INCR_DEV_OPS_REF(ops);
40497c478bd9Sstevel@tonic-gate 				(void) ddi_pathname(dip, md->path);
40507c478bd9Sstevel@tonic-gate 				DECR_DEV_OPS_REF(ops);
40517c478bd9Sstevel@tonic-gate 				UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
40527c478bd9Sstevel@tonic-gate 				(void) sprintf(md->path + strlen(md->path),
40537c478bd9Sstevel@tonic-gate 					":%s", dp->ddm_name);
40547c478bd9Sstevel@tonic-gate 				if (dp->next == NULL)
40557c478bd9Sstevel@tonic-gate 					/* no more */
40567c478bd9Sstevel@tonic-gate 					md->flags |= PCM_EVENT_MORE;
40577c478bd9Sstevel@tonic-gate 			}
40587c478bd9Sstevel@tonic-gate 		} else {
40597c478bd9Sstevel@tonic-gate 			count = 0;
40607c478bd9Sstevel@tonic-gate 		}
40617c478bd9Sstevel@tonic-gate 	}
4062b9ccdc5aScth 	ndi_devi_exit(dip, circ);
40637c478bd9Sstevel@tonic-gate 	return (count);
40647c478bd9Sstevel@tonic-gate }
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
40677c478bd9Sstevel@tonic-gate static char *ddmtypes[] = { "minor", "alias", "default", "internal" };
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate static void
40707c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dev_info_t *dip)
40717c478bd9Sstevel@tonic-gate {
4072b9ccdc5aScth 	int circ;
40737c478bd9Sstevel@tonic-gate 	int count = 0;
40747c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *dp;
40757c478bd9Sstevel@tonic-gate 	int unit, major;
40767c478bd9Sstevel@tonic-gate 	dev_info_t *np;
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate 	unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
40797c478bd9Sstevel@tonic-gate 	    PCM_DEV_SOCKET, -1);
40807c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT,
40817c478bd9Sstevel@tonic-gate 		"pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit);
40827c478bd9Sstevel@tonic-gate 
40837c478bd9Sstevel@tonic-gate 	major = ddi_driver_major(dip);
40847c478bd9Sstevel@tonic-gate 	if (major != -1) {
40857c478bd9Sstevel@tonic-gate 		for (np = devnamesp[major].dn_head; np != NULL;
40867c478bd9Sstevel@tonic-gate 		    np = (dev_info_t *)DEVI(np)->devi_next) {
40877c478bd9Sstevel@tonic-gate 			char *cf2 = "";
40887c478bd9Sstevel@tonic-gate 			char *cur = "";
4089a9fb0ae8Srw 			if (i_ddi_node_state(np) == DS_READY)
4090a9fb0ae8Srw 				cf2 = "DS_READY";
40917c478bd9Sstevel@tonic-gate 			if (np == dip)
40927c478bd9Sstevel@tonic-gate 				cur = "CUR";
40937c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\tsibs: %s %s %s\n",
40947c478bd9Sstevel@tonic-gate 				ddi_binding_name(np), cf2, cur);
40957c478bd9Sstevel@tonic-gate 
4096b9ccdc5aScth 			ndi_devi_enter(np, &circ);
40977c478bd9Sstevel@tonic-gate 			if (DEVI(np)->devi_minor !=
40987c478bd9Sstevel@tonic-gate 			    (struct ddi_minor_data *)NULL) {
40997c478bd9Sstevel@tonic-gate 				for (dp = DEVI(np)->devi_minor;
41007c478bd9Sstevel@tonic-gate 				    dp != (struct ddi_minor_data *)NULL;
41017c478bd9Sstevel@tonic-gate 				    dp = dp->next) {
41027c478bd9Sstevel@tonic-gate 					count++; /* have one more */
41037c478bd9Sstevel@tonic-gate 				}
41047c478bd9Sstevel@tonic-gate 				for (dp = DEVI(dip)->devi_minor;
41057c478bd9Sstevel@tonic-gate 				    dp != (struct ddi_minor_data *)NULL;
41067c478bd9Sstevel@tonic-gate 				    dp = dp->next) {
41077c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "\ttype=%s, name=%s,"
41087c478bd9Sstevel@tonic-gate 						"socket=%d, stype=%x, "
41097c478bd9Sstevel@tonic-gate 						"ntype=%s, dev_t=%x",
41107c478bd9Sstevel@tonic-gate 						ddmtypes[dp->type],
41117c478bd9Sstevel@tonic-gate 						dp->ddm_name,
41127c478bd9Sstevel@tonic-gate 						unit,
41137c478bd9Sstevel@tonic-gate 						dp->ddm_spec_type,
41147c478bd9Sstevel@tonic-gate 						dp->ddm_node_type,
41157c478bd9Sstevel@tonic-gate 						(int)dp->ddm_dev);
41167c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "\tbind name = %s\n",
41177c478bd9Sstevel@tonic-gate 						ddi_binding_name(np));
41187c478bd9Sstevel@tonic-gate 				}
41197c478bd9Sstevel@tonic-gate 			}
4120b9ccdc5aScth 			ndi_devi_exit(np, circ);
41217c478bd9Sstevel@tonic-gate 		}
41227c478bd9Sstevel@tonic-gate 	}
41237c478bd9Sstevel@tonic-gate }
41247c478bd9Sstevel@tonic-gate #endif
41257c478bd9Sstevel@tonic-gate 
41267c478bd9Sstevel@tonic-gate /*
41277c478bd9Sstevel@tonic-gate  * experimental merging code
41287c478bd9Sstevel@tonic-gate  * what are the things that we should merge on?
41297c478bd9Sstevel@tonic-gate  *	match something by name in the "compatible" property
41307c478bd9Sstevel@tonic-gate  *	restrict to a specific "socket"
41317c478bd9Sstevel@tonic-gate  *	restrict to a specific "instance"
41327c478bd9Sstevel@tonic-gate  */
41337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
41347c478bd9Sstevel@tonic-gate static int
41357c478bd9Sstevel@tonic-gate pcmcia_merge_conf(dev_info_t *dip)
41367c478bd9Sstevel@tonic-gate {
41377c478bd9Sstevel@tonic-gate 	return (0);		/* merge failed */
41387c478bd9Sstevel@tonic-gate }
41397c478bd9Sstevel@tonic-gate 
41407c478bd9Sstevel@tonic-gate /*
41417c478bd9Sstevel@tonic-gate  * pcmcia_mfc_intr()
41427c478bd9Sstevel@tonic-gate  *	Multifunction Card interrupt handler
41437c478bd9Sstevel@tonic-gate  *	While some adapters share interrupts at the lowest
41447c478bd9Sstevel@tonic-gate  *	level, some can't.  In order to be consistent, we
41457c478bd9Sstevel@tonic-gate  *	split multifunction cards out with this intercept and
41467c478bd9Sstevel@tonic-gate  *	allow the low level to do what is best for it.
41477c478bd9Sstevel@tonic-gate  *	the arg is a pcmcia_socket structure and all interrupts
41487c478bd9Sstevel@tonic-gate  *	are per-socket in this case.  We also have the option
41497c478bd9Sstevel@tonic-gate  *	to optimize if the cards support it.  It also means
41507c478bd9Sstevel@tonic-gate  *	that we can use the INTRACK mode if it proves desirable
41517c478bd9Sstevel@tonic-gate  */
41527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
41537c478bd9Sstevel@tonic-gate static uint32_t
41547c478bd9Sstevel@tonic-gate pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2)
41557c478bd9Sstevel@tonic-gate {
41567c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
41577c478bd9Sstevel@tonic-gate 	inthandler_t *intr, *first;
41587c478bd9Sstevel@tonic-gate 	int done, result;
41597c478bd9Sstevel@tonic-gate 
41607c478bd9Sstevel@tonic-gate 	sockp = (pcmcia_logical_socket_t *)arg1;
41617c478bd9Sstevel@tonic-gate 
41627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
41637c478bd9Sstevel@tonic-gate 	if (pcmcia_debug > 1) {
41647c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p"
41657c478bd9Sstevel@tonic-gate 		    " ls_inthandlers=%p\n"
41667c478bd9Sstevel@tonic-gate 		    "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n",
41677c478bd9Sstevel@tonic-gate 		    (void *) sockp, (void *) sockp->ls_inthandlers,
41687c478bd9Sstevel@tonic-gate 		    sockp->ls_flags, PCS_IRQ_ENABLED);
41697c478bd9Sstevel@tonic-gate 	}
41707c478bd9Sstevel@tonic-gate #endif
41717c478bd9Sstevel@tonic-gate 
41727c478bd9Sstevel@tonic-gate 	if (sockp == NULL || sockp->ls_inthandlers == NULL ||
41737c478bd9Sstevel@tonic-gate 	    !(sockp->ls_flags & PCS_IRQ_ENABLED))
41747c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate 	mutex_enter(&sockp->ls_ilock);
41777c478bd9Sstevel@tonic-gate 	for (done = 0, result = 0, first = intr = sockp->ls_inthandlers;
41787c478bd9Sstevel@tonic-gate 		intr != NULL && !done; intr = intr->next) {
41797c478bd9Sstevel@tonic-gate 		result |= intr->intr(intr->arg1, intr->arg2);
41807c478bd9Sstevel@tonic-gate 		if (intr->next == first)
41817c478bd9Sstevel@tonic-gate 			done++;
41827c478bd9Sstevel@tonic-gate 	}
41837c478bd9Sstevel@tonic-gate 	if (intr == NULL) {
41847c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list");
41857c478bd9Sstevel@tonic-gate 	}
41867c478bd9Sstevel@tonic-gate 	if (sockp->ls_inthandlers)
41877c478bd9Sstevel@tonic-gate 		sockp->ls_inthandlers = sockp->ls_inthandlers->next;
41887c478bd9Sstevel@tonic-gate 
41897c478bd9Sstevel@tonic-gate 	mutex_exit(&sockp->ls_ilock);
41907c478bd9Sstevel@tonic-gate 	return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
41917c478bd9Sstevel@tonic-gate }
41927c478bd9Sstevel@tonic-gate 
41937c478bd9Sstevel@tonic-gate /*
41947c478bd9Sstevel@tonic-gate  * pcmcia_power(dip)
41957c478bd9Sstevel@tonic-gate  *	control power for nexus and children
41967c478bd9Sstevel@tonic-gate  */
41977c478bd9Sstevel@tonic-gate int
41987c478bd9Sstevel@tonic-gate pcmcia_power(dev_info_t *dip, int component, int level)
41997c478bd9Sstevel@tonic-gate {
42007c478bd9Sstevel@tonic-gate #if 0
42017c478bd9Sstevel@tonic-gate 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
42027c478bd9Sstevel@tonic-gate 	int i;
42037c478bd9Sstevel@tonic-gate 	/*
42047c478bd9Sstevel@tonic-gate 	 * for now, we only have one component.  Should there be one per-socket?
42057c478bd9Sstevel@tonic-gate 	 * the level is only one (power on or off)
42067c478bd9Sstevel@tonic-gate 	 */
42077c478bd9Sstevel@tonic-gate 	if (component != 0 || level > 1)
42087c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
42097c478bd9Sstevel@tonic-gate 
42107c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcic->pc_numsockets; i++) {
42117c478bd9Sstevel@tonic-gate 		if (pcic->pc_callback)
42127c478bd9Sstevel@tonic-gate 			PC_CALLBACK(dip, pcic->pc_cb_arg,
42137c478bd9Sstevel@tonic-gate 			    (level == 0) ? PCE_PM_SUSPEND :
42147c478bd9Sstevel@tonic-gate 			    PCE_PM_RESUME,
42157c478bd9Sstevel@tonic-gate 			    i);
42167c478bd9Sstevel@tonic-gate 	}
42177c478bd9Sstevel@tonic-gate #else
42187c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s",
42197c478bd9Sstevel@tonic-gate 		component, level, ddi_get_name_addr(dip));
42207c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
42217c478bd9Sstevel@tonic-gate #endif
42227c478bd9Sstevel@tonic-gate }
42237c478bd9Sstevel@tonic-gate 
42247c478bd9Sstevel@tonic-gate void
42257c478bd9Sstevel@tonic-gate pcmcia_begin_resume(dev_info_t *dip)
42267c478bd9Sstevel@tonic-gate {
42277c478bd9Sstevel@tonic-gate 	int i;
42287c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter *adapt = NULL;
42297c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_adapters; i++) {
42307c478bd9Sstevel@tonic-gate 		if (pcmcia_adapters[i]->pca_dip == dip) {
42317c478bd9Sstevel@tonic-gate 			adapt = pcmcia_adapters[i];
42327c478bd9Sstevel@tonic-gate 			break;
42337c478bd9Sstevel@tonic-gate 		}
42347c478bd9Sstevel@tonic-gate 	}
42357c478bd9Sstevel@tonic-gate 	if (adapt == NULL)
42367c478bd9Sstevel@tonic-gate 		return;
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate 	for (i = 0; i < adapt->pca_numsockets; i++) {
42397c478bd9Sstevel@tonic-gate 		int s;
42407c478bd9Sstevel@tonic-gate 		s = adapt->pca_first_socket + i;
42417c478bd9Sstevel@tonic-gate 		if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) {
42427c478bd9Sstevel@tonic-gate 			if (pcmcia_sockets[s]->ls_flags &
42437c478bd9Sstevel@tonic-gate 			    (1 << PCE_PM_RESUME)) {
42447c478bd9Sstevel@tonic-gate 				(void) cs_event(PCE_PM_RESUME, s, 0);
42457c478bd9Sstevel@tonic-gate 				pcm_event_manager(PCE_PM_RESUME, s, NULL);
42467c478bd9Sstevel@tonic-gate 			}
42477c478bd9Sstevel@tonic-gate 			(void) cs_event(PCE_CARD_REMOVAL, s, 0);
42487c478bd9Sstevel@tonic-gate 			pcm_event_manager(PCE_CARD_REMOVAL, s, NULL);
42497c478bd9Sstevel@tonic-gate 		}
42507c478bd9Sstevel@tonic-gate 	}
42517c478bd9Sstevel@tonic-gate }
42527c478bd9Sstevel@tonic-gate 
425311c2b4c0Srw /*
425411c2b4c0Srw  * mark a cardbus card as "suspended" in the pcmcia module
425511c2b4c0Srw  */
425611c2b4c0Srw void
425711c2b4c0Srw pcmcia_cb_suspended(int socket)
425811c2b4c0Srw {
425911c2b4c0Srw 	mutex_enter(&pcmcia_global_lock);
426011c2b4c0Srw 	pcmcia_sockets[socket]->ls_flags |= PCS_SUSPENDED;
426111c2b4c0Srw 	mutex_exit(&pcmcia_global_lock);
426211c2b4c0Srw 
426311c2b4c0Srw }
426411c2b4c0Srw 
426511c2b4c0Srw /*
426611c2b4c0Srw  * mark a cardbus card as "resumed" in the pcmcia module
426711c2b4c0Srw  */
426811c2b4c0Srw void
426911c2b4c0Srw pcmcia_cb_resumed(int socket)
427011c2b4c0Srw {
427111c2b4c0Srw 	if (pcmcia_sockets[socket]->ls_flags & PCS_SUSPENDED) {
427211c2b4c0Srw 		mutex_enter(&pcmcia_global_lock);
427311c2b4c0Srw 		pcmcia_sockets[socket]->ls_flags &= ~PCS_SUSPENDED;
427411c2b4c0Srw 		cv_broadcast(&pcmcia_condvar);
427511c2b4c0Srw 		mutex_exit(&pcmcia_global_lock);
427611c2b4c0Srw #ifdef PCMCIA_DEBUG
427711c2b4c0Srw 		if (pcmcia_debug) {
427811c2b4c0Srw 			cmn_err(CE_NOTE, "pcmcia_cb_resume RESUMED");
427911c2b4c0Srw 		}
428011c2b4c0Srw #endif
428111c2b4c0Srw 	}
428211c2b4c0Srw 
428311c2b4c0Srw }
428411c2b4c0Srw 
42857c478bd9Sstevel@tonic-gate void
42867c478bd9Sstevel@tonic-gate pcmcia_wait_insert(dev_info_t *dip)
42877c478bd9Sstevel@tonic-gate {
42887c478bd9Sstevel@tonic-gate 	int i, f, tries, done;
42897c478bd9Sstevel@tonic-gate 	clock_t tm;
42907c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter *adapt = NULL;
42917c478bd9Sstevel@tonic-gate 	anp_t *nexus;
42927c478bd9Sstevel@tonic-gate 
42937c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_adapters; i++) {
42947c478bd9Sstevel@tonic-gate 		if (pcmcia_adapters[i]->pca_dip == dip) {
42957c478bd9Sstevel@tonic-gate 			adapt = pcmcia_adapters[i];
42967c478bd9Sstevel@tonic-gate 			break;
42977c478bd9Sstevel@tonic-gate 		}
42987c478bd9Sstevel@tonic-gate 	}
42997c478bd9Sstevel@tonic-gate 	if (adapt == NULL)
43007c478bd9Sstevel@tonic-gate 		return;
43017c478bd9Sstevel@tonic-gate 
43027c478bd9Sstevel@tonic-gate 	for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) {
43037c478bd9Sstevel@tonic-gate 		done = 1;
43047c478bd9Sstevel@tonic-gate 		mutex_enter(&pcmcia_global_lock);
43057c478bd9Sstevel@tonic-gate 		for (i = 0; i < adapt->pca_numsockets; i++) {
43067c478bd9Sstevel@tonic-gate 			int s;
43077c478bd9Sstevel@tonic-gate 			s = adapt->pca_first_socket + i;
43087c478bd9Sstevel@tonic-gate 			for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++)
43097c478bd9Sstevel@tonic-gate 				if (pcmcia_sockets[s] &&
43107c478bd9Sstevel@tonic-gate 				    pcmcia_sockets[s]->ls_flags &
43117c478bd9Sstevel@tonic-gate 				    PCS_SUSPENDED) {
431211c2b4c0Srw 
431311c2b4c0Srw #ifdef PCMCIA_DEBUG
431411c2b4c0Srw 					if (pcmcia_debug) {
431511c2b4c0Srw 						cmn_err(CE_NOTE,
431611c2b4c0Srw 						"pcmcia_wait_insert: "
431711c2b4c0Srw 						"socket in SUSPENDED state");
431811c2b4c0Srw 					}
431911c2b4c0Srw #endif
43207c478bd9Sstevel@tonic-gate 					done = 0;
43217c478bd9Sstevel@tonic-gate 					break;
43227c478bd9Sstevel@tonic-gate 				}
43237c478bd9Sstevel@tonic-gate 		}
43247c478bd9Sstevel@tonic-gate 		if (!done) {
43257c478bd9Sstevel@tonic-gate 			tm = ddi_get_lbolt();
43267c478bd9Sstevel@tonic-gate 			(void) cv_timedwait(&pcmcia_condvar,
43277c478bd9Sstevel@tonic-gate 			    &pcmcia_global_lock,
43287c478bd9Sstevel@tonic-gate 			    tm + drv_usectohz(100000));
43297c478bd9Sstevel@tonic-gate 		} else {
43307c478bd9Sstevel@tonic-gate 			tries = 0;
43317c478bd9Sstevel@tonic-gate 		}
43327c478bd9Sstevel@tonic-gate 		mutex_exit(&pcmcia_global_lock);
43337c478bd9Sstevel@tonic-gate 	}
43347c478bd9Sstevel@tonic-gate 
433511c2b4c0Srw 	if (tries == 0) {
433611c2b4c0Srw 		cmn_err(CE_NOTE, "pcmcia_wait_insert timed out");
433711c2b4c0Srw 	}
433811c2b4c0Srw 
43397c478bd9Sstevel@tonic-gate 	nexus = (anp_t *)ddi_get_driver_private(dip);
43407c478bd9Sstevel@tonic-gate 	pcmcia_find_cards(nexus);
43417c478bd9Sstevel@tonic-gate }
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate int
43447c478bd9Sstevel@tonic-gate pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra,
43457c478bd9Sstevel@tonic-gate 		uint32_t state, caddr_t *base,
43467c478bd9Sstevel@tonic-gate 		ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib,
43477c478bd9Sstevel@tonic-gate 		uint32_t req_base)
43487c478bd9Sstevel@tonic-gate {
43497c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
43507c478bd9Sstevel@tonic-gate 	int rnum = 0, type = PCMCIA_MAP_MEM;
43517c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
43527c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
43537c478bd9Sstevel@tonic-gate 	int result;
43547c478bd9Sstevel@tonic-gate 	struct regspec *reg;
43557c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
43567c478bd9Sstevel@tonic-gate 
43577c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
43587c478bd9Sstevel@tonic-gate 		ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
43597c478bd9Sstevel@tonic-gate 		if (ppd == NULL)
43607c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
43617c478bd9Sstevel@tonic-gate 		for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) {
43627c478bd9Sstevel@tonic-gate 			struct pcm_regs *p;
43637c478bd9Sstevel@tonic-gate 			p = &ppd->ppd_reg[rnum];
43647c478bd9Sstevel@tonic-gate 			if (state & WS_IO) {
43657c478bd9Sstevel@tonic-gate 				/* need I/O */
43667c478bd9Sstevel@tonic-gate 				type = PCMCIA_MAP_IO;
43677c478bd9Sstevel@tonic-gate 				/*
43687c478bd9Sstevel@tonic-gate 				 * We want to find an IO regspec. When we
43697c478bd9Sstevel@tonic-gate 				 *	find one, it either has to match
43707c478bd9Sstevel@tonic-gate 				 *	the caller's requested base address
43717c478bd9Sstevel@tonic-gate 				 *	or it has to be relocatable.
43727c478bd9Sstevel@tonic-gate 				 * We match on the requested base address
43737c478bd9Sstevel@tonic-gate 				 *	rather than the allocated base
43747c478bd9Sstevel@tonic-gate 				 *	address so that we handle the case
43757c478bd9Sstevel@tonic-gate 				 *	of adapters that have IO window base
43767c478bd9Sstevel@tonic-gate 				 *	relocation registers.
43777c478bd9Sstevel@tonic-gate 				 */
43787c478bd9Sstevel@tonic-gate 				if ((p->phys_hi &
43797c478bd9Sstevel@tonic-gate 				    PC_REG_SPACE(PC_REG_SPACE_IO)) &&
43807c478bd9Sstevel@tonic-gate 					((req_base == p->phys_lo) ||
43817c478bd9Sstevel@tonic-gate 					!(p->phys_hi & PC_REG_RELOC(1))))
43827c478bd9Sstevel@tonic-gate 				    break;
43837c478bd9Sstevel@tonic-gate 			} else {
43847c478bd9Sstevel@tonic-gate 				/* need memory */
43857c478bd9Sstevel@tonic-gate 				type = PCMCIA_MAP_MEM;
43867c478bd9Sstevel@tonic-gate 				if (p->phys_hi &
43877c478bd9Sstevel@tonic-gate 				    PC_REG_SPACE(PC_REG_SPACE_MEMORY|
43887c478bd9Sstevel@tonic-gate 				    PC_REG_SPACE_ATTRIBUTE))
43897c478bd9Sstevel@tonic-gate 					break;
43907c478bd9Sstevel@tonic-gate 			}
43917c478bd9Sstevel@tonic-gate 		}
43927c478bd9Sstevel@tonic-gate 		if (rnum >= ppd->ppd_nreg)
43937c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
43947c478bd9Sstevel@tonic-gate 	} else if (state & WS_IO) {
43957c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
43967c478bd9Sstevel@tonic-gate 	}
43977c478bd9Sstevel@tonic-gate 
43987c478bd9Sstevel@tonic-gate 	reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP);
43997c478bd9Sstevel@tonic-gate 	reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra);
44007c478bd9Sstevel@tonic-gate 
44017c478bd9Sstevel@tonic-gate 	if (attrib == NULL ||
44027c478bd9Sstevel@tonic-gate 	    attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) {
44037c478bd9Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
44047c478bd9Sstevel@tonic-gate 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
44057c478bd9Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
44067c478bd9Sstevel@tonic-gate 	} else {
44077c478bd9Sstevel@tonic-gate 		attr = *attrib;
44087c478bd9Sstevel@tonic-gate 	}
44097c478bd9Sstevel@tonic-gate 	/*
44107c478bd9Sstevel@tonic-gate 	 * Allocate and initialize the common elements of data access handle.
44117c478bd9Sstevel@tonic-gate 	 */
44127c478bd9Sstevel@tonic-gate 	*handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
44137c478bd9Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handle);
44147c478bd9Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
44157c478bd9Sstevel@tonic-gate 	hp->ah_dip = dip != NULL ? dip : pdip;
44167c478bd9Sstevel@tonic-gate 	hp->ah_rnumber = rnum;
44177c478bd9Sstevel@tonic-gate 	hp->ah_offset = 0;
44187c478bd9Sstevel@tonic-gate 	hp->ah_len = ra->ra_len;
44197c478bd9Sstevel@tonic-gate 	hp->ah_acc = attr;
44207c478bd9Sstevel@tonic-gate 
44217c478bd9Sstevel@tonic-gate 	/*
44227c478bd9Sstevel@tonic-gate 	 * Set up the mapping request and call to parent.
44237c478bd9Sstevel@tonic-gate 	 */
44247c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
44257c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
44267c478bd9Sstevel@tonic-gate 	mr.map_obj.rp = reg;
44277c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
44287c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
44297c478bd9Sstevel@tonic-gate 	mr.map_handlep = hp;
44307c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
44317c478bd9Sstevel@tonic-gate 
44327c478bd9Sstevel@tonic-gate 	result = ddi_map(pdip, &mr, 0, ra->ra_len, base);
44337c478bd9Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
44347c478bd9Sstevel@tonic-gate 		impl_acc_hdl_free(*handle);
44357c478bd9Sstevel@tonic-gate 		*handle = (ddi_acc_handle_t)NULL;
44367c478bd9Sstevel@tonic-gate 	} else {
44377c478bd9Sstevel@tonic-gate 		hp->ah_addr = *base;
44387c478bd9Sstevel@tonic-gate 		if (mr.map_op == DDI_MO_UNMAP)
44397c478bd9Sstevel@tonic-gate 			ra = NULL;
44407c478bd9Sstevel@tonic-gate 		if (dip != NULL)
44417c478bd9Sstevel@tonic-gate 			pcmcia_set_assigned(dip, rnum, ra);
44427c478bd9Sstevel@tonic-gate 	}
44437c478bd9Sstevel@tonic-gate 
4444981012acSrw 	kmem_free(reg, sizeof (pci_regspec_t));
4445981012acSrw 
44467c478bd9Sstevel@tonic-gate 	return (result);
44477c478bd9Sstevel@tonic-gate }
44487c478bd9Sstevel@tonic-gate 
44497c478bd9Sstevel@tonic-gate struct pcmcia_adapter *
44507c478bd9Sstevel@tonic-gate pcmcia_get_adapter(dev_info_t *dip)
44517c478bd9Sstevel@tonic-gate {
44527c478bd9Sstevel@tonic-gate 	int i;
44537c478bd9Sstevel@tonic-gate 
44547c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcmcia_num_adapters; i++) {
44557c478bd9Sstevel@tonic-gate 		if (pcmcia_adapters[i] &&
44567c478bd9Sstevel@tonic-gate 		    pcmcia_adapters[i]->pca_dip == dip) {
44577c478bd9Sstevel@tonic-gate 			return (pcmcia_adapters[i]);
44587c478bd9Sstevel@tonic-gate 		}
44597c478bd9Sstevel@tonic-gate 	}
44607c478bd9Sstevel@tonic-gate 	return (NULL);
44617c478bd9Sstevel@tonic-gate }
44627c478bd9Sstevel@tonic-gate 
44637c478bd9Sstevel@tonic-gate 
44647c478bd9Sstevel@tonic-gate void
44657c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret)
44667c478bd9Sstevel@tonic-gate {
44677c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
44687c478bd9Sstevel@tonic-gate 	struct pcm_regs *reg, *assign;
44697c478bd9Sstevel@tonic-gate 
44707c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
44717c478bd9Sstevel@tonic-gate 	if (ppd) {
44727c478bd9Sstevel@tonic-gate 		reg = &ppd->ppd_reg[rnum];
44737c478bd9Sstevel@tonic-gate 		assign = &ppd->ppd_assigned[rnum];
44747c478bd9Sstevel@tonic-gate 		if (ret) {
44757c478bd9Sstevel@tonic-gate 			if (assign->phys_hi == 0) {
44767c478bd9Sstevel@tonic-gate 				assign->phys_hi = reg->phys_hi;
44777c478bd9Sstevel@tonic-gate 				assign->phys_lo = ret->ra_addr_lo;
44787c478bd9Sstevel@tonic-gate 				assign->phys_len = ret->ra_len;
44797c478bd9Sstevel@tonic-gate 			} else if (assign->phys_lo != ret->ra_addr_lo) {
44807c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG
44817c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pcmcia: bad address:"
44827c478bd9Sstevel@tonic-gate 					"%s=<%x,%x>",
44837c478bd9Sstevel@tonic-gate 					ddi_get_name_addr(dip),
44847c478bd9Sstevel@tonic-gate 					ret->ra_addr_lo, assign->phys_lo);
44857c478bd9Sstevel@tonic-gate #else
44867c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "!pcmcia: bad address:"
44877c478bd9Sstevel@tonic-gate 					"%s=<%x,%x>",
44887c478bd9Sstevel@tonic-gate 					ddi_get_name_addr(dip),
44897c478bd9Sstevel@tonic-gate 					ret->ra_addr_lo, (int)assign->phys_lo);
44907c478bd9Sstevel@tonic-gate #endif
44917c478bd9Sstevel@tonic-gate 			}
44927c478bd9Sstevel@tonic-gate 			assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi);
44937c478bd9Sstevel@tonic-gate 		} else {
44947c478bd9Sstevel@tonic-gate 			int i;
44957c478bd9Sstevel@tonic-gate 			assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi);
44967c478bd9Sstevel@tonic-gate 			i = PC_GET_REG_REFCNT(assign->phys_hi);
44977c478bd9Sstevel@tonic-gate 			if (i == 0) {
44987c478bd9Sstevel@tonic-gate 				assign->phys_hi = 0;
44997c478bd9Sstevel@tonic-gate 				assign->phys_lo = 0;
45007c478bd9Sstevel@tonic-gate 				assign->phys_len = 0;
45017c478bd9Sstevel@tonic-gate 			}
45027c478bd9Sstevel@tonic-gate 		}
45037c478bd9Sstevel@tonic-gate 	}
45047c478bd9Sstevel@tonic-gate }
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate int
45078134ee03Srw pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
45088134ee03Srw 		dev_info_t **res_dip)
45097c478bd9Sstevel@tonic-gate {
45108134ee03Srw 	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip));
45117c478bd9Sstevel@tonic-gate }
45127c478bd9Sstevel@tonic-gate 
45137c478bd9Sstevel@tonic-gate int
45148134ee03Srw pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
45158134ee03Srw 		dev_info_t **res_dip)
45167c478bd9Sstevel@tonic-gate {
45178134ee03Srw 	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip));
45188134ee03Srw }
45198134ee03Srw 
45208134ee03Srw static boolean_t
45218134ee03Srw is_subtractv(dev_info_t *dip)
45228134ee03Srw {
45238134ee03Srw 	uint_t  class;
45248134ee03Srw 
45258134ee03Srw 	if (dip == NULL)
45268134ee03Srw 		return (B_FALSE);
45278134ee03Srw 	class = ddi_getprop(DDI_DEV_T_ANY, dip,
45288134ee03Srw 		DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
45298134ee03Srw 		"class-code", 0xff);
45308134ee03Srw 	if (class == PPB_SUBTRACTIVE) {
45318134ee03Srw 		return (B_TRUE);
45328134ee03Srw 	}
45338134ee03Srw 	return (B_FALSE);
45348134ee03Srw }
45358134ee03Srw 
45368134ee03Srw /*
45378134ee03Srw  * pcmcia_pci_alloc()
45388134ee03Srw  * 	allocate mem or I/O resource from the ancestor of the cardbus bridge.
45398134ee03Srw  * 	First start from the parent node. If the parent is a subtractive
45408134ee03Srw  * 	decode bridge and it does not have the requested resource, go up the
45418134ee03Srw  * 	device tree to find the resource.
45428134ee03Srw  *
45438134ee03Srw  * 	dip		the parent node of the cardbus bridge
45448134ee03Srw  *
45458134ee03Srw  * 	res_dip		returns a pointer to the node from which the
45468134ee03Srw  * 			resource is obtained. *res_dip could point to
45478134ee03Srw  * 			the parent or a higher level ancestor. *res_dip
45488134ee03Srw  * 			should be saved by the caller and later passed
45498134ee03Srw  * 			to pcmcia_ra_free();
45508134ee03Srw  */
45518134ee03Srw int
45528134ee03Srw pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
45538134ee03Srw 		char *type, dev_info_t **res_dip)
45548134ee03Srw {
45558134ee03Srw 	uint64_t base = 0;
45568134ee03Srw 	uint64_t len = 0;
45578134ee03Srw 
45588134ee03Srw 	if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
45598134ee03Srw 							== NDI_FAILURE) ||
45608134ee03Srw 	    ((base >> 32) != 0)) {
45618134ee03Srw 		if (is_subtractv(dip)) {
45628134ee03Srw 			return (pcmcia_pci_alloc(ddi_get_parent(dip),
45638134ee03Srw 					req, ret, type, res_dip));
45648134ee03Srw 
45658134ee03Srw 		} else {
45668134ee03Srw 			ret->ra_addr_hi = 0;
45678134ee03Srw 			ret->ra_addr_lo = 0;
45688134ee03Srw 			ret->ra_len = 0;
45698134ee03Srw 			return (DDI_FAILURE);
45708134ee03Srw 		}
45718134ee03Srw 	}
45728134ee03Srw 	ret->ra_addr_lo =  base & 0xffffffff;
45738134ee03Srw 	ret->ra_addr_hi = 0;
45748134ee03Srw 	ret->ra_len = len;
45758134ee03Srw 	*res_dip = dip;
45768134ee03Srw 	return (DDI_SUCCESS);
45777c478bd9Sstevel@tonic-gate }
45787c478bd9Sstevel@tonic-gate 
45797c478bd9Sstevel@tonic-gate int
45807c478bd9Sstevel@tonic-gate pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
45818134ee03Srw 		char *type, dev_info_t **res_dip)
45827c478bd9Sstevel@tonic-gate {
45837c478bd9Sstevel@tonic-gate 	uint64_t base = 0;
45847c478bd9Sstevel@tonic-gate 	uint64_t len = 0;
45857c478bd9Sstevel@tonic-gate 
45867c478bd9Sstevel@tonic-gate 	/*
45877c478bd9Sstevel@tonic-gate 	 * Allocate space from busra resource list
45887c478bd9Sstevel@tonic-gate 	 * should not return an address > 32 bits
45897c478bd9Sstevel@tonic-gate 	 */
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate 	if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
45927c478bd9Sstevel@tonic-gate 							== NDI_FAILURE) ||
45937c478bd9Sstevel@tonic-gate 	    ((base >> 32) != 0)) {
45948134ee03Srw 		return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret,
45958134ee03Srw 				type, res_dip));
45967c478bd9Sstevel@tonic-gate 	} else {
45977c478bd9Sstevel@tonic-gate 		ret->ra_addr_lo =  base & 0xffffffff;
45988134ee03Srw 		ret->ra_addr_hi = 0;
45997c478bd9Sstevel@tonic-gate 		ret->ra_len = len;
46008134ee03Srw 		*res_dip = dip;
46018134ee03Srw 		return (DDI_SUCCESS);
46027c478bd9Sstevel@tonic-gate 	}
46037c478bd9Sstevel@tonic-gate }
46047c478bd9Sstevel@tonic-gate 
46057c478bd9Sstevel@tonic-gate int
46067c478bd9Sstevel@tonic-gate pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret)
46077c478bd9Sstevel@tonic-gate {
46087c478bd9Sstevel@tonic-gate 	return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM));
46097c478bd9Sstevel@tonic-gate }
46107c478bd9Sstevel@tonic-gate 
46117c478bd9Sstevel@tonic-gate int
46127c478bd9Sstevel@tonic-gate pcmcia_free_io(dev_info_t *dip, ra_return_t *ret)
46137c478bd9Sstevel@tonic-gate {
46147c478bd9Sstevel@tonic-gate 	return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO));
46157c478bd9Sstevel@tonic-gate }
46167c478bd9Sstevel@tonic-gate 
46177c478bd9Sstevel@tonic-gate int
46187c478bd9Sstevel@tonic-gate pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type)
46197c478bd9Sstevel@tonic-gate {
462081ea8c75Srw 	if (dip == (dev_info_t *)-1)
462181ea8c75Srw 		return (DDI_FAILURE);
46227c478bd9Sstevel@tonic-gate 	if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len,
46237c478bd9Sstevel@tonic-gate 	    type, NDI_RA_PASS) == NDI_SUCCESS) {
46247c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
46257c478bd9Sstevel@tonic-gate 	} else {
46267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
46277c478bd9Sstevel@tonic-gate 	}
46287c478bd9Sstevel@tonic-gate }
46297c478bd9Sstevel@tonic-gate 
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate /*
46327c478bd9Sstevel@tonic-gate  * when the low level device configuration does resource assignment
46337c478bd9Sstevel@tonic-gate  * (devconf) then free the allocated resources so we can reassign them
46347c478bd9Sstevel@tonic-gate  * later.  Walk the child list to get them.
46357c478bd9Sstevel@tonic-gate  */
46367c478bd9Sstevel@tonic-gate void
46377c478bd9Sstevel@tonic-gate pcmcia_free_resources(dev_info_t *self)
46387c478bd9Sstevel@tonic-gate {
46397c478bd9Sstevel@tonic-gate 	struct regspec *assigned;
46407c478bd9Sstevel@tonic-gate 	int len;
46417c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
4642b9ccdc5aScth 	int circ;
46437c478bd9Sstevel@tonic-gate 
4644b9ccdc5aScth 	ndi_devi_enter(self, &circ);
46457c478bd9Sstevel@tonic-gate 	/* do searches in compatible property order */
46467c478bd9Sstevel@tonic-gate 	for (dip = (dev_info_t *)DEVI(self)->devi_child;
46477c478bd9Sstevel@tonic-gate 	    dip != NULL;
46487c478bd9Sstevel@tonic-gate 	    dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
46497c478bd9Sstevel@tonic-gate 		len = 0;
4650a3282898Scth 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
46517c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP,
46527c478bd9Sstevel@tonic-gate 		    "assigned-addresses",
46537c478bd9Sstevel@tonic-gate 		    (caddr_t)&assigned,
46547c478bd9Sstevel@tonic-gate 		    &len) == DDI_PROP_SUCCESS) {
46557c478bd9Sstevel@tonic-gate 			/*
46567c478bd9Sstevel@tonic-gate 			 * if there are assigned resources at this point,
46577c478bd9Sstevel@tonic-gate 			 * then the OBP or devconf have assigned them and
46587c478bd9Sstevel@tonic-gate 			 * they need to be freed.
46597c478bd9Sstevel@tonic-gate 			 */
46607c478bd9Sstevel@tonic-gate 			kmem_free(assigned, len);
46617c478bd9Sstevel@tonic-gate 		}
46627c478bd9Sstevel@tonic-gate 	}
4663b9ccdc5aScth 	ndi_devi_exit(self, circ);
46647c478bd9Sstevel@tonic-gate }
46657c478bd9Sstevel@tonic-gate 
46667c478bd9Sstevel@tonic-gate /*
46677c478bd9Sstevel@tonic-gate  * this is the equivalent of pcm_get_intr using ra_allocs.
46687c478bd9Sstevel@tonic-gate  * returns -1 if failed, otherwise returns the allocated irq.
46697c478bd9Sstevel@tonic-gate  * The input request, if less than zero it means not a specific
46707c478bd9Sstevel@tonic-gate  * irq requested. If larger then 0 then we are requesting that specific
46717c478bd9Sstevel@tonic-gate  * irq
46727c478bd9Sstevel@tonic-gate  */
46737c478bd9Sstevel@tonic-gate int
46747c478bd9Sstevel@tonic-gate pcmcia_get_intr(dev_info_t *dip, int request)
46757c478bd9Sstevel@tonic-gate {
46767c478bd9Sstevel@tonic-gate 	ndi_ra_request_t req;
46777c478bd9Sstevel@tonic-gate 	uint64_t base;
46787c478bd9Sstevel@tonic-gate 	uint64_t len;
46797c478bd9Sstevel@tonic-gate 	int err;
46807c478bd9Sstevel@tonic-gate 
46817c478bd9Sstevel@tonic-gate 	bzero(&req, sizeof (req));
46827c478bd9Sstevel@tonic-gate 	base = 0;
46837c478bd9Sstevel@tonic-gate 	len = 1;
46847c478bd9Sstevel@tonic-gate 	if (request >= 0) {
46857c478bd9Sstevel@tonic-gate 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
46867c478bd9Sstevel@tonic-gate 		req.ra_len = 1;
46877c478bd9Sstevel@tonic-gate 		req.ra_addr = (uint64_t)request;
46887c478bd9Sstevel@tonic-gate 	}
46897c478bd9Sstevel@tonic-gate 
46907c478bd9Sstevel@tonic-gate 	req.ra_boundbase = 0;
46917c478bd9Sstevel@tonic-gate 	req.ra_boundlen = 0xffffffffUL;
46927c478bd9Sstevel@tonic-gate 	req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
46937c478bd9Sstevel@tonic-gate 
46947c478bd9Sstevel@tonic-gate 	err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR,
46957c478bd9Sstevel@tonic-gate 	    NDI_RA_PASS);
46967c478bd9Sstevel@tonic-gate 
46977c478bd9Sstevel@tonic-gate 	if (err == NDI_FAILURE) {
46987c478bd9Sstevel@tonic-gate 		return (-1);
46997c478bd9Sstevel@tonic-gate 	} else {
47007c478bd9Sstevel@tonic-gate 		return ((int)base);
47017c478bd9Sstevel@tonic-gate 	}
47027c478bd9Sstevel@tonic-gate }
47037c478bd9Sstevel@tonic-gate 
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate int
47067c478bd9Sstevel@tonic-gate pcmcia_return_intr(dev_info_t *dip, int request)
47077c478bd9Sstevel@tonic-gate {
47087c478bd9Sstevel@tonic-gate 	if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR,
47097c478bd9Sstevel@tonic-gate 	    NDI_RA_PASS)) == NDI_SUCCESS) {
47107c478bd9Sstevel@tonic-gate 		return (0);
47117c478bd9Sstevel@tonic-gate 	} else
47127c478bd9Sstevel@tonic-gate 		return (-1);
47137c478bd9Sstevel@tonic-gate 
47147c478bd9Sstevel@tonic-gate }
47157c478bd9Sstevel@tonic-gate 
47167c478bd9Sstevel@tonic-gate #ifdef sparc
47177c478bd9Sstevel@tonic-gate 
47187c478bd9Sstevel@tonic-gate int
47197c478bd9Sstevel@tonic-gate pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
47207c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
47217c478bd9Sstevel@tonic-gate {
47227c478bd9Sstevel@tonic-gate 
47237c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
47247c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
47257c478bd9Sstevel@tonic-gate 	int socket, ret;
47267c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter *adapt;
47277c478bd9Sstevel@tonic-gate 	set_irq_handler_t handler;
47287c478bd9Sstevel@tonic-gate 	struct intrspec *pispec;
47297c478bd9Sstevel@tonic-gate 
47307c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
47317c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
47327c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
47337c478bd9Sstevel@tonic-gate 		    "pcmcia_add_intr_impl() entered "
47347c478bd9Sstevel@tonic-gate 		    "dip=%p rdip=%p hdlp=%p \n",
47357c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
47367c478bd9Sstevel@tonic-gate 	}
47377c478bd9Sstevel@tonic-gate #endif
47387c478bd9Sstevel@tonic-gate 
47397c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
47407c478bd9Sstevel@tonic-gate 	socket = ppd->ppd_socket;
47417c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
47427c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
47437c478bd9Sstevel@tonic-gate 
47447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
47457c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
47467c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
47477c478bd9Sstevel@tonic-gate 		    " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n"
47487c478bd9Sstevel@tonic-gate 		    " ppd_intrspec=%p ls_inthandlers=%p\n",
47497c478bd9Sstevel@tonic-gate 		    ppd->ppd_flags, PPD_CARD_MULTI,
47507c478bd9Sstevel@tonic-gate 		    (void *) ppd->ppd_intrspec,
47517c478bd9Sstevel@tonic-gate 		    (void *)sockp->ls_inthandlers);
47527c478bd9Sstevel@tonic-gate 	}
47537c478bd9Sstevel@tonic-gate #endif
47547c478bd9Sstevel@tonic-gate 
47557c478bd9Sstevel@tonic-gate 	/*
47567c478bd9Sstevel@tonic-gate 	 * calculate IPL level when we support multiple levels
47577c478bd9Sstevel@tonic-gate 	 */
47587c478bd9Sstevel@tonic-gate 	pispec = ppd->ppd_intrspec;
47597c478bd9Sstevel@tonic-gate 	if (pispec == NULL) {
47607c478bd9Sstevel@tonic-gate 		sockp->ls_error = BAD_IRQ;
47617c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
47627c478bd9Sstevel@tonic-gate 	}
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate 	handler.socket = sockp->ls_socket;
47657c478bd9Sstevel@tonic-gate 	handler.irq = 0;	/* default case */
47667c478bd9Sstevel@tonic-gate 	handler.handler = (f_tt *)hdlp->ih_cb_func;
47677c478bd9Sstevel@tonic-gate 	handler.arg1 = hdlp->ih_cb_arg1;
47687c478bd9Sstevel@tonic-gate 	handler.arg2 = hdlp->ih_cb_arg2;
4769360e6f5eSmathue 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
47707c478bd9Sstevel@tonic-gate 
47717c478bd9Sstevel@tonic-gate 	/*
47727c478bd9Sstevel@tonic-gate 	 * check if multifunction and do the right thing
47737c478bd9Sstevel@tonic-gate 	 * we put an intercept in between the mfc handler and
47747c478bd9Sstevel@tonic-gate 	 * us so we can catch and process.  We might be able
47757c478bd9Sstevel@tonic-gate 	 * to optimize this depending on the card features
47767c478bd9Sstevel@tonic-gate 	 * (a future option).
47777c478bd9Sstevel@tonic-gate 	 */
47787c478bd9Sstevel@tonic-gate 	if (ppd->ppd_flags & PPD_CARD_MULTI) {
47797c478bd9Sstevel@tonic-gate 		inthandler_t *intr;
47807c478bd9Sstevel@tonic-gate 		/*
47817c478bd9Sstevel@tonic-gate 		 * note that the first function is a special
47827c478bd9Sstevel@tonic-gate 		 * case since it sets things up.  We fall through
47837c478bd9Sstevel@tonic-gate 		 * to the lower code and get the hardware set up.
47847c478bd9Sstevel@tonic-gate 		 * subsequent times we just lock the list and insert
47857c478bd9Sstevel@tonic-gate 		 * the handler and all is well.
47867c478bd9Sstevel@tonic-gate 		 */
47877c478bd9Sstevel@tonic-gate 		intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
47887c478bd9Sstevel@tonic-gate 		if (intr == NULL) {
47897c478bd9Sstevel@tonic-gate 			sockp->ls_error = BAD_IRQ;
47907c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
47917c478bd9Sstevel@tonic-gate 		}
47927c478bd9Sstevel@tonic-gate 		intr->intr = hdlp->ih_cb_func;
4793360e6f5eSmathue 		intr->handler_id = (uint_t)(uintptr_t)rdip;
47947c478bd9Sstevel@tonic-gate 		intr->arg1 = hdlp->ih_cb_arg1;
47957c478bd9Sstevel@tonic-gate 		intr->arg2 = hdlp->ih_cb_arg2;
47967c478bd9Sstevel@tonic-gate 		intr->socket = socket;
47977c478bd9Sstevel@tonic-gate 
47987c478bd9Sstevel@tonic-gate 		mutex_enter(&sockp->ls_ilock);
47997c478bd9Sstevel@tonic-gate 		if (sockp->ls_inthandlers == NULL) {
48007c478bd9Sstevel@tonic-gate 			intr->next = intr->prev = intr;
48017c478bd9Sstevel@tonic-gate 			sockp->ls_inthandlers = intr;
48027c478bd9Sstevel@tonic-gate 			sockp->ls_mfintr_dip = rdip;
48037c478bd9Sstevel@tonic-gate 			mutex_exit(&sockp->ls_ilock);
48047c478bd9Sstevel@tonic-gate 
48057c478bd9Sstevel@tonic-gate 			/*
48067c478bd9Sstevel@tonic-gate 			 * replace first function handler with
48077c478bd9Sstevel@tonic-gate 			 * the mfc handler
48087c478bd9Sstevel@tonic-gate 			 */
48097c478bd9Sstevel@tonic-gate 			handler.handler =  (f_tt *)pcmcia_mfc_intr;
48107c478bd9Sstevel@tonic-gate 			handler.arg1 = (caddr_t)sockp;
48117c478bd9Sstevel@tonic-gate 			handler.arg2 = NULL;
48127c478bd9Sstevel@tonic-gate 		} else {
48137c478bd9Sstevel@tonic-gate 			insque(intr, sockp->ls_inthandlers);
48147c478bd9Sstevel@tonic-gate 			mutex_exit(&sockp->ls_ilock);
48157c478bd9Sstevel@tonic-gate 
48167c478bd9Sstevel@tonic-gate 			pispec->intrspec_vec = sockp->ls_intr_vec;
48177c478bd9Sstevel@tonic-gate 			pispec->intrspec_pri = sockp->ls_intr_pri;
48187c478bd9Sstevel@tonic-gate 			hdlp->ih_pri = sockp->ls_intr_pri;
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
48217c478bd9Sstevel@tonic-gate 		}
48227c478bd9Sstevel@tonic-gate 	}
48237c478bd9Sstevel@tonic-gate 
48247c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
48257c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
48267c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n");
48277c478bd9Sstevel@tonic-gate 	}
48287c478bd9Sstevel@tonic-gate #endif
48297c478bd9Sstevel@tonic-gate 	pispec->intrspec_func = (uint32_t (*)())handler.handler;
48307c478bd9Sstevel@tonic-gate 
48317c478bd9Sstevel@tonic-gate 	/* set default IPL then check for override */
48327c478bd9Sstevel@tonic-gate 
48337c478bd9Sstevel@tonic-gate 	pispec->intrspec_pri = sockp->ls_intr_pri;
48347c478bd9Sstevel@tonic-gate 	hdlp->ih_pri = pispec->intrspec_pri;
48357c478bd9Sstevel@tonic-gate 
48367c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
48377c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
48387c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d"
48397c478bd9Sstevel@tonic-gate 		    " handler_id=0X%x handler=%p arg1=%p arg2=%p\n",
48407c478bd9Sstevel@tonic-gate 		    handler.socket, handler.irq,
48417c478bd9Sstevel@tonic-gate 		    handler.handler_id, (void *)handler.handler, handler.arg1,
48427c478bd9Sstevel@tonic-gate 		    handler.arg2);
48437c478bd9Sstevel@tonic-gate 	}
48447c478bd9Sstevel@tonic-gate #endif
48457c478bd9Sstevel@tonic-gate 
48467c478bd9Sstevel@tonic-gate 	if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
48477c478bd9Sstevel@tonic-gate 	    SUCCESS) {
48487c478bd9Sstevel@tonic-gate 		sockp->ls_error = ret;
48497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
48507c478bd9Sstevel@tonic-gate 	}
48517c478bd9Sstevel@tonic-gate 
48527c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
48537c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
48547c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
48557c478bd9Sstevel@tonic-gate 		    " iblk_cookie=%p idev_cookie=%p\n"
48567c478bd9Sstevel@tonic-gate 		    " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n",
48577c478bd9Sstevel@tonic-gate 		    (void *)handler.iblk_cookie,
48587c478bd9Sstevel@tonic-gate 		    (void *)handler.idev_cookie,
48597c478bd9Sstevel@tonic-gate 		    sockp->ls_flags, PCS_COOKIES_VALID);
48607c478bd9Sstevel@tonic-gate 	}
48617c478bd9Sstevel@tonic-gate #endif
48627c478bd9Sstevel@tonic-gate 
48637c478bd9Sstevel@tonic-gate 	if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
4864360e6f5eSmathue 		hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie;
48657c478bd9Sstevel@tonic-gate 		sockp->ls_iblk = *handler.iblk_cookie;
48667c478bd9Sstevel@tonic-gate 		sockp->ls_idev = *handler.idev_cookie;
48677c478bd9Sstevel@tonic-gate 		sockp->ls_flags |= PCS_COOKIES_VALID;
48687c478bd9Sstevel@tonic-gate 	}
48697c478bd9Sstevel@tonic-gate 
48707c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
48717c478bd9Sstevel@tonic-gate }
48727c478bd9Sstevel@tonic-gate 
48737c478bd9Sstevel@tonic-gate void
48747c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
48757c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
48767c478bd9Sstevel@tonic-gate {
48777c478bd9Sstevel@tonic-gate 
48787c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private *ppd;
48797c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t *sockp;
48807c478bd9Sstevel@tonic-gate 	clear_irq_handler_t handler;
48817c478bd9Sstevel@tonic-gate 	struct intrspec *pispec;
48827c478bd9Sstevel@tonic-gate 	int socket;
48837c478bd9Sstevel@tonic-gate 
48847c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
48857c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
48867c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered"
48877c478bd9Sstevel@tonic-gate 		    " dip=%p rdip=%p hdlp=%p\n",
48887c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
48897c478bd9Sstevel@tonic-gate 	}
48907c478bd9Sstevel@tonic-gate #endif
48917c478bd9Sstevel@tonic-gate 
48927c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
48937c478bd9Sstevel@tonic-gate 	socket = ppd->ppd_socket;
48947c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
48957c478bd9Sstevel@tonic-gate 	pispec = ppd->ppd_intrspec;
48967c478bd9Sstevel@tonic-gate 
48977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
48987c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
48997c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
49007c478bd9Sstevel@tonic-gate 		    " ls_inthandlers=%p ls_intrspec=%p\n",
49017c478bd9Sstevel@tonic-gate 		    (void *)sockp->ls_inthandlers,
49027c478bd9Sstevel@tonic-gate 		    (void *)&sockp->ls_intrspec);
49037c478bd9Sstevel@tonic-gate 	}
49047c478bd9Sstevel@tonic-gate #endif
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate 	/* first handle the multifunction case since it is simple */
49077c478bd9Sstevel@tonic-gate 	mutex_enter(&sockp->ls_ilock);
4908a195726fSgovinda 	if (sockp->ls_inthandlers != NULL) {
49097c478bd9Sstevel@tonic-gate 		/* we must be MFC */
49107c478bd9Sstevel@tonic-gate 		inthandler_t *intr;
49117c478bd9Sstevel@tonic-gate 		int remhandler = 0;
49127c478bd9Sstevel@tonic-gate 		intr = sockp->ls_inthandlers;
49137c478bd9Sstevel@tonic-gate 
49147c478bd9Sstevel@tonic-gate 		/* Check if there is only one handler left */
49157c478bd9Sstevel@tonic-gate 		if ((intr->next == intr) && (intr->prev == intr)) {
4916360e6f5eSmathue 			if (intr->handler_id == (unsigned)(uintptr_t)rdip) {
49177c478bd9Sstevel@tonic-gate 				sockp->ls_inthandlers = NULL;
49187c478bd9Sstevel@tonic-gate 				remhandler++;
49197c478bd9Sstevel@tonic-gate 				kmem_free(intr, sizeof (inthandler_t));
49207c478bd9Sstevel@tonic-gate 			}
49217c478bd9Sstevel@tonic-gate 		} else {
49227c478bd9Sstevel@tonic-gate 			inthandler_t *first;
49237c478bd9Sstevel@tonic-gate 			int done;
49247c478bd9Sstevel@tonic-gate 
49257c478bd9Sstevel@tonic-gate 			for (done = 0, first = intr; !done; intr = intr->next) {
49267c478bd9Sstevel@tonic-gate 				if (intr->next == first)
49277c478bd9Sstevel@tonic-gate 					done++;
4928360e6f5eSmathue 				if (intr->handler_id ==
4929360e6f5eSmathue 				    (unsigned)(uintptr_t)rdip) {
49307c478bd9Sstevel@tonic-gate 					done++;
49317c478bd9Sstevel@tonic-gate 
49327c478bd9Sstevel@tonic-gate 					/*
49337c478bd9Sstevel@tonic-gate 					 * If we're about to remove the
49347c478bd9Sstevel@tonic-gate 					 *	handler at the head of
49357c478bd9Sstevel@tonic-gate 					 *	the list, make the next
49367c478bd9Sstevel@tonic-gate 					 *	handler in line the head.
49377c478bd9Sstevel@tonic-gate 					 */
49387c478bd9Sstevel@tonic-gate 					if (sockp->ls_inthandlers == intr)
49397c478bd9Sstevel@tonic-gate 						sockp->ls_inthandlers =
49407c478bd9Sstevel@tonic-gate 						    intr->next;
49417c478bd9Sstevel@tonic-gate 
49427c478bd9Sstevel@tonic-gate 					remque(intr);
49437c478bd9Sstevel@tonic-gate 					kmem_free(intr, sizeof (inthandler_t));
49447c478bd9Sstevel@tonic-gate 					break;
49457c478bd9Sstevel@tonic-gate 				} /* handler_id */
49467c478bd9Sstevel@tonic-gate 			} /* for */
49477c478bd9Sstevel@tonic-gate 		} /* intr->next */
49487c478bd9Sstevel@tonic-gate 
49497c478bd9Sstevel@tonic-gate 		if (!remhandler) {
49507c478bd9Sstevel@tonic-gate 			mutex_exit(&sockp->ls_ilock);
49517c478bd9Sstevel@tonic-gate 			return;
49527c478bd9Sstevel@tonic-gate 		}
49537c478bd9Sstevel@tonic-gate 
49547c478bd9Sstevel@tonic-gate 		/* need to get the dip that was used to add the handler */
49557c478bd9Sstevel@tonic-gate 		rdip = sockp->ls_mfintr_dip;
49567c478bd9Sstevel@tonic-gate 	}
49577c478bd9Sstevel@tonic-gate 
4958a195726fSgovinda 	mutex_exit(&sockp->ls_ilock);
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
49617c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
49627c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
49637c478bd9Sstevel@tonic-gate 		    " pispec=%p rdip=%p\n",
49647c478bd9Sstevel@tonic-gate 		    (void *)pispec, (void *)rdip);
49657c478bd9Sstevel@tonic-gate 	}
49667c478bd9Sstevel@tonic-gate #endif
49677c478bd9Sstevel@tonic-gate 
49687c478bd9Sstevel@tonic-gate 	handler.socket = sockp->ls_socket;
4969360e6f5eSmathue 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
49707c478bd9Sstevel@tonic-gate 	handler.handler = (f_tt *)pispec->intrspec_func;
49717c478bd9Sstevel@tonic-gate 	CLEAR_IRQ(sockp->ls_if, dip, &handler);
49727c478bd9Sstevel@tonic-gate }
49737c478bd9Sstevel@tonic-gate 
49747c478bd9Sstevel@tonic-gate 
49757c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */
49767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
49777c478bd9Sstevel@tonic-gate int
49787c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
49797c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
49807c478bd9Sstevel@tonic-gate {
4981a195726fSgovinda 	int	ret = DDI_SUCCESS;
49827c478bd9Sstevel@tonic-gate 
49837c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
49847c478bd9Sstevel@tonic-gate 	if (pcmcia_debug) {
49857c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n",
49867c478bd9Sstevel@tonic-gate 		    (int)intr_op);
49877c478bd9Sstevel@tonic-gate 	}
49887c478bd9Sstevel@tonic-gate #endif
49897c478bd9Sstevel@tonic-gate 
49907c478bd9Sstevel@tonic-gate 	switch (intr_op) {
49917c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
4992a195726fSgovinda 		*(int *)result = DDI_INTR_FLAG_LEVEL;
49937c478bd9Sstevel@tonic-gate 		break;
49947c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
49957c478bd9Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
49967c478bd9Sstevel@tonic-gate 		break;
49977c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
49987c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
49997c478bd9Sstevel@tonic-gate 		break;
50007c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
50017c478bd9Sstevel@tonic-gate 		break;
50027c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
50037c478bd9Sstevel@tonic-gate 		if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS)
50047c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
50057c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_pri;
50067c478bd9Sstevel@tonic-gate 		pcmcia_remove_intr_impl(dip, rdip, hdlp);
50077c478bd9Sstevel@tonic-gate 		break;
50087c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETPRI:
50097c478bd9Sstevel@tonic-gate 		break;
50107c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
50117c478bd9Sstevel@tonic-gate 		ret = pcmcia_add_intr_impl(dip, rdip, hdlp);
50127c478bd9Sstevel@tonic-gate 		break;
50137c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
50147c478bd9Sstevel@tonic-gate 		pcmcia_remove_intr_impl(dip, rdip, hdlp);
50157c478bd9Sstevel@tonic-gate 		break;
50167c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
50177c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
50187c478bd9Sstevel@tonic-gate 		break;
50197c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
50207c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
5021a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
50227c478bd9Sstevel@tonic-gate 		break;
50237c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
50247c478bd9Sstevel@tonic-gate 		/* PCI nexus driver supports only fixed interrupts */
5025a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
50267c478bd9Sstevel@tonic-gate 		    DDI_INTR_TYPE_FIXED : 0;
50277c478bd9Sstevel@tonic-gate 		break;
50287c478bd9Sstevel@tonic-gate 	default:
50297c478bd9Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
50307c478bd9Sstevel@tonic-gate 		break;
50317c478bd9Sstevel@tonic-gate 	}
50327c478bd9Sstevel@tonic-gate 
50337c478bd9Sstevel@tonic-gate 	return (ret);
50347c478bd9Sstevel@tonic-gate }
50357c478bd9Sstevel@tonic-gate 
50367c478bd9Sstevel@tonic-gate #elif defined(__x86) || defined(__amd64)
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate static struct intrspec	*pcmcia_intr_get_ispec(dev_info_t *, int,
50397c478bd9Sstevel@tonic-gate 			    pcmcia_logical_socket_t **);
50407c478bd9Sstevel@tonic-gate static struct intrspec	*pcmcia_intr_add_isr(dev_info_t *, dev_info_t *,
50417c478bd9Sstevel@tonic-gate 			    ddi_intr_handle_impl_t *);
50427c478bd9Sstevel@tonic-gate static int		pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *,
50437c478bd9Sstevel@tonic-gate 			    ddi_intr_handle_impl_t *);
50447c478bd9Sstevel@tonic-gate static void		pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *,
50457c478bd9Sstevel@tonic-gate 			    ddi_intr_handle_impl_t *);
50467c478bd9Sstevel@tonic-gate static void		pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *,
50477c478bd9Sstevel@tonic-gate 			    ddi_intr_handle_impl_t *);
50487c478bd9Sstevel@tonic-gate 
50497c478bd9Sstevel@tonic-gate /*
50507c478bd9Sstevel@tonic-gate  * pcmcia_intr_get_ispec:
50517c478bd9Sstevel@tonic-gate  *	This is mostly copied from older 'pcmcia_get_intrspec' function
50527c478bd9Sstevel@tonic-gate  */
50537c478bd9Sstevel@tonic-gate static struct intrspec *
50547c478bd9Sstevel@tonic-gate pcmcia_intr_get_ispec(dev_info_t *rdip, int inum,
50557c478bd9Sstevel@tonic-gate     pcmcia_logical_socket_t **sockp)
50567c478bd9Sstevel@tonic-gate {
50577c478bd9Sstevel@tonic-gate 	int				socket;
50587c478bd9Sstevel@tonic-gate 	struct intrspec			*intrspec;
50597c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private	*ppd;
50607c478bd9Sstevel@tonic-gate 
50617c478bd9Sstevel@tonic-gate 	if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip,
50627c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "interrupts", -1) < 0))
50637c478bd9Sstevel@tonic-gate 		return (NULL);
50647c478bd9Sstevel@tonic-gate 
50657c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
50667c478bd9Sstevel@tonic-gate 	if (ppd == NULL || ppd->ppd_intrspec == NULL)
50677c478bd9Sstevel@tonic-gate 		return (NULL);
50687c478bd9Sstevel@tonic-gate 
50697c478bd9Sstevel@tonic-gate 	if ((socket = ppd->ppd_socket) < 0)
50707c478bd9Sstevel@tonic-gate 		return (NULL);
50717c478bd9Sstevel@tonic-gate 
50727c478bd9Sstevel@tonic-gate 	if ((*sockp = pcmcia_sockets[socket]) == NULL)
50737c478bd9Sstevel@tonic-gate 		return (NULL);
50747c478bd9Sstevel@tonic-gate 
50757c478bd9Sstevel@tonic-gate 	intrspec = ppd->ppd_intrspec;
50767c478bd9Sstevel@tonic-gate 	if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0)
50777c478bd9Sstevel@tonic-gate 		intrspec->intrspec_vec = (*sockp)->ls_intr_vec;
50787c478bd9Sstevel@tonic-gate 
50797c478bd9Sstevel@tonic-gate 	return (intrspec);
50807c478bd9Sstevel@tonic-gate }
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate static struct intrspec *
50837c478bd9Sstevel@tonic-gate pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip,
50847c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
50857c478bd9Sstevel@tonic-gate {
50867c478bd9Sstevel@tonic-gate 	int				socket;
50877c478bd9Sstevel@tonic-gate 	struct intrspec			*ispecp;
50887c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter		*adapt;
50897c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t		*sockp;
50907c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private	*ppd;
50917c478bd9Sstevel@tonic-gate 
50927c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
50937c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
50947c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_add_isr: "
50957c478bd9Sstevel@tonic-gate 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
50967c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
50977c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
51007c478bd9Sstevel@tonic-gate 	socket = ppd->ppd_socket;
51017c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
51027c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
51037c478bd9Sstevel@tonic-gate 
51047c478bd9Sstevel@tonic-gate 	ispecp = ppd->ppd_intrspec;
51057c478bd9Sstevel@tonic-gate 	if (ispecp == NULL) {
51067c478bd9Sstevel@tonic-gate 		sockp->ls_error = BAD_IRQ;
51077c478bd9Sstevel@tonic-gate 		return (ispecp);
51087c478bd9Sstevel@tonic-gate 	}
51097c478bd9Sstevel@tonic-gate 
51107c478bd9Sstevel@tonic-gate 	/*
51117c478bd9Sstevel@tonic-gate 	 * check if multifunction and do the right thing
51127c478bd9Sstevel@tonic-gate 	 * we put an intercept in between the mfc handler and us so we can
51137c478bd9Sstevel@tonic-gate 	 * catch and process. We might be able to optimize this depending
51147c478bd9Sstevel@tonic-gate 	 * on the card features (a future option).
51157c478bd9Sstevel@tonic-gate 	 */
51167c478bd9Sstevel@tonic-gate 	if (ppd->ppd_flags & PPD_CARD_MULTI &&
51177c478bd9Sstevel@tonic-gate 	    hdlp->ih_cb_func != pcmcia_mfc_intr) {
51187c478bd9Sstevel@tonic-gate 		inthandler_t *intr;
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 		/*
51217c478bd9Sstevel@tonic-gate 		 * note that the first function is a special case since it
51227c478bd9Sstevel@tonic-gate 		 * sets things up.  We fall through to the lower code and
51237c478bd9Sstevel@tonic-gate 		 * get the hardware set up. Subsequent times we just lock
51247c478bd9Sstevel@tonic-gate 		 * the list and insert the handler and all is well.
51257c478bd9Sstevel@tonic-gate 		 */
51267c478bd9Sstevel@tonic-gate 		intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
51277c478bd9Sstevel@tonic-gate 		if (intr == NULL) {
51287c478bd9Sstevel@tonic-gate 			sockp->ls_error = BAD_IRQ;
51297c478bd9Sstevel@tonic-gate 			return (NULL);
51307c478bd9Sstevel@tonic-gate 		}
51317c478bd9Sstevel@tonic-gate 
51327c478bd9Sstevel@tonic-gate 		intr->intr = (uint32_t (*)())hdlp->ih_cb_func;
51337c478bd9Sstevel@tonic-gate 		intr->handler_id = (uint32_t)(uintptr_t)rdip;
51347c478bd9Sstevel@tonic-gate 		intr->arg1 = hdlp->ih_cb_arg1;
51357c478bd9Sstevel@tonic-gate 		intr->arg2 = hdlp->ih_cb_arg2;
51367c478bd9Sstevel@tonic-gate 		intr->socket = socket;
51377c478bd9Sstevel@tonic-gate 		mutex_enter(&sockp->ls_ilock);
51387c478bd9Sstevel@tonic-gate 		if (sockp->ls_inthandlers == NULL) {
51397c478bd9Sstevel@tonic-gate 			intr->next = intr->prev = intr;
51407c478bd9Sstevel@tonic-gate 			sockp->ls_inthandlers = intr;
51417c478bd9Sstevel@tonic-gate 			sockp->ls_mfintr_dip = rdip;
51427c478bd9Sstevel@tonic-gate 		} else {
51437c478bd9Sstevel@tonic-gate 			insque(intr, sockp->ls_inthandlers);
51447c478bd9Sstevel@tonic-gate 		}
51457c478bd9Sstevel@tonic-gate 		mutex_exit(&sockp->ls_ilock);
51467c478bd9Sstevel@tonic-gate 		return (ispecp);
51477c478bd9Sstevel@tonic-gate 	}
51487c478bd9Sstevel@tonic-gate 
51497c478bd9Sstevel@tonic-gate 	/*
51507c478bd9Sstevel@tonic-gate 	 * Do we need to allocate an IRQ at this point or not?
51517c478bd9Sstevel@tonic-gate 	 */
51527c478bd9Sstevel@tonic-gate 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
51537c478bd9Sstevel@tonic-gate 		int i, irq;
51547c478bd9Sstevel@tonic-gate 
51557c478bd9Sstevel@tonic-gate 		/*
51567c478bd9Sstevel@tonic-gate 		 * this adapter needs IRQ allocations
51577c478bd9Sstevel@tonic-gate 		 * this is only necessary if it is the first function on the
51587c478bd9Sstevel@tonic-gate 		 * card being setup. The socket will keep the allocation info
51597c478bd9Sstevel@tonic-gate 		 */
51607c478bd9Sstevel@tonic-gate 		/* all functions use same intrspec except mfc handler */
51617c478bd9Sstevel@tonic-gate 		if (hdlp->ih_cb_func == pcmcia_mfc_intr) {
51627c478bd9Sstevel@tonic-gate 			/*
51637c478bd9Sstevel@tonic-gate 			 * We treat this special in order to allow things to
51647c478bd9Sstevel@tonic-gate 			 * work properly for MFC cards. The intrspec for the
51657c478bd9Sstevel@tonic-gate 			 * mfc dispatcher is intercepted and taken from the
51667c478bd9Sstevel@tonic-gate 			 * logical socket in order to not be trying to
51677c478bd9Sstevel@tonic-gate 			 * multiplex the meaning when ENABLE is called.
51687c478bd9Sstevel@tonic-gate 			 */
51697c478bd9Sstevel@tonic-gate 			ispecp = &sockp->ls_intrspec;
51707a364d25Sschwartz 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
51717c478bd9Sstevel@tonic-gate 		}
51727c478bd9Sstevel@tonic-gate 
51737c478bd9Sstevel@tonic-gate 		if (adapt->pca_flags & PCA_IRQ_ISA) {
51747c478bd9Sstevel@tonic-gate 			for (irq = -1, i = 1; irq == -1 && i < 16; i++) {
51757c478bd9Sstevel@tonic-gate 				/* find available and usable IRQ level */
51767c478bd9Sstevel@tonic-gate 				if (adapt->pca_avail_intr & (1 << i))
51777c478bd9Sstevel@tonic-gate 					irq = pcmcia_get_intr(dip, i);
51787c478bd9Sstevel@tonic-gate 			}
51797c478bd9Sstevel@tonic-gate 		}
51807c478bd9Sstevel@tonic-gate 		if (irq < 0) {
51817c478bd9Sstevel@tonic-gate 			sockp->ls_error = NO_RESOURCE;
51827c478bd9Sstevel@tonic-gate 			return (NULL);
51837c478bd9Sstevel@tonic-gate 		}
51847c478bd9Sstevel@tonic-gate 		hdlp->ih_vector = sockp->ls_intr_vec = irq;
51857c478bd9Sstevel@tonic-gate 
51867c478bd9Sstevel@tonic-gate 
51877c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
51887c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
51897c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "allocated irq=%x\n", irq);
51907c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
51917c478bd9Sstevel@tonic-gate 
51927c478bd9Sstevel@tonic-gate 		ispecp->intrspec_vec = sockp->ls_intr_vec;
51937c478bd9Sstevel@tonic-gate 		ispecp->intrspec_pri = sockp->ls_intr_pri;
51947c478bd9Sstevel@tonic-gate 		return (ispecp);
51957c478bd9Sstevel@tonic-gate 	}
51967c478bd9Sstevel@tonic-gate 
51977c478bd9Sstevel@tonic-gate 	if (ispecp->intrspec_func != NULL)
51987c478bd9Sstevel@tonic-gate 		ispecp->intrspec_func = hdlp->ih_cb_func;
51997c478bd9Sstevel@tonic-gate 
52007c478bd9Sstevel@tonic-gate 	/* set default IPL then check for override */
52017c478bd9Sstevel@tonic-gate 	ispecp->intrspec_pri = sockp->ls_intr_pri;
52027c478bd9Sstevel@tonic-gate 	return (ispecp);
52037c478bd9Sstevel@tonic-gate }
52047c478bd9Sstevel@tonic-gate 
52057c478bd9Sstevel@tonic-gate 
52067c478bd9Sstevel@tonic-gate static int
52077c478bd9Sstevel@tonic-gate pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip,
52087c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
52097c478bd9Sstevel@tonic-gate {
52107c478bd9Sstevel@tonic-gate 	int				socket, ret;
52117c478bd9Sstevel@tonic-gate 	int				irq = 0;	/* default case */
52127c478bd9Sstevel@tonic-gate 	dev_info_t			*parent = ddi_root_node();
52137c478bd9Sstevel@tonic-gate 	struct intrspec			*ispecp;
52147c478bd9Sstevel@tonic-gate 	set_irq_handler_t		handler;
52157c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter		*adapt;
52167c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t		*sockp;
52177c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private	*ppd;
52187c478bd9Sstevel@tonic-gate 
52197c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
52207c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
52217c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_enable_isr: "
52227c478bd9Sstevel@tonic-gate 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
52237c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
52247c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
52277c478bd9Sstevel@tonic-gate 	socket = ppd->ppd_socket;
52287c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
52297c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
52307c478bd9Sstevel@tonic-gate 
52317c478bd9Sstevel@tonic-gate 	ispecp = ppd->ppd_intrspec;
52327c478bd9Sstevel@tonic-gate 	ASSERT(ispecp);
52337c478bd9Sstevel@tonic-gate 
52347c478bd9Sstevel@tonic-gate 	mutex_enter(&sockp->ls_ilock);
52357c478bd9Sstevel@tonic-gate 	if ((sockp->ls_inthandlers != NULL) &&
52367a364d25Sschwartz 	    ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
52377a364d25Sschwartz 	    &sockp->ls_intrspec) {
52387c478bd9Sstevel@tonic-gate 		inthandler_t *intr = sockp->ls_inthandlers;
52397c478bd9Sstevel@tonic-gate 
52407c478bd9Sstevel@tonic-gate 		ASSERT(ppd->ppd_flags & PPD_CARD_MULTI);
52417c478bd9Sstevel@tonic-gate 
52427c478bd9Sstevel@tonic-gate 		/* Only one handler. So, call ddi_add_intr on it */
52437c478bd9Sstevel@tonic-gate 		if ((intr->next == intr) && (intr->prev == intr)) {
52447c478bd9Sstevel@tonic-gate 			hdlp->ih_cb_func = pcmcia_mfc_intr;
52457c478bd9Sstevel@tonic-gate 			hdlp->ih_cb_arg1 = (caddr_t)sockp;
52467c478bd9Sstevel@tonic-gate 			hdlp->ih_cb_arg2 = NULL;
52477c478bd9Sstevel@tonic-gate 
52487c478bd9Sstevel@tonic-gate 			ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->
52497c478bd9Sstevel@tonic-gate 			    bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE,
52507c478bd9Sstevel@tonic-gate 			    hdlp, NULL);
52517c478bd9Sstevel@tonic-gate 
52527c478bd9Sstevel@tonic-gate 			if (ret == DDI_FAILURE) {
52537c478bd9Sstevel@tonic-gate 				sockp->ls_inthandlers = NULL;
52547c478bd9Sstevel@tonic-gate 				kmem_free(intr, sizeof (inthandler_t));
52557c478bd9Sstevel@tonic-gate 				sockp->ls_error = BAD_IRQ;
52567c478bd9Sstevel@tonic-gate 				mutex_exit(&sockp->ls_ilock);
52577c478bd9Sstevel@tonic-gate 				return (ret);
52587c478bd9Sstevel@tonic-gate 			}
52597c478bd9Sstevel@tonic-gate 		}
52607c478bd9Sstevel@tonic-gate 		mutex_exit(&sockp->ls_ilock);
52617c478bd9Sstevel@tonic-gate 		hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec;
52627c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = sockp->ls_intr_pri;
5263abdbd06dSagiri 		sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
52647c478bd9Sstevel@tonic-gate 		    sockp->ls_intr_pri;
52657c478bd9Sstevel@tonic-gate 		sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector;
52667c478bd9Sstevel@tonic-gate 		sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
52677c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
52687c478bd9Sstevel@tonic-gate 	}
52697c478bd9Sstevel@tonic-gate 	mutex_exit(&sockp->ls_ilock);
52707c478bd9Sstevel@tonic-gate 
52717c478bd9Sstevel@tonic-gate 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
52727c478bd9Sstevel@tonic-gate 		if (hdlp->ih_cb_func == pcmcia_mfc_intr)
52737c478bd9Sstevel@tonic-gate 			ispecp = (struct intrspec *)&sockp->ls_intrspec;
52747c478bd9Sstevel@tonic-gate 
52757c478bd9Sstevel@tonic-gate 		/* XXX: remove it later as this is done in _add_isr as well */
52767c478bd9Sstevel@tonic-gate 		ispecp->intrspec_vec = sockp->ls_intr_vec;
52777c478bd9Sstevel@tonic-gate 		ispecp->intrspec_pri = sockp->ls_intr_pri;
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate 		/* Enable interrupts */
52807c478bd9Sstevel@tonic-gate 		ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
52817c478bd9Sstevel@tonic-gate 		    parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL);
52827c478bd9Sstevel@tonic-gate 
5283abdbd06dSagiri 		sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
52847c478bd9Sstevel@tonic-gate 		    sockp->ls_intr_pri;
52857c478bd9Sstevel@tonic-gate 		sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec;
52867c478bd9Sstevel@tonic-gate 		sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
52877c478bd9Sstevel@tonic-gate 
52887c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS)
52897c478bd9Sstevel@tonic-gate 			sockp->ls_error = BAD_IRQ;
52907c478bd9Sstevel@tonic-gate 		return (ret);
52917c478bd9Sstevel@tonic-gate 	}
52927c478bd9Sstevel@tonic-gate 
52937c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
52947c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
52957c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n");
52967c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
52977c478bd9Sstevel@tonic-gate 
52987c478bd9Sstevel@tonic-gate 	handler.socket = sockp->ls_socket;
52997c478bd9Sstevel@tonic-gate 	handler.irq = irq;
53007c478bd9Sstevel@tonic-gate 	handler.handler = (f_tt *)hdlp->ih_cb_func;
53017c478bd9Sstevel@tonic-gate 	handler.arg1 = hdlp->ih_cb_arg1;
53027c478bd9Sstevel@tonic-gate 	handler.arg2 = hdlp->ih_cb_arg2;
53037c478bd9Sstevel@tonic-gate 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
53047c478bd9Sstevel@tonic-gate 	if (ispecp->intrspec_func != NULL)
53057c478bd9Sstevel@tonic-gate 		ispecp->intrspec_func = hdlp->ih_cb_func;
53067c478bd9Sstevel@tonic-gate 
53077c478bd9Sstevel@tonic-gate 	/* set default IPL then check for override */
53087c478bd9Sstevel@tonic-gate 	ispecp->intrspec_pri = sockp->ls_intr_pri;
53097c478bd9Sstevel@tonic-gate 
53107c478bd9Sstevel@tonic-gate 	if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
53117c478bd9Sstevel@tonic-gate 	    SUCCESS) {
53127c478bd9Sstevel@tonic-gate 		sockp->ls_error = ret;
53137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
53147c478bd9Sstevel@tonic-gate 	}
53157c478bd9Sstevel@tonic-gate 	ispecp->intrspec_func = hdlp->ih_cb_func;
53167c478bd9Sstevel@tonic-gate 	if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
53177c478bd9Sstevel@tonic-gate 		sockp->ls_iblk = *handler.iblk_cookie;
53187c478bd9Sstevel@tonic-gate 		sockp->ls_idev = *handler.idev_cookie;
53197c478bd9Sstevel@tonic-gate 		sockp->ls_flags |= PCS_COOKIES_VALID;
53207c478bd9Sstevel@tonic-gate 	}
53217c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
53227c478bd9Sstevel@tonic-gate }
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate /* ARGSUSED */
53257c478bd9Sstevel@tonic-gate static void
53267c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip,
53277c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
53287c478bd9Sstevel@tonic-gate {
53297c478bd9Sstevel@tonic-gate 	int				done, remhandler = 0;
53307c478bd9Sstevel@tonic-gate 	inthandler_t			*intr, *first;
53317c478bd9Sstevel@tonic-gate 	struct intrspec			*ispecp;
53327c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t		*sockp;
53337c478bd9Sstevel@tonic-gate 
53347c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
53357c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
53367c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_remove_isr: "
53377c478bd9Sstevel@tonic-gate 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
53387c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
53397c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
53407c478bd9Sstevel@tonic-gate 
53417c478bd9Sstevel@tonic-gate 	ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
53427c478bd9Sstevel@tonic-gate 	ASSERT(ispecp);
53437c478bd9Sstevel@tonic-gate 
53447c478bd9Sstevel@tonic-gate 	/* first handle the multifunction case since it is simple */
53457c478bd9Sstevel@tonic-gate 	mutex_enter(&sockp->ls_ilock);
53467c478bd9Sstevel@tonic-gate 	if (sockp->ls_inthandlers != NULL &&
53477a364d25Sschwartz 	    ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
53487a364d25Sschwartz 	    &sockp->ls_intrspec) {
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate 		intr = sockp->ls_inthandlers;
53517c478bd9Sstevel@tonic-gate 
53527c478bd9Sstevel@tonic-gate 		/* Check if there is only one handler left */
53537c478bd9Sstevel@tonic-gate 		if ((intr->next == intr) && (intr->prev == intr)) {
53547c478bd9Sstevel@tonic-gate 			if (intr->handler_id == (uint32_t)(uintptr_t)rdip) {
53557c478bd9Sstevel@tonic-gate 				sockp->ls_inthandlers = NULL;
53567c478bd9Sstevel@tonic-gate 				remhandler++;
53577c478bd9Sstevel@tonic-gate 				kmem_free(intr, sizeof (inthandler_t));
53587c478bd9Sstevel@tonic-gate 			}
53597c478bd9Sstevel@tonic-gate 
53607c478bd9Sstevel@tonic-gate 		} else {
53617c478bd9Sstevel@tonic-gate 			for (done = 0, first = intr; !done; intr = intr->next) {
53627c478bd9Sstevel@tonic-gate 				if (intr->next == first)
53637c478bd9Sstevel@tonic-gate 					done++;
53647c478bd9Sstevel@tonic-gate 				if (intr->handler_id ==
53657c478bd9Sstevel@tonic-gate 				    (uint32_t)(uintptr_t)rdip) {
53667c478bd9Sstevel@tonic-gate 					done++;
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate 					/*
53697c478bd9Sstevel@tonic-gate 					 * If we're about to remove the handler
53707c478bd9Sstevel@tonic-gate 					 * at the head of the list, make the
53717c478bd9Sstevel@tonic-gate 					 * next handler in line the head.
53727c478bd9Sstevel@tonic-gate 					 */
53737c478bd9Sstevel@tonic-gate 					if (sockp->ls_inthandlers == intr)
53747c478bd9Sstevel@tonic-gate 					    sockp->ls_inthandlers = intr->next;
53757c478bd9Sstevel@tonic-gate 
53767c478bd9Sstevel@tonic-gate 					remque(intr);
53777c478bd9Sstevel@tonic-gate 					kmem_free(intr, sizeof (inthandler_t));
53787c478bd9Sstevel@tonic-gate 					break;
53797c478bd9Sstevel@tonic-gate 				} /* handler_id */
53807c478bd9Sstevel@tonic-gate 			} /* end of for */
53817c478bd9Sstevel@tonic-gate 		} /* end of if intr->next */
53827c478bd9Sstevel@tonic-gate 
53837c478bd9Sstevel@tonic-gate 		if (!remhandler) {
53847c478bd9Sstevel@tonic-gate 			mutex_exit(&sockp->ls_ilock);
53857c478bd9Sstevel@tonic-gate 			return;
53867c478bd9Sstevel@tonic-gate 		}
53877c478bd9Sstevel@tonic-gate 	}
53887c478bd9Sstevel@tonic-gate 	mutex_exit(&sockp->ls_ilock);
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate 	if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) {
53917c478bd9Sstevel@tonic-gate 		sockp->ls_intr_vec = 0;
53927c478bd9Sstevel@tonic-gate 		ispecp->intrspec_vec = 0;
53937c478bd9Sstevel@tonic-gate 	}
53947c478bd9Sstevel@tonic-gate }
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate 
53977c478bd9Sstevel@tonic-gate static void
53987c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip,
53997c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
54007c478bd9Sstevel@tonic-gate {
54017c478bd9Sstevel@tonic-gate 	int				socket, ret;
54027c478bd9Sstevel@tonic-gate 	dev_info_t			*parent;
54037c478bd9Sstevel@tonic-gate 	struct intrspec			*ispecp;
54047c478bd9Sstevel@tonic-gate 	clear_irq_handler_t		handler;
54057c478bd9Sstevel@tonic-gate 	struct pcmcia_adapter		*adapt;
54067c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t		*sockp;
54077c478bd9Sstevel@tonic-gate 	struct pcmcia_parent_private	*ppd;
54087a364d25Sschwartz 	ihdl_plat_t			*ihdl_plat_datap =
54097a364d25Sschwartz 					    (ihdl_plat_t *)hdlp->ih_private;
54107c478bd9Sstevel@tonic-gate 
54117c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
54127c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
54137c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
54147c478bd9Sstevel@tonic-gate 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
54157c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, (void *)hdlp);
54167c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
54177c478bd9Sstevel@tonic-gate 
54187c478bd9Sstevel@tonic-gate 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
54197c478bd9Sstevel@tonic-gate 	socket = ppd->ppd_socket;
54207c478bd9Sstevel@tonic-gate 	sockp = pcmcia_sockets[socket];
54217c478bd9Sstevel@tonic-gate 	adapt = sockp->ls_adapter;
54227c478bd9Sstevel@tonic-gate 	ispecp = ppd->ppd_intrspec;
54237c478bd9Sstevel@tonic-gate 	ASSERT(ispecp);
54247c478bd9Sstevel@tonic-gate 
54257c478bd9Sstevel@tonic-gate 	mutex_enter(&sockp->ls_ilock);
54267c478bd9Sstevel@tonic-gate 	if (sockp->ls_inthandlers != NULL &&
54277a364d25Sschwartz 	    ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) {
54287c478bd9Sstevel@tonic-gate 		inthandler_t	*intr = sockp->ls_inthandlers;
54297c478bd9Sstevel@tonic-gate 
54307c478bd9Sstevel@tonic-gate 		/* Check if there is only one handler left */
54317c478bd9Sstevel@tonic-gate 		if ((intr->next == intr) && (intr->prev == intr)) {
54327c478bd9Sstevel@tonic-gate 			if (intr->handler_id != (uint32_t)(uintptr_t)rdip)
54337c478bd9Sstevel@tonic-gate 				/*
54347c478bd9Sstevel@tonic-gate 				 * need to get the dip that was
54357c478bd9Sstevel@tonic-gate 				 * used to add the handler
54367c478bd9Sstevel@tonic-gate 				 */
54377c478bd9Sstevel@tonic-gate 				rdip = sockp->ls_mfintr_dip;
54387c478bd9Sstevel@tonic-gate 				ispecp = (struct intrspec *)&sockp->ls_intrspec;
54397c478bd9Sstevel@tonic-gate 		} else {
54407c478bd9Sstevel@tonic-gate 			/* Don't call cleanup if list still has members */
54417c478bd9Sstevel@tonic-gate 			mutex_exit(&sockp->ls_ilock);
54427c478bd9Sstevel@tonic-gate 			return;
54437c478bd9Sstevel@tonic-gate 		}
54447c478bd9Sstevel@tonic-gate 	}
54457c478bd9Sstevel@tonic-gate 	mutex_exit(&sockp->ls_ilock);
54467c478bd9Sstevel@tonic-gate 
54477a364d25Sschwartz 	if (ihdl_plat_datap->ip_ispecp ==
54487c478bd9Sstevel@tonic-gate 	    (struct intrspec *)&sockp->ls_intrspec)
54497a364d25Sschwartz 		ispecp = ihdl_plat_datap->ip_ispecp;
54507c478bd9Sstevel@tonic-gate 
54517c478bd9Sstevel@tonic-gate 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
54527c478bd9Sstevel@tonic-gate 		ret = ispecp->intrspec_vec;
54537c478bd9Sstevel@tonic-gate 		parent = ddi_root_node();
54547c478bd9Sstevel@tonic-gate 		ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
54557c478bd9Sstevel@tonic-gate 		    parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL);
54567c478bd9Sstevel@tonic-gate 		(void) pcmcia_return_intr(dip, hdlp->ih_vector);
54577c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
54587c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
54597c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
54607c478bd9Sstevel@tonic-gate 			    "INTROP_DISABLE returned %x\n", ret);
54617c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
54627c478bd9Sstevel@tonic-gate 	} else {
54637c478bd9Sstevel@tonic-gate 		handler.socket = sockp->ls_socket;
54647c478bd9Sstevel@tonic-gate 		handler.handler_id = (uint32_t)(uintptr_t)rdip;
54657c478bd9Sstevel@tonic-gate 		handler.handler = (f_tt *)ispecp->intrspec_func;
54667c478bd9Sstevel@tonic-gate 		ret = CLEAR_IRQ(sockp->ls_if, dip, &handler);
54677c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
54687c478bd9Sstevel@tonic-gate 		if (pcmcia_debug)
54697c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
54707c478bd9Sstevel@tonic-gate 			    "CLEAR_IRQ returned %x\n", ret);
54717c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
54727c478bd9Sstevel@tonic-gate 	}
54737c478bd9Sstevel@tonic-gate }
54747c478bd9Sstevel@tonic-gate 
54757c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */
54767c478bd9Sstevel@tonic-gate int
54777c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
54787c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
54797c478bd9Sstevel@tonic-gate {
54807c478bd9Sstevel@tonic-gate 	struct intrspec		*ispecp;
54817c478bd9Sstevel@tonic-gate 	pcmcia_logical_socket_t	*sockp;
54827c478bd9Sstevel@tonic-gate 
54837c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG)
54847c478bd9Sstevel@tonic-gate 	if (pcmcia_debug)
54857c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pcmcia_intr_ops: "
54867c478bd9Sstevel@tonic-gate 		    "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n",
54877c478bd9Sstevel@tonic-gate 		    (void *)dip, (void *)rdip, intr_op, (void *)hdlp);
54887c478bd9Sstevel@tonic-gate #endif	/* PCMCIA_DEBUG */
54897c478bd9Sstevel@tonic-gate 
54907c478bd9Sstevel@tonic-gate 	switch (intr_op) {
54917c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
54927c478bd9Sstevel@tonic-gate 		if (ddi_get_parent_data(rdip) == NULL) {
54937c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
54947c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
54957c478bd9Sstevel@tonic-gate 		}
54967c478bd9Sstevel@tonic-gate 		*(int *)result = DDI_INTR_TYPE_FIXED;
54977c478bd9Sstevel@tonic-gate 		break;
54987c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
5499a195726fSgovinda 		*(int *)result = DDI_INTR_FLAG_LEVEL;
55007c478bd9Sstevel@tonic-gate 		break;
55017c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
55027c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
5503a54f81fbSanish 		if (i_ddi_get_intx_nintrs(rdip) == 0) {
55047c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
55057c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55067c478bd9Sstevel@tonic-gate 		}
55077c478bd9Sstevel@tonic-gate 		*(int *)result = 1;	/* for PCMCIA there is only one intr */
55087c478bd9Sstevel@tonic-gate 		break;
55097c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
55107c478bd9Sstevel@tonic-gate 		if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum,
55117c478bd9Sstevel@tonic-gate 		    &sockp)) == NULL)
55127c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55137c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
55147c478bd9Sstevel@tonic-gate 		break;
55157c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
55167c478bd9Sstevel@tonic-gate 		break;
55177c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
55187c478bd9Sstevel@tonic-gate 		ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
55197c478bd9Sstevel@tonic-gate 		if (ispecp == NULL) {
55207c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
55217c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55227c478bd9Sstevel@tonic-gate 		}
55237c478bd9Sstevel@tonic-gate 
55247c478bd9Sstevel@tonic-gate 		*(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri;
55257c478bd9Sstevel@tonic-gate 		break;
55267c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETPRI:
55277c478bd9Sstevel@tonic-gate 		if (*(int *)result > LOCK_LEVEL)
55287c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55297c478bd9Sstevel@tonic-gate 		ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
55307c478bd9Sstevel@tonic-gate 		ASSERT(ispecp);
55317c478bd9Sstevel@tonic-gate 		ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result;
55327c478bd9Sstevel@tonic-gate 		break;
55337c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
55347c478bd9Sstevel@tonic-gate 		if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL)
55357c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55367a364d25Sschwartz 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
55377c478bd9Sstevel@tonic-gate 		break;
55387c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
55397c478bd9Sstevel@tonic-gate 		pcmcia_intr_remove_isr(dip, rdip, hdlp);
55407c478bd9Sstevel@tonic-gate 		break;
55417c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
55427c478bd9Sstevel@tonic-gate 		if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS)
55437c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
55447c478bd9Sstevel@tonic-gate 		break;
55457c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
55467c478bd9Sstevel@tonic-gate 		pcmcia_intr_disable_isr(dip, rdip, hdlp);
55477c478bd9Sstevel@tonic-gate 		break;
55487c478bd9Sstevel@tonic-gate 	default:
55497c478bd9Sstevel@tonic-gate 		return (DDI_ENOTSUP);
55507c478bd9Sstevel@tonic-gate 	}
55517c478bd9Sstevel@tonic-gate 
55527c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
55537c478bd9Sstevel@tonic-gate }
55547c478bd9Sstevel@tonic-gate #endif
5555