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