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