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