Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  * DRT device/interrupt handler
     29  */
     30 
     31 #include <sys/types.h>
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #include <sys/user.h>
     35 #include <sys/buf.h>
     36 #include <sys/file.h>
     37 #include <sys/uio.h>
     38 #include <sys/conf.h>
     39 #include <sys/stat.h>
     40 #include <sys/autoconf.h>
     41 #include <sys/vtoc.h>
     42 #include <sys/dkio.h>
     43 #include <sys/ddi.h>
     44 #include <sys/sunddi.h>
     45 #include <sys/ddidmareq.h>
     46 #include <sys/kstat.h>
     47 #include <sys/kmem.h>
     48 
     49 #include <sys/pctypes.h>
     50 #include <sys/pcmcia.h>
     51 #include <sys/sservice.h>
     52 
     53 #include <sys/stp4020_reg.h>
     54 #include <sys/stp4020_var.h>
     55 #include <sys/spl.h>
     56 
     57 
     58 struct stpramap *stpra_freelist = NULL;
     59 
     60 
     61 
     62 char _depends_on[] = "misc/pcmcia";
     63 
     64 #define	OUTB(a, b)	outb(a, b)
     65 #define	INB(a)		inb(a)
     66 
     67 int drt_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
     68 static int drt_attach(dev_info_t *, ddi_attach_cmd_t);
     69 static int drt_detach(dev_info_t *, ddi_detach_cmd_t);
     70 
     71 static void drt_ll_reset(drt_dev_t *, int);
     72 static void drt_stop_intr(drt_dev_t *, int);
     73 static void drt_cpr(drt_dev_t *, int);
     74 static void drt_new_card(drt_dev_t *, int);
     75 static void drt_fixprops(dev_info_t *);
     76 static int drt_inquire_adapter(dev_info_t *, inquire_adapter_t *);
     77 
     78 static struct stpramap *stpra_alloc_map();
     79 static void stpra_free_map(struct stpramap *);
     80 static void stpra_free(struct stpramap **, uint32_t, uint32_t);
     81 static int stpra_alloc(struct stpramap **, stpra_request_t *, stpra_return_t *);
     82 static uint32_t stpra_fix_pow2(uint32_t);
     83 
     84 
     85 static kmutex_t stpra_lock;
     86 
     87 static
     88 struct bus_ops pcmciabus_ops = {
     89 	BUSO_REV,
     90 	i_ddi_bus_map,
     91 	NULL,
     92 	NULL,
     93 	NULL,
     94 	i_ddi_map_fault,
     95 	ddi_no_dma_map,
     96 	ddi_no_dma_allochdl,
     97 	ddi_no_dma_freehdl,
     98 	ddi_no_dma_bindhdl,
     99 	ddi_no_dma_unbindhdl,
    100 	ddi_no_dma_flush,
    101 	ddi_no_dma_win,
    102 	ddi_no_dma_mctl,
    103 	pcmcia_ctlops,
    104 	pcmcia_prop_op,
    105 	NULL,			/* (*bus_get_eventcookie)();	*/
    106 	NULL,			/* (*bus_add_eventcall)();	*/
    107 	NULL,			/* (*bus_remove_eventcall)();	*/
    108 	NULL,			/* (*bus_post_event)();		*/
    109 	NULL,			/* (*bus_intr_ctl)();		*/
    110 	NULL,			/* (*bus_config)(); 		*/
    111 	NULL,			/* (*bus_unconfig)(); 		*/
    112 	NULL,			/* (*bus_fm_init)(); 		*/
    113 	NULL,			/* (*bus_fm_fini)(); 		*/
    114 	NULL,			/* (*bus_enter)()		*/
    115 	NULL,			/* (*bus_exit)()		*/
    116 	NULL,			/* (*bus_power)()		*/
    117 	pcmcia_intr_ops		/* (*bus_intr_op)(); 		*/
    118 };
    119 
    120 static struct dev_ops drt_devops = {
    121 	DEVO_REV,
    122 	0,
    123 	drt_getinfo,
    124 	nulldev,
    125 	nulldev,
    126 	drt_attach,
    127 	drt_detach,
    128 	nulldev,
    129 	NULL,
    130 	&pcmciabus_ops,
    131 	ddi_power,
    132 	ddi_quiesce_not_supported,	/* devo_quiesce */
    133 };
    134 
    135 #if defined(DEBUG)
    136 #define	DRT_DEBUG
    137 #endif
    138 #if defined(DRT_DEBUG)
    139 static void drt_dmp_regs(stp4020_socket_csr_t *);
    140 int drt_debug = 0;
    141 #endif
    142 
    143 /* bit patterns to select voltage levels */
    144 int drt_vpp_levels[13] = {
    145 	0, 0, 0, 0, 0,
    146 	1,			/* 5V */
    147 	0, 0, 0, 0, 0, 0,
    148 	2			/* 12V */
    149 };
    150 struct power_entry drt_power[DRT_NUM_POWER] = {
    151 	{
    152 		0,		/* off */
    153 		VCC|VPP1|VPP2
    154 	},
    155 	{
    156 		5*10,		/* 5Volt */
    157 		VCC|VPP1|VPP2
    158 	},
    159 	{
    160 		12*10,		/* 12Volt */
    161 		VPP1|VPP2
    162 	},
    163 };
    164 
    165 drt_dev_t *drt_get_driver_private(dev_info_t *);
    166 uint32_t drt_hi_intr(caddr_t);
    167 uint32_t drt_lo_intr(caddr_t);
    168 
    169 static int drt_callback(dev_info_t *, int (*)(), int);
    170 static int drt_inquire_adapter(dev_info_t *, inquire_adapter_t *);
    171 static int drt_get_adapter(dev_info_t *, get_adapter_t *);
    172 static int drt_get_page(dev_info_t *, get_page_t *);
    173 static int drt_get_socket(dev_info_t *, get_socket_t *);
    174 static int drt_get_status(dev_info_t *, get_ss_status_t *);
    175 static int drt_get_window(dev_info_t *, get_window_t *);
    176 static int drt_inquire_socket(dev_info_t *, inquire_socket_t *);
    177 static int drt_inquire_window(dev_info_t *, inquire_window_t *);
    178 static int drt_reset_socket(dev_info_t *, int, int);
    179 static int drt_set_page(dev_info_t *, set_page_t *);
    180 static int drt_set_window(dev_info_t *, set_window_t *);
    181 static int drt_set_socket(dev_info_t *, set_socket_t *);
    182 static int drt_set_interrupt(dev_info_t *, set_irq_handler_t *);
    183 static int drt_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
    184 void drt_socket_card_id(drt_dev_t *, drt_socket_t *, int);
    185 
    186 /*
    187  * pcmcia interface operations structure
    188  * this is the private interface that is exported to the nexus
    189  */
    190 pcmcia_if_t drt_if_ops = {
    191 	PCIF_MAGIC,
    192 	PCIF_VERSION,
    193 	drt_callback,
    194 	drt_get_adapter,
    195 	drt_get_page,
    196 	drt_get_socket,
    197 	drt_get_status,
    198 	drt_get_window,
    199 	drt_inquire_adapter,
    200 	drt_inquire_socket,
    201 	drt_inquire_window,
    202 	drt_reset_socket,
    203 	drt_set_page,
    204 	drt_set_window,
    205 	drt_set_socket,
    206 	drt_set_interrupt,
    207 	drt_clear_interrupt,
    208 	NULL,
    209 };
    210 
    211 /*
    212  * This is the loadable module wrapper.
    213  */
    214 #include <sys/modctl.h>
    215 
    216 extern struct mod_ops mod_driverops;
    217 
    218 static struct modldrv modldrv = {
    219 	&mod_driverops,		/* Type of module. This one is a driver */
    220 	"STP4020 (SUNW,pcmcia) adapter driver", /* Name of the module. */
    221 	&drt_devops,		/* driver ops */
    222 };
    223 
    224 static struct modlinkage modlinkage = {
    225 	MODREV_1, (void *)&modldrv, NULL
    226 };
    227 
    228 int
    229 _init()
    230 {
    231 	int ret;
    232 
    233 	mutex_init(&stpra_lock, NULL, MUTEX_DRIVER,
    234 	    (void *)(uintptr_t)__ipltospl(SPL7 - 1));
    235 	if ((ret = mod_install(&modlinkage)) != 0) {
    236 		mutex_destroy(&stpra_lock);
    237 	}
    238 	return (ret);
    239 }
    240 
    241 int
    242 _fini()
    243 {
    244 	int ret;
    245 	struct stpramap *next;
    246 
    247 	if ((ret = mod_remove(&modlinkage)) == 0) {
    248 
    249 		mutex_enter(&stpra_lock);
    250 		while (stpra_freelist != NULL) {
    251 			next = stpra_freelist->ra_next;
    252 			kmem_free((caddr_t)stpra_freelist,
    253 			    sizeof (struct stpramap));
    254 			stpra_freelist = next;
    255 		}
    256 		mutex_exit(&stpra_lock);
    257 
    258 		mutex_destroy(&stpra_lock);
    259 	}
    260 	return (ret);
    261 }
    262 
    263 int
    264 _info(struct modinfo *modinfop)
    265 {
    266 	return (mod_info(&modlinkage, modinfop));
    267 }
    268 
    269 /*
    270  * drt_getinfo()
    271  *	provide instance/device information about driver
    272  */
    273 int
    274 drt_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
    275 {
    276 	int error = DDI_SUCCESS;
    277 	switch (cmd) {
    278 	case DDI_INFO_DEVT2DEVINFO:
    279 		/* should make independent of SUNW,pcmcia */
    280 		dip = ddi_find_devinfo("SUNW,pcmcia", getminor((dev_t)arg), 1);
    281 		*result = dip;
    282 		break;
    283 	case DDI_INFO_DEVT2INSTANCE:
    284 		*result = 0;
    285 		break;
    286 	default:
    287 		error = DDI_FAILURE;
    288 		break;
    289 	}
    290 
    291 	return (error);
    292 }
    293 
    294 /*
    295  * drt_attach()
    296  *	attach the DRT (SPARC STP4020) driver
    297  *	to the system.  This is a child of "sysbus" since that is where
    298  *	the hardware lives, but it provides services to the "pcmcia"
    299  *	nexus driver.  It gives a pointer back via its private data
    300  *	structure which contains both the dip and socket services entry
    301  *	points
    302  */
    303 static int
    304 drt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    305 {
    306 	drt_dev_t *drt;
    307 	struct pcmcia_adapter_nexus_private *drt_nexus;
    308 	int i;
    309 	ddi_device_acc_attr_t dev_attr;
    310 	int regs[24];
    311 	int err;
    312 
    313 #if defined(DRT_DEBUG)
    314 	if (drt_debug) {
    315 		cmn_err(CE_CONT, "drt_attach(%d): entered\n", cmd);
    316 	}
    317 #endif
    318 	switch (cmd) {
    319 	default:
    320 		return (DDI_FAILURE);
    321 	case DDI_RESUME:
    322 		drt_nexus = ddi_get_driver_private(dip);
    323 		drt = (drt_dev_t *)drt_get_driver_private(dip);
    324 #if defined(DRT_DEBUG)
    325 		if (drt_debug) {
    326 			cmn_err(CE_CONT, "drt_attach: DDI_RESUME\n");
    327 		}
    328 #endif
    329 		if (drt != NULL && drt->pc_flags & PCF_SUSPENDED) {
    330 			/* XXX - why would drt be NULL?? */
    331 			int sn;
    332 			for (sn = 0; sn < DRSOCKETS; sn++) {
    333 				drt_socket_t *sockp = &drt->pc_sockets[sn];
    334 
    335 			    /* Restore adapter hardware state */
    336 				mutex_enter(&drt->pc_lock);
    337 				drt_cpr(drt, DRT_RESTORE_HW_STATE);
    338 				drt_new_card(drt, sn);
    339 				drt_socket_card_id(drt, sockp,
    340 				    drt->pc_csr->socket[sn].stat0);
    341 				mutex_exit(&drt->pc_lock);
    342 
    343 			} /* for (sn) */
    344 			mutex_enter(&drt->pc_lock);
    345 			drt->pc_flags &= ~PCF_SUSPENDED;
    346 			mutex_exit(&drt->pc_lock);
    347 			/* do we want to do anything here??? */
    348 
    349 			/* this code should do PC Card Standard form */
    350 			(void) pcmcia_begin_resume(dip);
    351 			/*
    352 			 * this will do the CARD_INSERTION
    353 			 * due to needing time for threads to
    354 			 * run, it must be delayed for a short amount
    355 			 * of time.  pcmcia_wait_insert checks for all
    356 			 * children to be removed and then triggers insert.
    357 			 */
    358 			(void) pcmcia_wait_insert(dip);
    359 			/*
    360 			 * for complete implementation need END_RESUME (later)
    361 			 */
    362 			return (DDI_SUCCESS);
    363 		}
    364 		return (DDI_FAILURE);
    365 	case DDI_ATTACH:
    366 		break;
    367 	}
    368 
    369 	drt = (drt_dev_t *)kmem_zalloc(sizeof (drt_dev_t), KM_NOSLEEP);
    370 	if (drt == NULL) {
    371 		return (DDI_FAILURE);
    372 	}
    373 
    374 #if defined(DRT_DEBUG)
    375 	if (drt_debug)
    376 		cmn_err(CE_CONT, "drt_attach: drt=%p\n", (void *)drt);
    377 #endif
    378 	drt_nexus = (struct pcmcia_adapter_nexus_private *)
    379 	    kmem_zalloc(sizeof (struct pcmcia_adapter_nexus_private),
    380 	    KM_NOSLEEP);
    381 	if (drt_nexus == NULL) {
    382 		kmem_free(drt, sizeof (drt_dev_t));
    383 		return (DDI_FAILURE);
    384 	}
    385 	/* map everything in we will ultimately need */
    386 	drt->pc_devinfo = dip;
    387 	drt->pc_csr = 0;
    388 	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    389 	dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
    390 	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    391 	if (ddi_regs_map_setup(dip, DRMAP_ASIC_CSRS, (caddr_t *)&drt->pc_csr,
    392 	    (off_t)0, sizeof (stp4020_socket_csr_t),
    393 	    &dev_attr, &drt->pc_handle) != 0) {
    394 		kmem_free(drt, sizeof (drt_dev_t));
    395 		kmem_free(drt_nexus,
    396 		    sizeof (struct pcmcia_adapter_nexus_private *));
    397 		return (DDI_FAILURE);
    398 	}
    399 #if defined(DRT_DEBUG)
    400 	if (drt_debug) {
    401 		cmn_err(CE_CONT, "drt_attach: %x->%p\n", DRMAP_ASIC_CSRS,
    402 		    (void *)drt->pc_csr);
    403 	}
    404 #endif
    405 
    406 	i = sizeof (regs);
    407 	if ((err = ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
    408 	    DDI_PROP_CANSLEEP, "reg",
    409 	    (caddr_t)regs, &i)) != DDI_SUCCESS) {
    410 
    411 		kmem_free(drt, sizeof (drt_dev_t));
    412 		kmem_free(drt_nexus,
    413 		    sizeof (struct pcmcia_adapter_nexus_private));
    414 		return (DDI_FAILURE);
    415 	}
    416 
    417 
    418 	drt_nexus->an_dip = dip;
    419 	drt_nexus->an_if = &drt_if_ops;
    420 	drt_nexus->an_private = drt;
    421 
    422 	drt->pc_numpower = DRT_NUM_POWER;
    423 	drt->pc_power = drt_power;
    424 
    425 	drt->pc_numsockets = DRSOCKETS;
    426 	drt->pc_flags |= PCF_ATTACHING;
    427 
    428 	ddi_set_driver_private(dip, drt_nexus);
    429 
    430 	/* allow property to override audio */
    431 	if (ddi_getprop(DDI_DEV_T_NONE, dip,
    432 	    DDI_PROP_DONTPASS, "disable-audio", -1) == -1)
    433 		drt->pc_flags |= PCF_AUDIO;
    434 
    435 	/* now enable both interrupt handlers */
    436 	if (ddi_add_intr(dip, 1, &drt->pc_icookie_hi, &drt->pc_dcookie_hi,
    437 	    drt_hi_intr, (caddr_t)dip) != DDI_SUCCESS) {
    438 		/* if it fails, unwind everything */
    439 		ddi_regs_map_free(&drt->pc_handle);
    440 		kmem_free((caddr_t)drt, sizeof (drt_dev_t));
    441 		kmem_free((caddr_t)drt_nexus, sizeof (*drt_nexus));
    442 		return (DDI_FAILURE);
    443 	}
    444 
    445 #if 0
    446 	if (ddi_add_intr(dip, 0, &drt->pc_icookie_lo, &drt->pc_dcookie_lo,
    447 	    drt_lo_intr, (caddr_t)dip) != DDI_SUCCESS) {
    448 		/* if it fails, unwind everything */
    449 		ddi_remove_intr(dip, 0, &drt->pc_icookie_hi);
    450 		ddi_regs_map_free(&drt->pc_handle);
    451 		kmem_free((caddr_t)drt, sizeof (drt_dev_t));
    452 		kmem_free((caddr_t)drt_nexus, sizeof (*drt_nexus));
    453 		return (DDI_FAILURE);
    454 	}
    455 #endif
    456 	mutex_init(&drt->pc_lock, NULL, MUTEX_DRIVER, drt->pc_icookie_hi);
    457 	mutex_init(&drt->pc_intr, NULL, MUTEX_DRIVER, drt->pc_icookie_hi);
    458 
    459 	drt_nexus->an_iblock = &drt->pc_icookie_hi;
    460 	drt_nexus->an_idev = &drt->pc_dcookie_hi;
    461 
    462 	mutex_enter(&drt->pc_lock);
    463 
    464 	for (i = 0; i < DRSOCKETS; i++) {
    465 		struct stpramap *map;
    466 
    467 		drt->pc_csr->socket[i].ctl1 = 0; /* turn things off */
    468 		drt->pc_csr->socket[i].ctl0 = 0; /* before we touch anything */
    469 
    470 		/* work around for false status bugs */
    471 		drt->pc_csr->socket[i].stat1 = 0x3FFF;
    472 		drt->pc_csr->socket[i].stat0 = 0x3FFF;
    473 
    474 		/*
    475 		 * enable the socket as well
    476 		 * want status change interrupts for all possible events
    477 		 * We do this even though CS hasn't asked.  The system
    478 		 * wants to manage these and will only tell CS of those
    479 		 * it asks for
    480 		 */
    481 		/* identify current state of card */
    482 		drt_socket_card_id(drt, &drt->pc_sockets[i],
    483 		    drt->pc_csr->socket[i].stat0);
    484 
    485 		/* finally, turn it on */
    486 		drt->pc_csr->socket[i].ctl0 = DRT_CHANGE_DEFAULT;
    487 
    488 		/* now we need per-socket I/O space allocation */
    489 		map = drt->pc_sockets[i].drt_iomap = stpra_alloc_map();
    490 		map->ra_base = 0;
    491 		map->ra_len = 0xffffff;	/* 1MB */
    492 	}
    493 
    494 	drt_fixprops(dip);
    495 
    496 	/*
    497 	 * now that the adapter is fully operational
    498 	 * it is time to pull in the PCMCIA framework
    499 	 * and let it know we exist and are "ready"
    500 	 */
    501 	mutex_exit(&drt->pc_lock);
    502 	err = pcmcia_attach(dip, drt_nexus);
    503 
    504 	return (err);
    505 }
    506 
    507 /*
    508  * drt_detach()
    509  *	request to detach from the system
    510  */
    511 static int
    512 drt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    513 {
    514 	int i;
    515 	drt_dev_t *drt = (drt_dev_t *)drt_get_driver_private(dip);
    516 
    517 	switch (cmd) {
    518 	case DDI_DETACH:
    519 		if (drt != NULL) {
    520 			/* turn everything off for all sockets and chips */
    521 			for (i = 0; i < drt->pc_numsockets; i++) {
    522 				drt->pc_csr->socket[i].ctl0 = 0;
    523 				drt->pc_csr->socket[i].ctl1 = 0;
    524 			}
    525 			stpra_free_map(drt->pc_sockets[i].drt_iomap);
    526 			ddi_regs_map_free(&drt->pc_handle);
    527 			ddi_remove_intr(dip, 0, drt->pc_icookie_lo);
    528 			ddi_remove_intr(dip, 1, drt->pc_icookie_hi);
    529 			drt->pc_flags = 0;
    530 			mutex_destroy(&drt->pc_lock);
    531 			return (DDI_SUCCESS);
    532 		}
    533 		break;
    534 
    535 	case DDI_PM_SUSPEND:
    536 #if defined(DRT_DEBUG)
    537 		if (drt_debug) {
    538 			cmn_err(CE_WARN, "stp4020: DDI_PM_SUSPEND\n");
    539 		}
    540 #endif
    541 						/*FALLTHROUGH*/
    542 	case DDI_SUSPEND:
    543 #if defined(DRT_DEBUG)
    544 		if (drt_debug) {
    545 			cmn_err(CE_CONT, "drt_detach: DDI_SUSPEND\n");
    546 		}
    547 #endif
    548 		if (drt != NULL) {
    549 			/* XXX - why is this test necessary here? */
    550 			int sn;
    551 			mutex_enter(&drt->pc_lock);
    552 			drt->pc_flags |= PCF_SUSPENDED;
    553 			mutex_exit(&drt->pc_lock);
    554 			for (sn = 0; sn < DRSOCKETS; sn++) {
    555 			    /* drt_stop_intr(drt, sn); XXX ?? */
    556 				mutex_enter(&drt->pc_lock);
    557 				/* clears sockp->drt_flags */
    558 				drt_new_card(drt, sn);
    559 				mutex_exit(&drt->pc_lock);
    560 			}
    561 			/*
    562 			 * Save the adapter's hardware state here
    563 			 */
    564 			mutex_enter(&drt->pc_lock);
    565 			drt_cpr(drt, DRT_SAVE_HW_STATE);
    566 			mutex_exit(&drt->pc_lock);
    567 			return (DDI_SUCCESS);
    568 		} /* if (drt) */
    569 	} /* switch */
    570 	return (DDI_FAILURE);
    571 }
    572 
    573 drt_dev_t *
    574 drt_get_driver_private(dev_info_t *dip)
    575 {
    576 	struct pcmcia_adapter_nexus_private *nexus;
    577 	nexus = ddi_get_driver_private(dip);
    578 	return ((drt_dev_t *)nexus->an_private);
    579 }
    580 
    581 /*
    582  * drt_inquire_adapter()
    583  *	SocketServices InquireAdapter function
    584  *	get characteristics of the physical adapter
    585  */
    586 static int
    587 drt_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
    588 {
    589 	drt_dev_t *drt = drt_get_driver_private(dip);
    590 #if defined(DRT_DEBUG)
    591 	if (drt_debug)
    592 		cmn_err(CE_CONT, "drt_inquire_adapter\n");
    593 #endif
    594 	config->NumSockets = drt->pc_numsockets;
    595 	config->NumWindows = DRT_NUMWINDOWS;
    596 	config->NumEDCs = 0;
    597 	config->AdpCaps = 0;
    598 	config->ActiveHigh = 3;
    599 	config->ActiveLow = 0;
    600 	config->NumPower = drt->pc_numpower;
    601 	config->power_entry = drt->pc_power; /* until we resolve this */
    602 	config->ResourceFlags = RES_OWN_IRQ | RES_OWN_IO | RES_OWN_MEM |
    603 	    RES_IRQ_NEXUS | RES_IRQ_SHAREABLE;
    604 	return (SUCCESS);
    605 }
    606 
    607 /*
    608  * drt_callback()
    609  *	The PCMCIA nexus calls us via this function
    610  *	in order to set the callback function we are
    611  *	to call the nexus with
    612  */
    613 static int
    614 drt_callback(dev_info_t *dip, int (*handler)(), int arg)
    615 {
    616 	drt_dev_t *drt = (drt_dev_t *)drt_get_driver_private(dip);
    617 #if defined(DRT_DEBUG)
    618 	if (drt_debug) {
    619 #ifdef	XXX
    620 		cmn_err(CE_CONT, "drt_callback: drt=%x, lock=%x\n",
    621 		    (int)drt, (int)drt->pc_lock);
    622 #endif
    623 		cmn_err(CE_CONT, "\thandler=%p, arg=%x\n", (void *)handler,
    624 		    arg);
    625 	}
    626 #endif
    627 	if (handler != NULL) {
    628 		drt->pc_callback = handler;
    629 		drt->pc_cb_arg  = arg;
    630 		drt->pc_flags |= PCF_CALLBACK;
    631 	} else {
    632 		drt->pc_callback = NULL;
    633 		drt->pc_cb_arg = 0;
    634 		drt->pc_flags &= ~PCF_CALLBACK;
    635 	}
    636 	/*
    637 	 * we're now registered with the nexus
    638 	 * it is acceptable to do callbacks at this point.
    639 	 * don't call back from here though since it could block
    640 	 */
    641 
    642 	return (PC_SUCCESS);
    643 }
    644 
    645 /*
    646  * drt_calc_speed()
    647  *	determine the bit pattern for speeds to be put in the control register
    648  */
    649 
    650 static int
    651 drt_calc_speed(int speed)
    652 {
    653 	int length;
    654 	int delay;
    655 	/*
    656 	 * the documented speed determination (25MHZ) is
    657 	 * 250 + (CMDLNG - 4) * 40 < speed <= 250 + (CMDLNG - 3) * 40
    658 	 * The value of CMDLNG is roughly determined by
    659 	 * CMDLNG == ((speed - 250) / 40) + [3|4]
    660 	 * the calculation is very approximate.
    661 	 * for speeds <= 250ns, use simple formula
    662 	 *
    663 	 * this should really be based on processor speed.
    664 	 */
    665 
    666 	if (speed <= 250) {
    667 		if (speed < 100)
    668 			speed = 100;
    669 		length = (speed - 100) / 50;
    670 		if (speed <= 100)
    671 			delay = 1;
    672 		else
    673 			delay = 2;
    674 	} else {
    675 		length = ((speed - 250) / 40);
    676 		if ((250 + (length - 3) * 40) == speed)
    677 			length += 3;
    678 		else
    679 			length += 4;
    680 		delay = 2;
    681 	}
    682 
    683 #if defined(DRT_DEBUG)
    684 	if (drt_debug)
    685 		cmn_err(CE_CONT, "drt_calc_speed: speed=%d, length=%x, "
    686 		    "delay=%x, ret=%x\n",
    687 		    speed, length, delay,
    688 		    (SET_DRWIN_CMDDLY(delay) | SET_DRWIN_CMDLNG(length)));
    689 #endif
    690 	return (SET_DRWIN_CMDDLY(delay) | SET_DRWIN_CMDLNG(length));
    691 }
    692 
    693 /*
    694  * drt_set_window
    695  *	essentially the same as the Socket Services specification
    696  *	We use socket and not adapter since they are identifiable
    697  *	but the rest is the same
    698  *
    699  *	dip	drt driver's device information
    700  *	window	parameters for the request
    701  */
    702 static int
    703 drt_set_window(dev_info_t *dip, set_window_t *window)
    704 {
    705 	int prevstate;
    706 	int which, win;
    707 	drt_dev_t *drt = drt_get_driver_private(dip);
    708 	drt_socket_t *sockp;
    709 	struct drt_window *winp;
    710 	stp4020_socket_csr_t *csrp;
    711 	int windex;
    712 
    713 #if defined(DRT_DEBUG)
    714 	if (drt_debug) {
    715 		cmn_err(CE_CONT, "drt_set_window: entered\n");
    716 		cmn_err(CE_CONT,
    717 		    "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
    718 		    window->window, window->socket, window->WindowSize,
    719 		    window->speed);
    720 		cmn_err(CE_CONT,
    721 		    "\tbase=%x, state=%x\n", (int)window->base,
    722 		    window->state);
    723 	}
    724 #endif
    725 
    726 
    727 	/*
    728 	 * do some basic sanity checking on what we support
    729 	 * we don't do paged mode
    730 	 */
    731 	if (window->state & WS_PAGED)
    732 		return (BAD_ATTRIBUTE);
    733 
    734 	/*
    735 	 * make sure we use the correct internal socket/window
    736 	 * combination
    737 	 */
    738 	win = window->window % DRWINDOWS;
    739 	if (window->socket != (window->window / DRWINDOWS)) {
    740 		return (BAD_SOCKET);
    741 	}
    742 
    743 	if (!(window->state & WS_IO) && (window->WindowSize != DRWINSIZE &&
    744 	    !(window->state & WS_EXACT_MAPIN)) ||
    745 	    window->WindowSize > DRWINSIZE) {
    746 #if defined(DRT_DEBUG)
    747 		if (drt_debug)
    748 			cmn_err(CE_CONT, "\tBAD SIZE\n");
    749 #endif
    750 		return (BAD_SIZE);
    751 	}
    752 
    753 	sockp = &drt->pc_sockets[window->socket];
    754 
    755 #if defined(DRT_DEBUG)
    756 	if (drt_debug)
    757 		cmn_err(CE_CONT,
    758 		    "\tusing window/socket %d/%d\n", win, window->socket);
    759 #endif
    760 
    761 	/*
    762 	 * we don't care about previous mappings.
    763 	 * Card Services will deal with that so don't
    764 	 * even check
    765 	 */
    766 
    767 	winp = &sockp->drt_windows[win];
    768 	csrp = &drt->pc_csr->socket[window->socket];
    769 
    770 	mutex_enter(&drt->pc_lock); /* protect the registers */
    771 	prevstate = winp->drtw_flags;
    772 	which = 0;		/* no error */
    773 
    774 	/* disable current settings */
    775 	csrp->window[win].ctl0 = 0;
    776 
    777 	/*
    778 	 * disable current mapping
    779 	 * this will handle the case of WS_ENABLED not being set
    780 	 */
    781 #ifdef notdef
    782 	if ((window->state & (WS_IO|WS_EXACT_MAPIN)) ==
    783 	    (WS_IO|WS_EXACT_MAPIN)) {
    784 		if (window->base.base != 0) {
    785 			/* compensate for having to start at 0 */
    786 			window->WindowSize += (uint32_t)window->base.base;
    787 		}
    788 	}
    789 #endif
    790 
    791 	if (window->socket == 0)
    792 		windex = DRMAP_CARD0_WIN0 + win;
    793 	else
    794 		windex = DRMAP_CARD1_WIN0 + win;
    795 
    796 	if ((prevstate & DRW_MAPPED) &&
    797 	    (window->WindowSize != winp->drtw_len)) {
    798 		mutex_exit(&drt->pc_lock);
    799 		ddi_regs_map_free(&winp->drtw_handle);
    800 		mutex_enter(&drt->pc_lock);
    801 #if defined(DRT_DEBUG)
    802 		if (drt_debug)
    803 			cmn_err(CE_CONT,
    804 			    "\tunmapped: base being set to NULL\n");
    805 #endif
    806 		winp->drtw_flags &= ~(DRW_MAPPED|DRW_ENABLED);
    807 		if (prevstate & DRW_IO) {
    808 			stpra_free(&sockp->drt_iomap,
    809 			    (uint32_t)(uintptr_t)winp->drtw_reqaddr,
    810 			    (uint32_t)winp->drtw_len);
    811 		}
    812 		winp->drtw_base = NULL;
    813 	}
    814 
    815 	if (window->state & WS_ENABLED) {
    816 		if (winp->drtw_base == NULL) {
    817 			if (window->state & WS_IO) {
    818 				stpra_request_t req;
    819 				stpra_return_t ret;
    820 				bzero((caddr_t)&req, sizeof (req));
    821 				bzero((caddr_t)&ret, sizeof (ret));
    822 				req.ra_flags = STP_RA_ALLOC_POW2 |
    823 				    STP_RA_ALIGN_SIZE;
    824 				req.ra_len = window->WindowSize;
    825 				req.ra_addr_lo = window->base;
    826 
    827 				if (window->base != 0)
    828 					req.ra_flags |= STP_RA_ALLOC_SPECIFIED;
    829 
    830 				if (stpra_alloc(&sockp->drt_iomap,
    831 				    &req, &ret) != DDI_SUCCESS) {
    832 					mutex_exit(&drt->pc_lock);
    833 					return (BAD_BASE);
    834 				}
    835 				/* now use the resultant address */
    836 				window->base = ret.ra_addr_lo;
    837 			}
    838 			mutex_exit(&drt->pc_lock);
    839 			which = ddi_regs_map_setup(drt->pc_devinfo,
    840 			    windex,
    841 			    &winp->drtw_base,
    842 			    (offset_t)window->base,
    843 			    window->WindowSize,
    844 			    &window->attr,
    845 			    &winp->drtw_handle);
    846 			mutex_enter(&drt->pc_lock);
    847 			if (which != DDI_SUCCESS) {
    848 				mutex_exit(&drt->pc_lock);
    849 				return (BAD_SIZE);
    850 			}
    851 #if defined(DRT_DEBUG)
    852 			if (drt_debug)
    853 				cmn_err(CE_CONT,
    854 				    "\tmapped: handle = 0x%p base = %p, "
    855 				    "len=%x\n",
    856 				    (void *)winp->drtw_handle,
    857 				    (void *)winp->drtw_base,
    858 				    (int)window->WindowSize);
    859 #endif
    860 		}
    861 		winp->drtw_reqaddr = (caddr_t)(uintptr_t)window->base;
    862 		winp->drtw_flags |= DRW_MAPPED | DRW_ENABLED;
    863 
    864 		if (!(window->state & WS_IO)) {
    865 			winp->drtw_speed = window->speed;
    866 			winp->drtw_ctl0 = drt_calc_speed(window->speed);
    867 			winp->drtw_ctl0 |= DRWIN_ASPSEL_CM;
    868 			winp->drtw_flags &= ~DRW_IO;
    869 		} else {
    870 			winp->drtw_flags |= DRW_IO;
    871 			winp->drtw_ctl0 = DRWIN_ASPSEL_IO |
    872 			    drt_calc_speed(window->speed);
    873 			winp->drtw_modhandle.ah_addr +=	(int)window->base;
    874 		}
    875 		window->handle = winp->drtw_handle;
    876 		csrp->window[win].ctl0 = winp->drtw_ctl0;
    877 		csrp->window[win].ctl1 = SET_DRWIN_WAITREQ(1) |
    878 		    SET_DRWIN_WAITDLY(0);
    879 		winp->drtw_len = window->WindowSize;
    880 	} else {
    881 		if (winp->drtw_flags & DRW_ENABLED) {
    882 			winp->drtw_flags &= ~DRW_ENABLED;
    883 			csrp->window[win].ctl0 = 0; /* force off */
    884 #ifdef	XXX
    885 			if (prevstate & DRW_IO) {
    886 				stpra_free(&sockp->drt_iomap,
    887 				    (uint32_t)winp->drtw_reqaddr,
    888 				    (uint32_t)winp->drtw_len);
    889 			}
    890 #endif	/* XXX */
    891 		}
    892 		winp->drtw_base = NULL;
    893 	}
    894 
    895 #if defined(DRT_DEBUG)
    896 	if (drt_debug) {
    897 		cmn_err(CE_CONT,
    898 		    "\tbase now set to %p (->%p), csrp=%p, winreg=%p"
    899 		    ", len=%x\n",
    900 		    (void *)window->handle,
    901 		    (void *)winp->drtw_base, (void *)csrp,
    902 		    (void *)&csrp->window[win].ctl0,
    903 		    (int)window->WindowSize);
    904 		cmn_err(CE_CONT,
    905 		    "\twindow type is now %s\n", window->state & WS_IO ?
    906 		    "I/O" : "memory");
    907 		if (drt_debug > 1)
    908 			drt_dmp_regs(csrp);
    909 	}
    910 #endif
    911 
    912 	mutex_exit(&drt->pc_lock);
    913 
    914 	return (SUCCESS);
    915 }
    916 
    917 /*
    918  * drt_card_state()
    919  *	compute the instantaneous Card State information
    920  */
    921 int
    922 drt_card_state(drt_dev_t *drt, int socket)
    923 {
    924 	int value, result;
    925 
    926 	mutex_enter(&drt->pc_lock); /* protect the registers */
    927 
    928 	value = drt->pc_csr->socket[socket].stat0;
    929 #if defined(DRT_DEBUG)
    930 	if (drt_debug) {
    931 		cmn_err(CE_CONT, "drt_card_state: socket=%d, *lock=%p\n",
    932 		    socket, (void *)&drt->pc_lock);
    933 		cmn_err(CE_CONT, "\tcsr@%p\n", (void *)drt->pc_csr);
    934 
    935 		cmn_err(CE_CONT, "\tstat0=%b\n", value,
    936 		    "\020\1PWRON\2WAIT\3WP\4RDYBSY\5BVD1\6BVD2\7CD1"
    937 		    "\10CD2\011ACCTO\012WPC\013RBC\014BVD1C\015BVD2C"
    938 		    "\016CDSC\017STAT");
    939 		cmn_err(CE_CONT,
    940 		    "\tstat1=%x\n",
    941 		    (int)drt->pc_csr->socket[socket].stat1);
    942 		cmn_err(CE_CONT, "\t&stat0=%p, &stat1=%p\n",
    943 		    (void *)&drt->pc_csr->socket[socket].stat0,
    944 		    (void *)&drt->pc_csr->socket[socket].stat1);
    945 	}
    946 #endif
    947 
    948 	if (value & DRSTAT_WPST)
    949 		result = SBM_WP;
    950 	else
    951 		result = 0;
    952 
    953 	switch (value & DRSTAT_BVDST) {
    954 	case DRSTAT_BATT_LOW:
    955 		result |= SBM_BVD2;
    956 		break;
    957 	case DRSTAT_BATT_OK:
    958 		break;
    959 	default:
    960 		/* battery dead */
    961 		result |= SBM_BVD1;
    962 		break;
    963 	}
    964 
    965 	if (value & DRSTAT_RDYST)
    966 		result |= SBM_RDYBSY;
    967 	if ((value & (DRSTAT_CD1ST|DRSTAT_CD2ST)) ==
    968 	    (DRSTAT_CD1ST|DRSTAT_CD2ST))
    969 		result |= SBM_CD;
    970 
    971 	mutex_exit(&drt->pc_lock);
    972 
    973 	return (result);
    974 }
    975 
    976 /*
    977  * drt_set_page()
    978  *	SocketServices SetPage function
    979  *	set the page of PC Card memory that should be in the mapped
    980  *	window
    981  */
    982 
    983 int
    984 drt_set_page(dev_info_t *dip, set_page_t *page)
    985 {
    986 	int which, socket, win;
    987 	drt_dev_t *drt = drt_get_driver_private(dip);
    988 	drt_socket_t *sockp;
    989 	struct drt_window *winp;
    990 	stp4020_socket_csr_t *csrp;
    991 
    992 	if (page->window >= DRT_NUMWINDOWS) {
    993 #if defined(DRT_DEBUG)
    994 		if (drt_debug)
    995 			cmn_err(CE_CONT, "drt_set_page: window=%d (%d)\n",
    996 			    page->window, DRWINDOWS);
    997 #endif
    998 		return (BAD_WINDOW);
    999 	}
   1000 
   1001 	win = page->window % DRWINDOWS;
   1002 	socket = page->window / DRWINDOWS;
   1003 
   1004 	sockp = &drt->pc_sockets[socket];
   1005 
   1006 #if defined(DRT_DEBUG)
   1007 	if (drt_debug) {
   1008 		cmn_err(CE_CONT,
   1009 		    "drt_set_page: window=%d, socket=%d, page=%d\n",
   1010 		    win, socket, page->page);
   1011 	}
   1012 #endif
   1013 
   1014 	/* only one page supported (fixed at 1MB) */
   1015 #if defined(DRT_DEBUG)
   1016 	if (drt_debug)
   1017 		cmn_err(CE_CONT, "\tpage=%d\n", page->page);
   1018 #endif
   1019 	winp = &sockp->drt_windows[win];
   1020 	csrp = &drt->pc_csr->socket[socket];
   1021 
   1022 	if (winp->drtw_flags & DRW_IO) {
   1023 		return (BAD_WINDOW);
   1024 	}
   1025 
   1026 	if (page->page != 0) {
   1027 		return (BAD_PAGE);
   1028 	}
   1029 
   1030 	mutex_enter(&drt->pc_lock); /* protect the registers */
   1031 
   1032 	/*
   1033 	 * now map the card's memory pages - we start with page 0
   1034 	 */
   1035 
   1036 	if (page->state & PS_ATTRIBUTE) {
   1037 		which = SET_DRWIN_CMDDLY(2) | SET_DRWIN_CMDLNG(4);
   1038 		winp->drtw_flags |= DRW_ATTRIBUTE;
   1039 	} else {
   1040 		which = winp->drtw_ctl0 & (DRWIN_CMDLNG_M|DRWIN_CMDDLY_M);
   1041 		winp->drtw_flags &= ~DRW_ATTRIBUTE;
   1042 	}
   1043 
   1044 	which |= (page->state & PS_ATTRIBUTE) ?
   1045 	    DRWIN_ASPSEL_AM : DRWIN_ASPSEL_CM;
   1046 
   1047 	/* if card says Write Protect, enforce it */
   1048 	/* but we don't have hardware support to do it */
   1049 
   1050 	/* The actual PC Card address mapping */
   1051 #if defined(DRT_DEBUG)
   1052 	if (drt_debug)
   1053 		cmn_err(CE_CONT, "\ta2p=%x, base=%x, csrp=%p\n",
   1054 		    (int)ADDR2PAGE(page->offset),
   1055 		    SET_DRWIN_BASE(ADDR2PAGE(page->offset)),
   1056 		    (void *)csrp);
   1057 #endif
   1058 	which |= SET_DRWIN_BASE(ADDR2PAGE(page->offset));
   1059 	winp->drtw_addr = (caddr_t)page->offset;
   1060 
   1061 	/* now set the register */
   1062 #if defined(DRT_DEBUG)
   1063 	if (drt_debug)
   1064 		cmn_err(CE_CONT, "\tset ctl0=%x\n", which);
   1065 #endif
   1066 
   1067 	csrp->window[win].ctl0 = (ushort_t)which;
   1068 	csrp->window[win].ctl1 = SET_DRWIN_WAITREQ(1) | SET_DRWIN_WAITDLY(0);
   1069 
   1070 	/* now  */
   1071 
   1072 #if defined(DRT_DEBUG)
   1073 	if (drt_debug) {
   1074 		cmn_err(CE_CONT, "\tmemory type = %s\n",
   1075 		    (which & DRWIN_ASPSEL_CM) ? "common" : "attribute");
   1076 	}
   1077 #endif
   1078 
   1079 
   1080 #if defined(DRT_DEBUG)
   1081 	if (drt_debug) {
   1082 		cmn_err(CE_CONT,
   1083 		    "\tpage offset=%x, base=%p (PC addr=%p, sockets=%d)\n",
   1084 		    (int)page->offset, (void *)winp->drtw_base,
   1085 		    (void *)winp->drtw_addr, drt->pc_numsockets);
   1086 		cmn_err(CE_CONT, "\t*base=%x, win reg=%p\n",
   1087 		    *(ushort_t *)winp->drtw_base,
   1088 		    (void *)&csrp->window[win].ctl0);
   1089 		if (drt_debug > 1)
   1090 			drt_dmp_regs(csrp);
   1091 	}
   1092 #endif
   1093 	mutex_exit(&drt->pc_lock);
   1094 
   1095 	return (SUCCESS);
   1096 }
   1097 
   1098 /*
   1099  * drt_set_socket()
   1100  *	Socket Services SetSocket call
   1101  *	sets basic socket configuration
   1102  */
   1103 static int
   1104 drt_set_socket(dev_info_t *dip, set_socket_t *socket)
   1105 {
   1106 	int value, sock;
   1107 	drt_dev_t *drt = drt_get_driver_private(dip);
   1108 	drt_socket_t *sockp = &drt->pc_sockets[socket->socket];
   1109 	int irq = 0;
   1110 	int powerlevel = 0;
   1111 	int ind;
   1112 
   1113 	sock = socket->socket;
   1114 
   1115 #if defined(DRT_DEBUG)
   1116 	if (drt_debug) {
   1117 		cmn_err(CE_CONT, "drt_set_socket: entered (socket=%d)\n", sock);
   1118 	}
   1119 #endif
   1120 	/*
   1121 	 * check VccLevel, etc. before setting mutex
   1122 	 * if this is zero, power is being turned off
   1123 	 * if it is non-zero, power is being turned on.
   1124 	 * the default case is to assume Vcc only.
   1125 	 */
   1126 
   1127 	/* this appears to be very implementation specific */
   1128 
   1129 	if (socket->VccLevel == 0) {
   1130 		powerlevel = 0;
   1131 	} else  if (socket->VccLevel < drt->pc_numpower &&
   1132 	    drt_power[socket->VccLevel].ValidSignals & VCC) {
   1133 		/* enable Vcc */
   1134 		powerlevel = DRCTL_MSTPWR|DRCTL_PCIFOE;
   1135 		sockp->drt_vcc = socket->VccLevel;
   1136 	} else {
   1137 		return (BAD_VCC);
   1138 	}
   1139 #if defined(DRT_DEBUG)
   1140 	if (drt_debug) {
   1141 		cmn_err(CE_CONT, "\tVccLevel=%d, Vpp1Level=%d, Vpp2Level=%d\n",
   1142 		    socket->VccLevel,
   1143 		    socket->Vpp1Level, socket->Vpp2Level);
   1144 	}
   1145 #endif
   1146 	ind = 0;		/* default index to 0 power */
   1147 	if (socket->Vpp1Level >= 0 && socket->Vpp1Level < drt->pc_numpower) {
   1148 		if (!(drt_power[socket->Vpp1Level].ValidSignals & VPP1)) {
   1149 			return (BAD_VPP);
   1150 		}
   1151 		ind = drt_power[socket->Vpp1Level].PowerLevel/10;
   1152 		powerlevel |= drt_vpp_levels[ind] << 2;
   1153 		sockp->drt_vpp1 = socket->Vpp1Level;
   1154 	}
   1155 	if (socket->Vpp2Level >= 0 && socket->Vpp2Level < drt->pc_numpower) {
   1156 		if (!(drt_power[socket->Vpp2Level].ValidSignals & VPP2)) {
   1157 			return (BAD_VPP);
   1158 		}
   1159 		ind = drt_power[socket->Vpp2Level].PowerLevel/10;
   1160 		powerlevel |= (drt_vpp_levels[ind] << 4);
   1161 		sockp->drt_vpp2 = socket->Vpp2Level;
   1162 	}
   1163 
   1164 #if defined(DRT_DEBUG)
   1165 	if (drt_debug) {
   1166 		cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n", powerlevel, ind);
   1167 	}
   1168 #endif
   1169 	mutex_enter(&drt->pc_lock); /* protect the registers */
   1170 
   1171 	/* make sure not still in RESET */
   1172 	value = drt->pc_csr->socket[sock].ctl0;
   1173 	drt->pc_csr->socket[sock].ctl0 = value & ~DRCTL_RESET;
   1174 	/*
   1175 	 * ctlind processing -- we can ignore this
   1176 	 * there aren't any outputs on the chip for this
   1177 	 * the GUI will display what it thinks is correct
   1178 	 */
   1179 
   1180 
   1181 	/* handle event mask */
   1182 	sockp->drt_intmask = socket->SCIntMask;
   1183 	value = (drt->pc_csr->socket[sock].ctl0 & ~DRT_CHANGE_MASK) |
   1184 	    DRT_CHANGE_DEFAULT; /* always want CD */
   1185 
   1186 	if (socket->SCIntMask & SBM_CD)
   1187 		value |= DRCTL_CDIE;
   1188 	if (socket->SCIntMask & SBM_BVD1)
   1189 		value |= DRCTL_BVD1IE;
   1190 	if (socket->SCIntMask & SBM_BVD2)
   1191 		value |= DRCTL_BVD2IE;
   1192 	if (socket->SCIntMask & SBM_WP)
   1193 		value |= DRCTL_WPIE;
   1194 	if (socket->SCIntMask & SBM_RDYBSY)
   1195 		value |= DRCTL_RDYIE;
   1196 	/* irq processing */
   1197 	if (socket->IFType == IF_IO) {
   1198 				/* IRQ only for I/O */
   1199 		irq = socket->IREQRouting & 0xF;
   1200 		if (socket->IREQRouting & IRQ_ENABLE) {
   1201 			irq = DRCTL_IOIE;
   1202 #if 0
   1203 			if (socket->IREQRouting & IRQ_PRIORITY) {
   1204 				irq |= DRCTL_IOILVL_SB1;
   1205 				sockp->drt_flags |= DRT_INTR_HIPRI;
   1206 			} else {
   1207 				irq |= DRCTL_IOILVL_SB0;
   1208 			}
   1209 #else
   1210 			irq |= DRCTL_IOILVL_SB1;
   1211 			sockp->drt_flags |= DRT_INTR_HIPRI;
   1212 #endif
   1213 			sockp->drt_flags |= DRT_INTR_ENABLED;
   1214 		} else {
   1215 			irq = 0; /* no interrupts */
   1216 			sockp->drt_flags &= ~(DRT_INTR_ENABLED|DRT_INTR_HIPRI);
   1217 		}
   1218 		sockp->drt_irq = socket->IREQRouting;
   1219 
   1220 #if defined(DRT_DEBUG)
   1221 		if (drt_debug) {
   1222 			cmn_err(CE_CONT,
   1223 			    "\tsocket type is I/O and irq %x is %s\n", irq,
   1224 			    (socket->IREQRouting & IRQ_ENABLE) ?
   1225 			    "enabled" : "not enabled");
   1226 		}
   1227 #endif
   1228 		sockp->drt_flags |= DRT_SOCKET_IO;
   1229 		if (drt->pc_flags & PCF_AUDIO)
   1230 			value |= DRCTL_IFTYPE_IO | irq | DRCTL_SPKREN;
   1231 		else
   1232 			value |= DRCTL_IFTYPE_IO | irq;
   1233 	} else {
   1234 		/* enforce memory mode */
   1235 		value &= ~(DRCTL_IFTYPE_IO | DRCTL_SPKREN |
   1236 		    DRCTL_IOILVL_SB1 | DRCTL_IOILVL_SB0 |
   1237 		    DRCTL_IOIE);
   1238 		sockp->drt_flags &= ~(DRT_INTR_ENABLED|DRT_SOCKET_IO);
   1239 	}
   1240 	drt->pc_csr->socket[sock].ctl0 = (ushort_t)value;
   1241 
   1242 	/*
   1243 	 * set power to socket
   1244 	 * note that the powerlevel was calculated earlier
   1245 	 */
   1246 
   1247 	drt->pc_csr->socket[sock].ctl1 = (ushort_t)powerlevel;
   1248 #if defined(DRT_DEBUG)
   1249 	if (drt_debug) {
   1250 		cmn_err(CE_CONT,
   1251 		    "\tpowerlevel (socket->ctl1) = %x\n", powerlevel);
   1252 		if (drt_debug > 1)
   1253 			drt_dmp_regs(&drt->pc_csr->socket[sock]);
   1254 	}
   1255 #endif
   1256 	sockp->drt_state &= ~socket->State;
   1257 	mutex_exit(&drt->pc_lock);
   1258 	return (SUCCESS);
   1259 }
   1260 
   1261 /*
   1262  * drt_inquire_socket()
   1263  *	SocketServices InquireSocket function
   1264  *	returns basic characteristics of the socket
   1265  */
   1266 static int
   1267 drt_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
   1268 {
   1269 	int value;
   1270 	drt_dev_t *drt = drt_get_driver_private(dip);
   1271 
   1272 	socket->SCIntCaps = DRT_DEFAULT_INT_CAPS;
   1273 	socket->SCRptCaps = DRT_DEFAULT_RPT_CAPS;
   1274 	socket->CtlIndCaps = DRT_DEFAULT_CTL_CAPS;
   1275 	value = drt->pc_sockets[socket->socket].drt_flags;
   1276 	socket->SocketCaps = IF_IO | IF_MEMORY;
   1277 	socket->ActiveHigh = 3;	/* 0 and 1 */
   1278 	socket->ActiveLow = 0;
   1279 
   1280 #ifdef	lint
   1281 	if (value > 0)
   1282 		panic("lint panic");
   1283 #endif
   1284 
   1285 	return (SUCCESS);
   1286 }
   1287 
   1288 /*
   1289  * drt_inquire_window()
   1290  *	SocketServices InquireWindow function
   1291  *	returns detailed characteristics of the window
   1292  *	this is where windows get tied to sockets
   1293  */
   1294 static int
   1295 drt_inquire_window(dev_info_t *dip, inquire_window_t *window)
   1296 {
   1297 	int socket, win;
   1298 	drt_dev_t *drt = drt_get_driver_private(dip);
   1299 	struct drt_window *winp;
   1300 	iowin_char_t *io;
   1301 	mem_win_char_t *mem;
   1302 
   1303 #if defined(DRT_DEBUG)
   1304 	if (drt_debug)
   1305 		cmn_err(CE_CONT,
   1306 		    "drt_inquire_window: win=%d\n", window->window);
   1307 #endif
   1308 	window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT|WC_IO;
   1309 
   1310 	/* get correct socket */
   1311 	socket = window->window / DRWINDOWS;
   1312 	win = window->window % DRWINDOWS;
   1313 	winp = &drt->pc_sockets[socket].drt_windows[win];
   1314 	/* initialize the socket map - one socket per window */
   1315 	PR_ZERO(window->Sockets);
   1316 	PR_SET(window->Sockets, socket);
   1317 
   1318 	io = &window->iowin_char;
   1319 	io->IOWndCaps = WC_CALIGN|WC_IO_RANGE_PER_WINDOW|WC_WENABLE|
   1320 	    WC_8BIT|WC_16BIT|WC_SIZE;
   1321 	io->FirstByte = (baseaddr_t)winp->drtw_base;
   1322 	io->LastByte = (baseaddr_t)winp->drtw_base + DRWINSIZE;
   1323 	io->MinSize = 1;
   1324 	io->MaxSize = DRWINSIZE;
   1325 	io->ReqGran = ddi_ptob(dip, 1);
   1326 	io->AddrLines = DRADDRLINES;
   1327 	io->EISASlot = 0;
   1328 
   1329 	mem = &window->mem_win_char;
   1330 	mem->MemWndCaps = WC_CALIGN|WC_WENABLE|WC_8BIT|WC_16BIT;
   1331 	mem->FirstByte = (baseaddr_t)winp->drtw_base;
   1332 	mem->LastByte = (baseaddr_t)winp->drtw_base + DRWINSIZE;
   1333 #if defined(DRT_DEBUG)
   1334 	if (drt_debug) {
   1335 		cmn_err(CE_CONT, "\tFirstByte=%p, LastByte=%p\n",
   1336 		    (void *)mem->FirstByte, (void *)mem->LastByte);
   1337 	}
   1338 #endif
   1339 	mem->MinSize = DRWINSIZE;
   1340 	mem->MaxSize = DRWINSIZE;
   1341 	mem->ReqGran = ddi_ptob(dip, 1L);
   1342 	mem->ReqBase = 0;
   1343 	mem->ReqOffset = DRWINSIZE;
   1344 	mem->Slowest = MEM_SPEED_MAX;
   1345 	mem->Fastest = MEM_SPEED_MIN;
   1346 
   1347 	return (SUCCESS);
   1348 }
   1349 
   1350 /*
   1351  * drt_get_adapter()
   1352  *	SocketServices GetAdapter function
   1353  *	this is nearly a no-op.
   1354  */
   1355 static int
   1356 drt_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
   1357 {
   1358 	drt_dev_t *drt = drt_get_driver_private(dip);
   1359 
   1360 	if (drt->pc_flags & PCF_INTRENAB)
   1361 		adapt->SCRouting = IRQ_ENABLE;
   1362 	adapt->state = 0;
   1363 	return (SUCCESS);
   1364 }
   1365 
   1366 /*
   1367  * drt_get_page()
   1368  *	SocketServices GetPage function
   1369  *	returns info about the window
   1370  */
   1371 static int
   1372 drt_get_page(dev_info_t *dip, get_page_t *page)
   1373 {
   1374 	int socket, window;
   1375 	drt_dev_t *drt = drt_get_driver_private(dip);
   1376 	struct drt_window *winp;
   1377 
   1378 	window = page->window % DRWINDOWS;
   1379 	socket = page->window / DRWINDOWS;
   1380 
   1381 	winp = &drt->pc_sockets[socket].drt_windows[window];
   1382 
   1383 	if (page->page > 0)
   1384 		return (BAD_PAGE);
   1385 
   1386 	page->state = 0;
   1387 
   1388 	if (winp->drtw_flags & DRW_IO)
   1389 		page->state |= PS_IO;
   1390 
   1391 	if (winp->drtw_flags & DRW_ENABLED)
   1392 		page->state |= PS_ENABLED;
   1393 
   1394 	if (winp->drtw_flags & DRW_ATTRIBUTE)
   1395 		page->state |= PS_ATTRIBUTE;
   1396 
   1397 	page->offset = (off_t)winp->drtw_addr;
   1398 
   1399 	return (SUCCESS);
   1400 }
   1401 
   1402 /*
   1403  * drt_get_socket()
   1404  *	SocketServices GetSocket
   1405  *	returns information about the current socket settings
   1406  */
   1407 static int
   1408 drt_get_socket(dev_info_t *dip, get_socket_t *socket)
   1409 {
   1410 	int socknum, irq_enabled;
   1411 	drt_socket_t *sockp;
   1412 	drt_dev_t *drt = drt_get_driver_private(dip);
   1413 
   1414 	socknum = socket->socket;
   1415 	sockp = &drt->pc_sockets[socknum];
   1416 
   1417 	socket->SCIntMask = sockp->drt_intmask;
   1418 	socket->state = sockp->drt_state;
   1419 	socket->VccLevel = sockp->drt_vcc;
   1420 	socket->Vpp1Level = sockp->drt_vpp1;
   1421 	socket->Vpp2Level = sockp->drt_vpp2;
   1422 	socket->CtlInd = 0;	/* no indicators */
   1423 	irq_enabled = (sockp->drt_flags & DRT_INTR_ENABLED) ? IRQ_ENABLE : 0;
   1424 #if 0
   1425 	irq_enabled |= (sockp->drt_flags & DRT_INTR_HIPRI) ? IRQ_HIGH : 0;
   1426 #endif
   1427 	socket->IRQRouting = sockp->drt_irq | irq_enabled;
   1428 	socket->IFType = (sockp->drt_flags & DRT_SOCKET_IO) ? IF_IO : IF_MEMORY;
   1429 	return (SUCCESS);
   1430 }
   1431 
   1432 /*
   1433  * drt_get_status()
   1434  *	SocketServices GetStatus
   1435  *	returns status information about the PC Card in
   1436  *	the selected socket
   1437  */
   1438 static int
   1439 drt_get_status(dev_info_t *dip, get_ss_status_t *status)
   1440 {
   1441 	int socknum, irq_enabled;
   1442 	drt_socket_t *sockp;
   1443 	drt_dev_t *drt = drt_get_driver_private(dip);
   1444 #if defined(DRT_DEBUG)
   1445 	if (drt_debug) {
   1446 		cmn_err(CE_CONT, "drt_get_status: drt=%p\n", (void *)drt);
   1447 	}
   1448 #endif
   1449 
   1450 	if (drt == NULL) {
   1451 		return (BAD_ADAPTER);
   1452 	}
   1453 
   1454 	socknum = status->socket;
   1455 	sockp = &drt->pc_sockets[socknum];
   1456 
   1457 	status->CardState = drt_card_state(drt, socknum);
   1458 	status->SocketState = sockp->drt_state;
   1459 	status->CtlInd = 0;	/* no indicators */
   1460 	irq_enabled = (sockp->drt_flags & DRT_INTR_ENABLED) ? IRQ_ENABLE : 0;
   1461 	status->IRQRouting = sockp->drt_irq | irq_enabled;
   1462 	status->IFType = (sockp->drt_flags & DRT_SOCKET_IO) ?
   1463 	    IF_IO : IF_MEMORY;
   1464 	return (SUCCESS);
   1465 }
   1466 
   1467 /*
   1468  * drt_get_window()
   1469  *	SocketServices GetWindow function
   1470  *	returns state information about the specified window
   1471  */
   1472 static int
   1473 drt_get_window(dev_info_t *dip, get_window_t *window)
   1474 {
   1475 	int socket, win;
   1476 	drt_socket_t *sockp;
   1477 	drt_dev_t *drt = drt_get_driver_private(dip);
   1478 	struct drt_window *winp;
   1479 
   1480 	if (window->window >= DRT_NUMWINDOWS) {
   1481 #if defined(DRT_DEBUG)
   1482 		if (drt_debug)
   1483 			cmn_err(CE_CONT, "drt_get_window: failed\n");
   1484 #endif
   1485 		return (BAD_WINDOW);
   1486 	}
   1487 	socket = window->window / DRWINDOWS;
   1488 	win = window->window % DRWINDOWS;
   1489 	window->socket = socket;
   1490 	sockp = &drt->pc_sockets[socket];
   1491 	winp = &sockp->drt_windows[win];
   1492 
   1493 	window->size = winp->drtw_len;
   1494 	window->speed = winp->drtw_speed;
   1495 	window->base = (uint32_t)(uintptr_t)winp->drtw_reqaddr;
   1496 	window->handle = winp->drtw_handle;
   1497 	window->state = 0;
   1498 
   1499 	if (winp->drtw_flags & DRW_IO)
   1500 		window->state |= WS_IO;
   1501 
   1502 	if (winp->drtw_flags & DRW_ENABLED)
   1503 		window->state |= WS_ENABLED;
   1504 #if defined(DRT_DEBUG)
   1505 	if (drt_debug) {
   1506 		cmn_err(CE_CONT,
   1507 		    "drt_get_window: socket=%d, window=%d\n", socket, win);
   1508 		cmn_err(CE_CONT,
   1509 		    "\tsize=%d, speed=%d, base=%x, state=%x\n",
   1510 		    window->size, (int)window->speed,
   1511 		    (int)window->base,
   1512 		    window->state);
   1513 	}
   1514 #endif
   1515 
   1516 	return (SUCCESS);
   1517 }
   1518 
   1519 /*
   1520  * drt_ll_reset - This function handles the socket RESET signal timing and
   1521  *			control.
   1522  *
   1523  *	There are two variables that control the RESET timing:
   1524  *		drt_prereset_time - time in mS before asserting RESET
   1525  *		drt_reset_time - time in mS to assert RESET
   1526  *
   1527  * XXX - need to rethink RESET timing delays to avoid using drv_usecwait
   1528  */
   1529 int drt_prereset_time = 1;
   1530 int drt_reset_time = 5;
   1531 
   1532 static void
   1533 drt_ll_reset(drt_dev_t *drt, int socket)
   1534 {
   1535 	uint32_t value;
   1536 
   1537 	value = drt->pc_csr->socket[socket].ctl0;
   1538 
   1539 	if (drt_prereset_time > 0)
   1540 		drv_usecwait(drt_prereset_time * 1000);
   1541 
   1542 	/* turn reset on then off again */
   1543 	drt->pc_csr->socket[socket].ctl0 = value | DRCTL_RESET;
   1544 
   1545 	if (drt_reset_time > 0)
   1546 		drv_usecwait(drt_reset_time * 1000);
   1547 
   1548 	drt->pc_csr->socket[socket].ctl0 = value & ~DRCTL_RESET;
   1549 
   1550 #if defined(DRT_DEBUG)
   1551 	if (drt_debug)
   1552 		cmn_err(CE_CONT, "drt_ll_reset: socket=%d, ctl0=%x, ctl1=%x\n",
   1553 		    socket,
   1554 		    drt->pc_csr->socket[socket].ctl0,
   1555 		    drt->pc_csr->socket[socket].ctl1);
   1556 #endif
   1557 }
   1558 
   1559 /*
   1560  * drt_new_card()
   1561  *	put socket into known state on card insertion
   1562  */
   1563 static void
   1564 drt_new_card(drt_dev_t *drt, int socket)
   1565 {
   1566 	drt->pc_csr->socket[socket].ctl0 = 0; /* off */
   1567 	drt->pc_csr->socket[socket].ctl0 = DRT_CHANGE_DEFAULT; /* on */
   1568 	drt->pc_csr->socket[socket].ctl1 = 0;
   1569 	drt->pc_sockets[socket].drt_state = 0;
   1570 	drt->pc_sockets[socket].drt_flags = 0;
   1571 }
   1572 
   1573 /*
   1574  * drt_reset_socket()
   1575  *	SocketServices ResetSocket function
   1576  *	puts the PC Card in the socket into the RESET state
   1577  *	and then takes it out after the the cycle time
   1578  *	The socket is back to initial state when done
   1579  */
   1580 static int
   1581 drt_reset_socket(dev_info_t *dip, int socket, int mode)
   1582 {
   1583 	drt_dev_t *drt = drt_get_driver_private(dip);
   1584 	int window;
   1585 	drt_socket_t *sockp;
   1586 
   1587 	mutex_enter(&drt->pc_lock); /* protect the registers */
   1588 
   1589 	drt_ll_reset(drt, socket);
   1590 
   1591 	if (mode == RESET_MODE_FULL) {
   1592 		/* need to unmap windows, etc. */
   1593 
   1594 		drt->pc_sockets[socket].drt_state = 0;
   1595 
   1596 		for (window = 0, sockp = &drt->pc_sockets[socket];
   1597 		    window < DRT_NUMWINDOWS; window++) {
   1598 			sockp->drt_windows[window].drtw_flags &= ~DRW_ENABLED;
   1599 		}
   1600 	}
   1601 
   1602 	mutex_exit(&drt->pc_lock);
   1603 	return (SUCCESS);
   1604 }
   1605 
   1606 /*
   1607  * drt_set_interrupt()
   1608  *	SocketServices SetInterrupt function
   1609  */
   1610 static int
   1611 drt_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
   1612 {
   1613 	inthandler_t *intr;
   1614 	drt_dev_t *drt = drt_get_driver_private(dip);
   1615 
   1616 #if defined(DRT_DEBUG)
   1617 	if (drt_debug)
   1618 		cmn_err(CE_CONT, "drt_set_interrupt(%p, %p) pc_handlers=%p\n",
   1619 		    (void *)dip, (void *)handler, (void *)drt->pc_handlers);
   1620 #endif
   1621 
   1622 	intr = (inthandler_t *)kmem_zalloc(sizeof (inthandler_t),
   1623 	    KM_NOSLEEP);
   1624 	if (intr == NULL) {
   1625 		return (BAD_IRQ);
   1626 	}
   1627 
   1628 	intr->intr = (uint32_t (*)())handler->handler;
   1629 	intr->handler_id = handler->handler_id;
   1630 	intr->arg1 = handler->arg1;
   1631 	intr->arg2 = handler->arg2;
   1632 	intr->socket = handler->socket;
   1633 	intr->irq = handler->irq;
   1634 	mutex_enter(&drt->pc_intr);
   1635 	mutex_enter(&drt->pc_lock); /* protect the registers and structures */
   1636 
   1637 	if (drt->pc_handlers == NULL) {
   1638 		drt->pc_handlers = intr;
   1639 		intr->next = intr;
   1640 		intr->prev = intr;
   1641 	} else {
   1642 		insque(intr, drt->pc_handlers);
   1643 	}
   1644 
   1645 	/* interrupt handlers for both interrupts already done in attach */
   1646 
   1647 	/*
   1648 	 * need to fill in cookies in event of multiple high priority
   1649 	 * interrupt handlers on same IRQ
   1650 	 */
   1651 	intr->iblk_cookie = drt->pc_icookie_hi;
   1652 	intr->idev_cookie = drt->pc_dcookie_hi;
   1653 	mutex_exit(&drt->pc_lock);
   1654 	mutex_exit(&drt->pc_intr);
   1655 
   1656 	handler->iblk_cookie = &intr->iblk_cookie;
   1657 	handler->idev_cookie = &intr->idev_cookie;
   1658 
   1659 	return (SUCCESS);
   1660 }
   1661 
   1662 /*
   1663  * drt_clear_interrupt()
   1664  *	SocketServices ClearInterrupt function
   1665  *	"What  controls the socket interrupt?"
   1666  */
   1667 static int
   1668 drt_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
   1669 {
   1670 	int i = 0;
   1671 	drt_dev_t *drt = drt_get_driver_private(dip);
   1672 	inthandler_t *intr, *done;
   1673 
   1674 #if defined(DRT_DEBUG)
   1675 	if (drt_debug)
   1676 		cmn_err(CE_CONT, "drt_clear_interrupt(%p, %p) "
   1677 		    "pc_handlers = %p\n",
   1678 		    (void *)dip, (void *)handler, (void *)drt->pc_handlers);
   1679 #endif
   1680 
   1681 	mutex_enter(&drt->pc_lock); /* protect the registers */
   1682 
   1683 	for (intr = drt->pc_handlers, done = drt->pc_handlers;
   1684 	    done != NULL; /* empty */) {
   1685 
   1686 		if (intr->handler_id == handler->handler_id) {
   1687 			/* Check if there is only one handler left */
   1688 			if ((intr->next == intr) && (intr->prev == intr)) {
   1689 				drt->pc_handlers = NULL;
   1690 			} else {
   1691 				if (drt->pc_handlers == intr) {
   1692 					drt->pc_handlers = intr->next;
   1693 				}
   1694 				remque(intr);
   1695 			}
   1696 			kmem_free((caddr_t)intr, sizeof (inthandler_t));
   1697 			break;
   1698 		}
   1699 		intr = intr->next;
   1700 		if (intr == done)
   1701 			done = NULL;
   1702 	}
   1703 
   1704 	mutex_exit(&drt->pc_lock);
   1705 
   1706 #ifdef	lint
   1707 	if (i > 0)
   1708 		panic("lint panic");
   1709 #endif
   1710 
   1711 	return (SUCCESS);
   1712 }
   1713 
   1714 static void
   1715 drt_stop_intr(drt_dev_t *drt, int socket)
   1716 {
   1717 	inthandler_t *intr;
   1718 	int done;
   1719 
   1720 	mutex_enter(&drt->pc_intr);
   1721 	for (intr = drt->pc_handlers, done = 0; !done && intr != NULL;
   1722 	    intr = intr->next) {
   1723 		if (socket == intr->socket) {
   1724 			intr->socket |= 0x8000;	/* make an illegal socket */
   1725 		}
   1726 		if (intr->next == drt->pc_handlers)
   1727 			done++;
   1728 	}
   1729 	mutex_exit(&drt->pc_intr);
   1730 }
   1731 
   1732 /*ARGSUSED*/
   1733 int
   1734 drt_do_intr(drt_dev_t *drt, int socket, int priority)
   1735 {
   1736 	inthandler_t *intr, *done;
   1737 	int result = 0;
   1738 
   1739 	mutex_enter(&drt->pc_intr);
   1740 
   1741 #if defined(DRT_DEBUG)
   1742 	if (drt_debug > 2)
   1743 		cmn_err(CE_CONT, "drt_do_intr(%p, %d, %d)\n",
   1744 		    (void *)drt, socket, priority);
   1745 #endif
   1746 
   1747 	/*
   1748 	 * If we're suspended, then we don't need to process
   1749 	 *	any more interrupts. We have already (or will
   1750 	 *	shortly) be disabling all interrupts on the
   1751 	 *	adapter, but we still need to ACK any that
   1752 	 *	we receive and that the adapter has generated.
   1753 	 * XXX - do we really want to do this here, or does it
   1754 	 *	make more sense to let the clients receive any
   1755 	 *	interrupts even as we're in the process of
   1756 	 *	suspending?
   1757 	 */
   1758 	if (drt->pc_flags & PCF_SUSPENDED) {
   1759 		mutex_exit(&drt->pc_intr);
   1760 		return (DDI_INTR_CLAIMED);
   1761 	}
   1762 
   1763 #if defined(DRT_DEBUG)
   1764 	if (drt_debug && drt->pc_handlers == NULL)
   1765 		cmn_err(CE_CONT, "drt_do_intr: pc_handlers == NULL\n");
   1766 #endif
   1767 	for (intr = drt->pc_handlers, done = drt->pc_handlers;
   1768 	    done != NULL && intr != NULL; intr = intr->next) {
   1769 #if defined(DRT_DEBUG)
   1770 		if (drt_debug > 2)
   1771 			cmn_err(CE_CONT,
   1772 			    "\tintr-> socket=%d, priority=%d, intr=%p,"
   1773 			    "arg1=%p arg2=%p (drt_flags=%x:%s)\n",
   1774 			    intr->socket, intr->priority,
   1775 			    (void *)intr->intr, intr->arg1, intr->arg2,
   1776 			    drt->pc_sockets[socket].drt_flags,
   1777 			    (drt->pc_sockets[socket].drt_flags &
   1778 			    DRT_INTR_ENABLED) ?
   1779 			    "true":"false");
   1780 #endif
   1781 #if 0
   1782 		/* may need to rethink the priority stuff */
   1783 		if (socket == intr->socket &&
   1784 		    (priority ^ (intr->priority < 10)) &&
   1785 		    drt->pc_sockets[socket].drt_flags & DRT_INTR_ENABLED) {
   1786 			result |= (*intr->intr)(intr->arg);
   1787 		}
   1788 #else
   1789 		result |= (*intr->intr)(intr->arg1, intr->arg2);
   1790 #endif
   1791 		if (done == intr->next)
   1792 			done = NULL;
   1793 	}
   1794 	/* do a round robin adjust */
   1795 	if (drt->pc_handlers != NULL)
   1796 		drt->pc_handlers = drt->pc_handlers->next;
   1797 	mutex_exit(&drt->pc_intr);
   1798 	return (result);
   1799 }
   1800 
   1801 uint32_t
   1802 drt_hi_intr(caddr_t arg)
   1803 {
   1804 	drt_dev_t *drt = drt_get_driver_private((dev_info_t *)arg);
   1805 	int i, intr_sockets = 0;
   1806 	int result, changes;
   1807 
   1808 	mutex_enter(&drt->pc_lock);
   1809 
   1810 #if defined(DRT_DEBUG)
   1811 	if (drt_debug)
   1812 		cmn_err(CE_CONT, "drt_hi_intr: entered\n");
   1813 #endif
   1814 
   1815 	/*
   1816 	 * need to change to only ACK and touch the slot that
   1817 	 * actually caused the interrupt.  Currently everything
   1818 	 * is acked
   1819 	 *
   1820 	 * we need to look at all known sockets to determine
   1821 	 * what might have happened, so step through the list
   1822 	 * of them
   1823 	 */
   1824 	result = 0;
   1825 
   1826 	for (i = 0; i < DRSOCKETS; i++) {
   1827 		int card_type;
   1828 		int x = drt->pc_cb_arg;
   1829 		drt_socket_t *sockp;
   1830 
   1831 		sockp = &drt->pc_sockets[i];
   1832 
   1833 		if (drt->pc_csr->socket[i].ctl0 & DRCTL_IFTYPE)
   1834 			card_type = IF_IO;
   1835 		else
   1836 			card_type = IF_MEMORY;
   1837 
   1838 		changes = drt->pc_csr->socket[i].stat0;
   1839 #if defined(DRT_DEBUG)
   1840 		if (drt_debug)
   1841 			cmn_err(CE_CONT, "\tstat0=%x, type=%s\n",
   1842 			    changes, card_type == IF_IO ? "IO":"MEM");
   1843 #endif
   1844 		/* ack the interrupts we see */
   1845 		drt->pc_csr->socket[i].stat0 = (ushort_t)changes;
   1846 
   1847 		if (changes & DRSTAT_SCINT) {
   1848 #if defined(DRT_DEBUG)
   1849 			if (drt_debug)
   1850 				cmn_err(CE_CONT,
   1851 				    "\tcard status change interrupt"
   1852 				    " on socket %d\n", i);
   1853 #endif
   1854 			/*
   1855 			 * We set the result here mainly for IF_MEMORY cases.
   1856 			 * The drt_do_intr() call at the end of this for loop
   1857 			 * will not be called for IF_MEMORY cases since
   1858 			 * intr_sockets are set ONLY for IF_IO cases.
   1859 			 */
   1860 			result |= DDI_INTR_CLAIMED;
   1861 
   1862 			/* there was a valid interrupt on status change  */
   1863 			if (drt->pc_callback == NULL) {
   1864 				/* nothing to do */
   1865 				continue;
   1866 			}
   1867 			if (changes & DRSTAT_CDCHG) {
   1868 				if ((sockp->drt_flags &
   1869 				    DRT_CARD_PRESENT) &&
   1870 				    (changes & DRSTAT_CD_MASK) !=
   1871 				    DRSTAT_PRESENT_OK) {
   1872 					sockp->drt_flags &=
   1873 					    ~DRT_CARD_PRESENT;
   1874 					/*
   1875 					 * stop interrupt handler
   1876 					 * then do the callback
   1877 					 */
   1878 					drt_stop_intr(drt, i);
   1879 					/*
   1880 					 * XXX - note that drt_new_card will
   1881 					 *	clear sockp->drt_flags
   1882 					 */
   1883 					drt_new_card(drt, i); /* paranoia */
   1884 					PC_CALLBACK(drt, arg, x,
   1885 					    PCE_CARD_REMOVAL, i);
   1886 					continue;
   1887 				} else {
   1888 					if ((changes & DRSTAT_CD_MASK) ==
   1889 					    DRSTAT_PRESENT_OK &&
   1890 					    !(sockp->drt_flags &
   1891 					    DRT_CARD_PRESENT)) {
   1892 						drt_new_card(drt, i);
   1893 						drt_ll_reset(drt, i);
   1894 						sockp->drt_state |= SBM_CD;
   1895 						drt_socket_card_id(drt,
   1896 						    sockp,
   1897 						    changes);
   1898 						PC_CALLBACK(drt, arg, x,
   1899 						    PCE_CARD_INSERT,
   1900 						    i);
   1901 						continue;
   1902 					}
   1903 				}
   1904 				/*
   1905 				 * since other events may be the result of
   1906 				 * "bounce", don't check them on this pass.
   1907 				 * The insert code will check them anyway.
   1908 				 */
   1909 				continue;
   1910 			}
   1911 
   1912 			/* Ready/Change Detect */
   1913 #if defined(DRT_DEBUG)
   1914 			if (drt_debug && changes & DRSTAT_RDYCHG)
   1915 				cmn_err(CE_CONT, "\trdychg: stat=%x, type=%s\n",
   1916 				    changes,
   1917 				    card_type == IF_MEMORY ?
   1918 				    "memory" : "I/O");
   1919 #endif
   1920 			if (card_type == IF_MEMORY &&
   1921 			    changes & DRSTAT_RDYCHG &&
   1922 			    changes & DRSTAT_RDYST) {
   1923 				sockp->drt_state |= SBM_RDYBSY;
   1924 				PC_CALLBACK(drt, arg, x, PCE_CARD_READY, i);
   1925 			}
   1926 
   1927 			/* write protect switch moved */
   1928 			if (card_type == IF_MEMORY && changes & DRSTAT_WPCHG) {
   1929 				if (changes & DRSTAT_WPST)
   1930 					sockp->drt_state |= SBM_WP;
   1931 				else
   1932 					sockp->drt_state &= ~SBM_WP;
   1933 				PC_CALLBACK(drt, arg, x,
   1934 				    PCE_CARD_WRITE_PROTECT, i);
   1935 			}
   1936 
   1937 			if (card_type == IF_MEMORY &&
   1938 			    changes & DRSTAT_BVDCHG) {
   1939 				/*
   1940 				 * there was a change in battery state.
   1941 				 * this could be a false alarm at
   1942 				 * card insertion but could be real.
   1943 				 * The individual change bits aren't
   1944 				 * meaningful so look at the live
   1945 				 * status and latch that
   1946 				 */
   1947 				switch (changes & DRSTAT_BVDST) {
   1948 				case DRSTAT_BATT_LOW:
   1949 					if (!(sockp->drt_flags &
   1950 					    DRT_BATTERY_LOW)) {
   1951 						sockp->drt_flags |=
   1952 						    DRT_BATTERY_LOW;
   1953 						sockp->drt_state |= SBM_BVD2;
   1954 						sockp->drt_state &= ~SBM_BVD1;
   1955 						PC_CALLBACK(drt, arg, x,
   1956 						    PCE_CARD_BATTERY_WARN,
   1957 						    i);
   1958 					}
   1959 					break;
   1960 				case DRSTAT_BATT_OK:
   1961 					sockp->drt_state &=
   1962 					    ~(DRT_BATTERY_LOW|
   1963 					    DRT_BATTERY_DEAD);
   1964 					sockp->drt_state &=
   1965 					    ~(SBM_BVD1|SBM_BVD2);
   1966 					break;
   1967 				default: /* battery failed */
   1968 					if (!(sockp->drt_flags &
   1969 					    DRT_BATTERY_DEAD)) {
   1970 						/* so we only see one of them */
   1971 						sockp->drt_flags |=
   1972 						    DRT_BATTERY_DEAD;
   1973 						sockp->drt_flags &=
   1974 						    DRT_BATTERY_LOW;
   1975 						sockp->drt_state |= SBM_BVD1;
   1976 						PC_CALLBACK(drt, arg, x,
   1977 						    PCE_CARD_BATTERY_DEAD,
   1978 						    i);
   1979 					}
   1980 				}
   1981 			}
   1982 			if (card_type == IF_IO &&
   1983 			    !(changes & DRSTAT_BVD1ST)) {
   1984 				/*
   1985 				 * Disable status change interrupts. We
   1986 				 *	will enable them again later after
   1987 				 *	Card Services has processed this
   1988 				 *	event.
   1989 				 */
   1990 				drt->pc_csr->socket[i].ctl0 &=
   1991 				    ~DRCTL_BVD1IE;
   1992 
   1993 				/* we have an I/O status change */
   1994 				PC_CALLBACK(drt, arg, x,
   1995 				    PCE_CARD_STATUS_CHANGE,
   1996 				    i);
   1997 			}
   1998 #if 0
   1999 			/*
   2000 			 * need to reexamine this section to see what really
   2001 			 * needs to be done
   2002 			 */
   2003 			/* Battery Warn Detect */
   2004 			if (changes & DRSTAT_BVD2CHG) {
   2005 				if (card_type == IF_MEMORY &&
   2006 				    !(sockp->drt_flags & DRT_BATTERY_LOW)) {
   2007 					sockp->drt_flags |= DRT_BATTERY_LOW;
   2008 					sockp->drt_state |= SBM_BVD2;
   2009 					PC_CALLBACK(drt, arg, x,
   2010 					    PCE_CARD_BATTERY_WARN,
   2011 					    i);
   2012 				} else if (card_type == IF_IO) {
   2013 					PC_CALLBACK(drt, arg, x,
   2014 					    PCE_CARD_STATUS_CHANGE,
   2015 					    i);
   2016 				}
   2017 			}
   2018 
   2019 			/* Battery Fail Detect */
   2020 			if (card_type == IF_MEMORY &&
   2021 			    changes & DRSTAT_BVD1CHG &&
   2022 			    !(sockp->drt_flags & DRT_BATTERY_DEAD)) {
   2023 				/* so we only see one of them */
   2024 				sockp->drt_flags |= DRT_BATTERY_DEAD;
   2025 				sockp->drt_state |= SBM_BVD1;
   2026 				PC_CALLBACK(drt, arg, x,
   2027 				    PCE_CARD_BATTERY_DEAD, i);
   2028 			}
   2029 #endif
   2030 		}
   2031 		/* now flag any PC Card interrupts */
   2032 		if (card_type == IF_IO && changes & DRSTAT_IOINT) {
   2033 			intr_sockets |= 1 << i;
   2034 		}
   2035 #if defined(DRT_DEBUG)
   2036 		if (drt_debug)
   2037 			cmn_err(CE_CONT, "\tsocket %d: ctl0=%x, ctl1=%x\n",
   2038 			    i,
   2039 			    drt->pc_csr->socket[i].ctl0,
   2040 			    drt->pc_csr->socket[i].ctl1);
   2041 #endif
   2042 	}
   2043 
   2044 	mutex_exit(&drt->pc_lock);
   2045 
   2046 	for (i = 0; i < DRSOCKETS; i++) {
   2047 		if (intr_sockets & (1 << i))
   2048 			result |= drt_do_intr(drt, i, 1);
   2049 	}
   2050 
   2051 	if (changes & DRSTAT_SCINT || result || intr_sockets)
   2052 		return (DDI_INTR_CLAIMED);
   2053 	if (drt->pc_flags & PCF_ATTACHING) {
   2054 		drt->pc_flags &= ~PCF_ATTACHING;
   2055 		return (DDI_INTR_CLAIMED);
   2056 	}
   2057 
   2058 	return (DDI_INTR_UNCLAIMED);
   2059 }
   2060 
   2061 uint32_t
   2062 drt_lo_intr(caddr_t arg)
   2063 {
   2064 	drt_dev_t *drt = drt_get_driver_private((dev_info_t *)arg);
   2065 	int i, result;
   2066 
   2067 #if defined(DRT_DEBUG)
   2068 	if (drt_debug)
   2069 		cmn_err(CE_CONT, "drt_lo_intr(%p)\n", (void *)arg);
   2070 #endif
   2071 	/*
   2072 	 * we need to look at all known sockets to determine
   2073 	 * what might have happened, so step through the list
   2074 	 * of them
   2075 	 */
   2076 
   2077 	/* XXX is this the lost interrupt problem?? XXX */
   2078 	for (i = 0, result = 0; i < drt->pc_numsockets; i++) {
   2079 		if (drt->pc_csr->socket[i].stat0 & DRSTAT_IOINT) {
   2080 #if defined(DRT_DEBUG)
   2081 			if (drt_debug)
   2082 				cmn_err(CE_CONT, "\tsocket=%x, stat0=%x\n",
   2083 				    i, drt->pc_csr->socket[i].stat0);
   2084 #endif
   2085 			result |= drt_do_intr(drt, i, 0);
   2086 			drt->pc_csr->socket[i].stat0 |= DRSTAT_IOINT;
   2087 		}
   2088 	}
   2089 	if (result)
   2090 		return (DDI_INTR_CLAIMED);
   2091 	return (DDI_INTR_UNCLAIMED);
   2092 }
   2093 
   2094 /*
   2095  * drt_socket_card_id()
   2096  *	figure out current status of card in socket
   2097  *	this is used to prevent callbacks at card insertion
   2098  */
   2099 /* ARGSUSED */
   2100 void
   2101 drt_socket_card_id(drt_dev_t *drt, drt_socket_t *socket, int status)
   2102 {
   2103 
   2104 	/* need to record if a card is present to init state */
   2105 	if ((status & DRSTAT_CD_MASK) == DRSTAT_PRESENT_OK)
   2106 		socket->drt_flags |= DRT_CARD_PRESENT;
   2107 
   2108 	/* check battery state to avoid callbacks */
   2109 	switch (status & DRSTAT_BVDST) {
   2110 	case DRSTAT_BATT_LOW:
   2111 		socket->drt_flags |= DRT_BATTERY_LOW;
   2112 		socket->drt_flags &= ~DRT_BATTERY_DEAD;
   2113 		socket->drt_state |= SBM_BVD2;
   2114 		socket->drt_state &= ~SBM_BVD1;
   2115 		break;
   2116 	case DRSTAT_BATT_OK:
   2117 		socket->drt_flags &= ~(DRT_BATTERY_LOW|DRT_BATTERY_DEAD);
   2118 		socket->drt_state &= ~(SBM_BVD1|SBM_BVD2);
   2119 		break;
   2120 	default:
   2121 				/* battery dead */
   2122 		socket->drt_flags |= DRT_BATTERY_DEAD;
   2123 		socket->drt_state |= SBM_BVD1;
   2124 		break;
   2125 	}
   2126 
   2127 	/* check write protect status */
   2128 	if (status & DRSTAT_WPST)
   2129 		socket->drt_state |= SBM_WP;
   2130 	else
   2131 		socket->drt_state &= ~SBM_WP;
   2132 
   2133 	/* and ready/busy */
   2134 	if (status & DRSTAT_RDYST)
   2135 		socket->drt_state |= SBM_RDYBSY;
   2136 	else
   2137 		socket->drt_state &= ~SBM_RDYBSY;
   2138 }
   2139 
   2140 #if defined(DRT_DEBUG)
   2141 static void
   2142 drt_dmp_regs(stp4020_socket_csr_t *csrp)
   2143 {
   2144 	int i;
   2145 
   2146 	cmn_err(CE_CONT, "drt_dmp_regs (%p):\n", (void *)csrp);
   2147 	cmn_err(CE_CONT, "\tctl0: %b\n", csrp->ctl0,
   2148 	    "\020\1IFTYPE\2SFTRST\3SPKREN\4IOILVL\5IOIE\6RSVD"
   2149 	    "\7CTOIE\010WPIE\011RDYIE\012BVD1IE\013BVD2IE\014CDIE"
   2150 	    "\015SCILVL\016PROMEN\017RSVDX");
   2151 	cmn_err(CE_CONT,
   2152 	    "\tctl1: %b\n", csrp->ctl1,
   2153 	    "\020\1PCIFOE\1MSTPWR\7APWREN"
   2154 	    "\10RSVD\11DIAGEN\12WAITDB\13WPDB\14RDYDB\15BVD1DB\16BVD2DB"
   2155 	    "\17CD1DB\20LPBKEN");
   2156 	cmn_err(CE_CONT,
   2157 	    "\tstat0: %b\n", csrp->stat0,
   2158 	    "\020\1PWRON\2WAITST\3WPST"
   2159 	    "\4RDYST\5BVD1ST\6BVD2ST\7CD1ST\10CD2ST\11PCTO\12WPCHG"
   2160 	    "\13RDCHG\14BVD1CHG\15BVD2CHG\16CDCHG\17SCINT\20IOINT");
   2161 	cmn_err(CE_CONT,
   2162 	    "\tstat1: types=%x, rev=%x\n",
   2163 	    (int)(csrp->stat1 & DRSTAT_PCTYS_M),
   2164 	    csrp->stat1 & DRSTAT_REV_M);
   2165 	for (i = 0; i < 3; i++) {
   2166 		cmn_err(CE_CONT, "\twin%d:\tctl0: cmdlng=%x, cmddly=%x, "
   2167 		    "aspsel=%x, base=%x\n", i,
   2168 		    GET_DRWIN_CMDLNG(csrp->window[i].ctl0),
   2169 		    GET_DRWIN_CMDDLY(csrp->window[i].ctl0),
   2170 		    csrp->window[i].ctl0 & DRWIN_ASPSEL_M,
   2171 		    GET_DRWIN_BASE(csrp->window[i].ctl0));
   2172 		cmn_err(CE_CONT, "\t\tctl1: %x\n", csrp->window[i].ctl1);
   2173 	}
   2174 }
   2175 
   2176 #endif
   2177 
   2178 /*
   2179  * drt_cpr - save/restore the adapter's hardware state
   2180  */
   2181 static void
   2182 drt_cpr(drt_dev_t *drt, int cmd)
   2183 {
   2184 	int sn, wn;
   2185 
   2186 	switch (cmd) {
   2187 		case DRT_SAVE_HW_STATE:
   2188 		for (sn = 0; sn < DRSOCKETS; sn++) {
   2189 			stp4020_socket_csr_t *drs = &drt->pc_csr->socket[sn];
   2190 			for (wn = 0; wn < DRWINDOWS; wn++) {
   2191 				drt->saved_socket[sn].window[wn].ctl0 =
   2192 				    drs->window[wn].ctl0;
   2193 				drt->saved_socket[sn].window[wn].ctl1 =
   2194 				    drs->window[wn].ctl1;
   2195 			}
   2196 			drt->saved_socket[sn].ctl0 = drs->ctl0;
   2197 			drt->saved_socket[sn].ctl1 = drs->ctl1;
   2198 		}
   2199 		break;
   2200 		case DRT_RESTORE_HW_STATE:
   2201 		for (sn = 0; sn < DRSOCKETS; sn++) {
   2202 			stp4020_socket_csr_t *drs = &drt->pc_csr->socket[sn];
   2203 			for (wn = 0; wn < DRWINDOWS; wn++) {
   2204 				drs->window[wn].ctl0 =
   2205 				    drt->saved_socket[sn].window[wn].ctl0;
   2206 				drs->window[wn].ctl1 =
   2207 				    drt->saved_socket[sn].window[wn].ctl1;
   2208 			}
   2209 
   2210 			/* work around for false status bugs */
   2211 			/* XXX - why 0x3FFF and not 0xFFFF?? */
   2212 			drs->stat0 = 0x3FFF;
   2213 			drs->stat1 = 0x3FFF;
   2214 
   2215 			drs->ctl0 = drt->saved_socket[sn].ctl0;
   2216 			drs->ctl1 = drt->saved_socket[sn].ctl1;
   2217 		}
   2218 		break;
   2219 	} /* switch */
   2220 
   2221 }
   2222 
   2223 /*
   2224  * drt_fixprops(dip)
   2225  *	if the adapter predates 1275 properties, add them.
   2226  *	We do this by checking presence of the property
   2227  *	and adding what we know if properties not present
   2228  */
   2229 /* ARGSUSED */
   2230 static void
   2231 drt_fixprops(dev_info_t *dip)
   2232 {
   2233 
   2234 	/*
   2235 	 * note that there are a number of properties that
   2236 	 * should be added here if not present
   2237 	 */
   2238 
   2239 }
   2240 
   2241 
   2242 
   2243 
   2244 /*
   2245  * stpra_alloc_map()
   2246  *	allocate an stpramap structure.
   2247  */
   2248 
   2249 struct stpramap *
   2250 stpra_alloc_map()
   2251 {
   2252 	struct stpramap *new;
   2253 	mutex_enter(&stpra_lock);
   2254 	new = NULL;
   2255 	if (stpra_freelist != NULL) {
   2256 		new = stpra_freelist;
   2257 		stpra_freelist = new->ra_next;
   2258 	}
   2259 	mutex_exit(&stpra_lock);
   2260 	if (new == NULL) {
   2261 		new = (struct stpramap *)kmem_zalloc(sizeof (struct stpramap),
   2262 		    KM_SLEEP);
   2263 	} else {
   2264 		bzero((caddr_t)new, sizeof (struct stpramap));
   2265 	}
   2266 	return (new);
   2267 }
   2268 
   2269 /*
   2270  * stpra_free_map(map)
   2271  *	return a used map to the freelist.
   2272  *	Should probably check to see if above
   2273  *	some threshold and kmem_free() any excess
   2274  */
   2275 void
   2276 stpra_free_map(struct stpramap *map)
   2277 {
   2278 	if (map != NULL) {
   2279 		mutex_enter(&stpra_lock);
   2280 		map->ra_next = stpra_freelist;
   2281 		stpra_freelist = map;
   2282 		mutex_exit(&stpra_lock);
   2283 	}
   2284 }
   2285 
   2286 
   2287 /*
   2288  * stpra_free(map, base, len)
   2289  *	return the specified range (base to base+len)
   2290  *	to the specified map
   2291  */
   2292 
   2293 void
   2294 stpra_free(struct stpramap **map, uint32_t base, uint32_t len)
   2295 {
   2296 	struct stpramap *newmap, *oldmap = NULL;
   2297 	struct stpramap *mapp, *backp;
   2298 	uint32_t newbase, mapend;
   2299 
   2300 	/*
   2301 	 * always allocate a map entry so we can manipulate
   2302 	 * things without blocking inside our lock
   2303 	 */
   2304 	newmap = stpra_alloc_map();
   2305 	ASSERT(newmap);
   2306 
   2307 	mutex_enter(&stpra_lock);
   2308 
   2309 	mapp = *map;
   2310 	backp = (struct stpramap *)map;
   2311 
   2312 	/* now find where range lies and fix things up */
   2313 	newbase = base + len;
   2314 	for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
   2315 		mapend = mapp->ra_base + mapp->ra_len;
   2316 		if (mapend == 0) {
   2317 			/*
   2318 			 * special case: sum is larger than 32bit
   2319 			 */
   2320 			mapend = mapp->ra_len;
   2321 		}
   2322 		if (newbase == mapp->ra_base) {
   2323 			/* simple - on front */
   2324 			mapp->ra_base = base;
   2325 			mapp->ra_len += len;
   2326 			/*
   2327 			 * don't need to check if it merges with
   2328 			 * previous since that would match on on end
   2329 			 */
   2330 			break;
   2331 		} else if (newbase == mapend) {
   2332 			/* simple - on end */
   2333 			mapp->ra_len += len;
   2334 			if (mapp->ra_next && newbase ==
   2335 			    mapp->ra_next->ra_base) {
   2336 				/* merge with next node */
   2337 				oldmap = mapp->ra_next;
   2338 				mapp->ra_len += oldmap->ra_len;
   2339 				mapp->ra_next = oldmap->ra_next;
   2340 			}
   2341 			break;
   2342 		} else if (base < mapp->ra_base) {
   2343 			/* somewhere in between so just an insert */
   2344 			newmap->ra_base = base;
   2345 			newmap->ra_len = len;
   2346 			newmap->ra_next = mapp;
   2347 			backp->ra_next = newmap;
   2348 			newmap = NULL;
   2349 			break;
   2350 		}
   2351 		/* else haven't found the spot yet */
   2352 	}
   2353 	if (mapp == NULL) {
   2354 		/* special case of running off the end - stick on end */
   2355 		newmap->ra_base = base;
   2356 		newmap->ra_len = len;
   2357 		backp->ra_next = newmap;
   2358 		newmap = NULL;
   2359 	}
   2360 	mutex_exit(&stpra_lock);
   2361 	if (newmap != NULL)
   2362 		stpra_free_map(newmap);
   2363 	if (oldmap != NULL)
   2364 		stpra_free_map(oldmap);
   2365 }
   2366 
   2367 /*
   2368  * stpra_alloc(map, reqest, return)
   2369  *	Allocate a memory-like resource (physical memory, I/O space)
   2370  *	subject to the constraints defined in the request structure.
   2371  */
   2372 
   2373 int
   2374 stpra_alloc(struct stpramap **map, stpra_request_t *req, stpra_return_t *ret)
   2375 {
   2376 	struct stpramap *mapp, *backp;
   2377 	struct stpramap *newmap, *old = NULL;
   2378 	int type = 0, len;
   2379 	uint32_t mask = 0;
   2380 	int newlen, rval = DDI_FAILURE;
   2381 	uint32_t base, lower, upper;
   2382 
   2383 	if (req->ra_flags & STP_RA_ALLOC_SPECIFIED)
   2384 		type = STP_RA_ALLOC_SPECIFIED;
   2385 	else
   2386 		type = 0;
   2387 
   2388 	if (req->ra_flags & (STP_RA_ALLOC_POW2|STP_RA_ALIGN_SIZE)) {
   2389 		if (req->ra_len != stpra_fix_pow2(req->ra_len)) {
   2390 #if defined(DRT_DEBUG)
   2391 			if (drt_debug)
   2392 				cmn_err(CE_WARN, "ra: bad length (pow2) %d\n",
   2393 				    req->ra_len);
   2394 #endif
   2395 			ret->ra_addr_hi = 0;
   2396 			ret->ra_addr_lo = 0;
   2397 			ret->ra_len = 0;
   2398 			return (DDI_FAILURE);
   2399 		}
   2400 	}
   2401 	mask = req->ra_align;
   2402 	if (req->ra_flags & STP_RA_ALIGN_SIZE) {
   2403 		len = stpra_fix_pow2(req->ra_len);
   2404 		mask = len - 1;
   2405 #if defined(DRT_DEBUG)
   2406 		if (drt_debug)
   2407 			cmn_err(CE_CONT, "len=%d, mask=%x\n", len, mask);
   2408 #endif
   2409 	}
   2410 
   2411 	newmap = stpra_alloc_map(); /* just in case */
   2412 
   2413 	mutex_enter(&stpra_lock);
   2414 
   2415 	mapp = *map;
   2416 #if defined(DRT_DEBUG)
   2417 		if (drt_debug)
   2418 			cmn_err(CE_CONT, "stpra_alloc: mapp = %p\n",
   2419 			    (void *)mapp);
   2420 #endif
   2421 
   2422 	backp = (struct stpramap *)map;
   2423 
   2424 	len = req->ra_len;
   2425 
   2426 	lower = 0;
   2427 	upper = ~(uint32_t)0;
   2428 
   2429 
   2430 
   2431 	if (type != STP_RA_ALLOC_SPECIFIED) {
   2432 		/* first fit - not user specified */
   2433 #if defined(DRT_DEBUG)
   2434 		if (drt_debug)
   2435 			cmn_err(CE_CONT, "stpra_alloc(unspecified request)"
   2436 			    "lower=%x, upper=%x\n", lower, upper);
   2437 #endif
   2438 		for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
   2439 #if defined(DRT_DEBUG)
   2440 		if (drt_debug)
   2441 			cmn_err(CE_CONT, "stpra_alloc: ra_len = %x, len = %x",
   2442 			    mapp->ra_len, len);
   2443 #endif
   2444 
   2445 			if (mapp->ra_len >= len) {
   2446 				/* a candidate -- apply constraints */
   2447 				base = mapp->ra_base;
   2448 				if (base < lower &&
   2449 				    (base + mapp->ra_len) < (lower + len)) {
   2450 					if (((base + mapp->ra_len) != 0) ||
   2451 					    ((base + mapp->ra_len) >
   2452 					    mapp->ra_len))
   2453 					    /* same as the above case */
   2454 						continue;
   2455 				}
   2456 				if (base < lower)
   2457 					base = lower;
   2458 #if defined(DRT_DEBUG)
   2459 				if (drt_debug)
   2460 					cmn_err(CE_CONT,
   2461 					    "\tbase=%x, ra_base=%x,"
   2462 					    "mask=%x\n",
   2463 					    base, mapp->ra_base, mask);
   2464 #endif
   2465 				if ((mapp->ra_base & mask) != 0) {
   2466 					/*
   2467 					 * failed a critical constraint
   2468 					 * adjust and see if it still fits
   2469 					 */
   2470 					base = mapp->ra_base & ~mask;
   2471 					base += (mask + 1);
   2472 #if defined(DRT_DEBUG)
   2473 					if (drt_debug)
   2474 						cmn_err(CE_CONT,
   2475 						    "\tnew base=%x\n",
   2476 						    base);
   2477 #endif
   2478 					if (len > (mapp->ra_len -
   2479 					    (base - mapp->ra_base)))
   2480 						continue;
   2481 				}
   2482 				/* we have a fit */
   2483 #if defined(DRT_DEBUG)
   2484 				if (drt_debug)
   2485 					cmn_err(CE_CONT, "\thave a fit\n");
   2486 #endif
   2487 #ifdef lint
   2488 				upper = upper; /* need to check upper bound */
   2489 #endif
   2490 				if (base != mapp->ra_base) {
   2491 					/* in the middle or end */
   2492 					newlen = base - mapp->ra_base;
   2493 					if ((mapp->ra_len - newlen) == len) {
   2494 						/* on the end */
   2495 						mapp->ra_len = newlen;
   2496 					} else {
   2497 						newmap->ra_next = mapp->ra_next;
   2498 						newmap->ra_base = base + len;
   2499 						newmap->ra_len = mapp->ra_len -
   2500 						    (len + newlen);
   2501 						mapp->ra_len = newlen;
   2502 						mapp->ra_next = newmap;
   2503 						newmap = NULL;
   2504 					}
   2505 
   2506 				} else {
   2507 					/* at the beginning */
   2508 					mapp->ra_base += len;
   2509 					mapp->ra_len -= len;
   2510 					if (mapp->ra_len == 0) {
   2511 						/* remove the whole node */
   2512 						backp->ra_next = mapp->ra_next;
   2513 						old = mapp;
   2514 					}
   2515 				}
   2516 				rval = DDI_SUCCESS;
   2517 				break;
   2518 			}
   2519 		}
   2520 	} else {
   2521 		/* want an exact value/fit */
   2522 		base = req->ra_addr_lo;
   2523 		len = req->ra_len;
   2524 		for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
   2525 			if (base >= mapp->ra_base &&
   2526 			    base < (mapp->ra_base + mapp->ra_len)) {
   2527 			    /* this is the node */
   2528 				if ((base + len) >
   2529 				    (mapp->ra_base + mapp->ra_len)) {
   2530 				    /* no match */
   2531 					base = 0;
   2532 				} else {
   2533 				    /* this is the one */
   2534 					if (base == mapp->ra_base) {
   2535 					    /* at the front */
   2536 						mapp->ra_base += len;
   2537 						mapp->ra_len -= len;
   2538 						if (mapp->ra_len == 0) {
   2539 						    /* used it up */
   2540 							old = mapp;
   2541 							backp->ra_next =
   2542 							    mapp->ra_next;
   2543 						}
   2544 					} else {
   2545 					    /* on the end or in middle */
   2546 						if ((base + len) ==
   2547 						    (mapp->ra_base +
   2548 						    mapp->ra_len)) {
   2549 						    /* on end */
   2550 							mapp->ra_len -= len;
   2551 						} else {
   2552 							uint32_t
   2553 							    newbase, newlen;
   2554 							/* in the middle */
   2555 							newbase = base + len;
   2556 							newlen =
   2557 							    (mapp->ra_base +
   2558 							    mapp->ra_len) -
   2559 							    newbase;
   2560 							newmap->ra_base =
   2561 							    newbase;
   2562 							newmap->ra_len = newlen;
   2563 							newmap->ra_next =
   2564 							    mapp->ra_next;
   2565 							mapp->ra_next = newmap;
   2566 							mapp->ra_len -=
   2567 							    newlen + len;
   2568 							newmap = NULL;
   2569 						}
   2570 					}
   2571 				}
   2572 				rval = DDI_SUCCESS;
   2573 				break;
   2574 			}
   2575 		}
   2576 	}
   2577 
   2578 	mutex_exit(&stpra_lock);
   2579 
   2580 	if (old)
   2581 		stpra_free_map(old);
   2582 	if (newmap)
   2583 		stpra_free_map(newmap);
   2584 
   2585 
   2586 	if (rval == DDI_SUCCESS) {
   2587 		ret->ra_addr_hi = 0;
   2588 		ret->ra_addr_lo = base;
   2589 		ret->ra_len = req->ra_len;
   2590 	}
   2591 	return (rval);
   2592 }
   2593 
   2594 
   2595 
   2596 
   2597 /*
   2598  * stpra_fix_pow2(value)
   2599  *	a utility function which rounds up to the
   2600  *	nearest power of two value.
   2601  */
   2602 
   2603 uint32_t
   2604 stpra_fix_pow2(uint32_t value)
   2605 {
   2606 	int i;
   2607 
   2608 	if (ddi_ffs(value) == ddi_fls(value))
   2609 		return (value);
   2610 	/* not a power of two so round up */
   2611 	i = ddi_fls(value);
   2612 	/* this works since ffs/fls is plus 1 */
   2613 #if defined(DRT_DEBUG)
   2614 	if (drt_debug)  {
   2615 		cmn_err(CE_CONT, "stpra_fix_pow2(%x)->%x:%x\n", value, i,
   2616 		    1 << i);
   2617 		cmn_err(CE_CONT,
   2618 		    "\tffs=%d, fls=%d\n", ddi_ffs(value), ddi_fls(value));
   2619 	}
   2620 #endif
   2621 	return (1 << i);
   2622 }
   2623