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