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