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