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