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