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