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