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