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