xref: /onnv-gate/usr/src/uts/common/io/cardbus/cardbus.c (revision 7240:c4957ab6a78e)
12305Sstevel /*
22305Sstevel  * CDDL HEADER START
32305Sstevel  *
42305Sstevel  * The contents of this file are subject to the terms of the
52305Sstevel  * Common Development and Distribution License (the "License").
62305Sstevel  * You may not use this file except in compliance with the License.
72305Sstevel  *
82305Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel  * or http://www.opensolaris.org/os/licensing.
102305Sstevel  * See the License for the specific language governing permissions
112305Sstevel  * and limitations under the License.
122305Sstevel  *
132305Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel  * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel  *
192305Sstevel  * CDDL HEADER END
202305Sstevel  */
212305Sstevel /*
227151Srw148561  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
232305Sstevel  * Use is subject to license terms.
242305Sstevel  */
252305Sstevel 
262305Sstevel /*
272305Sstevel  * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
282305Sstevel  * All rights reserved.
292305Sstevel  * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
302305Sstevel  */
312305Sstevel 
322305Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
332305Sstevel 
342305Sstevel /*
352305Sstevel  * Cardbus module
362305Sstevel  */
372305Sstevel 
382305Sstevel #include <sys/conf.h>
392305Sstevel #include <sys/modctl.h>
402305Sstevel 
412305Sstevel #include <sys/pci.h>
422305Sstevel 
432305Sstevel #include <sys/ddi.h>
442305Sstevel #include <sys/sunndi.h>
452305Sstevel #include <sys/ddi_impldefs.h>
462305Sstevel 
472305Sstevel #include <sys/hotplug/hpcsvc.h>
482305Sstevel 
492305Sstevel #include <sys/pctypes.h>
502305Sstevel #include <sys/pcmcia.h>
512305Sstevel #include <sys/sservice.h>
522305Sstevel #include <sys/note.h>
532305Sstevel 
542305Sstevel #include <sys/pci/pci_types.h>
552305Sstevel #include <sys/pci/pci_sc.h>
562305Sstevel 
572305Sstevel #include <sys/pcic_reg.h>
582305Sstevel #include <sys/pcic_var.h>
592305Sstevel #include <sys/pcmcia.h>
602305Sstevel 
612305Sstevel #ifdef sparc
622305Sstevel #include <sys/ddi_subrdefs.h>
632305Sstevel #elif defined(__x86) || defined(__amd64)
642305Sstevel #include <sys/pci_intr_lib.h>
652305Sstevel #include <sys/mach_intr.h>
662305Sstevel #endif
672305Sstevel 
682305Sstevel #include "cardbus.h"
692305Sstevel #include "cardbus_parse.h"
702305Sstevel #include "cardbus_hp.h"
712305Sstevel #include "cardbus_cfg.h"
722305Sstevel 
732305Sstevel static int cardbus_command_default = PCI_COMM_SERR_ENABLE |
742305Sstevel 				PCI_COMM_WAIT_CYC_ENAB |
752305Sstevel 				PCI_COMM_PARITY_DETECT |
762305Sstevel 				PCI_COMM_ME | PCI_COMM_MAE |
772305Sstevel 				PCI_COMM_IO;
782305Sstevel 
792305Sstevel static int cardbus_next_instance = 0;
802305Sstevel static int cardbus_count = 0;
812451Srw148561 int number_of_cardbus_cards = 0;
822305Sstevel 
832305Sstevel static int cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip,
842305Sstevel 		ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp);
852305Sstevel static void pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp);
862305Sstevel 
872305Sstevel static int cardbus_ctlops(dev_info_t *, dev_info_t *,
882305Sstevel 			ddi_ctl_enum_t, void *arg, void *);
892305Sstevel static void cardbus_init_child_regs(dev_info_t *child);
902305Sstevel static int cardbus_initchild(dev_info_t *, dev_info_t *,
912305Sstevel 			dev_info_t *, void *);
922305Sstevel static int cardbus_name_child(dev_info_t *, char *, int);
932305Sstevel static void cardbus_removechild(dev_info_t *dip);
942305Sstevel 
952305Sstevel static int cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
962305Sstevel 		ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
972305Sstevel 		ddi_dma_handle_t *handlep);
982305Sstevel static int cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
992305Sstevel 		ddi_dma_handle_t handle);
1002305Sstevel static int cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1012305Sstevel 		ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1022305Sstevel 		ddi_dma_cookie_t *cp, uint_t *ccountp);
1032305Sstevel static int cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1042305Sstevel 		ddi_dma_handle_t handle);
1052305Sstevel static int cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1062305Sstevel 		ddi_dma_handle_t handle, off_t off, size_t len,
1072305Sstevel 		uint_t cache_flags);
1082305Sstevel static int cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
1092305Sstevel 		ddi_dma_handle_t handle, uint_t win, off_t *offp,
1102305Sstevel 		size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
1112305Sstevel static int cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
1122305Sstevel 		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep);
1132305Sstevel 
1142305Sstevel static int cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
1152305Sstevel 		ddi_prop_op_t prop_op, int mod_flags,
1162305Sstevel 		char *name, caddr_t valuep, int *lengthp);
1172305Sstevel 
1182305Sstevel static int cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
1192305Sstevel 		char *eventname, ddi_eventcookie_t *cookiep);
1202305Sstevel static int cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
1212305Sstevel 		ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
1222305Sstevel 		ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
1232305Sstevel 		void *arg, ddi_callback_id_t *cb_id);
1242305Sstevel static int cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
1252305Sstevel static int cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
1262305Sstevel 		ddi_eventcookie_t cookie, void *bus_impldata);
1272305Sstevel 
1282305Sstevel static int cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1292305Sstevel 		ddi_intr_op_t intr_op,
1302305Sstevel 		ddi_intr_handle_impl_t *hdlp, void *result);
1312305Sstevel 
1322305Sstevel static int check_token(char *token, int *len);
1332305Sstevel static char *find_token(char **cp, int *l, char *endc);
1342305Sstevel static int parse_token(char *token);
1352305Sstevel static int token_to_hex(char *token, unsigned *val, int len);
1362305Sstevel static int token_to_dec(char *token, unsigned *val, int len);
1372305Sstevel static void cardbus_add_prop(struct cb_deviceset_props *cdsp, int type,
1382305Sstevel 		char *name, caddr_t vp, int len);
1392305Sstevel static void cardbus_add_stringprop(struct cb_deviceset_props *cdsp,
1402305Sstevel 		char *name, char *vp, int len);
1412305Sstevel static void cardbus_prop_free(ddi_prop_t *propp);
1422305Sstevel static void cardbus_devprops_free(struct cb_deviceset_props *cbdp);
1432305Sstevel static int cardbus_parse_devprop(cbus_t *cbp, char *cp);
1442305Sstevel static void cardbus_device_props(cbus_t *cbp);
1452305Sstevel 
1462305Sstevel static void cardbus_expand_busrange(dev_info_t *dip);
1472305Sstevel 
1482305Sstevel static int cardbus_convert_properties(dev_info_t *dip);
1492305Sstevel static void cardbus_revert_properties(dev_info_t *dip);
1502305Sstevel 
1512305Sstevel /*
1522305Sstevel  * driver global data
1532305Sstevel  */
1542305Sstevel kmutex_t cardbus_list_mutex; /* Protects the probe handle list */
1552305Sstevel void *cardbus_state;
1562305Sstevel int cardbus_latency_timer = 0x40;
1572305Sstevel int cardbus_debug = 0;
1582305Sstevel 
1592305Sstevel /*
1602305Sstevel  * Module linkage information for the kernel.
1612305Sstevel  */
1622305Sstevel extern struct mod_ops mod_miscops;
1632305Sstevel static struct modlmisc modlmisc = {
1642305Sstevel 	&mod_miscops,
165*7240Srh87107 	"Cardbus Configurator support",
1662305Sstevel };
1672305Sstevel 
1682305Sstevel static struct modlinkage modlinkage = {
1692305Sstevel 	MODREV_1,
1702305Sstevel 	&modlmisc,
1712305Sstevel 	NULL
1722305Sstevel };
1732305Sstevel 
1742305Sstevel int
_init(void)1752305Sstevel _init(void)
1762305Sstevel {
1772305Sstevel 	int error;
1782305Sstevel 
1792305Sstevel 	error =  ddi_soft_state_init(&cardbus_state, sizeof (cbus_t), 0);
1802305Sstevel 	if (error != 0)
1812305Sstevel 		return (error);
1822305Sstevel 
1832305Sstevel 	mutex_init(&cardbus_list_mutex, NULL, MUTEX_DRIVER, NULL);
1842305Sstevel 	if ((error = mod_install(&modlinkage)) != 0) {
1852305Sstevel 		mutex_destroy(&cardbus_list_mutex);
1862305Sstevel 	}
1872305Sstevel 
1882305Sstevel 	return (error);
1892305Sstevel }
1902305Sstevel 
1912305Sstevel int
_fini(void)1922305Sstevel _fini(void)
1932305Sstevel {
1942305Sstevel 	int error;
1952305Sstevel 	if ((error = mod_remove(&modlinkage)) == 0) {
1962305Sstevel 		mutex_destroy(&cardbus_list_mutex);
1972305Sstevel 		ddi_soft_state_fini(&cardbus_state);
1982305Sstevel 	}
1992305Sstevel 	return (error);
2002305Sstevel }
2012305Sstevel 
2022305Sstevel int
_info(struct modinfo * modinfop)2032305Sstevel _info(struct modinfo *modinfop)
2042305Sstevel {
2052305Sstevel 	return (mod_info(&modlinkage, modinfop));
2062305Sstevel }
2072305Sstevel 
2082305Sstevel static
2092305Sstevel struct bus_ops cardbusbus_ops = {
2102305Sstevel 	BUSO_REV,
2112305Sstevel 	cardbus_bus_map,
2122305Sstevel 	NULL,
2132305Sstevel 	NULL,
2142305Sstevel 	NULL,
2152305Sstevel 	i_ddi_map_fault,
2162305Sstevel 	cardbus_dma_map,
2172305Sstevel 	cardbus_dma_allochdl,
2182305Sstevel 	cardbus_dma_freehdl,
2192305Sstevel 	cardbus_dma_bindhdl,
2202305Sstevel 	cardbus_dma_unbindhdl,
2212305Sstevel 	cardbus_dma_flush,
2222305Sstevel 	cardbus_dma_win,
2232305Sstevel 	ddi_dma_mctl,
2242305Sstevel 	cardbus_ctlops,			/* (*bus_ctl)();		*/
2252305Sstevel 	cardbus_prop_op,
2262305Sstevel 	cardbus_get_eventcookie,	/* (*bus_get_eventcookie)();	*/
2272305Sstevel 	cardbus_add_eventcall,		/* (*bus_add_eventcall)();	*/
2282305Sstevel 	cardbus_remove_eventcall,	/* (*bus_remove_eventcall)();	*/
2292305Sstevel 	cardbus_post_event,		/* (*bus_post_event)();		*/
2302305Sstevel 	NULL,				/* (*bus_intr_ctl)();		*/
2312305Sstevel 	NULL,				/* (*bus_config)();		*/
2322305Sstevel 	NULL,				/* (*bus_unconfig)();		*/
2332305Sstevel 	NULL,				/* (*bus_fm_init)();		*/
2342305Sstevel 	NULL,				/* (*bus_fm_fini)();		*/
2352305Sstevel 	NULL,				/* (*bus_enter)();		*/
2362305Sstevel 	NULL,				/* (*bus_exit)();		*/
2372305Sstevel 	NULL,				/* (*bus_power)();		*/
2382305Sstevel 	cardbus_intr_ops		/* (*bus_intr_op)();		*/
2392305Sstevel };
2402305Sstevel 
2412305Sstevel #define	CB_EVENT_TAG_INSERT	0
2422305Sstevel #define	CB_EVENT_TAG_REMOVE	1
2432305Sstevel 
2442305Sstevel static ndi_event_definition_t cb_ndi_event_defs[] = {
2452305Sstevel 	{ CB_EVENT_TAG_INSERT, DDI_DEVI_INSERT_EVENT, EPL_INTERRUPT, 0 },
2462305Sstevel 	{ CB_EVENT_TAG_REMOVE, DDI_DEVI_REMOVE_EVENT, EPL_INTERRUPT, 0 }
2472305Sstevel };
2482305Sstevel 
2492305Sstevel #define	CB_N_NDI_EVENTS \
2502305Sstevel 	(sizeof (cb_ndi_event_defs) / sizeof (cb_ndi_event_defs[0]))
2512305Sstevel 
2522305Sstevel #ifdef sparc
2532305Sstevel struct busnum_ctrl {
2542305Sstevel 	int	rv;
2552305Sstevel 	dev_info_t *dip;
2562305Sstevel 	cardbus_bus_range_t *range;
2572305Sstevel };
2582305Sstevel 
2592305Sstevel static int
cardbus_claim_pci_busnum(dev_info_t * dip,void * arg)2602305Sstevel cardbus_claim_pci_busnum(dev_info_t *dip, void *arg)
2612305Sstevel {
2622305Sstevel 	cardbus_bus_range_t pci_bus_range;
2632305Sstevel 	struct busnum_ctrl *ctrl;
2642305Sstevel 	ndi_ra_request_t req;
2652305Sstevel 	char bus_type[16] = "(unknown)";
2662305Sstevel 	int len;
2672305Sstevel 	uint64_t base;
2682305Sstevel 	uint64_t retlen;
2692305Sstevel 
2702305Sstevel 	ctrl = (struct busnum_ctrl *)arg;
2712305Sstevel 
2722305Sstevel 	/* check if this is a PCI bus node */
2732305Sstevel 	len = sizeof (bus_type);
2742305Sstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2752305Sstevel 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
2762305Sstevel 	    "device_type",
2772305Sstevel 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
2782305Sstevel 		return (0);	/* (DDI_WALK_PRUNECHILD); */
2792305Sstevel 
2802305Sstevel 	if ((strcmp(bus_type, "pci") != 0) &&
2812305Sstevel 	    (strcmp(bus_type, "pciex") != 0)) /* it is not a pci bus type */
2822305Sstevel 		return (0);	/* (DDI_WALK_PRUNECHILD); */
2832305Sstevel 
2842305Sstevel 	/* look for the bus-range property */
2852305Sstevel 	len = sizeof (struct cardbus_bus_range);
2862305Sstevel 	if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2872305Sstevel 	    "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
2882305Sstevel 		cardbus_err(dip, 1, "cardbus_claim_pci_busnum: %u -> %u \n",
289*7240Srh87107 		    pci_bus_range.lo, pci_bus_range.hi);
2902305Sstevel 		if ((pci_bus_range.lo >= ctrl->range->lo) &&
2912305Sstevel 		    (pci_bus_range.hi <= ctrl->range->hi)) {
2922305Sstevel 			cardbus_err(dip, 1,
2932305Sstevel 			    "cardbus_claim_pci_busnum: claim %u -> %u \n",
2942305Sstevel 			    pci_bus_range.lo, pci_bus_range.hi);
2952305Sstevel 
2962305Sstevel 			/* claim the bus range from the bus resource map */
2972305Sstevel 			bzero((caddr_t)&req, sizeof (req));
2982305Sstevel 			req.ra_addr = (uint64_t)pci_bus_range.lo;
2992305Sstevel 			req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
3002305Sstevel 			req.ra_len = (uint64_t)pci_bus_range.hi -
3012305Sstevel 			    (uint64_t)pci_bus_range.lo + 1;
3022305Sstevel 
3032305Sstevel 			if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
3042305Sstevel 			    NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
3052305Sstevel 				return (0);	/* (DDI_WALK_PRUNECHILD); */
3062305Sstevel 		}
3072305Sstevel 	}
3082305Sstevel 
3092305Sstevel 	/*
3102305Sstevel 	 * never Error return.
3112305Sstevel 	 */
3122305Sstevel 	ctrl->rv = DDI_SUCCESS;
3132305Sstevel 	return (DDI_WALK_TERMINATE);
3142305Sstevel }
3152305Sstevel 
3162305Sstevel static void
cardbus_walk_node_child(dev_info_t * parent,int (* f)(dev_info_t *,void *),void * arg)3172305Sstevel cardbus_walk_node_child(dev_info_t *parent,
3182305Sstevel 	int (*f)(dev_info_t *, void *), void *arg)
3192305Sstevel {
3202305Sstevel 	dev_info_t *dip;
3212305Sstevel 	int ret;
3222305Sstevel 
3232305Sstevel 	for (dip = ddi_get_child(parent); dip;
3242305Sstevel 	    dip = ddi_get_next_sibling(dip)) {
3252305Sstevel 
3262305Sstevel 		ret = (*f) (dip, arg);
3272305Sstevel 		if (ret)
3282305Sstevel 			return;
3292305Sstevel 	}
3302305Sstevel }
3312305Sstevel 
cardbus_fix_hostbridge_busrange(dev_info_t * dip)3322305Sstevel static void cardbus_fix_hostbridge_busrange(dev_info_t *dip)
3332305Sstevel {
3342305Sstevel 	cardbus_bus_range_t bus_range;
3352305Sstevel 	struct busnum_ctrl ctrl;
3362305Sstevel 
3372305Sstevel 	uint64_t next_bus;
3382305Sstevel 	uint64_t blen;
3392305Sstevel 	ndi_ra_request_t req;
3402305Sstevel 	int	len;
3412305Sstevel 
3422305Sstevel 	cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange\n");
3432305Sstevel 
3442305Sstevel 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
3452305Sstevel 	req.ra_len = 1;
3462305Sstevel 	if (ndi_ra_alloc(dip, &req,
3472305Sstevel 	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
3482305Sstevel 	    0) != NDI_SUCCESS) {
3492305Sstevel 		(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
3502305Sstevel 
3512305Sstevel 		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
3522305Sstevel 		    == NDI_FAILURE) {
3532305Sstevel 			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3542305Sstevel 			    "NDI_RA_TYPE_PCI_BUSNUM setup fail\n");
3552305Sstevel 			return;
3562305Sstevel 		}
3572305Sstevel 
3582305Sstevel 		bus_range.lo = 0;
3592305Sstevel 		(void) ddi_getlongprop_buf(DDI_DEV_T_NONE, dip,
360*7240Srh87107 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus_range, &len);
3612305Sstevel 		bus_range.hi = 255;
3622305Sstevel 
3632305Sstevel 		(void) ndi_ra_free(dip,
3642305Sstevel 		    (uint64_t)bus_range.lo + 1,
3652305Sstevel 		    (uint64_t)bus_range.hi - (uint64_t)bus_range.lo,
3662305Sstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
3672305Sstevel 
3682305Sstevel 		ctrl.rv = DDI_SUCCESS;
3692305Sstevel 		ctrl.dip = dip;
3702305Sstevel 		ctrl.range = &bus_range;
3712305Sstevel 
3722305Sstevel 		cardbus_walk_node_child(dip, cardbus_claim_pci_busnum,
3732305Sstevel 		    (void*)&ctrl);
3742305Sstevel 
3752305Sstevel 		if (ctrl.rv != DDI_SUCCESS)
3762305Sstevel 			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3772305Sstevel 			    "cardbus_walk_node_child fails\n");
3782305Sstevel 
3792305Sstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
380*7240Srh87107 		    "bus-range", (int *)&bus_range, 2);
3812305Sstevel 
3822305Sstevel 	} else {
3832305Sstevel 		cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3842305Sstevel 		    "already set up %x\n", (int)next_bus);
3852305Sstevel 		(void) ndi_ra_free(dip, next_bus, (uint64_t)1,
3862305Sstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
3872305Sstevel 	}
3882305Sstevel }
3892305Sstevel 
3902305Sstevel static dev_info_t *
cardbus_find_hsbridge_dip(dev_info_t * dip)3912305Sstevel cardbus_find_hsbridge_dip(dev_info_t *dip)
3922305Sstevel {
3932305Sstevel 	dev_info_t *pdip;
3942305Sstevel 
3952305Sstevel 	pdip = ddi_get_parent(dip);
3962305Sstevel 	while (pdip) {
3972305Sstevel 		if (ddi_get_parent(pdip) == ddi_root_node())
3982305Sstevel 			break;
3992305Sstevel 		pdip = ddi_get_parent(pdip);
4002305Sstevel 	}
4012305Sstevel 
4022305Sstevel 	return (pdip);
4032305Sstevel }
4042305Sstevel #endif /* sparc */
4052305Sstevel 
4062305Sstevel /*
4072305Sstevel  * Attach a device to the cardbus infrastructure.
4082305Sstevel  */
4092305Sstevel int
cardbus_attach(dev_info_t * dip,cb_nexus_cb_t * nex_ops)4102305Sstevel cardbus_attach(dev_info_t *dip, cb_nexus_cb_t *nex_ops)
4112305Sstevel {
4122305Sstevel 	cbus_t *cbp;
4132305Sstevel 	int cb_instance;
4142305Sstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
4152305Sstevel 	struct dev_info *devi = DEVI(dip);
4162305Sstevel 
4172305Sstevel 	mutex_enter(&cardbus_list_mutex);
4182305Sstevel 
4192305Sstevel 	/*
4202305Sstevel 	 * Make sure that it is not already initialized.
4212305Sstevel 	 */
4222305Sstevel 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
4232305Sstevel 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
4242305Sstevel 	    "cbus-instance") == 1) {
4252305Sstevel 		cmn_err(CE_WARN,
4262305Sstevel 		    "%s%d: cardbus instance already initialized!\n",
4272305Sstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
428*7240Srh87107 			mutex_exit(&cardbus_list_mutex);
4292305Sstevel 		return (DDI_FAILURE);
4302305Sstevel 	}
4312305Sstevel 
4322305Sstevel 	/*
4332305Sstevel 	 * initialize soft state structure for the bus instance.
4342305Sstevel 	 */
4352305Sstevel 	cb_instance = cardbus_next_instance++;
4362305Sstevel 
4372305Sstevel 	if (ddi_soft_state_zalloc(cardbus_state, cb_instance) != DDI_SUCCESS) {
4382305Sstevel 		cmn_err(CE_WARN, "%s%d: can't allocate cardbus soft state\n",
4392305Sstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
4402305Sstevel 		mutex_exit(&cardbus_list_mutex);
4412305Sstevel 		return (DDI_FAILURE);
4422305Sstevel 	}
4432305Sstevel 
4442305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
4452305Sstevel 	cbp->cb_instance = cb_instance;
4462305Sstevel 	cbp->cb_dip = dip;
4472305Sstevel 	mutex_init(&cbp->cb_mutex, NULL, MUTEX_DRIVER, NULL);
4482305Sstevel 
4492305Sstevel 	/*
4502305Sstevel 	 * Save the instance number of the soft state structure for
4512305Sstevel 	 * this bus as a devinfo property.
4522305Sstevel 	 */
4532305Sstevel 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
4542305Sstevel 	    "cbus-instance", (caddr_t)&cb_instance,
4552305Sstevel 	    sizeof (cb_instance)) != DDI_SUCCESS) {
4562305Sstevel 		cmn_err(CE_WARN,
4572305Sstevel 		    "%s%d: failed to add the property 'cbus-instance'",
4582305Sstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
4592305Sstevel 		ddi_soft_state_free(cardbus_state, cb_instance);
4602305Sstevel 		mutex_exit(&cardbus_list_mutex);
4612305Sstevel 		return (DDI_FAILURE);
4622305Sstevel 	}
4632305Sstevel 
4642305Sstevel 	cbp->cb_nex_ops = nex_ops;
4652305Sstevel 	/*
4662305Sstevel 	 * TODO - Should probably be some sort of locking on the devinfo here.
4672305Sstevel 	 */
4682305Sstevel 	cbp->orig_dopsp = devi->devi_ops;
4692305Sstevel 	cbp->orig_bopsp = devi->devi_ops->devo_bus_ops;
4702305Sstevel 	cbp->cb_dops = *devi->devi_ops;
4712305Sstevel 	devi->devi_ops = &cbp->cb_dops;
4722305Sstevel 
4732305Sstevel 	if (ndi_event_alloc_hdl(dip, *anp->an_iblock, &cbp->cb_ndi_event_hdl,
4742305Sstevel 	    NDI_SLEEP) == NDI_SUCCESS) {
4752305Sstevel 		cbp->cb_ndi_events.ndi_n_events = CB_N_NDI_EVENTS;
4762305Sstevel 		cbp->cb_ndi_events.ndi_events_version = NDI_EVENTS_REV1;
4772305Sstevel 		cbp->cb_ndi_events.ndi_event_defs = cb_ndi_event_defs;
4782305Sstevel 		if (ndi_event_bind_set(cbp->cb_ndi_event_hdl,
4792305Sstevel 		    &cbp->cb_ndi_events,
4802305Sstevel 		    NDI_SLEEP) != NDI_SUCCESS) {
4812305Sstevel 			cardbus_err(dip, 1,
4822305Sstevel 			    "cardbus_attach: ndi_event_bind_set failed\n");
4832305Sstevel 		}
4842305Sstevel 	}
4852305Sstevel 
4862305Sstevel 	/*
4872305Sstevel 	 * Check for device initialization property.
4882305Sstevel 	 */
4892305Sstevel 	cardbus_device_props(cbp);
4902305Sstevel 
4912305Sstevel 	if (cardbus_init_hotplug(cbp) != DDI_SUCCESS) {
4922305Sstevel 		ddi_soft_state_free(cardbus_state, cb_instance);
4932305Sstevel 		mutex_exit(&cardbus_list_mutex);
4942305Sstevel 		return (DDI_FAILURE);
4952305Sstevel 	}
4962305Sstevel 
4972305Sstevel #ifdef sparc
4982305Sstevel 	/* a hack to fix the bus-range problem on pci root nodes */
4992305Sstevel 	{
5002305Sstevel 		dev_info_t *hs_dip;
5012305Sstevel 
5022305Sstevel 		hs_dip = cardbus_find_hsbridge_dip(dip);
5032305Sstevel 		cardbus_fix_hostbridge_busrange(hs_dip);
5042305Sstevel 	}
5052305Sstevel #endif
5062305Sstevel 
5072305Sstevel 	cardbus_expand_busrange(dip);
5082305Sstevel 	cardbus_count++;
5092305Sstevel 	mutex_exit(&cardbus_list_mutex);
5102305Sstevel 	return (DDI_SUCCESS);
5112305Sstevel }
5122305Sstevel 
5132305Sstevel #ifdef TODO
5142305Sstevel static int
cardbus_detach(dev_info_t * dip)5152305Sstevel cardbus_detach(dev_info_t *dip)
5162305Sstevel {
5172305Sstevel 	int cb_instance;
5182305Sstevel 	cbus_t *cbp;
5192305Sstevel 
5202305Sstevel 	mutex_enter(&cardbus_list_mutex);
5212305Sstevel 	/* get the instance number for the cardbus soft state data */
5222305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
523*7240Srh87107 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
5242305Sstevel 	if (cb_instance < 0) {
5252305Sstevel 		mutex_exit(&cardbus_list_mutex);
5262305Sstevel 		return (DDI_FAILURE); /* no instance is setup for this bus */
5272305Sstevel 	}
5282305Sstevel 
5292305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5302305Sstevel 
5312305Sstevel 	if (cbp->cb_dsp) {
5322305Sstevel 		struct cb_deviceset_props *cbdp, *ncbdp;
5332305Sstevel 
5342305Sstevel 		cbdp = cbp->cb_dsp;
5352305Sstevel 		while (cbdp) {
5362305Sstevel 			ncbdp = cbdp->next;
5372305Sstevel 			cardbus_devprops_free(cbdp);
5382305Sstevel 			cbdp = ncbdp;
5392305Sstevel 		}
5402305Sstevel 	}
5412305Sstevel 	/*
5422305Sstevel 	 * Unregister the bus with the HPS.
5432305Sstevel 	 *
5442305Sstevel 	 * (Note: It is assumed that the HPS framework uninstalls
5452305Sstevel 	 *  event handlers for all the hot plug slots on this bus.)
5462305Sstevel 	 */
5472305Sstevel 	(void) hpc_nexus_unregister_bus(dip);
5482305Sstevel 
5492305Sstevel 	if (cbp->cb_ndi_event_hdl != NULL) {
5502305Sstevel 		(void) ndi_event_unbind_set(cbp->cb_ndi_event_hdl,
5512305Sstevel 		    &cbp->cb_ndi_events, NDI_SLEEP);
5522305Sstevel 		ndi_event_free_hdl(cbp->cb_ndi_event_hdl);
5532305Sstevel 	}
5542305Sstevel 
5552305Sstevel 	mutex_destroy(&cbp->cb_mutex);
5562305Sstevel 	if (cbp->nexus_path)
5572305Sstevel 		kmem_free(cbp->nexus_path, strlen(cbp->nexus_path) + 1);
5582305Sstevel 	if (cbp->name)
5592305Sstevel 		kmem_free(cbp->name, strlen(cbp->name) + 1);
5602305Sstevel 
5612305Sstevel 	ddi_soft_state_free(cardbus_state, cb_instance);
5622305Sstevel 
5632305Sstevel 	/* remove the 'cbus-instance' property from the devinfo node */
5642305Sstevel 	(void) ddi_prop_remove(DDI_DEV_T_ANY, dip, "cbus-instance");
5652305Sstevel 
5662305Sstevel 	ASSERT(cardbus_count != 0);
5672305Sstevel 	--cardbus_count;
5682305Sstevel 
5692305Sstevel 	mutex_exit(&cardbus_list_mutex);
5702305Sstevel 	return (DDI_SUCCESS);
5712305Sstevel }
5722305Sstevel #endif
5732305Sstevel 
5742305Sstevel boolean_t
cardbus_load_cardbus(dev_info_t * dip,uint_t socket,uint32_t pc_base)5752305Sstevel cardbus_load_cardbus(dev_info_t *dip, uint_t socket, uint32_t pc_base)
5762305Sstevel {
5772305Sstevel #ifndef HOTPLUG
5782305Sstevel 	struct cardbus_config_ctrl ctrl;
5792305Sstevel 	int circular_count;
5802305Sstevel #endif
5812305Sstevel 	int cb_instance;
5822305Sstevel 	cbus_t *cbp;
5832305Sstevel 	struct dev_info *devi = DEVI(dip);
5842305Sstevel 
5852305Sstevel 	_NOTE(ARGUNUSED(socket, pc_base))
5862305Sstevel 
5872305Sstevel #if defined(CARDBUS_DEBUG)
5882305Sstevel 	cardbus_err(dip, 6, "cardbus_load_cardbus\n");
5892305Sstevel #endif
5902305Sstevel 
5912305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
592*7240Srh87107 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
5932305Sstevel 	ASSERT(cb_instance >= 0);
5942305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5952305Sstevel 
5962305Sstevel 	if (cbp->fatal_problem)
5972305Sstevel 		return (B_FALSE);
5982305Sstevel 
5992305Sstevel 	if (cardbus_convert_properties(dip) == DDI_FAILURE)
6002305Sstevel 		return (B_FALSE);
6012305Sstevel 
6022305Sstevel 	number_of_cardbus_cards++;
6032305Sstevel 	devi->devi_ops->devo_bus_ops = &cardbusbus_ops;
6042305Sstevel 
6052305Sstevel #ifdef HOTPLUG
6062305Sstevel 	mutex_enter(&cbp->cb_mutex);
6072305Sstevel 	cbp->card_present = B_TRUE;
6082305Sstevel 
6092305Sstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6102305Sstevel 	    HPC_EVENT_SLOT_INSERTION, 0);
6112305Sstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6122305Sstevel 	    HPC_EVENT_SLOT_POWER_ON, 0);
6132305Sstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6142305Sstevel 	    HPC_EVENT_SLOT_CONFIGURE, 0);
6152305Sstevel 
6162305Sstevel 	mutex_exit(&cbp->cb_mutex);
6172305Sstevel #else
6182305Sstevel 	if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
6192305Sstevel #if defined(CARDBUS_DEBUG)
6202305Sstevel 		cardbus_err(dip, 6, "cardbus_configure failed\n");
6212305Sstevel #endif
6222305Sstevel 		return (B_FALSE);
6232305Sstevel 	}
6242305Sstevel 
6252305Sstevel 	ctrl.rv = NDI_SUCCESS;
6262305Sstevel 	ctrl.busno = cardbus_primary_busno(dip);
6272305Sstevel 	ctrl.op = PCICFG_OP_ONLINE;
6282305Sstevel 	ctrl.dip = NULL;
6292305Sstevel 	ctrl.flags = PCICFG_FLAGS_CONTINUE;
6302305Sstevel 
6312305Sstevel 	/*
6322305Sstevel 	 * The child of the dip is the cardbus dip. The child of the
6332305Sstevel 	 * cardbus dip is the device itself
6342305Sstevel 	 */
6352305Sstevel #if defined(CARDBUS_DEBUG)
6362305Sstevel 	cardbus_err(dip, 8, "cardbus_load_cardbus: calling cbus_configure\n");
6372305Sstevel #endif
6382305Sstevel 	ndi_devi_enter(dip, &circular_count);
6392305Sstevel 	ddi_walk_devs(ddi_get_child(dip), cbus_configure, (void *)&ctrl);
6402305Sstevel 	ndi_devi_exit(dip, circular_count);
6412305Sstevel 
6422305Sstevel 	if (ctrl.rv != NDI_SUCCESS) {
6432305Sstevel 		cardbus_err(dip, 1,
6442305Sstevel 		    "cardbus_load_cardbus (%s%d): failed to attach (%d)\n",
6452305Sstevel 		    ctrl.dip ? ddi_driver_name(ctrl.dip) : "Unknown",
6462305Sstevel 		    ctrl.dip ? ddi_get_instance(ctrl.dip) : 0,
6472305Sstevel 		    ctrl.rv);
6482305Sstevel 
6492305Sstevel 		/*
6502305Sstevel 		 * Returning error here will cause the pcic_load_cardbus() call
6512305Sstevel 		 * to fail. This will invoke pcic_unload_cardbus() which calls
6522305Sstevel 		 * cardbus_unload_cardbus() below.
6532305Sstevel 		 */
6542305Sstevel 		return (B_FALSE);
6552305Sstevel 	}
6562305Sstevel #endif
6572305Sstevel 
6582305Sstevel #if defined(CARDBUS_DEBUG)
6592305Sstevel 	cardbus_err(dip, 7, "cardbus_load_cardbus: returning TRUE\n");
6602305Sstevel #endif
6612305Sstevel 
6622305Sstevel 	return (B_TRUE);
6632305Sstevel }
6642305Sstevel 
6652305Sstevel /*
6662305Sstevel  * Unload the cardbus module
6672305Sstevel  */
6682305Sstevel void
cardbus_unload_cardbus(dev_info_t * dip)6692305Sstevel cardbus_unload_cardbus(dev_info_t *dip)
6702305Sstevel {
6712305Sstevel 	int	cb_instance;
6722305Sstevel #ifndef HOTPLUG
6732305Sstevel 	int	prim_bus = cardbus_primary_busno(dip);
6742305Sstevel 	int	rval;
6752305Sstevel #endif
6762305Sstevel 	cbus_t *cbp;
6772305Sstevel 
6782305Sstevel 	cardbus_err(dip, 6, "cardbus_unload_cardbus\n");
6792305Sstevel 
6802305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
6812305Sstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
6822305Sstevel 	ASSERT(cb_instance >= 0);
6832305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
6842305Sstevel 
6852305Sstevel 	if (number_of_cardbus_cards == 0)
6862305Sstevel 		return;
6872305Sstevel 
6882305Sstevel #ifdef HOTPLUG
6892305Sstevel 	mutex_enter(&cbp->cb_mutex);
6902305Sstevel 	cbp->card_present = B_FALSE;
6912305Sstevel 
6922305Sstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6932305Sstevel 	    HPC_EVENT_SLOT_POWER_OFF, 0);
6942305Sstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6952451Srw148561 	    HPC_EVENT_SLOT_UNCONFIGURE, 0);
6962451Srw148561 	(void) hpc_slot_event_notify(cbp->slot_handle,
6972305Sstevel 	    HPC_EVENT_SLOT_REMOVAL, 0);
6982305Sstevel 
6992305Sstevel 	mutex_exit(&cbp->cb_mutex);
7002305Sstevel #else
7012305Sstevel 
7022305Sstevel 	cardbus_err(dip, 8,
7032305Sstevel 	    "cardbus_unload_cardbus: calling cardbus_unconfigure_node\n");
7042305Sstevel 
7052305Sstevel 	rval = cardbus_unconfigure_node(dip, prim_bus, B_TRUE);
7062305Sstevel 
7072305Sstevel 	if (rval != NDI_SUCCESS) {
7082305Sstevel 		cardbus_err(dip, 4,
7092305Sstevel 		    "cardbus_unload_cardbus: "
7102305Sstevel 		    "cardbus_unconfigure_node failed\n");
7112305Sstevel 		number_of_cardbus_cards--;
7122305Sstevel 		cbp->fatal_problem = B_TRUE;
7132305Sstevel 		cmn_err(CE_WARN,
7142305Sstevel 		    "cardbus(%s%d): Failed to remove device tree: "
7152305Sstevel 		    "Slot disabled",
7162305Sstevel 		    ddi_get_name(dip), ddi_get_instance(dip));
7172305Sstevel 		return;
7182305Sstevel 	}
7192305Sstevel 
7202305Sstevel 	(void) cardbus_unconfigure(cbp);
7212305Sstevel #endif
7222305Sstevel 
7232305Sstevel 	/*
7242305Sstevel 	 * Inform the lower drivers that the card has been removed
7252305Sstevel 	 */
7262305Sstevel 	if (cbp->cb_ndi_event_hdl != NULL) {
7272305Sstevel 		ddi_eventcookie_t cookie;
7282305Sstevel 		if (ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, dip,
7292305Sstevel 		    DDI_DEVI_REMOVE_EVENT, &cookie, 0) == NDI_SUCCESS) {
7302305Sstevel 			(void) ndi_event_run_callbacks(cbp->cb_ndi_event_hdl,
7312305Sstevel 			    dip, cookie, NULL);
7322305Sstevel 		}
7332305Sstevel 	}
7342305Sstevel 
7352305Sstevel 	cardbus_revert_properties(dip);
7362305Sstevel }
7372305Sstevel 
7387151Srw148561 static boolean_t
is_32bit_pccard(dev_info_t * dip)7397151Srw148561 is_32bit_pccard(dev_info_t *dip)
7402305Sstevel {
7417151Srw148561 	int len;
7427151Srw148561 	char bus_type[16];
7437151Srw148561 
7447151Srw148561 	len = sizeof (bus_type);
7457151Srw148561 	if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7467151Srw148561 		PROP_LEN_AND_VAL_BUF,
7477151Srw148561 		DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
7487151Srw148561 		"device_type",
7497151Srw148561 		(caddr_t)&bus_type, &len) != DDI_SUCCESS)
7507151Srw148561 		return (B_FALSE);
7517151Srw148561 
7527151Srw148561 	if ((strcmp(bus_type, "pci") != 0) &&
7537151Srw148561 	    (strcmp(bus_type, "pciex") != 0) &&
7547151Srw148561 	    (strcmp(bus_type, "cardbus") != 0)) /* not of pci type */
7557151Srw148561 		return (B_FALSE);
7567151Srw148561 
7577151Srw148561 	return (B_TRUE);
7587151Srw148561 }
7592305Sstevel 
7607151Srw148561 void
cardbus_save_children(dev_info_t * dip)7617151Srw148561 cardbus_save_children(dev_info_t *dip)
7627151Srw148561 {
7637151Srw148561 	for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
7647151Srw148561 		cardbus_save_children(ddi_get_child(dip));
7657151Srw148561 
7667151Srw148561 		if (strcmp("pcs", ddi_node_name(dip)) == 0)
7677151Srw148561 			continue;
7687151Srw148561 		if (!is_32bit_pccard(dip))
7697151Srw148561 			continue;
7707151Srw148561 		cardbus_err(dip, 1, "Saving device\n");
7717151Srw148561 		(void) pci_save_config_regs(dip);
7727151Srw148561 	}
7737151Srw148561 
7747151Srw148561 }
7757151Srw148561 
7767151Srw148561 void
cardbus_restore_children(dev_info_t * dip)7777151Srw148561 cardbus_restore_children(dev_info_t *dip)
7787151Srw148561 {
7797151Srw148561 	for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
7807151Srw148561 		cardbus_restore_children(ddi_get_child(dip));
7817151Srw148561 
7827151Srw148561 		if (strcmp("pcs", ddi_node_name(dip)) == 0)
7837151Srw148561 			continue;
7847151Srw148561 		if (!is_32bit_pccard(dip))
7857151Srw148561 			continue;
7867151Srw148561 		cardbus_err(dip, 1, "restoring device\n");
7877151Srw148561 		(void) pci_restore_config_regs(dip);
7887151Srw148561 	}
7897151Srw148561 
7902305Sstevel }
7912305Sstevel 
7922305Sstevel static int
cardbus_convert_properties(dev_info_t * dip)7932305Sstevel cardbus_convert_properties(dev_info_t *dip)
7942305Sstevel {
7952305Sstevel 	struct pcm_regs *pcic_avail_p, *old_avail_p;
7962305Sstevel 	pci_regspec_t *cb_avail_p, *new_avail_p;
7972305Sstevel 	pcic_ranges_t *pcic_range_p, *old_range_p;
7982305Sstevel 	cardbus_range_t *cb_range_p, *new_range_p;
7992305Sstevel 	int range_len, range_entries, i;
8002305Sstevel 	int avail_len, avail_entries;
8012305Sstevel 
8022305Sstevel #if defined(CARDBUS_DEBUG)
8032305Sstevel 	cardbus_err(dip, 6, "cardbus_convert_properties\n");
8042305Sstevel #endif
8052305Sstevel 
8062305Sstevel 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8072305Sstevel 	    "#address-cells", 3) != DDI_SUCCESS) {
8082305Sstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8092305Sstevel 		    "failed to update #address-cells property\n");
8102305Sstevel 		return (DDI_FAILURE);
8112305Sstevel 	}
8122305Sstevel 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8132305Sstevel 	    "#size-cells", 2) != DDI_SUCCESS) {
8142305Sstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8152305Sstevel 		    "failed to update #size-cells property\n");
8162305Sstevel 		return (DDI_FAILURE);
8172305Sstevel 	}
8182305Sstevel 
8192305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "available",
8202305Sstevel 	    (caddr_t)&pcic_avail_p, &avail_len) != DDI_PROP_SUCCESS) {
8212305Sstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8222305Sstevel 		    "no available property for pcmcia\n");
8232305Sstevel 	} else {
8242305Sstevel 		avail_entries = avail_len / sizeof (struct pcm_regs);
8252305Sstevel 		cb_avail_p = kmem_alloc(sizeof (pci_regspec_t) * avail_entries,
8262305Sstevel 		    KM_SLEEP);
8272305Sstevel 
8282305Sstevel 		old_avail_p = pcic_avail_p;
8292305Sstevel 		new_avail_p = cb_avail_p;
8302305Sstevel 		for (i = 0; i < avail_entries;
8312305Sstevel 		    i++, old_avail_p++, new_avail_p++) {
8322305Sstevel 			new_avail_p->pci_phys_hi = old_avail_p->phys_hi;
8332305Sstevel 			new_avail_p->pci_phys_mid = 0;
8342305Sstevel 			new_avail_p->pci_phys_low = old_avail_p->phys_lo;
8352305Sstevel 			new_avail_p->pci_size_hi = 0;
8362305Sstevel 			new_avail_p->pci_size_low = old_avail_p->phys_len;
8372305Sstevel 		}
8382305Sstevel 
8392305Sstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
8402305Sstevel 		    "available",
8412305Sstevel 		    (int *)cb_avail_p,
8422305Sstevel 		    (sizeof (pci_regspec_t) * avail_entries)/sizeof (int));
8432305Sstevel 
8442305Sstevel 		kmem_free(pcic_avail_p, avail_len);
8452305Sstevel 		kmem_free(cb_avail_p, sizeof (pci_regspec_t) * avail_entries);
8462305Sstevel 	}
8472305Sstevel 
8482305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "ranges",
8492305Sstevel 	    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
8502305Sstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8512305Sstevel 		    "no ranges property for pcmcia\n");
8522305Sstevel 	} else {
8532305Sstevel 		range_entries = range_len / sizeof (pcic_ranges_t);
8542305Sstevel 		cb_range_p = kmem_alloc(
8552305Sstevel 		    sizeof (cardbus_range_t) * range_entries, KM_SLEEP);
8562305Sstevel 
8572305Sstevel 		old_range_p = pcic_range_p;
8582305Sstevel 		new_range_p = cb_range_p;
8592305Sstevel 		for (i = 0; i < range_entries;
8602305Sstevel 		    i++, old_range_p++, new_range_p++) {
8612305Sstevel 			new_range_p->child_hi =
8622305Sstevel 			    old_range_p->pcic_range_caddrhi;
8632305Sstevel 			new_range_p->child_mid = 0;
8642305Sstevel 			new_range_p->child_lo =
8652305Sstevel 			    old_range_p->pcic_range_caddrlo;
8662305Sstevel 			new_range_p->parent_hi =
8672305Sstevel 			    old_range_p->pcic_range_paddrhi;
8682305Sstevel 			new_range_p->parent_mid =
8692305Sstevel 			    old_range_p->pcic_range_paddrmid;
8702305Sstevel 			new_range_p->parent_lo =
8712305Sstevel 			    old_range_p->pcic_range_paddrlo;
8722305Sstevel 			new_range_p->size_hi = 0;
8732305Sstevel 			new_range_p->size_lo = old_range_p->pcic_range_size;
8742305Sstevel 		}
8752305Sstevel 
8762305Sstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
8772305Sstevel 		    (int *)cb_range_p,
8782305Sstevel 		    (sizeof (cardbus_range_t) * range_entries)/sizeof (int));
8792305Sstevel 
8802305Sstevel 		kmem_free(pcic_range_p, range_len);
8812305Sstevel 		kmem_free(cb_range_p, sizeof (cardbus_range_t) * range_entries);
8822305Sstevel 	}
8832305Sstevel 
8842305Sstevel 	return (DDI_SUCCESS);
8852305Sstevel }
8862305Sstevel 
8872305Sstevel static void
cardbus_revert_properties(dev_info_t * dip)8882305Sstevel cardbus_revert_properties(dev_info_t *dip)
8892305Sstevel {
8902305Sstevel #if defined(CARDBUS_DEBUG)
8912305Sstevel 	cardbus_err(dip, 6, "cardbus_revert_properties\n");
8922305Sstevel #endif
8932305Sstevel 
8942305Sstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#address-cells");
8952305Sstevel 
8962305Sstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#size-cells");
8972305Sstevel 
8982305Sstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
8992305Sstevel }
9002305Sstevel 
9012305Sstevel static int
cardbus_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)9022305Sstevel cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
9032305Sstevel 		ddi_prop_op_t prop_op, int mod_flags,
9042305Sstevel 		char *name, caddr_t valuep, int *lengthp)
9052305Sstevel {
9062305Sstevel #if defined(CARDBUS_DEBUG)
9072305Sstevel 	if ((ch_dip != dip) || (cardbus_debug >= 9))
9082305Sstevel 		cardbus_err(dip, 6,
9092305Sstevel 		    "cardbus_prop_op(%s) (dip=0x%p, op=%d, name=%s)\n",
9102305Sstevel 		    ddi_driver_name(ch_dip), (void *) dip, prop_op, name);
9112305Sstevel #endif
9122305Sstevel 	return (impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
9132305Sstevel 	    mod_flags, name, valuep, lengthp));
9142305Sstevel }
9152305Sstevel 
9162305Sstevel static int
cardbus_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)9172305Sstevel cardbus_ctlops(dev_info_t *dip, dev_info_t *rdip,
9182305Sstevel 	ddi_ctl_enum_t ctlop, void *arg, void *result)
9192305Sstevel {
9202305Sstevel 	pci_regspec_t *regs;
9212305Sstevel 	int	totreg, reglen;
9222305Sstevel 	const char	*dname = ddi_driver_name(dip);
9232305Sstevel 
9242305Sstevel 	ASSERT(number_of_cardbus_cards != 0);
9252305Sstevel 
9262305Sstevel 	cardbus_err(dip, 6,
9272305Sstevel 	    "cardbus_ctlops(%p, %p, %d, %p, %p)\n",
9282305Sstevel 	    (void *)dip, (void *)rdip, ctlop, (void *)arg, (void *)result);
9292305Sstevel 
9302305Sstevel 	switch (ctlop) {
9312305Sstevel 	case DDI_CTLOPS_UNINITCHILD:
9322305Sstevel 		cardbus_removechild((dev_info_t *)arg);
9332305Sstevel 		return (DDI_SUCCESS);
9347151Srw148561 	case DDI_CTLOPS_POWER:
9357151Srw148561 		return (DDI_SUCCESS);
9362305Sstevel 
9372305Sstevel 	default:
9382305Sstevel 		/*
9392305Sstevel 		 * Do Nothing
9402305Sstevel 		 */
9412305Sstevel 		cardbus_err(dip, 8,
9422305Sstevel 		    "cardbus_ctlops: Unsupported DDI_CTLOP %d\n", ctlop);
9432305Sstevel 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
9442305Sstevel 
9452305Sstevel 	case DDI_CTLOPS_SIDDEV:		/* see ddi_dev_is_sid(9F) */
9462305Sstevel 		return (DDI_SUCCESS);
9472305Sstevel 
9482305Sstevel 	case DDI_CTLOPS_SLAVEONLY:	/* see ddi_slaveonly(9F) */
9492305Sstevel 		return (DDI_FAILURE);	/* cardbus */
9502305Sstevel 
9512305Sstevel 	case DDI_CTLOPS_REGSIZE:
9522305Sstevel 	case DDI_CTLOPS_NREGS:
9532305Sstevel 		if (rdip == (dev_info_t *)NULL) {
9542305Sstevel 			*(int *)result = 0;
9552305Sstevel 			return (DDI_FAILURE);
9562305Sstevel 		}
9572305Sstevel 		break;
9582305Sstevel 
9592305Sstevel 	case DDI_CTLOPS_IOMIN:
9602305Sstevel 		/*
9612305Sstevel 		 * If we are using the streaming cache, align at
9622305Sstevel 		 * least on a cache line boundary. Otherwise use
9632305Sstevel 		 * whatever alignment is passed in.
9642305Sstevel 		 */
9652305Sstevel 
9662305Sstevel 		if (arg) {
9672305Sstevel 			int	val = *((int *)result);
9682305Sstevel 
9692305Sstevel #ifdef  PCI_SBUF_LINE_SIZE
9702305Sstevel 			val = maxbit(val, PCI_SBUF_LINE_SIZE);
9712305Sstevel #else
9722305Sstevel 			val = maxbit(val, 64);
9732305Sstevel #endif
9742305Sstevel 			*((int *)result) = val;
9752305Sstevel 		}
9762305Sstevel 		return (DDI_SUCCESS);
9772305Sstevel 
9782305Sstevel 	case DDI_CTLOPS_INITCHILD:
9792305Sstevel 		return (cardbus_initchild(rdip, dip, (dev_info_t *)arg,
980*7240Srh87107 		    result));
9812305Sstevel 
9822305Sstevel 	case DDI_CTLOPS_REPORTDEV:
9832305Sstevel 		if (rdip == (dev_info_t *)0)
9842305Sstevel 			return (DDI_FAILURE);
9852305Sstevel 
9862305Sstevel 		if (strcmp("pcs", ddi_node_name(rdip)) == 0)
9872305Sstevel 			cardbus_err(dip, 1,
9882305Sstevel 			    "cardbus_ctlops: PCCard socket %d at %s@%s\n",
9892305Sstevel 			    ddi_get_instance(rdip),
9902305Sstevel 			    dname, ddi_get_name_addr(dip));
9912305Sstevel 		else {
9922305Sstevel 			pci_regspec_t *pci_rp;
9932305Sstevel 			dev_info_t *next;
9942305Sstevel 			int	length;
9952305Sstevel 
9962305Sstevel 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
9972305Sstevel 			    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
9982305Sstevel 			    (uint_t *)&length) != DDI_PROP_SUCCESS)
9992305Sstevel 				return (DDI_FAILURE);
10002305Sstevel 
10012305Sstevel 			if (pci_rp->pci_phys_hi == 0)
10022305Sstevel 				cardbus_err(dip, 1, "%s%d at %s@%s\n",
10032305Sstevel 				    ddi_driver_name(rdip),
10042305Sstevel 				    ddi_get_instance(rdip),
10052305Sstevel 				    dname, ddi_get_name_addr(dip));
10062305Sstevel 			else {
10072305Sstevel 				uint8_t bus, device, function;
10082305Sstevel 				int32_t val32;
10092305Sstevel 				char	*ptr, buf[128];
10102305Sstevel 
10112305Sstevel 				bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
10122305Sstevel 				device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
10132305Sstevel 				function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
10142305Sstevel 
10152305Sstevel 				ptr = buf;
10162305Sstevel 				(void) sprintf(ptr, "  "
10172305Sstevel 				    "Bus %3d Device %2d Function %2d",
10182305Sstevel 				    bus, device, function);
10192305Sstevel 				ptr = &ptr[strlen(ptr)];
10202305Sstevel 
10212305Sstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10222305Sstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10232305Sstevel 				    "vendor-id", -1);
10242305Sstevel 				if (val32 != -1) {
10252305Sstevel 					(void) sprintf(ptr, " Vendor 0x%04x",
10262305Sstevel 					    val32);
10272305Sstevel 					ptr = &ptr[strlen(ptr)];
10282305Sstevel 				}
10292305Sstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10302305Sstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10312305Sstevel 				    "device-id", -1);
10322305Sstevel 				if (val32 != -1) {
10332305Sstevel 					(void) sprintf(ptr, " Device 0x%04x",
10342305Sstevel 					    val32);
10352305Sstevel 					ptr = &ptr[strlen(ptr)];
10362305Sstevel 				}
10372305Sstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10382305Sstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10392305Sstevel 				    "class-code", -1);
10402305Sstevel 				if (val32 != -1) {
10412305Sstevel 					const char	*name;
10422305Sstevel 
10432305Sstevel 					if ((name = ddi_get_name(rdip)) !=
10442305Sstevel 					    NULL)
10452305Sstevel 						(void) sprintf(ptr, " Name %s",
10462305Sstevel 						    name);
10472305Sstevel 					else
10482305Sstevel 						(void) sprintf(ptr,
10492305Sstevel 						    " Class 0x%x", val32 >> 8);
10502305Sstevel 					ptr = &ptr[strlen(ptr)];
10512305Sstevel 				}
10522305Sstevel 
10532305Sstevel 				*ptr++ = '\n';
10542305Sstevel 				ASSERT(((caddr_t)ptr - (caddr_t)buf) <
1055*7240Srh87107 				    sizeof (buf));
10562305Sstevel 				*ptr = '\0';
10572305Sstevel 
10582305Sstevel 				cardbus_err(dip, 1, buf);
10592305Sstevel 			}
10602305Sstevel 			ddi_prop_free(pci_rp);
10612305Sstevel 
10622305Sstevel 			for (next = ddi_get_child(rdip); next;
10632305Sstevel 			    next = ddi_get_next_sibling(next))
10642305Sstevel 				(void) cardbus_ctlops(next, next,
10652305Sstevel 				    DDI_CTLOPS_REPORTDEV, arg, result);
10662305Sstevel 		}
10672305Sstevel 		return (DDI_SUCCESS);
10682305Sstevel 	}
10692305Sstevel 	*(int *)result = 0;
10702305Sstevel 
10712305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip,
10722305Sstevel 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
10732305Sstevel 	    (caddr_t)&regs, &reglen) != DDI_SUCCESS)
10742305Sstevel 		return (DDI_FAILURE);
10752305Sstevel 
10762305Sstevel 	totreg = reglen / sizeof (pci_regspec_t);
10772305Sstevel 	if (ctlop == DDI_CTLOPS_NREGS) {
10782305Sstevel 		cardbus_err(dip, 6,
10792305Sstevel 		    "cardbus_ctlops, returning NREGS = %d\n", totreg);
10802305Sstevel 		*(int *)result = totreg;
10812305Sstevel 	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
10822305Sstevel 		const int	rn = *(int *)arg;
10832305Sstevel 		if (rn > totreg)
10842305Sstevel 			return (DDI_FAILURE);
10852305Sstevel 		cardbus_err(dip, 6,
10862305Sstevel 		    "cardbus_ctlops, returning REGSIZE(%d) = %d\n",
10872305Sstevel 		    rn, regs[rn].pci_size_low);
10882305Sstevel 		*(off_t *)result = regs[rn].pci_size_low;
10892305Sstevel 	}
10902305Sstevel 	kmem_free(regs, reglen);
10912305Sstevel 	return (DDI_SUCCESS);
10922305Sstevel }
10932305Sstevel 
10942305Sstevel static void
cardbus_init_child_regs(dev_info_t * child)10952305Sstevel cardbus_init_child_regs(dev_info_t *child)
10962305Sstevel {
10972305Sstevel 	ddi_acc_handle_t config_handle;
10982305Sstevel 	uint16_t command_preserve, command;
10992305Sstevel #if !defined(__i386) && !defined(__amd64)
11002305Sstevel 	uint8_t bcr;
11012305Sstevel #endif
11022305Sstevel 	uint8_t header_type;
11032305Sstevel 	uint8_t min_gnt, latency_timer;
11042305Sstevel 	uint_t n;
11052305Sstevel 
11062305Sstevel 	/*
11072305Sstevel 	 * Map the child configuration space to for initialization.
11082305Sstevel 	 *
11092305Sstevel 	 *  Set the latency-timer register to values appropriate
11102305Sstevel 	 *  for the devices on the bus (based on other devices
11112305Sstevel 	 *  MIN_GNT and MAX_LAT registers.
11122305Sstevel 	 *
11132305Sstevel 	 *  Set the fast back-to-back enable bit in the command
11142305Sstevel 	 *  register if it's supported and all devices on the bus
11152305Sstevel 	 *  have the capability.
11162305Sstevel 	 *
11172305Sstevel 	 */
11182305Sstevel 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
11192305Sstevel 		return;
11202305Sstevel 
11212305Sstevel 	cardbus_err(child, 6, "cardbus_init_child_regs()\n");
11222305Sstevel 
11232305Sstevel 	/*
11242305Sstevel 	 * Determine the configuration header type.
11252305Sstevel 	 */
11262305Sstevel 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
11272305Sstevel 
11282305Sstevel 	/*
11292305Sstevel 	 * Support for "command-preserve" property.  Note that we
11302305Sstevel 	 * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
11312305Sstevel 	 * since the obp will set this if the device supports and
11322305Sstevel 	 * all targets on the same bus support it.  Since psycho
11332305Sstevel 	 * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
11342305Sstevel 	 * be set.  This is just here in case future revs do support
11352305Sstevel 	 * PCI_COMM_BACK2BACK_ENAB.
11362305Sstevel 	 */
11372305Sstevel 	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
11382305Sstevel 	    DDI_PROP_DONTPASS,
11392305Sstevel 	    "command-preserve", 0);
11402305Sstevel 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
11412305Sstevel 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
11422305Sstevel 	command |= (cardbus_command_default & ~command_preserve);
11432305Sstevel 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
11442305Sstevel 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
11452305Sstevel 
11462305Sstevel #if !defined(__i386) && !defined(__amd64)
11472305Sstevel 	/*
11482305Sstevel 	 * If the device has a bus control register then program it
11492305Sstevel 	 * based on the settings in the command register.
11502305Sstevel 	 */
11512305Sstevel 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11522305Sstevel 		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
11532305Sstevel 		if (cardbus_command_default & PCI_COMM_PARITY_DETECT)
11542305Sstevel 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
11552305Sstevel 		if (cardbus_command_default & PCI_COMM_SERR_ENABLE)
11562305Sstevel 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
11572305Sstevel 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
11582305Sstevel 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
11592305Sstevel 	}
11602305Sstevel #endif
11612305Sstevel 
11622305Sstevel 	/*
11632305Sstevel 	 * Initialize cache-line-size configuration register if needed.
11642305Sstevel 	 */
11652305Sstevel 	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11662305Sstevel 	    "cache-line-size", 0) == 0) {
11672305Sstevel 
11682305Sstevel 		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
11692305Sstevel 		    PCI_CACHE_LINE_SIZE);
11702305Sstevel 		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
11712305Sstevel 		if (n != 0)
11722305Sstevel 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
1173*7240Srh87107 			    "cache-line-size", n);
11742305Sstevel 	}
11752305Sstevel 
11762305Sstevel 	/*
11772305Sstevel 	 * Initialize latency timer registers if needed.
11782305Sstevel 	 */
11792305Sstevel 	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11802305Sstevel 	    "latency-timer", 0) == 0) {
11812305Sstevel 
11822305Sstevel 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11832305Sstevel 			latency_timer = cardbus_latency_timer;
11842305Sstevel 			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
1185*7240Srh87107 			    latency_timer);
11862305Sstevel 		} else {
11872305Sstevel 			min_gnt = pci_config_get8(config_handle,
1188*7240Srh87107 			    PCI_CONF_MIN_G);
11892305Sstevel 
11902305Sstevel 			/*
11912305Sstevel 			 * Cardbus os only 33Mhz
11922305Sstevel 			 */
11932305Sstevel 			if (min_gnt != 0) {
11942305Sstevel 				latency_timer = min_gnt * 8;
11952305Sstevel 			}
11962305Sstevel 		}
11972305Sstevel 		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
1198*7240Srh87107 		    latency_timer);
11992305Sstevel 		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
12002305Sstevel 		if (n != 0)
12012305Sstevel 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
1202*7240Srh87107 			"latency-timer", n);
12032305Sstevel 	}
12042305Sstevel 
12052305Sstevel 	pci_config_teardown(&config_handle);
12062305Sstevel }
12072305Sstevel 
12082305Sstevel static int
cardbus_initchild(dev_info_t * rdip,dev_info_t * dip,dev_info_t * child,void * result)12092305Sstevel cardbus_initchild(dev_info_t *rdip, dev_info_t *dip, dev_info_t *child,
12102305Sstevel 		void *result)
12112305Sstevel {
12122305Sstevel 	char	name[MAXNAMELEN];
12132305Sstevel 	const char	*dname = ddi_driver_name(dip);
12142305Sstevel 	const struct cb_ops *cop;
12152305Sstevel 
12162305Sstevel 	_NOTE(ARGUNUSED(rdip, result))
12172305Sstevel 
12182305Sstevel 	cardbus_err(child, 6, "cardbus_initchild\n");
12192305Sstevel 
12202305Sstevel 	/*
12212305Sstevel 	 * Name the child
12222305Sstevel 	 */
12232305Sstevel 	if (cardbus_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
12242305Sstevel 		return (DDI_FAILURE);
12252305Sstevel 
12262305Sstevel 	ddi_set_name_addr(child, name);
12272305Sstevel 	ddi_set_parent_data(child, NULL);
12282305Sstevel 
12292305Sstevel 	if (ndi_dev_is_persistent_node(child) == 0) {
12302305Sstevel 		/*
12312305Sstevel 		 * Try to merge the properties from this prototype
12322305Sstevel 		 * node into real h/w nodes.
12332305Sstevel 		 */
12342305Sstevel 		if (ndi_merge_node(child, cardbus_name_child) == DDI_SUCCESS) {
12352305Sstevel 			/*
12362305Sstevel 			 * Merged ok - return failure to remove the node.
12372305Sstevel 			 */
12382305Sstevel 			cardbus_removechild(child);
12392305Sstevel 			return (DDI_FAILURE);
12402305Sstevel 		}
12412305Sstevel 		/*
12422305Sstevel 		 * The child was not merged into a h/w node,
12432305Sstevel 		 * but there's not much we can do with it other
12442305Sstevel 		 * than return failure to cause the node to be removed.
12452305Sstevel 		 */
12462305Sstevel 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
12472305Sstevel 		    ddi_driver_name(child), ddi_get_name_addr(child),
12482305Sstevel 		    ddi_driver_name(child));
12492305Sstevel 		cardbus_removechild(child);
12502305Sstevel 		return (DDI_NOT_WELL_FORMED);
12512305Sstevel 	}
12522305Sstevel 	cop = DEVI(dip)->devi_ops->devo_cb_ops;
12532305Sstevel 
12542305Sstevel 	if ((cop == NULL) || (!(cop->cb_flag & D_HOTPLUG))) {
12552305Sstevel 		cmn_err(CE_WARN, "%s: driver doesn't support HOTPLUG\n", dname);
12562305Sstevel 		return (DDI_FAILURE);
12572305Sstevel 	}
12582305Sstevel 
12592305Sstevel 	cardbus_init_child_regs(child);
12602305Sstevel 
12612305Sstevel 	/*
12622305Sstevel 	 * Create ppd if needed.
12632305Sstevel 	 */
12642305Sstevel 	if (ddi_get_parent_data(child) == NULL) {
12652305Sstevel 		struct cardbus_parent_private_data *ppd;
12662305Sstevel 
12672305Sstevel #ifdef sparc
12682305Sstevel 		ppd = (struct cardbus_parent_private_data *)
1269*7240Srh87107 		    kmem_zalloc(sizeof (struct cardbus_parent_private_data),
12702305Sstevel 		    KM_SLEEP);
12712305Sstevel 
12722305Sstevel #elif defined(__x86) || defined(__amd64)
12732305Sstevel 		ppd = (struct cardbus_parent_private_data *)
12742305Sstevel 		    kmem_zalloc(sizeof (struct cardbus_parent_private_data)
1275*7240Srh87107 		    + sizeof (struct intrspec), KM_SLEEP);
12762305Sstevel 
12772305Sstevel 		ppd->ppd.par_intr = (struct intrspec *)(ppd + 1);
12782305Sstevel 		(ppd->ppd.par_intr)->intrspec_pri = 0;
12792305Sstevel 		(ppd->ppd.par_intr)->intrspec_vec = 0;
12802305Sstevel 		(ppd->ppd.par_intr)->intrspec_func = (uint_t (*)()) 0;
12812305Sstevel #endif
12822305Sstevel 
12832305Sstevel 		if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
12842305Sstevel 		    "interrupts", -1) != -1)
12852305Sstevel 			ppd->ppd.par_nintr = 1;
12862305Sstevel 
12872305Sstevel 		ppd->code = CB_PPD_CODE;
12882305Sstevel 
12892305Sstevel 		cardbus_err(child, 5,
12902305Sstevel 		    "cardbus_initchild: Creating empty ppd\n");
12912305Sstevel 		ppd->ppd.par_nreg = 0;
12922305Sstevel 		ppd->ppd.par_reg = NULL;
12932305Sstevel 
12942305Sstevel 		ddi_set_parent_data(child, (caddr_t)ppd);
12952305Sstevel 	}
12962305Sstevel 
12972305Sstevel 	return (DDI_SUCCESS);
12982305Sstevel }
12992305Sstevel 
13002305Sstevel static int
cardbus_name_child(dev_info_t * child,char * name,int namelen)13012305Sstevel cardbus_name_child(dev_info_t *child, char *name, int namelen)
13022305Sstevel {
13032305Sstevel 	pci_regspec_t *pci_rp;
13042305Sstevel 	char	**unit_addr;
13052305Sstevel 	uint_t n;
13062305Sstevel 	int	bus, device, func;
13072305Sstevel 
13082305Sstevel 	/*
13092305Sstevel 	 * Pseudo nodes indicate a prototype node with per-instance
13102305Sstevel 	 * properties to be merged into the real h/w device node.
13112305Sstevel 	 * The interpretation of the unit-address is DD[,F]
13122305Sstevel 	 * where DD is the device id and F is the function.
13132305Sstevel 	 */
13142305Sstevel 	if (ndi_dev_is_persistent_node(child) == 0) {
13152305Sstevel 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
13162305Sstevel 		    DDI_PROP_DONTPASS,
13172305Sstevel 		    "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) {
13182305Sstevel 			cmn_err(CE_WARN, "cannot name node from %s.conf",
13192305Sstevel 			    ddi_driver_name(child));
13202305Sstevel 			return (DDI_FAILURE);
13212305Sstevel 		}
13222305Sstevel 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
13232305Sstevel 			cmn_err(CE_WARN, "unit-address property in %s.conf"
13242305Sstevel 			    " not well-formed", ddi_driver_name(child));
13252305Sstevel 			ddi_prop_free(unit_addr);
13262305Sstevel 			return (DDI_FAILURE);
13272305Sstevel 		}
13282305Sstevel 		(void) snprintf(name, namelen, "%s", *unit_addr);
13292305Sstevel 		ddi_prop_free(unit_addr);
13302305Sstevel 		return (DDI_SUCCESS);
13312305Sstevel 	}
13322305Sstevel 
13332305Sstevel 	/*
13342305Sstevel 	 * Get the address portion of the node name based on
13352305Sstevel 	 * the function and device number.
13362305Sstevel 	 */
13372305Sstevel 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
13382305Sstevel 	    "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
13392305Sstevel 		return (DDI_FAILURE);
13402305Sstevel 	}
13412305Sstevel 
13422305Sstevel 	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
13432305Sstevel 	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
13442305Sstevel 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
13452305Sstevel 	ddi_prop_free(pci_rp);
13462305Sstevel 
13472305Sstevel 	if (func != 0)
13482305Sstevel 		(void) snprintf(name, namelen, "%x,%x", device, func);
13492305Sstevel 	else
13502305Sstevel 		(void) snprintf(name, namelen, "%x", device);
13512305Sstevel 
13522305Sstevel 	cardbus_err(child, 8,
13532305Sstevel 	    "cardbus_name_child: system init done [%x][%x][%x]"
13542305Sstevel 	    " for %s [%s] nodeid: %x @%s\n",
13552305Sstevel 	    bus, device, func,
13562305Sstevel 	    ddi_get_name(child), ddi_get_name_addr(child),
13572305Sstevel 	    DEVI(child)->devi_nodeid, name);
13582305Sstevel 
13592305Sstevel 	return (DDI_SUCCESS);
13602305Sstevel }
13612305Sstevel 
13622305Sstevel static void
cardbus_removechild(dev_info_t * dip)13632305Sstevel cardbus_removechild(dev_info_t *dip)
13642305Sstevel {
13652305Sstevel 	struct cardbus_parent_private_data *ppd;
13662305Sstevel 
13672305Sstevel 	ddi_set_name_addr(dip, NULL);
13682305Sstevel 	impl_rem_dev_props(dip);
13692305Sstevel 	ppd = (struct cardbus_parent_private_data *)ddi_get_parent_data(dip);
13702305Sstevel 	if (ppd && (ppd->code == CB_PPD_CODE)) {
13712305Sstevel 		if (ppd->ppd.par_reg && (ppd->ppd.par_nreg > 0))
13722305Sstevel 			kmem_free((caddr_t)ppd->ppd.par_reg,
13732305Sstevel 			    ppd->ppd.par_nreg * sizeof (struct regspec));
13742305Sstevel #ifdef sparc
13752305Sstevel 		kmem_free(ppd, sizeof (struct cardbus_parent_private_data));
13762305Sstevel #elif defined(__x86) || defined(__amd64)
13772305Sstevel 		kmem_free(ppd, sizeof (struct cardbus_parent_private_data) +
13782305Sstevel 		    sizeof (struct intrspec));
13792305Sstevel #endif
13802305Sstevel 		cardbus_err(dip, 5,
13812305Sstevel 		    "cardbus_removechild: ddi_set_parent_data(NULL)\n");
13822305Sstevel 		ddi_set_parent_data(dip, NULL);
13832305Sstevel 	}
13842305Sstevel }
13852305Sstevel 
13862305Sstevel 
13872305Sstevel static char	cb_bnamestr[] = "binding_name";
13882305Sstevel static char	cb_venidstr[] = "VendorID";
13892305Sstevel static char	cb_devidstr[] = "DeviceID";
13902305Sstevel static char	cb_nnamestr[] = "nodename";
13912305Sstevel 
13922305Sstevel static cb_props_parse_tree_t cb_props_parse_tree[] = {
13932305Sstevel 	{ cb_bnamestr, PT_STATE_STRING_VAR },
13942305Sstevel 	{ cb_venidstr, PT_STATE_HEX_VAR },
13952305Sstevel 	{ cb_devidstr, PT_STATE_HEX_VAR } };
13962305Sstevel 
13972305Sstevel static int
check_token(char * token,int * len)13982305Sstevel check_token(char *token, int *len)
13992305Sstevel {
14002305Sstevel 	int	state = PT_STATE_DEC_VAR;
14012305Sstevel 	int	sl = strlen(token), il = 1;
14022305Sstevel 	char	c;
14032305Sstevel 
14042305Sstevel 	if (token[0] == '0' && token[2] && (token[1] == 'x' || token[1] ==
14052305Sstevel 	    'X')) {
14062305Sstevel 		state = PT_STATE_HEX_VAR;
14072305Sstevel 		token += 2;
14082305Sstevel 	}
14092305Sstevel 
14102305Sstevel 	while (c = *token++) {
14112305Sstevel 		if (isdigit(c))
14122305Sstevel 			continue;
14132305Sstevel 		if (c == PARSE_COMMA) {
14142305Sstevel 			il++;
14152305Sstevel 			if (token[0] == '0' && token[2] && isx(token[1])) {
14162305Sstevel 				state = PT_STATE_HEX_VAR;
14172305Sstevel 				token += 2;
14182305Sstevel 			}
14192305Sstevel 			continue;
14202305Sstevel 		}
14212305Sstevel 		if (!isxdigit(c)) {
14222305Sstevel 			*len = sl;
14232305Sstevel 			return (PT_STATE_STRING_VAR);
14242305Sstevel 		}
14252305Sstevel 		state = PT_STATE_HEX_VAR;
14262305Sstevel 	}
14272305Sstevel 	*len = il;
14282305Sstevel 	return (state);
14292305Sstevel }
14302305Sstevel 
14312305Sstevel 
14322305Sstevel static char *
find_token(char ** cp,int * l,char * endc)14332305Sstevel find_token(char **cp, int *l, char *endc)
14342305Sstevel {
14352305Sstevel 	char	*cpp = *cp;
14362305Sstevel 
14372305Sstevel 	while ((**cp && (isalpha(**cp) || isxdigit(**cp) ||
14382305Sstevel 	    (**cp == PARSE_UNDERSCORE) ||
14392305Sstevel 	    (**cp == PARSE_COMMA) ||
14402305Sstevel 	    (**cp == PARSE_DASH)))) {
14412305Sstevel 		(*cp)++;
14422305Sstevel 		(*l)++;
14432305Sstevel 	}
14442305Sstevel 
14452305Sstevel 	*endc = **cp;
14462305Sstevel 	**cp = NULL;
14472305Sstevel 
14482305Sstevel 	return (cpp);
14492305Sstevel }
14502305Sstevel 
14512305Sstevel static int
parse_token(char * token)14522305Sstevel parse_token(char *token)
14532305Sstevel {
14542305Sstevel 	cb_props_parse_tree_t *pt = cb_props_parse_tree;
14552305Sstevel 	int	k = sizeof (cb_props_parse_tree) /
14562305Sstevel 	    sizeof (cb_props_parse_tree_t);
14572305Sstevel 
14582305Sstevel 	while (k--) {
14592305Sstevel 		if (strcmp((char *)token, pt->token) == 0)
14602305Sstevel 			return (pt->state);
14612305Sstevel 		pt++;
14622305Sstevel 	}
14632305Sstevel 
14642305Sstevel 	return (PT_STATE_UNKNOWN);
14652305Sstevel }
14662305Sstevel 
14672305Sstevel static int
token_to_hex(char * token,unsigned * val,int len)14682305Sstevel token_to_hex(char *token, unsigned *val, int len)
14692305Sstevel {
14702305Sstevel 	uchar_t c;
14712305Sstevel 
14722305Sstevel 	*val = 0;
14732305Sstevel 	if (token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) {
14742305Sstevel 		token += 2;
14752305Sstevel 	}
14762305Sstevel 
14772305Sstevel 	while (*token) {
14782305Sstevel 		if (!isxdigit(*token)) {
14792305Sstevel 			if (*token == PARSE_COMMA) {
14802305Sstevel 				if (!(--len))
14812305Sstevel 					return (1);
14822305Sstevel 				val++;
14832305Sstevel 				*val = 0;
14842305Sstevel 				token++;
14852305Sstevel 				if (token[0] == '0' && (token[1] == 'x' ||
14862305Sstevel 				    token[1] == 'X')) {
14872305Sstevel 					token += 2;
14882305Sstevel 				}
14892305Sstevel 				continue;
14902305Sstevel 			}
14912305Sstevel 			return (0);
14922305Sstevel 		}
14932305Sstevel 		c = toupper(*token);
14942305Sstevel 		if (c >= 'A')
14952305Sstevel 			c = c - 'A' + 10 + '0';
14962305Sstevel 		*val = ((*val * 16) + (c - '0'));
14972305Sstevel 		token++;
14982305Sstevel 	}
14992305Sstevel 
15002305Sstevel 	return (1);
15012305Sstevel }
15022305Sstevel 
15032305Sstevel static int
token_to_dec(char * token,unsigned * val,int len)15042305Sstevel token_to_dec(char *token, unsigned *val, int len)
15052305Sstevel {
15062305Sstevel 	*val = 0;
15072305Sstevel 
15082305Sstevel 	while (*token) {
15092305Sstevel 		if (!isdigit(*token)) {
15102305Sstevel 			if (*token == PARSE_COMMA) {
15112305Sstevel 				if (!(--len))
15122305Sstevel 					return (1);
15132305Sstevel 				val++;
15142305Sstevel 				*val = 0;
15152305Sstevel 				token++;
15162305Sstevel 				continue;
15172305Sstevel 			}
15182305Sstevel 			return (0);
15192305Sstevel 		}
15202305Sstevel 		*val = ((*val * 10) + (*token - '0'));
15212305Sstevel 		token++;
15222305Sstevel 	}
15232305Sstevel 
15242305Sstevel 	return (1);
15252305Sstevel }
15262305Sstevel 
15272305Sstevel static void
cardbus_add_prop(struct cb_deviceset_props * cdsp,int type,char * name,caddr_t vp,int len)15282305Sstevel cardbus_add_prop(struct cb_deviceset_props *cdsp, int type, char *name,
15292305Sstevel 		caddr_t vp, int len)
15302305Sstevel {
15312305Sstevel 	ddi_prop_t *propp;
15322305Sstevel 	int	pnlen = strlen(name) + 1;
15332305Sstevel 
15342305Sstevel 	propp = (ddi_prop_t *)kmem_zalloc(sizeof (ddi_prop_t), KM_SLEEP);
15352305Sstevel 	propp->prop_name = (char *)kmem_alloc(pnlen, KM_SLEEP);
15362305Sstevel 	propp->prop_val = vp;
15372305Sstevel 	bcopy(name, propp->prop_name, pnlen);
15382305Sstevel 	propp->prop_len = len;
15392305Sstevel 	propp->prop_flags = type;
15402305Sstevel 	propp->prop_next = cdsp->prop_list;
15412305Sstevel 	cdsp->prop_list = propp;
15422305Sstevel }
15432305Sstevel 
15442305Sstevel static void
cardbus_add_stringprop(struct cb_deviceset_props * cdsp,char * name,char * vp,int len)15452305Sstevel cardbus_add_stringprop(struct cb_deviceset_props *cdsp, char *name,
15462305Sstevel 		char *vp, int len)
15472305Sstevel {
15482305Sstevel 	char	*nstr = kmem_zalloc(len + 1, KM_SLEEP);
15492305Sstevel 
15502305Sstevel 	bcopy(vp, nstr, len);
15512305Sstevel 	cardbus_add_prop(cdsp, DDI_PROP_TYPE_STRING, name, (caddr_t)nstr,
15522305Sstevel 	    len + 1);
15532305Sstevel }
15542305Sstevel 
15552305Sstevel static void
cardbus_prop_free(ddi_prop_t * propp)15562305Sstevel cardbus_prop_free(ddi_prop_t *propp)
15572305Sstevel {
15582305Sstevel 	if (propp->prop_len) {
15592305Sstevel 		switch (propp->prop_flags) {
15602305Sstevel 		case DDI_PROP_TYPE_STRING:
15612305Sstevel 			kmem_free(propp->prop_val, propp->prop_len);
15622305Sstevel 			break;
15632305Sstevel 		case DDI_PROP_TYPE_INT:
15642305Sstevel 			kmem_free(propp->prop_val,
15652305Sstevel 			    propp->prop_len * sizeof (int));
15662305Sstevel 			break;
15672305Sstevel 		}
15682305Sstevel 	}
15692305Sstevel 	kmem_free(propp->prop_name, strlen(propp->prop_name) + 1);
15702305Sstevel 	kmem_free(propp, sizeof (ddi_prop_t *));
15712305Sstevel }
15722305Sstevel 
15732305Sstevel static void
cardbus_devprops_free(struct cb_deviceset_props * cbdp)15742305Sstevel cardbus_devprops_free(struct cb_deviceset_props *cbdp)
15752305Sstevel {
15762305Sstevel 	ddi_prop_t *propp, *npropp;
15772305Sstevel 
15782305Sstevel 	propp = cbdp->prop_list;
15792305Sstevel 	while (propp) {
15802305Sstevel 		npropp = propp->prop_next;
15812305Sstevel 		cardbus_prop_free(propp);
15822305Sstevel 		propp = npropp;
15832305Sstevel 	}
15842305Sstevel 	if (cbdp->nodename)
15852305Sstevel 		kmem_free(cbdp->nodename, strlen(cbdp->nodename) + 1);
15862305Sstevel 	if (cbdp->binding_name)
15872305Sstevel 		kmem_free(cbdp->binding_name, strlen(cbdp->binding_name) +
15882305Sstevel 		    1);
15892305Sstevel 	kmem_free(cbdp, sizeof (*cbdp));
15902305Sstevel }
15912305Sstevel 
15922305Sstevel /*
15932305Sstevel  * Format of "cb-device-init-props" property:
15942305Sstevel  * Anything before the semi-colon is an identifying equate, anything
15952305Sstevel  * after the semi-colon is a setting equate.
15962305Sstevel  *
15972305Sstevel  * "binding_name=xXxXxX VendorID=NNNN DeviceID=NNNN; nodename=NewName
15982305Sstevel  * 					Prop=PropVal"
15992305Sstevel  *
16002305Sstevel  */
16012305Sstevel static int
cardbus_parse_devprop(cbus_t * cbp,char * cp)16022305Sstevel cardbus_parse_devprop(cbus_t *cbp, char *cp)
16032305Sstevel {
16042305Sstevel 	int	state = PT_STATE_TOKEN, qm = 0, em = 0, smc = 0, l = 0;
16052305Sstevel 	int	length;
16062305Sstevel 	char	*token = "beginning of line";
16072305Sstevel 	char	*ptoken = NULL, *quote;
16082305Sstevel 	char	eq = NULL;
16092305Sstevel 	struct cb_deviceset_props *cdsp;
16102305Sstevel 
16112305Sstevel 	cdsp = (struct cb_deviceset_props *)kmem_zalloc(sizeof (*cdsp),
16122305Sstevel 	    KM_SLEEP);
16132305Sstevel 	length = strlen(cp);
16142305Sstevel 
16152305Sstevel 	while ((*cp) && (l < length)) {
16162305Sstevel 		/*
16172305Sstevel 		 * Check for escaped characters
16182305Sstevel 		 */
16192305Sstevel 		if (*cp == PARSE_ESCAPE) {
16202305Sstevel 			char	*cpp = cp, *cppp = cp + 1;
16212305Sstevel 
16222305Sstevel 			em = 1;
16232305Sstevel 
16242305Sstevel 			if (!qm) {
16252305Sstevel 				cmn_err(CE_CONT, "cardbus_parse_devprop: "
16262305Sstevel 				    "escape not allowed outside "
16272305Sstevel 				    "of quotes at [%s]\n", token);
16282305Sstevel 				return (DDI_FAILURE);
16292305Sstevel 
16302305Sstevel 			} /* if (!qm) */
16312305Sstevel 
16322305Sstevel 			while (*cppp)
16332305Sstevel 				*cpp++ = *cppp++;
16342305Sstevel 
16352305Sstevel 			l++;
16362305Sstevel 
16372305Sstevel 			*cpp = NULL;
16382305Sstevel 		} /* PARSE_ESCAPE */
16392305Sstevel 
16402305Sstevel 		/*
16412305Sstevel 		 * Check for quoted strings
16422305Sstevel 		 */
16432305Sstevel 		if (!em && (*cp == PARSE_QUOTE)) {
16442305Sstevel 			qm ^= 1;
16452305Sstevel 			if (qm) {
16462305Sstevel 				quote = cp + 1;
16472305Sstevel 			} else {
16482305Sstevel 				*cp = NULL;
16492305Sstevel 				if (state == PT_STATE_CHECK) {
16502305Sstevel 					if (strcmp(token, cb_nnamestr) == 0) {
16512305Sstevel 						cdsp->nodename = kmem_alloc(
16522305Sstevel 						    strlen(quote) + 1,
16532305Sstevel 						    KM_SLEEP);
16542305Sstevel 						(void) strcpy(cdsp->nodename,
16552305Sstevel 						    quote);
16562305Sstevel 					} else
16572305Sstevel 						cardbus_add_stringprop(cdsp,
16582305Sstevel 						    token, quote,
16592305Sstevel 						    strlen(quote));
16602305Sstevel 				} else if (state != PT_STATE_STRING_VAR) {
16612305Sstevel 					cmn_err(CE_CONT,
16622305Sstevel 					    "cardbus_parse_devprop: "
16632305Sstevel 					    "unexpected string [%s] after "
16642305Sstevel 					    "[%s]\n", quote, token);
16652305Sstevel 					return (DDI_FAILURE);
16662305Sstevel 				} else {
16672305Sstevel 					if (strcmp(token, cb_bnamestr) == 0) {
16682305Sstevel 						cdsp->binding_name = kmem_alloc(
16692305Sstevel 						    strlen(quote) + 1,
16702305Sstevel 						    KM_SLEEP);
16712305Sstevel 						(void) strcpy(
16722305Sstevel 						    cdsp->binding_name, quote);
16732305Sstevel 					}
16742305Sstevel 				}
16752305Sstevel 				state = PT_STATE_TOKEN;
16762305Sstevel 			} /* if (qm) */
16772305Sstevel 		} /* PARSE_QUOTE */
16782305Sstevel 
16792305Sstevel 		em = 0;
16802305Sstevel 
16812305Sstevel 		if (!qm && (*cp == PARSE_SEMICOLON)) {
16822305Sstevel 			smc = 1;
16832305Sstevel 		}
16842305Sstevel 
16852305Sstevel 		/*
16862305Sstevel 		 * Check for tokens
16872305Sstevel 		 */
16882305Sstevel 		else if (!qm && (isalpha(*cp) || isxdigit(*cp))) {
16892305Sstevel 			int	tl;
16902305Sstevel 			unsigned	*intp;
16912305Sstevel 			ptoken = token;
16922305Sstevel 			token = find_token(&cp, &l, &eq);
16932305Sstevel 
16942305Sstevel 			switch (state) {
16952305Sstevel 			case PT_STATE_TOKEN:
16962305Sstevel 				if (smc) {
16972305Sstevel 					if (eq == PARSE_EQUALS)
16982305Sstevel 						state = PT_STATE_CHECK;
16992305Sstevel 					else
17002305Sstevel 						cardbus_add_prop(cdsp,
17012305Sstevel 						    DDI_PROP_TYPE_ANY,
17022305Sstevel 						    token,
17032305Sstevel 						    NULL, 0);
17042305Sstevel 				} else if (eq == PARSE_EQUALS)
17052305Sstevel 					switch (state = parse_token(token)) {
17062305Sstevel 					case PT_STATE_UNKNOWN:
17072305Sstevel 						cmn_err(CE_CONT,
17082305Sstevel 						    "cardbus_parse_devprop: "
17092305Sstevel 						    "unknown token [%s]\n",
17102305Sstevel 						    token);
17112305Sstevel 						state = PT_STATE_TOKEN;
17122305Sstevel 					} /* switch (parse_token) */
17132305Sstevel 				else
17142305Sstevel 					state = PT_STATE_TOKEN;
17152305Sstevel 				break;
17162305Sstevel 
17172305Sstevel 			case PT_STATE_CHECK:
17182305Sstevel 				switch (check_token(token, &tl)) {
17192305Sstevel 				case PT_STATE_DEC_VAR:
17202305Sstevel 					intp = (unsigned *)kmem_alloc(
17212305Sstevel 					    sizeof (int)*tl,
17222305Sstevel 					    KM_SLEEP);
17232305Sstevel 					if (token_to_dec(token, intp, tl))
17242305Sstevel 						cardbus_add_prop(cdsp,
17252305Sstevel 						    DDI_PROP_TYPE_INT, ptoken,
17262305Sstevel 						    (caddr_t)intp, tl);
17272305Sstevel 					else
17282305Sstevel 						kmem_free(intp,
17292305Sstevel 						    sizeof (int)*tl);
17302305Sstevel 					break;
17312305Sstevel 				case PT_STATE_HEX_VAR:
17322305Sstevel 					intp = (unsigned *)kmem_alloc(
17332305Sstevel 					    sizeof (int)*tl,
17342305Sstevel 					    KM_SLEEP);
17352305Sstevel 					if (token_to_hex(token, intp, tl))
17362305Sstevel 						cardbus_add_prop(cdsp,
17372305Sstevel 						    DDI_PROP_TYPE_INT,
17382305Sstevel 						    ptoken,
17392305Sstevel 						    (caddr_t)intp, tl);
17402305Sstevel 					else
17412305Sstevel 						kmem_free(intp,
17422305Sstevel 						    sizeof (int)*tl);
17432305Sstevel 					break;
17442305Sstevel 				case PT_STATE_STRING_VAR:
17452305Sstevel 					if (strcmp(ptoken, cb_nnamestr) == 0) {
17462305Sstevel 						cdsp->nodename = kmem_alloc(
17472305Sstevel 						    tl + 1, KM_SLEEP);
17482305Sstevel 						(void) strcpy(cdsp->nodename,
17492305Sstevel 						    token);
17502305Sstevel 					} else
17512305Sstevel 						cardbus_add_stringprop(cdsp,
17522305Sstevel 						    ptoken, token, tl);
17532305Sstevel 					break;
17542305Sstevel 				}
17552305Sstevel 				state = PT_STATE_TOKEN;
17562305Sstevel 				break;
17572305Sstevel 
17582305Sstevel 			case PT_STATE_HEX_VAR:
17592305Sstevel 				if (strcmp(ptoken, cb_venidstr) == 0) {
17602305Sstevel 					uint_t val;
17612305Sstevel 					if (token_to_hex(token, &val, 1))
17622305Sstevel 						cdsp->venid = val;
17632305Sstevel 				} else if (strcmp(ptoken, cb_devidstr) == 0) {
17642305Sstevel 					uint_t val;
17652305Sstevel 					if (token_to_hex(token, &val, 1))
17662305Sstevel 						cdsp->devid = val;
17672305Sstevel 				}
17682305Sstevel 				state = PT_STATE_TOKEN;
17692305Sstevel 				break;
17702305Sstevel 
17712305Sstevel 			case PT_STATE_DEC_VAR:
17722305Sstevel 				if (strcmp(ptoken, cb_venidstr) == 0) {
17732305Sstevel 					uint_t val;
17742305Sstevel 					if (token_to_dec(token, &val, 1))
17752305Sstevel 						cdsp->venid = val;
17762305Sstevel 				} else if (strcmp(ptoken, cb_devidstr) == 0) {
17772305Sstevel 					uint_t val;
17782305Sstevel 					if (token_to_dec(token, &val, 1))
17792305Sstevel 						cdsp->devid = val;
17802305Sstevel 				}
17812305Sstevel 				state = PT_STATE_TOKEN;
17822305Sstevel 				break;
17832305Sstevel 
17842305Sstevel 			case PT_STATE_STRING_VAR:
17852305Sstevel 				if (strcmp(ptoken, cb_bnamestr) == 0) {
17862305Sstevel 					cdsp->binding_name = kmem_alloc(
17872305Sstevel 					    strlen(token) + 1, KM_SLEEP);
17882305Sstevel 					(void) strcpy(cdsp->binding_name,
17892305Sstevel 					    token);
17902305Sstevel 				}
17912305Sstevel 				state = PT_STATE_TOKEN;
17922305Sstevel 				break;
17932305Sstevel 
17942305Sstevel 			default:
17952305Sstevel 				cmn_err(CE_CONT, "cardbus_parse_devprop: "
17962305Sstevel 				    "unknown state machine state = %d\n",
17972305Sstevel 				    state);
17982305Sstevel 
17992305Sstevel 				cardbus_devprops_free(cdsp);
18002305Sstevel 				return (DDI_FAILURE);
18012305Sstevel 			} /* switch (state) */
18022305Sstevel 			if (eq == PARSE_SEMICOLON)
18032305Sstevel 				smc = 1;
18042305Sstevel 		}
18052305Sstevel 		cp++;
18062305Sstevel 		l++;
18072305Sstevel 	} /* while (*cp) */
18082305Sstevel 
18092305Sstevel 	if (qm) {
18102305Sstevel 		cmn_err(CE_CONT, "cb_props_parse_line: unterminated "
18112305Sstevel 		    "string = [%s]\n", quote);
18122305Sstevel 		cardbus_devprops_free(cdsp);
18132305Sstevel 		return (DDI_FAILURE);
18142305Sstevel 	}
18152305Sstevel 
18162305Sstevel 	if (state != PT_STATE_TOKEN) {
18172305Sstevel 		cmn_err(CE_CONT, "cardbus_parse_devprop: token [%s] "
18182305Sstevel 		    "requires value\n", token);
18192305Sstevel 		cardbus_devprops_free(cdsp);
18202305Sstevel 		return (DDI_FAILURE);
18212305Sstevel 	}
18222305Sstevel 
18232305Sstevel 	if (cdsp->venid == 0 || cdsp->devid == 0) {
18242305Sstevel 		cmn_err(CE_CONT, "cardbus_parse_devprop: Entry "
18252305Sstevel 		    "requires VendorID and DeviceID\n");
18262305Sstevel 		cardbus_devprops_free(cdsp);
18272305Sstevel 		return (DDI_FAILURE);
18282305Sstevel 	}
18292305Sstevel 
18302305Sstevel 	cdsp->next = cbp->cb_dsp;
18312305Sstevel 	cbp->cb_dsp = cdsp;
18322305Sstevel 	return (DDI_SUCCESS);
18332305Sstevel }
18342305Sstevel 
18352305Sstevel static void
cardbus_device_props(cbus_t * cbp)18362305Sstevel cardbus_device_props(cbus_t *cbp)
18372305Sstevel {
18382305Sstevel 	char	**prop_array;
18392305Sstevel 	uint_t i, n;
18402305Sstevel 
18412305Sstevel 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, cbp->cb_dip,
18422305Sstevel 	    DDI_PROP_DONTPASS,
18432305Sstevel 	    "cb-device-init-props", &prop_array,
18442305Sstevel 	    &n) != DDI_PROP_SUCCESS)
18452305Sstevel 		return;
18462305Sstevel 
18472305Sstevel 	for (i = 0; i < n; i++)
18482305Sstevel 		(void) cardbus_parse_devprop(cbp, prop_array[i]);
18492305Sstevel 
18502305Sstevel 	ddi_prop_free(prop_array);
18512305Sstevel }
18522305Sstevel 
18532305Sstevel static int
cardbus_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)18542305Sstevel cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
18552305Sstevel 		off_t offset, off_t len, caddr_t *vaddrp)
18562305Sstevel {
18572305Sstevel 	register dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
18582305Sstevel 	int	rc;
18592305Sstevel 
18602305Sstevel 	cardbus_err(dip, 9,
18612305Sstevel 	    "cardbus_bus_map(dip=0x%p, rdip=0x%p)\n",
18622305Sstevel 	    (void *) dip, (void *) rdip);
18632305Sstevel 
18642305Sstevel 	if (pdip == NULL)
18652305Sstevel 		return (DDI_FAILURE);
18662305Sstevel 
18672305Sstevel 	/* A child has asked us to set something up */
18682305Sstevel 	cardbus_err(dip, 9,
18692305Sstevel 	    "cardbus_bus_map(%s) calling %s - 0x%p, "
18702305Sstevel 	    "offset 0x%x, len 0x%x\n",
18712305Sstevel 	    ddi_driver_name(rdip),
18722305Sstevel 	    ddi_driver_name(pdip),
18732305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_map,
18742305Sstevel 	    (int)offset, (int)len);
18752305Sstevel 
18762305Sstevel 	rc = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
18772305Sstevel 	    (pdip, rdip, mp, offset, len, vaddrp);
18782305Sstevel 	/* rc = ddi_map(dip, mp, offset, len, vaddrp); */
18792305Sstevel 
18803097Srw148561 	if (rc != DDI_SUCCESS) {
18812305Sstevel 		cardbus_err(rdip, 8, "cardbus_bus_map failed, rc = %d\n", rc);
18823097Srw148561 		return (DDI_FAILURE);
18833097Srw148561 	} else {
18842305Sstevel 		cardbus_err(rdip, 9, "cardbus_bus_map OK\n");
18852305Sstevel 		return (DDI_SUCCESS);
18862305Sstevel 	}
18872305Sstevel }
18882305Sstevel 
18892305Sstevel static void
pcirp2rp(const pci_regspec_t * pci_rp,struct regspec * rp)18902305Sstevel pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp)
18912305Sstevel {
18922305Sstevel 	/* bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); */
18932305Sstevel 	if (PCI_REG_ADDR_G(pci_rp->pci_phys_hi) ==
18942305Sstevel 	    PCI_REG_ADDR_G(PCI_ADDR_IO)) {
18952305Sstevel 		/* I/O */
18962305Sstevel 		rp->regspec_bustype = 1;
18972305Sstevel 	} else {
18982305Sstevel 		/* memory */
18992305Sstevel 		rp->regspec_bustype = 0;
19002305Sstevel 	}
19012305Sstevel 	rp->regspec_addr = pci_rp->pci_phys_low;
19022305Sstevel 	rp->regspec_size = pci_rp->pci_size_low;
19032305Sstevel }
19042305Sstevel 
19052305Sstevel static int
cardbus_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)19062305Sstevel cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
19072305Sstevel 		int (*waitfp)(caddr_t), caddr_t arg,
19082305Sstevel 		ddi_dma_handle_t *handlep)
19092305Sstevel {
19102305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19112305Sstevel 
19122305Sstevel 	cardbus_err(dip, 10,
19132305Sstevel 	    "cardbus_dma_allochdl(dip=0x%p, rdip=0x%p)\n",
19142305Sstevel 	    (void *) dip, (void *) rdip);
19152305Sstevel 
19162305Sstevel 	if (pdip == NULL)
19172305Sstevel 		return (DDI_FAILURE);
19182305Sstevel 
19192305Sstevel 	cardbus_err(dip, 11,
19202305Sstevel 	    "cardbus_dma_allochdl calling %s - 0x%p\n",
19212305Sstevel 	    ddi_driver_name(pdip),
19222305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_allochdl);
19232305Sstevel 
19242305Sstevel 	return (ddi_dma_allochdl(dip, rdip, attr, waitfp, arg, handlep));
19252305Sstevel }
19262305Sstevel 
19272305Sstevel static int
cardbus_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19282305Sstevel cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
19292305Sstevel 		ddi_dma_handle_t handle)
19302305Sstevel {
19312305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19322305Sstevel 
19332305Sstevel 	cardbus_err(dip, 10,
19342305Sstevel 	    "cardbus_dma_freehdl(dip=0x%p, rdip=0x%p)\n",
19352305Sstevel 	    (void *) dip, (void *) rdip);
19362305Sstevel 
19372305Sstevel 	if (pdip == NULL)
19382305Sstevel 		return (DDI_FAILURE);
19392305Sstevel 
19402305Sstevel 	cardbus_err(dip, 11,
19412305Sstevel 	    "cardbus_dma_freehdl calling %s - 0x%p\n",
19422305Sstevel 	    ddi_driver_name(pdip),
19432305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_freehdl);
19442305Sstevel 
19452305Sstevel 	return (ddi_dma_freehdl(dip, rdip, handle));
19462305Sstevel }
19472305Sstevel 
19482305Sstevel static int
cardbus_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)19492305Sstevel cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
19502305Sstevel 		ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
19512305Sstevel 		ddi_dma_cookie_t *cp, uint_t *ccountp)
19522305Sstevel {
19532305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19542305Sstevel 
19552305Sstevel 	cardbus_err(dip, 10,
19562305Sstevel 	    "cardbus_dma_bindhdl(dip=0x%p, rdip=0x%p)\n",
19572305Sstevel 	    (void *) dip, (void *) rdip);
19582305Sstevel 
19592305Sstevel 	if (pdip == NULL)
19602305Sstevel 		return (DDI_FAILURE);
19612305Sstevel 
19622305Sstevel 	cardbus_err(dip, 11,
19632305Sstevel 	    "cardbus_dma_bindhdl calling %s - 0x%p\n",
19642305Sstevel 	    ddi_driver_name(pdip),
19652305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl);
19662305Sstevel 
19672305Sstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl(pdip,
19682305Sstevel 	    rdip, handle, dmareq, cp, ccountp));
19692305Sstevel }
19702305Sstevel 
19712305Sstevel static int
cardbus_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19722305Sstevel cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
19732305Sstevel 		ddi_dma_handle_t handle)
19742305Sstevel {
19752305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19762305Sstevel 
19772305Sstevel 	cardbus_err(dip, 10,
19782305Sstevel 	    "cardbus_dma_unbindhdl(dip=0x%p, rdip=0x%p)\n",
19792305Sstevel 	    (void *) dip, (void *) rdip);
19802305Sstevel 
19812305Sstevel 	if (pdip == NULL)
19822305Sstevel 		return (DDI_FAILURE);
19832305Sstevel 
19842305Sstevel 	cardbus_err(dip, 11,
19852305Sstevel 	    "cardbus_dma_unbindhdl calling %s - 0x%p\n",
19862305Sstevel 	    ddi_driver_name(pdip),
19872305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl);
19882305Sstevel 
19892305Sstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl(pdip,
19902305Sstevel 	    rdip, handle));
19912305Sstevel }
19922305Sstevel 
19932305Sstevel static int
cardbus_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)19942305Sstevel cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
19952305Sstevel 		ddi_dma_handle_t handle, off_t off, size_t len,
19962305Sstevel 		uint_t cache_flags)
19972305Sstevel {
19982305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19992305Sstevel 
20002305Sstevel 	cardbus_err(dip, 10,
20012305Sstevel 	    "cardbus_dma_flush(dip=0x%p, rdip=0x%p)\n",
20022305Sstevel 	    (void *) dip, (void *) rdip);
20032305Sstevel 
20042305Sstevel 	if (pdip == NULL)
20052305Sstevel 		return (DDI_FAILURE);
20062305Sstevel 
20072305Sstevel 	cardbus_err(dip, 11,
20082305Sstevel 	    "cardbus_dma_flush calling %s - 0x%p\n",
20092305Sstevel 	    ddi_driver_name(pdip),
20102305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush);
20112305Sstevel 
20122305Sstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush(pdip, rdip,
20132305Sstevel 	    handle, off, len, cache_flags));
20142305Sstevel }
20152305Sstevel 
20162305Sstevel static int
cardbus_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)20172305Sstevel cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
20182305Sstevel 		ddi_dma_handle_t handle, uint_t win, off_t *offp,
20192305Sstevel 		size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
20202305Sstevel {
20212305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
20222305Sstevel 	cardbus_err(dip, 6,
20232305Sstevel 	    "cardbus_dma_win(dip=0x%p, rdip=0x%p)\n",
20242305Sstevel 	    (void *) dip, (void *) rdip);
20252305Sstevel 
20262305Sstevel 	if (pdip == NULL)
20272305Sstevel 		return (DDI_FAILURE);
20282305Sstevel 
20292305Sstevel 	cardbus_err(dip, 8,
20302305Sstevel 	    "cardbus_dma_win calling %s - 0x%p\n",
20312305Sstevel 	    ddi_driver_name(pdip),
20322305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win);
20332305Sstevel 
20342305Sstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win(pdip, rdip,
20352305Sstevel 	    handle, win, offp, lenp, cookiep, ccountp));
20362305Sstevel }
20372305Sstevel 
20382305Sstevel static int
cardbus_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)20392305Sstevel cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
20402305Sstevel 		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
20412305Sstevel {
20422305Sstevel 	dev_info_t *pdip = ddi_get_parent(dip);
20432305Sstevel 
20442305Sstevel 	cardbus_err(dip, 10,
20452305Sstevel 	    "cardbus_dma_map(dip=0x%p, rdip=0x%p)\n",
20462305Sstevel 	    (void *) dip, (void *) rdip);
20472305Sstevel 
20482305Sstevel 	if (pdip == NULL)
20492305Sstevel 		return (DDI_FAILURE);
20502305Sstevel 
20512305Sstevel 	cardbus_err(dip, 11,
20522305Sstevel 	    "cardbus_dma_map calling %s - 0x%p\n",
20532305Sstevel 	    ddi_driver_name(pdip),
20542305Sstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map);
20552305Sstevel 
20562305Sstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map(pdip, rdip,
20572305Sstevel 	    dmareqp, handlep));
20582305Sstevel }
20592305Sstevel 
20602305Sstevel static int
cardbus_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * cookiep)20612305Sstevel cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
20622305Sstevel 		char *eventname, ddi_eventcookie_t *cookiep)
20632305Sstevel {
20642305Sstevel 	cbus_t *cbp;
20652305Sstevel 	int	cb_instance;
20662305Sstevel 	int	rc;
20672305Sstevel 
20682305Sstevel 	/*
20692305Sstevel 	 * get the soft state structure for the bus instance.
20702305Sstevel 	 */
20712305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
20722305Sstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
20732305Sstevel 	ASSERT(cb_instance >= 0);
20742305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
20752305Sstevel 
20762305Sstevel 	cardbus_err(dip, 6, "cardbus_get_eventcookie %s\n", eventname);
20772305Sstevel 
20782305Sstevel 	ASSERT(number_of_cardbus_cards != 0);
20792305Sstevel 
20802305Sstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
20812305Sstevel 		/*
20822305Sstevel 		 * We can't handle up (probably called at the attachment
20832305Sstevel 		 * point) so pass it on up
20842305Sstevel 		 */
20852305Sstevel 		dev_info_t *pdip = ddi_get_parent(dip);
20862305Sstevel 		cardbus_err(dip, 8,
20872305Sstevel 		    "cardbus_get_eventcookie calling %s - 0x%p\n",
20882305Sstevel 		    ddi_driver_name(pdip),
20892305Sstevel 		    (void *)
20902305Sstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie);
20912305Sstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
20922305Sstevel 		    bus_get_eventcookie(pdip, rdip, eventname, cookiep));
20932305Sstevel 	}
20942305Sstevel 
20952305Sstevel 	cardbus_err(dip, 8,
20962305Sstevel 	    "cardbus_get_eventcookie calling ndi_event_retrieve_cookie\n");
20972305Sstevel 
20982305Sstevel 	rc = ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, rdip, eventname,
20992305Sstevel 	    cookiep, NDI_EVENT_NOPASS);
21002305Sstevel 
21012305Sstevel 	cardbus_err(dip, 7,
21022305Sstevel 	    "cardbus_get_eventcookie rc %d cookie %p\n", rc, (void *)*cookiep);
21032305Sstevel 	return (rc);
21042305Sstevel }
21052305Sstevel 
21062305Sstevel static int
cardbus_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void (* callback)(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata),void * arg,ddi_callback_id_t * cb_id)21072305Sstevel cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
21082305Sstevel 		ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
21092305Sstevel 		ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
21102305Sstevel 		void *arg, ddi_callback_id_t *cb_id)
21112305Sstevel {
21122305Sstevel 	cbus_t *cbp;
21132305Sstevel 	int	cb_instance;
21142305Sstevel 	int	rc;
21152305Sstevel 
21162305Sstevel 	/*
21172305Sstevel 	 * get the soft state structure for the bus instance.
21182305Sstevel 	 */
21192305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21202305Sstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
21212305Sstevel 	ASSERT(cb_instance >= 0);
21222305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21232305Sstevel 
21242305Sstevel 	cardbus_err(dip, 6, "cardbus_add_eventcall\n");
21252305Sstevel 
21262305Sstevel 	ASSERT(number_of_cardbus_cards != 0);
21272305Sstevel 
21282305Sstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
21292305Sstevel 		/*
21302305Sstevel 		 * We can't handle up (probably called at the attachment
21312305Sstevel 		 * point) so pass it on up
21322305Sstevel 		 */
21332305Sstevel 		dev_info_t *pdip = ddi_get_parent(dip);
21342305Sstevel 		cardbus_err(dip, 8,
21352305Sstevel 		    "cardbus_add_eventcall calling %s - 0x%p\n",
21362305Sstevel 		    ddi_driver_name(pdip),
21372305Sstevel 		    (void *)
21382305Sstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_add_eventcall);
21392305Sstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
21402305Sstevel 		    bus_add_eventcall(pdip, rdip, cookie, callback,
21412305Sstevel 		    arg, cb_id));
21422305Sstevel 	}
21432305Sstevel 
21442305Sstevel 	cardbus_err(dip, 8,
21452305Sstevel 	    "cardbus_add_eventcall calling ndi_event_add_callback\n");
21462305Sstevel 
21472305Sstevel 	rc = ndi_event_add_callback(cbp->cb_ndi_event_hdl, rdip, cookie,
21482305Sstevel 	    callback, arg, NDI_EVENT_NOPASS, cb_id);
21492305Sstevel 	cardbus_err(dip, 7,
21502305Sstevel 	    "cardbus_add_eventcall rc %d cookie %p\n", rc, (void *)cookie);
21512305Sstevel 	return (rc);
21522305Sstevel }
21532305Sstevel 
21542305Sstevel static int
cardbus_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)21552305Sstevel cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
21562305Sstevel {
21572305Sstevel 	cbus_t *cbp;
21582305Sstevel 	int	cb_instance;
21592305Sstevel 
21602305Sstevel 	/*
21612305Sstevel 	 * get the soft state structure for the bus instance.
21622305Sstevel 	 */
21632305Sstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21642305Sstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
21652305Sstevel 	ASSERT(cb_instance >= 0);
21662305Sstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21672305Sstevel 
21682305Sstevel 	cardbus_err(dip, 6, "cardbus_remove_eventcall\n");
21692305Sstevel 
21702305Sstevel 	ASSERT(number_of_cardbus_cards != 0);
21712305Sstevel 
21722305Sstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
21732305Sstevel 		/*
21742305Sstevel 		 * We can't handle up (probably called at the attachment
21752305Sstevel 		 * point) so pass it on up
21762305Sstevel 		 */
21772305Sstevel 		dev_info_t *pdip = ddi_get_parent(dip);
21782305Sstevel 		cardbus_err(dip, 8,
21792305Sstevel 		    "cardbus_remove_eventcall calling %s - 0x%p\n",
21802305Sstevel 		    ddi_driver_name(pdip),
21812305Sstevel 		    (void *)
21822305Sstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_remove_eventcall);
21832305Sstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
21842305Sstevel 		    bus_remove_eventcall(pdip, cb_id));
21852305Sstevel 	}
21862305Sstevel 
21872305Sstevel 	return (ndi_event_remove_callback(cbp->cb_ndi_event_hdl, cb_id));
21882305Sstevel }
21892305Sstevel 
21902305Sstevel static int
cardbus_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * bus_impldata)21912305Sstevel cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
21922305Sstevel 		ddi_eventcookie_t cookie, void *bus_impldata)
21932305Sstevel {
21942305Sstevel 	_NOTE(ARGUNUSED(rdip, cookie, bus_impldata))
21952305Sstevel 	cardbus_err(dip, 1, "cardbus_post_event()\n");
21962305Sstevel 	return (DDI_FAILURE);
21972305Sstevel }
21982305Sstevel 
21992305Sstevel static int cardbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22002305Sstevel 		ddi_intr_handle_impl_t *hdlp);
22012305Sstevel static int cardbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22022305Sstevel 		ddi_intr_handle_impl_t *hdlp);
22032305Sstevel static int cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22042305Sstevel 		ddi_intr_handle_impl_t *hdlp);
22052305Sstevel static int cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22062305Sstevel 		ddi_intr_handle_impl_t *hdlp);
22072305Sstevel 
22082451Srw148561 static int
cardbus_get_pil(dev_info_t * dip)22092451Srw148561 cardbus_get_pil(dev_info_t *dip)
22102451Srw148561 {
22112451Srw148561 	return ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
22122451Srw148561 	    "interrupt-priorities", 6);
22132451Srw148561 }
22142451Srw148561 
22152305Sstevel static int
cardbus_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)22162305Sstevel cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
22172305Sstevel 	ddi_intr_handle_impl_t *hdlp, void *result)
22182305Sstevel {
22192305Sstevel 	int ret = DDI_SUCCESS;
22202305Sstevel 
22212305Sstevel #if defined(CARDBUS_DEBUG)
22222305Sstevel 	cardbus_err(dip, 8, "cardbus_intr_ops() intr_op=%d\n", (int)intr_op);
22232305Sstevel #endif
22242305Sstevel 
22252305Sstevel 	switch (intr_op) {
22262305Sstevel 	case DDI_INTROP_GETCAP:
22272305Sstevel 		*(int *)result = DDI_INTR_FLAG_LEVEL;
22282305Sstevel 		break;
22292305Sstevel 	case DDI_INTROP_ALLOC:
22302305Sstevel 		*(int *)result = hdlp->ih_scratch1;
22312305Sstevel 		break;
22322305Sstevel 	case DDI_INTROP_FREE:
22332305Sstevel 		break;
22342305Sstevel 	case DDI_INTROP_GETPRI:
22352305Sstevel 		*(int *)result = hdlp->ih_pri ?
22362451Srw148561 		    hdlp->ih_pri : cardbus_get_pil(dip);
22372305Sstevel 		break;
22382305Sstevel 	case DDI_INTROP_SETPRI:
22392305Sstevel 		break;
22402305Sstevel 	case DDI_INTROP_ADDISR:
22412305Sstevel 	case DDI_INTROP_REMISR:
22422305Sstevel 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22432305Sstevel 			cardbus_err(dip, 1, "Only fixed interrupts\n");
22442305Sstevel 			return (DDI_FAILURE);
22452305Sstevel 		}
22462305Sstevel 		break;
22472305Sstevel 	case DDI_INTROP_ENABLE:
22482305Sstevel 		ret = cardbus_enable_intr_impl(dip, rdip, hdlp);
22492305Sstevel 		break;
22502305Sstevel 	case DDI_INTROP_DISABLE:
22512305Sstevel 		ret = cardbus_disable_intr_impl(dip, rdip, hdlp);
22522305Sstevel 		break;
22532305Sstevel 	case DDI_INTROP_NINTRS:
22542305Sstevel 	case DDI_INTROP_NAVAIL:
22552451Srw148561 #ifdef sparc
22562580Sanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
22572451Srw148561 #else
22582451Srw148561 		*(int *)result = 1;
22592451Srw148561 #endif
22602305Sstevel 		break;
22612305Sstevel 	case DDI_INTROP_SUPPORTED_TYPES:
22622451Srw148561 		*(int *)result = DDI_INTR_TYPE_FIXED;
22632305Sstevel 		break;
22642305Sstevel 	default:
22652305Sstevel 		ret = DDI_ENOTSUP;
22662305Sstevel 		break;
22672305Sstevel 	}
22682305Sstevel 
22692305Sstevel 	return (ret);
22702305Sstevel }
22712305Sstevel 
22722305Sstevel static int
cardbus_enable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)22732305Sstevel cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22742305Sstevel 		ddi_intr_handle_impl_t *hdlp)
22752305Sstevel {
22762305Sstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
22772305Sstevel 	set_irq_handler_t sih;
22782305Sstevel 	uint_t socket = 0; /* We only support devices */
22792305Sstevel 			    /* with one socket per function */
22802305Sstevel 
22812305Sstevel 	ASSERT(anp != NULL);
22822305Sstevel 
22832305Sstevel 	cardbus_err(dip, 9,
22842305Sstevel 	    "cardbus_enable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
22852305Sstevel 	    "rdip=0x%p(%s)\n",
22862305Sstevel 	    (void *) hdlp->ih_cb_func,
22872305Sstevel 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
22882305Sstevel 	    (void *) rdip, ddi_driver_name(rdip));
22892305Sstevel 
22902305Sstevel 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22912305Sstevel 		cardbus_err(dip, 1, "Only fixed interrupts\n");
22922305Sstevel 		return (DDI_FAILURE);
22932305Sstevel 	}
22942305Sstevel 
22952305Sstevel 	sih.socket = socket;
22962451Srw148561 	sih.handler_id = (unsigned)(long)rdip;
22972305Sstevel 	sih.handler = (f_tt *)hdlp->ih_cb_func;
22982305Sstevel 	sih.arg1 = hdlp->ih_cb_arg1;
22992305Sstevel 	sih.arg2 = hdlp->ih_cb_arg2;
23002451Srw148561 	sih.irq = cardbus_get_pil(dip);
23012305Sstevel 
23022305Sstevel 	if ((*anp->an_if->pcif_set_interrupt)(dip, &sih) != SUCCESS)
23032305Sstevel 		return (DDI_FAILURE);
23042305Sstevel 
23052305Sstevel 	return (DDI_SUCCESS);
23062305Sstevel }
23072305Sstevel 
23082305Sstevel static int
cardbus_disable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)23092305Sstevel cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
23102305Sstevel 		ddi_intr_handle_impl_t *hdlp)
23112305Sstevel {
23122305Sstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
23132305Sstevel 	clear_irq_handler_t cih;
23142305Sstevel 	uint_t socket = 0; /* We only support devices with 1 socket per */
23152305Sstevel 			    /* function. */
23162305Sstevel 
23172305Sstevel 	ASSERT(anp != NULL);
23182305Sstevel 
23192305Sstevel 	cardbus_err(dip, 9,
23202305Sstevel 	    "cardbus_disable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
23212305Sstevel 	    "rdip=0x%p(%s%d)\n",
23222305Sstevel 	    (void *) hdlp->ih_cb_func,
23232305Sstevel 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
23242305Sstevel 	    (void *) rdip, ddi_driver_name(rdip), ddi_get_instance(rdip));
23252305Sstevel 
23262305Sstevel 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
23272305Sstevel 		cardbus_err(dip, 1, "Only fixed interrupts\n");
23282305Sstevel 		return (DDI_FAILURE);
23292305Sstevel 	}
23302305Sstevel 
23312305Sstevel 	cih.socket = socket;
23322451Srw148561 	cih.handler_id = (unsigned)(long)rdip;
23332305Sstevel 	cih.handler = (f_tt *)hdlp->ih_cb_func;
23342305Sstevel 
23352305Sstevel 	if ((*anp->an_if->pcif_clr_interrupt)(dip, &cih) != SUCCESS)
23362305Sstevel 		return (DDI_FAILURE);
23372305Sstevel 
23382305Sstevel 	return (DDI_SUCCESS);
23392305Sstevel }
23402305Sstevel 
23412305Sstevel #if defined(CARDBUS_DEBUG)
23422305Sstevel static int	cardbus_do_pprintf = 0;
23432305Sstevel #endif
23442305Sstevel 
23452305Sstevel /*PRINTFLIKE3*/
23462305Sstevel void
cardbus_err(dev_info_t * dip,int level,const char * fmt,...)23472305Sstevel cardbus_err(dev_info_t *dip, int level, const char *fmt, ...)
23482305Sstevel {
23492305Sstevel 	if (cardbus_debug && (level <= cardbus_debug)) {
23502305Sstevel 		va_list adx;
23512305Sstevel 		int	instance;
23522305Sstevel 		char	buf[256];
23532305Sstevel 		const char	*name;
23542305Sstevel 		char	*nl = "";
23552305Sstevel #if !defined(CARDBUS_DEBUG)
23562305Sstevel 		int	ce;
23572305Sstevel 		char	qmark = 0;
23582305Sstevel 
23592305Sstevel 		if (level <= 3)
23602305Sstevel 			ce = CE_WARN;
23612305Sstevel 		else
23622305Sstevel 			ce = CE_CONT;
23632305Sstevel 		if (level == 4)
23642305Sstevel 			qmark = 1;
23652305Sstevel #endif
23662305Sstevel 
23672305Sstevel 		if (dip) {
23682305Sstevel 			instance = ddi_get_instance(dip);
23692305Sstevel 			/* name = ddi_binding_name(dip); */
23702305Sstevel 			name = ddi_driver_name(dip);
23712305Sstevel 		} else {
23722305Sstevel 			instance = 0;
23732305Sstevel 			name = "";
23742305Sstevel 		}
23752305Sstevel 
23762305Sstevel 		va_start(adx, fmt);
23772305Sstevel 		/* vcmn_err(ce, fmt, adx); */
23782305Sstevel 		/* vprintf(fmt, adx); */
23792305Sstevel 		/* prom_vprintf(fmt, adx); */
23802305Sstevel 		(void) vsprintf(buf, fmt, adx);
23812305Sstevel 		va_end(adx);
23822305Sstevel 
23832305Sstevel 		if (buf[strlen(buf) - 1] != '\n')
23842305Sstevel 			nl = "\n";
23852305Sstevel 
23862305Sstevel #if defined(CARDBUS_DEBUG)
23872305Sstevel 		if (cardbus_do_pprintf) {
23882305Sstevel 			if (dip) {
23892305Sstevel 				if (instance >= 0)
23902305Sstevel 					prom_printf("%s(%d),0x%p: %s%s",
2391*7240Srh87107 					    name, instance, (void *)dip,
2392*7240Srh87107 					    buf, nl);
23932305Sstevel 				else
23942305Sstevel 					prom_printf("%s,0x%p: %s%s", name,
2395*7240Srh87107 					    (void *)dip, buf, nl);
23962305Sstevel 			} else
23972305Sstevel 				prom_printf("%s%s", buf, nl);
23982305Sstevel 		} else {
23992305Sstevel 			if (dip) {
24002305Sstevel 				if (instance >= 0)
24012305Sstevel 					cmn_err(CE_CONT, "%s(%d),0x%p: %s%s",
2402*7240Srh87107 					    name, instance, (void *)dip,
24032305Sstevel 					    buf, nl);
24042305Sstevel 				else
24052305Sstevel 					cmn_err(CE_CONT, "%s,0x%p: %s%s",
2406*7240Srh87107 					    name, (void *)dip, buf, nl);
24072305Sstevel 			} else
24082305Sstevel 				cmn_err(CE_CONT, "%s%s", buf, nl);
24092305Sstevel 		}
24102305Sstevel #else
24112305Sstevel 		if (dip)
24122305Sstevel 			cmn_err(ce, qmark ? "?%s%d: %s%s" : "%s%d: %s%s",
24132305Sstevel 			    name, instance, buf, nl);
24142305Sstevel 		else
24152305Sstevel 			cmn_err(ce, qmark ? "?%s%s" : "%s%s", buf, nl);
24162305Sstevel #endif
24172305Sstevel 	}
24182305Sstevel }
24192305Sstevel 
cardbus_expand_busrange(dev_info_t * dip)24202305Sstevel static void cardbus_expand_busrange(dev_info_t *dip)
24212305Sstevel {
24222305Sstevel 	dev_info_t *pdip;
24232305Sstevel 	cardbus_bus_range_t *bus_range;
24242305Sstevel 	int len;
24252305Sstevel 
24262305Sstevel 	pdip = ddi_get_parent(dip);
24272305Sstevel 
24282305Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "bus-range",
24292305Sstevel 	    (caddr_t)&bus_range, &len) == DDI_PROP_SUCCESS) {
24302305Sstevel 		ndi_ra_request_t req;
24312305Sstevel 		uint64_t next_bus, blen;
24322305Sstevel 		uint32_t ret;
24332305Sstevel 		ddi_acc_handle_t handle;
24342305Sstevel 
24352305Sstevel 		if (bus_range->lo != bus_range->hi)
24362305Sstevel 			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24372305Sstevel 			    "%u -> %u\n", bus_range->lo, bus_range->hi);
24382305Sstevel 		else {
24392305Sstevel 
24402305Sstevel 			bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24412305Sstevel 			req.ra_addr = bus_range->lo + 1;
24422305Sstevel 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
24432305Sstevel 			req.ra_len = 12;
24442305Sstevel 
24452305Sstevel 			while ((req.ra_len > 0) &&
24462305Sstevel 			    (ret = ndi_ra_alloc(ddi_get_parent(pdip), &req,
24472305Sstevel 			    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24482305Sstevel 			    NDI_RA_PASS)) != NDI_SUCCESS)
24492305Sstevel 				req.ra_len--;
24502305Sstevel 
24512305Sstevel 			if (ret != NDI_SUCCESS) {
24522305Sstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24532305Sstevel 				    "fail to allocate bus number\n");
24542305Sstevel 				goto exit;
24552305Sstevel 			}
24562305Sstevel 
24572305Sstevel 			bus_range->hi = bus_range->lo + req.ra_len;
24582305Sstevel 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip,
24592305Sstevel 			    "bus-range", (int *)bus_range, 2) != DDI_SUCCESS) {
24602305Sstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24612305Sstevel 				    "fail to update bus-range property\n");
24622305Sstevel 				goto exit;
24632305Sstevel 			}
24642305Sstevel 
24652305Sstevel 			if (pci_config_setup(pdip, &handle) != DDI_SUCCESS) {
24662305Sstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24672305Sstevel 				    "fail to pci_config_setup\n");
24682305Sstevel 				goto exit;
24692305Sstevel 			}
24702305Sstevel 
24712305Sstevel 			pci_config_put8(handle, PCI_BCNF_SECBUS, bus_range->lo);
24722305Sstevel 			pci_config_put8(handle, PCI_BCNF_SUBBUS, bus_range->hi);
24732305Sstevel 
24742305Sstevel 			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24752305Sstevel 			    "parent dip %u -> %u\n",
24762305Sstevel 			    pci_config_get8(handle, PCI_BCNF_SECBUS),
24772305Sstevel 			    pci_config_get8(handle, PCI_BCNF_SUBBUS));
24782305Sstevel 			pci_config_teardown(&handle);
24792305Sstevel 
24802305Sstevel 			if (ndi_ra_map_setup(pdip, NDI_RA_TYPE_PCI_BUSNUM)
24812305Sstevel 			    != NDI_SUCCESS) {
24822305Sstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24832305Sstevel 				    "fail to ndi_ra_map_setup of bus number\n");
24842305Sstevel 				goto exit;
24852305Sstevel 			}
24862305Sstevel 
24872305Sstevel 			(void) ndi_ra_free(pdip,
24882305Sstevel 			    (uint64_t)bus_range->lo + 1, req.ra_len,
24892305Sstevel 			    NDI_RA_TYPE_PCI_BUSNUM, 0);
24902305Sstevel 		}
24912305Sstevel 
24922305Sstevel 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24932305Sstevel 		req.ra_len = 2;
24942305Sstevel 
24952305Sstevel 		while ((req.ra_len > 0) &&
24962305Sstevel 		    (ret = ndi_ra_alloc(pdip, &req,
24972305Sstevel 		    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24982305Sstevel 		    0)) != NDI_SUCCESS)
24992305Sstevel 			req.ra_len--;
25002305Sstevel 
25012305Sstevel 		cardbus_err(dip, 1, "cardbus_expand_busrange: "
25022305Sstevel 		    "cardbus dip base %u length %d\n",
25032305Sstevel 		    (int)next_bus, (int)req.ra_len);
25042305Sstevel 
25052305Sstevel 		if (ret != NDI_SUCCESS) {
25062305Sstevel 			cardbus_err(dip, 1, "cardbus_expand_busrange: "
25072305Sstevel 			    "fail to allocate bus number of length %d "
25082305Sstevel 			    "from parent\n",
25092305Sstevel 			    (int)req.ra_len);
25102305Sstevel 			goto exit;
25112305Sstevel 		}
25122305Sstevel 
25132305Sstevel 		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
25142305Sstevel 		    != NDI_SUCCESS) {
25152305Sstevel 			cardbus_err(dip, 1, "cardbus_expand_busrange: "
25162305Sstevel 			    "fail to ndi_ra_map_setup of bus numbers\n");
25172305Sstevel 			goto exit;
25182305Sstevel 		}
25192305Sstevel 
25202305Sstevel 		(void) ndi_ra_free(dip,
25212305Sstevel 		    (uint64_t)next_bus, req.ra_len,
25222305Sstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
25232305Sstevel exit:
25242305Sstevel 		kmem_free(bus_range, len);
25252305Sstevel 
25262305Sstevel 	} else
25272305Sstevel 		cardbus_err(pdip, 1, "cardbus_expand_busrange: "
25282305Sstevel 		    "parent dip doesn't have busrange prop\n");
25292305Sstevel }
2530