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