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