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