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