xref: /illumos-gate/usr/src/uts/common/pcmcia/nexus/pcmcia.c (revision e2738c5e21a9e5d9a6525e48af4738deda3df455)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * PCMCIA NEXUS
30  *	The PCMCIA module is a generalized interface for
31  *	implementing PCMCIA nexus drivers.  It preserves
32  *	the logical socket name space while allowing multiple
33  *	instances of the hardware to be properly represented
34  *	in the device tree.
35  *
36  *	The nexus also exports events to an event manager
37  *	driver if it has registered.
38  */
39 
40 #include <sys/types.h>
41 #include <sys/systm.h>
42 #include <sys/user.h>
43 #include <sys/buf.h>
44 #include <sys/file.h>
45 #include <sys/uio.h>
46 #include <sys/conf.h>
47 #include <sys/stat.h>
48 #include <sys/autoconf.h>
49 #include <sys/vtoc.h>
50 #include <sys/dkio.h>
51 #include <sys/ddi.h>
52 #include <sys/debug.h>
53 #include <sys/sunddi.h>
54 #include <sys/sunndi.h>
55 #include <sys/cred.h>
56 #include <sys/kstat.h>
57 #include <sys/kmem.h>
58 #include <sys/modctl.h>
59 #include <sys/kobj.h>
60 #include <sys/callb.h>
61 #include <sys/param.h>
62 #include <sys/thread.h>
63 #include <sys/proc.h>
64 
65 #include <sys/pctypes.h>
66 #include <sys/pcmcia.h>
67 #include <sys/sservice.h>
68 #include <pcmcia/sys/cs_types.h>
69 #include <pcmcia/sys/cis.h>
70 #include <pcmcia/sys/cis_handlers.h>
71 #include <pcmcia/sys/cs.h>
72 #include <pcmcia/sys/cs_priv.h>
73 
74 #ifdef sparc
75 #include <sys/ddi_subrdefs.h>
76 
77 #elif defined(__x86) || defined(__amd64)
78 #include <sys/mach_intr.h>
79 #endif
80 
81 #undef SocketServices
82 
83 /* some bus specific stuff */
84 
85 /* need PCI regspec size for worst case at present */
86 #include <sys/pci.h>
87 
88 typedef struct pcmcia_logical_socket {
89 	int			ls_socket; /* adapter's socket number */
90 	uint32_t		ls_flags;
91 	struct pcmcia_adapter	*ls_adapter;
92 	pcmcia_if_t		*ls_if;
93 	dev_info_t		*ls_sockdrv;
94 	dev_info_t		*ls_dip[PCMCIA_MAX_FUNCTIONS];
95 	dev_info_t		*ls_mfintr_dip;
96 	int			ls_functions;
97 	uint32_t		ls_cs_events;
98 	uint32_t		ls_intr_pri;
99 	uint32_t		ls_intr_vec;
100 	int			ls_intrrefs;
101 	struct intrspec		ls_intrspec; /* MFC intrspec */
102 	inthandler_t		*ls_inthandlers; /* for multifunction cards */
103 	ddi_iblock_cookie_t	ls_iblk;
104 	ddi_idevice_cookie_t	ls_idev;
105 	kmutex_t		ls_ilock;
106 	int			ls_error; /* error for CS return */
107 } pcmcia_logical_socket_t;
108 
109 /*
110  * entry points used by the true nexus
111  */
112 int pcmcia_detach(dev_info_t *, ddi_detach_cmd_t);
113 int pcmcia_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
114 int pcmcia_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t,
115 			int, char *, caddr_t, int *);
116 void pcmcia_set_assigned(dev_info_t *, int, ra_return_t *);
117 int pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
118     ddi_intr_handle_impl_t *hdlp, void *result);
119 
120 /*
121  * prototypes used internally by the nexus and sometimes Card Services
122  */
123 int SocketServices(int function, ...);
124 
125 
126 void *CISParser(int function, ...);
127 extern void *(*cis_parser)(int, ...);
128 
129 struct regspec *pcmcia_cons_regspec(dev_info_t *, int, uchar_t *,
130 					ra_return_t *);
131 
132 static int (*pcmcia_card_services)(int, ...) = NULL;
133 
134 /*
135  * variables used in the logical/physical mappings
136  * that the nexus common code maintains.
137  */
138 struct pcmcia_adapter *pcmcia_adapters[PCMCIA_MAX_ADAPTERS];
139 int    pcmcia_num_adapters;
140 pcmcia_logical_socket_t *pcmcia_sockets[PCMCIA_MAX_SOCKETS];
141 int    pcmcia_num_sockets;
142 pcmcia_logical_window_t *pcmcia_windows[PCMCIA_MAX_WINDOWS];
143 int    pcmcia_num_windows;
144 struct power_entry pcmcia_power_table[PCMCIA_MAX_POWER];
145 int	pcmcia_num_power;
146 
147 struct pcmcia_mif *pcmcia_mif_handlers = NULL;
148 pcm_dev_node_t *pcmcia_devnodes = NULL;
149 
150 kmutex_t pcmcia_global_lock;
151 kcondvar_t pcmcia_condvar;
152 kmutex_t pcmcia_enum_lock;
153 
154 /*
155  * Mapping of the device "type" to names acceptable to
156  * the DDI
157  */
158 static char *pcmcia_dev_type[] = {
159 	"multifunction",
160 	"byte",
161 	"serial",
162 	"parallel",
163 	"block",
164 	"display",
165 	"network",
166 	"block",
167 	"byte"
168 };
169 
170 char *pcmcia_default_pm_mode = "parental-suspend-resume";
171 
172 /*
173  * generic names from the approved list:
174  *	disk tape pci sbus scsi token-ring isa keyboard display mouse
175  *	audio ethernet timer memory parallel serial rtc nvram scanner
176  *	floppy(controller) fddi isdn atm ide pccard video-in video-out
177  * in some cases there will need to be device class dependent names.
178  * network -> ethernet, token-ring, etc.
179  * this list is a first guess and is used when all else fails.
180  */
181 
182 char *pcmcia_generic_names[] = {
183 	"multifunction",
184 	"memory",
185 	"serial",
186 	"parallel",
187 	"disk",
188 	"video",		/* no spec for video-out yet */
189 	"network",
190 	"aims",
191 	"scsi",
192 	"security"
193 };
194 
195 #define	PCM_GENNAME_SIZE	(sizeof (pcmcia_generic_names) / \
196 					sizeof (char *))
197 #define	PCMCIA_MAP_IO	0x0
198 #define	PCMCIA_MAP_MEM	0x1
199 
200 /*
201  * The following should be 2^^n - 1
202  */
203 #define	PCMCIA_SOCKET_BITS	0x7f
204 
205 #ifdef PCMCIA_DEBUG
206 int pcmcia_debug = 0x0;
207 static void pcmcia_dump_minors(dev_info_t *);
208 #endif
209 
210 static f_tt *pcmcia_cs_event = NULL;
211 int pcmcia_timer_id;
212 dev_info_t	*pcmcia_dip;
213 /*
214  * XXX - See comments in cs.c
215  */
216 static f_tt *pcmcia_cis_parser = NULL;
217 
218 extern struct pc_socket_services pc_socket_services;
219 
220 /* some function declarations */
221 static int pcm_adapter_callback(dev_info_t *, int, int, int);
222 extern void pcmcia_init_adapter(anp_t *, dev_info_t *);
223 static void pcmcia_enum_thread(anp_t *);
224 extern void pcmcia_find_cards(anp_t *);
225 extern void pcmcia_merge_power(struct power_entry *);
226 extern void pcmcia_do_resume(int, pcmcia_logical_socket_t *);
227 extern void pcmcia_resume(int, pcmcia_logical_socket_t *);
228 extern void pcmcia_do_suspend(int, pcmcia_logical_socket_t *);
229 extern void pcm_event_manager(int, int, void *);
230 static void pcmcia_create_dev_info(int);
231 static int pcmcia_create_device(ss_make_device_node_t *);
232 static void pcmcia_init_devinfo(dev_info_t *, struct pcm_device_info *);
233 void pcmcia_fix_string(char *str);
234 dev_info_t *pcmcia_number_socket(dev_info_t *, int);
235 static int pcmcia_merge_conf(dev_info_t *);
236 static uint32_t pcmcia_mfc_intr(caddr_t, caddr_t);
237 void pcmcia_free_resources(dev_info_t *);
238 static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd);
239 int pcmcia_get_intr(dev_info_t *, int);
240 int pcmcia_return_intr(dev_info_t *, int);
241 int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *);
242 int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *);
243 
244 extern int cs_init(void);
245 extern int cs_deinit(void);
246 extern void cisp_init(void);
247 extern void cis_deinit(void);
248 
249 /*
250  * non-DDI compliant functions are listed here
251  * some will be declared while others that have
252  * entries in .h files. All will be commented on.
253  *
254  * with declarations:
255  *	ddi_add_child
256  *	ddi_binding_name
257  *	ddi_bus_prop_op
258  *	ddi_ctlops
259  *	ddi_find_devinfo
260  *	ddi_get_name_addr
261  *	ddi_get_parent_data
262  *	ddi_hold_installed_driver
263  *	ddi_name_to_major
264  *	ddi_node_name
265  *	ddi_pathname
266  *	ddi_rele_driver
267  *	ddi_set_name_addr
268  *	ddi_set_parent_data
269  *	ddi_unorphan_devs
270  *	i_ddi_bind_node_to_driver
271  *	i_ddi_bind_node_to_driver
272  *	i_ddi_bus_map
273  *	i_ddi_map_fault
274  *	i_ddi_mem_alloc
275  *	i_ddi_mem_alloc
276  *	i_ddi_mem_free
277  *	i_ddi_mem_free
278  *	modload
279  *	modunload
280  */
281 
282 extern void ddi_unorphan_devs(major_t);
283 
284 /* Card&Socket Services entry points */
285 static int GetCookiesAndDip(sservice_t *);
286 static int SSGetAdapter(get_adapter_t *);
287 static int SSGetPage(get_page_t *);
288 static int SSGetSocket(get_socket_t *);
289 static int SSGetStatus(get_ss_status_t *);
290 static int SSGetWindow(get_window_t *);
291 static int SSInquireAdapter(inquire_adapter_t *);
292 static int SSInquireSocket(inquire_socket_t *);
293 static int SSInquireWindow(inquire_window_t *);
294 static int SSResetSocket(int, int);
295 static int SSSetPage(set_page_t *);
296 static int SSSetSocket(set_socket_t *);
297 static int SSSetWindow(set_window_t *);
298 static int SSSetIRQHandler(set_irq_handler_t *);
299 static int SSClearIRQHandler(clear_irq_handler_t *);
300 
301 static struct modldrv modlmisc = {
302 	&mod_miscops,		/* Type of module. This one is a driver */
303 	"PCMCIA Nexus Support %I%", /* Name of the module. */
304 };
305 
306 static struct modlinkage modlinkage = {
307 	MODREV_1, (void *)&modlmisc, NULL
308 };
309 
310 int
311 _init()
312 {
313 	int	ret;
314 
315 	cisp_init();
316 
317 	if (cs_init() != CS_SUCCESS) {
318 	    if (cs_deinit() != CS_SUCCESS)
319 		cmn_err(CE_CONT, "pcmcia: _init cs_deinit error\n");
320 	    return (-1);
321 	}
322 
323 	mutex_init(&pcmcia_global_lock, NULL, MUTEX_DEFAULT, NULL);
324 	cv_init(&pcmcia_condvar, NULL, CV_DRIVER, NULL);
325 	mutex_init(&pcmcia_enum_lock, NULL, MUTEX_DEFAULT, NULL);
326 
327 	if ((ret = mod_install(&modlinkage)) != 0) {
328 		mutex_destroy(&pcmcia_global_lock);
329 		cv_destroy(&pcmcia_condvar);
330 		mutex_destroy(&pcmcia_enum_lock);
331 	}
332 	return (ret);
333 }
334 
335 int
336 _fini()
337 {
338 	int	ret;
339 
340 	if ((ret = mod_remove(&modlinkage)) == 0) {
341 		mutex_destroy(&pcmcia_global_lock);
342 		cv_destroy(&pcmcia_condvar);
343 		mutex_destroy(&pcmcia_enum_lock);
344 		cis_deinit();
345 		if (cs_deinit() != CS_SUCCESS) {
346 			cmn_err(CE_CONT, "pcmcia: _fini cs_deinit error\n");
347 		}
348 	}
349 	return (ret);
350 }
351 
352 int
353 _info(struct modinfo *modinfop)
354 {
355 	return (mod_info(&modlinkage, modinfop));
356 }
357 
358 extern pri_t minclsyspri;
359 
360 /*
361  * pcmcia_attach()
362  *	the attach routine must make sure that everything needed is present
363  *	including real hardware.  The sequence of events is:
364  *		attempt to load all adapter drivers
365  *		attempt to load Card Services (which _depends_on pcmcia)
366  *		initialize logical sockets
367  *		report the nexus exists
368  */
369 
370 int
371 pcmcia_attach(dev_info_t *dip, anp_t *adapter)
372 {
373 	int count, done, i;
374 
375 #if defined(PCMCIA_DEBUG)
376 	if (pcmcia_debug) {
377 		cmn_err(CE_CONT, "pcmcia_attach: dip=0x%p adapter=0x%p\n",
378 		    (void *)dip, (void *)adapter);
379 	}
380 #endif
381 
382 	pcmcia_dip = dip;
383 
384 	mutex_enter(&pcmcia_enum_lock);
385 	mutex_enter(&pcmcia_global_lock);
386 	if (pcmcia_num_adapters == 0) {
387 		pcmcia_cis_parser = (f_tt *)CISParser;
388 		cis_parser = (void *(*)(int, ...)) CISParser;
389 		pcmcia_cs_event = (f_tt *)cs_event;
390 		cs_socket_services = SocketServices;
391 		/* tell CS we are up with basic init level */
392 		(void) cs_event(PCE_SS_INIT_STATE, PCE_SS_STATE_INIT, 0);
393 	}
394 
395 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
396 	    PCM_DEVICETYPE, "pccard");
397 
398 	ddi_report_dev(dip);	/* directory/device naming */
399 
400 	/*
401 	 * now setup any power management stuff necessary.
402 	 * we do it here in order to ensure that all PC Card nexi
403 	 * implement it.
404 	 */
405 
406 	if (pm_create_components(dip, 1) != DDI_SUCCESS) {
407 		cmn_err(CE_WARN, "%s: not power managed\n",
408 			ddi_get_name_addr(dip));
409 	} else {
410 		pm_set_normal_power(dip, 0, 1);
411 	}
412 
413 	/*
414 	 * setup the info necessary for Card Services/SocketServices
415 	 * and notify CS when ready.
416 	 */
417 
418 	pcmcia_free_resources(dip);
419 	pcmcia_init_adapter(adapter, dip);
420 	/* exit mutex so CS can run for any cards found */
421 	mutex_exit(&pcmcia_global_lock);
422 
423 	/*
424 	 * schedule an asynchronous thread to enumerate the cards
425 	 * present in the adapter at boot time
426 	 */
427 	(void) thread_create(NULL, 0, pcmcia_enum_thread, adapter, 0, &p0,
428 	    TS_RUN, minclsyspri);
429 
430 	/*
431 	 * make sure the devices are identified before
432 	 * returning.  We do this by checking each socket to see if
433 	 * a card is present.  If there is one, and there isn't a dip,
434 	 * we can't be done.  We scan the list of sockets doing the
435 	 * check. if we aren't done, wait for a condition variable to
436 	 * wakeup.
437 	 * Because we can miss a wakeup and because things can
438 	 * take time, we do eventually give up and have a timeout.
439 	 */
440 
441 	for (count = 0, done = 0;
442 	    done == 0 && count < max(pcmcia_num_sockets, 16);
443 	    count++) {
444 		done = 1;
445 		/* block CS while checking so we don't miss anything */
446 		mutex_enter(&pcmcia_global_lock);
447 		for (i = 0; i < pcmcia_num_sockets; i++) {
448 			get_ss_status_t status;
449 			if (pcmcia_sockets[i] == NULL)
450 				continue;
451 			bzero(&status, sizeof (status));
452 			status.socket = i;
453 			if (SSGetStatus(&status) == SUCCESS) {
454 				if (status.CardState & SBM_CD &&
455 				    pcmcia_sockets[i]->ls_dip[0] == NULL) {
456 					done = 0;
457 				}
458 			}
459 		}
460 		/* only wait if we aren't done with this set */
461 		if (!done) {
462 			mutex_exit(&pcmcia_global_lock);
463 			delay(10); /* give up CPU for a time */
464 			mutex_enter(&pcmcia_global_lock);
465 		}
466 		mutex_exit(&pcmcia_global_lock);
467 	}
468 
469 	mutex_exit(&pcmcia_enum_lock);
470 	return (DDI_SUCCESS);
471 }
472 
473 /*
474  * pcmcia_detach
475  *	unload everything and then detach the nexus
476  */
477 /* ARGSUSED */
478 int
479 pcmcia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
480 {
481 	switch (cmd) {
482 	case DDI_DETACH:
483 		pm_destroy_components(dip);
484 		return (DDI_SUCCESS);
485 
486 	/*
487 	 * resume from a checkpoint
488 	 * We don't do anything special here since the adapter
489 	 * driver will generate resume events that we intercept
490 	 * and convert to insert events.
491 	 */
492 	case DDI_SUSPEND:
493 	case DDI_PM_SUSPEND:
494 		return (DDI_SUCCESS);
495 
496 	default:
497 		return (DDI_FAILURE);
498 	}
499 }
500 
501 /*
502  * card_services_error()
503  *	used to make 2.4/2.5 drivers get an error when
504  *	they try to initialize.
505  */
506 static int
507 card_services_error()
508 {
509 	return (CS_BAD_VERSION);
510 }
511 static int (*cs_error_ptr)() = card_services_error;
512 
513 /*
514  * pcmcia_ctlops
515  *	handle the nexus control operations for the cases where
516  *	a PC Card driver gets called and we need to modify the
517  *	devinfo structure or otherwise do bus specific operations
518  */
519 int
520 pcmcia_ctlops(dev_info_t *dip, dev_info_t *rdip,
521 	ddi_ctl_enum_t ctlop, void *arg, void *result)
522 {
523 	int e;
524 	char name[64];
525 	struct pcmcia_parent_private *ppd;
526 	power_req_t *pm;
527 
528 #if defined(PCMCIA_DEBUG)
529 	if (pcmcia_debug) {
530 		cmn_err(CE_CONT, "pcmcia_ctlops(%p, %p, %d, %p, %p)\n",
531 			(void *)dip, (void *)rdip, ctlop, (void *)arg,
532 			(void *)result);
533 		if (rdip != NULL && ddi_get_name(rdip) != NULL)
534 			cmn_err(CE_CONT, "\t[%s]\n", ddi_get_name(rdip));
535 	}
536 #endif
537 
538 	switch (ctlop) {
539 	case DDI_CTLOPS_REPORTDEV:
540 		if (rdip == (dev_info_t *)0)
541 			return (DDI_FAILURE);
542 
543 		if (strcmp("pcs", ddi_node_name(rdip)) == 0)
544 			cmn_err(CE_CONT, "?PCCard socket %d at %s@%s\n",
545 				ddi_get_instance(rdip),
546 				ddi_driver_name(dip), ddi_get_name_addr(dip));
547 		else
548 			cmn_err(CE_CONT, "?%s%d at %s@%s in socket %d\n",
549 				ddi_driver_name(rdip),
550 				ddi_get_instance(rdip),
551 				ddi_driver_name(dip),
552 				ddi_get_name_addr(dip),
553 				CS_GET_SOCKET_NUMBER(
554 				    ddi_getprop(DDI_DEV_T_NONE, rdip,
555 				    DDI_PROP_DONTPASS,
556 				    PCM_DEV_SOCKET, -1)));
557 
558 		return (DDI_SUCCESS);
559 
560 	case DDI_CTLOPS_INITCHILD:
561 		/*
562 		 * we get control here before the child is called.
563 		 * we can change things if necessary.  This is where
564 		 * the CardServices hook gets planted.
565 		 */
566 #if defined(PCMCIA_DEBUG)
567 		if (pcmcia_debug) {
568 			cmn_err(CE_CONT, "pcmcia: init child: %s(%d) @%p\n",
569 				ddi_node_name(arg), ddi_get_instance(arg),
570 				(void *)arg);
571 			if (DEVI(arg)->devi_binding_name != NULL)
572 				cmn_err(CE_CONT, "\tbinding_name=%s\n",
573 					DEVI(arg)->devi_binding_name);
574 			if (DEVI(arg)->devi_node_name != NULL)
575 				cmn_err(CE_CONT, "\tnode_name=%s\n",
576 					DEVI(arg)->devi_node_name);
577 		}
578 #endif
579 
580 		ppd = (struct pcmcia_parent_private *)
581 			ddi_get_parent_data((dev_info_t *)arg);
582 		if (ppd == NULL)
583 			return (DDI_FAILURE);
584 
585 		if (strcmp("pcs", ddi_node_name((dev_info_t *)arg)) == 0) {
586 			if (ppd == NULL)
587 				return (DDI_FAILURE);
588 			(void) sprintf(name, "%x",
589 			    (int)ppd->ppd_reg[0].phys_hi);
590 			ddi_set_name_addr((dev_info_t *)arg, name);
591 			return (DDI_SUCCESS);
592 		}
593 
594 		/*
595 		 * We don't want driver.conf files that stay in
596 		 * pseudo device form.	It is acceptable to have
597 		 * .conf files add properties only.
598 		 */
599 		if (ndi_dev_is_persistent_node((dev_info_t *)arg) == 0) {
600 			(void) pcmcia_merge_conf((dev_info_t *)arg);
601 			cmn_err(CE_WARN, "%s%d: %s.conf invalid",
602 				ddi_get_name((dev_info_t *)arg),
603 				ddi_get_instance((dev_info_t *)arg),
604 				ddi_get_name((dev_info_t *)arg));
605 			return (DDI_FAILURE);
606 		}
607 
608 
609 #if defined(PCMCIA_DEBUG)
610 		if (pcmcia_debug && ppd != NULL) {
611 			cmn_err(CE_CONT, "\tnreg=%x, intr=%x, socket=%x,"
612 				" function=%x, active=%x, flags=%x\n",
613 				ppd->ppd_nreg, ppd->ppd_intr,
614 				ppd->ppd_socket, ppd->ppd_function,
615 				ppd->ppd_active, ppd->ppd_flags);
616 		}
617 #endif
618 
619 		/*
620 		 * make sure names are relative to socket number
621 		 */
622 		if (ppd->ppd_function > 0) {
623 			int sock;
624 			int func;
625 			sock = ppd->ppd_socket;
626 			func = ppd->ppd_function;
627 			(void) sprintf(name, "%x,%x", sock, func);
628 		} else {
629 			(void) sprintf(name, "%x", ppd->ppd_socket);
630 		}
631 		ddi_set_name_addr((dev_info_t *)arg, name);
632 
633 #if defined(PCMCIA_DEBUG)
634 		if (pcmcia_debug)
635 			cmn_err(CE_CONT, "pcmcia: system init done for %s [%s] "
636 				"nodeid: %x @%s\n",
637 				ddi_get_name(arg), ddi_get_name_addr(arg),
638 				DEVI(arg)->devi_nodeid, name);
639 		if (pcmcia_debug > 1)
640 			pcmcia_dump_minors((dev_info_t *)arg);
641 #endif
642 
643 		return (DDI_SUCCESS);
644 
645 	case DDI_CTLOPS_UNINITCHILD:
646 
647 #if defined(PCMCIA_DEBUG)
648 		if (pcmcia_debug) {
649 			cmn_err(CE_CONT, "pcmcia: uninit child: %s(%d) @%p\n",
650 				ddi_node_name(arg), ddi_get_instance(arg),
651 				(void *)arg);
652 			if (DEVI(arg)->devi_binding_name != NULL)
653 				cmn_err(CE_CONT, "\tbinding_name=%s\n",
654 					DEVI(arg)->devi_binding_name);
655 			if (DEVI(arg)->devi_node_name != NULL)
656 				cmn_err(CE_CONT, "\tnode_name=%s\n",
657 					DEVI(arg)->devi_node_name);
658 		}
659 #endif
660 
661 		ddi_set_name_addr((dev_info_t *)arg, NULL);
662 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
663 		return (DDI_SUCCESS);
664 
665 	case DDI_CTLOPS_SLAVEONLY:
666 		/* PCMCIA devices can't ever be busmaster until CardBus */
667 		ppd = (struct pcmcia_parent_private *)
668 			ddi_get_parent_data(rdip);
669 		if (ppd != NULL && ppd->ppd_flags & PPD_CB_BUSMASTER)
670 			return (DDI_FAILURE); /* at most */
671 		return (DDI_SUCCESS);
672 
673 	case DDI_CTLOPS_SIDDEV:
674 		/* in general this is true. */
675 		return (DDI_SUCCESS);
676 
677 	case DDI_CTLOPS_NREGS:
678 		ppd = (struct pcmcia_parent_private *)
679 			ddi_get_parent_data(rdip);
680 		if (ppd != NULL)
681 			*((uint32_t *)result) = (ppd->ppd_nreg);
682 		else
683 			*((uint32_t *)result) = 0;
684 		return (DDI_SUCCESS);
685 
686 	case DDI_CTLOPS_REGSIZE:
687 		ppd = (struct pcmcia_parent_private *)
688 			ddi_get_parent_data(rdip);
689 		if (ppd != NULL && ppd->ppd_nreg > 0)
690 			*((off_t *)result) =  sizeof (struct pcm_regs);
691 		else
692 			*((off_t *)result) = 0;
693 		return (DDI_SUCCESS);
694 
695 	case DDI_CTLOPS_POWER:
696 		ppd = (struct pcmcia_parent_private *)
697 			ddi_get_parent_data(rdip);
698 
699 		if (ppd == NULL)
700 			return (DDI_FAILURE);
701 		/*
702 		 * if this is not present, don't bother (claim success)
703 		 * since it is already in the right state.  Don't
704 		 * do any resume either since the card insertion will
705 		 * happen independently.
706 		 */
707 		if (!ppd->ppd_active)
708 			return (DDI_SUCCESS);
709 		for (e = 0; e < pcmcia_num_adapters; e++)
710 			if (pcmcia_adapters[e] ==
711 			    pcmcia_sockets[ppd->ppd_socket]->ls_adapter)
712 				break;
713 		if (e == pcmcia_num_adapters)
714 			return (DDI_FAILURE);
715 		pm = (power_req_t *)arg;
716 #if defined(PCMCIA_DEBUG)
717 		if (pcmcia_debug) {
718 			cmn_err(CE_WARN, "power: %d: %p, %d, %d [%s]\n",
719 				pm->request_type,
720 				(void *)pm->req.set_power_req.who,
721 				pm->req.set_power_req.cmpt,
722 				pm->req.set_power_req.level,
723 				ddi_get_name_addr(rdip));
724 		}
725 #endif
726 		e = ppd->ppd_socket;
727 		switch (pm->request_type) {
728 		case PMR_SUSPEND:
729 			if (!(pcmcia_sockets[e]->ls_flags &
730 			    PCS_SUSPENDED)) {
731 				pcmcia_do_suspend(ppd->ppd_socket,
732 				    pcmcia_sockets[e]);
733 			}
734 			ppd->ppd_flags |= PPD_SUSPENDED;
735 			return (DDI_SUCCESS);
736 		case PMR_RESUME:
737 			/* for now, we just succeed since the rest is done */
738 			return (DDI_SUCCESS);
739 		case PMR_SET_POWER:
740 			/*
741 			 * not sure how to handle power control
742 			 * for now, we let the child handle it itself
743 			 */
744 			(void) pcmcia_power(pm->req.set_power_req.who,
745 				pm->req.set_power_req.cmpt,
746 				pm->req.set_power_req.level);
747 			break;
748 		default:
749 			break;
750 		}
751 		return (DDI_FAILURE);
752 		/* These CTLOPS will need to be implemented for new form */
753 		/* let CardServices know about this */
754 
755 	default:
756 		/* if we don't understand, pass up the tree */
757 		/* most things default to general ops */
758 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
759 	}
760 }
761 
762 struct pcmcia_props {
763 	char *name;
764 	int   len;
765 	int   prop;
766 } pcmcia_internal_props[] = {
767 	{ PCM_DEV_ACTIVE, 0, PCMCIA_PROP_ACTIVE },
768 	{ PCM_DEV_R2TYPE, 0, PCMCIA_PROP_R2TYPE },
769 	{ PCM_DEV_CARDBUS, 0, PCMCIA_PROP_CARDBUS },
770 	{ CS_PROP, sizeof (void *), PCMCIA_PROP_OLDCS },
771 	{ "reg", 0, PCMCIA_PROP_REG },
772 	{ "interrupts", sizeof (int), PCMCIA_PROP_INTR },
773 	{ "pm-hardware-state", 0, PCMCIA_PROP_DEFAULT_PM },
774 };
775 
776 /*
777  * pcmcia_prop_decode(name)
778  *	decode the name and determine if this is a property
779  *	we construct on the fly, one we have on the prop list
780  *	or one that requires calling the CIS code.
781  */
782 static int
783 pcmcia_prop_decode(char *name)
784 {
785 	int i;
786 	if (strncmp(name, "cistpl_", 7) == 0)
787 		return (PCMCIA_PROP_CIS);
788 
789 	for (i = 0; i < (sizeof (pcmcia_internal_props) /
790 	    sizeof (struct pcmcia_props)); i++) {
791 		if (strcmp(name, pcmcia_internal_props[i].name) == 0)
792 			return (i);
793 	}
794 
795 	return (PCMCIA_PROP_UNKNOWN);
796 }
797 
798 /*
799  * pcmcia_prop_op()
800  *	we don't have properties in PROM per se so look for them
801  *	only in the devinfo node.  Future may allow us to find
802  *	certain CIS tuples via this interface if a user asks for
803  *	a property of the form "cistpl-<tuplename>" but not yet.
804  *
805  *	The addition of 1275 properties adds to the necessity.
806  */
807 int
808 pcmcia_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
809     ddi_prop_op_t prop_op, int mod_flags,
810     char *name, caddr_t valuep, int *lengthp)
811 {
812 	int len, proplen, which, flags;
813 	caddr_t buff, propptr;
814 	struct pcmcia_parent_private *ppd;
815 
816 	len = *lengthp;
817 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(ch_dip);
818 
819 	switch (which = pcmcia_prop_decode(name)) {
820 	default:
821 		if (ppd == NULL)
822 			return (DDI_PROP_NOT_FOUND);
823 
824 		/* note that proplen may get modified */
825 		proplen = pcmcia_internal_props[which].len;
826 		switch (pcmcia_internal_props[which].prop) {
827 		case PCMCIA_PROP_DEFAULT_PM:
828 			propptr = pcmcia_default_pm_mode;
829 			proplen = strlen(propptr) + 1;
830 			break;
831 		case PCMCIA_PROP_OLDCS:
832 			propptr = (caddr_t)&cs_error_ptr;
833 			break;
834 		case PCMCIA_PROP_REG:
835 			propptr = (caddr_t)ppd->ppd_reg;
836 			proplen = ppd->ppd_nreg * sizeof (struct pcm_regs);
837 			break;
838 		case PCMCIA_PROP_INTR:
839 			propptr = (caddr_t)&ppd->ppd_intr;
840 			break;
841 
842 		/* the next set are boolean values */
843 		case PCMCIA_PROP_ACTIVE:
844 			propptr = NULL;
845 			if (!ppd->ppd_active) {
846 				return (DDI_PROP_NOT_FOUND);
847 			}
848 			break;
849 		case PCMCIA_PROP_R2TYPE:
850 			propptr = NULL;
851 			if (ppd->ppd_flags & PPD_CARD_CARDBUS)
852 				return (DDI_PROP_NOT_FOUND);
853 			break;
854 		case PCMCIA_PROP_CARDBUS:
855 			propptr = NULL;
856 			if (!(ppd->ppd_flags * PPD_CARD_CARDBUS))
857 				return (DDI_PROP_NOT_FOUND);
858 			break;
859 		}
860 
861 		break;
862 
863 	case PCMCIA_PROP_CIS:
864 		/*
865 		 * once we have the lookup code in place
866 		 * it is sufficient to break out of the switch
867 		 * once proplen and propptr are set.
868 		 * The common prop_op code deals with the rest.
869 		 */
870 	case PCMCIA_PROP_UNKNOWN:
871 		return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
872 		    mod_flags | DDI_PROP_NOTPROM,
873 		    name, valuep, lengthp));
874 	}
875 
876 	if (prop_op == PROP_LEN) {
877 		/* just the length */
878 		*lengthp = proplen;
879 		return (DDI_PROP_SUCCESS);
880 	}
881 	switch (prop_op) {
882 	case PROP_LEN_AND_VAL_ALLOC:
883 		if (mod_flags & DDI_PROP_CANSLEEP)
884 			flags = KM_SLEEP;
885 		else
886 			flags = KM_NOSLEEP;
887 		buff = kmem_alloc((size_t)proplen, flags);
888 		if (buff == NULL)
889 			return (DDI_PROP_NO_MEMORY);
890 		*(caddr_t *)valuep = (caddr_t)buff;
891 		break;
892 	case PROP_LEN_AND_VAL_BUF:
893 		buff = (caddr_t)valuep;
894 		if (len < proplen)
895 			return (DDI_PROP_BUF_TOO_SMALL);
896 		break;
897 	default:
898 		break;
899 	}
900 
901 	if (proplen > 0)
902 		bcopy(propptr, buff, proplen);
903 	*lengthp = proplen;
904 	return (DDI_PROP_SUCCESS);
905 }
906 
907 
908 struct regspec *
909 pcmcia_rnum_to_regspec(dev_info_t *dip, int rnumber)
910 {
911 	struct pcmcia_parent_private *ppd;
912 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
913 	if (ppd->ppd_nreg < rnumber)
914 		return (NULL);
915 	return ((struct regspec *)&ppd->ppd_reg[rnumber]);
916 }
917 
918 struct regspec *
919 pcmcia_rnum_to_mapped(dev_info_t *dip, int rnumber)
920 {
921 	struct pcmcia_parent_private *ppd;
922 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
923 	if (ppd->ppd_nreg < rnumber)
924 		return (NULL);
925 	if (ppd->ppd_assigned == NULL)
926 		return (NULL);
927 	if (ppd->ppd_assigned[rnumber].phys_len == 0)
928 		return (NULL);
929 	else
930 		return ((struct regspec *)&ppd->ppd_assigned[rnumber]);
931 }
932 
933 int
934 pcmcia_find_rnum(dev_info_t *dip, struct regspec *reg)
935 {
936 	struct pcmcia_parent_private *ppd;
937 	struct regspec *regp;
938 	int i;
939 
940 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
941 	if (ppd == NULL)
942 		return (-1);
943 	for (regp = (struct regspec *)ppd->ppd_reg, i = 0;
944 	    i < ppd->ppd_nreg; i++, regp++) {
945 		if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
946 			return (i);
947 	}
948 	for (regp = (struct regspec *)ppd->ppd_assigned, i = 0;
949 	    i < ppd->ppd_nreg; i++, regp++) {
950 		if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
951 			return (i);
952 	}
953 
954 	return (-1);
955 }
956 
957 int
958 pcmcia_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
959 	off_t offset, off_t len, caddr_t *vaddrp)
960 {
961 	struct pcm_regs *regs, *mregs = NULL, tmp_reg;
962 	ddi_map_req_t mr = *mp;
963 	ra_return_t ret;
964 	int check, rnum = -1;
965 	uint32_t base;
966 	uchar_t regbuf[sizeof (pci_regspec_t)];
967 
968 	mp = &mr;		/* a copy of original request */
969 
970 	/* check for register number */
971 	switch (mp->map_type) {
972 	case DDI_MT_REGSPEC:
973 		regs = (struct pcm_regs *)mp->map_obj.rp;
974 		mregs = (struct pcm_regs *)mp->map_obj.rp;
975 		/*
976 		 * when using regspec, must not be relocatable
977 		 * and should be from assigned space.
978 		 */
979 		if (!PC_REG_RELOC(regs->phys_hi))
980 			return (DDI_FAILURE);
981 		rnum = pcmcia_find_rnum(rdip, (struct regspec *)mregs);
982 		break;
983 	case DDI_MT_RNUMBER:
984 		regs = (struct pcm_regs *)
985 			pcmcia_rnum_to_regspec(rdip, mp->map_obj.rnumber);
986 		mregs = (struct pcm_regs *)
987 			pcmcia_rnum_to_mapped(rdip, mp->map_obj.rnumber);
988 		rnum = mp->map_obj.rnumber;
989 		if (regs == NULL)
990 			return (DDI_FAILURE);
991 		mp->map_type = DDI_MT_REGSPEC;
992 		mp->map_obj.rp = (struct regspec *)mregs;
993 		break;
994 	default:
995 		return (DDI_ME_INVAL);
996 	}
997 
998 	/* basic sanity checks */
999 	switch (mp->map_op) {
1000 	default:
1001 		return (DDI_ME_UNIMPLEMENTED);
1002 	case DDI_MO_UNMAP:
1003 		if (mregs == NULL)
1004 			return (DDI_FAILURE);
1005 		regs = mregs;
1006 		break;
1007 	case DDI_MO_MAP_LOCKED:
1008 	case DDI_MO_MAP_HANDLE:
1009 		panic("unsupported bus operation");
1010 		/*NOTREACHED*/
1011 	}
1012 
1013 	/*
1014 	 * we need a private copy for manipulation and
1015 	 * calculation of the correct ranges
1016 	 */
1017 	tmp_reg = *regs;
1018 	mp->map_obj.rp = (struct regspec *)(regs = &tmp_reg);
1019 	base = regs->phys_lo;
1020 	if (base == 0 && offset != 0) {
1021 		/*
1022 		 * for now this is an error.  What does it really mean
1023 		 * to ask for an offset from an address that hasn't
1024 		 * been allocated yet.
1025 		 */
1026 		return (DDI_ME_INVAL);
1027 	}
1028 	regs->phys_lo += (uint32_t)offset;
1029 	if (len != 0) {
1030 		if (len > regs->phys_len) {
1031 			return (DDI_ME_INVAL);
1032 		}
1033 		regs->phys_len = len;
1034 	}
1035 
1036 	/*
1037 	 * basic sanity is checked so now make sure
1038 	 * we can actually allocate something for this
1039 	 * request and then convert to a "standard"
1040 	 * regspec for the next layer up (pci/isa/rootnex/etc.)
1041 	 */
1042 
1043 	switch (PC_GET_REG_TYPE(regs->phys_hi)) {
1044 	case PC_REG_SPACE_IO:
1045 		check = PCA_RES_NEED_IO;
1046 		break;
1047 	case PC_REG_SPACE_MEMORY:
1048 		check = PCA_RES_NEED_MEM;
1049 		break;
1050 	default:
1051 		/* not a valid register type */
1052 		return (DDI_FAILURE);
1053 	}
1054 
1055 	mr.map_type = DDI_MT_REGSPEC;
1056 	ret.ra_addr_hi = 0;
1057 	ret.ra_addr_lo = regs->phys_lo;
1058 	ret.ra_len = regs->phys_len;
1059 	mr.map_obj.rp = pcmcia_cons_regspec(dip,
1060 	    (check == PCA_RES_NEED_IO) ?
1061 	    PCMCIA_MAP_IO : PCMCIA_MAP_MEM,
1062 	    regbuf, &ret);
1063 	switch (mp->map_op) {
1064 	case DDI_MO_UNMAP:
1065 		pcmcia_set_assigned(rdip, rnum, NULL);
1066 		break;
1067 	default:
1068 		break;
1069 	}
1070 	return (ddi_map(dip, &mr, (off_t)0, (off_t)0, vaddrp));
1071 }
1072 
1073 /*
1074  * pcmcia_cons_regspec()
1075  * based on parent's bus type, construct a regspec that is usable
1076  * by that parent to map the resource into the system.
1077  */
1078 #define	PTYPE_PCI	1
1079 #define	PTYPE_ISA	0
1080 struct regspec *
1081 pcmcia_cons_regspec(dev_info_t *dip, int type, uchar_t *buff, ra_return_t *ret)
1082 {
1083 	int ptype = -1, len, bus;
1084 	char device_type[MODMAXNAMELEN + 1];
1085 	dev_info_t *pdip;
1086 	struct regspec *defreg;
1087 	pci_regspec_t *pcireg;
1088 
1089 	pdip = ddi_get_parent(dip);
1090 	if (pdip != ddi_root_node()) {
1091 		/* we're not a child of root so find out what */
1092 		len = sizeof (device_type);
1093 		if (ddi_prop_op(DDI_DEV_T_ANY, pdip, PROP_LEN_AND_VAL_BUF, 0,
1094 			"device_type", (caddr_t)device_type, &len) ==
1095 		    DDI_PROP_SUCCESS) {
1096 			/* check things out */
1097 			if (strcmp(device_type, "pci") == 0)
1098 				ptype = PTYPE_PCI;
1099 			else if (strcmp(device_type, "isa") == 0)
1100 				ptype = PTYPE_ISA;
1101 		}
1102 	}
1103 	switch (ptype) {
1104 	case PTYPE_PCI:
1105 		/* XXX need to look at carefully */
1106 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1107 			"reg", (caddr_t)&pcireg, &len) == DDI_SUCCESS) {
1108 			bus = PCI_REG_BUS_G(pcireg->pci_phys_hi);
1109 			kmem_free(pcireg, len);
1110 		} else {
1111 			bus = 0;
1112 		}
1113 		pcireg = (pci_regspec_t *)buff;
1114 		pcireg->pci_phys_hi = (type == PCMCIA_MAP_IO ? PCI_ADDR_IO :
1115 			PCI_ADDR_MEM32) | PCI_RELOCAT_B | (bus << 16);
1116 		pcireg->pci_phys_mid = ret->ra_addr_hi;
1117 		pcireg->pci_phys_low = ret->ra_addr_lo;
1118 		if (type == PCMCIA_MAP_IO)
1119 			pcireg->pci_phys_low &= 0xFFFF;
1120 		pcireg->pci_size_hi = 0;
1121 		pcireg->pci_size_low = ret->ra_len;
1122 		break;
1123 	default:
1124 		/* default case is to use struct regspec */
1125 		defreg = (struct regspec *)buff;
1126 		defreg->regspec_bustype = type == PCMCIA_MAP_IO ? 1 : 0;
1127 		defreg->regspec_addr = ret->ra_addr_lo;
1128 		defreg->regspec_size = ret->ra_len;
1129 		break;
1130 	}
1131 	return ((struct regspec *)buff);
1132 }
1133 
1134 /*
1135  * pcmcia_init_adapter
1136  *	Initialize the per-adapter structures and check to see if
1137  *	there are possible other instances coming.
1138  */
1139 void
1140 pcmcia_init_adapter(anp_t *adapter, dev_info_t *dip)
1141 {
1142 	int i, n;
1143 	pcmcia_if_t *ls_if;
1144 
1145 	i = pcmcia_num_adapters++;
1146 	pcmcia_adapters[i] = kmem_zalloc(sizeof (struct pcmcia_adapter),
1147 	    KM_SLEEP);
1148 	pcmcia_adapters[i]->pca_dip = dip;
1149 	/* should this be pca_winshift??? */
1150 	pcmcia_adapters[i]->pca_module = ddi_name_to_major(ddi_get_name(dip));
1151 	pcmcia_adapters[i]->pca_unit = ddi_get_instance(dip);
1152 	pcmcia_adapters[i]->pca_iblock = adapter->an_iblock;
1153 	pcmcia_adapters[i]->pca_idev = adapter->an_idev;
1154 	pcmcia_adapters[i]->pca_if = ls_if = adapter->an_if;
1155 	pcmcia_adapters[i]->pca_number = i;
1156 	(void) strcpy(pcmcia_adapters[i]->pca_name, ddi_get_name(dip));
1157 	pcmcia_adapters[i]->
1158 		pca_name[sizeof (pcmcia_adapters[i]->pca_name) - 1] = NULL;
1159 
1160 	if (ls_if != NULL) {
1161 		inquire_adapter_t conf;
1162 		int sock, win;
1163 
1164 		if (ls_if->pcif_inquire_adapter != NULL)
1165 			GET_CONFIG(ls_if, dip, &conf);
1166 
1167 		/* resources - assume worst case and fix from there */
1168 		pcmcia_adapters[i]->pca_flags = PCA_RES_NEED_IRQ |
1169 			PCA_RES_NEED_IO | PCA_RES_NEED_MEM;
1170 		/* indicate first socket not initialized */
1171 		pcmcia_adapters[i]->pca_first_socket = -1;
1172 
1173 		if (conf.ResourceFlags & RES_OWN_IRQ)
1174 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IRQ;
1175 		if (conf.ResourceFlags & RES_OWN_IO)
1176 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IO;
1177 		if (conf.ResourceFlags & RES_OWN_MEM)
1178 			pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_MEM;
1179 		if (conf.ResourceFlags & RES_IRQ_SHAREABLE)
1180 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SHAREABLE;
1181 		if (conf.ResourceFlags & RES_IRQ_NEXUS)
1182 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SMI_SHARE;
1183 
1184 		/* need to know interrupt limitations */
1185 		if (conf.ActiveLow) {
1186 			pcmcia_adapters[i]->pca_avail_intr = conf.ActiveLow;
1187 			pcmcia_adapters[i]->pca_flags |= PCA_IRQ_ISA;
1188 		} else
1189 			pcmcia_adapters[i]->pca_avail_intr = conf.ActiveHigh;
1190 
1191 		/* power entries for adapter */
1192 		pcmcia_adapters[i]->pca_power =
1193 			conf.power_entry;
1194 		pcmcia_adapters[i]->pca_numpower =
1195 			conf.NumPower;
1196 
1197 		for (n = 0; n < conf.NumPower; n++)
1198 			pcmcia_merge_power(&conf.power_entry[n]);
1199 
1200 		/* now setup the per socket info */
1201 		for (sock = 0; sock < conf.NumSockets;
1202 		    sock++) {
1203 			dev_info_t *sockdrv = NULL;
1204 			sockdrv = pcmcia_number_socket(dip, sock);
1205 			if (sockdrv == NULL)
1206 				n = sock + pcmcia_num_sockets;
1207 			else {
1208 				n = ddi_get_instance(sockdrv);
1209 			}
1210 			/* make sure we know first socket on adapter */
1211 			if (pcmcia_adapters[i]->pca_first_socket == -1)
1212 				pcmcia_adapters[i]->pca_first_socket = n;
1213 
1214 			/*
1215 			 * the number of sockets is weird.
1216 			 * we might have only two sockets but
1217 			 * due to persistence of instances we
1218 			 * will need to call them something other
1219 			 * than 0 and 1.  So, we use the largest
1220 			 * instance number as the number and
1221 			 * have some that just don't get used.
1222 			 */
1223 			if (n >= pcmcia_num_sockets)
1224 				pcmcia_num_sockets = n + 1;
1225 #if defined(PCMCIA_DEBUG)
1226 			if (pcmcia_debug) {
1227 				cmn_err(CE_CONT,
1228 					"pcmcia_init: new socket added %d "
1229 					"(%d)\n",
1230 					n, pcmcia_num_sockets);
1231 			}
1232 #endif
1233 
1234 			pcmcia_sockets[n] =
1235 				kmem_zalloc(sizeof (pcmcia_logical_socket_t),
1236 				KM_SLEEP);
1237 			pcmcia_sockets[n]->ls_socket = sock;
1238 			pcmcia_sockets[n]->ls_if = ls_if;
1239 			pcmcia_sockets[n]->ls_adapter =
1240 				pcmcia_adapters[i];
1241 			pcmcia_sockets[n]->ls_cs_events = 0L;
1242 			pcmcia_sockets[n]->ls_sockdrv = sockdrv;
1243 			/* Prototype of intrspec */
1244 			pcmcia_sockets[n]->ls_intr_pri =
1245 				adapter->an_ipl;
1246 #if defined(PCMCIA_DEBUG)
1247 			if (pcmcia_debug)
1248 				cmn_err(CE_CONT,
1249 					"phys sock %d, log sock %d\n",
1250 					sock, n);
1251 #endif
1252 			mutex_init(&pcmcia_sockets[n]->ls_ilock, NULL,
1253 				MUTEX_DRIVER, *adapter->an_iblock);
1254 		}
1255 
1256 		pcmcia_adapters[i]->pca_numsockets = conf.NumSockets;
1257 		/* now setup the per window information */
1258 		for (win = 0; win < conf.NumWindows; win++) {
1259 			n = win + pcmcia_num_windows;
1260 			pcmcia_windows[n] =
1261 				kmem_zalloc(sizeof (pcmcia_logical_window_t),
1262 				    KM_SLEEP);
1263 			pcmcia_windows[n]->lw_window = win;
1264 			pcmcia_windows[n]->lw_if = ls_if;
1265 			pcmcia_windows[n]->lw_adapter =
1266 				pcmcia_adapters[i];
1267 		}
1268 		pcmcia_num_windows += conf.NumWindows;
1269 		SET_CALLBACK(ls_if, dip,
1270 		    pcm_adapter_callback, i);
1271 
1272 		/* now tell CS about each socket */
1273 		for (sock = 0; sock < pcmcia_num_sockets; sock++) {
1274 #if defined(PCMCIA_DEBUG)
1275 			if (pcmcia_debug) {
1276 				cmn_err(CE_CONT,
1277 					"pcmcia_init: notify CS socket %d "
1278 					"sockp=%p\n",
1279 					sock, (void *)pcmcia_sockets[sock]);
1280 			}
1281 #endif
1282 			if (pcmcia_sockets[sock] == NULL ||
1283 			    (pcmcia_sockets[sock]->ls_flags &
1284 				PCS_SOCKET_ADDED)) {
1285 				/* skip the ones that are done already */
1286 				continue;
1287 			}
1288 			pcmcia_sockets[sock]->ls_flags |= PCS_SOCKET_ADDED;
1289 			if (cs_event(PCE_ADD_SOCKET, sock, 0) !=
1290 			    CS_SUCCESS) {
1291 				/* flag socket as broken */
1292 				pcmcia_sockets[sock]->ls_flags = 0;
1293 			} else {
1294 				pcm_event_manager(PCE_ADD_SOCKET,
1295 				    sock, NULL);
1296 			}
1297 		}
1298 
1299 	}
1300 #if defined(PCMCIA_DEBUG)
1301 	if (pcmcia_debug) {
1302 		cmn_err(CE_CONT, "logical sockets:\n");
1303 		for (i = 0; i < pcmcia_num_sockets; i++) {
1304 			if (pcmcia_sockets[i] == NULL)
1305 				continue;
1306 			cmn_err(CE_CONT,
1307 				"\t%d: phys sock=%d, if=%p, adapt=%p\n",
1308 				i, pcmcia_sockets[i]->ls_socket,
1309 				(void *)pcmcia_sockets[i]->ls_if,
1310 				(void *)pcmcia_sockets[i]->ls_adapter);
1311 		}
1312 		cmn_err(CE_CONT, "logical windows:\n");
1313 		for (i = 0; i < pcmcia_num_windows; i++) {
1314 			cmn_err(CE_CONT,
1315 				"\t%d: phys_window=%d, if=%p, adapt=%p\n",
1316 				i, pcmcia_windows[i]->lw_window,
1317 				(void *)pcmcia_windows[i]->lw_if,
1318 				(void *)pcmcia_windows[i]->lw_adapter);
1319 		}
1320 		cmn_err(CE_CONT, "\tpcmcia_num_power=%d\n", pcmcia_num_power);
1321 		for (n = 0; n < pcmcia_num_power; n++)
1322 			cmn_err(CE_CONT,
1323 				"\t\tPowerLevel: %d\tValidSignals: %x\n",
1324 				pcmcia_power_table[n].PowerLevel,
1325 				pcmcia_power_table[n].ValidSignals);
1326 	}
1327 #endif
1328 }
1329 
1330 /*
1331  * pcmcia_enum_thread()
1332  *
1333  *	This thread is scheduled by pcmcia_attach() to enumerate the
1334  *	cards present in an adapter at boot time.
1335  *	pcmcia_enum_lock is used to serialize the execution of this
1336  *	thread with pcmcia_attach().
1337  */
1338 static void
1339 pcmcia_enum_thread(anp_t *adapter)
1340 {
1341 	mutex_enter(&pcmcia_enum_lock);
1342 	pcmcia_find_cards(adapter);
1343 	mutex_exit(&pcmcia_enum_lock);
1344 	thread_exit();
1345 }
1346 
1347 /*
1348  * pcmcia_find_cards()
1349  *	check the adapter to see if there are cards present at
1350  *	driver attach time.  If there are, generate an artificial
1351  *	card insertion event to get CS running and the PC Card ultimately
1352  *	identified.
1353  */
1354 void
1355 pcmcia_find_cards(anp_t *adapt)
1356 {
1357 	int i;
1358 	get_ss_status_t status;
1359 	for (i = 0; i < pcmcia_num_sockets; i++) {
1360 		if (pcmcia_sockets[i] &&
1361 		    pcmcia_sockets[i]->ls_if == adapt->an_if) {
1362 			/* check the status */
1363 			status.socket = i;
1364 			if (SSGetStatus(&status) == SUCCESS &&
1365 			    status.IFType != IF_CARDBUS &&
1366 			    status.CardState & SBM_CD &&
1367 			    pcmcia_sockets[i]->ls_dip[0] == NULL) {
1368 				(void) cs_event(PCE_CARD_INSERT, i, 0);
1369 				delay(1);
1370 			}
1371 		}
1372 	}
1373 }
1374 
1375 /*
1376  * pcmcia_number_socket(dip, adapt)
1377  *	we determine socket number by creating a driver for each
1378  *	socket on the adapter and then forcing it to attach.  This
1379  *	results in an instance being assigned which becomes the
1380  *	logical socket number.	If it fails, then we are the first
1381  *	set of sockets and renumbering occurs later.  We do this
1382  *	one socket at a time and return the dev_info_t so the
1383  *	instance number can be used.
1384  */
1385 dev_info_t *
1386 pcmcia_number_socket(dev_info_t *dip, int localsocket)
1387 {
1388 	dev_info_t *child = NULL;
1389 	struct pcmcia_parent_private *ppd;
1390 
1391 	if (ndi_devi_alloc(dip, "pcs", (pnode_t)DEVI_SID_NODEID,
1392 	    &child) == NDI_SUCCESS) {
1393 		ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
1394 		    KM_SLEEP);
1395 		ppd->ppd_reg = kmem_zalloc(sizeof (struct pcm_regs), KM_SLEEP);
1396 		ppd->ppd_nreg = 1;
1397 		ppd->ppd_reg[0].phys_hi = localsocket;
1398 		ddi_set_parent_data(child, (caddr_t)ppd);
1399 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
1400 			(void) ndi_devi_free(child);
1401 			child = NULL;
1402 		}
1403 	}
1404 	return (child);
1405 }
1406 
1407 /*
1408  * pcm_phys_to_log_socket()
1409  *	from an adapter and socket number return the logical socket
1410  */
1411 int
1412 pcm_phys_to_log_socket(struct pcmcia_adapter *adapt, int socket)
1413 {
1414 	register pcmcia_logical_socket_t *sockp;
1415 	int i;
1416 
1417 	for (i = 0, sockp = pcmcia_sockets[0];
1418 		i < pcmcia_num_sockets; i++, sockp = pcmcia_sockets[i]) {
1419 		if (sockp == NULL)
1420 			continue;
1421 		if (sockp->ls_socket == socket && sockp->ls_adapter == adapt)
1422 			break;
1423 	}
1424 	if (i >= pcmcia_num_sockets) {
1425 #if defined(PCMCIA_DEBUG)
1426 		if (pcmcia_debug)
1427 			cmn_err(CE_CONT,
1428 				"\tbad socket/adapter: %x/%p != %x/%x\n",
1429 				socket, (void *)adapt, pcmcia_num_sockets,
1430 				pcmcia_num_adapters);
1431 #endif
1432 		return (-1);
1433 	}
1434 
1435 	return (i);		/* want logical socket */
1436 }
1437 
1438 /*
1439  * pcm_adapter_callback()
1440  *	this function is called back by the adapter driver at interrupt time.
1441  *	It is here that events should get generated for the event manager if it
1442  *	is present.  It would also be the time where a device information
1443  *	tree could be constructed for a card that was added in if we
1444  *	choose to create them dynamically.
1445  */
1446 
1447 #if defined(PCMCIA_DEBUG)
1448 char *cblist[] = {
1449 	"removal",
1450 	"insert",
1451 	"ready",
1452 	"battery-warn",
1453 	"battery-dead",
1454 	"status-change",
1455 	"write-protect", "reset", "unlock", "client-info", "eject-complete",
1456 	"eject-request", "erase-complete", "exclusive-complete",
1457 	"exclusive-request", "insert-complete", "insert-request",
1458 	"reset-complete", "reset-request", "timer-expired",
1459 	"resume", "suspend"
1460 };
1461 #endif
1462 
1463 /*ARGSUSED*/
1464 static int
1465 pcm_adapter_callback(dev_info_t *dip, int adapter, int event, int socket)
1466 {
1467 	pcmcia_logical_socket_t *sockp;
1468 
1469 #if defined(PCMCIA_DEBUG)
1470 	if (pcmcia_debug) {
1471 		cmn_err(CE_CONT, "pcm_adapter_callback: %p %x %x %x: ",
1472 			(void *)dip, adapter, event, socket);
1473 		cmn_err(CE_CONT, "[%s]\n", cblist[event]);
1474 	}
1475 #endif
1476 
1477 	if (adapter >= pcmcia_num_adapters || adapter < 0) {
1478 #if defined(PCMCIA_DEBUG)
1479 		if (pcmcia_debug)
1480 			cmn_err(CE_CONT, "\tbad adapter number: %d : %d\n",
1481 				adapter, pcmcia_num_adapters);
1482 #endif
1483 		return (1);
1484 	}
1485 
1486 	/* get the logical socket since that is what CS knows */
1487 	socket = pcm_phys_to_log_socket(pcmcia_adapters[adapter], socket);
1488 	if (socket == -1) {
1489 		cmn_err(CE_WARN, "pcmcia callback - bad logical socket\n");
1490 		return (0);
1491 	}
1492 	sockp = pcmcia_sockets[socket];
1493 	switch (event) {
1494 	case -1:		/* special case of adapter going away */
1495 	case PCE_CARD_INSERT:
1496 		sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
1497 			PCE_E2M(PCE_CARD_REMOVAL);
1498 		break;
1499 	case PCE_CARD_REMOVAL:
1500 				/* disable interrupts at this point */
1501 		sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
1502 			PCE_E2M(PCE_CARD_REMOVAL);
1503 		/* remove children that never attached */
1504 
1505 		break;
1506 	case PCE_PM_RESUME:
1507 		pcmcia_do_resume(socket, sockp);
1508 		/* event = PCE_CARD_INSERT; */
1509 		break;
1510 	case PCE_PM_SUSPEND:
1511 		pcmcia_do_suspend(socket, sockp);
1512 		/* event = PCE_CARD_REMOVAL; */
1513 		break;
1514 	default:
1515 		/* nothing to do */
1516 		break;
1517 	}
1518 
1519 #if defined(PCMCIA_DEBUG)
1520 	if (pcmcia_debug) {
1521 		cmn_err(CE_CONT,
1522 			"\tevent %d, event mask=%x, match=%x (log socket=%d)\n",
1523 			event,
1524 			(int)sockp->ls_cs_events,
1525 			(int)(sockp->ls_cs_events & PCE_E2M(event)), socket);
1526 	}
1527 #endif
1528 
1529 	if (pcmcia_cs_event && sockp->ls_cs_events & (1 << event)) {
1530 #if defined(PCMCIA_DEBUG)
1531 		if (pcmcia_debug)
1532 			cmn_err(CE_CONT, "\tcalling CS event handler (%p) "
1533 				"with event=%d\n",
1534 				(void *)pcmcia_cs_event, event);
1535 #endif
1536 		CS_EVENT(event, socket, 0);
1537 	}
1538 
1539 	/* let the event manager(s) know about the event */
1540 	pcm_event_manager(event, socket, NULL);
1541 
1542 	return (0);
1543 }
1544 
1545 /*
1546  * pcm_event_manager()
1547  *	checks for registered management driver callback handlers
1548  *	if there are any, call them if the event warrants it
1549  */
1550 void
1551 pcm_event_manager(int event, int socket, void *arg)
1552 {
1553 	struct pcmcia_mif *mif;
1554 
1555 	for (mif = pcmcia_mif_handlers; mif != NULL; mif = mif->mif_next) {
1556 #if defined(PCMCIA_DEBUG)
1557 		if (pcmcia_debug)
1558 			cmn_err(CE_CONT,
1559 				"pcm_event_manager: event=%d, mif_events=%x"
1560 				" (tst:%d)\n",
1561 				event, (int)*(uint32_t *)mif->mif_events,
1562 				PR_GET(mif->mif_events, event));
1563 #endif
1564 		if (PR_GET(mif->mif_events, event)) {
1565 			mif->mif_function(mif->mif_id, event, socket, arg);
1566 		}
1567 	}
1568 
1569 }
1570 
1571 /*
1572  * pcm_search_devinfo(dev_info_t *, pcm_device_info *, int)
1573  * search for an immediate child node to the nexus and not siblings of nexus
1574  * and not grandchildren.  We follow the same sequence that name binding
1575  * follows so we match same class of device (modem == modem) and don't
1576  * have to depend on features that might not exist.
1577  */
1578 dev_info_t *
1579 pcm_search_devinfo(dev_info_t *self, struct pcm_device_info *info, int socket)
1580 {
1581 	char bf[256];
1582 	struct pcmcia_parent_private *ppd;
1583 	dev_info_t *dip;
1584 	int circular;
1585 
1586 #if defined(PCMCIA_DEBUG)
1587 	if (pcmcia_debug)
1588 		cmn_err(CE_CONT,
1589 		    "pcm_search_devinfo: socket=%x [%s|%s|%s] pd_flags=%x\n",
1590 		    socket, info->pd_bind_name, info->pd_generic_name,
1591 		    info->pd_vers1_name, info->pd_flags);
1592 #endif
1593 
1594 	ndi_devi_enter(self, &circular);
1595 	/* do searches in compatible property order */
1596 	for (dip = (dev_info_t *)DEVI(self)->devi_child;
1597 	    dip != NULL;
1598 	    dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
1599 		int ppd_socket;
1600 		ppd = (struct pcmcia_parent_private *)
1601 			ddi_get_parent_data(dip);
1602 		if (ppd == NULL) {
1603 #if defined(PCMCIA_DEBUG)
1604 			cmn_err(CE_WARN, "No parent private data\n");
1605 #endif
1606 			continue;
1607 		}
1608 		ppd_socket = CS_MAKE_SOCKET_NUMBER(ppd->ppd_socket,
1609 		    ppd->ppd_function);
1610 #if defined(PCMCIA_DEBUG)
1611 		if (pcmcia_debug) {
1612 			cmn_err(CE_CONT, "\tbind=[%s], node=[%s]\n",
1613 				DEVI(dip)->devi_binding_name,
1614 				DEVI(dip)->devi_node_name);
1615 		}
1616 #endif
1617 		if (info->pd_flags & PCM_NAME_VERS1) {
1618 			(void) strcpy(bf, info->pd_vers1_name);
1619 			pcmcia_fix_string(bf);
1620 			if (DEVI(dip)->devi_binding_name &&
1621 			    strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
1622 			    socket == ppd_socket)
1623 				break;
1624 		}
1625 		if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
1626 		    (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
1627 			(void) sprintf(bf, "%s,%x", info->pd_bind_name,
1628 				info->pd_function);
1629 			if (strcmp(bf, DEVI(dip)->devi_binding_name) == 0 &&
1630 			    socket == ppd->ppd_socket)
1631 				break;
1632 		}
1633 		if (info->pd_flags & PCM_NAME_1275) {
1634 			if (DEVI(dip)->devi_binding_name &&
1635 			    strcmp(DEVI(dip)->devi_binding_name,
1636 				info->pd_bind_name) == 0 &&
1637 			    socket == ppd_socket)
1638 				break;
1639 		}
1640 		if (info->pd_flags & PCM_NAME_GENERIC) {
1641 			(void) sprintf(bf, "%s,%s", PCMDEV_NAMEPREF,
1642 				info->pd_generic_name);
1643 			if (DEVI(dip)->devi_binding_name &&
1644 			    strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
1645 			    socket == ppd_socket)
1646 				break;
1647 		}
1648 		if (info->pd_flags & PCM_NAME_GENERIC) {
1649 			if (DEVI(dip)->devi_binding_name &&
1650 			    strcmp(DEVI(dip)->devi_binding_name,
1651 				info->pd_generic_name) == 0 &&
1652 			    socket == ppd_socket)
1653 				break;
1654 		}
1655 		if (info->pd_flags & PCM_NO_CONFIG) {
1656 			if (DEVI(dip)->devi_binding_name &&
1657 			    strcmp(DEVI(dip)->devi_binding_name,
1658 					"pccard,memory") == 0 &&
1659 			    socket == ppd_socket)
1660 				break;
1661 		}
1662 	}
1663 	ndi_devi_exit(self, circular);
1664 	return (dip);
1665 }
1666 
1667 /*
1668  * pcm_find_devinfo()
1669  *	this is a wrapper around DDI calls to "find" any
1670  *	devinfo node and then from there find the one associated
1671  *	with the socket
1672  */
1673 dev_info_t *
1674 pcm_find_devinfo(dev_info_t *pdip, struct pcm_device_info *info, int socket)
1675 {
1676 	dev_info_t *dip;
1677 
1678 	dip = pcm_search_devinfo(pdip, info, socket);
1679 	if (dip == NULL)
1680 		return (NULL);
1681 	/*
1682 	 * we have at least a base level dip
1683 	 * see if there is one (this or a sibling)
1684 	 * that has the correct socket number
1685 	 * if there is, return that one else
1686 	 * NULL so a new one is created
1687 	 */
1688 #if defined(PCMCIA_DEBUG)
1689 	if (pcmcia_debug)
1690 		cmn_err(CE_CONT, "find: initial dip = %p, socket=%d, name=%s "
1691 			"(instance=%d, socket=%d, name=%s)\n",
1692 			(void *)dip, socket, info->pd_bind_name,
1693 			ddi_get_instance(dip),
1694 			ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1695 			PCM_DEV_SOCKET, -1),
1696 			ddi_get_name(dip));
1697 #endif
1698 
1699 #if defined(PCMCIA_DEBUG)
1700 	if (pcmcia_debug && dip != NULL)
1701 		cmn_err(CE_CONT, "\treturning non-NULL dip (%s)\n",
1702 			ddi_get_name(dip));
1703 #endif
1704 	return (dip);
1705 }
1706 
1707 /*
1708  * pcm_find_parent_dip(socket)
1709  *	find the correct parent dip for this logical socket
1710  */
1711 dev_info_t *
1712 pcm_find_parent_dip(int socket)
1713 {
1714 	if ((socket < 0 || socket >= pcmcia_num_sockets) ||
1715 	    pcmcia_sockets[socket] == NULL)
1716 		return (NULL);
1717 	return (pcmcia_sockets[socket]->ls_adapter->pca_dip);
1718 }
1719 
1720 /*
1721  * pcmcia_set_em_handler()
1722  *	This is called by the management and event driver to tell
1723  *	the nexus what to call.	 Multiple drivers are allowed
1724  *	but normally only one will exist.
1725  */
1726 int
1727 pcmcia_set_em_handler(int (*handler)(), caddr_t events, int elen,
1728 			uint32_t id, void **cs, void **ss)
1729 {
1730 	struct pcmcia_mif *mif, *tmp;
1731 
1732 	if (handler == NULL) {
1733 		/* NULL means remove the handler based on the ID */
1734 		if (pcmcia_mif_handlers == NULL)
1735 			return (0);
1736 		mutex_enter(&pcmcia_global_lock);
1737 		if (pcmcia_mif_handlers->mif_id == id) {
1738 			mif = pcmcia_mif_handlers;
1739 			pcmcia_mif_handlers = mif->mif_next;
1740 			kmem_free(mif, sizeof (struct pcmcia_mif));
1741 		} else {
1742 			for (mif = pcmcia_mif_handlers;
1743 			    mif->mif_next != NULL &&
1744 			    mif->mif_next->mif_id != id;
1745 			    mif = mif->mif_next)
1746 				;
1747 			if (mif->mif_next != NULL &&
1748 			    mif->mif_next->mif_id == id) {
1749 				tmp = mif->mif_next;
1750 				mif->mif_next = tmp->mif_next;
1751 				kmem_free(tmp, sizeof (struct pcmcia_mif));
1752 			}
1753 		}
1754 		mutex_exit(&pcmcia_global_lock);
1755 	} else {
1756 
1757 		if (pcmcia_num_adapters == 0) {
1758 			return (ENXIO);
1759 		}
1760 		if (elen > EM_EVENTSIZE)
1761 			return (EINVAL);
1762 
1763 		mif = (struct pcmcia_mif *)
1764 			kmem_zalloc(sizeof (struct pcmcia_mif),
1765 			    KM_NOSLEEP);
1766 		if (mif == NULL)
1767 			return (ENOSPC);
1768 
1769 		mif->mif_function = (void (*)())handler;
1770 		bcopy(events, mif->mif_events, elen);
1771 		mif->mif_id = id;
1772 		mutex_enter(&pcmcia_global_lock);
1773 		mif->mif_next = pcmcia_mif_handlers;
1774 		pcmcia_mif_handlers = mif;
1775 		if (cs != NULL)
1776 			*cs = (void *)pcmcia_card_services;
1777 		if (ss != NULL) {
1778 			*ss = (void *)SocketServices;
1779 		}
1780 
1781 		mutex_exit(&pcmcia_global_lock);
1782 	}
1783 	return (0);
1784 }
1785 
1786 /*
1787  * pcm_fix_bits(uchar_t *data, int num, int dir)
1788  *	shift socket bits left(0) or right(0)
1789  *	This is used when mapping logical and physical
1790  */
1791 void
1792 pcm_fix_bits(socket_enum_t src, socket_enum_t dst, int num, int dir)
1793 {
1794 	int i;
1795 
1796 	PR_ZERO(dst);
1797 
1798 	if (dir == 0) {
1799 				/* LEFT */
1800 		for (i = 0; i <= (sizeof (dst) * PR_WORDSIZE) - num; i++) {
1801 			if (PR_GET(src, i))
1802 				PR_SET(dst, i + num);
1803 		}
1804 	} else {
1805 				/* RIGHT */
1806 		for (i = num; i < sizeof (dst) * PR_WORDSIZE; i++) {
1807 			if (PR_GET(src, i))
1808 			    PR_SET(dst, i - num);
1809 		}
1810 	}
1811 }
1812 
1813 uint32_t
1814 genmask(int len)
1815 {
1816 	uint32_t mask;
1817 	for (mask = 0; len > 0; len--) {
1818 		mask |= 1 << (len - 1);
1819 	}
1820 	return (mask);
1821 }
1822 
1823 int
1824 genp2(int val)
1825 {
1826 	int i;
1827 	if (val == 0)
1828 		return (0);
1829 	for (i = 0; i < 32; i++)
1830 		if (val > (1 << i))
1831 			return (i);
1832 	return (0);
1833 }
1834 
1835 #if defined(PCMCIA_DEBUG)
1836 char *ssfuncs[128] = {
1837 	"GetAdapter", "GetPage", "GetSocket", "GetStatus", "GetWindow",
1838 	"InquireAdapter", "InquireSocket", "InquireWindow", "ResetSocket",
1839 	"SetPage", "SetAdapter", "SetSocket", "SetWindow", "SetIRQHandler",
1840 	"ClearIRQHandler",
1841 	/* 15 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1842 	/* 25 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1843 	/* 35 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1844 	/* 45 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1845 	/* 55 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1846 	/* 65 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1847 	/* 75 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1848 	/* 85 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1849 	/* 95 */ NULL, NULL, NULL,
1850 	"CSIsActiveDip",
1851 	"CSInitDev", "CSRegister", "CSCISInit", "CSUnregister",
1852 	"CISGetAddress", "CISSetAddress", "CSCardRemoved", "CSGetCookiesAndDip"
1853 };
1854 #endif
1855 
1856 /*
1857  * SocketServices
1858  *	general entrypoint for Card Services to find
1859  *	Socket Services.  Finding the entry requires
1860  *	a _depends_on[] relationship.
1861  *
1862  *	In some cases, the work is done locally but usually
1863  *	the parameters are adjusted and the adapter driver
1864  *	code asked to do the work.
1865  */
1866 int
1867 SocketServices(int function, ...)
1868 {
1869 	va_list arglist;
1870 	uint32_t args[16];
1871 	csregister_t *reg;
1872 	sservice_t *serv;
1873 	dev_info_t *dip;
1874 	int socket, func;
1875 	int error = SUCCESS;
1876 	pcmcia_logical_socket_t *sockp;
1877 
1878 	va_start(arglist, function);
1879 
1880 #if defined(PCMCIA_DEBUG)
1881 	if (pcmcia_debug > 1)
1882 		cmn_err(CE_CONT, "SocketServices called for function %d [%s]\n",
1883 			function,
1884 			((function < 128) && ssfuncs[function] != NULL) ?
1885 			ssfuncs[function] : "UNKNOWN");
1886 #endif
1887 	switch (function) {
1888 	case CSRegister:
1889 	case CISGetAddress:
1890 	case CISSetAddress:
1891 
1892 		reg = va_arg(arglist, csregister_t *);
1893 
1894 		if (reg->cs_magic != PCCS_MAGIC ||
1895 		    reg->cs_version != PCCS_VERSION) {
1896 			cmn_err(CE_WARN,
1897 				"pcmcia: CSRegister (%x, %x, %p, %p) *ERROR*",
1898 				reg->cs_magic, reg->cs_version,
1899 				(void *)reg->cs_card_services,
1900 				(void *)reg->cs_event);
1901 			error = BAD_FUNCTION;
1902 			break;
1903 		}
1904 
1905 		switch (function) {
1906 		case CISGetAddress:
1907 			reg->cs_event = pcmcia_cis_parser;
1908 			break;
1909 		case CISSetAddress:
1910 			pcmcia_cis_parser = reg->cs_event;
1911 			break;
1912 		case CSRegister:
1913 			break;
1914 		}
1915 		break;
1916 
1917 	case CSUnregister:
1918 		break;
1919 
1920 	case CSCISInit:
1921 		args[0] = va_arg(arglist, int);
1922 #if defined(PCMCIA_DEBUG)
1923 		if (pcmcia_debug)
1924 			cmn_err(CE_CONT,
1925 				"CSCISInit: CIS is initialized on socket %d\n",
1926 				(int)args[0]);
1927 #endif
1928 		/*
1929 		 * now that the CIS has been parsed (there may not
1930 		 * be one but the work is done) we can create the
1931 		 * device information structures.
1932 		 *
1933 		 * we serialize the node creation to avoid problems
1934 		 * with initial probe/attach of nexi.
1935 		 */
1936 
1937 		mutex_enter(&pcmcia_global_lock);
1938 		pcmcia_create_dev_info(args[0]);
1939 		cv_broadcast(&pcmcia_condvar); /* wakeup the nexus attach */
1940 		mutex_exit(&pcmcia_global_lock);
1941 		break;
1942 
1943 	case CSInitDev:
1944 #if defined(PCMCIA_DEBUG)
1945 		if (pcmcia_debug)
1946 			cmn_err(CE_CONT, "CSInitDev: initialize device\n");
1947 #endif
1948 		/*
1949 		 * this is where we create the /devices entries
1950 		 * that let us out into the world
1951 		 */
1952 
1953 		(void) pcmcia_create_device(va_arg(arglist,
1954 		    ss_make_device_node_t *));
1955 		break;
1956 
1957 	case CSCardRemoved:
1958 		args[0] = va_arg(arglist, uint32_t);
1959 		socket = CS_GET_SOCKET_NUMBER(args[0]);
1960 		func = CS_GET_FUNCTION_NUMBER(args[0]);
1961 #if defined(PCMCIA_DEBUG)
1962 		if (pcmcia_debug)
1963 			cmn_err(CE_CONT,
1964 				"CSCardRemoved! (socket=%d)\n", (int)args[0]);
1965 #endif
1966 		if (socket >= pcmcia_num_sockets)
1967 			break;
1968 
1969 		sockp = pcmcia_sockets[socket];
1970 		if (sockp == NULL) {
1971 			cmn_err(CE_WARN,
1972 			    "pcmcia: bad socket = %x", socket);
1973 			break;
1974 		}
1975 
1976 		for (func = 0; func < sockp->ls_functions; func++) {
1977 			/*
1978 			 * break the association of dip and socket
1979 			 * for all functions on that socket
1980 			 */
1981 			dip = sockp->ls_dip[func];
1982 			sockp->ls_dip[func] = NULL;
1983 			if (dip != NULL) {
1984 				struct pcmcia_parent_private *ppd;
1985 				ppd = (struct pcmcia_parent_private *)
1986 				    ddi_get_parent_data(dip);
1987 				ppd->ppd_active = 0;
1988 				(void) ndi_devi_offline(dip,
1989 				    NDI_DEVI_REMOVE);
1990 			}
1991 #if defined(PCMCIA_DEBUG)
1992 			else {
1993 				if (pcmcia_debug)
1994 					cmn_err(CE_CONT,
1995 					    "CardRemoved: no "
1996 					    "dip present "
1997 					    "on socket %d!\n",
1998 					    (int)args[0]);
1999 			}
2000 #endif
2001 		}
2002 		if (sockp->ls_flags & PCS_SUSPENDED) {
2003 			mutex_enter(&pcmcia_global_lock);
2004 			sockp->ls_flags &= ~PCS_SUSPENDED;
2005 			cv_broadcast(&pcmcia_condvar);
2006 			mutex_exit(&pcmcia_global_lock);
2007 		}
2008 		break;
2009 
2010 	case CSGetCookiesAndDip:
2011 		serv = va_arg(arglist, sservice_t *);
2012 		if (serv != NULL)
2013 			error = GetCookiesAndDip(serv);
2014 		else
2015 			error = BAD_SOCKET;
2016 		break;
2017 
2018 	case CSGetActiveDip:
2019 		/*
2020 		 * get the dip associated with the card currently
2021 		 * in the specified socket
2022 		 */
2023 		args[0] = va_arg(arglist, uint32_t);
2024 		socket = CS_GET_SOCKET_NUMBER(args[0]);
2025 		func = CS_GET_FUNCTION_NUMBER(args[0]);
2026 		error = (long)pcmcia_sockets[socket]->ls_dip[func];
2027 		break;
2028 
2029 		/*
2030 		 * the remaining entries are SocketServices calls
2031 		 */
2032 	case SS_GetAdapter:
2033 		error = SSGetAdapter(va_arg(arglist, get_adapter_t *));
2034 		break;
2035 	case SS_GetPage:
2036 		error = SSGetPage(va_arg(arglist, get_page_t *));
2037 		break;
2038 	case SS_GetSocket:
2039 		error = SSGetSocket(va_arg(arglist, get_socket_t *));
2040 		break;
2041 	case SS_GetStatus:
2042 		error = SSGetStatus(va_arg(arglist, get_ss_status_t *));
2043 		break;
2044 	case SS_GetWindow:
2045 		error = SSGetWindow(va_arg(arglist, get_window_t *));
2046 		break;
2047 	case SS_InquireAdapter:
2048 		error = SSInquireAdapter(va_arg(arglist, inquire_adapter_t *));
2049 		break;
2050 	case SS_InquireSocket:
2051 		error = SSInquireSocket(va_arg(arglist, inquire_socket_t *));
2052 		break;
2053 	case SS_InquireWindow:
2054 		error = SSInquireWindow(va_arg(arglist, inquire_window_t *));
2055 		break;
2056 	case SS_ResetSocket:
2057 		args[0] = va_arg(arglist, uint32_t);
2058 		args[1] = va_arg(arglist, int);
2059 		error = SSResetSocket(args[0], args[1]);
2060 		break;
2061 	case SS_SetPage:
2062 		error = SSSetPage(va_arg(arglist, set_page_t *));
2063 		break;
2064 	case SS_SetSocket:
2065 		error = SSSetSocket(va_arg(arglist, set_socket_t *));
2066 		break;
2067 	case SS_SetWindow:
2068 		error = SSSetWindow(va_arg(arglist, set_window_t *));
2069 		break;
2070 	case SS_SetIRQHandler:
2071 		error = SSSetIRQHandler(va_arg(arglist, set_irq_handler_t *));
2072 		break;
2073 	case SS_ClearIRQHandler:
2074 		error = SSClearIRQHandler(va_arg(arglist,
2075 		    clear_irq_handler_t *));
2076 		break;
2077 	default:
2078 		error = BAD_FUNCTION;
2079 		break;
2080 	}
2081 	va_end(arglist);
2082 	return (error);
2083 }
2084 
2085 /*
2086  * pcmcia_merge_power()
2087  *	The adapters may have different power tables so it
2088  *	is necessary to construct a single power table that
2089  *	can be used throughout the system.  The result is
2090  *	a merger of all capabilities.  The nexus adds
2091  *	power table entries one at a time.
2092  */
2093 void
2094 pcmcia_merge_power(struct power_entry *power)
2095 {
2096 	int i;
2097 	struct power_entry pwr;
2098 
2099 	pwr = *power;
2100 
2101 	for (i = 0; i < pcmcia_num_power; i++) {
2102 		if (pwr.PowerLevel == pcmcia_power_table[i].PowerLevel) {
2103 			if (pwr.ValidSignals ==
2104 				pcmcia_power_table[i].ValidSignals) {
2105 				return;
2106 			} else {
2107 				/* partial match */
2108 				pwr.ValidSignals &=
2109 					~pcmcia_power_table[i].ValidSignals;
2110 			}
2111 		}
2112 	}
2113 	/* what's left becomes a new entry */
2114 	if (pcmcia_num_power == PCMCIA_MAX_POWER)
2115 		return;
2116 	pcmcia_power_table[pcmcia_num_power++] = pwr;
2117 }
2118 
2119 /*
2120  * pcmcia_do_suspend()
2121  *	tell CS that a suspend has happened by passing a
2122  *	card removal event.  Then cleanup the socket state
2123  *	to fake the cards being removed so resume works
2124  */
2125 void
2126 pcmcia_do_suspend(int socket, pcmcia_logical_socket_t *sockp)
2127 {
2128 	get_ss_status_t stat;
2129 	struct pcmcia_adapter *adapt;
2130 	pcmcia_if_t *ls_if;
2131 	dev_info_t *dip;
2132 	int i;
2133 
2134 #ifdef	XXX
2135 	if (pcmcia_cs_event == NULL) {
2136 		return;
2137 	}
2138 #endif
2139 
2140 	ls_if = sockp->ls_if;
2141 	adapt = sockp->ls_adapter;
2142 
2143 	if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
2144 		return;
2145 	}
2146 
2147 	stat.socket = socket;
2148 #if defined(PCMCIA_DEBUG)
2149 	if (pcmcia_debug) {
2150 		cmn_err(CE_CONT,
2151 			"pcmcia_do_suspend(%d, %p)\n", socket, (void *)sockp);
2152 	}
2153 #endif
2154 
2155 	if (GET_STATUS(ls_if, adapt->pca_dip, &stat) != SUCCESS)
2156 		return;
2157 
2158 	/*
2159 	 * If there is a card in the socket, then we need to send
2160 	 *	everyone a PCE_CARD_REMOVAL event, and remove the
2161 	 *	card active property.
2162 	 */
2163 
2164 	for (i = 0; i < sockp->ls_functions; i++) {
2165 		struct pcmcia_parent_private *ppd;
2166 		dip = sockp->ls_dip[i];
2167 		if (dip != NULL) {
2168 			ppd = (struct pcmcia_parent_private *)
2169 				ddi_get_parent_data(dip);
2170 			ppd->ppd_flags |= PPD_SUSPENDED;
2171 		}
2172 #if 0
2173 		sockp->ls_dip[i] = NULL;
2174 #endif
2175 	}
2176 	sockp->ls_flags |= PCS_SUSPENDED;
2177 
2178 	if (pcmcia_cs_event &&
2179 	    (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
2180 		CS_EVENT(PCE_PM_SUSPEND, socket, 0);
2181 	}
2182 	pcm_event_manager(PCE_PM_SUSPEND, socket, NULL);
2183 }
2184 
2185 /*
2186  * pcmcia_do_resume()
2187  *	tell CS that a suspend has happened by passing a
2188  *	card removal event.  Then cleanup the socket state
2189  *	to fake the cards being removed so resume works
2190  */
2191 void
2192 pcmcia_do_resume(int socket, pcmcia_logical_socket_t *sockp)
2193 {
2194 	get_ss_status_t stat;
2195 	struct pcmcia_adapter *adapt;
2196 	pcmcia_if_t *ls_if;
2197 
2198 #ifdef	XXX
2199 	if (pcmcia_cs_event == NULL) {
2200 		return;
2201 	}
2202 #endif
2203 
2204 	ls_if = sockp->ls_if;
2205 	adapt = sockp->ls_adapter;
2206 
2207 	if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
2208 		return;
2209 	}
2210 
2211 	stat.socket = socket;
2212 #if defined(PCMCIA_DEBUG)
2213 	if (pcmcia_debug) {
2214 		cmn_err(CE_CONT,
2215 			"pcmcia_do_resume(%d, %p)\n", socket, (void *)sockp);
2216 	}
2217 #endif
2218 	if (GET_STATUS(ls_if, adapt->pca_dip, &stat) ==
2219 	    SUCCESS) {
2220 
2221 #if defined(PCMCIA_DEBUG)
2222 		if (pcmcia_debug)
2223 			cmn_err(CE_CONT, "\tsocket=%x, CardState=%x\n",
2224 				socket, stat.CardState);
2225 #endif
2226 #if 0
2227 		/* now have socket info -- do we have events? */
2228 		if ((stat.CardState & SBM_CD) == SBM_CD) {
2229 			if (pcmcia_cs_event &&
2230 			    (sockp->ls_cs_events & (1 << PCE_CARD_INSERT))) {
2231 				CS_EVENT(PCE_CARD_INSERT, socket, 0);
2232 			}
2233 
2234 			/* we should have card removed from CS soon */
2235 			pcm_event_manager(PCE_CARD_INSERT, socket, NULL);
2236 		}
2237 #else
2238 		if (pcmcia_cs_event &&
2239 		    (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
2240 			CS_EVENT(PCE_PM_RESUME, socket, 0);
2241 			CS_EVENT(PCE_CARD_REMOVAL, socket, 0);
2242 			if ((stat.CardState & SBM_CD) == SBM_CD)
2243 				CS_EVENT(PCE_CARD_INSERT, socket, 0);
2244 		}
2245 #endif
2246 	}
2247 }
2248 
2249 /*
2250  * pcmcia_map_power_set()
2251  *	Given a power table entry and level, find it in the
2252  *	master table and return the index in the adapter table.
2253  */
2254 static int
2255 pcmcia_map_power_set(struct pcmcia_adapter *adapt, int level, int which)
2256 {
2257 	int plevel, i;
2258 	struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
2259 	plevel = pcmcia_power_table[level].PowerLevel;
2260 	/* mask = pcmcia_power_table[level].ValidSignals; */
2261 	for (i = 0; i < adapt->pca_numpower; i++)
2262 		if (plevel == pwr[i].PowerLevel &&
2263 		    pwr[i].ValidSignals & which)
2264 			return (i);
2265 	return (0);
2266 }
2267 
2268 /*
2269  * pcmcia_map_power_get()
2270  *	Given an adapter power entry, find the appropriate index
2271  *	in the master table.
2272  */
2273 static int
2274 pcmcia_map_power_get(struct pcmcia_adapter *adapt, int level, int which)
2275 {
2276 	int plevel, i;
2277 	struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
2278 	plevel = pwr[level].PowerLevel;
2279 	/* mask = pwr[level].ValidSignals; */
2280 	for (i = 0; i < pcmcia_num_power; i++)
2281 		if (plevel == pcmcia_power_table[i].PowerLevel &&
2282 		    pcmcia_power_table[i].ValidSignals & which)
2283 			return (i);
2284 	return (0);
2285 }
2286 
2287 /*
2288  * XXX - SS really needs a way to allow the caller to express
2289  *	interest in PCE_CARD_STATUS_CHANGE events.
2290  */
2291 static uint32_t
2292 pcm_event_map[32] = {
2293 	PCE_E2M(PCE_CARD_WRITE_PROTECT)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2294 	PCE_E2M(PCE_CARD_UNLOCK)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2295 	PCE_E2M(PCE_EJECTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2296 	PCE_E2M(PCE_INSERTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2297 	PCE_E2M(PCE_CARD_BATTERY_WARN)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2298 	PCE_E2M(PCE_CARD_BATTERY_DEAD)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2299 	PCE_E2M(PCE_CARD_READY)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2300 	PCE_E2M(PCE_CARD_REMOVAL)|PCE_E2M(PCE_CARD_INSERT)|
2301 					PCE_E2M(PCE_CARD_STATUS_CHANGE),
2302 	PCE_E2M(PCE_PM_SUSPEND)|PCE_E2M(PCE_PM_RESUME),
2303 };
2304 
2305 static int
2306 pcm_mapevents(uint32_t eventmask)
2307 {
2308 	uint32_t mask;
2309 	int i;
2310 
2311 	for (i = 0, mask = 0; eventmask && i < 32; i++) {
2312 		if (eventmask & (1 << i)) {
2313 			mask |= pcm_event_map[i];
2314 			eventmask &= ~(1 << i);
2315 		}
2316 	}
2317 	return (mask);
2318 }
2319 
2320 
2321 /*
2322  * PCMCIA Generic Naming Support
2323  *
2324  * With 2.6, PCMCIA naming moves to the 1275 and generic naming model.
2325  * Consequently, the whole naming mechanism is to be changed.  This is
2326  * not backward compatible with the current names but that isn't a problem
2327  * due to so few drivers existing.
2328  *
2329  * For cards with a device_id tuple, a generic name will be used.
2330  * if there is no device_id, then the 1275 name will be used if possible.
2331  * The 1275 name is of the form pccardNNNN,MMMM from the manfid tuple.
2332  * if there is not manfid tuple, an attempt will be made to bind the
2333  * node to the version_1 strings.
2334  *
2335  * In all cases, a "compatible" property is created with a number
2336  * of names.  The most generic name will be last in the list.
2337  */
2338 
2339 /*
2340  * pcmcia_fix_string()
2341  * want to avoid special characters in alias strings so convert
2342  * to something innocuous
2343  */
2344 
2345 void
2346 pcmcia_fix_string(char *str)
2347 {
2348 	for (; str && *str; str++) {
2349 		switch (*str) {
2350 			case ' ':
2351 			case '\t':
2352 				*str = '_';
2353 				break;
2354 		}
2355 	}
2356 }
2357 
2358 void
2359 pcmcia_1275_name(int socket, struct pcm_device_info *info,
2360 			client_handle_t handle)
2361 {
2362 	cistpl_manfid_t manfid;
2363 	cistpl_jedec_t jedec;
2364 	tuple_t tuple;
2365 	int i;
2366 
2367 	tuple.Socket = socket;
2368 
2369 	/* get MANFID if it exists -- this is most important form */
2370 	tuple.DesiredTuple = CISTPL_MANFID;
2371 	tuple.Attributes = 0;
2372 	if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2373 	    SUCCESS) {
2374 		i = csx_Parse_CISTPL_MANFID(handle, &tuple,
2375 		    &manfid);
2376 		if (i == SUCCESS) {
2377 			(void) sprintf(info->pd_bind_name, "%s%x,%x",
2378 				PCMDEV_NAMEPREF,
2379 				manfid.manf, manfid.card);
2380 			info->pd_flags |= PCM_NAME_1275;
2381 		}
2382 	} else {
2383 		tuple.Attributes = 0;
2384 		tuple.DesiredTuple = CISTPL_JEDEC_A;
2385 		if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2386 		    SUCCESS) {
2387 			i = csx_Parse_CISTPL_JEDEC_A(handle, &tuple,
2388 			    &jedec);
2389 			if (i == SUCCESS) {
2390 				(void) sprintf(info->pd_bind_name, "%s%x,%x",
2391 					PCMDEV_NAMEPREF,
2392 					jedec.jid[0].id, jedec.jid[0].info);
2393 				info->pd_flags |= PCM_NAME_1275;
2394 			}
2395 		}
2396 	}
2397 }
2398 
2399 void
2400 pcmcia_vers1_name(int socket, struct pcm_device_info *info,
2401 			client_handle_t handle)
2402 {
2403 	cistpl_vers_1_t vers1;
2404 	tuple_t tuple;
2405 	int which = 0;
2406 	int i, len, space;
2407 
2408 	tuple.Socket = socket;
2409 	info->pd_vers1_name[0] = '\0';
2410 
2411 	/* Version 1 strings */
2412 	tuple.DesiredTuple = CISTPL_VERS_1;
2413 	tuple.Attributes = 0;
2414 	if (!which &&
2415 	    (i = csx_GetFirstTuple(handle, &tuple)) ==
2416 		SUCCESS) {
2417 		i = csx_Parse_CISTPL_VERS_1(handle, &tuple, &vers1);
2418 		if (i == SUCCESS) {
2419 			for (i = 0, len = 0, space = 0; i < vers1.ns; i++) {
2420 			    if ((space + len + strlen(info->pd_vers1_name)) >=
2421 				sizeof (info->pd_vers1_name))
2422 				    break;
2423 			    if (space) {
2424 				    info->pd_vers1_name[len++] = ',';
2425 			    }
2426 			    (void) strcpy(info->pd_vers1_name + len,
2427 				(char *)vers1.pi[i]);
2428 			    len += strlen((char *)vers1.pi[i]);
2429 			    /* strip trailing spaces off of string */
2430 			    while (info->pd_vers1_name[len - 1] == ' ' &&
2431 				    len > 0)
2432 				    len--;
2433 			    space = 1;
2434 			}
2435 			info->pd_vers1_name[len] = '\0';
2436 			info->pd_flags |= PCM_NAME_VERS1;
2437 		}
2438 	}
2439 }
2440 
2441 
2442 int
2443 pcmcia_get_funce(client_handle_t handle, tuple_t *tuple)
2444 {
2445 	int ret = 0;
2446 
2447 	tuple->Attributes = 0;
2448 	while (csx_GetNextTuple(handle, tuple) == SUCCESS) {
2449 		if (tuple->TupleCode == CISTPL_FUNCID) {
2450 			break;
2451 		}
2452 		if (tuple->TupleCode == CISTPL_FUNCE) {
2453 			ret = 1;
2454 			break;
2455 		}
2456 		tuple->Attributes = 0;
2457 	}
2458 	return (ret);
2459 }
2460 
2461 char *pcmcia_lan_types[] = {
2462 	"arcnet",
2463 	"ethernet",
2464 	"token-ring",
2465 	"localtalk",
2466 	"fddi",
2467 	"atm",
2468 	"wireless",
2469 	"reserved"
2470 };
2471 
2472 void
2473 pcmcia_generic_name(int socket, struct pcm_device_info *info,
2474 			client_handle_t handle)
2475 {
2476 	cistpl_funcid_t funcid;
2477 	cistpl_funce_t funce;
2478 	tuple_t tuple;
2479 	int which = 0;
2480 	int i;
2481 
2482 	tuple.Socket = socket;
2483 
2484 	tuple.DesiredTuple = CISTPL_FUNCID;
2485 	tuple.Attributes = 0;
2486 	if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2487 	    SUCCESS) {
2488 		/*
2489 		 * need to make sure that CISTPL_FUNCID is not
2490 		 * present in both a global and local CIS for MF
2491 		 * cards.  3COM seems to do this erroneously
2492 		 */
2493 
2494 		if (info->pd_flags & PCM_MULTI_FUNCTION &&
2495 		    tuple.Flags & CISTPLF_GLOBAL_CIS) {
2496 			tuple_t ltuple;
2497 			ltuple = tuple;
2498 			ltuple.DesiredTuple = CISTPL_FUNCID;
2499 			ltuple.Attributes = 0;
2500 			if ((i = csx_GetNextTuple(handle, &ltuple)) ==
2501 			    SUCCESS) {
2502 				/* this is the per-function funcid */
2503 				tuple = ltuple;
2504 			}
2505 		}
2506 
2507 		i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid);
2508 		if (i == SUCCESS) {
2509 			/* in case no function extension */
2510 			if (funcid.function < PCM_GENNAME_SIZE)
2511 				(void) strcpy(info->pd_generic_name,
2512 				    pcmcia_generic_names[funcid.function]);
2513 			else
2514 				(void) sprintf(info->pd_generic_name,
2515 					"class,%x",
2516 					funcid.function);
2517 		}
2518 		info->pd_type = funcid.function;
2519 		switch (funcid.function) {
2520 		case TPLFUNC_LAN:
2521 			which = pcmcia_get_funce(handle, &tuple);
2522 			if (which) {
2523 				i = csx_Parse_CISTPL_FUNCE(handle,
2524 				    &tuple,
2525 				    &funce, TPLFUNC_LAN);
2526 				if (i == SUCCESS) {
2527 					i = funce.data.lan.tech;
2528 					if (i > sizeof (pcmcia_lan_types) /
2529 					    sizeof (char *)) {
2530 						break;
2531 					}
2532 					(void) strcpy(info->pd_generic_name,
2533 						pcmcia_lan_types[i]);
2534 				}
2535 			}
2536 			break;
2537 		case TPLFUNC_VIDEO:
2538 #ifdef future_pcmcia_spec
2539 			which = pcmcia_get_funce(handle, &tuple);
2540 			if (which) {
2541 				i = csx_Parse_CISTPL_FUNCE(handle,
2542 				    &tuple,
2543 				    &funce, TPLFUNC_VIDEO);
2544 				if (i == SUCCESS) {
2545 					i = funce.video.tech;
2546 					if (i > sizeof (pcmcia_lan_types) /
2547 					    sizeof (char *)) {
2548 						break;
2549 					}
2550 					(void) strcpy(info->pd_generic_names,
2551 						pcmcia_lan_types[i]);
2552 				}
2553 			}
2554 #endif
2555 			break;
2556 		}
2557 		info->pd_flags |= PCM_NAME_GENERIC;
2558 	} else {
2559 		/* if no FUNCID, do we have CONFIG */
2560 		tuple.DesiredTuple = CISTPL_CONFIG;
2561 		tuple.Attributes = 0;
2562 		if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) {
2563 			info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC;
2564 			(void) strcpy(info->pd_generic_name,
2565 				pcmcia_generic_names[PCM_TYPE_MEMORY]);
2566 			info->pd_type = PCM_TYPE_MEMORY;
2567 		}
2568 	}
2569 }
2570 
2571 
2572 /*
2573  * pcmcia_add_compatible()
2574  * add the cached compatible property list.
2575  */
2576 void
2577 pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info)
2578 {
2579 	int length = 0, i;
2580 	char buff[MAXNAMELEN];
2581 	char *compat_name[8];
2582 	int ci = 0;
2583 
2584 	bzero(compat_name, sizeof (compat_name));
2585 
2586 	if (info->pd_flags & PCM_NAME_VERS1) {
2587 		(void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
2588 		    info->pd_vers1_name);
2589 		pcmcia_fix_string(buff); /* don't want spaces */
2590 		length = strlen(buff) + 1;
2591 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2592 		(void) strcpy(compat_name[ci++], buff);
2593 	}
2594 
2595 	if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
2596 	    (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
2597 		(void) sprintf(buff, "%s,%x", info->pd_bind_name,
2598 		    info->pd_function);
2599 		length = strlen(buff) + 1;
2600 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2601 		(void) strcpy(compat_name[ci++], buff);
2602 	}
2603 
2604 	if (info->pd_flags & PCM_NAME_1275) {
2605 		length = strlen(info->pd_bind_name) + 1;
2606 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2607 		(void) strcpy(compat_name[ci++], info->pd_bind_name);
2608 	}
2609 
2610 	if (info->pd_flags & PCM_NAME_GENERIC) {
2611 		if (strncmp(info->pd_generic_name, "class,", 6) == 0) {
2612 			/* no generic without "pccard" */
2613 			(void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF,
2614 				info->pd_generic_name);
2615 		} else {
2616 			/* first pccard,generic-name */
2617 			(void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
2618 				info->pd_generic_name);
2619 		}
2620 		length = strlen(buff) + 1;
2621 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2622 		(void) strcpy(compat_name[ci++], buff);
2623 
2624 		/* now the simple generic name */
2625 		length = strlen(info->pd_generic_name) + 1;
2626 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2627 		(void) strcpy(compat_name[ci++], info->pd_generic_name);
2628 	}
2629 
2630 	if (info->pd_flags & PCM_NO_CONFIG) {
2631 		char *mem = "pccard,memory";
2632 		/*
2633 		 * I/O cards are required to have a config tuple.
2634 		 * there are some that violate the spec and don't
2635 		 * but it is most likely that this is a memory card
2636 		 * so tag it as such.  "memory" is more general
2637 		 * than other things so needs to come last.
2638 		 */
2639 		length = strlen(mem) + 1;
2640 		compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2641 		(void) strcpy(compat_name[ci++], mem);
2642 	}
2643 
2644 	if (ci == 0)
2645 		return;
2646 
2647 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
2648 	    "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS)
2649 		cmn_err(CE_WARN, "pcmcia: unable to create compatible prop");
2650 
2651 	for (i = 0; i < ci; i++)
2652 		kmem_free(compat_name[i], strlen(compat_name[i]) + 1);
2653 }
2654 /*
2655  * CIS parsing and other PC Card specific code
2656  */
2657 
2658 /*
2659  * pcmcia_get_mem_regs()
2660  */
2661 static int
2662 pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info,
2663 			int type, int pctype)
2664 {
2665 	int num_regs = 0;
2666 	tuple_t tuple;
2667 	cistpl_device_t device;
2668 	uint32_t curr_base;
2669 	int ret, len;
2670 	int space;
2671 
2672 	/*
2673 	 * current plan for reg spec:
2674 	 * device_a will be accumulated to determine max size of
2675 	 * attribute memory.  device for common.  Then config
2676 	 * tuples to get a worst case I/O size.
2677 	 */
2678 	bzero(&tuple, sizeof (tuple));
2679 	tuple.Socket = info->pd_socket;
2680 
2681 	tuple.DesiredTuple = (cisdata_t)type;
2682 
2683 	space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE :
2684 		PC_REG_SPACE_MEMORY;
2685 	if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) {
2686 		bzero(&device, sizeof (device));
2687 
2688 		if (type == CISTPL_DEVICE)
2689 			ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple,
2690 			    &device);
2691 		else
2692 			ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple,
2693 			    &device);
2694 
2695 		if (ret == CS_SUCCESS) {
2696 		    curr_base = 0;
2697 		    for (ret = 0; ret < device.num_devices;
2698 			ret++) {
2699 			    /* need to order these for real mem first */
2700 			    if (device.devnode[ret].type !=
2701 				CISTPL_DEVICE_DTYPE_NULL) {
2702 				    /* how to represent types??? */
2703 				    regs[num_regs].phys_hi =
2704 					PC_REG_PHYS_HI(0, 0,
2705 					    pctype,
2706 					    space,
2707 					    info->pd_socket,
2708 					    info->pd_function,
2709 					    0);
2710 				    regs[num_regs].phys_lo = curr_base;
2711 				    len = device.devnode[ret].size_in_bytes;
2712 				    curr_base += len;
2713 				    regs[num_regs].phys_len = len;
2714 				    num_regs++;
2715 			    } else {
2716 				/*
2717 				 * NULL device is a "hole"
2718 				 */
2719 				    curr_base +=
2720 					    device.devnode[ret].size_in_bytes;
2721 			    }
2722 			}
2723 	    }
2724 	}
2725 	return (num_regs);
2726 }
2727 
2728 /*
2729  *
2730  */
2731 static int
2732 pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info,
2733 		    int pctype)
2734 {
2735 	int num_regs = 0;
2736 	tuple_t tuple;
2737 	uint32_t curr_base;
2738 	int len, curr, i, curr_len;
2739 	cistpl_config_t config;
2740 	cistpl_cftable_entry_t cftable;
2741 	struct pcm_regs tmp[16];
2742 	int found = 0;
2743 
2744 	bzero(&tuple, sizeof (tuple));
2745 	tuple.DesiredTuple = CISTPL_CONFIG;
2746 	tuple.Socket = info->pd_socket;
2747 	tuple.Attributes = 0;
2748 	curr_base = 0;
2749 	len = 0;
2750 
2751 	if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) {
2752 	    if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
2753 					&tuple, &config) != CS_SUCCESS) {
2754 		info->pd_flags |= PCM_NO_CONFIG; /* must be memory */
2755 		return (0);
2756 	}
2757 	curr = 0;
2758 
2759 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
2760 	tuple.Socket = info->pd_socket;
2761 	tuple.Attributes = 0;
2762 	bzero(tmp, sizeof (tmp));
2763 	while (csx_GetNextTuple(info->pd_handle,
2764 				&tuple) == CS_SUCCESS) {
2765 	    bzero(&cftable, sizeof (cftable));
2766 	    if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
2767 						&tuple, &cftable) ==
2768 		CS_SUCCESS) {
2769 		if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) {
2770 		    /* we have an I/O entry */
2771 		    if (cftable.io.flags &
2772 			CISTPL_CFTABLE_TPCE_FS_IO_RANGE) {
2773 			len = cftable.io.addr_lines;
2774 			if (len != 0)
2775 				len = 1 << len;
2776 			for (i = 0; i < cftable.io.ranges && curr < 16; i++) {
2777 			    curr_base = cftable.io.range[i].addr;
2778 			    curr_len = cftable.io.range[i].length;
2779 			    if (curr_len == 0)
2780 				    curr_len = len;
2781 			    if (len != 0 || cftable.io.addr_lines == 0) {
2782 				/* we have potential relocation */
2783 				int mask;
2784 				mask = cftable.io.addr_lines ?
2785 						cftable.io.addr_lines :
2786 							genp2(len);
2787 				mask = genmask(mask);
2788 				if ((mask & curr_base) == 0) {
2789 					/* more accurate length */
2790 					regs->phys_len = curr_len;
2791 					regs->phys_lo = 0;
2792 					regs->phys_hi =
2793 					    PC_REG_PHYS_HI(0,
2794 						0,
2795 						pctype,
2796 						PC_REG_SPACE_IO,
2797 						info->pd_socket,
2798 						info->pd_function,
2799 						0);
2800 					num_regs++;
2801 					found = 2;
2802 					break;
2803 				}
2804 			    }
2805 			    tmp[curr].phys_len = curr_len;
2806 			    tmp[curr].phys_lo = curr_base;
2807 			    curr++;
2808 			    found = 1;
2809 			}
2810 			if (found == 2)
2811 				break;
2812 		    } else {
2813 			/* no I/O range so just a mask */
2814 			regs->phys_len = 1 << cftable.io.addr_lines;
2815 			regs->phys_hi =
2816 				PC_REG_PHYS_HI(0,
2817 						0,
2818 						pctype,
2819 						PC_REG_SPACE_IO,
2820 						info->pd_socket,
2821 						info->pd_function,
2822 						0);
2823 			regs->phys_lo = 0;
2824 			num_regs++;
2825 			regs++;
2826 			/* quit on "good" entry */
2827 			break;
2828 		    }
2829 		    /* was this the last CFTABLE Entry? */
2830 		    if (config.last == cftable.index)
2831 			    break;
2832 		}
2833 	    }
2834 	}
2835 	if (found == 1) {
2836 		/*
2837 		 * have some non-relocatable values
2838 		 * so we include them all for now
2839 		 */
2840 		for (i = 0; i < curr && num_regs < 8; i++) {
2841 		    regs->phys_len = tmp[i].phys_len;
2842 		    regs->phys_lo = tmp[i].phys_lo;
2843 		    regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype,
2844 			    PC_REG_SPACE_IO, info->pd_socket,
2845 			    info->pd_function, 0);
2846 		    regs++;
2847 		    num_regs++;
2848 		}
2849 	    }
2850 	}
2851 	return (num_regs);
2852 }
2853 
2854 /*
2855  * pcmcia_create_regs()
2856  *	create a valid set of regspecs for the card
2857  *	The first one is always for CIS access and naming
2858  */
2859 /*ARGSUSED*/
2860 static void
2861 pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info,
2862 			struct pcmcia_parent_private *ppd)
2863 {
2864 	struct pcm_regs regs[32]; /* assume worst case */
2865 	int num_regs = 0;
2866 	int len;
2867 	int bustype;
2868 
2869 	if (ppd->ppd_flags & PPD_CARD_CARDBUS) {
2870 		/* always have a CIS map */
2871 		regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS,
2872 						PC_REG_SPACE_CONFIG,
2873 						info->pd_socket,
2874 						info->pd_function, 0);
2875 		bustype = PC_REG_TYPE_CARDBUS;
2876 	} else {
2877 		/* always have a CIS map */
2878 		regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
2879 						PC_REG_SPACE_ATTRIBUTE,
2880 						info->pd_socket,
2881 						info->pd_function, 0);
2882 		bustype = PC_REG_TYPE_16BIT;
2883 	}
2884 	regs[0].phys_lo = 0;	/* always starts at zero */
2885 	regs[0].phys_len = 0;
2886 	num_regs++;
2887 	/*
2888 	 * need to search CIS for other memory instances
2889 	 */
2890 
2891 	if (info->pd_flags & PCM_OTHER_NOCIS) {
2892 		/* special case of memory only card without CIS */
2893 		regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
2894 						PC_REG_SPACE_MEMORY,
2895 						info->pd_socket,
2896 						info->pd_function, 0);
2897 		regs[1].phys_lo = 0;
2898 		regs[1].phys_len = PCM_MAX_R2_MEM;
2899 		num_regs++;
2900 	} else {
2901 		/*
2902 		 * want to get any other memory and/or I/O regions
2903 		 * on the card and represent them here.
2904 		 */
2905 		num_regs += pcmcia_get_mem_regs(&regs[num_regs], info,
2906 						CISTPL_DEVICE_A, bustype);
2907 		num_regs += pcmcia_get_mem_regs(&regs[num_regs], info,
2908 						CISTPL_DEVICE, bustype);
2909 
2910 		/* now look for an I/O space to configure */
2911 		num_regs += pcmcia_get_io_regs(&regs[num_regs], info,
2912 						bustype);
2913 
2914 	}
2915 
2916 	len = num_regs * sizeof (uint32_t) * 3;
2917 	ppd->ppd_nreg = num_regs;
2918 	ppd->ppd_reg = kmem_alloc(len, KM_SLEEP);
2919 	bcopy(regs, ppd->ppd_reg, len);
2920 	len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
2921 	ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP);
2922 }
2923 
2924 
2925 /*
2926  * pcmcia_need_intr()
2927  *	check to see if an interrupt tuple exists.
2928  *	existence means we need one in the intrspec.
2929  */
2930 static int
2931 pcmcia_need_intr(int socket, struct pcm_device_info *info)
2932 {
2933 	cistpl_config_t config;
2934 	cistpl_cftable_entry_t cftable;
2935 	tuple_t tuple;
2936 	int i;
2937 
2938 	bzero(&tuple, sizeof (tuple));
2939 	tuple.DesiredTuple = CISTPL_CONFIG;
2940 	tuple.Socket = socket;
2941 	tuple.Attributes = 0;
2942 	if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) {
2943 		return (0);
2944 	}
2945 #if defined(PCMCIA_DEBUG)
2946 	if (pcmcia_debug) {
2947 		cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n");
2948 	}
2949 #endif
2950 	bzero(&config, sizeof (config));
2951 	if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
2952 	    &tuple, &config) != CS_SUCCESS) {
2953 		cmn_err(CE_WARN, "pcmcia: config failed to parse\n");
2954 		return (0);
2955 	}
2956 
2957 	for (cftable.index = (int)-1, i = -1;
2958 		i != config.last; i = cftable.index) {
2959 		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
2960 		tuple.Attributes = 0;
2961 		if (csx_GetNextTuple(info->pd_handle,
2962 		    &tuple) != CS_SUCCESS) {
2963 			cmn_err(CE_WARN, "pcmcia: get cftable failed\n");
2964 			break;
2965 		}
2966 		bzero(&cftable, sizeof (cftable));
2967 		if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
2968 		    &tuple, &cftable) !=
2969 		    CS_SUCCESS) {
2970 			cmn_err(CE_WARN, "pcmcia: parse cftable failed\n");
2971 			break;
2972 		}
2973 #if defined(PCMCIA_DEBUG)
2974 		if (pcmcia_debug)
2975 			cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n",
2976 				i, cftable.flags,
2977 				cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ);
2978 #endif
2979 		if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ)
2980 			return (1);
2981 	}
2982 	return (0);
2983 
2984 }
2985 
2986 /*
2987  * pcmcia_num_funcs()
2988  *	look for a CISTPL_LONGLINK_MFC
2989  *	if there is one, return the number of functions
2990  *	if there isn't one, then there is one function
2991  */
2992 static int
2993 pcmcia_num_funcs(int socket, client_handle_t handle)
2994 {
2995 	int count = 1;
2996 	cistpl_longlink_mfc_t mfc;
2997 	tuple_t tuple;
2998 
2999 	bzero(&tuple, sizeof (tuple_t));
3000 	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
3001 	tuple.Socket = socket;
3002 	tuple.Attributes = 0;
3003 	if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) {
3004 		/* this is a multifunction card */
3005 		if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc,
3006 		    CISTPL_LONGLINK_MFC) == CS_SUCCESS) {
3007 			count = mfc.nfuncs;
3008 		}
3009 	}
3010 	return (count);
3011 }
3012 
3013 client_handle_t pcmcia_cs_handle;
3014 
3015 /*
3016  * pcmcia_create_dev_info(socket)
3017  *	either find or create the device information structure
3018  *	for the card(s) just inserted.	We don't care about removal yet.
3019  *	In any case, we will only do this at CS request
3020  */
3021 static void
3022 pcmcia_create_dev_info(int socket)
3023 {
3024 	struct pcm_device_info card_info;
3025 	client_reg_t reg;
3026 	cisinfo_t cisinfo;
3027 	int i;
3028 	dev_info_t *pdip;
3029 	static int handle_def = 0;
3030 
3031 #if defined(PCMCIA_DEBUG)
3032 	if (pcmcia_debug)
3033 		cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n",
3034 			socket);
3035 #endif
3036 
3037 	/*
3038 	 * before we can do anything else, we need the parent
3039 	 * devinfo of the socket.  This gets things in the right
3040 	 * place in the device tree.
3041 	 */
3042 
3043 	pdip = pcm_find_parent_dip(socket);
3044 	if (pdip == NULL)
3045 		return;
3046 
3047 	/* Card Services calls needed to get CIS info */
3048 	reg.dip = NULL;
3049 	reg.Attributes = INFO_SOCKET_SERVICES;
3050 	reg.EventMask = 0;
3051 	reg.event_handler = NULL;
3052 	reg.Version = CS_VERSION;
3053 
3054 	bzero(&card_info, sizeof (card_info));
3055 
3056 	if (handle_def == 0) {
3057 		if (csx_RegisterClient(&pcmcia_cs_handle,
3058 		    &reg) != CS_SUCCESS) {
3059 #if defined(PCMCIA_DEBUG)
3060 			if (pcmcia_debug)
3061 				cmn_err(CE_CONT,
3062 					"pcmcia: RegisterClient failed\n");
3063 #endif
3064 			return;
3065 		}
3066 		handle_def++;
3067 	}
3068 	card_info.pd_handle = pcmcia_cs_handle;
3069 
3070 #if defined(PCMCIA_DEBUG)
3071 	if (pcmcia_debug)
3072 		cmn_err(CE_CONT,
3073 			"pcmcia_create_dev_info: handle = %x\n",
3074 			(int)card_info.pd_handle);
3075 #endif
3076 	card_info.pd_type = -1; /* no type to start */
3077 	card_info.pd_socket = socket;
3078 	card_info.pd_function = 0;
3079 	pcmcia_sockets[socket]->ls_functions = 1; /* default */
3080 
3081 	cisinfo.Socket = socket;
3082 
3083 	if ((i = csx_ValidateCIS(card_info.pd_handle,
3084 	    &cisinfo)) != SUCCESS ||
3085 	    cisinfo.Tuples == 0) {
3086 		/* no CIS means memory */
3087 		(void) strcpy(card_info.pd_generic_name, "memory");
3088 		card_info.pd_flags |= PCM_NAME_GENERIC |
3089 			PCM_OTHER_NOCIS | PCM_NAME_1275;
3090 		(void) strcpy(card_info.pd_bind_name, "pccard,memory");
3091 		(void) strcpy(card_info.pd_generic_name, "memory");
3092 		card_info.pd_type = PCM_TYPE_MEMORY;
3093 	} else {
3094 		int functions, lsocket;
3095 		card_info.pd_tuples = cisinfo.Tuples;
3096 
3097 		/*
3098 		 * how many functions on the card?
3099 		 * we need to know and then we do one
3100 		 * child node for each function using
3101 		 * the function specific tuples.
3102 		 */
3103 		lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS);
3104 		functions = pcmcia_num_funcs(lsocket,
3105 		    card_info.pd_handle);
3106 		pcmcia_sockets[socket]->ls_functions = functions;
3107 		if (functions > 1) {
3108 			card_info.pd_flags |= PCM_MULTI_FUNCTION;
3109 		}
3110 		for (i = 0; i < functions; i++) {
3111 		    register int flags;
3112 		    lsocket = CS_MAKE_SOCKET_NUMBER(socket, i);
3113 		    card_info.pd_socket = socket;
3114 		    card_info.pd_function = i;
3115 			/*
3116 			 * new name construction
3117 			 */
3118 		    if (functions != 1) {
3119 			    /* need per function handle */
3120 			    card_info.pd_function = i;
3121 			    /* get new handle */
3122 		    }
3123 		    pcmcia_1275_name(lsocket, &card_info,
3124 			card_info.pd_handle);
3125 		    pcmcia_vers1_name(lsocket, &card_info,
3126 			card_info.pd_handle);
3127 		    pcmcia_generic_name(lsocket, &card_info,
3128 			card_info.pd_handle);
3129 		    flags = card_info.pd_flags;
3130 		    if (!(flags & PCM_NAME_1275)) {
3131 			if (flags & PCM_NAME_VERS1) {
3132 			    (void) strcpy(card_info.pd_bind_name,
3133 				PCMDEV_NAMEPREF);
3134 			    card_info.pd_bind_name[sizeof (PCMDEV_NAMEPREF)] =
3135 				',';
3136 			    (void) strncpy(card_info.pd_bind_name +
3137 				sizeof (PCMDEV_NAMEPREF),
3138 				card_info.pd_vers1_name,
3139 				MODMAXNAMELEN -
3140 				sizeof (PCMDEV_NAMEPREF));
3141 			    pcmcia_fix_string(card_info.pd_bind_name);
3142 			} else {
3143 				/*
3144 				 * have a CIS but not the right info
3145 				 * so treat as generic "pccard"
3146 				 */
3147 				(void) strcpy(card_info.pd_generic_name,
3148 					"pccard,memory");
3149 				card_info.pd_flags |= PCM_NAME_GENERIC;
3150 				(void) strcpy(card_info.pd_bind_name,
3151 					"pccard,memory");
3152 			}
3153 		    }
3154 		    pcmcia_init_devinfo(pdip, &card_info);
3155 		}
3156 		return;
3157 	}
3158 
3159 	pcmcia_init_devinfo(pdip, &card_info);
3160 }
3161 
3162 /*
3163  * pcmcia_init_devinfo()
3164  *	if there isn't a device info structure, create one
3165  *	if there is, we don't do much.
3166  *
3167  *	Note: this will need updating as 1275 finalizes their spec.
3168  */
3169 static void
3170 pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info)
3171 {
3172 	int unit;
3173 	dev_info_t *dip;
3174 	char *name;
3175 	struct pcmcia_parent_private *ppd;
3176 
3177 #if defined(PCMCIA_DEBUG)
3178 	if (pcmcia_debug)
3179 		cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name,
3180 			info->pd_socket);
3181 #endif
3182 
3183 	/*
3184 	 * find out if there is already an instance of this
3185 	 * device.  We don't want to create a new one unnecessarily
3186 	 */
3187 	unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function);
3188 
3189 	dip = pcm_find_devinfo(pdip, info, unit);
3190 	if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip,
3191 	    DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) {
3192 		/* it already exist but isn't a .conf file */
3193 
3194 #if defined(PCMCIA_DEBUG)
3195 		if (pcmcia_debug)
3196 			cmn_err(CE_CONT, "\tfound existing device node (%s)\n",
3197 				ddi_get_name(dip));
3198 #endif
3199 		if (strlen(info->pd_vers1_name) > 0)
3200 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
3201 			    dip, PCM_DEV_MODEL, info->pd_vers1_name);
3202 
3203 		ppd = (struct pcmcia_parent_private *)
3204 			ddi_get_parent_data(dip);
3205 
3206 		pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
3207 		    dip;
3208 
3209 		ppd->ppd_active = 1;
3210 
3211 		if (ndi_devi_online(dip, 0) == NDI_FAILURE) {
3212 			pcmcia_sockets[info->pd_socket]-> \
3213 			    ls_dip[info->pd_function] = NULL;
3214 			ppd->ppd_active = 0;
3215 		}
3216 	} else {
3217 
3218 		char *dtype;
3219 
3220 #if defined(PCMCIA_DEBUG)
3221 		if (pcmcia_debug)
3222 			cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n",
3223 			    info->pd_bind_name, info->pd_socket,
3224 			    info->pd_generic_name);
3225 #endif
3226 
3227 		if (info->pd_flags & PCM_NAME_GENERIC)
3228 			name = info->pd_generic_name;
3229 		else
3230 			name = info->pd_bind_name;
3231 
3232 		if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID,
3233 		    &dip) !=
3234 		    NDI_SUCCESS) {
3235 			cmn_err(CE_WARN,
3236 			    "pcmcia: unable to create device [%s](%d)\n",
3237 			    name, info->pd_socket);
3238 			return;
3239 		}
3240 		/*
3241 		 * construct the "compatible" property if the device
3242 		 * has a generic name
3243 		 */
3244 		pcmcia_add_compatible(dip, info);
3245 
3246 		ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
3247 			    KM_SLEEP);
3248 
3249 		ppd->ppd_socket = info->pd_socket;
3250 		ppd->ppd_function = info->pd_function;
3251 
3252 		/*
3253 		 * add the "socket" property
3254 		 * the value of this property contains the logical PCMCIA
3255 		 * socket number the device has been inserted in, along
3256 		 * with the function # if the device is part of a
3257 		 * multi-function device.
3258 		 */
3259 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3260 		    PCM_DEV_SOCKET, unit);
3261 
3262 		if (info->pd_flags & PCM_MULTI_FUNCTION)
3263 			ppd->ppd_flags |= PPD_CARD_MULTI;
3264 
3265 		/*
3266 		 * determine all the properties we need for PPD
3267 		 * then create the properties
3268 		 */
3269 		/* socket is unique */
3270 		pcmcia_find_regs(dip, info, ppd);
3271 
3272 		ppd->ppd_intr = pcmcia_need_intr(unit, info);
3273 
3274 		if (ppd->ppd_nreg > 0)
3275 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3276 			    "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg *
3277 			    sizeof (struct pcm_regs) / sizeof (int));
3278 		if (ppd->ppd_intr) {
3279 			(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
3280 			    "interrupts", ppd->ppd_intr);
3281 			ppd->ppd_intrspec =
3282 			    kmem_zalloc(sizeof (struct intrspec), KM_SLEEP);
3283 		}
3284 
3285 		/* set parent private - our own format */
3286 		ddi_set_parent_data(dip, (caddr_t)ppd);
3287 
3288 		/* init the device type */
3289 		if (info->pd_type >= 0 &&
3290 		    info->pd_type < (sizeof (pcmcia_dev_type) /
3291 		    (sizeof (char *))))
3292 			dtype = pcmcia_dev_type[info->pd_type];
3293 		else
3294 			dtype = "unknown";
3295 
3296 		if (strlen(info->pd_vers1_name) > 0)
3297 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
3298 			    dip, PCM_DEV_MODEL, info->pd_vers1_name);
3299 
3300 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
3301 		    PCM_DEVICETYPE, dtype);
3302 
3303 		/* set PC Card as active and present in socket */
3304 		pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
3305 			dip;
3306 
3307 		ppd->ppd_active = 1;
3308 
3309 		/*
3310 		 * We should not call ndi_devi_online here if
3311 		 * pcmcia attach is in progress. This causes a deadlock.
3312 		 */
3313 		if (pcmcia_dip != dip) {
3314 			if (ndi_devi_online_async(dip, 0)
3315 			    != NDI_SUCCESS) {
3316 				pcmcia_sockets[info->pd_socket]->\
3317 				ls_dip[info->pd_function] = NULL;
3318 				pcmcia_ppd_free(ppd);
3319 				(void) ndi_devi_free(dip);
3320 				return;
3321 			}
3322 		}
3323 
3324 #if defined(PCMCIA_DEBUG)
3325 	if (pcmcia_debug)
3326 		cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n",
3327 			ddi_get_name(dip), info->pd_socket);
3328 #endif
3329 	}
3330 
3331 	/*
3332 	 * inform the event manager that a child was added
3333 	 * to the device tree.
3334 	 */
3335 	pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip));
3336 
3337 #if defined(PCMCIA_DEBUG)
3338 	if (pcmcia_debug > 1) {
3339 		pcmcia_dump_minors(dip);
3340 	}
3341 #endif
3342 }
3343 
3344 /*
3345  * free any allocated parent-private data
3346  */
3347 static void
3348 pcmcia_ppd_free(struct pcmcia_parent_private *ppd)
3349 {
3350 	size_t len;
3351 
3352 	if (ppd->ppd_nreg != 0) {
3353 		len = ppd->ppd_nreg * sizeof (uint32_t) * 3;
3354 		kmem_free(ppd->ppd_reg, len);
3355 		len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
3356 		kmem_free(ppd->ppd_assigned, len);
3357 	}
3358 
3359 	/*
3360 	 * pcmcia only allocates 1 intrspec today
3361 	 */
3362 	if (ppd->ppd_intr != 0) {
3363 		len = sizeof (struct intrspec) * ppd->ppd_intr;
3364 		kmem_free(ppd->ppd_intrspec, len);
3365 	}
3366 
3367 	kmem_free(ppd, sizeof (*ppd));
3368 }
3369 
3370 
3371 /*
3372  * pcmcia_get_devinfo(socket)
3373  *	entry point to allow finding the device info structure
3374  *	for a given logical socket.  Used by event manager
3375  */
3376 dev_info_t *
3377 pcmcia_get_devinfo(int socket)
3378 {
3379 	int func = CS_GET_FUNCTION_NUMBER(socket);
3380 	socket = CS_GET_SOCKET_NUMBER(socket);
3381 	if (pcmcia_sockets[socket])
3382 		return (pcmcia_sockets[socket]->ls_dip[func]);
3383 	return ((dev_info_t *)NULL);
3384 }
3385 
3386 /*
3387  * CSGetCookiesAndDip()
3388  *	get info needed by CS to setup soft interrupt handler and provide
3389  *		socket-specific adapter information
3390  */
3391 static int
3392 GetCookiesAndDip(sservice_t *serv)
3393 {
3394 	pcmcia_logical_socket_t *socket;
3395 	csss_adapter_info_t *ai;
3396 	int sock;
3397 
3398 	sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket);
3399 
3400 	if (sock >= pcmcia_num_sockets ||
3401 	    (int)serv->get_cookies.socket < 0)
3402 		return (BAD_SOCKET);
3403 
3404 	socket = pcmcia_sockets[sock];
3405 	ai = &serv->get_cookies.adapter_info;
3406 	serv->get_cookies.dip = socket->ls_adapter->pca_dip;
3407 	serv->get_cookies.iblock = socket->ls_adapter->pca_iblock;
3408 	serv->get_cookies.idevice = socket->ls_adapter->pca_idev;
3409 
3410 	/*
3411 	 * Setup the adapter info for Card Services
3412 	 */
3413 	(void) strcpy(ai->name, socket->ls_adapter->pca_name);
3414 	ai->major = socket->ls_adapter->pca_module;
3415 	ai->minor = socket->ls_adapter->pca_unit;
3416 	ai->number = socket->ls_adapter->pca_number;
3417 	ai->num_sockets = socket->ls_adapter->pca_numsockets;
3418 	ai->first_socket = socket->ls_adapter->pca_first_socket;
3419 
3420 	return (SUCCESS);
3421 }
3422 
3423 /*
3424  * Note:
3425  *	The following functions that start with 'SS'
3426  *	implement SocketServices interfaces.  They
3427  *	simply map the socket and/or window number to
3428  *	the adapter specific number based on the general
3429  *	value that CardServices uses.
3430  *
3431  *	See the descriptions in SocketServices for
3432  *	details.  Also refer to specific adapter drivers
3433  *	for implementation reference.
3434  */
3435 
3436 static int
3437 SSGetAdapter(get_adapter_t *adapter)
3438 {
3439 	int n;
3440 	get_adapter_t info;
3441 
3442 	adapter->state = (unsigned)0xFFFFFFFF;
3443 	adapter->SCRouting = 0xFFFFFFFF;
3444 
3445 	for (n = 0; n < pcmcia_num_adapters; n++) {
3446 		GET_ADAPTER(pcmcia_adapters[n]->pca_if,
3447 			pcmcia_adapters[n]->pca_dip, &info);
3448 		adapter->state &= info.state;
3449 		adapter->SCRouting &= info.SCRouting;
3450 	}
3451 
3452 	return (SUCCESS);
3453 }
3454 
3455 static int
3456 SSGetPage(get_page_t *page)
3457 {
3458 	pcmcia_logical_window_t *window;
3459 	get_page_t newpage;
3460 	int retval, win;
3461 
3462 	if (page->window > pcmcia_num_windows) {
3463 		return (BAD_WINDOW);
3464 	}
3465 
3466 	window = pcmcia_windows[page->window];
3467 	newpage = *page;
3468 	win = newpage.window = window->lw_window; /* real window */
3469 
3470 	retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip,
3471 		&newpage);
3472 	if (retval == SUCCESS) {
3473 		*page = newpage;
3474 		page->window = win;
3475 	}
3476 	return (retval);
3477 }
3478 
3479 static int
3480 SSGetSocket(get_socket_t *socket)
3481 {
3482 	int retval, sock;
3483 	get_socket_t newsocket;
3484 	pcmcia_logical_socket_t *sockp;
3485 
3486 	sock = socket->socket;
3487 	if (sock > pcmcia_num_sockets ||
3488 		(sockp = pcmcia_sockets[sock]) == NULL) {
3489 		return (BAD_SOCKET);
3490 	}
3491 
3492 	newsocket = *socket;
3493 	newsocket.socket = sockp->ls_socket;
3494 	retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3495 	    &newsocket);
3496 	if (retval == SUCCESS) {
3497 		newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
3498 		    newsocket.VccLevel,
3499 		    VCC);
3500 		newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
3501 		    newsocket.Vpp1Level,
3502 		    VPP1);
3503 		newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
3504 		    newsocket.Vpp2Level,
3505 		    VPP2);
3506 		*socket = newsocket;
3507 		socket->socket = sock;
3508 	}
3509 
3510 	return (retval);
3511 }
3512 
3513 static int
3514 SSGetStatus(get_ss_status_t *status)
3515 {
3516 	get_ss_status_t newstat;
3517 	int sock, retval;
3518 	pcmcia_logical_socket_t *sockp;
3519 
3520 	sock = status->socket;
3521 	if (sock > pcmcia_num_sockets ||
3522 		(sockp = pcmcia_sockets[sock]) == NULL) {
3523 		return (BAD_SOCKET);
3524 	}
3525 
3526 	newstat = *status;
3527 	newstat.socket = sockp->ls_socket;
3528 	retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip,
3529 	    &newstat);
3530 	if (retval == SUCCESS) {
3531 		*status = newstat;
3532 		status->socket = sock;
3533 	}
3534 
3535 	return (retval);
3536 }
3537 
3538 static int
3539 SSGetWindow(get_window_t *window)
3540 {
3541 	int win, retval;
3542 	get_window_t newwin;
3543 	pcmcia_logical_window_t *winp;
3544 
3545 	win = window->window;
3546 	winp = pcmcia_windows[win];
3547 	newwin = *window;
3548 	newwin.window = winp->lw_window;
3549 
3550 	retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
3551 	    &newwin);
3552 	if (retval == SUCCESS) {
3553 		newwin.socket = winp->lw_socket;
3554 		newwin.window = win;
3555 		*window = newwin;
3556 	}
3557 	return (retval);
3558 }
3559 
3560 /*
3561  * SSInquireAdapter()
3562  *	Get the capabilities of the "generic" adapter
3563  *	we are exporting to CS.
3564  */
3565 static int
3566 SSInquireAdapter(inquire_adapter_t *adapter)
3567 {
3568 	adapter->NumSockets = pcmcia_num_sockets;
3569 	adapter->NumWindows = pcmcia_num_windows;
3570 	adapter->NumEDCs = 0;
3571 	/*
3572 	 * notes: Adapter Capabilities are going to be difficult to
3573 	 * determine with reliability.	Fortunately, most of them
3574 	 * don't matter under Solaris or can be handled transparently
3575 	 */
3576 	adapter->AdpCaps = 0;	/* need to fix these */
3577 	/*
3578 	 * interrupts need a little work.  For x86, the valid IRQs will
3579 	 * be restricted to those that the system has exported to the nexus.
3580 	 * for SPARC, it will be the DoRight values.
3581 	 */
3582 	adapter->ActiveHigh = 0;
3583 	adapter->ActiveLow = 0;
3584 	adapter->power_entry = pcmcia_power_table; /* until we resolve this */
3585 	adapter->NumPower = pcmcia_num_power;
3586 	return (SUCCESS);
3587 }
3588 
3589 static int
3590 SSInquireSocket(inquire_socket_t *socket)
3591 {
3592 	int retval, sock;
3593 	inquire_socket_t newsocket;
3594 	pcmcia_logical_socket_t *sockp;
3595 
3596 	sock = socket->socket;
3597 	if (sock > pcmcia_num_sockets ||
3598 		(sockp = pcmcia_sockets[sock]) == NULL)
3599 		return (BAD_SOCKET);
3600 	newsocket = *socket;
3601 	newsocket.socket = sockp->ls_socket;
3602 	retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3603 	    &newsocket);
3604 	if (retval == SUCCESS) {
3605 		*socket = newsocket;
3606 		socket->socket = sock;
3607 	}
3608 	return (retval);
3609 }
3610 
3611 static int
3612 SSInquireWindow(inquire_window_t *window)
3613 {
3614 	int retval, win;
3615 	pcmcia_logical_window_t *winp;
3616 	inquire_window_t newwin;
3617 	int slide;
3618 
3619 	win = window->window;
3620 	if (win > pcmcia_num_windows)
3621 		return (BAD_WINDOW);
3622 
3623 	winp = pcmcia_windows[win];
3624 	newwin = *window;
3625 	newwin.window = winp->lw_window;
3626 	retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
3627 	    &newwin);
3628 #if defined(PCMCIA_DEBUG)
3629 		if (pcmcia_debug > 1)
3630 			cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n",
3631 				win, newwin.window);
3632 #endif
3633 	if (retval == SUCCESS) {
3634 		*window = newwin;
3635 		/* just in case */
3636 		window->iowin_char.IOWndCaps &= ~WC_BASE;
3637 		slide = winp->lw_adapter->pca_first_socket;
3638 		/*
3639 		 * note that sockets are relative to the adapter.
3640 		 * we have to adjust the bits to show a logical
3641 		 * version.
3642 		 */
3643 
3644 		pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0);
3645 
3646 #if defined(PCMCIA_DEBUG)
3647 		if (pcmcia_debug > 1) {
3648 			cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n",
3649 				(int)*(uint32_t *)newwin.Sockets,
3650 				(int)*(uint32_t *)window->Sockets);
3651 			cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps,
3652 				window->mem_win_char.MemWndCaps,
3653 				window->mem_win_char.MinSize);
3654 		}
3655 #endif
3656 		window->window = win;
3657 	}
3658 	return (retval);
3659 }
3660 
3661 static int
3662 SSResetSocket(int socket, int mode)
3663 {
3664 	pcmcia_logical_socket_t *sockp;
3665 
3666 	if (socket >= pcmcia_num_sockets ||
3667 		(sockp = pcmcia_sockets[socket]) == NULL)
3668 		return (BAD_SOCKET);
3669 
3670 	return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3671 	    sockp->ls_socket, mode));
3672 }
3673 
3674 static int
3675 SSSetPage(set_page_t *page)
3676 {
3677 	int window, retval;
3678 	set_page_t newpage;
3679 	pcmcia_logical_window_t *winp;
3680 
3681 	window = page->window;
3682 	if (window > pcmcia_num_windows) {
3683 #if defined(PCMCIA_DEBUG)
3684 		if (pcmcia_debug > 1)
3685 			cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n",
3686 				window, pcmcia_num_windows);
3687 #endif
3688 		return (BAD_WINDOW);
3689 	}
3690 
3691 	winp = pcmcia_windows[window];
3692 	newpage = *page;
3693 	newpage.window = winp->lw_window;
3694 	retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage);
3695 	if (retval == SUCCESS) {
3696 		newpage.window = window;
3697 		*page = newpage;
3698 	}
3699 #if defined(PCMCIA_DEBUG)
3700 	if ((pcmcia_debug > 1) && retval != SUCCESS)
3701 		cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval);
3702 #endif
3703 	return (retval);
3704 }
3705 
3706 static int
3707 SSSetWindow(set_window_t *win)
3708 {
3709 	int socket, window, retval, func;
3710 	set_window_t newwin;
3711 	pcmcia_logical_window_t *winp;
3712 	pcmcia_logical_socket_t *sockp;
3713 
3714 	window = win->window;
3715 	if (window > pcmcia_num_windows)
3716 		return (BAD_WINDOW);
3717 
3718 	socket = CS_GET_SOCKET_NUMBER(win->socket);
3719 	func = CS_GET_FUNCTION_NUMBER(win->socket);
3720 
3721 	if (socket > pcmcia_num_sockets ||
3722 		(sockp = pcmcia_sockets[socket]) == NULL) {
3723 		return (BAD_SOCKET);
3724 	}
3725 
3726 	winp = pcmcia_windows[window];
3727 	winp->lw_socket = win->socket; /* reverse map */
3728 	newwin = *win;
3729 	newwin.window = winp->lw_window;
3730 	newwin.socket = sockp->ls_socket;
3731 	newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */
3732 
3733 	retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin);
3734 	if (retval == SUCCESS) {
3735 		newwin.window = window;
3736 		newwin.socket = winp->lw_socket;
3737 		*win = newwin;
3738 	}
3739 	return (retval);
3740 }
3741 
3742 static int
3743 SSSetSocket(set_socket_t *socket)
3744 {
3745 	int sock, retval;
3746 	pcmcia_logical_socket_t *sockp;
3747 	set_socket_t newsock;
3748 
3749 	sock = socket->socket;
3750 	if (sock > pcmcia_num_sockets ||
3751 		(sockp = pcmcia_sockets[sock]) == NULL) {
3752 		return (BAD_SOCKET);
3753 	}
3754 
3755 	newsock = *socket;
3756 	/* note: we force CS to always get insert/removal events */
3757 	sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) |
3758 		PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL);
3759 #if defined(PCMCIA_DEBUG)
3760 	if (pcmcia_debug > 1)
3761 		cmn_err(CE_CONT,
3762 			"SetSocket: SCIntMask = %x\n", newsock.SCIntMask);
3763 #endif
3764 	newsock.socket = sockp->ls_socket;
3765 	newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter,
3766 	    newsock.VccLevel, VCC);
3767 	newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter,
3768 	    newsock.Vpp1Level, VPP1);
3769 	newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter,
3770 	    newsock.Vpp2Level, VPP2);
3771 	retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3772 	    &newsock);
3773 	if (retval == SUCCESS) {
3774 		newsock.socket = sock;
3775 		newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
3776 		    newsock.VccLevel,
3777 		    VCC);
3778 		newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
3779 		    newsock.Vpp1Level,
3780 		    VPP1);
3781 		newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
3782 		    newsock.Vpp2Level,
3783 		    VPP2);
3784 		*socket = newsock;
3785 		if (socket->IREQRouting & IRQ_ENABLE) {
3786 			sockp->ls_flags |= PCS_IRQ_ENABLED;
3787 		} else {
3788 			sockp->ls_flags &= ~PCS_IRQ_ENABLED;
3789 		}
3790 	}
3791 	return (retval);
3792 }
3793 
3794 /*
3795  * SSSetIRQHandler()
3796  *	arrange for IRQ to be allocated if appropriate and always
3797  *	arrange that PC Card interrupt handlers get called.
3798  */
3799 static int
3800 SSSetIRQHandler(set_irq_handler_t *handler)
3801 {
3802 	int sock, retval, func;
3803 	pcmcia_logical_socket_t *sockp;
3804 	struct pcmcia_parent_private *ppd;
3805 	dev_info_t *dip;
3806 	ddi_iblock_cookie_t iblk;
3807 	ddi_idevice_cookie_t idev;
3808 
3809 	sock = CS_GET_SOCKET_NUMBER(handler->socket);
3810 	func = CS_GET_FUNCTION_NUMBER(handler->socket);
3811 	if (sock > pcmcia_num_sockets ||
3812 		(sockp = pcmcia_sockets[sock]) == NULL) {
3813 		return (BAD_SOCKET);
3814 	}
3815 #if defined(PCMCIA_DEBUG)
3816 	if (pcmcia_debug) {
3817 
3818 		cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n",
3819 			sock, func);
3820 		cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n",
3821 			(void *)handler->handler, handler->socket, handler->irq,
3822 			handler->handler_id);
3823 	}
3824 #endif
3825 	dip = sockp->ls_dip[func];
3826 
3827 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
3828 
3829 	handler->iblk_cookie = &iblk;
3830 	handler->idev_cookie = &idev;
3831 
3832 	retval = ddi_add_intr(dip, 0, handler->iblk_cookie,
3833 	    handler->idev_cookie,
3834 	    (uint32_t(*)(caddr_t)) handler->handler,
3835 	    handler->arg1);
3836 
3837 	if (retval == DDI_SUCCESS) {
3838 		handler->iblk_cookie = &sockp->ls_iblk;
3839 		handler->idev_cookie = &sockp->ls_idev;
3840 		handler->irq = ppd->ppd_intrspec->intrspec_vec;
3841 		retval = SUCCESS;
3842 	} else {
3843 		retval = sockp->ls_error;
3844 	}
3845 	return (retval);
3846 }
3847 
3848 /*
3849  * SSClearIRQHandler()
3850  *	Arrange to have the interrupt handler specified removed
3851  *	from the interrupt list.
3852  */
3853 static int
3854 SSClearIRQHandler(clear_irq_handler_t *handler)
3855 {
3856 	int sock, func;
3857 	pcmcia_logical_socket_t *sockp;
3858 	dev_info_t *dip;
3859 
3860 	sock = CS_GET_SOCKET_NUMBER(handler->socket);
3861 	func = CS_GET_FUNCTION_NUMBER(handler->socket);
3862 
3863 #if defined(PCMCIA_DEBUG)
3864 	if (pcmcia_debug) {
3865 
3866 		cmn_err(CE_CONT,
3867 			"SSClearIRQHandler: socket=%x, function=%x\n",
3868 			sock, func);
3869 		cmn_err(CE_CONT,
3870 			"\thandler(%p): socket=%x, id=%x\n",
3871 			(void *)handler, handler->socket,
3872 			handler->handler_id);
3873 	}
3874 #endif
3875 
3876 	if (sock > pcmcia_num_sockets ||
3877 		(sockp = pcmcia_sockets[sock]) == NULL) {
3878 		return (BAD_SOCKET);
3879 	}
3880 	dip = sockp->ls_dip[func];
3881 	if (dip) {
3882 		ddi_remove_intr(dip, 0, NULL);
3883 		return (SUCCESS);
3884 	}
3885 	return (BAD_SOCKET);
3886 }
3887 
3888 
3889 /*
3890  * pcm_pathname()
3891  *	make a partial path from dip.
3892  *	used to mknods relative to /devices/pcmcia/
3893  *
3894  * XXX - we now use ddi_get_name_addr to get the "address" portion
3895  *	of the name; that way, we only have to modify the name creation
3896  *	algorithm in one place
3897  */
3898 static void
3899 pcm_pathname(dev_info_t *dip, char *name, char *path)
3900 {
3901 	(void) sprintf(path, "%s@%s:%s", ddi_node_name(dip),
3902 	    ddi_get_name_addr(dip), name);
3903 }
3904 
3905 /*
3906  * pcmcia_create_device()
3907  *	create the /devices entries for the driver
3908  *	it is assumed that the PC Card driver will do a
3909  *	RegisterClient for each subdevice.
3910  *	The device type string is encoded here to match
3911  *	the standardized names when possible.
3912  * XXX - note that we may need to provide a way for the
3913  *	caller to specify the complete name string that
3914  *	we pass to ddi_set_name_addr
3915  */
3916 static int
3917 pcmcia_create_device(ss_make_device_node_t *init)
3918 {
3919 	int err = SUCCESS;
3920 	struct pcm_make_dev device;
3921 	struct dev_ops *ops;
3922 	major_t major;
3923 
3924 	/*
3925 	 * Now that we have the name, create it.
3926 	 */
3927 
3928 	bzero(&device, sizeof (device));
3929 	if (init->flags & SS_CSINITDEV_CREATE_DEVICE) {
3930 		if ((err = ddi_create_minor_node(init->dip,
3931 		    init->name,
3932 		    init->spec_type,
3933 		    init->minor_num,
3934 		    init->node_type,
3935 		    0)) != DDI_SUCCESS) {
3936 #if defined(PCMCIA_DEBUG)
3937 			if (pcmcia_debug)
3938 				cmn_err(CE_CONT,
3939 					"pcmcia_create_device: failed "
3940 					"create\n");
3941 #endif
3942 			return (BAD_ATTRIBUTE);
3943 		}
3944 
3945 		major = ddi_name_to_major(ddi_binding_name(init->dip));
3946 		ops = ddi_get_driver(init->dip);
3947 		LOCK_DEV_OPS(&devnamesp[major].dn_lock);
3948 		INCR_DEV_OPS_REF(ops);
3949 		(void) ddi_pathname(init->dip, device.path);
3950 		DECR_DEV_OPS_REF(ops);
3951 		UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
3952 		(void) sprintf(device.path + strlen(device.path), ":%s",
3953 		    init->name);
3954 
3955 		(void) strcpy(device.driver, ddi_binding_name(init->dip));
3956 #if defined(PCMCIA_DEBUG)
3957 		if (pcmcia_debug)
3958 			cmn_err(CE_CONT,
3959 				"pcmcia_create_device: created %s "
3960 				"from %s [%s]\n",
3961 				device.path, init->name, device.driver);
3962 #endif
3963 		device.dev =
3964 		    makedevice(ddi_name_to_major(ddi_get_name(init->dip)),
3965 		    init->minor_num);
3966 		device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ?
3967 		    PCM_EVENT_MORE : 0;
3968 		device.type = init->spec_type;
3969 		device.op = SS_CSINITDEV_CREATE_DEVICE;
3970 		device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
3971 		    DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
3972 		    -1);
3973 	} else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) {
3974 		device.op = SS_CSINITDEV_REMOVE_DEVICE;
3975 		device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
3976 		    DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
3977 		    -1);
3978 		if (init->name != NULL)
3979 			(void) strcpy(device.path, init->name);
3980 		device.dev =
3981 		    makedevice(ddi_name_to_major(ddi_get_name(init->dip)),
3982 		    0);
3983 		ddi_remove_minor_node(init->dip, init->name);
3984 	}
3985 
3986 	/*
3987 	 *	we send an event for ALL devices created.
3988 	 *	To do otherwise ties us to using drvconfig
3989 	 *	forever.  There are relatively few devices
3990 	 *	ever created so no need to do otherwise.
3991 	 *	The existence of the event manager must never
3992 	 *	be visible to a PCMCIA device driver.
3993 	 */
3994 	pcm_event_manager(PCE_INIT_DEV, device.socket, &device);
3995 
3996 	return (err);
3997 }
3998 
3999 /*
4000  * pcmcia_get_minors()
4001  *	We need to traverse the minor node list of the
4002  *	dip if there are any.  This takes two passes;
4003  *	one to get the count and buffer size and the
4004  *	other to actually copy the data into the buffer.
4005  *	The framework requires that the dip be locked
4006  *	during this time to avoid breakage as well as the
4007  *	driver being locked.
4008  */
4009 int
4010 pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors)
4011 {
4012 	int count = 0;
4013 	struct ddi_minor_data *dp;
4014 	struct pcm_make_dev *md;
4015 	int socket;
4016 	major_t major;
4017 	struct dev_ops *ops;
4018 
4019 	socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4020 	    PCM_DEV_SOCKET, -1);
4021 	mutex_enter(&(DEVI(dip)->devi_lock));
4022 	if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) {
4023 		for (dp = DEVI(dip)->devi_minor;
4024 			dp != (struct ddi_minor_data *)NULL;
4025 			dp = dp->next) {
4026 			count++; /* have one more */
4027 		}
4028 		/* we now know how many nodes to allocate */
4029 		md = kmem_zalloc(count * sizeof (struct pcm_make_dev),
4030 		    KM_NOSLEEP);
4031 		if (md != NULL) {
4032 			*minors = md;
4033 			for (dp = DEVI(dip)->devi_minor;
4034 				dp != (struct ddi_minor_data *)NULL;
4035 				dp = dp->next, md++) {
4036 #if defined(PCMCIA_DEBUG)
4037 				if (pcmcia_debug > 1) {
4038 					cmn_err(CE_CONT,
4039 						"pcmcia_get_minors: name=%s,"
4040 						"socket=%d, stype=%x, "
4041 						"ntype=%s, dev_t=%x",
4042 						dp->ddm_name,
4043 						socket,
4044 						dp->ddm_spec_type,
4045 						dp->ddm_node_type,
4046 						(int)dp->ddm_dev);
4047 					cmn_err(CE_CONT,
4048 						"\tbind name = %s\n",
4049 						ddi_binding_name(dip));
4050 				}
4051 #endif
4052 				md->socket = socket;
4053 				md->op = SS_CSINITDEV_CREATE_DEVICE;
4054 				md->dev = dp->ddm_dev;
4055 				md->type = dp->ddm_spec_type;
4056 				(void) strcpy(md->driver,
4057 				    ddi_binding_name(dip));
4058 				major = ddi_name_to_major(md->driver);
4059 				ops = ddi_get_driver(dip);
4060 				LOCK_DEV_OPS(&devnamesp[major].dn_lock);
4061 				pcm_pathname(dip, dp->ddm_name, md->path);
4062 				INCR_DEV_OPS_REF(ops);
4063 				(void) ddi_pathname(dip, md->path);
4064 				DECR_DEV_OPS_REF(ops);
4065 				UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
4066 				(void) sprintf(md->path + strlen(md->path),
4067 					":%s", dp->ddm_name);
4068 				if (dp->next == NULL)
4069 					/* no more */
4070 					md->flags |= PCM_EVENT_MORE;
4071 			}
4072 		} else {
4073 			count = 0;
4074 		}
4075 	}
4076 	mutex_exit(&(DEVI(dip)->devi_lock));
4077 	return (count);
4078 }
4079 
4080 #if defined(PCMCIA_DEBUG)
4081 static char *ddmtypes[] = { "minor", "alias", "default", "internal" };
4082 
4083 static void
4084 pcmcia_dump_minors(dev_info_t *dip)
4085 {
4086 	int count = 0;
4087 	struct ddi_minor_data *dp;
4088 	int unit, major;
4089 	dev_info_t *np;
4090 
4091 	unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4092 	    PCM_DEV_SOCKET, -1);
4093 	cmn_err(CE_CONT,
4094 		"pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit);
4095 
4096 	major = ddi_driver_major(dip);
4097 	if (major != -1) {
4098 		for (np = devnamesp[major].dn_head; np != NULL;
4099 		    np = (dev_info_t *)DEVI(np)->devi_next) {
4100 			char *cf2 = "";
4101 			char *cur = "";
4102 			if (i_ddi_node_state(np) == DS_READY)
4103 				cf2 = "DS_READY";
4104 			if (np == dip)
4105 				cur = "CUR";
4106 			cmn_err(CE_CONT, "\tsibs: %s %s %s\n",
4107 				ddi_binding_name(np), cf2, cur);
4108 
4109 			mutex_enter(&(DEVI(np)->devi_lock));
4110 			if (DEVI(np)->devi_minor !=
4111 			    (struct ddi_minor_data *)NULL) {
4112 				for (dp = DEVI(np)->devi_minor;
4113 				    dp != (struct ddi_minor_data *)NULL;
4114 				    dp = dp->next) {
4115 					count++; /* have one more */
4116 				}
4117 				for (dp = DEVI(dip)->devi_minor;
4118 				    dp != (struct ddi_minor_data *)NULL;
4119 				    dp = dp->next) {
4120 					cmn_err(CE_CONT, "\ttype=%s, name=%s,"
4121 						"socket=%d, stype=%x, "
4122 						"ntype=%s, dev_t=%x",
4123 						ddmtypes[dp->type],
4124 						dp->ddm_name,
4125 						unit,
4126 						dp->ddm_spec_type,
4127 						dp->ddm_node_type,
4128 						(int)dp->ddm_dev);
4129 					cmn_err(CE_CONT, "\tbind name = %s\n",
4130 						ddi_binding_name(np));
4131 				}
4132 			}
4133 			mutex_exit(&(DEVI(np)->devi_lock));
4134 		}
4135 	}
4136 }
4137 #endif
4138 
4139 /*
4140  * experimental merging code
4141  * what are the things that we should merge on?
4142  *	match something by name in the "compatible" property
4143  *	restrict to a specific "socket"
4144  *	restrict to a specific "instance"
4145  */
4146 /*ARGSUSED*/
4147 static int
4148 pcmcia_merge_conf(dev_info_t *dip)
4149 {
4150 	return (0);		/* merge failed */
4151 }
4152 
4153 /*
4154  * pcmcia_mfc_intr()
4155  *	Multifunction Card interrupt handler
4156  *	While some adapters share interrupts at the lowest
4157  *	level, some can't.  In order to be consistent, we
4158  *	split multifunction cards out with this intercept and
4159  *	allow the low level to do what is best for it.
4160  *	the arg is a pcmcia_socket structure and all interrupts
4161  *	are per-socket in this case.  We also have the option
4162  *	to optimize if the cards support it.  It also means
4163  *	that we can use the INTRACK mode if it proves desirable
4164  */
4165 /*ARGSUSED*/
4166 static uint32_t
4167 pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2)
4168 {
4169 	pcmcia_logical_socket_t *sockp;
4170 	inthandler_t *intr, *first;
4171 	int done, result;
4172 
4173 	sockp = (pcmcia_logical_socket_t *)arg1;
4174 
4175 #if defined(PCMCIA_DEBUG)
4176 	if (pcmcia_debug > 1) {
4177 		cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p"
4178 		    " ls_inthandlers=%p\n"
4179 		    "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n",
4180 		    (void *) sockp, (void *) sockp->ls_inthandlers,
4181 		    sockp->ls_flags, PCS_IRQ_ENABLED);
4182 	}
4183 #endif
4184 
4185 	if (sockp == NULL || sockp->ls_inthandlers == NULL ||
4186 	    !(sockp->ls_flags & PCS_IRQ_ENABLED))
4187 		return (DDI_INTR_UNCLAIMED);
4188 
4189 	mutex_enter(&sockp->ls_ilock);
4190 	for (done = 0, result = 0, first = intr = sockp->ls_inthandlers;
4191 		intr != NULL && !done; intr = intr->next) {
4192 		result |= intr->intr(intr->arg1, intr->arg2);
4193 		if (intr->next == first)
4194 			done++;
4195 	}
4196 	if (intr == NULL) {
4197 		cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list");
4198 	}
4199 	if (sockp->ls_inthandlers)
4200 		sockp->ls_inthandlers = sockp->ls_inthandlers->next;
4201 
4202 	mutex_exit(&sockp->ls_ilock);
4203 	return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
4204 }
4205 
4206 /*
4207  * pcmcia_power(dip)
4208  *	control power for nexus and children
4209  */
4210 int
4211 pcmcia_power(dev_info_t *dip, int component, int level)
4212 {
4213 #if 0
4214 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
4215 	int i;
4216 	/*
4217 	 * for now, we only have one component.  Should there be one per-socket?
4218 	 * the level is only one (power on or off)
4219 	 */
4220 	if (component != 0 || level > 1)
4221 		return (DDI_FAILURE);
4222 
4223 	for (i = 0; i < pcic->pc_numsockets; i++) {
4224 		if (pcic->pc_callback)
4225 			PC_CALLBACK(dip, pcic->pc_cb_arg,
4226 			    (level == 0) ? PCE_PM_SUSPEND :
4227 			    PCE_PM_RESUME,
4228 			    i);
4229 	}
4230 #else
4231 	cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s",
4232 		component, level, ddi_get_name_addr(dip));
4233 	return (DDI_FAILURE);
4234 #endif
4235 }
4236 
4237 void
4238 pcmcia_begin_resume(dev_info_t *dip)
4239 {
4240 	int i;
4241 	struct pcmcia_adapter *adapt = NULL;
4242 	for (i = 0; i < pcmcia_num_adapters; i++) {
4243 		if (pcmcia_adapters[i]->pca_dip == dip) {
4244 			adapt = pcmcia_adapters[i];
4245 			break;
4246 		}
4247 	}
4248 	if (adapt == NULL)
4249 		return;
4250 
4251 	for (i = 0; i < adapt->pca_numsockets; i++) {
4252 		int s;
4253 		s = adapt->pca_first_socket + i;
4254 		if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) {
4255 			if (pcmcia_sockets[s]->ls_flags &
4256 			    (1 << PCE_PM_RESUME)) {
4257 				(void) cs_event(PCE_PM_RESUME, s, 0);
4258 				pcm_event_manager(PCE_PM_RESUME, s, NULL);
4259 			}
4260 			(void) cs_event(PCE_CARD_REMOVAL, s, 0);
4261 			pcm_event_manager(PCE_CARD_REMOVAL, s, NULL);
4262 		}
4263 	}
4264 }
4265 
4266 void
4267 pcmcia_wait_insert(dev_info_t *dip)
4268 {
4269 	int i, f, tries, done;
4270 	clock_t tm;
4271 	struct pcmcia_adapter *adapt = NULL;
4272 	anp_t *nexus;
4273 
4274 	for (i = 0; i < pcmcia_num_adapters; i++) {
4275 		if (pcmcia_adapters[i]->pca_dip == dip) {
4276 			adapt = pcmcia_adapters[i];
4277 			break;
4278 		}
4279 	}
4280 	if (adapt == NULL)
4281 		return;
4282 
4283 	for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) {
4284 		done = 1;
4285 		mutex_enter(&pcmcia_global_lock);
4286 		for (i = 0; i < adapt->pca_numsockets; i++) {
4287 			int s;
4288 			s = adapt->pca_first_socket + i;
4289 			for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++)
4290 				if (pcmcia_sockets[s] &&
4291 				    pcmcia_sockets[s]->ls_flags &
4292 				    PCS_SUSPENDED) {
4293 					done = 0;
4294 					break;
4295 				}
4296 		}
4297 		if (!done) {
4298 			tm = ddi_get_lbolt();
4299 			(void) cv_timedwait(&pcmcia_condvar,
4300 			    &pcmcia_global_lock,
4301 			    tm + drv_usectohz(100000));
4302 		} else {
4303 			tries = 0;
4304 		}
4305 		mutex_exit(&pcmcia_global_lock);
4306 	}
4307 
4308 	nexus = (anp_t *)ddi_get_driver_private(dip);
4309 	pcmcia_find_cards(nexus);
4310 }
4311 
4312 int
4313 pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra,
4314 		uint32_t state, caddr_t *base,
4315 		ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib,
4316 		uint32_t req_base)
4317 {
4318 	struct pcmcia_parent_private *ppd;
4319 	int rnum = 0, type = PCMCIA_MAP_MEM;
4320 	ddi_map_req_t mr;
4321 	ddi_acc_hdl_t *hp;
4322 	int result;
4323 	struct regspec *reg;
4324 	ddi_device_acc_attr_t attr;
4325 
4326 	if (dip != NULL) {
4327 		ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
4328 		if (ppd == NULL)
4329 			return (DDI_FAILURE);
4330 		for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) {
4331 			struct pcm_regs *p;
4332 			p = &ppd->ppd_reg[rnum];
4333 			if (state & WS_IO) {
4334 				/* need I/O */
4335 				type = PCMCIA_MAP_IO;
4336 				/*
4337 				 * We want to find an IO regspec. When we
4338 				 *	find one, it either has to match
4339 				 *	the caller's requested base address
4340 				 *	or it has to be relocatable.
4341 				 * We match on the requested base address
4342 				 *	rather than the allocated base
4343 				 *	address so that we handle the case
4344 				 *	of adapters that have IO window base
4345 				 *	relocation registers.
4346 				 */
4347 				if ((p->phys_hi &
4348 				    PC_REG_SPACE(PC_REG_SPACE_IO)) &&
4349 					((req_base == p->phys_lo) ||
4350 					!(p->phys_hi & PC_REG_RELOC(1))))
4351 				    break;
4352 			} else {
4353 				/* need memory */
4354 				type = PCMCIA_MAP_MEM;
4355 				if (p->phys_hi &
4356 				    PC_REG_SPACE(PC_REG_SPACE_MEMORY|
4357 				    PC_REG_SPACE_ATTRIBUTE))
4358 					break;
4359 			}
4360 		}
4361 		if (rnum >= ppd->ppd_nreg)
4362 			return (DDI_FAILURE);
4363 	} else if (state & WS_IO) {
4364 		return (DDI_FAILURE);
4365 	}
4366 
4367 	reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP);
4368 	reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra);
4369 
4370 	if (attrib == NULL ||
4371 	    attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) {
4372 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4373 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4374 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4375 	} else {
4376 		attr = *attrib;
4377 	}
4378 	/*
4379 	 * Allocate and initialize the common elements of data access handle.
4380 	 */
4381 	*handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
4382 	hp = impl_acc_hdl_get(*handle);
4383 	hp->ah_vers = VERS_ACCHDL;
4384 	hp->ah_dip = dip != NULL ? dip : pdip;
4385 	hp->ah_rnumber = rnum;
4386 	hp->ah_offset = 0;
4387 	hp->ah_len = ra->ra_len;
4388 	hp->ah_acc = attr;
4389 
4390 	/*
4391 	 * Set up the mapping request and call to parent.
4392 	 */
4393 	mr.map_op = DDI_MO_MAP_LOCKED;
4394 	mr.map_type = DDI_MT_REGSPEC;
4395 	mr.map_obj.rp = reg;
4396 	mr.map_prot = PROT_READ | PROT_WRITE;
4397 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
4398 	mr.map_handlep = hp;
4399 	mr.map_vers = DDI_MAP_VERSION;
4400 
4401 	result = ddi_map(pdip, &mr, 0, ra->ra_len, base);
4402 	if (result != DDI_SUCCESS) {
4403 		impl_acc_hdl_free(*handle);
4404 		*handle = (ddi_acc_handle_t)NULL;
4405 		kmem_free(reg, sizeof (pci_regspec_t));
4406 	} else {
4407 		hp->ah_addr = *base;
4408 		if (mr.map_op == DDI_MO_UNMAP)
4409 			ra = NULL;
4410 		if (dip != NULL)
4411 			pcmcia_set_assigned(dip, rnum, ra);
4412 	}
4413 
4414 	return (result);
4415 }
4416 
4417 struct pcmcia_adapter *
4418 pcmcia_get_adapter(dev_info_t *dip)
4419 {
4420 	int i;
4421 
4422 	for (i = 0; i < pcmcia_num_adapters; i++) {
4423 		if (pcmcia_adapters[i] &&
4424 		    pcmcia_adapters[i]->pca_dip == dip) {
4425 			return (pcmcia_adapters[i]);
4426 		}
4427 	}
4428 	return (NULL);
4429 }
4430 
4431 
4432 void
4433 pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret)
4434 {
4435 	struct pcmcia_parent_private *ppd;
4436 	struct pcm_regs *reg, *assign;
4437 
4438 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
4439 	if (ppd) {
4440 		reg = &ppd->ppd_reg[rnum];
4441 		assign = &ppd->ppd_assigned[rnum];
4442 		if (ret) {
4443 			if (assign->phys_hi == 0) {
4444 				assign->phys_hi = reg->phys_hi;
4445 				assign->phys_lo = ret->ra_addr_lo;
4446 				assign->phys_len = ret->ra_len;
4447 			} else if (assign->phys_lo != ret->ra_addr_lo) {
4448 #ifdef PCMCIA_DEBUG
4449 				cmn_err(CE_WARN, "pcmcia: bad address:"
4450 					"%s=<%x,%x>",
4451 					ddi_get_name_addr(dip),
4452 					ret->ra_addr_lo, assign->phys_lo);
4453 #else
4454 				cmn_err(CE_WARN, "!pcmcia: bad address:"
4455 					"%s=<%x,%x>",
4456 					ddi_get_name_addr(dip),
4457 					ret->ra_addr_lo, (int)assign->phys_lo);
4458 #endif
4459 			}
4460 			assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi);
4461 		} else {
4462 			int i;
4463 			assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi);
4464 			i = PC_GET_REG_REFCNT(assign->phys_hi);
4465 			if (i == 0) {
4466 				assign->phys_hi = 0;
4467 				assign->phys_lo = 0;
4468 				assign->phys_len = 0;
4469 			}
4470 		}
4471 	}
4472 }
4473 
4474 int
4475 pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret)
4476 {
4477 	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM));
4478 }
4479 
4480 int
4481 pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret)
4482 {
4483 	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO));
4484 }
4485 
4486 int
4487 pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
4488 		char *type)
4489 {
4490 	int rval;
4491 	uint64_t base = 0;
4492 	uint64_t len = 0;
4493 
4494 	/*
4495 	 * Allocate space from busra resource list
4496 	 * should not return an address > 32 bits
4497 	 */
4498 
4499 	if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
4500 							== NDI_FAILURE) ||
4501 	    ((base >> 32) != 0)) {
4502 		ret->ra_addr_lo = 0;
4503 		ret->ra_len = 0;
4504 		rval = DDI_FAILURE;
4505 	} else {
4506 		ret->ra_addr_lo =  base & 0xffffffff;
4507 		ret->ra_len = len;
4508 		rval = DDI_SUCCESS;
4509 	}
4510 	ret->ra_addr_hi = 0;
4511 	return (rval);
4512 }
4513 
4514 int
4515 pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret)
4516 {
4517 	return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM));
4518 }
4519 
4520 int
4521 pcmcia_free_io(dev_info_t *dip, ra_return_t *ret)
4522 {
4523 	return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO));
4524 }
4525 
4526 int
4527 pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type)
4528 {
4529 	if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len,
4530 	    type, NDI_RA_PASS) == NDI_SUCCESS) {
4531 		return (DDI_SUCCESS);
4532 	} else {
4533 		return (DDI_FAILURE);
4534 	}
4535 }
4536 
4537 
4538 /*
4539  * when the low level device configuration does resource assignment
4540  * (devconf) then free the allocated resources so we can reassign them
4541  * later.  Walk the child list to get them.
4542  */
4543 void
4544 pcmcia_free_resources(dev_info_t *self)
4545 {
4546 	struct regspec *assigned;
4547 	int len;
4548 	dev_info_t *dip;
4549 	int circular;
4550 
4551 	ndi_devi_enter(self, &circular);
4552 	/* do searches in compatible property order */
4553 	for (dip = (dev_info_t *)DEVI(self)->devi_child;
4554 	    dip != NULL;
4555 	    dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
4556 		len = 0;
4557 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
4558 		    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP,
4559 		    "assigned-addresses",
4560 		    (caddr_t)&assigned,
4561 		    &len) == DDI_PROP_SUCCESS) {
4562 			/*
4563 			 * if there are assigned resources at this point,
4564 			 * then the OBP or devconf have assigned them and
4565 			 * they need to be freed.
4566 			 */
4567 			kmem_free(assigned, len);
4568 		}
4569 	}
4570 	ndi_devi_exit(self, circular);
4571 }
4572 
4573 /*
4574  * this is the equivalent of pcm_get_intr using ra_allocs.
4575  * returns -1 if failed, otherwise returns the allocated irq.
4576  * The input request, if less than zero it means not a specific
4577  * irq requested. If larger then 0 then we are requesting that specific
4578  * irq
4579  */
4580 int
4581 pcmcia_get_intr(dev_info_t *dip, int request)
4582 {
4583 	ndi_ra_request_t req;
4584 	uint64_t base;
4585 	uint64_t len;
4586 	int err;
4587 
4588 	bzero(&req, sizeof (req));
4589 	base = 0;
4590 	len = 1;
4591 	if (request >= 0) {
4592 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
4593 		req.ra_len = 1;
4594 		req.ra_addr = (uint64_t)request;
4595 	}
4596 
4597 	req.ra_boundbase = 0;
4598 	req.ra_boundlen = 0xffffffffUL;
4599 	req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
4600 
4601 	err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR,
4602 	    NDI_RA_PASS);
4603 
4604 	if (err == NDI_FAILURE) {
4605 		return (-1);
4606 	} else {
4607 		return ((int)base);
4608 	}
4609 }
4610 
4611 
4612 int
4613 pcmcia_return_intr(dev_info_t *dip, int request)
4614 {
4615 	if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR,
4616 	    NDI_RA_PASS)) == NDI_SUCCESS) {
4617 		return (0);
4618 	} else
4619 		return (-1);
4620 
4621 }
4622 
4623 #ifdef sparc
4624 
4625 int
4626 pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
4627     ddi_intr_handle_impl_t *hdlp)
4628 {
4629 
4630 	struct pcmcia_parent_private *ppd;
4631 	pcmcia_logical_socket_t *sockp;
4632 	int socket, ret;
4633 	struct pcmcia_adapter *adapt;
4634 	set_irq_handler_t handler;
4635 	struct intrspec *pispec;
4636 
4637 #if defined(PCMCIA_DEBUG)
4638 	if (pcmcia_debug) {
4639 		cmn_err(CE_CONT,
4640 		    "pcmcia_add_intr_impl() entered "
4641 		    "dip=%p rdip=%p hdlp=%p \n",
4642 		    (void *)dip, (void *)rdip, (void *)hdlp);
4643 	}
4644 #endif
4645 
4646 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
4647 	socket = ppd->ppd_socket;
4648 	sockp = pcmcia_sockets[socket];
4649 	adapt = sockp->ls_adapter;
4650 
4651 #if defined(PCMCIA_DEBUG)
4652 	if (pcmcia_debug) {
4653 		cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
4654 		    " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n"
4655 		    " ppd_intrspec=%p ls_inthandlers=%p\n",
4656 		    ppd->ppd_flags, PPD_CARD_MULTI,
4657 		    (void *) ppd->ppd_intrspec,
4658 		    (void *)sockp->ls_inthandlers);
4659 	}
4660 #endif
4661 
4662 	/*
4663 	 * calculate IPL level when we support multiple levels
4664 	 */
4665 	pispec = ppd->ppd_intrspec;
4666 	if (pispec == NULL) {
4667 		sockp->ls_error = BAD_IRQ;
4668 		return (DDI_FAILURE);
4669 	}
4670 
4671 	handler.socket = sockp->ls_socket;
4672 	handler.irq = 0;	/* default case */
4673 	handler.handler = (f_tt *)hdlp->ih_cb_func;
4674 	handler.arg1 = hdlp->ih_cb_arg1;
4675 	handler.arg2 = hdlp->ih_cb_arg2;
4676 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
4677 
4678 	/*
4679 	 * check if multifunction and do the right thing
4680 	 * we put an intercept in between the mfc handler and
4681 	 * us so we can catch and process.  We might be able
4682 	 * to optimize this depending on the card features
4683 	 * (a future option).
4684 	 */
4685 	if (ppd->ppd_flags & PPD_CARD_MULTI) {
4686 		inthandler_t *intr;
4687 		/*
4688 		 * note that the first function is a special
4689 		 * case since it sets things up.  We fall through
4690 		 * to the lower code and get the hardware set up.
4691 		 * subsequent times we just lock the list and insert
4692 		 * the handler and all is well.
4693 		 */
4694 		intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
4695 		if (intr == NULL) {
4696 			sockp->ls_error = BAD_IRQ;
4697 			return (DDI_FAILURE);
4698 		}
4699 		intr->intr = hdlp->ih_cb_func;
4700 		intr->handler_id = (uint_t)(uintptr_t)rdip;
4701 		intr->arg1 = hdlp->ih_cb_arg1;
4702 		intr->arg2 = hdlp->ih_cb_arg2;
4703 		intr->socket = socket;
4704 
4705 		mutex_enter(&sockp->ls_ilock);
4706 		if (sockp->ls_inthandlers == NULL) {
4707 			intr->next = intr->prev = intr;
4708 			sockp->ls_inthandlers = intr;
4709 			sockp->ls_mfintr_dip = rdip;
4710 			mutex_exit(&sockp->ls_ilock);
4711 
4712 			/*
4713 			 * replace first function handler with
4714 			 * the mfc handler
4715 			 */
4716 			handler.handler =  (f_tt *)pcmcia_mfc_intr;
4717 			handler.arg1 = (caddr_t)sockp;
4718 			handler.arg2 = NULL;
4719 		} else {
4720 			insque(intr, sockp->ls_inthandlers);
4721 			mutex_exit(&sockp->ls_ilock);
4722 
4723 			pispec->intrspec_vec = sockp->ls_intr_vec;
4724 			pispec->intrspec_pri = sockp->ls_intr_pri;
4725 			hdlp->ih_pri = sockp->ls_intr_pri;
4726 
4727 			return (DDI_SUCCESS);
4728 		}
4729 	}
4730 
4731 #if defined(PCMCIA_DEBUG)
4732 	if (pcmcia_debug) {
4733 		cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n");
4734 	}
4735 #endif
4736 	pispec->intrspec_func = (uint32_t (*)())handler.handler;
4737 
4738 	/* set default IPL then check for override */
4739 
4740 	pispec->intrspec_pri = sockp->ls_intr_pri;
4741 	hdlp->ih_pri = pispec->intrspec_pri;
4742 
4743 #if defined(PCMCIA_DEBUG)
4744 	if (pcmcia_debug) {
4745 		cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d"
4746 		    " handler_id=0X%x handler=%p arg1=%p arg2=%p\n",
4747 		    handler.socket, handler.irq,
4748 		    handler.handler_id, (void *)handler.handler, handler.arg1,
4749 		    handler.arg2);
4750 	}
4751 #endif
4752 
4753 	if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
4754 	    SUCCESS) {
4755 		sockp->ls_error = ret;
4756 		return (DDI_FAILURE);
4757 	}
4758 
4759 #if defined(PCMCIA_DEBUG)
4760 	if (pcmcia_debug) {
4761 		cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
4762 		    " iblk_cookie=%p idev_cookie=%p\n"
4763 		    " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n",
4764 		    (void *)handler.iblk_cookie,
4765 		    (void *)handler.idev_cookie,
4766 		    sockp->ls_flags, PCS_COOKIES_VALID);
4767 	}
4768 #endif
4769 
4770 	if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
4771 		hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie;
4772 		sockp->ls_iblk = *handler.iblk_cookie;
4773 		sockp->ls_idev = *handler.idev_cookie;
4774 		sockp->ls_flags |= PCS_COOKIES_VALID;
4775 	}
4776 
4777 	return (DDI_SUCCESS);
4778 }
4779 
4780 void
4781 pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
4782     ddi_intr_handle_impl_t *hdlp)
4783 {
4784 
4785 	struct pcmcia_parent_private *ppd;
4786 	pcmcia_logical_socket_t *sockp;
4787 	clear_irq_handler_t handler;
4788 	struct intrspec *pispec;
4789 	int socket;
4790 
4791 #if defined(PCMCIA_DEBUG)
4792 	if (pcmcia_debug) {
4793 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered"
4794 		    " dip=%p rdip=%p hdlp=%p\n",
4795 		    (void *)dip, (void *)rdip, (void *)hdlp);
4796 	}
4797 #endif
4798 
4799 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
4800 	socket = ppd->ppd_socket;
4801 	sockp = pcmcia_sockets[socket];
4802 	pispec = ppd->ppd_intrspec;
4803 
4804 #if defined(PCMCIA_DEBUG)
4805 	if (pcmcia_debug) {
4806 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
4807 		    " ls_inthandlers=%p ls_intrspec=%p\n",
4808 		    (void *)sockp->ls_inthandlers,
4809 		    (void *)&sockp->ls_intrspec);
4810 	}
4811 #endif
4812 
4813 	/* first handle the multifunction case since it is simple */
4814 	mutex_enter(&sockp->ls_ilock);
4815 	if (sockp->ls_inthandlers != NULL) {
4816 		/* we must be MFC */
4817 		inthandler_t *intr;
4818 		int remhandler = 0;
4819 		intr = sockp->ls_inthandlers;
4820 
4821 		/* Check if there is only one handler left */
4822 		if ((intr->next == intr) && (intr->prev == intr)) {
4823 			if (intr->handler_id == (unsigned)(uintptr_t)rdip) {
4824 				sockp->ls_inthandlers = NULL;
4825 				remhandler++;
4826 				kmem_free(intr, sizeof (inthandler_t));
4827 			}
4828 		} else {
4829 			inthandler_t *first;
4830 			int done;
4831 
4832 			for (done = 0, first = intr; !done; intr = intr->next) {
4833 				if (intr->next == first)
4834 					done++;
4835 				if (intr->handler_id ==
4836 				    (unsigned)(uintptr_t)rdip) {
4837 					done++;
4838 
4839 					/*
4840 					 * If we're about to remove the
4841 					 *	handler at the head of
4842 					 *	the list, make the next
4843 					 *	handler in line the head.
4844 					 */
4845 					if (sockp->ls_inthandlers == intr)
4846 						sockp->ls_inthandlers =
4847 						    intr->next;
4848 
4849 					remque(intr);
4850 					kmem_free(intr, sizeof (inthandler_t));
4851 					break;
4852 				} /* handler_id */
4853 			} /* for */
4854 		} /* intr->next */
4855 
4856 		if (!remhandler) {
4857 			mutex_exit(&sockp->ls_ilock);
4858 			return;
4859 		}
4860 
4861 		/* need to get the dip that was used to add the handler */
4862 		rdip = sockp->ls_mfintr_dip;
4863 	}
4864 
4865 	mutex_exit(&sockp->ls_ilock);
4866 
4867 #if defined(PCMCIA_DEBUG)
4868 	if (pcmcia_debug) {
4869 		cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
4870 		    " pispec=%p rdip=%p\n",
4871 		    (void *)pispec, (void *)rdip);
4872 	}
4873 #endif
4874 
4875 	handler.socket = sockp->ls_socket;
4876 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
4877 	handler.handler = (f_tt *)pispec->intrspec_func;
4878 	CLEAR_IRQ(sockp->ls_if, dip, &handler);
4879 }
4880 
4881 
4882 /* Consolidated interrupt processing interface */
4883 /*ARGSUSED*/
4884 int
4885 pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
4886     ddi_intr_handle_impl_t *hdlp, void *result)
4887 {
4888 	int	ret = DDI_SUCCESS;
4889 
4890 #if defined(PCMCIA_DEBUG)
4891 	if (pcmcia_debug) {
4892 		cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n",
4893 		    (int)intr_op);
4894 	}
4895 #endif
4896 
4897 	switch (intr_op) {
4898 	case DDI_INTROP_GETCAP:
4899 		*(int *)result = DDI_INTR_FLAG_LEVEL;
4900 		break;
4901 	case DDI_INTROP_SETCAP:
4902 		ret = DDI_ENOTSUP;
4903 		break;
4904 	case DDI_INTROP_ALLOC:
4905 		*(int *)result = hdlp->ih_scratch1;
4906 		break;
4907 	case DDI_INTROP_FREE:
4908 		break;
4909 	case DDI_INTROP_GETPRI:
4910 		if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS)
4911 			return (DDI_FAILURE);
4912 		*(int *)result = hdlp->ih_pri;
4913 		pcmcia_remove_intr_impl(dip, rdip, hdlp);
4914 		break;
4915 	case DDI_INTROP_SETPRI:
4916 		break;
4917 	case DDI_INTROP_ADDISR:
4918 		ret = pcmcia_add_intr_impl(dip, rdip, hdlp);
4919 		break;
4920 	case DDI_INTROP_REMISR:
4921 		pcmcia_remove_intr_impl(dip, rdip, hdlp);
4922 		break;
4923 	case DDI_INTROP_ENABLE:
4924 	case DDI_INTROP_DISABLE:
4925 		break;
4926 	case DDI_INTROP_NINTRS:
4927 	case DDI_INTROP_NAVAIL:
4928 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
4929 		break;
4930 	case DDI_INTROP_SUPPORTED_TYPES:
4931 		/* PCI nexus driver supports only fixed interrupts */
4932 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
4933 		    DDI_INTR_TYPE_FIXED : 0;
4934 		break;
4935 	default:
4936 		ret = DDI_ENOTSUP;
4937 		break;
4938 	}
4939 
4940 	return (ret);
4941 }
4942 
4943 #elif defined(__x86) || defined(__amd64)
4944 
4945 static struct intrspec	*pcmcia_intr_get_ispec(dev_info_t *, int,
4946 			    pcmcia_logical_socket_t **);
4947 static struct intrspec	*pcmcia_intr_add_isr(dev_info_t *, dev_info_t *,
4948 			    ddi_intr_handle_impl_t *);
4949 static int		pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *,
4950 			    ddi_intr_handle_impl_t *);
4951 static void		pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *,
4952 			    ddi_intr_handle_impl_t *);
4953 static void		pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *,
4954 			    ddi_intr_handle_impl_t *);
4955 
4956 /*
4957  * pcmcia_intr_get_ispec:
4958  *	This is mostly copied from older 'pcmcia_get_intrspec' function
4959  */
4960 static struct intrspec *
4961 pcmcia_intr_get_ispec(dev_info_t *rdip, int inum,
4962     pcmcia_logical_socket_t **sockp)
4963 {
4964 	int				socket;
4965 	struct intrspec			*intrspec;
4966 	struct pcmcia_parent_private	*ppd;
4967 
4968 	if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip,
4969 	    DDI_PROP_DONTPASS, "interrupts", -1) < 0))
4970 		return (NULL);
4971 
4972 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
4973 	if (ppd == NULL || ppd->ppd_intrspec == NULL)
4974 		return (NULL);
4975 
4976 	if ((socket = ppd->ppd_socket) < 0)
4977 		return (NULL);
4978 
4979 	if ((*sockp = pcmcia_sockets[socket]) == NULL)
4980 		return (NULL);
4981 
4982 	intrspec = ppd->ppd_intrspec;
4983 	if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0)
4984 		intrspec->intrspec_vec = (*sockp)->ls_intr_vec;
4985 
4986 	return (intrspec);
4987 }
4988 
4989 static struct intrspec *
4990 pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip,
4991     ddi_intr_handle_impl_t *hdlp)
4992 {
4993 	int				socket;
4994 	struct intrspec			*ispecp;
4995 	struct pcmcia_adapter		*adapt;
4996 	pcmcia_logical_socket_t		*sockp;
4997 	struct pcmcia_parent_private	*ppd;
4998 
4999 #if defined(PCMCIA_DEBUG)
5000 	if (pcmcia_debug)
5001 		cmn_err(CE_CONT, "pcmcia_intr_add_isr: "
5002 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5003 		    (void *)dip, (void *)rdip, (void *)hdlp);
5004 #endif	/* PCMCIA_DEBUG */
5005 
5006 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5007 	socket = ppd->ppd_socket;
5008 	sockp = pcmcia_sockets[socket];
5009 	adapt = sockp->ls_adapter;
5010 
5011 	ispecp = ppd->ppd_intrspec;
5012 	if (ispecp == NULL) {
5013 		sockp->ls_error = BAD_IRQ;
5014 		return (ispecp);
5015 	}
5016 
5017 	/*
5018 	 * check if multifunction and do the right thing
5019 	 * we put an intercept in between the mfc handler and us so we can
5020 	 * catch and process. We might be able to optimize this depending
5021 	 * on the card features (a future option).
5022 	 */
5023 	if (ppd->ppd_flags & PPD_CARD_MULTI &&
5024 	    hdlp->ih_cb_func != pcmcia_mfc_intr) {
5025 		inthandler_t *intr;
5026 
5027 		/*
5028 		 * note that the first function is a special case since it
5029 		 * sets things up.  We fall through to the lower code and
5030 		 * get the hardware set up. Subsequent times we just lock
5031 		 * the list and insert the handler and all is well.
5032 		 */
5033 		intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
5034 		if (intr == NULL) {
5035 			sockp->ls_error = BAD_IRQ;
5036 			return (NULL);
5037 		}
5038 
5039 		intr->intr = (uint32_t (*)())hdlp->ih_cb_func;
5040 		intr->handler_id = (uint32_t)(uintptr_t)rdip;
5041 		intr->arg1 = hdlp->ih_cb_arg1;
5042 		intr->arg2 = hdlp->ih_cb_arg2;
5043 		intr->socket = socket;
5044 		mutex_enter(&sockp->ls_ilock);
5045 		if (sockp->ls_inthandlers == NULL) {
5046 			intr->next = intr->prev = intr;
5047 			sockp->ls_inthandlers = intr;
5048 			sockp->ls_mfintr_dip = rdip;
5049 		} else {
5050 			insque(intr, sockp->ls_inthandlers);
5051 		}
5052 		mutex_exit(&sockp->ls_ilock);
5053 		return (ispecp);
5054 	}
5055 
5056 	/*
5057 	 * Do we need to allocate an IRQ at this point or not?
5058 	 */
5059 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5060 		int i, irq;
5061 
5062 		/*
5063 		 * this adapter needs IRQ allocations
5064 		 * this is only necessary if it is the first function on the
5065 		 * card being setup. The socket will keep the allocation info
5066 		 */
5067 		/* all functions use same intrspec except mfc handler */
5068 		if (hdlp->ih_cb_func == pcmcia_mfc_intr) {
5069 			/*
5070 			 * We treat this special in order to allow things to
5071 			 * work properly for MFC cards. The intrspec for the
5072 			 * mfc dispatcher is intercepted and taken from the
5073 			 * logical socket in order to not be trying to
5074 			 * multiplex the meaning when ENABLE is called.
5075 			 */
5076 			ispecp = &sockp->ls_intrspec;
5077 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
5078 		}
5079 
5080 		if (adapt->pca_flags & PCA_IRQ_ISA) {
5081 			for (irq = -1, i = 1; irq == -1 && i < 16; i++) {
5082 				/* find available and usable IRQ level */
5083 				if (adapt->pca_avail_intr & (1 << i))
5084 					irq = pcmcia_get_intr(dip, i);
5085 			}
5086 		}
5087 		if (irq < 0) {
5088 			sockp->ls_error = NO_RESOURCE;
5089 			return (NULL);
5090 		}
5091 		hdlp->ih_vector = sockp->ls_intr_vec = irq;
5092 
5093 
5094 #if defined(PCMCIA_DEBUG)
5095 		if (pcmcia_debug)
5096 			cmn_err(CE_CONT, "allocated irq=%x\n", irq);
5097 #endif	/* PCMCIA_DEBUG */
5098 
5099 		ispecp->intrspec_vec = sockp->ls_intr_vec;
5100 		ispecp->intrspec_pri = sockp->ls_intr_pri;
5101 		return (ispecp);
5102 	}
5103 
5104 	if (ispecp->intrspec_func != NULL)
5105 		ispecp->intrspec_func = hdlp->ih_cb_func;
5106 
5107 	/* set default IPL then check for override */
5108 	ispecp->intrspec_pri = sockp->ls_intr_pri;
5109 	return (ispecp);
5110 }
5111 
5112 
5113 static int
5114 pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip,
5115     ddi_intr_handle_impl_t *hdlp)
5116 {
5117 	int				socket, ret;
5118 	int				irq = 0;	/* default case */
5119 	dev_info_t			*parent = ddi_root_node();
5120 	struct intrspec			*ispecp;
5121 	set_irq_handler_t		handler;
5122 	struct pcmcia_adapter		*adapt;
5123 	pcmcia_logical_socket_t		*sockp;
5124 	struct pcmcia_parent_private	*ppd;
5125 
5126 #if defined(PCMCIA_DEBUG)
5127 	if (pcmcia_debug)
5128 		cmn_err(CE_CONT, "pcmcia_intr_enable_isr: "
5129 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5130 		    (void *)dip, (void *)rdip, (void *)hdlp);
5131 #endif	/* PCMCIA_DEBUG */
5132 
5133 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5134 	socket = ppd->ppd_socket;
5135 	sockp = pcmcia_sockets[socket];
5136 	adapt = sockp->ls_adapter;
5137 
5138 	ispecp = ppd->ppd_intrspec;
5139 	ASSERT(ispecp);
5140 
5141 	mutex_enter(&sockp->ls_ilock);
5142 	if ((sockp->ls_inthandlers != NULL) &&
5143 	    ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
5144 	    &sockp->ls_intrspec) {
5145 		inthandler_t *intr = sockp->ls_inthandlers;
5146 
5147 		ASSERT(ppd->ppd_flags & PPD_CARD_MULTI);
5148 
5149 		/* Only one handler. So, call ddi_add_intr on it */
5150 		if ((intr->next == intr) && (intr->prev == intr)) {
5151 			hdlp->ih_cb_func = pcmcia_mfc_intr;
5152 			hdlp->ih_cb_arg1 = (caddr_t)sockp;
5153 			hdlp->ih_cb_arg2 = NULL;
5154 
5155 			ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->
5156 			    bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE,
5157 			    hdlp, NULL);
5158 
5159 			if (ret == DDI_FAILURE) {
5160 				sockp->ls_inthandlers = NULL;
5161 				kmem_free(intr, sizeof (inthandler_t));
5162 				sockp->ls_error = BAD_IRQ;
5163 				mutex_exit(&sockp->ls_ilock);
5164 				return (ret);
5165 			}
5166 		}
5167 		mutex_exit(&sockp->ls_ilock);
5168 		hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec;
5169 		hdlp->ih_pri = sockp->ls_intr_pri;
5170 		sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
5171 		    sockp->ls_intr_pri;
5172 		sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector;
5173 		sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
5174 		return (DDI_SUCCESS);
5175 	}
5176 	mutex_exit(&sockp->ls_ilock);
5177 
5178 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5179 		if (hdlp->ih_cb_func == pcmcia_mfc_intr)
5180 			ispecp = (struct intrspec *)&sockp->ls_intrspec;
5181 
5182 		/* XXX: remove it later as this is done in _add_isr as well */
5183 		ispecp->intrspec_vec = sockp->ls_intr_vec;
5184 		ispecp->intrspec_pri = sockp->ls_intr_pri;
5185 
5186 		/* Enable interrupts */
5187 		ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
5188 		    parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL);
5189 
5190 		sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
5191 		    sockp->ls_intr_pri;
5192 		sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec;
5193 		sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
5194 
5195 		if (ret != DDI_SUCCESS)
5196 			sockp->ls_error = BAD_IRQ;
5197 		return (ret);
5198 	}
5199 
5200 #if defined(PCMCIA_DEBUG)
5201 	if (pcmcia_debug)
5202 		cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n");
5203 #endif	/* PCMCIA_DEBUG */
5204 
5205 	handler.socket = sockp->ls_socket;
5206 	handler.irq = irq;
5207 	handler.handler = (f_tt *)hdlp->ih_cb_func;
5208 	handler.arg1 = hdlp->ih_cb_arg1;
5209 	handler.arg2 = hdlp->ih_cb_arg2;
5210 	handler.handler_id = (uint32_t)(uintptr_t)rdip;
5211 	if (ispecp->intrspec_func != NULL)
5212 		ispecp->intrspec_func = hdlp->ih_cb_func;
5213 
5214 	/* set default IPL then check for override */
5215 	ispecp->intrspec_pri = sockp->ls_intr_pri;
5216 
5217 	if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
5218 	    SUCCESS) {
5219 		sockp->ls_error = ret;
5220 		return (DDI_FAILURE);
5221 	}
5222 	ispecp->intrspec_func = hdlp->ih_cb_func;
5223 	if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
5224 		sockp->ls_iblk = *handler.iblk_cookie;
5225 		sockp->ls_idev = *handler.idev_cookie;
5226 		sockp->ls_flags |= PCS_COOKIES_VALID;
5227 	}
5228 	return (DDI_SUCCESS);
5229 }
5230 
5231 /* ARGSUSED */
5232 static void
5233 pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip,
5234     ddi_intr_handle_impl_t *hdlp)
5235 {
5236 	int				done, remhandler = 0;
5237 	inthandler_t			*intr, *first;
5238 	struct intrspec			*ispecp;
5239 	pcmcia_logical_socket_t		*sockp;
5240 
5241 #if defined(PCMCIA_DEBUG)
5242 	if (pcmcia_debug)
5243 		cmn_err(CE_CONT, "pcmcia_intr_remove_isr: "
5244 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5245 		    (void *)dip, (void *)rdip, (void *)hdlp);
5246 #endif	/* PCMCIA_DEBUG */
5247 
5248 	ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5249 	ASSERT(ispecp);
5250 
5251 	/* first handle the multifunction case since it is simple */
5252 	mutex_enter(&sockp->ls_ilock);
5253 	if (sockp->ls_inthandlers != NULL &&
5254 	    ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
5255 	    &sockp->ls_intrspec) {
5256 
5257 		intr = sockp->ls_inthandlers;
5258 
5259 		/* Check if there is only one handler left */
5260 		if ((intr->next == intr) && (intr->prev == intr)) {
5261 			if (intr->handler_id == (uint32_t)(uintptr_t)rdip) {
5262 				sockp->ls_inthandlers = NULL;
5263 				remhandler++;
5264 				kmem_free(intr, sizeof (inthandler_t));
5265 			}
5266 
5267 		} else {
5268 			for (done = 0, first = intr; !done; intr = intr->next) {
5269 				if (intr->next == first)
5270 					done++;
5271 				if (intr->handler_id ==
5272 				    (uint32_t)(uintptr_t)rdip) {
5273 					done++;
5274 
5275 					/*
5276 					 * If we're about to remove the handler
5277 					 * at the head of the list, make the
5278 					 * next handler in line the head.
5279 					 */
5280 					if (sockp->ls_inthandlers == intr)
5281 					    sockp->ls_inthandlers = intr->next;
5282 
5283 					remque(intr);
5284 					kmem_free(intr, sizeof (inthandler_t));
5285 					break;
5286 				} /* handler_id */
5287 			} /* end of for */
5288 		} /* end of if intr->next */
5289 
5290 		if (!remhandler) {
5291 			mutex_exit(&sockp->ls_ilock);
5292 			return;
5293 		}
5294 	}
5295 	mutex_exit(&sockp->ls_ilock);
5296 
5297 	if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) {
5298 		sockp->ls_intr_vec = 0;
5299 		ispecp->intrspec_vec = 0;
5300 	}
5301 }
5302 
5303 
5304 static void
5305 pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip,
5306     ddi_intr_handle_impl_t *hdlp)
5307 {
5308 	int				socket, ret;
5309 	dev_info_t			*parent;
5310 	struct intrspec			*ispecp;
5311 	clear_irq_handler_t		handler;
5312 	struct pcmcia_adapter		*adapt;
5313 	pcmcia_logical_socket_t		*sockp;
5314 	struct pcmcia_parent_private	*ppd;
5315 	ihdl_plat_t			*ihdl_plat_datap =
5316 					    (ihdl_plat_t *)hdlp->ih_private;
5317 
5318 #if defined(PCMCIA_DEBUG)
5319 	if (pcmcia_debug)
5320 		cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5321 		    "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5322 		    (void *)dip, (void *)rdip, (void *)hdlp);
5323 #endif	/* PCMCIA_DEBUG */
5324 
5325 	ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5326 	socket = ppd->ppd_socket;
5327 	sockp = pcmcia_sockets[socket];
5328 	adapt = sockp->ls_adapter;
5329 	ispecp = ppd->ppd_intrspec;
5330 	ASSERT(ispecp);
5331 
5332 	mutex_enter(&sockp->ls_ilock);
5333 	if (sockp->ls_inthandlers != NULL &&
5334 	    ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) {
5335 		inthandler_t	*intr = sockp->ls_inthandlers;
5336 
5337 		/* Check if there is only one handler left */
5338 		if ((intr->next == intr) && (intr->prev == intr)) {
5339 			if (intr->handler_id != (uint32_t)(uintptr_t)rdip)
5340 				/*
5341 				 * need to get the dip that was
5342 				 * used to add the handler
5343 				 */
5344 				rdip = sockp->ls_mfintr_dip;
5345 				ispecp = (struct intrspec *)&sockp->ls_intrspec;
5346 		} else {
5347 			/* Don't call cleanup if list still has members */
5348 			mutex_exit(&sockp->ls_ilock);
5349 			return;
5350 		}
5351 	}
5352 	mutex_exit(&sockp->ls_ilock);
5353 
5354 	if (ihdl_plat_datap->ip_ispecp ==
5355 	    (struct intrspec *)&sockp->ls_intrspec)
5356 		ispecp = ihdl_plat_datap->ip_ispecp;
5357 
5358 	if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5359 		ret = ispecp->intrspec_vec;
5360 		parent = ddi_root_node();
5361 		ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
5362 		    parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL);
5363 		(void) pcmcia_return_intr(dip, hdlp->ih_vector);
5364 #if defined(PCMCIA_DEBUG)
5365 		if (pcmcia_debug)
5366 			cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5367 			    "INTROP_DISABLE returned %x\n", ret);
5368 #endif	/* PCMCIA_DEBUG */
5369 	} else {
5370 		handler.socket = sockp->ls_socket;
5371 		handler.handler_id = (uint32_t)(uintptr_t)rdip;
5372 		handler.handler = (f_tt *)ispecp->intrspec_func;
5373 		ret = CLEAR_IRQ(sockp->ls_if, dip, &handler);
5374 #if defined(PCMCIA_DEBUG)
5375 		if (pcmcia_debug)
5376 			cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5377 			    "CLEAR_IRQ returned %x\n", ret);
5378 #endif	/* PCMCIA_DEBUG */
5379 	}
5380 }
5381 
5382 /* Consolidated interrupt processing interface */
5383 int
5384 pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
5385     ddi_intr_handle_impl_t *hdlp, void *result)
5386 {
5387 	struct intrspec		*ispecp;
5388 	pcmcia_logical_socket_t	*sockp;
5389 
5390 #if defined(PCMCIA_DEBUG)
5391 	if (pcmcia_debug)
5392 		cmn_err(CE_CONT, "pcmcia_intr_ops: "
5393 		    "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n",
5394 		    (void *)dip, (void *)rdip, intr_op, (void *)hdlp);
5395 #endif	/* PCMCIA_DEBUG */
5396 
5397 	switch (intr_op) {
5398 	case DDI_INTROP_SUPPORTED_TYPES:
5399 		if (ddi_get_parent_data(rdip) == NULL) {
5400 			*(int *)result = 0;
5401 			return (DDI_FAILURE);
5402 		}
5403 		*(int *)result = DDI_INTR_TYPE_FIXED;
5404 		break;
5405 	case DDI_INTROP_GETCAP:
5406 		*(int *)result = DDI_INTR_FLAG_LEVEL;
5407 		break;
5408 	case DDI_INTROP_NINTRS:
5409 	case DDI_INTROP_NAVAIL:
5410 		if (i_ddi_get_intx_nintrs(rdip) == 0) {
5411 			*(int *)result = 0;
5412 			return (DDI_FAILURE);
5413 		}
5414 		*(int *)result = 1;	/* for PCMCIA there is only one intr */
5415 		break;
5416 	case DDI_INTROP_ALLOC:
5417 		if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum,
5418 		    &sockp)) == NULL)
5419 			return (DDI_FAILURE);
5420 		*(int *)result = hdlp->ih_scratch1;
5421 		break;
5422 	case DDI_INTROP_FREE:
5423 		break;
5424 	case DDI_INTROP_GETPRI:
5425 		ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5426 		if (ispecp == NULL) {
5427 			*(int *)result = 0;
5428 			return (DDI_FAILURE);
5429 		}
5430 
5431 		*(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri;
5432 		break;
5433 	case DDI_INTROP_SETPRI:
5434 		if (*(int *)result > LOCK_LEVEL)
5435 			return (DDI_FAILURE);
5436 		ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5437 		ASSERT(ispecp);
5438 		ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result;
5439 		break;
5440 	case DDI_INTROP_ADDISR:
5441 		if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL)
5442 			return (DDI_FAILURE);
5443 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
5444 		break;
5445 	case DDI_INTROP_REMISR:
5446 		pcmcia_intr_remove_isr(dip, rdip, hdlp);
5447 		break;
5448 	case DDI_INTROP_ENABLE:
5449 		if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS)
5450 			return (DDI_FAILURE);
5451 		break;
5452 	case DDI_INTROP_DISABLE:
5453 		pcmcia_intr_disable_isr(dip, rdip, hdlp);
5454 		break;
5455 	default:
5456 		return (DDI_ENOTSUP);
5457 	}
5458 
5459 	return (DDI_SUCCESS);
5460 }
5461 #endif
5462