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