1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  * PCMCIA Card Services
  31  *      The PCMCIA Card Services is a loadable module which
  32  *      presents the Card Services interface to client device
  33  *      drivers.
  34  *
  35  *      Card Services uses Socket Services-like calls into the
  36  *      PCMCIA nexus driver to manipulate socket and adapter
  37  *      resources.
  38  *
  39  * Note that a bunch of comments are not indented correctly with the
  40  *      code that they are commenting on. This is because cstyle is
  41  *      is inflexible concerning 4-column indenting.
  42  */
  43 
  44 #if defined(DEBUG)
  45 #define CS_DEBUG
  46 #endif
  47 
  48 #include <sys/types.h>
  49 #include <sys/systm.h>
  50 #include <sys/user.h>
  51 #include <sys/buf.h>
  52 #include <sys/file.h>
  53 #include <sys/uio.h>
  54 #include <sys/conf.h>
  55 #include <sys/stat.h>
  56 #include <sys/autoconf.h>
  57 #include <sys/vtoc.h>
  58 #include <sys/dkio.h>
  59 #include <sys/ddi.h>
  60 #include <sys/sunddi.h>
  61 #include <sys/debug.h>
  62 #include <sys/varargs.h>
  63 #include <sys/var.h>
  64 #include <sys/proc.h>
  65 #include <sys/thread.h>
  66 #include <sys/utsname.h>
  67 #include <sys/vtrace.h>
  68 #include <sys/kstat.h>
  69 #include <sys/kmem.h>
  70 #include <sys/modctl.h>
  71 #include <sys/kobj.h>
  72 #include <sys/callb.h>
  73 #include <sys/time.h>
  74 
  75 #include <sys/pctypes.h>
  76 #include <pcmcia/sys/cs_types.h>
  77 #include <sys/pcmcia.h>
  78 #include <sys/sservice.h>
  79 #include <pcmcia/sys/cis.h>
  80 #include <pcmcia/sys/cis_handlers.h>
  81 #include <pcmcia/sys/cs.h>
  82 #include <pcmcia/sys/cs_priv.h>
  83 #include <pcmcia/sys/cs_stubs.h>
  84 
  85 /*
  86  * The cs_strings header file is where all of the major strings that
  87  *      Card Services uses are located.
  88  */
  89 #include <pcmcia/sys/cs_strings.h>
  90 
  91 
  92 /*
  93  * Function declarations
  94  *
  95  * The main Card Services entry point
  96  */
  97 int CardServices(int function, ...);
  98 
  99 /*
 100  * functions and globals used by Socket Services
 101  *
 102  * WAS: void *(*cis_parser)(int, ...) = NULL;
 103  */
 104 void *(*cis_parser)(int, ...) = NULL;
 105 csfunction_t *cs_socket_services = NULL;
 106 
 107 /*
 108  * event handling functions
 109  */
 110 static event_t ss_to_cs_events(cs_socket_t *, event_t);
 111 static event_t cs_cse2sbm(event_t);
 112 static void cs_event_thread(uint32_t);
 113 static int cs_card_insertion(cs_socket_t *, event_t);
 114 static int cs_card_removal(cs_socket_t *);
 115 static void cs_ss_thread(uint32_t);
 116 void cs_ready_timeout(void *);
 117 static int cs_card_for_client(client_t *);
 118 static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
 119 static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
 120 static int cs_get_event_mask(client_handle_t, sockevent_t *);
 121 static int cs_set_event_mask(client_handle_t, sockevent_t *);
 122 static int cs_event2text(event2text_t *, int);
 123 static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
 124                                                 get_ss_status_t *, int);
 125 uint32_t cs_socket_event_softintr(caddr_t);
 126 void cs_event_softintr_timeout(void *);
 127 static int cs_get_status(client_handle_t, get_status_t *);
 128 static uint32_t cs_sbm2cse(uint32_t);
 129 static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
 130 static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
 131 
 132 /*
 133  * SS<->CS communication and internal socket and window  handling functions
 134  */
 135 static uint32_t cs_add_socket(uint32_t);
 136 static uint32_t cs_drop_socket(uint32_t);
 137 static cs_socket_t *cs_get_sp(uint32_t);
 138 static cs_socket_t *cs_find_sp(uint32_t);
 139 static cs_window_t *cs_get_wp(uint32_t);
 140 static cs_window_t *cs_find_wp(uint32_t);
 141 static int cs_add_windows(int, uint32_t);
 142 static uint32_t cs_ss_init();
 143 static void cs_set_acc_attributes(set_window_t *, uint32_t);
 144 
 145 /*
 146  * CIS handling functions
 147  */
 148 cistpl_callout_t *cis_cistpl_std_callout;
 149 static int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
 150 static int cs_get_tuple_data(client_handle_t, tuple_t *);
 151 static int cs_validate_cis(client_handle_t, cisinfo_t *);
 152 static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
 153 static int cs_create_cis(cs_socket_t *);
 154 static int cs_destroy_cis(cs_socket_t *);
 155 
 156 /*
 157  * client handling functions
 158  */
 159 unsigned cs_create_next_client_minor(unsigned, unsigned);
 160 static client_t *cs_find_client(client_handle_t, int *);
 161 static client_handle_t cs_create_client_handle(unsigned, client_t *);
 162 static int cs_destroy_client_handle(client_handle_t);
 163 static int cs_register_client(client_handle_t *, client_reg_t *);
 164 static int cs_deregister_client(client_handle_t);
 165 static int cs_deregister_mtd(client_handle_t);
 166 static void cs_clear_superclient_lock(int);
 167 static int cs_add_client_to_socket(unsigned, client_handle_t *,
 168                                                 client_reg_t *, int);
 169 static int cs_get_client_info(client_handle_t, client_info_t *);
 170 static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
 171 
 172 /*
 173  * window handling functions
 174  */
 175 static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
 176 static int cs_release_window(window_handle_t);
 177 static int cs_modify_window(window_handle_t, modify_win_t *);
 178 static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
 179                                                                         int);
 180 static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
 181 static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
 182 static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
 183 static int cs_valid_window_speed(inquire_window_t *, uint32_t);
 184 static window_handle_t cs_create_window_handle(uint32_t);
 185 static cs_window_t *cs_find_window(window_handle_t);
 186 static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
 187 
 188 /*
 189  * IO, IRQ and configuration handling functions
 190  */
 191 static int cs_request_io(client_handle_t, io_req_t *);
 192 static int cs_release_io(client_handle_t, io_req_t *);
 193 static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
 194 static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
 195                                         uint32_t *, uint32_t, uint32_t);
 196 static int cs_request_irq(client_handle_t, irq_req_t *);
 197 static int cs_release_irq(client_handle_t, irq_req_t *);
 198 static int cs_request_configuration(client_handle_t, config_req_t *);
 199 static int cs_release_configuration(client_handle_t, release_config_t *);
 200 static int cs_modify_configuration(client_handle_t, modify_config_t *);
 201 static int cs_access_configuration_register(client_handle_t,
 202                                                 access_config_reg_t *);
 203 
 204 /*
 205  * RESET and general info functions
 206  */
 207 static int cs_reset_function(client_handle_t, reset_function_t *);
 208 static int cs_get_configuration_info(client_handle_t *,
 209                                                 get_configuration_info_t *);
 210 static int cs_get_cardservices_info(client_handle_t,
 211                                                 get_cardservices_info_t *);
 212 static int cs_get_physical_adapter_info(client_handle_t,
 213                                                 get_physical_adapter_info_t *);
 214 
 215 /*
 216  * general functions
 217  */
 218 static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
 219                                         cs_socket_t **, client_t **);
 220 static int cs_convert_speed(convert_speed_t *);
 221 static int cs_convert_size(convert_size_t *);
 222 static char *cs_error2text(int, int);
 223 static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
 224 static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
 225 static int cs_make_device_node(client_handle_t, make_device_node_t *);
 226 static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
 227 static int cs_ddi_info(cs_ddi_info_t *);
 228 static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
 229                                 uint32_t);
 230 static int cs_sys_ctl(cs_sys_ctl_t *);
 231 
 232 /*
 233  * global variables
 234  */
 235 static int cs_max_client_handles = CS_MAX_CLIENTS;
 236 static client_t cs_socket_services_client;      /* global SS client */
 237 static client_types_t client_types[MAX_CLIENT_TYPES];
 238 static cs_globals_t cs_globals;
 239 int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
 240 int cs_rc1_delay = CS_RC1_DELAY;
 241 int cs_rc2_delay = CS_RC2_DELAY;
 242 int cs_rq_delay = CS_RQ_DELAY;
 243 
 244 #ifdef  CS_DEBUG
 245 int     cs_debug = 0;
 246 #endif
 247 
 248 /*
 249  * cs_init - Initialize CS internal structures, databases, and state,
 250  *              and register with SS
 251  *
 252  * XXX - Need to make sure that if we fail at any point that we free
 253  *              any resources that we allocated, as well as kill any
 254  *              threads that may have been started.
 255  */
 256 int
 257 cs_init()
 258 {
 259         client_types_t *ct;
 260         client_t *client;
 261 
 262         /*
 263          * Initialize the CS global structure
 264          */
 265         bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
 266 
 267         mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
 268         mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
 269 
 270         cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
 271 
 272         /*
 273          * Set up the global Socket Services client, since we're going to
 274          *      need it once we register with SS.
 275          */
 276         client = &cs_socket_services_client;
 277         bzero((caddr_t)client, sizeof (client_t));
 278         client->client_handle = CS_SS_CLIENT_HANDLE;
 279         client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
 280 
 281         /*
 282          * Setup the client type structure - this is used in the socket event
 283          *      thread to sequence the delivery of events to all clients on
 284          *      the socket.
 285          */
 286         ct = &client_types[0];
 287         ct->type = INFO_IO_CLIENT;
 288         ct->order = CLIENT_EVENTS_LIFO;
 289         ct->next = &client_types[1];
 290 
 291         ct = ct->next;
 292         ct->type = INFO_MTD_CLIENT;
 293         ct->order = CLIENT_EVENTS_FIFO;
 294         ct->next = &client_types[2];
 295 
 296         ct = ct->next;
 297         ct->type = INFO_MEM_CLIENT;
 298         ct->order = CLIENT_EVENTS_FIFO;
 299         ct->next = NULL;
 300 
 301         return (CS_SUCCESS);
 302 }
 303 
 304 /*
 305  * cs_deinit - Deinitialize CS
 306  *
 307  * This function cleans up any allocated resources, stops any running threads,
 308  *      destroys any mutexes and condition variables, and finally frees up the
 309  *      global socket and window structure arrays.
 310  */
 311 int
 312 cs_deinit()
 313 {
 314         cs_socket_t *sp;
 315         int sn, have_clients = 0, have_sockets = 0;
 316         cs_register_cardservices_t rcs;
 317 
 318 #if defined(CS_DEBUG)
 319         if (cs_debug > 1)
 320             cmn_err(CE_CONT, "CS: cs_deinit\n");
 321 #endif
 322 
 323         /*
 324          * Deregister with the Card Services kernel stubs module
 325          */
 326         rcs.magic = CS_STUBS_MAGIC;
 327         rcs.function = CS_ENTRY_DEREGISTER;
 328         (void) csx_register_cardservices(&rcs);
 329 
 330         /*
 331          * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
 332          *      from registering.
 333          */
 334         mutex_enter(&cs_globals.global_lock);
 335         cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
 336         mutex_exit(&cs_globals.global_lock);
 337 
 338         /*
 339          * Go through each socket and make sure that there are no clients
 340          *      on any of the sockets.  If there are, we can't deinit until
 341          *      all the clients for every socket are gone.
 342          */
 343         for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
 344             if ((sp = cs_get_sp(sn)) != NULL) {
 345                 have_sockets++;
 346                 if (sp->client_list) {
 347                     cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
 348                                 "socket %d has registered clients\n", sn);
 349                     have_clients++;
 350                 }
 351             }
 352         }
 353 
 354         /*
 355          * We don't allow unload if there are any clients registered
 356          *      or if there are still sockets that are active.
 357          */
 358         if ((have_clients > 0) || (have_sockets > 0))
 359             return (BAD_FUNCTION);
 360 
 361 #ifdef  XXX
 362         /*
 363          * If one or more sockets have been added, we need to deallocate
 364          *      the resources associated with those sockets.
 365          */
 366 
 367         /*
 368          * First, tell Socket Services that we're leaving, so that we
 369          *      don't get any more event callbacks.
 370          */
 371         SocketServices(CSUnregister);
 372 
 373         /*
 374          * Wait for the soft int timer to tell us it's done
 375          */
 376         mutex_enter(&cs_globals.global_lock);
 377         cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
 378         mutex_exit(&cs_globals.global_lock);
 379         UNTIMEOUT(cs_globals.sotfint_tmo);
 380 
 381         /*
 382          * Remove the soft interrupt handler.
 383          */
 384         mutex_enter(&cs_globals.global_lock);
 385         if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
 386             ddi_remove_softintr(cs_globals.softint_id);
 387             cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
 388         }
 389         mutex_exit(&cs_globals.global_lock);
 390 
 391         return (CS_SUCCESS);
 392 
 393         /*
 394          * Go through each socket and free any resource allocated to that
 395          *      socket, as well as any mutexs and condition variables.
 396          */
 397         for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
 398             set_socket_t set_socket;
 399 
 400             if ((sp = cs_get_sp(sn)) != NULL) {
 401 
 402                 /*
 403                  * untimeout possible pending ready/busy timer
 404                  */
 405                 UNTIMEOUT(sp->rdybsy_tmo_id);
 406 
 407                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 408                     mutex_enter(&sp->lock);
 409                 sp->flags = SOCKET_UNLOAD_MODULE;
 410                 if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
 411                     sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
 412                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 413                     mutex_exit(&sp->lock);
 414 
 415                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 416                     mutex_enter(&sp->cis_lock);
 417                 (void) cs_destroy_cis(sp);
 418                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 419                     mutex_exit(&sp->cis_lock);
 420 
 421                 /*
 422                  * Tell the event handler thread that we want it to exit, then
 423                  *      wait around until it tells us that it has exited.
 424                  */
 425                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 426                     mutex_enter(&sp->client_lock);
 427                 if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
 428                     sp->thread_state = SOCKET_THREAD_EXIT;
 429                     cv_broadcast(&sp->thread_cv);
 430                     cv_wait(&sp->caller_cv, &sp->client_lock);
 431                 }
 432                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 433                     mutex_exit(&sp->client_lock);
 434 
 435                 /*
 436                  * Tell the SS work thread that we want it to exit, then
 437                  *      wait around until it tells us that it has exited.
 438                  */
 439                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 440                     mutex_enter(&sp->ss_thread_lock);
 441                 if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
 442                     sp->ss_thread_state = SOCKET_THREAD_EXIT;
 443                     cv_broadcast(&sp->ss_thread_cv);
 444                     cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
 445                 }
 446 
 447                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
 448                     mutex_exit(&sp->ss_thread_lock);
 449 
 450                 /*
 451                  * Free the mutexii and condition variables that we used.
 452                  */
 453                 if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
 454                     mutex_destroy(&sp->lock);
 455                     mutex_destroy(&sp->client_lock);
 456                     mutex_destroy(&sp->cis_lock);
 457                     mutex_destroy(&sp->ss_thread_lock);
 458                 }
 459 
 460                 if (sp->init_state & SOCKET_INIT_STATE_CV) {
 461                     cv_destroy(&sp->thread_cv);
 462                     cv_destroy(&sp->caller_cv);
 463                     cv_destroy(&sp->reset_cv);
 464                     cv_destroy(&sp->ss_thread_cv);
 465                     cv_destroy(&sp->ss_caller_cv);
 466                 }
 467 
 468 #ifdef  USE_IOMMAP_WINDOW
 469                 /*
 470                  * Free the memory-mapped IO structure if we allocated one.
 471                  */
 472                 if (sp->io_mmap_window)
 473                     kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
 474 #endif  /* USE_IOMMAP_WINDOW */
 475 
 476                 /*
 477                  * Return the socket to memory-only mode and turn off the
 478                  *      socket power.
 479                  */
 480                 sp->event_mask = 0;
 481                 set_socket.socket = sp->socket_num;
 482                 set_socket.SCIntMask = 0;
 483                 set_socket.IREQRouting = 0;
 484                 set_socket.IFType = IF_MEMORY;
 485                 set_socket.CtlInd = 0; /* turn off controls and indicators */
 486                 set_socket.State = (unsigned)~0; /* clear latched state bits */
 487 
 488                 (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
 489                                                 &set_socket.VccLevel);
 490                 (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
 491                                                 &set_socket.Vpp1Level);
 492                 (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
 493                                                 &set_socket.Vpp2Level);
 494 
 495                 /*
 496                  * If we fail this call, there's not much we can do, so
 497                  *      just continue with the resource deallocation.
 498                  */
 499                 if ((ret =
 500                         SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
 501                     cmn_err(CE_CONT,
 502                         "cs_deinit: socket %d SS_SetSocket failure %d\n",
 503                                                         sp->socket_num, ret);
 504                 }
 505             } /* cs_get_sp */
 506         } /* for (sn) */
 507 #endif  /* XXX */
 508 
 509         /*
 510          * Destroy the global mutexii.
 511          */
 512         mutex_destroy(&cs_globals.global_lock);
 513         mutex_destroy(&cs_globals.window_lock);
 514 
 515 #ifdef  XXX
 516         /*
 517          * Free the global "super-client" structure
 518          */
 519         if (cs_globals.sclient_list)
 520             kmem_free(cs_globals.sclient_list,
 521                 (cs_globals.num_sockets * sizeof (struct sclient_list_t)));
 522         cs_globals.sclient_list = NULL;
 523 #endif  /* XXX */
 524 
 525         return (CS_SUCCESS);
 526 }
 527 
 528 /*
 529  * ==== drip, drip, drip - the Card Services waterfall :-) ====
 530  */
 531 
 532 /*
 533  * CardServices - general Card Services entry point for CS clients
 534  *                      and Socket Services; the address of this
 535  *                      function is handed to SS via the CSRegister
 536  *                      SS call
 537  */
 538 int
 539 CardServices(int function, ...)
 540 {
 541         va_list arglist;
 542         int retcode = CS_UNSUPPORTED_FUNCTION;
 543 
 544         cs_socket_t     *socp;
 545         uint32_t        *offp;
 546         acc_handle_t    *hp;
 547         client_handle_t ch;
 548         client_handle_t *chp;
 549         window_handle_t wh;
 550         window_handle_t *whp;
 551         tuple_t         *tuple;
 552         cisparse_t      *cisparse;
 553 
 554 #ifdef  CS_DEBUG
 555         if (cs_debug > 127) {
 556             cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
 557                                 cs_error2text(function, CSFUN2TEXT_FUNCTION),
 558                                 function);
 559         }
 560 #endif
 561 
 562         va_start(arglist, function);
 563 
 564         /*
 565          * Here's the Card Services waterfall
 566          */
 567         switch (function) {
 568         /*
 569          * We got here as a result of the CIS module calling us
 570          *      in response to cs_ss_init() calling the CIS module
 571          *      at CIS_PARSER(CISP_CIS_SETUP, ...)
 572          */
 573             case CISRegister: {
 574                 cisregister_t *cisr;
 575 
 576                     cisr = va_arg(arglist, cisregister_t *);
 577 
 578                     if (cisr->cis_magic != PCCS_MAGIC ||
 579                         cisr->cis_version != PCCS_VERSION) {
 580                             cmn_err(CE_WARN,
 581                                 "CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
 582                                         (long)cisr->cis_magic,
 583                                         (long)cisr->cis_version,
 584                                         (long)cisr->cis_parser,
 585                                         (long)cisr->cistpl_std_callout);
 586                         retcode = CS_BAD_ARGS;
 587                     } else {
 588                         /*
 589                          * Replace the CIS Parser entry point if
 590                          *      necessary.
 591                          */
 592                         if (cisr->cis_parser != NULL)
 593                             cis_parser = cisr->cis_parser;
 594                         cis_cistpl_std_callout = cisr->cistpl_std_callout;
 595                         retcode = CS_SUCCESS;
 596                     }
 597                 }
 598                 break;
 599             case CISUnregister: /* XXX - should we do some more checking */
 600                 /* XXX - need to protect this by a mutex */
 601                 cis_parser = NULL;
 602                 cis_cistpl_std_callout = NULL;
 603                 retcode = CS_SUCCESS;
 604                 break;
 605             case InitCISWindow:
 606                 socp    = va_arg(arglist, cs_socket_t *);
 607                 offp    = va_arg(arglist, uint32_t *);
 608                 hp      = va_arg(arglist, acc_handle_t *);
 609                 retcode = cs_init_cis_window(socp, offp, hp,
 610                                 va_arg(arglist, uint32_t));
 611                 break;
 612             case RegisterClient:
 613                 chp = va_arg(arglist, client_handle_t *),
 614                 retcode = cs_register_client(chp,
 615                                 va_arg(arglist, client_reg_t *));
 616                 break;
 617             case DeregisterClient:
 618                 retcode = cs_deregister_client(
 619                                 va_arg(arglist, client_handle_t));
 620                 break;
 621             case GetStatus:
 622                 ch = va_arg(arglist, client_handle_t);
 623                 retcode = cs_get_status(ch,
 624                                 va_arg(arglist, get_status_t *));
 625                 break;
 626             case ResetFunction:
 627                 ch = va_arg(arglist, client_handle_t);
 628                 retcode = cs_reset_function(ch,
 629                                 va_arg(arglist, reset_function_t *));
 630                 break;
 631             case SetEventMask:
 632                 ch = va_arg(arglist, client_handle_t);
 633                 retcode = cs_set_event_mask(ch,
 634                                 va_arg(arglist, sockevent_t *));
 635                 break;
 636             case GetEventMask:
 637                 ch = va_arg(arglist, client_handle_t);
 638                 retcode = cs_get_event_mask(ch,
 639                                 va_arg(arglist, sockevent_t *));
 640                 break;
 641             case RequestIO:
 642                 ch = va_arg(arglist, client_handle_t);
 643                 retcode = cs_request_io(ch,
 644                                 va_arg(arglist, io_req_t *));
 645                 break;
 646             case ReleaseIO:
 647                 ch = va_arg(arglist, client_handle_t);
 648                 retcode = cs_release_io(ch,
 649                                 va_arg(arglist, io_req_t *));
 650                 break;
 651             case RequestIRQ:
 652                 ch = va_arg(arglist, client_handle_t);
 653                 retcode = cs_request_irq(ch,
 654                                 va_arg(arglist, irq_req_t *));
 655                 break;
 656             case ReleaseIRQ:
 657                 ch = va_arg(arglist, client_handle_t);
 658                 retcode = cs_release_irq(ch,
 659                                 va_arg(arglist, irq_req_t *));
 660                 break;
 661             case RequestWindow:
 662                 ch = va_arg(arglist, client_handle_t);
 663                 whp = va_arg(arglist, window_handle_t *);
 664                 retcode = cs_request_window(ch, whp,
 665                                 va_arg(arglist, win_req_t *));
 666                 break;
 667             case ReleaseWindow:
 668                 retcode = cs_release_window(
 669                                 va_arg(arglist, window_handle_t));
 670                 break;
 671             case ModifyWindow:
 672                 wh = va_arg(arglist, window_handle_t);
 673                 retcode = cs_modify_window(wh,
 674                                 va_arg(arglist, modify_win_t *));
 675                 break;
 676             case MapMemPage:
 677                 wh = va_arg(arglist, window_handle_t);
 678                 retcode = cs_map_mem_page(wh,
 679                                 va_arg(arglist, map_mem_page_t *));
 680                 break;
 681             case RequestSocketMask:
 682                 ch = va_arg(arglist, client_handle_t);
 683                 retcode = cs_request_socket_mask(ch,
 684                                 va_arg(arglist, request_socket_mask_t *));
 685                 break;
 686             case ReleaseSocketMask:
 687                 ch = va_arg(arglist, client_handle_t);
 688                 retcode = cs_release_socket_mask(ch,
 689                                 va_arg(arglist, release_socket_mask_t *));
 690                 break;
 691             case RequestConfiguration:
 692                 ch = va_arg(arglist, client_handle_t);
 693                 retcode = cs_request_configuration(ch,
 694                                 va_arg(arglist, config_req_t *));
 695                 break;
 696             case GetPhysicalAdapterInfo:
 697                 ch = va_arg(arglist, client_handle_t);
 698                 retcode = cs_get_physical_adapter_info(ch,
 699                                 va_arg(arglist, get_physical_adapter_info_t *));
 700                 break;
 701             case GetCardServicesInfo:
 702                 ch = va_arg(arglist, client_handle_t);
 703                 retcode = cs_get_cardservices_info(ch,
 704                                 va_arg(arglist, get_cardservices_info_t *));
 705                 break;
 706             case GetConfigurationInfo:
 707                 chp = va_arg(arglist, client_handle_t *);
 708                 retcode = cs_get_configuration_info(chp,
 709                                 va_arg(arglist, get_configuration_info_t *));
 710                 break;
 711             case ModifyConfiguration:
 712                 ch = va_arg(arglist, client_handle_t);
 713                 retcode = cs_modify_configuration(ch,
 714                                 va_arg(arglist, modify_config_t *));
 715                 break;
 716             case AccessConfigurationRegister:
 717                 ch = va_arg(arglist, client_handle_t);
 718                 retcode = cs_access_configuration_register(ch,
 719                                 va_arg(arglist, access_config_reg_t *));
 720                 break;
 721             case ReleaseConfiguration:
 722                 ch = va_arg(arglist, client_handle_t);
 723                 retcode = cs_release_configuration(ch,
 724                                 va_arg(arglist, release_config_t *));
 725                 break;
 726             case OpenMemory:
 727                 cmn_err(CE_CONT, "CS: OpenMemory\n");
 728                 break;
 729             case ReadMemory:
 730                 cmn_err(CE_CONT, "CS: ReadMemory\n");
 731                 break;
 732             case WriteMemory:
 733                 cmn_err(CE_CONT, "CS: WriteMemory\n");
 734                 break;
 735             case CopyMemory:
 736                 cmn_err(CE_CONT, "CS: CopyMemory\n");
 737                 break;
 738             case RegisterEraseQueue:
 739                 cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
 740                 break;
 741             case CheckEraseQueue:
 742                 cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
 743                 break;
 744             case DeregisterEraseQueue:
 745                 cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
 746                 break;
 747             case CloseMemory:
 748                 cmn_err(CE_CONT, "CS: CloseMemory\n");
 749                 break;
 750             case GetFirstRegion:
 751                 cmn_err(CE_CONT, "CS: GetFirstRegion\n");
 752                 break;
 753             case GetNextRegion:
 754                 cmn_err(CE_CONT, "CS: GetNextRegion\n");
 755                 break;
 756             case GetFirstPartition:
 757                 cmn_err(CE_CONT, "CS: GetFirstPartition\n");
 758                 break;
 759             case GetNextPartition:
 760                 cmn_err(CE_CONT, "CS: GetNextPartition\n");
 761                 break;
 762             case ReturnSSEntry:
 763                 cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
 764                 break;
 765             case MapLogSocket:
 766                 ch = va_arg(arglist, client_handle_t);
 767                 retcode = cs_map_log_socket(ch,
 768                                 va_arg(arglist, map_log_socket_t *));
 769                 break;
 770             case MapPhySocket:
 771                 cmn_err(CE_CONT, "CS: MapPhySocket\n");
 772                 break;
 773             case MapLogWindow:
 774                 cmn_err(CE_CONT, "CS: MapLogWindow\n");
 775                 break;
 776             case MapPhyWindow:
 777                 cmn_err(CE_CONT, "CS: MapPhyWindow\n");
 778                 break;
 779             case RegisterMTD:
 780                 cmn_err(CE_CONT, "CS: RegisterMTD\n");
 781                 break;
 782             case RegisterTimer:
 783                 cmn_err(CE_CONT, "CS: RegisterTimer\n");
 784                 break;
 785             case SetRegion:
 786                 cmn_err(CE_CONT, "CS: SetRegion\n");
 787                 break;
 788             case RequestExclusive:
 789                 cmn_err(CE_CONT, "CS: RequestExclusive\n");
 790                 break;
 791             case ReleaseExclusive:
 792                 cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
 793                 break;
 794             case GetFirstClient:
 795                 retcode = cs_get_firstnext_client(
 796                                 va_arg(arglist, get_firstnext_client_t *),
 797                                 CS_GET_FIRST_FLAG);
 798                 break;
 799             case GetNextClient:
 800                 retcode = cs_get_firstnext_client(
 801                                 va_arg(arglist, get_firstnext_client_t *),
 802                                 CS_GET_NEXT_FLAG);
 803                 break;
 804             case GetClientInfo:
 805                 ch = va_arg(arglist, client_handle_t);
 806                 retcode = cs_get_client_info(ch,
 807                                 va_arg(arglist, client_info_t *));
 808                 break;
 809             case AddSocketServices:
 810                 cmn_err(CE_CONT, "CS: AddSocketServices\n");
 811                 break;
 812             case ReplaceSocketServices:
 813                 cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
 814                 break;
 815             case VendorSpecific:
 816                 cmn_err(CE_CONT, "CS: VendorSpecific\n");
 817                 break;
 818             case AdjustResourceInfo:
 819                 cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
 820                 break;
 821             case ValidateCIS:
 822                 ch = va_arg(arglist, client_handle_t);
 823                 retcode = cs_validate_cis(ch,
 824                                 va_arg(arglist, cisinfo_t *));
 825                 break;
 826             case GetFirstTuple:
 827                 ch = va_arg(arglist, client_handle_t);
 828                 retcode = cs_get_firstnext_tuple(ch,
 829                                 va_arg(arglist, tuple_t *),
 830                                 CS_GET_FIRST_FLAG);
 831                 break;
 832             case GetNextTuple:
 833                 ch = va_arg(arglist, client_handle_t);
 834                 retcode = cs_get_firstnext_tuple(ch,
 835                                 va_arg(arglist, tuple_t *),
 836                                 CS_GET_NEXT_FLAG);
 837                 break;
 838             case GetTupleData:
 839                 ch = va_arg(arglist, client_handle_t);
 840                 retcode = cs_get_tuple_data(ch,
 841                                 va_arg(arglist, tuple_t *));
 842                 break;
 843             case ParseTuple:
 844                 ch = va_arg(arglist, client_handle_t);
 845                 tuple = va_arg(arglist, tuple_t *);
 846                 cisparse = va_arg(arglist, cisparse_t *);
 847                 retcode = cs_parse_tuple(ch, tuple, cisparse,
 848                                 va_arg(arglist, uint_t));
 849                 break;
 850             case MakeDeviceNode:
 851                 ch = va_arg(arglist, client_handle_t);
 852                 retcode = cs_make_device_node(ch,
 853                                 va_arg(arglist, make_device_node_t *));
 854                 break;
 855             case RemoveDeviceNode:
 856                 ch = va_arg(arglist, client_handle_t);
 857                 retcode = cs_remove_device_node(ch,
 858                                 va_arg(arglist, remove_device_node_t *));
 859                 break;
 860             case ConvertSpeed:
 861                 retcode = cs_convert_speed(
 862                                 va_arg(arglist, convert_speed_t *));
 863                 break;
 864             case ConvertSize:
 865                 retcode = cs_convert_size(
 866                                 va_arg(arglist, convert_size_t *));
 867                 break;
 868             case Event2Text:
 869                 retcode = cs_event2text(
 870                                 va_arg(arglist, event2text_t *), 1);
 871                 break;
 872             case Error2Text: {
 873                 error2text_t *cft;
 874 
 875                 cft = va_arg(arglist, error2text_t *);
 876                 (void) strcpy(cft->text,
 877                                 cs_error2text(cft->item, CSFUN2TEXT_RETURN));
 878                 retcode = CS_SUCCESS;
 879                 }
 880                 break;
 881             case CS_DDI_Info:
 882                 retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
 883                 break;
 884             case CS_Sys_Ctl:
 885                 retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
 886                 break;
 887             default:
 888                 cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
 889                 break;
 890         } /* switch(function) */
 891 
 892         va_end(arglist);
 893 
 894 #ifdef  CS_DEBUG
 895         if (cs_debug > 127) {
 896             cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
 897                                 cs_error2text(retcode, CSFUN2TEXT_RETURN),
 898                                 retcode);
 899         }
 900 #endif
 901 
 902         return (retcode);
 903 }
 904 
 905 /*
 906  * ==== tuple and CIS handling section ====
 907  */
 908 
 909 /*
 910  * cs_parse_tuple - This function supports the CS ParseTuple function call.
 911  *
 912  *    returns:  CS_SUCCESS - if tuple parsed sucessfully
 913  *              CS_NO_CARD - if no card in socket
 914  *              CS_BAD_ARGS - if passed CIS list pointer is NULL
 915  *              CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
 916  *              CS_BAD_CIS - if generic parser error
 917  *              CS_NO_CIS - if no CIS for card/function
 918  *
 919  *    See notes for the cs_get_firstnext_tuple function.
 920  */
 921 static int
 922 cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
 923                                 cisparse_t *cisparse, cisdata_t cisdata)
 924 {
 925         cs_socket_t *sp;
 926         client_t *client;
 927         uint32_t fn;
 928         int ret;
 929 
 930         if ((ret = cs_get_socket(client_handle, &tuple->Socket,
 931                                         &fn, &sp, &client)) != CS_SUCCESS)
 932             return (ret);
 933 
 934         /*
 935          * If there's no card in the socket or the card in the socket is not
 936          *      for this client, then return an error.
 937          */
 938         if (!(client->flags & CLIENT_CARD_INSERTED))
 939             return (CS_NO_CARD);
 940 
 941         /*
 942          * Sanity check to be sure that we've got a non-NULL CIS list
 943          *      pointer.
 944          */
 945         if (!(tuple->CISOffset))
 946             return (CS_BAD_ARGS);
 947 
 948         mutex_enter(&sp->cis_lock);
 949 
 950         /*
 951          * Check to see if there is a valid CIS for this function.
 952          *      There is an implicit assumption here that if this
 953          *      is a multi-function CIS and the specified function
 954          *      number is not CS_GLOBAL_CIS that in order for there
 955          *      to be a valid function-specific CIS, there also must
 956          *      be a valid global CIS. This means that we don't need
 957          *      to know whether this tuple came from the global CIS
 958          *      or from the function-specific CIS.
 959          */
 960         if ((sp->cis_flags & CW_VALID_CIS) &&
 961                                 (sp->cis[fn].flags & CW_VALID_CIS)) {
 962             ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
 963                                 cis_cistpl_std_callout,
 964                                 tuple->CISOffset,
 965                                 (tuple->Attributes & TUPLE_RETURN_NAME)?
 966                                                         HANDTPL_RETURN_NAME:
 967                                                         HANDTPL_PARSE_LTUPLE,
 968                                 cisparse, cisdata);
 969             mutex_exit(&sp->cis_lock);
 970             if (ret == CISTPLF_UNKNOWN)
 971                 return (CS_UNKNOWN_TUPLE);
 972             if (ret != CISTPLF_NOERROR)
 973                 return (CS_BAD_CIS);
 974             ret = CS_SUCCESS;
 975         } else {
 976             mutex_exit(&sp->cis_lock);
 977             ret = CS_NO_CIS;
 978         } /* if (CW_VALID_CIS) */
 979 
 980         return (ret);
 981 }
 982 
 983 /*
 984  * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
 985  *                              this is to support the GetFirstTuple and
 986  *                              GetNextTuple function call
 987  *
 988  *    flags - one of:
 989  *              CS_GET_FIRST_FLAG causes function to support GetFirstTuple
 990  *              CS_GET_NEXT_FLAG causes function to support GetNextTuple
 991  *
 992  *      tuple_t->Attributes flags:
 993  *              TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
 994  *              TUPLE_RETURN_IGNORED_TUPLES - return tuples with
 995  *                              CISTPLF_IGNORE_TUPLE set in the
 996  *                              cistpl_t->flags member.
 997  *
 998  *    Notes for regular PC card driver callers:
 999  *
1000  *      On a single-function card, the caller will get back all the tuples in
1001  *      the CIS.
1002  *
1003  *      On a multi-function card, the caller will get the tuples from the
1004  *      global CIS followed by the tuples in the function-specific CIS. The
1005  *      caller will not get any tuples from a function-specific CIS that
1006  *      does not belong to the caller's function.
1007  *
1008  *    Notes for Socket Services, the "super-client" or CSI driver callers:
1009  *
1010  *      On a single-function card, the operation is the same as for regular
1011  *      PC card driver callers with the addition that if the function number
1012  *      is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
1013  *
1014  *      On a multi-function card, the operation is the same as for regular
1015  *      PC card driver callers with the addition that if the function number
1016  *      is set to CS_GLOBAL_CIS the caller will only get tuples from the
1017  *      global CIS. If a particular function nubmer does not exist, this
1018  *      function will return CS_NO_CIS for that function.
1019  *
1020  *    General notes:
1021  *
1022  *      On both a single-function card and a multi-function card, if the tuple
1023  *      comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
1024  *      set in the tuple_t->flags member.
1025  *
1026  *      On a multi-function card, if the tuple comes from the function-specific
1027  *      CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
1028  *      member.
1029  *
1030  *      For other flags that are set in the tuple_t->flags member, see the
1031  *      comments for the cis_list_lcreate function in the cis.c file.
1032  *
1033  *      The CIS parser may not include all the tuples that are in the CIS in
1034  *      the private CIS list that it creates and maintains. See the CIS
1035  *      parser documentation for a list of tuples that the parser does not
1036  *      include in the list.
1037  *
1038  *      If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
1039  *      parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
1040  *      be returned to the caller. Instead, the next tuple that matches
1041  *      the calling criteria will be returned (or NULL if no other tuples
1042  *      match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
1043  *      the flags paramter, tuples in the CIS list that match the calling
1044  *      criteria will be returned.
1045  *
1046  * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
1047  *      the tuple_t->Attributes member is not set, then we don't return
1048  *      any of the link tuples. This function ignores this flag and always
1049  *      returns link tuples.
1050  *
1051  *    Return codes:
1052  *              CS_SUCCESS - if tuple sucessfully found and returned
1053  *              CS_NO_CARD - if no card inserted
1054  *              CS_NO_CIS - if no CIS for the specified card/function
1055  *              CS_NO_MORE_ITEMS - if tuple not found or no more tuples
1056  *                                      to return
1057  *
1058  *    See notes for cs_get_socket for a description of valid client, socket
1059  *      and function number combinations.
1060  */
1061 static int
1062 cs_get_firstnext_tuple(client_handle_t client_handle,
1063     tuple_t *tuple, uint32_t flags)
1064 {
1065         cs_socket_t *sp;
1066         client_t *client;
1067         uint32_t fn;
1068         int ret;
1069 
1070         if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
1071                                                 &sp, &client)) != CS_SUCCESS)
1072             return (ret);
1073 
1074         /*
1075          * If there's no card in the socket or the card in the socket is not
1076          *      for this client, then return an error.
1077          */
1078         if (!(client->flags & CLIENT_CARD_INSERTED))
1079             return (CS_NO_CARD);
1080 
1081         mutex_enter(&sp->cis_lock);
1082 
1083         /*
1084          * If there's no CIS on this card or no CIS for the specified
1085          *      function, then we can't do much.
1086          */
1087         if ((!(sp->cis_flags & CW_VALID_CIS)) ||
1088                                 (!(sp->cis[fn].flags & CW_VALID_CIS))) {
1089             mutex_exit(&sp->cis_lock);
1090             return (CS_NO_CIS);
1091         }
1092 
1093         /*
1094          * This will set the CIS_GET_LTUPLE_IGNORE flag if the
1095          *      TUPLE_RETURN_IGNORED_TUPLES flag is set. The
1096          *      assumption here is that the CIS_GET_LTUPLE_IGNORE
1097          *      flag and the TUPLE_RETURN_IGNORED_TUPLES flag
1098          *      shares the same bit position. If this ever changes,
1099          *      we'll ahve to re-work this section of code.
1100          */
1101         if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
1102             flags |= CIS_GET_LTUPLE_IGNORE;
1103 
1104         /*
1105          * Are we GetFirstTuple or GetNextTuple?
1106          */
1107         if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
1108         /*
1109          * Initialize the tuple structure; we need this information when
1110          *      we have to process a GetNextTuple or ParseTuple call.
1111          * If this card has a multi-function CIS, then we always start out
1112          *      delivering tuples from the global CIS chain. If this card does
1113          *      not have a multi-function CIS, then the function 0 CIS chain
1114          *      will contain the complete CIS list.
1115          * If this is a multi-function card, then use the GET_FIRST_LTUPLE
1116          *      macro to return the first tuple in the CIS list - we do this
1117          *      since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
1118          *      set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
1119          * Note that we don't have to cross over into the fucntion-specific
1120          *      CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
1121          *      always have at least a CISTPL_LONGLINK_MFC tuple in the global
1122          *      CIS chain - the test for NULL is just a sanity check.
1123          */
1124             if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1125                 if ((tuple->CISOffset =
1126                         GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
1127                                                         flags)) == NULL) {
1128                     mutex_exit(&sp->cis_lock);
1129                     return (CS_NO_MORE_ITEMS);
1130                 } /* GET_FIRST_LTUPLE */
1131             } else {
1132                 tuple->CISOffset = sp->cis[0].cis;
1133             } /* CW_MULTI_FUNCTION_CIS */
1134         } else {
1135             cistpl_t *tp;
1136 
1137                 /*
1138                  * Check to be sure that we have a non-NULL tuple list pointer.
1139                  *      This is necessary in the case where the caller calls us
1140                  *      with get next tuple requests but we don't have any more
1141                  *      tuples to give back.
1142                  */
1143             if (tuple->CISOffset == NULL) {
1144                 mutex_exit(&sp->cis_lock);
1145                 return (CS_NO_MORE_ITEMS);
1146             }
1147 
1148                 /*
1149                  * Point to the next tuple in the list.  If we're searching for
1150                  *      a particular tuple, FIND_LTUPLE_FWD will find it.
1151                  *
1152                  * If there are no more tuples in the chain that we're looking
1153                  *      at, then if we're looking at the global portion of a
1154                  *      multi-function CIS, switch to the function-specific list
1155                  *      and start looking there.
1156                  */
1157             if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
1158                 if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1159                     if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
1160                                                         (fn != CS_GLOBAL_CIS)) {
1161                         tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
1162                     } /* CISTPLF_GLOBAL_CIS */
1163                 } /* CW_MULTI_FUNCTION_CIS */
1164             } /* GET_NEXT_TUPLE */
1165 
1166                 /*
1167                  * If there are no more tuples in the chain, then return.
1168                  */
1169             if ((tuple->CISOffset = tp) == NULL) {
1170                 mutex_exit(&sp->cis_lock);
1171                 return (CS_NO_MORE_ITEMS);
1172             }
1173         } /* CS_GET_FIRST_FLAG */
1174 
1175         /*
1176          * Check if we want to get the first of a particular type of tuple
1177          *      or just the first tuple in the chain.
1178          * If there are no more tuples of the type we're searching for in
1179          *      the chain that we're looking at, then if we're looking at
1180          *      the global portion of a multi-function CIS, switch to the
1181          *      function-specific list and start looking there.
1182          */
1183         if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
1184             cistpl_t *tp;
1185 
1186             if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
1187                                         tuple->DesiredTuple, flags)) == NULL) {
1188                 if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1189                     if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
1190                                                         (fn != CS_GLOBAL_CIS)) {
1191                         tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
1192                                                 tuple->DesiredTuple, flags);
1193                     } /* CISTPLF_GLOBAL_CIS */
1194                 } /* CW_MULTI_FUNCTION_CIS */
1195             } /* FIND_LTUPLE_FWD */
1196 
1197                 /*
1198                  * If there are no more tuples in the chain, then return.
1199                  */
1200             if ((tuple->CISOffset = tp) == NULL) {
1201                 mutex_exit(&sp->cis_lock);
1202                 return (CS_NO_MORE_ITEMS);
1203             }
1204         } /* !RETURN_FIRST_TUPLE */
1205 
1206         /*
1207          * We've got a tuple, now fill out the rest of the tuple_t
1208          *      structure.  Callers can use the flags member to
1209          *      determine whether or not the tuple data was copied
1210          *      to the linked list or if it's still on the card.
1211          */
1212         tuple->Flags = tuple->CISOffset->flags;
1213         tuple->TupleCode = tuple->CISOffset->type;
1214         tuple->TupleLink = tuple->CISOffset->len;
1215         tuple->TupleDataLen = tuple->CISOffset->len;
1216 
1217         mutex_exit(&sp->cis_lock);
1218 
1219         return (CS_SUCCESS);
1220 }
1221 
1222 /*
1223  * cs_get_tuple_data - get the data portion of a tuple; this is to
1224  *      support the GetTupleData function call.
1225  *
1226  *    Note that if the data body of a tuple was not read from the CIS,
1227  *      then this function will return CS_NO_MORE_ITEMS.
1228  *
1229  *    For flags that are set in the tuple_t->flags member, see the
1230  *      comments for the cis_list_lcreate function in the cis.c file.
1231  *      These flags are copied into the tuple_t->flags member by the
1232  *      cs_get_firstnext_tuple function call.
1233  *
1234  *    See notes for the cs_get_firstnext_tuple function.
1235  */
1236 static int
1237 cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
1238 {
1239         cs_socket_t *sp;
1240         client_t *client;
1241         int ret, nbytes;
1242         uint32_t fn, flags;
1243         cisdata_t *tsd, *tdd;
1244         uint32_t newoffset;
1245         acc_handle_t cis_handle;
1246 
1247         if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
1248                                                 &sp, &client)) != CS_SUCCESS)
1249             return (ret);
1250 
1251         /*
1252          * If there's no card in the socket or the card in the socket is not
1253          *      for this client, then return an error.
1254          */
1255         if (!(client->flags & CLIENT_CARD_INSERTED))
1256             return (CS_NO_CARD);
1257 
1258         mutex_enter(&sp->cis_lock);
1259 
1260         if ((sp->cis_flags & CW_VALID_CIS) &&
1261                                 (sp->cis[fn].flags & CW_VALID_CIS)) {
1262 
1263                 /*
1264                  * Check to be sure that we have a non-NULL pointer to
1265                  *      a CIS list.
1266                  */
1267             if (!(tuple->CISOffset)) {
1268                 mutex_exit(&sp->cis_lock);
1269                 return (CS_NO_MORE_ITEMS);
1270             }
1271 
1272         /*
1273          * Since the tuple data buffer that the caller calls us with
1274          *      is preallocated in the tuple_t structure, we ignore any
1275          *      TupleDataMax value that the caller has setup and use the
1276          *      actual size of the tuple data buffer in the structure.
1277          */
1278             tuple->TupleDataMax = sizeof (tuple->TupleData);
1279 
1280         /*
1281          * Make sure the requested offset is not past the end of the
1282          *      tuple data body nor past the end of the user-supplied
1283          *      buffer.
1284          */
1285             if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
1286                                                 (int)tuple->TupleDataMax)) {
1287                 mutex_exit(&sp->cis_lock);
1288                 return (CS_NO_MORE_ITEMS);
1289             }
1290 
1291             tuple->TupleDataLen = tuple->TupleLink;
1292 
1293             if ((nbytes = min((int)tuple->TupleDataMax -
1294                                                 (int)tuple->TupleOffset,
1295                                                 (int)tuple->TupleDataLen -
1296                                                 (int)tuple->TupleOffset)) < 1) {
1297                 mutex_exit(&sp->cis_lock);
1298                 return (CS_BAD_ARGS);
1299             }
1300 
1301         /*
1302          * The tuple data destination is always the tuple_t->TupleData
1303          *      buffer in the tuple_t structure no matter where we read the
1304          *      tuple data from.
1305          */
1306             tdd = tuple->TupleData;
1307             bzero((caddr_t)tdd, sizeof (tuple->TupleData));
1308 
1309         /*
1310          * Do we have a copy of the tuple data?  If not, we have to
1311          *      get a pointer to the CIS and read the tuple data from the
1312          *      card itself.
1313          */
1314             switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
1315                 case CISTPLF_LM_SPACE:
1316                     tsd = (tuple->CISOffset->data +
1317                                         (unsigned)tuple->TupleOffset);
1318                     while (nbytes--)
1319                         *tdd++ = *tsd++;
1320                     break;
1321                 case CISTPLF_AM_SPACE:
1322                 case CISTPLF_CM_SPACE:
1323                     newoffset = tuple->CISOffset->offset;
1324 
1325                 /*
1326                  * Setup the proper space flags as well as setup the
1327                  *      address offset to point to the start of the tuple
1328                  *      data area; we need to do the latter since the
1329                  *      cis_store_cis_addr function in cis.c sets up the
1330                  *      tuple->CISOffset->offset offset to point to the
1331                  *      start of the tuple.
1332                  */
1333                     if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
1334                         flags = CISTPLF_AM_SPACE;
1335                         newoffset += ((tuple->TupleOffset * 2) + 4);
1336                     } else {
1337                         flags = CISTPLF_CM_SPACE;
1338                         newoffset += (tuple->TupleOffset + 2);
1339                     }
1340 
1341                     if (cs_init_cis_window(sp, &newoffset, &cis_handle,
1342                                                         flags) != CS_SUCCESS) {
1343                         mutex_exit(&sp->cis_lock);
1344                         cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
1345                                                 "can't init CIS window\n",
1346                                                         sp->socket_num);
1347                         return (CS_GENERAL_FAILURE);
1348                     } /* cs_init_cis_window */
1349                     while (nbytes--) {
1350                         *tdd++ = csx_Get8(cis_handle, newoffset++);
1351                         if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
1352                             newoffset++;
1353                     } /* while */
1354                     break;
1355                 default:
1356                     mutex_exit(&sp->cis_lock);
1357                     return (CS_GENERAL_FAILURE);
1358             } /* switch */
1359 
1360             ret = CS_SUCCESS;
1361         } else {
1362             ret = CS_NO_CIS;
1363         } /* if (CW_VALID_CIS) */
1364 
1365         mutex_exit(&sp->cis_lock);
1366 
1367         return (ret);
1368 }
1369 
1370 /*
1371  * cs_validate_cis - validates the CIS on a card in the given socket; this
1372  *                      is to support the ValidateCIS function call.
1373  *
1374  *    Notes for regular PC card driver callers:
1375  *
1376  *      Regular PC card drivers calling ValidateCIS will get the meaning of
1377  *      the structure members as specified in the standard.
1378  *
1379  *    Notes for Socket Services, the "super-client" or CSI driver callers:
1380  *
1381  *              with: Function Number = CS_GLOBAL_CIS
1382  *
1383  *      For a single-function card, CS_NO_CIS will be returned and the
1384  *      cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
1385  *
1386  *      For a multi-function card, cisinfo_t->Chains will contain a count of
1387  *      the number of CIS chains in the global portion of the CIS, and
1388  *      cisinfo_t->Tuples will contain a count of the number of tuples in
1389  *      the global portion of the CIS.
1390  *
1391  *              with: 0 <= Function Number < CIS_MAX_FUNCTIONS
1392  *
1393  *      For a single-function card, if the function number is equal to 0 and
1394  *      has a CIS, cisinfo_t->Chains will contain a count of the number of
1395  *      CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
1396  *      the number of tuples in the CIS. If the card does not have a CIS, or
1397  *      if the function number is not equal to 0, CS_NO_CIS will be returned
1398  *      and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
1399  *      to 0.
1400  *
1401  *      For a multi-function card, cisinfo_t->Chains will contain a count of
1402  *      the number of CIS chains in the global and function-specific
1403  *      portions of the CIS, and cisinfo_t->Tuples will contain a count of
1404  *      the number of tuples in the global and function-specific portions of
1405  *      the CIS. If the function does not exist or has no CIS, CS_NO_CIS
1406  *      will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
1407  *      members will be set to 0.
1408  *
1409  *    General notes:
1410  *
1411  *      If the card does not have a CIS, or if the function does not exist
1412  *      or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
1413  *      and cisinfo_t->Tuples members will be set to 0.
1414  *
1415  *      Most of the work of validating the CIS has already been done by the
1416  *      CIS parser module, so we don't have to do much here except for
1417  *      looking at the various flags and tuple/chain counts that were already
1418  *      setup by the CIS parser.
1419  *
1420  *    See notes for the cs_get_firstnext_tuple function.
1421  */
1422 static int
1423 cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
1424 {
1425         cs_socket_t *sp;
1426         client_t *client;
1427         uint32_t fn;
1428         int ret;
1429 
1430         if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
1431                                                 &sp, &client)) != CS_SUCCESS)
1432             return (ret);
1433 
1434         /*
1435          * If there's no card in the socket or the card in the socket is not
1436          *      for this client, then return an error.
1437          */
1438         if (!(client->flags & CLIENT_CARD_INSERTED))
1439             return (CS_NO_CARD);
1440 
1441         mutex_enter(&sp->cis_lock);
1442         if ((sp->cis_flags & CW_VALID_CIS) &&
1443                                 (sp->cis[fn].flags & CW_VALID_CIS)) {
1444             cisinfo->Chains = sp->cis[fn].nchains;
1445             cisinfo->Tuples = sp->cis[fn].ntuples;
1446 
1447             if ((fn != CS_GLOBAL_CIS) &&
1448                         (sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
1449                 cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
1450                 cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
1451             } /* !CS_GLOBAL_CIS */
1452 
1453             ret = CS_SUCCESS;
1454         } else {
1455             cisinfo->Chains = 0;
1456             cisinfo->Tuples = 0;
1457             ret = CS_NO_CIS;
1458         }
1459         mutex_exit(&sp->cis_lock);
1460 
1461         return (ret);
1462 }
1463 
1464 /*
1465  * cs_init_cis_window - initializes the CIS window for the passed socket
1466  *
1467  *      calling: *sp - pointer to the per-socket structure
1468  *               *offset - offset from start of AM or CM space
1469  *               *hp - pointer to acc_handle_t to store modified
1470  *                              window access handle in
1471  *               flags - one of:
1472  *                              CISTPLF_AM_SPACE - set window to AM space
1473  *                              CISTPLF_CM_SPACE - set window to CM space
1474  *
1475  *      returns: CS_SUCCESS if CIS window was set up
1476  *               *offset - contains adjusted offset to use to access
1477  *                              requested space
1478  *               CS_BAD_WINDOW if CIS window could not be setup
1479  *               CS_GENERAL_FAILURE if socket has a CIS window number
1480  *                                      but the window flags are wrong
1481  *
1482  *      Note: This function will check to be sure that there is a valid
1483  *              CIS window allocated to this socket.
1484  *            If there is an error in setting up the window hardware, the
1485  *              CIS window information for this socket is cleared.
1486  *            This function is also used by routines that need to get
1487  *              a pointer to the base of AM space to access the card's
1488  *              configuration registers.
1489  *            The passed offset is the un-window-size-aligned offset.
1490  */
1491 int
1492 cs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
1493     acc_handle_t *hp, uint32_t flags)
1494 {
1495         set_window_t sw;
1496         get_window_t gw;
1497         inquire_window_t iw;
1498         set_page_t set_page;
1499         cs_window_t *cw;
1500 
1501         /*
1502          * Check to be sure that we have a valid CIS window
1503          */
1504         if (!SOCKET_HAS_CIS_WINDOW(sp)) {
1505             cmn_err(CE_CONT,
1506                         "cs_init_cis_window: socket %d has no CIS window\n",
1507                                 sp->socket_num);
1508             return (CS_BAD_WINDOW);
1509         }
1510 
1511         /*
1512          * Check to be sure that this window is allocated for CIS use
1513          */
1514         if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
1515             return (CS_BAD_WINDOW);
1516 
1517         if (!(cw->state & CW_CIS)) {
1518             cmn_err(CE_CONT,
1519                 "cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
1520                                 sp->socket_num, cw->state);
1521             return (CS_BAD_WINDOW);
1522         }
1523 
1524         /*
1525          * Get the characteristics of this window - we use this to
1526          *      determine whether we need to re-map the window or
1527          *      just move the window offset on the card.
1528          */
1529         iw.window = sp->cis_win_num;
1530         SocketServices(SS_InquireWindow, &iw);
1531 
1532         /*
1533          * We've got a window, now set up the hardware. If we've got
1534          *      a variable sized window, then all we need to do is to
1535          *      get a valid mapping to the base of the window using
1536          *      the current window size; if we've got a fixed-size
1537          *      window, then we need to get a mapping to the window
1538          *      starting at offset zero of the window.
1539          */
1540         if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
1541             sw.WindowSize = sp->cis_win_size;
1542             set_page.offset = ((*offset / sp->cis_win_size) *
1543                                                 sp->cis_win_size);
1544         } else {
1545             set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
1546                                                 iw.mem_win_char.MinSize);
1547             sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
1548                                         (set_page.offset - 1)) + PAGESIZE);
1549         }
1550 
1551         /*
1552          * Return a normalized base offset; this takes care of the case
1553          *      where the required offset is greater than the window size.
1554          * BugID 1236404
1555          *      code was:
1556          *              *offset = *offset & (set_page.offset - 1);
1557          */
1558         *offset = *offset - set_page.offset;
1559 
1560 #ifdef  CS_DEBUG
1561         if (cs_debug > 1)
1562             cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
1563                                                         "offset 0x%x\n",
1564                                                         (int)sw.WindowSize,
1565                                                         (int)set_page.offset);
1566         if (cs_debug > 1)
1567             cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
1568                                                         (int)*offset,
1569                                         (flags & CISTPLF_AM_SPACE)?
1570                                         "CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
1571 #endif
1572 
1573         sw.window = sp->cis_win_num;
1574         sw.socket = sp->socket_num;
1575         sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
1576         sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1577         sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1578         sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1579 
1580         /*
1581          * The PCMCIA SS spec specifies this be expressed in
1582          *      a device speed format per 5.2.7.1.3 but
1583          *      our implementation of SS_SetWindow uses
1584          *      actual nanoseconds.
1585          */
1586         sw.speed = CIS_DEFAULT_SPEED;
1587         sw.base = 0;
1588         /*
1589          * Set up the window - if this fails, then just set the
1590          *      CIS window number back to it's initialized value so
1591          *      that we'll fail when we break out of the loop.
1592          */
1593         if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
1594             sp->cis_win_num = PCMCIA_MAX_WINDOWS;
1595             cw->state = 0; /* XXX do we really want to do this? */
1596             return (CS_BAD_WINDOW);
1597         } else {
1598                 set_page.window = sp->cis_win_num;
1599                 set_page.page = 0;
1600                 set_page.state = PS_ENABLED;
1601                 if (flags & CISTPLF_AM_SPACE)
1602                     set_page.state |= PS_ATTRIBUTE;
1603 
1604                 if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
1605                     sp->cis_win_num = PCMCIA_MAX_WINDOWS;
1606                     cw->state = 0; /* XXX do we really want to do this? */
1607                     return (CS_BAD_WINDOW);
1608                 } /* if (SS_SetPage) */
1609         } /* if (SS_SetWindow) */
1610 
1611         /*
1612          * Get the window information for the CIS window for this socket.
1613          */
1614         gw.window = sp->cis_win_num;
1615         gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
1616         if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
1617             return (CS_BAD_WINDOW);
1618 
1619         *hp = (acc_handle_t)gw.handle;
1620 
1621         return (CS_SUCCESS);
1622 }
1623 
1624 /*
1625  * ==== client registration/deregistration section ====
1626  */
1627 
1628 /*
1629  * cs_register_client - This supports the RegisterClient call.
1630  *
1631  * Upon successful registration, the client_handle_t * handle argument will
1632  *      contain the new client handle and we return CS_SUCCESS.
1633  */
1634 static int
1635 cs_register_client(client_handle_t *ch, client_reg_t *cr)
1636 {
1637         uint32_t sn;
1638         int super_client = 0;
1639         sclient_reg_t *scr = cr->priv;
1640         struct sclient_list_t *scli;
1641 
1642         /*
1643          * See if we're not supposed to register any new clients.
1644          */
1645         if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
1646             return (CS_OUT_OF_RESOURCE);
1647 
1648         /*
1649          * Do a version check - if the client expects a later version of
1650          *      Card Services than what we are, return CS_BAD_VERSION.
1651          * XXX - How do we specify just a PARTICULAR version of CS??
1652          */
1653         if (CS_VERSION < cr->Version)
1654             return (CS_BAD_VERSION);
1655 
1656         /*
1657          * Check to be sure that the client has given us a valid set of
1658          *      client type flags.  We also use this opportunity to see
1659          *      if the registering client is Socket Services or is a
1660          *      "super-client" or a CSI client.
1661          *
1662          * Note that SS can not set any flag in the Attributes field other
1663          *      than the INFO_SOCKET_SERVICES flag.
1664          *
1665          * Valid combinations of cr->Attributes and cr->EventMask flags:
1666          *
1667          *  for Socket Services:
1668          *      cr->Attributes:
1669          *          set:
1670          *              INFO_SOCKET_SERVICES
1671          *          clear:
1672          *              {all other flags}
1673          *      cr->EventMask:
1674          *          don't care:
1675          *              {all flags}
1676          *
1677          *  for regular clients:
1678          *      cr->Attributes:
1679          *          only one of:
1680          *              INFO_IO_CLIENT
1681          *              INFO_MTD_CLIENT
1682          *              INFO_MEM_CLIENT
1683          *          don't care:
1684          *              INFO_CARD_SHARE
1685          *              INFO_CARD_EXCL
1686          *      cr->EventMask:
1687          *          clear:
1688          *              CS_EVENT_ALL_CLIENTS
1689          *          don't care:
1690          *              {all other flags}
1691          *
1692          *  for CSI clients:
1693          *      cr->Attributes:
1694          *          set:
1695          *              INFO_IO_CLIENT
1696          *              INFO_CSI_CLIENT
1697          *          clear:
1698          *              INFO_MTD_CLIENT
1699          *              INFO_MEM_CLIENT
1700          *          don't care:
1701          *              INFO_CARD_SHARE
1702          *              INFO_CARD_EXCL
1703          *      cr->EventMask:
1704          *          don't care:
1705          *              {all flags}
1706          *
1707          *  for "super-clients":
1708          *      cr->Attributes:
1709          *          set:
1710          *              INFO_IO_CLIENT
1711          *              INFO_MTD_CLIENT
1712          *              INFO_SOCKET_SERVICES
1713          *              INFO_CARD_SHARE
1714          *          clear:
1715          *              INFO_MEM_CLIENT
1716          *              INFO_CARD_EXCL
1717          *      cr->EventMask:
1718          *          don't care:
1719          *              {all flags}
1720          */
1721         switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
1722         /*
1723          * Check first to see if this is Socket Services registering; if
1724          *      so, we don't do anything but return the client handle that is
1725          *      in the global SS client.
1726          */
1727             case INFO_SOCKET_SERVICES:
1728                 *ch = cs_socket_services_client.client_handle;
1729                 return (CS_SUCCESS);
1730                 /* NOTREACHED */
1731             /* CSI clients */
1732             case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
1733                 break;
1734             /* regular clients */
1735             case INFO_IO_CLIENT:
1736             case INFO_MTD_CLIENT:
1737             case INFO_MEM_CLIENT:
1738                 if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
1739                     return (CS_BAD_ATTRIBUTE);
1740                 break;
1741             /* "super-client" clients */
1742             case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
1743                 if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
1744                                 (cr->Attributes & INFO_CARD_EXCL))
1745                     return (CS_BAD_ATTRIBUTE);
1746                 /*
1747                  * We only allow one "super-client" per system.
1748                  */
1749                 mutex_enter(&cs_globals.global_lock);
1750                 if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
1751                     mutex_exit(&cs_globals.global_lock);
1752                     return (CS_NO_MORE_ITEMS);
1753                 }
1754                 cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
1755                 mutex_exit(&cs_globals.global_lock);
1756                 super_client = CLIENT_SUPER_CLIENT;
1757                 break;
1758             default:
1759                 return (CS_BAD_ATTRIBUTE);
1760         } /* switch (cr->Attributes) */
1761 
1762         /*
1763          * Now, actually create the client node on the socket; this will
1764          *      also return the new client handle if there were no errors
1765          *      creating the client node.
1766          * The DIP2SOCKET_NUM macro will return the socket and function
1767          *      number using the encoding specified in the cs_priv.h file.
1768          */
1769         if (super_client != CLIENT_SUPER_CLIENT) {
1770             if (cr->Attributes & INFO_CSI_CLIENT)
1771                 sn = (uint32_t)(uintptr_t)cr->priv;
1772             else
1773                 sn = DIP2SOCKET_NUM(cr->dip);
1774             return (cs_add_client_to_socket(sn, ch, cr, super_client));
1775         } /* CLIENT_SUPER_CLIENT */
1776 
1777         /*
1778          * This registering client is a "super-client", so we create one
1779          *      client node for each socket in the system.  We use the
1780          *      client_reg_t.priv structure member to point to a struct
1781          *      that the "super-client" client knows about.  The client
1782          *      handle pointer is not used in this case.
1783          * We return CS_SUCCESS if at least one client node could be
1784          *      created.  The client must check the error codes in the
1785          *      error code array to determine which clients could not
1786          *      be created on which sockets.
1787          * We return CS_BAD_HANDLE if no client nodes could be created.
1788          */
1789         scr->num_clients = 0;
1790         scr->max_socket_num = cs_globals.max_socket_num;
1791         scr->num_sockets = cs_globals.num_sockets;
1792         scr->num_windows = cs_globals.num_windows;
1793 
1794         *(scr->sclient_list) = cs_globals.sclient_list;
1795 
1796         for (sn = 0; sn < scr->num_sockets; sn++) {
1797             scli = scr->sclient_list[sn];
1798             if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
1799                                             cr, super_client)) == CS_SUCCESS) {
1800                 scr->num_clients++;
1801             }
1802         }
1803 
1804         /*
1805          * If we couldn't create any client nodes at all, then
1806          *      return an error.
1807          */
1808         if (!scr->num_clients) {
1809         /*
1810          * XXX - The global superclient lock now gets
1811          * cleared in cs_deregister_client
1812          */
1813             /* cs_clear_superclient_lock(super_client); */
1814             return (CS_BAD_HANDLE);
1815         }
1816 
1817         return (CS_SUCCESS);
1818 }
1819 
1820 /*
1821  * cs_add_client_to_socket - this function creates the client node on the
1822  *                              requested socket.
1823  *
1824  * Note that if we return an error, there is no state that can be cleaned
1825  *      up.  The only way that we can return an error with allocated resources
1826  *      would be if one of the client handle functions had an internal error.
1827  *      Since we wouldn't get a valid client handle in this case anyway, there
1828  *      would be no way to find out what was allocated and what wasn't.
1829  */
1830 static int
1831 cs_add_client_to_socket(unsigned sn, client_handle_t *ch,
1832                                         client_reg_t *cr, int super_client)
1833 {
1834         cs_socket_t *sp;
1835         client_t *client, *cclp;
1836         int error, cie = 1;
1837         int client_lock_acquired;
1838 
1839         if (cr->event_handler == NULL)
1840             return (CS_BAD_ARGS);
1841 
1842         if ((sp = cs_get_sp(sn)) == NULL)
1843             return (CS_BAD_SOCKET);
1844 
1845         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
1846 
1847         /*
1848          * Run through all of the registered clients and compare the passed
1849          *      dip to the dip of each client to make sure that this client
1850          *      is not trying to register more than once.  If they are, then
1851          *      display a message and return an error.
1852          * XXX - we should really check all the sockets in case the client
1853          *      manipulates the instance number in the dip.
1854          * XXX - if we check each socket, we ned to also check for the
1855          *      "super-client" since it will use the same dip for all
1856          *      of it's client nodes.
1857          */
1858         mutex_enter(&sp->lock);
1859         client = sp->client_list;
1860         while (client) {
1861             if (!(cr->Attributes & INFO_CSI_CLIENT) &&
1862                                                 (client->dip == cr->dip)) {
1863                 mutex_exit(&sp->lock);
1864                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1865                 cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
1866                                         "function 0x%x\n"
1867                                         "\tclient already registered with "
1868                                         "handle 0x%x\n",
1869                                                 (int)CS_GET_SOCKET_NUMBER(sn),
1870                                                 (int)CS_GET_FUNCTION_NUMBER(sn),
1871                                                 (int)client->client_handle);
1872                 return (CS_BAD_HANDLE);
1873             }
1874             client = client->next;
1875         } /* while (client) */
1876         mutex_exit(&sp->lock);
1877 
1878         /*
1879          * Create a unique client handle then make sure that we can find it.
1880          *      This has the side effect of getting us a pointer to the
1881          *      client structure as well.
1882          * Create a client list entry - cs_create_client_handle will use this
1883          *      as the new client node.
1884          * We do it here so that we can grab the sp->lock mutex for the
1885          *      duration of our manipulation of the client list.
1886          * If this function fails, then it will not have added the newly
1887          *      allocated client node to the client list on this socket,
1888          *      so we have to free the node that we allocated.
1889          */
1890         cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
1891 
1892         mutex_enter(&sp->lock);
1893         if (!(*ch = cs_create_client_handle(sn, cclp))) {
1894             mutex_exit(&sp->lock);
1895             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1896             kmem_free(cclp, sizeof (client_t));
1897             return (CS_OUT_OF_RESOURCE);
1898         }
1899 
1900         /*
1901          *  Make sure that this is a valid client handle.  We should never
1902          *      fail this since we just got a valid client handle.
1903          * If this fails, then we have an internal error so don't bother
1904          *      trying to clean up the allocated client handle since the
1905          *      whole system is probably hosed anyway and will shortly
1906          *      esplode.
1907          * It doesn't make sense to call cs_deregister_client at this point
1908          *      to clean up this broken client since the deregistration
1909          *      code will also call cs_find_client and most likely fail.
1910          */
1911         if (!(client = cs_find_client(*ch, &error))) {
1912             mutex_exit(&sp->lock);
1913             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1914             cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
1915                                 "invalid client handle created handle 0x%x\n",
1916                                                 (int)CS_GET_SOCKET_NUMBER(sn),
1917                                                 (int)CS_GET_FUNCTION_NUMBER(sn),
1918                                                 (int)*ch);
1919             return (error);
1920         }
1921 
1922         /*
1923          * Save the DDI information.
1924          */
1925         client->dip = cr->dip;
1926         cr->driver_name[MODMAXNAMELEN - 1] = NULL;
1927         client->driver_name = (char *)kmem_zalloc(strlen(cr->driver_name) + 1,
1928                                                                 KM_SLEEP);
1929         (void) strcpy(client->driver_name, cr->driver_name);
1930         client->instance = ddi_get_instance(cr->dip);
1931 
1932         /*
1933          * Copy over the interesting items that the client gave us.
1934          */
1935         client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
1936         client->event_callback_handler = cr->event_handler;
1937         bcopy((caddr_t)&cr->event_callback_args,
1938                                 (caddr_t)&client->event_callback_args,
1939                                 sizeof (event_callback_args_t));
1940         /*
1941          * Set the client handle since the client needs a client handle
1942          *      when they call us for their event handler.
1943          */
1944         client->event_callback_args.client_handle = *ch;
1945 
1946         /*
1947          * Initialize the IO window numbers; if an IO window number is equal
1948          *      to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
1949          */
1950         client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
1951         client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
1952 
1953         /*
1954          * Give the client the iblock and idevice cookies to use in
1955          *      the client's event handler high priority mutex.
1956          */
1957         cr->iblk_cookie = sp->iblk;
1958         cr->idev_cookie = sp->idev;
1959 
1960         /*
1961          * Set up the global event mask information; we copy this directly
1962          *      from the client; since we are the only source of events,
1963          *      any bogus bits that the client puts in here won't matter
1964          *      because we'll never look at them.
1965          */
1966         client->global_mask = cr->EventMask;
1967 
1968         /*
1969          * If this client registered as a CSI client, set the appropriate
1970          *      flag in the client's flags area.
1971          */
1972         if (cr->Attributes & INFO_CSI_CLIENT)
1973             client->flags |= CLIENT_CSI_CLIENT;
1974 
1975         /*
1976          * If this client registered as a "super-client" set the appropriate
1977          *      flag in the client's flags area.
1978          */
1979         if (super_client == CLIENT_SUPER_CLIENT)
1980             client->flags |= CLIENT_SUPER_CLIENT;
1981 
1982         /*
1983          * Save other misc information that this client gave us - it is
1984          *      used in the GetClientInfo function.
1985          */
1986         client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
1987 
1988         /*
1989          * Determine if we should give artificial card insertion events and
1990          *      a registration complete event. Since we don't differentiate
1991          *      between sharable and exclusive use cards when giving clients
1992          *      event notification, we modify the definition of the share/excl
1993          *      flags as follows:
1994          *
1995          *          If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
1996          *          the client will receive artificial card insertion
1997          *          events (if the client's card is currently in the
1998          *          socket) and a registration complete event.
1999          *
2000          *          If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
2001          *          set, the client will not receive an artificial card
2002          *          insertion event nor a registration complete event
2003          *          due to the client's call to register client.
2004          *
2005          *          The client's event mask is not affected by the setting
2006          *          of these two bits.
2007          */
2008         if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
2009             client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
2010 
2011         /*
2012          * Check to see if the card for this client is currently in
2013          *      the socket. If it is, then set CLIENT_CARD_INSERTED
2014          *      since clients that are calling GetStatus at attach
2015          *      time will typically check to see if their card is
2016          *      currently installed.
2017          * If this is the CSI client, we also need to check to see
2018          *      if there is any card inserted in the socket, since
2019          *      the cs_card_for_client function will always return
2020          *      TRUE for a CSI client.
2021          * XXX What about super-clients?
2022          */
2023         if (client->flags & CLIENT_CSI_CLIENT) {
2024             get_ss_status_t get_ss_status;
2025 
2026             get_ss_status.socket = sp->socket_num;
2027 
2028             if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
2029                 mutex_exit(&sp->lock);
2030                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2031                 return (CS_BAD_SOCKET);
2032             } /* SS_GetStatus */
2033 
2034             if (!(cs_sbm2cse(get_ss_status.CardState) &
2035                         CS_EVENT_CARD_INSERTION))
2036                 cie = 0;
2037 
2038         } /* CLIENT_CSI_CLIENT */
2039 
2040         if (cs_card_for_client(client) && (cie != 0)) {
2041             client->pending_events |= CS_EVENT_CARD_INSERTION;
2042             client->flags |= CLIENT_CARD_INSERTED;
2043         } /* cs_card_for_client */
2044 
2045         sp->num_clients++;
2046         mutex_exit(&sp->lock);
2047         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2048 
2049         return (CS_SUCCESS);
2050 }
2051 
2052 /*
2053  * cs_deregister_client - This supports the DeregisterClient call.
2054  */
2055 static int
2056 cs_deregister_client(client_handle_t client_handle)
2057 {
2058         cs_socket_t *sp;
2059         client_t *client;
2060         int error, super_client = 0;
2061         int client_lock_acquired;
2062 
2063         /*
2064          * Check to see if this is the Socket Services client handle; if it
2065          *      is, we don't do anything except for return success.
2066          */
2067         if (CLIENT_HANDLE_IS_SS(client_handle))
2068             return (CS_SUCCESS);
2069 
2070         /*
2071          * Get a pointer to this client's socket structure.
2072          */
2073         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
2074             return (CS_BAD_SOCKET);
2075 
2076         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
2077 
2078         /*
2079          *  Make sure that this is a valid client handle.
2080          */
2081         if (!(client = cs_find_client(client_handle, &error))) {
2082             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2083             return (error);
2084         }
2085 
2086         /*
2087          * Make sure that any resources allocated by this client are
2088          *      not still allocated, and that if this is an MTD that
2089          *      no MTD operations are still in progress.
2090          */
2091         if (client->flags &    (CLIENT_IO_ALLOCATED      |
2092                                 CLIENT_IRQ_ALLOCATED    |
2093                                 CLIENT_WIN_ALLOCATED    |
2094                                 REQ_CONFIGURATION_DONE  |
2095                                 REQ_SOCKET_MASK_DONE    |
2096                                 REQ_IO_DONE             |
2097                                 REQ_IRQ_DONE)) {
2098             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2099             return (CS_BUSY);
2100         }
2101 
2102         if (client->flags & CLIENT_MTD_IN_PROGRESS) {
2103             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2104             return (CS_IN_USE);
2105         }
2106 
2107         /*
2108          * Any previously allocated resources are not allocated anymore, and
2109          *      no MTD operations are in progress, so if this is an MTD client
2110          *      then do any MTD-specific client deregistration, and then
2111          *      nuke this client.
2112          * We expect cs_deregister_mtd to never fail.
2113          */
2114         if (client->flags & INFO_MTD_CLIENT)
2115             (void) cs_deregister_mtd(client_handle);
2116 
2117         if (client->flags & CLIENT_SUPER_CLIENT)
2118             super_client = CLIENT_SUPER_CLIENT;
2119 
2120         kmem_free(client->driver_name, strlen(client->driver_name) + 1);
2121 
2122         error = cs_destroy_client_handle(client_handle);
2123 
2124         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2125 
2126         /*
2127          * If this was the "super-client" deregistering, then this
2128          *      will clear the global "super-client" lock.
2129          * XXX - move this outside the per-socket code.
2130          */
2131         cs_clear_superclient_lock(super_client);
2132 
2133         return (error);
2134 }
2135 
2136 /*
2137  * cs_create_next_client_minor - returns the next available client minor
2138  *                                      number or 0 if none available
2139  *
2140  * Note that cs_find_client will always return a valid pointer to the
2141  *      global Socket Services client which has a client minor number
2142  *      of 0; this means that this function can never return a 0 as the
2143  *      next valid available client minor number.
2144  */
2145 unsigned
2146 cs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
2147 {
2148         unsigned max_client_handles = cs_max_client_handles;
2149 
2150         do {
2151             next_minor &= CS_MAX_CLIENTS_MASK;
2152             if (!cs_find_client(MAKE_CLIENT_HANDLE(
2153                                         CS_GET_SOCKET_NUMBER(socket_num),
2154                                         CS_GET_FUNCTION_NUMBER(socket_num),
2155                                                         next_minor), NULL)) {
2156                 return (next_minor);
2157             }
2158             next_minor++;
2159         } while (max_client_handles--);
2160 
2161         return (0);
2162 }
2163 
2164 /*
2165  * cs_find_client - finds the client pointer associated with the client handle
2166  *                      or NULL if client not found
2167  *
2168  * returns:     (client_t *)NULL - if client not found or an error occured
2169  *                                      If the error argument is not NULL,
2170  *                                      it is set to:
2171  *                      CS_BAD_SOCKET - socket number in client_handle_t is
2172  *                                              invalid
2173  *                      CS_BAD_HANDLE - client not found
2174  *                      If no error, the error argument is not modified.
2175  *              (client_t *) - pointer to client_t structure
2176  *
2177  * Note that each socket always has a pseudo client with a client minor number
2178  *      of 0; this client minor number is used for Socket Services access to
2179  *      Card Services functions. The client pointer returned for client minor
2180  *      number 0 is the global Socket Services client pointer.
2181  */
2182 static client_t *
2183 cs_find_client(client_handle_t client_handle, int *error)
2184 {
2185         cs_socket_t *sp;
2186         client_t *clp;
2187 
2188         /*
2189          * If we are being asked to see if a client with a minor number
2190          *      of 0 exists, always return a pointer to the global Socket
2191          *      Services client, since this client always exists, and is
2192          *      only for use by Socket Services.  There is no socket
2193          *      associated with this special client handle.
2194          */
2195         if (CLIENT_HANDLE_IS_SS(client_handle))
2196             return (&cs_socket_services_client);
2197 
2198         /*
2199          * Check to be sure that the socket number is in range
2200          */
2201         if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
2202                                         cs_globals.max_socket_num))) {
2203             if (error)
2204                 *error = CS_BAD_SOCKET;
2205             return (NULL);
2206         }
2207 
2208         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
2209             if (error)
2210                 *error = CS_BAD_SOCKET;
2211             return (NULL);
2212         }
2213 
2214         clp = sp->client_list;
2215 
2216         while (clp) {
2217             if (clp->client_handle == client_handle)
2218                 return (clp);
2219             clp = clp->next;
2220         }
2221 
2222         if (error)
2223             *error = CS_BAD_HANDLE;
2224 
2225         return (NULL);
2226 }
2227 
2228 /*
2229  * cs_destroy_client_handle - destroys client handle and client structure of
2230  *                              passed client handle
2231  *
2232  * returns:     CS_SUCCESS - if client handle sucessfully destroyed
2233  *              CS_BAD_HANDLE - if client handle is invalid or if trying
2234  *                                      to destroy global SS client
2235  *              {other errors} - other errors from cs_find_client()
2236  */
2237 static int
2238 cs_destroy_client_handle(client_handle_t client_handle)
2239 {
2240         client_t *clp;
2241         cs_socket_t *sp;
2242         int error = CS_BAD_HANDLE;
2243 
2244         /*
2245          * See if we were passed a valid client handle or if we're being asked
2246          *      to destroy the Socket Services client
2247          */
2248         if ((!(clp = cs_find_client(client_handle, &error))) ||
2249                         (CLIENT_HANDLE_IS_SS(client_handle)))
2250             return (error);
2251 
2252         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
2253             return (CS_BAD_SOCKET);
2254 
2255         /*
2256          * Recycle this client's minor number.  This will most likely
2257          *      be the next client minor number we use, but it is also
2258          *      a hint to cs_create_client_handle, and that function
2259          *      may actually create a new client handle using a minor
2260          *      number different that this number.
2261          */
2262         mutex_enter(&sp->lock);
2263         sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
2264 
2265         /*
2266          * See if we're the first or not in the client list; if we're
2267          *      not first, then just adjust the client behind us to
2268          *      point to the client ahead of us; this could be NULL
2269          *      if we're the last client in the list.
2270          */
2271         if (clp->prev) {
2272             clp->prev->next = clp->next;
2273         } else {
2274         /*
2275          * We are first, so adjust the client list head pointer
2276          *      in the socket to point to the client structure that
2277          *      follows us; this could turn out to be NULL if we're
2278          *      the only client on this socket.
2279          */
2280             sp->client_list = clp->next;
2281         }
2282 
2283         /*
2284          * If we're not the last client in the list, point the next
2285          *      client to the client behind us; this could turn out
2286          *      to be NULL if we're the first client on this socket.
2287          */
2288         if (clp->next)
2289             clp->next->prev = clp->prev;
2290 
2291         sp->num_clients--;
2292         mutex_exit(&sp->lock);
2293 
2294         /*
2295          * Free this client's memory.
2296          */
2297         kmem_free(clp, sizeof (client_t));
2298 
2299         return (CS_SUCCESS);
2300 }
2301 
2302 /*
2303  * cs_create_client_handle - create a new client handle for the passed
2304  *                              socket and function number
2305  *
2306  * returns:     0 -  if can't create client for some reason
2307  *              client_handle_t - new client handle
2308  */
2309 static client_handle_t
2310 cs_create_client_handle(unsigned socket_num, client_t *cclp)
2311 {
2312         client_t *clp;
2313         cs_socket_t *sp;
2314         unsigned next_minor;
2315         client_handle_t client_handle;
2316 
2317         if ((sp = cs_get_sp(socket_num)) == NULL)
2318             return (0);
2319 
2320         /*
2321          * Get the next available minor number that we can use.  We use the
2322          *      next_cl_minor number as a hint to cs_create_next_client_minor
2323          *      and in most cases this will be the minor number we get back.
2324          * If for some reason we can't get a minor number, return an error.
2325          *      The only way we could get an error would be if there are
2326          *      already the maximum number of clients for this socket. Since
2327          *      the maximum number of clients per socket is pretty large,
2328          *      this error is unlikely to occur.
2329          */
2330         if (!(next_minor =
2331                 cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
2332             return (0);
2333 
2334         /*
2335          * Got a new client minor number, now create a new client handle.
2336          */
2337         client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
2338                                         CS_GET_FUNCTION_NUMBER(socket_num),
2339                                         next_minor);
2340 
2341         /*
2342          * If this client handle exists, then we have an internal
2343          *      error; this should never happen, BTW.  This is really
2344          *      a double-check on the cs_create_next_client_minor
2345          *      function, which also calls cs_find_client.
2346          */
2347         if (cs_find_client(client_handle, NULL)) {
2348             cmn_err(CE_CONT,
2349                 "cs_create_client_handle: duplicate client handle 0x%x\n",
2350                                                         (int)client_handle);
2351             return (0);
2352         }
2353 
2354         /*
2355          * If we don't have any clients on this socket yet, create
2356          *      a new client and hang it on the socket client list.
2357          */
2358         if (!sp->client_list) {
2359             sp->client_list = cclp;
2360             clp = sp->client_list;
2361         } else {
2362         /*
2363          * There are other clients on this socket, so look for
2364          *      the last client and add our new client after it.
2365          */
2366             clp = sp->client_list;
2367             while (clp->next) {
2368                 clp = clp->next;
2369             }
2370 
2371             clp->next = cclp;
2372             clp->next->prev = clp;
2373             clp = clp->next;
2374         } /* if (!sp->client_list) */
2375 
2376         /*
2377          * Assign the new client handle to this new client structure.
2378          */
2379         clp->client_handle = client_handle;
2380 
2381         /*
2382          * Create the next available client minor number for this socket
2383          *      and save it away.
2384          */
2385         sp->next_cl_minor =
2386                 cs_create_next_client_minor(socket_num, sp->next_cl_minor);
2387 
2388         return (client_handle);
2389 }
2390 
2391 /*
2392  * cs_clear_superclient_lock - clears the global "super-client" lock
2393  *
2394  * Note: this function uses the cs_globals.global_lock so observe proper
2395  *              nexting of locks!!
2396  */
2397 static void
2398 cs_clear_superclient_lock(int super_client)
2399 {
2400 
2401         /*
2402          * If this was a "super-client" registering then we need
2403          *      to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
2404          *      so that other "super-clients" can register.
2405          */
2406         if (super_client == CLIENT_SUPER_CLIENT) {
2407             mutex_enter(&cs_globals.global_lock);
2408             cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
2409             mutex_exit(&cs_globals.global_lock);
2410         }
2411 }
2412 
2413 /*
2414  * ==== event handling section ====
2415  */
2416 
2417 /*
2418  * cs_event - CS event hi-priority callback handler
2419  *
2420  *      This function gets called by SS and is passed the event type in
2421  *              the "event" argument, and the socket number in the "sn"
2422  *              argument. The "sn" argument is a valid logical socket
2423  *              number for all events except the PCE_SS_READY event.
2424  *
2425  *      The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
2426  *              are never called at high priority. These events return
2427  *              the following return codes:
2428  *
2429  *                      CS_SUCCESS - operation sucessful
2430  *                      CS_BAD_SOCKET - unable to complete operation
2431  *                      CS_UNSUPPORTED_FUNCTION - bad subfunction of
2432  *                                                      PCE_SS_INIT_STATE
2433  *
2434  *              The caller MUST look at these return codes!
2435  *
2436  *      This function is called at high-priority interrupt time for standard
2437  *              Card Services events, and the only standard Card Services
2438  *              event that it handles directly is the CS_EVENT_CARD_REMOVAL
2439  *              event, which gets shuttled right into the client's event
2440  *              handler.  All other events are just queued up and the socket
2441  *              event thread is woken up via the soft interrupt handler.
2442  *      Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
2443  *              event field, since the CS card insertion/card ready processing
2444  *              code is responsible for setting this event in a client's
2445  *              event field.
2446  *
2447  */
2448 /*ARGSUSED*/
2449 uint32_t
2450 cs_event(event_t event, uint32_t sn, uint32_t arg)
2451 {
2452         client_t *client;
2453         cs_socket_t *sp;
2454         client_types_t *ct;
2455         uint32_t ret = CS_SUCCESS;
2456 
2457         /*
2458          * Handle special SS<->CS events
2459          */
2460         switch (event) {
2461             case PCE_SS_INIT_STATE:
2462                 mutex_enter(&cs_globals.global_lock);
2463                 switch (sn) {
2464                     case PCE_SS_STATE_INIT:
2465                         if ((ret = cs_ss_init()) == CS_SUCCESS)
2466                             cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
2467                         break;
2468                     case PCE_SS_STATE_DEINIT:
2469                         cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
2470                         break;
2471                     default:
2472                         ret = CS_UNSUPPORTED_FUNCTION;
2473                         cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
2474                                                 "directive: 0x%x\n", sn);
2475                         break;
2476                 } /* switch (sn) */
2477                 mutex_exit(&cs_globals.global_lock);
2478                 return (ret);
2479             case PCE_ADD_SOCKET:
2480                 return (cs_add_socket(sn));
2481             case PCE_DROP_SOCKET:
2482                 return (cs_drop_socket(sn));
2483         } /* switch (event) */
2484 
2485         if ((sp = cs_get_sp(sn)) == NULL)
2486             return (CS_BAD_SOCKET);
2487 
2488         /*
2489          * Check to see if CS wants to unload - we do this since it's possible
2490          *      to disable certain sockets.  Do NOT acquire any locks yet.
2491          */
2492         if (sp->flags & SOCKET_UNLOAD_MODULE) {
2493             if (event == PCE_CARD_INSERT)
2494                 cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
2495                                                         "remove card\n", sn);
2496             return (CS_SUCCESS);
2497         }
2498 
2499         mutex_enter(&sp->lock);
2500 
2501 #ifdef  CS_DEBUG
2502         if (cs_debug > 1) {
2503             event2text_t event2text;
2504 
2505             event2text.event = event;
2506             (void) cs_event2text(&event2text, 0);
2507             cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
2508                                 event2text.text, (int)event, (int)sn);
2509         }
2510 #endif
2511 
2512         /*
2513          * Convert SS events to CS events; handle the PRR if necessary.
2514          */
2515         sp->events |= ss_to_cs_events(sp, event);
2516 
2517         /*
2518          * We want to maintain the required event dispatching order as
2519          *      specified in the PCMCIA spec, so we cycle through all
2520          *      clients on this socket to make sure that they are
2521          *      notified in the correct order of any high-priority
2522          *      events.
2523          */
2524         ct = &client_types[0];
2525         while (ct) {
2526         /*
2527          * Point to the head of the client list for this socket, and go
2528          *      through each client to set up the client events as well as
2529          *      call the client's event handler directly if we have a high
2530          *      priority event that we need to tell the client about.
2531          */
2532             client = sp->client_list;
2533 
2534             if (ct->order & CLIENT_EVENTS_LIFO) {
2535                 client_t *clp = NULL;
2536 
2537                 while (client) {
2538                     clp = client;
2539                     client = client->next;
2540                 }
2541                 client = clp;
2542             }
2543 
2544             while (client) {
2545                 client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
2546                                     (client->event_mask | client->global_mask));
2547                 if (client->flags & ct->type) {
2548 #ifdef  CS_DEBUG
2549                     if (cs_debug > 1) {
2550                         cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
2551                                                 "events 0x%x flags 0x%x\n",
2552                                                 sn, client->driver_name,
2553                                                 (int)client->events,
2554                                                 (int)client->flags);
2555                     }
2556 #endif
2557 
2558                 /*
2559                  * Handle the suspend and card removal events
2560                  *      specially here so that the client can receive
2561                  *      these events at high-priority.
2562                  */
2563                     if (client->events & CS_EVENT_PM_SUSPEND) {
2564                         if (client->flags & CLIENT_CARD_INSERTED) {
2565                             CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
2566                                                         CS_EVENT_PRI_HIGH);
2567                         } /* if (CLIENT_CARD_INSERTED) */
2568                         client->events &= ~CS_EVENT_PM_SUSPEND;
2569                     } /* if (CS_EVENT_PM_SUSPEND) */
2570 
2571                     if (client->events & CS_EVENT_CARD_REMOVAL) {
2572                         if (client->flags & CLIENT_CARD_INSERTED) {
2573                             client->flags &= ~(CLIENT_CARD_INSERTED |
2574                                                 CLIENT_SENT_INSERTION);
2575                             CLIENT_EVENT_CALLBACK(client,
2576                                                         CS_EVENT_CARD_REMOVAL,
2577                                                         CS_EVENT_PRI_HIGH);
2578                         /*
2579                          * Check to see if the client wants low priority
2580                          *      removal events as well.
2581                          */
2582                             if ((client->event_mask | client->global_mask) &
2583                                                 CS_EVENT_CARD_REMOVAL_LOWP) {
2584                                 client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
2585                             }
2586                         } /* if (CLIENT_CARD_INSERTED) */
2587                         client->events &= ~CS_EVENT_CARD_REMOVAL;
2588                     } /* if (CS_EVENT_CARD_REMOVAL) */
2589 
2590                 } /* if (ct->type) */
2591                 if (ct->order & CLIENT_EVENTS_LIFO) {
2592                     client = client->prev;
2593                 } else {
2594                     client = client->next;
2595                 }
2596             } /* while (client) */
2597 
2598             ct = ct->next;
2599         } /* while (ct) */
2600 
2601         /*
2602          * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
2603          *      handler will wakeup this socket's event thread.
2604          */
2605         if (sp->events)
2606             sp->flags |= SOCKET_NEEDS_THREAD;
2607 
2608         /*
2609          * Fire off a soft interrupt that will cause the socket thread
2610          *      to be woken up and any remaining events to be sent to
2611          *      the clients on this socket.
2612          */
2613         if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
2614                         !(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
2615             ddi_trigger_softintr(sp->softint_id);
2616 
2617         mutex_exit(&sp->lock);
2618 
2619         return (CS_SUCCESS);
2620 }
2621 
2622 /*
2623  * cs_card_insertion - handle card insertion and card ready events
2624  *
2625  * We read the CIS, if present, and store it away, then tell SS that
2626  *      we have read the CIS and it's ready to be parsed.  Since card
2627  *      insertion and card ready events are pretty closely intertwined,
2628  *      we handle both here.  For card ready events that are not the
2629  *      result of a card insertion event, we expect that the caller has
2630  *      already done the appropriate processing and that we will not be
2631  *      called unless we received a card ready event right after a card
2632  *      insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
2633  *      sp->thread_state was set or if we get a CARD_READY event right
2634  *      after a CARD_INSERTION event.
2635  *
2636  *    calling:  sp - pointer to socket structure
2637  *              event - event to handle, one of:
2638  *                              CS_EVENT_CARD_INSERTION
2639  *                              CS_EVENT_CARD_READY
2640  *                              CS_EVENT_SS_UPDATED
2641  */
2642 static int
2643 cs_card_insertion(cs_socket_t *sp, event_t event)
2644 {
2645         int ret;
2646 
2647         /*
2648          * Since we're only called while waiting for the card insertion
2649          *      and card ready sequence to occur, we may have a pending
2650          *      card ready timer that hasn't gone off yet if we got a
2651          *      real card ready event.
2652          */
2653         UNTIMEOUT(sp->rdybsy_tmo_id);
2654 
2655 #ifdef  CS_DEBUG
2656         if (cs_debug > 1) {
2657             cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
2658                                                 (int)event, sp->socket_num);
2659         }
2660 #endif
2661 
2662         /*
2663          * Handle card insertion processing
2664          */
2665         if (event & CS_EVENT_CARD_INSERTION) {
2666             set_socket_t set_socket;
2667             get_ss_status_t gs;
2668 
2669         /*
2670          * Check to be sure that we have a valid CIS window
2671          */
2672             if (!SOCKET_HAS_CIS_WINDOW(sp)) {
2673                 cmn_err(CE_CONT,
2674                         "cs_card_insertion: socket %d has no "
2675                                                         "CIS window\n",
2676                                 sp->socket_num);
2677                 return (CS_GENERAL_FAILURE);
2678             }
2679 
2680         /*
2681          * Apply power to the socket, enable card detect and card ready
2682          *      events, then reset the socket.
2683          */
2684             mutex_enter(&sp->lock);
2685             sp->event_mask =   (CS_EVENT_CARD_REMOVAL   |
2686                                 CS_EVENT_CARD_READY);
2687             mutex_exit(&sp->lock);
2688             set_socket.socket = sp->socket_num;
2689             set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
2690             set_socket.IREQRouting = 0;
2691             set_socket.IFType = IF_MEMORY;
2692             set_socket.CtlInd = 0; /* turn off controls and indicators */
2693             set_socket.State = (unsigned)~0;    /* clear latched state bits */
2694 
2695             (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
2696                                                 &set_socket.VccLevel);
2697             (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
2698                                                 &set_socket.Vpp1Level);
2699             (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
2700                                                 &set_socket.Vpp2Level);
2701 
2702             if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
2703                 cmn_err(CE_CONT,
2704                     "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
2705                                 sp->socket_num, ret);
2706                 return (ret);
2707             }
2708 
2709         /*
2710          * Clear the ready and ready_timeout events since they are now
2711          *      bogus since we're about to reset the socket.
2712          * XXX - should these be cleared right after the RESET??
2713          */
2714             mutex_enter(&sp->lock);
2715 
2716             sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
2717             mutex_exit(&sp->lock);
2718 
2719             SocketServices(SS_ResetSocket, sp->socket_num,
2720                                                 RESET_MODE_CARD_ONLY);
2721 
2722         /*
2723          * We are required by the PCMCIA spec to wait some number of
2724          *      milliseconds after reset before we access the card, so
2725          *      we set up a timer here that will wake us up and allow us
2726          *      to continue with our card initialization.
2727          */
2728             mutex_enter(&sp->lock);
2729             sp->thread_state |= SOCKET_RESET_TIMER;
2730             (void) timeout(cs_ready_timeout, sp,
2731                 drv_usectohz(cs_reset_timeout_time * 1000));
2732             cv_wait(&sp->reset_cv, &sp->lock);
2733             sp->thread_state &= ~SOCKET_RESET_TIMER;
2734             mutex_exit(&sp->lock);
2735 
2736 #ifdef  CS_DEBUG
2737             if (cs_debug > 2) {
2738                 cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
2739                     "for %d mS sp->events 0x%x\n",
2740                     sp->socket_num, cs_reset_timeout_time, (int)sp->events);
2741             }
2742 #endif
2743 
2744         /*
2745          * If we have a pending CS_EVENT_CARD_REMOVAL event it
2746          *      means that we likely got CD line bounce on the
2747          *      insertion, so terminate this processing.
2748          */
2749             if (sp->events & CS_EVENT_CARD_REMOVAL) {
2750 #ifdef  CS_DEBUG
2751                 if (cs_debug > 0) {
2752                     cmn_err(CE_CONT, "cs_card_insertion: socket %d "
2753                                                 "CS_EVENT_CARD_REMOVAL event "
2754                                                 "terminating insertion "
2755                                                 "processing\n",
2756                                                         sp->socket_num);
2757                 }
2758 #endif
2759             return (CS_SUCCESS);
2760             } /* if (CS_EVENT_CARD_REMOVAL) */
2761 
2762         /*
2763          * If we got a card ready event after the reset, then don't
2764          *      bother setting up a card ready timer, since we'll blast
2765          *      right on through to the card ready processing.
2766          * Get the current card status to see if it's ready; if it
2767          *      is, we probably won't get a card ready event.
2768          */
2769             gs.socket = sp->socket_num;
2770             gs.CardState = 0;
2771             if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) {
2772                 cmn_err(CE_CONT,
2773                     "cs_card_insertion: socket %d SS_GetStatus failure %d\n",
2774                                 sp->socket_num, ret);
2775                 return (ret);
2776             }
2777 
2778             mutex_enter(&sp->lock);
2779             if ((sp->events & CS_EVENT_CARD_READY) ||
2780                                         (gs.CardState & SBM_RDYBSY)) {
2781                 event = CS_EVENT_CARD_READY;
2782 #ifdef  CS_DEBUG
2783                 if (cs_debug > 1) {
2784                     cmn_err(CE_CONT, "cs_card_insertion: socket %d card "
2785                                                 "READY\n", sp->socket_num);
2786                 }
2787 #endif
2788 
2789             } else {
2790 #ifdef  CS_DEBUG
2791                 if (cs_debug > 1) {
2792                     cmn_err(CE_CONT, "cs_card_insertion: socket %d setting "
2793                                         "READY timer\n", sp->socket_num);
2794                 }
2795 #endif
2796 
2797                 sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp,
2798                     READY_TIMEOUT_TIME);
2799                 sp->thread_state |= SOCKET_WAIT_FOR_READY;
2800 
2801             } /* if (CS_EVENT_CARD_READY) */
2802 
2803             mutex_exit(&sp->lock);
2804 
2805         } /* if (CS_EVENT_CARD_INSERTION) */
2806 
2807         /*
2808          * Handle card ready processing.  This is only card ready processing
2809          *      for card ready events in conjunction with a card insertion.
2810          */
2811         if (event == CS_EVENT_CARD_READY) {
2812             get_socket_t get_socket;
2813             set_socket_t set_socket;
2814 
2815         /*
2816          * The only events that we want to see now are card removal
2817          *      events.
2818          */
2819             mutex_enter(&sp->lock);
2820             sp->event_mask = CS_EVENT_CARD_REMOVAL;
2821             mutex_exit(&sp->lock);
2822             get_socket.socket = sp->socket_num;
2823             if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
2824                 cmn_err(CE_CONT,
2825                         "cs_card_insertion: socket %d SS_GetSocket failed\n",
2826                                                         sp->socket_num);
2827                 return (CS_BAD_SOCKET);
2828             }
2829 
2830             set_socket.socket = sp->socket_num;
2831             set_socket.SCIntMask = SBM_CD;
2832             set_socket.VccLevel = get_socket.VccLevel;
2833             set_socket.Vpp1Level = get_socket.Vpp1Level;
2834             set_socket.Vpp2Level = get_socket.Vpp2Level;
2835             set_socket.IREQRouting = get_socket.IRQRouting;
2836             set_socket.IFType = get_socket.IFType;
2837             set_socket.CtlInd = get_socket.CtlInd;
2838             /* XXX (is ~0 correct here?) to reset latched values */
2839             set_socket.State = (unsigned)~0;
2840 
2841             if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
2842                 cmn_err(CE_CONT,
2843                         "cs_card_insertion: socket %d SS_SetSocket failed\n",
2844                                                         sp->socket_num);
2845 
2846                 return (CS_BAD_SOCKET);
2847             }
2848 
2849                 /*
2850                  * Grab the cis_lock mutex to protect the CIS-to-be and
2851                  *      the CIS window, then fire off the CIS parser to
2852                  *      create a local copy of the card's CIS.
2853                  */
2854                 mutex_enter(&sp->cis_lock);
2855 
2856                 if ((ret = cs_create_cis(sp)) != CS_SUCCESS) {
2857                     mutex_exit(&sp->cis_lock);
2858                     return (ret);
2859                 }
2860 
2861                 mutex_exit(&sp->cis_lock);
2862 
2863                 /*
2864                  * If we have a pending CS_EVENT_CARD_REMOVAL event it
2865                  *      means that we likely got CD line bounce on the
2866                  *      insertion, so destroy the CIS and terminate this
2867                  *      processing. We'll get called back to handle the
2868                  *      insertion again later.
2869                  */
2870                 if (sp->events & CS_EVENT_CARD_REMOVAL) {
2871                     mutex_enter(&sp->cis_lock);
2872                     (void) cs_destroy_cis(sp);
2873                     mutex_exit(&sp->cis_lock);
2874                 } else {
2875                         /*
2876                          * Schedule the call to the Socket Services work thread.
2877                          */
2878                     mutex_enter(&sp->ss_thread_lock);
2879                     sp->ss_thread_state |= SOCKET_THREAD_CSCISInit;
2880                     cv_broadcast(&sp->ss_thread_cv);
2881                     mutex_exit(&sp->ss_thread_lock);
2882                 } /* if (CS_EVENT_CARD_REMOVAL) */
2883         } /* if (CS_EVENT_CARD_READY) */
2884 
2885         /*
2886          * Socket Services has parsed the CIS and has done any other
2887          *      work to get the client driver loaded and attached if
2888          *      necessary, so setup the per-client state.
2889          */
2890         if (event == CS_EVENT_SS_UPDATED) {
2891             client_t *client;
2892 
2893         /*
2894          * Now that we and SS are done handling the card insertion
2895          *      semantics, go through each client on this socket and set
2896          *      the CS_EVENT_CARD_INSERTION event in each client's event
2897          *      field.  We do this here instead of in cs_event so that
2898          *      when a client gets a CS_EVENT_CARD_INSERTION event, the
2899          *      card insertion and ready processing has already been done
2900          *      and SocketServices has had a chance to create a dip for
2901          *      the card in this socket.
2902          */
2903             mutex_enter(&sp->lock);
2904             client = sp->client_list;
2905             while (client) {
2906                 client->events |= (CS_EVENT_CARD_INSERTION &
2907                                 (client->event_mask | client->global_mask));
2908                 client = client->next;
2909             } /* while (client) */
2910 
2911             mutex_exit(&sp->lock);
2912 
2913         } /* if (CS_EVENT_SS_UPDATED) */
2914 
2915         return (CS_SUCCESS);
2916 }
2917 
2918 /*
2919  * cs_card_removal - handle card removal events
2920  *
2921  * Destroy the CIS.
2922  *
2923  *    calling:  sp - pointer to socket structure
2924  *
2925  */
2926 static int
2927 cs_card_removal(cs_socket_t *sp)
2928 {
2929         set_socket_t set_socket;
2930         int ret;
2931 
2932 #ifdef  CS_DEBUG
2933         if (cs_debug > 0) {
2934             cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num);
2935         }
2936 #endif
2937 
2938         /*
2939          * Remove any pending card ready timer
2940          */
2941         UNTIMEOUT(sp->rdybsy_tmo_id);
2942 
2943         /*
2944          * Clear various flags so that everyone else knows that there's
2945          *      nothing on this socket anymore.  Note that we clear the
2946          *      SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
2947          *      ss_to_cs_events event mapping function.
2948          */
2949         mutex_enter(&sp->lock);
2950         sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER);
2951 
2952         /*
2953          * Turn off socket power and set the socket back to memory mode.
2954          * Disable all socket events except for CARD_INSERTION events.
2955          */
2956         sp->event_mask = CS_EVENT_CARD_INSERTION;
2957         mutex_exit(&sp->lock);
2958         set_socket.socket = sp->socket_num;
2959         set_socket.SCIntMask = SBM_CD;
2960         set_socket.IREQRouting = 0;
2961         set_socket.IFType = IF_MEMORY;
2962         set_socket.CtlInd = 0; /* turn off controls and indicators */
2963         set_socket.State = (unsigned)~0;        /* clear latched state bits */
2964 
2965         (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
2966                                         &set_socket.VccLevel);
2967         (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
2968                                         &set_socket.Vpp1Level);
2969         (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
2970                                         &set_socket.Vpp2Level);
2971 
2972         if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
2973             cmn_err(CE_CONT,
2974                 "cs_card_removal: socket %d SS_SetSocket failure %d\n",
2975                                 sp->socket_num, ret);
2976             return (ret);
2977         }
2978 
2979 #ifdef  CS_DEBUG
2980         if (cs_debug > 2) {
2981             cmn_err(CE_CONT, "cs_card_removal: socket %d "
2982                                         "calling cs_destroy_cis\n",
2983                                                         sp->socket_num);
2984         }
2985 #endif
2986 
2987         /*
2988          * Destroy the CIS and tell Socket Services that we're done
2989          *      handling the card removal event.
2990          */
2991         mutex_enter(&sp->cis_lock);
2992         (void) cs_destroy_cis(sp);
2993         mutex_exit(&sp->cis_lock);
2994 
2995 #ifdef  CS_DEBUG
2996         if (cs_debug > 2) {
2997             cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n");
2998         }
2999 #endif
3000 
3001         SocketServices(CSCardRemoved, sp->socket_num);
3002 
3003         return (CS_SUCCESS);
3004 }
3005 
3006 /*
3007  * ss_to_cs_events - convert Socket Services events to Card Services event
3008  *                      masks; this function will not read the PRR if the
3009  *                      socket is in IO mode; this happens in cs_event_thread
3010  *
3011  * This function returns a bit mask of events.
3012  *
3013  * Note that we do some simple hysterious on card insertion and card removal
3014  *      events to prevent spurious insertion and removal events from being
3015  *      propogated down the chain.
3016  */
3017 static event_t
3018 ss_to_cs_events(cs_socket_t *sp, event_t event)
3019 {
3020         event_t revent = 0;
3021 
3022         switch (event) {
3023             case PCE_CARD_STATUS_CHANGE:
3024                 revent |= CS_EVENT_STATUS_CHANGE;
3025                 break;
3026             case PCE_CARD_REMOVAL:
3027                 if (sp->flags & SOCKET_CARD_INSERTED) {
3028                     sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO);
3029                     revent |= CS_EVENT_CARD_REMOVAL;
3030                         /*
3031                          * If we're processing a removal event, it makes
3032                          *      no sense to keep any insertion or ready events,
3033                          *      so nuke them here.  This will not clear any
3034                          *      insertion events in the per-client event field.
3035                          */
3036                     sp->events &= ~(CS_EVENT_CARD_INSERTION |
3037                                     CS_EVENT_CARD_READY |
3038                                     CS_EVENT_READY_TIMEOUT);
3039 
3040                 /*
3041                  * We also don't need to wait for READY anymore since
3042                  *      it probably won't show up, or if it does, it will
3043                  *      be a bogus READY event as the card is sliding out
3044                  *      of the socket.  Since we never do a cv_wait on the
3045                  *      card ready timer, it's OK for that timer to either
3046                  *      never go off (via an UNTIMEOUT in cs_card_removal)
3047                  *      or to go off but not do a cv_broadcast (since the
3048                  *      SOCKET_WAIT_FOR_READY flag is cleared here).
3049                  */
3050                     sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
3051 
3052                 }
3053                 break;
3054             case PCE_CARD_INSERT:
3055                 if (!(sp->flags & SOCKET_CARD_INSERTED)) {
3056                     sp->flags |= SOCKET_CARD_INSERTED;
3057                     revent |= CS_EVENT_CARD_INSERTION;
3058                 }
3059                 break;
3060             case PCE_CARD_READY:
3061                 if (sp->flags & SOCKET_CARD_INSERTED)
3062                     revent |= CS_EVENT_CARD_READY;
3063                 break;
3064             case PCE_CARD_BATTERY_WARN:
3065                 if (sp->flags & SOCKET_CARD_INSERTED)
3066                     revent |= CS_EVENT_BATTERY_LOW;
3067                 break;
3068             case PCE_CARD_BATTERY_DEAD:
3069                 if (sp->flags & SOCKET_CARD_INSERTED)
3070                     revent |= CS_EVENT_BATTERY_DEAD;
3071                 break;
3072             case PCE_CARD_WRITE_PROTECT:
3073                 if (sp->flags & SOCKET_CARD_INSERTED)
3074                     revent |= CS_EVENT_WRITE_PROTECT;
3075                 break;
3076             case PCE_PM_RESUME:
3077                 revent |= CS_EVENT_PM_RESUME;
3078                 break;
3079             case PCE_PM_SUSPEND:
3080                 revent |= CS_EVENT_PM_SUSPEND;
3081                 break;
3082             default:
3083                 cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n",
3084                                                                 (int)event);
3085                 break;
3086         } /* switch(event) */
3087 
3088         return (revent);
3089 }
3090 
3091 /*
3092  * cs_ready_timeout - general purpose READY/BUSY and RESET timer
3093  *
3094  * Note that we really only expect one of the two events to be asserted when
3095  *      we are called.  XXX - Perhaps this might be a problem later on??
3096  *
3097  *      There is also the problem of cv_broadcast dropping the interrupt
3098  *      priority, even though we have our high-priority mutex held.  If
3099  *      we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
3100  *      we get a high-priority interrupt during this time, the system will
3101  *      deadlock or panic.  Thanks to Andy Banta for finding this out in
3102  *      the SPC/S (stc.c) driver.
3103  *
3104  * This callback routine can not grab the sp->client_lock mutex or deadlock
3105  *      will result.
3106  */
3107 void
3108 cs_ready_timeout(void *arg)
3109 {
3110         cs_socket_t *sp = arg;
3111         kcondvar_t *cvp = NULL;
3112 
3113         mutex_enter(&sp->lock);
3114 
3115         if (sp->thread_state & SOCKET_RESET_TIMER) {
3116 #ifdef  CS_DEBUG
3117         if (cs_debug > 1) {
3118             cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n",
3119                                                         sp->socket_num);
3120         }
3121 #endif
3122 
3123             cvp = &sp->reset_cv;
3124         }
3125 
3126         if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
3127             sp->events |= CS_EVENT_READY_TIMEOUT;
3128             cvp = &sp->thread_cv;
3129 
3130 #ifdef  CS_DEBUG
3131             if (cs_debug > 1) {
3132                 cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY "
3133                                                 "socket %d\n", sp->socket_num);
3134             }
3135 #endif
3136 
3137         }
3138 
3139         mutex_exit(&sp->lock);
3140 
3141         if (cvp)
3142             cv_broadcast(cvp);
3143 }
3144 
3145 /*
3146  * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
3147  */
3148 /* ARGSUSED */
3149 void
3150 cs_event_softintr_timeout(void *arg)
3151 {
3152 
3153         /*
3154          * If we're trying to unload this module, then don't do
3155          *      anything but exit.
3156          * We acquire the cs_globals.global_lock mutex here so that
3157          *      we can correctly synchronize with cs_deinit when it
3158          *      is telling us to shut down. XXX - is this bogus??
3159          */
3160         mutex_enter(&cs_globals.global_lock);
3161         if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) {
3162             mutex_exit(&cs_globals.global_lock);
3163             (void) cs_socket_event_softintr(NULL);
3164             cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
3165                 NULL, SOFTINT_TIMEOUT_TIME);
3166         } else {
3167             mutex_exit(&cs_globals.global_lock);
3168         }
3169 }
3170 
3171 /*
3172  * cs_socket_event_softintr - This function just does a cv_broadcast on behalf
3173  *                              of the high-priority interrupt handler.
3174  *
3175  *      Note: There is no calling argument.
3176  */
3177 /*ARGSUSED*/
3178 uint32_t
3179 cs_socket_event_softintr(caddr_t notused)
3180 {
3181         cs_socket_t *sp;
3182         uint32_t sn;
3183         int ret = DDI_INTR_UNCLAIMED;
3184 
3185         /*
3186          * If the module is on it's way out, then don't bother
3187          *      to do anything else except return.
3188          */
3189         mutex_enter(&cs_globals.global_lock);
3190         if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) ||
3191                                 (cs_globals.init_state & GLOBAL_IN_SOFTINTR)) {
3192                 mutex_exit(&cs_globals.global_lock);
3193 
3194                 /*
3195                  * Note that we return DDI_INTR_UNCLAIMED here
3196                  *      since we don't want to be constantly
3197                  *      called back.
3198                  */
3199                 return (ret);
3200         } else {
3201             cs_globals.init_state |= GLOBAL_IN_SOFTINTR;
3202             mutex_exit(&cs_globals.global_lock);
3203         }
3204 
3205         /*
3206          * Go through each socket and dispatch the appropriate events.
3207          *      We have to funnel everything through this one routine because
3208          *      we can't do a cv_broadcast from a high level interrupt handler
3209          *      and we also can't have more than one soft interrupt handler
3210          *      on a single dip and using the same handler address.
3211          */
3212         for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3213             if ((sp = cs_get_sp(sn)) != NULL) {
3214                 if (sp->init_state & SOCKET_INIT_STATE_READY) {
3215                         /*
3216                          * If we're being asked to unload CS, then don't bother
3217                          *      waking up the socket event thread handler.
3218                          */
3219                     if (!(sp->flags & SOCKET_UNLOAD_MODULE) &&
3220                                         (sp->flags & SOCKET_NEEDS_THREAD)) {
3221                         ret = DDI_INTR_CLAIMED;
3222                         mutex_enter(&sp->client_lock);
3223                         cv_broadcast(&sp->thread_cv);
3224                         mutex_exit(&sp->client_lock);
3225                     } /* if (SOCKET_NEEDS_THREAD) */
3226                 } /* if (SOCKET_INIT_STATE_READY) */
3227             } /* cs_get_sp */
3228         } /* for (sn) */
3229 
3230         mutex_enter(&cs_globals.global_lock);
3231         cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR;
3232         mutex_exit(&cs_globals.global_lock);
3233 
3234         return (ret);
3235 }
3236 
3237 /*
3238  * cs_event_thread - This is the per-socket event thread.
3239  */
3240 static void
3241 cs_event_thread(uint32_t sn)
3242 {
3243         cs_socket_t     *sp;
3244         client_t        *client;
3245         client_types_t  *ct;
3246 
3247         if ((sp = cs_get_sp(sn)) == NULL)
3248             return;
3249 
3250 #ifdef  CS_DEBUG
3251         if (cs_debug > 1) {
3252             cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n",
3253                                                                 sp->socket_num);
3254         }
3255 #endif
3256 
3257         CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock,
3258                                         callb_generic_cpr, "cs_event_thread");
3259 
3260         mutex_enter(&sp->client_lock);
3261 
3262         for (;;) {
3263 
3264             CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs);
3265             cv_wait(&sp->thread_cv, &sp->client_lock);
3266             CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock);
3267 
3268             mutex_enter(&sp->lock);
3269             sp->flags &= ~SOCKET_NEEDS_THREAD;
3270             mutex_exit(&sp->lock);
3271 
3272         /*
3273          * Check to see if there are any special thread operations that
3274          *      we are being asked to perform.
3275          */
3276             if (sp->thread_state & SOCKET_THREAD_EXIT) {
3277 #ifdef  CS_DEBUG
3278                 if (cs_debug > 1) {
3279                     cmn_err(CE_CONT, "cs_event_thread: socket %d "
3280                                                         "SOCKET_THREAD_EXIT\n",
3281                                                         sp->socket_num);
3282                 }
3283 #endif
3284                 CALLB_CPR_EXIT(&sp->cprinfo_cs);
3285                 cv_broadcast(&sp->caller_cv);    /* wakes up cs_deinit */
3286                 mutex_exit(&sp->client_lock);
3287                 return;
3288             } /* if (SOCKET_THREAD_EXIT) */
3289 
3290 #ifdef  CS_DEBUG
3291             if (cs_debug > 1) {
3292                 cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n",
3293                                                         sp->socket_num,
3294                                                         (int)sp->events);
3295             }
3296 #endif
3297 
3298         /*
3299          * Handle CS_EVENT_CARD_INSERTION events
3300          */
3301             if (sp->events & CS_EVENT_CARD_INSERTION) {
3302                 mutex_enter(&sp->lock);
3303                 sp->events &= ~CS_EVENT_CARD_INSERTION;
3304                 mutex_exit(&sp->lock);
3305 
3306                 /*
3307                  * If we have a pending CS_EVENT_CARD_REMOVAL event it
3308                  *      means that we likely got CD line bounce on the
3309                  *      insertion, so terminate this processing.
3310                  */
3311                 if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) {
3312                     (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION);
3313                 }
3314 #ifdef  CS_DEBUG
3315                 else if (cs_debug > 0) {
3316                         cmn_err(CE_CONT, "cs_event_thread: socket %d "
3317                                         "CS_EVENT_CARD_REMOVAL event "
3318                                         "terminating "
3319                                         "CS_EVENT_CARD_INSERTION "
3320                                         "processing\n", sp->socket_num);
3321                     }
3322 #endif
3323         } /* if (CS_EVENT_CARD_INSERTION) */
3324 
3325         /*
3326          * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
3327          */
3328             if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) {
3329                 mutex_enter(&sp->lock);
3330                 sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
3331                 mutex_exit(&sp->lock);
3332                 if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
3333                     mutex_enter(&sp->lock);
3334                     sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
3335                     mutex_exit(&sp->lock);
3336                     (void) cs_card_insertion(sp, CS_EVENT_CARD_READY);
3337                 } /* if (SOCKET_WAIT_FOR_READY) */
3338             } /* if (CS_EVENT_CARD_READY) */
3339 
3340         /*
3341          * Handle CS_EVENT_SS_UPDATED events
3342          */
3343             if (sp->events & CS_EVENT_SS_UPDATED) {
3344                 mutex_enter(&sp->lock);
3345                 sp->events &= ~CS_EVENT_SS_UPDATED;
3346                 mutex_exit(&sp->lock);
3347                 (void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED);
3348             } /* if (CS_EVENT_SS_UPDATED) */
3349 
3350         /*
3351          * Handle CS_EVENT_STATUS_CHANGE events
3352          */
3353             if (sp->events & CS_EVENT_STATUS_CHANGE) {
3354                 event_t revent;
3355 
3356                 mutex_enter(&sp->cis_lock);
3357                 mutex_enter(&sp->lock);
3358                 sp->events &= ~CS_EVENT_STATUS_CHANGE;
3359 
3360                 /*
3361                  * Go through each client and add any events that we saw to
3362                  *      the client's event list if the client has that event
3363                  *      enabled in their event mask.
3364                  * Remove any events that may be pending for this client if
3365                  *      the client's event mask says that the client doesn't
3366                  *      want to see those events anymore. This handles the
3367                  *      case where the client had an event enabled in it's
3368                  *      event mask when the event came in but between that
3369                  *      time and the time we're called here the client
3370                  *      disabled that event.
3371                  */
3372                 client = sp->client_list;
3373 
3374                 while (client) {
3375                         /*
3376                          * Read the PRR (if it exists) and check for any events.
3377                          * The PRR will only be read if the socket is in IO
3378                          * mode, if there is a card in the socket, and if there
3379                          * is a PRR.
3380                          * We don't have to clear revent before we call the
3381                          * cs_read_event_status function since it will
3382                          * clear it before adding any current events.
3383                          */
3384                     if (client->flags & CLIENT_CARD_INSERTED) {
3385                         (void) cs_read_event_status(sp, client,
3386                                                         &revent, NULL, 0);
3387 
3388                         client->events = ((client->events | revent) &
3389                                                 (client->event_mask |
3390                                                         client->global_mask));
3391                     } /* CLIENT_CARD_INSERTED */
3392                     client = client->next;
3393                 } /* while (client) */
3394 
3395                 mutex_exit(&sp->lock);
3396                 mutex_exit(&sp->cis_lock);
3397             } /* if (CS_EVENT_STATUS_CHANGE) */
3398 
3399         /*
3400          * We want to maintain the required event dispatching order as
3401          *      specified in the PCMCIA spec, so we cycle through all
3402          *      clients on this socket to make sure that they are
3403          *      notified in the correct order.
3404          */
3405             ct = &client_types[0];
3406             while (ct) {
3407                 /*
3408                  * Point to the head of the client list for this socket, and go
3409                  *      through each client to set up the client events as well
3410                  *      as call the client's event handler directly if we have
3411                  *      a high priority event that we need to tell the client
3412                  *      about.
3413                  */
3414                 client = sp->client_list;
3415 
3416                 if (ct->order & CLIENT_EVENTS_LIFO) {
3417                     client_t *clp = NULL;
3418 
3419                     while (client) {
3420                         clp = client;
3421                         client = client->next;
3422                     }
3423                     client = clp;
3424                 }
3425 
3426                 while (client) {
3427                     if (client->flags & ct->type) {
3428                             uint32_t bit = 0;
3429                             event_t event;
3430 
3431                         while (client->events) {
3432 
3433                             switch (event = CS_BIT_GET(client->events, bit)) {
3434                                 /*
3435                                  * Clients always receive registration complete
3436                                  *      events, even if there is no card of
3437                                  *      their type currently in the socket.
3438                                  */
3439                                 case CS_EVENT_REGISTRATION_COMPLETE:
3440                                     CLIENT_EVENT_CALLBACK(client, event,
3441                                                         CS_EVENT_PRI_LOW);
3442                                     break;
3443                                 /*
3444                                  * The client only gets a card insertion event
3445                                  *      if there is currently a card in the
3446                                  *      socket that the client can control.
3447                                  *      The nexus determines this. We also
3448                                  *      prevent the client from receiving
3449                                  *      multiple CS_EVENT_CARD_INSERTION
3450                                  *      events without receiving intervening
3451                                  *      CS_EVENT_CARD_REMOVAL events.
3452                                  */
3453                                 case CS_EVENT_CARD_INSERTION:
3454                                     if (cs_card_for_client(client)) {
3455                                         int send_insertion;
3456 
3457                                         mutex_enter(&sp->lock);
3458                                         send_insertion = client->flags;
3459                                         client->flags |=
3460                                                 (CLIENT_CARD_INSERTED |
3461                                                 CLIENT_SENT_INSERTION);
3462                                         mutex_exit(&sp->lock);
3463                                         if (!(send_insertion &
3464                                                     CLIENT_SENT_INSERTION)) {
3465                                             CLIENT_EVENT_CALLBACK(client,
3466                                                 event, CS_EVENT_PRI_LOW);
3467                                         } /* if (!CLIENT_SENT_INSERTION) */
3468                                     }
3469                                     break;
3470                                 /*
3471                                  * The CS_EVENT_CARD_REMOVAL_LOWP is a low
3472                                  *      priority CS_EVENT_CARD_REMOVAL event.
3473                                  */
3474                                 case CS_EVENT_CARD_REMOVAL_LOWP:
3475                                     mutex_enter(&sp->lock);
3476                                     client->flags &= ~CLIENT_SENT_INSERTION;
3477                                     mutex_exit(&sp->lock);
3478                                     CLIENT_EVENT_CALLBACK(client,
3479                                                         CS_EVENT_CARD_REMOVAL,
3480                                                         CS_EVENT_PRI_LOW);
3481                                     break;
3482                                 /*
3483                                  * The hardware card removal events are handed
3484                                  *      to the client in cs_event at high
3485                                  *      priority interrupt time; this card
3486                                  *      removal event is a software-generated
3487                                  *      event.
3488                                  */
3489                                 case CS_EVENT_CARD_REMOVAL:
3490                                     if (client->flags & CLIENT_CARD_INSERTED) {
3491                                         mutex_enter(&sp->lock);
3492                                         client->flags &=
3493                                                 ~(CLIENT_CARD_INSERTED |
3494                                                 CLIENT_SENT_INSERTION);
3495                                         mutex_exit(&sp->lock);
3496                                         CLIENT_EVENT_CALLBACK(client, event,
3497                                                         CS_EVENT_PRI_LOW);
3498                                     }
3499                                     break;
3500                                 /*
3501                                  * Write protect events require the info field
3502                                  *      of the client's event callback args to
3503                                  *      be zero if the card is not write
3504                                  *      protected and one if it is.
3505                                  */
3506                                 case CS_EVENT_WRITE_PROTECT:
3507                                     if (client->flags & CLIENT_CARD_INSERTED) {
3508                                         get_ss_status_t gs;
3509 
3510                                         mutex_enter(&sp->cis_lock);
3511                                         mutex_enter(&sp->lock);
3512                                         (void) cs_read_event_status(sp, client,
3513                                                                         NULL,
3514                                                                         &gs, 0);
3515                                         if (gs.CardState & SBM_WP) {
3516                                             client->event_callback_args.info =
3517                                                 (void *)
3518                                                 CS_EVENT_WRITE_PROTECT_WPON;
3519                                         } else {
3520                                             client->event_callback_args.info =
3521                                                 (void *)
3522                                                 CS_EVENT_WRITE_PROTECT_WPOFF;
3523                                         }
3524                                         mutex_exit(&sp->lock);
3525                                         mutex_exit(&sp->cis_lock);
3526                                         CLIENT_EVENT_CALLBACK(client, event,
3527                                                         CS_EVENT_PRI_LOW);
3528                                     } /* CLIENT_CARD_INSERTED */
3529                                     break;
3530                                 case CS_EVENT_CLIENT_INFO:
3531                                     CLIENT_EVENT_CALLBACK(client, event,
3532                                                         CS_EVENT_PRI_LOW);
3533                                     break;
3534                                 case 0:
3535                                     break;
3536                                 default:
3537                                     if (client->flags & CLIENT_CARD_INSERTED) {
3538                                         CLIENT_EVENT_CALLBACK(client, event,
3539                                                         CS_EVENT_PRI_LOW);
3540                                     }
3541                                     break;
3542                             } /* switch */
3543                             mutex_enter(&sp->lock);
3544                             CS_BIT_CLEAR(client->events, bit);
3545                             mutex_exit(&sp->lock);
3546                             bit++;
3547                         } /* while (client->events) */
3548                     } /* if (ct->type) */
3549                     if (ct->order & CLIENT_EVENTS_LIFO) {
3550                         client = client->prev;
3551                     } else {
3552                         client = client->next;
3553                     }
3554                 } /* while (client) */
3555 
3556                 ct = ct->next;
3557             } /* while (ct) */
3558 
3559         /*
3560          * Handle CS_EVENT_CARD_REMOVAL events
3561          */
3562             if (sp->events & CS_EVENT_CARD_REMOVAL) {
3563                 mutex_enter(&sp->lock);
3564                 sp->events &= ~CS_EVENT_CARD_REMOVAL;
3565                 mutex_exit(&sp->lock);
3566                 (void) cs_card_removal(sp);
3567             } /* if (CS_EVENT_CARD_REMOVAL) */
3568 
3569                 /*
3570                  * If someone is waiting for us to complete, signal them now.
3571                  */
3572             if (sp->thread_state & SOCKET_WAIT_SYNC) {
3573                 mutex_enter(&sp->lock);
3574                 sp->thread_state &= ~SOCKET_WAIT_SYNC;
3575                 mutex_exit(&sp->lock);
3576                 cv_broadcast(&sp->caller_cv);
3577             } /* SOCKET_WAIT_SYNC */
3578 
3579         } /* for (;;) */
3580 }
3581 
3582 /*
3583  * cs_card_for_client - checks to see if a card that the client can control
3584  *                      is currently inserted in the socket.  Socket Services
3585  *                      has to tell us if this is the case.
3586  */
3587 static int
3588 cs_card_for_client(client_t *client)
3589 {
3590 
3591         /*
3592          * If the client has set the CS_EVENT_ALL_CLIENTS it means that they
3593          *      want to get all events for all clients, irrespective of
3594          *      whether or not there is a card in the socket.  Such clients
3595          *      have to be very careful if they touch the card hardware in
3596          *      any way to prevent causing problems for other clients on the
3597          *      same socket.  This flag will typically only be set by the
3598          *      "super-client" or CSI types of clients that wish to get
3599          *      information on other clients or cards in the system.
3600          * Note that the CS_EVENT_ALL_CLIENTS must be set in either the
3601          *      client's global event mask or client event mask.
3602          * The client must also have registered as a "super-client" or as a
3603          *      CSI client for this socket.
3604          */
3605         if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) &&
3606                         ((client->global_mask | client->event_mask) &
3607                                                         CS_EVENT_ALL_CLIENTS))
3608             return (1);
3609 
3610         /*
3611          * Look for the PCM_DEV_ACTIVE property on this client's dip; if
3612          *      it's found, it means that this client can control the card
3613          *      that is currently in the socket.  This is a boolean
3614          *      property managed by Socket Services.
3615          */
3616         if (ddi_getprop(DDI_DEV_T_ANY, client->dip,    (DDI_PROP_CANSLEEP |
3617                                                         DDI_PROP_NOTPROM),
3618                                                         PCM_DEV_ACTIVE, NULL)) {
3619 #ifdef  CS_DEBUG
3620             if (cs_debug > 1) {
3621                 cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x "
3622                                         "driver [%s] says %s found\n",
3623                                                 (int)client->client_handle,
3624                                                 client->driver_name,
3625                                                 PCM_DEV_ACTIVE);
3626             }
3627 #endif
3628             return (1);
3629         }
3630 
3631         return (0);
3632 }
3633 
3634 /*
3635  * cs_ss_thread - This is the Socket Services work thread. We fire off
3636  *                      any calls to Socket Services here that we want
3637  *                      to run on a thread that is seperate from the
3638  *                      per-socket event thread.
3639  */
3640 static void
3641 cs_ss_thread(uint32_t sn)
3642 {
3643         cs_socket_t *sp;
3644 
3645         if ((sp = cs_get_sp(sn)) == NULL)
3646             return;
3647 
3648         /*
3649          * Tell CPR that we've started a new thread.
3650          */
3651         CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock,
3652                                         callb_generic_cpr, "cs_ss_thread");
3653 
3654         mutex_enter(&sp->ss_thread_lock);
3655 
3656         for (;;) {
3657 
3658             CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss);
3659             cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock);
3660             CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock);
3661 
3662                 /*
3663                  * Check to see if there are any special thread operations
3664                  * that we are being asked to perform.
3665                  */
3666             if (sp->ss_thread_state & SOCKET_THREAD_EXIT) {
3667 #ifdef  CS_DEBUG
3668                 if (cs_debug > 1) {
3669                     cmn_err(CE_CONT, "cs_ss_thread: socket %d "
3670                                         "SOCKET_THREAD_EXIT\n",
3671                                                 sp->socket_num);
3672                 }
3673 #endif
3674                 CALLB_CPR_EXIT(&sp->cprinfo_ss);
3675                 cv_broadcast(&sp->ss_caller_cv); /* wake up cs_deinit */
3676                 mutex_exit(&sp->ss_thread_lock);
3677                 return;
3678             } /* if (SOCKET_THREAD_EXIT) */
3679 
3680 #ifdef  CS_DEBUG
3681             if (cs_debug > 1) {
3682                 cmn_err(CE_CONT, "cs_ss_thread: socket %d "
3683                                         "ss_thread_state = 0x%x\n",
3684                                                 (int)sp->socket_num,
3685                                                 (int)sp->ss_thread_state);
3686             }
3687 #endif
3688 
3689                 /*
3690                  * Call SocketServices(CSCISInit) to have SS parse the
3691                  *      CIS and load/attach any client drivers necessary.
3692                  */
3693             if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) {
3694 
3695                 sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit;
3696 
3697                 if (!(sp->flags & SOCKET_CARD_INSERTED)) {
3698                     cmn_err(CE_CONT, "cs_ss_thread %d "
3699                                         "card NOT inserted\n",
3700                                         sp->socket_num);
3701                 }
3702 
3703 #ifdef  CS_DEBUG
3704                 if (cs_debug > 1) {
3705                     cmn_err(CE_CONT, "cs_ss_thread: socket %d calling "
3706                                                 "CSCISInit\n", sp->socket_num);
3707                 }
3708 #endif
3709 
3710                 /*
3711                  * Tell SS that we have a complete CIS and that it can now
3712                  *      be parsed.
3713                  * Note that in some cases the client driver may block in
3714                  *      their attach routine, causing this call to block until
3715                  *      the client completes their attach.
3716                  */
3717                 SocketServices(CSCISInit, sp->socket_num);
3718 
3719                 /*
3720                  * Set the CS_EVENT_SS_UPDATED event for this socket so that the
3721                  *      event thread can continue any card insertion processing
3722                  *      that it has to do.
3723                  */
3724                 mutex_enter(&sp->lock);
3725                 sp->events |= CS_EVENT_SS_UPDATED;
3726                 mutex_exit(&sp->lock);
3727 
3728                 /*
3729                  * Wake up this socket's event thread so that clients can
3730                  *      continue any card insertion or attach processing
3731                  *      that they need to do.
3732                  */
3733                 cv_broadcast(&sp->thread_cv);
3734             } /* if ST_CSCISInit */
3735 
3736         } /* for (;;) */
3737 }
3738 
3739 /*
3740  * cs_request_socket_mask - set the client's event mask as well as causes
3741  *                              any events pending from RegisterClient to
3742  *                              be scheduled to be sent to the client
3743  */
3744 static int
3745 cs_request_socket_mask(client_handle_t client_handle,
3746                                         request_socket_mask_t *se)
3747 {
3748         cs_socket_t *sp;
3749         client_t *client;
3750         int error;
3751         int client_lock_acquired;
3752 
3753         /*
3754          * Check to see if this is the Socket Services client handle; if it
3755          *      is, we don't do anything except for return success.
3756          */
3757         if (CLIENT_HANDLE_IS_SS(client_handle))
3758             return (CS_SUCCESS);
3759 
3760         /*
3761          * Get a pointer to this client's socket structure.
3762          */
3763         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3764             return (CS_BAD_SOCKET);
3765 
3766         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3767 
3768         /*
3769          *  Make sure that this is a valid client handle.
3770          */
3771         if (!(client = cs_find_client(client_handle, &error))) {
3772             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3773             return (error);
3774         }
3775 
3776         mutex_enter(&sp->lock);
3777 
3778         /*
3779          * If this client has already done a RequestSocketMask without
3780          *      a corresponding ReleaseSocketMask, then return an error.
3781          */
3782         if (client->flags & REQ_SOCKET_MASK_DONE) {
3783             mutex_exit(&sp->lock);
3784             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3785             return (CS_IN_USE);
3786         }
3787 
3788         /*
3789          * Set up the event mask information; we copy this directly from
3790          *      the client; since we are the only source of events, any
3791          *      bogus bits that the client puts in here won't matter
3792          *      because we'll never look at them.
3793          */
3794         client->event_mask = se->EventMask;
3795 
3796         /*
3797          * If RegisterClient left us some events to process, set these
3798          *      events up here.
3799          */
3800         if (client->pending_events) {
3801             client->events |= client->pending_events;
3802             client->pending_events = 0;
3803 #ifdef  CS_DEBUG
3804             if (cs_debug > 1) {
3805                 cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x "
3806                                 "driver_name = [%s] events = 0x%x\n",
3807                                         (int)client->client_handle,
3808                                         client->driver_name,
3809                                         (int)client->events);
3810             }
3811 #endif
3812         }
3813 
3814         client->flags |= REQ_SOCKET_MASK_DONE;
3815 
3816         /*
3817          * Merge all the clients' event masks and set the socket
3818          *      to generate the appropriate events.
3819          */
3820         (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
3821 
3822         mutex_exit(&sp->lock);
3823 
3824         /*
3825          * Wakeup the event thread if there are any client events to process.
3826          */
3827         if (client->events) {
3828             cv_broadcast(&sp->thread_cv);
3829 #ifdef  CS_DEBUG
3830             if (cs_debug > 1) {
3831                 cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for "
3832                                 "client_handle = 0x%x "
3833                                 "driver_name = [%s] events = 0x%x\n",
3834                                         (int)client->client_handle,
3835                                         client->driver_name,
3836                                         (int)client->events);
3837             }
3838 #endif
3839 
3840         }
3841         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3842 
3843         return (CS_SUCCESS);
3844 }
3845 
3846 /*
3847  * cs_release_socket_mask - clear the client's event mask
3848  *
3849  * Once this function returns, the client is guaranteed
3850  *      not to get any more event callbacks.
3851  */
3852 /*ARGSUSED*/
3853 static int
3854 cs_release_socket_mask(client_handle_t client_handle,
3855                                         release_socket_mask_t *rsm)
3856 {
3857         cs_socket_t *sp;
3858         client_t *client;
3859         int error;
3860         int client_lock_acquired;
3861 
3862         /*
3863          * Check to see if this is the Socket Services client handle; if it
3864          *      is, we don't do anything except for return success.
3865          */
3866         if (CLIENT_HANDLE_IS_SS(client_handle))
3867             return (CS_SUCCESS);
3868 
3869         /*
3870          * Get a pointer to this client's socket structure.
3871          */
3872         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3873             return (CS_BAD_SOCKET);
3874 
3875         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3876 
3877         /*
3878          *  Make sure that this is a valid client handle.
3879          */
3880         if (!(client = cs_find_client(client_handle, &error))) {
3881             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3882             return (error);
3883         }
3884 
3885         mutex_enter(&sp->lock);
3886 
3887         /*
3888          * If this client has already done a RequestSocketMask without
3889          *      a corresponding ReleaseSocketMask, then return an error.
3890          */
3891         if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
3892             mutex_exit(&sp->lock);
3893             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3894             return (CS_BAD_SOCKET);
3895         }
3896 
3897         /*
3898          * Clear both the client event mask and the global event mask.
3899          *      We clear both since the semantics of this function are
3900          *      that once it returns, the client will not be called at
3901          *      it's event handler for any events until RequestSocketMask
3902          *      is called again.
3903          */
3904         client->event_mask = 0;
3905         client->global_mask = 0;
3906         client->flags &= ~REQ_SOCKET_MASK_DONE;
3907 
3908         /*
3909          * Merge all the clients' event masks and set the socket
3910          *      to generate the appropriate events.
3911          */
3912         (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
3913 
3914         mutex_exit(&sp->lock);
3915         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3916 
3917         return (CS_SUCCESS);
3918 }
3919 
3920 /*
3921  * cs_get_event_mask - return the event mask for this client
3922  */
3923 static int
3924 cs_get_event_mask(client_handle_t client_handle, sockevent_t *se)
3925 {
3926         cs_socket_t *sp;
3927         client_t *client;
3928         int error;
3929         int client_lock_acquired;
3930 
3931         /*
3932          * Check to see if this is the Socket Services client handle; if it
3933          *      is, we don't do anything except for return success.
3934          */
3935         if (CLIENT_HANDLE_IS_SS(client_handle))
3936             return (CS_SUCCESS);
3937 
3938         /*
3939          * Get a pointer to this client's socket structure.
3940          */
3941         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3942             return (CS_BAD_SOCKET);
3943 
3944         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3945 
3946         /*
3947          *  Make sure that this is a valid client handle.
3948          */
3949         if (!(client = cs_find_client(client_handle, &error))) {
3950             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3951             return (error);
3952         }
3953 
3954         mutex_enter(&sp->lock);
3955 
3956 #ifdef  XXX
3957         /*
3958          * If there's no card in the socket or the card in the socket is not
3959          *      for this client, then return an error.
3960          * XXX - how can a client get their event masks if their card
3961          *      goes away?
3962          */
3963         if (!(client->flags & CLIENT_CARD_INSERTED)) {
3964             mutex_exit(&sp->lock);
3965             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3966             return (CS_NO_CARD);
3967         }
3968 #endif
3969 
3970         /*
3971          * We are only allowed to get the client event mask if a
3972          *      RequestSocketMask has been called previously.  We
3973          *      are allowed to get the global event mask at any
3974          *      time.
3975          * The global event mask is initially set by the client
3976          *      in the call to RegisterClient.  The client event
3977          *      mask is set by the client in calls to SetEventMask
3978          *      and RequestSocketMask and gotten in calls to
3979          *      GetEventMask.
3980          */
3981         if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
3982             if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
3983                 mutex_exit(&sp->lock);
3984                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3985                 return (CS_BAD_SOCKET);
3986             }
3987             se->EventMask = client->event_mask;
3988         } else {
3989             se->EventMask = client->global_mask;
3990         }
3991 
3992         mutex_exit(&sp->lock);
3993         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3994 
3995         return (CS_SUCCESS);
3996 }
3997 
3998 /*
3999  * cs_set_event_mask - set the event mask for this client
4000  */
4001 static int
4002 cs_set_event_mask(client_handle_t client_handle, sockevent_t *se)
4003 {
4004         cs_socket_t *sp;
4005         client_t *client;
4006         int error;
4007         int client_lock_acquired;
4008 
4009         /*
4010          * Check to see if this is the Socket Services client handle; if it
4011          *      is, we don't do anything except for return success.
4012          */
4013         if (CLIENT_HANDLE_IS_SS(client_handle))
4014             return (CS_SUCCESS);
4015 
4016         /*
4017          * Get a pointer to this client's socket structure.
4018          */
4019         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4020             return (CS_BAD_SOCKET);
4021 
4022         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4023 
4024         /*
4025          *  Make sure that this is a valid client handle.
4026          */
4027         if (!(client = cs_find_client(client_handle, &error))) {
4028             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4029             return (error);
4030         }
4031 
4032         mutex_enter(&sp->lock);
4033 
4034 #ifdef  XXX
4035         /*
4036          * If there's no card in the socket or the card in the socket is not
4037          *      for this client, then return an error.
4038          */
4039         if (!(client->flags & CLIENT_CARD_INSERTED)) {
4040             mutex_exit(&sp->lock);
4041             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4042             return (CS_NO_CARD);
4043         }
4044 #endif
4045 
4046         /*
4047          * We are only allowed to set the client event mask if a
4048          *      RequestSocketMask has been called previously.  We
4049          *      are allowed to set the global event mask at any
4050          *      time.
4051          * The global event mask is initially set by the client
4052          *      in the call to RegisterClient.  The client event
4053          *      mask is set by the client in calls to SetEventMask
4054          *      and RequestSocketMask and gotten in calls to
4055          *      GetEventMask.
4056          */
4057         if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
4058             if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
4059                 mutex_exit(&sp->lock);
4060                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4061                 return (CS_BAD_SOCKET);
4062             }
4063             client->event_mask = se->EventMask;
4064         } else {
4065             client->global_mask = se->EventMask;
4066         }
4067 
4068         /*
4069          * Merge all the clients' event masks and set the socket
4070          *      to generate the appropriate events.
4071          */
4072         (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
4073 
4074         mutex_exit(&sp->lock);
4075         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4076 
4077         return (CS_SUCCESS);
4078 }
4079 
4080 /*
4081  * cs_read_event_status - handles PRR events and returns card status
4082  *
4083  *      calling: *sp - socket struct point
4084  *               *client - client to check events on
4085  *               *revent - pointer to event mask to update; if NULL, will
4086  *                              not be updated, if non-NULL, will be updated
4087  *                              with CS-format events; it is NOT necessary
4088  *                              to clear this value before calling this
4089  *                              function
4090  *               *gs - pointer to a get_ss_status_t used for the SS GetStatus
4091  *                              call; it is not necessary to initialize any
4092  *                              members in this structure; set to NULL if
4093  *                              not used
4094  *              flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
4095  *                              card present will not be done
4096  *
4097  *      returns: CS_SUCCESS
4098  *               CS_NO_CARD - if no card is in the socket and the flags arg
4099  *                              is not set to CS_RES_IGNORE_NO_CARD
4100  *               CS_BAD_SOCKET - if the SS_GetStatus function returned an
4101  *                                      error
4102  *
4103  *      Note that if the client that configured this socket has told us that
4104  *              the READY pin in the PRR isn't valid and the socket is in IO
4105  *              mode, we always return that the card is READY.
4106  *
4107  *      Note that if gs is not NULL, the current card state will be returned
4108  *              in the gs->CardState member; this will always reflect the
4109  *              current card state and the state will come from both the
4110  *              SS_GetStatus call and the PRR, whichever is appropriate for
4111  *              the mode that the socket is currently in.
4112  */
4113 static int
4114 cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent,
4115                                                 get_ss_status_t *gs, int flags)
4116 {
4117         cfg_regs_t prrd = 0;
4118 
4119         /*
4120          * SOCKET_IS_IO will only be set if a RequestConfiguration
4121          *      has been done by at least one client on this socket.
4122          * If there isn't a card in the socket or the caller wants to ignore
4123          *      whether the card is in the socket or not, get the current
4124          *      card status.
4125          */
4126         if ((sp->flags & SOCKET_CARD_INSERTED) ||
4127                                         (flags & CS_RES_IGNORE_NO_CARD)) {
4128             if (sp->flags & SOCKET_IS_IO) {
4129                 if (client->present & CONFIG_PINREPL_REG_PRESENT) {
4130                     acc_handle_t cis_handle;
4131                     uint32_t newoffset = client->config_regs_offset;
4132 
4133                         /*
4134                          * Get a handle to the CIS window
4135                          */
4136                     if (cs_init_cis_window(sp, &newoffset, &cis_handle,
4137                                         CISTPLF_AM_SPACE) != CS_SUCCESS) {
4138                         cmn_err(CE_CONT, "cs_read_event_status: socket %d "
4139                                             "can't init CIS window\n",
4140                                                         sp->socket_num);
4141                         return (CS_GENERAL_FAILURE);
4142                     } /* cs_init_cis_window */
4143 
4144                     prrd = csx_Get8(cis_handle, client->config_regs.prr_p);
4145                     prrd &= client->pin;
4146 
4147 #ifdef  CS_DEBUG
4148                     if (cs_debug > 1) {
4149                         cmn_err(CE_CONT, "cs_read_event_status: "
4150                                                 "prrd 0x%x client->pin 0x%x\n",
4151                                                                 (int)prrd,
4152                                                                 client->pin);
4153                         cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n",
4154                                                 ((prrd & PRR_WP_STATUS)?
4155                                                         "PRR_WP_STATUS ":""),
4156                                                 ((prrd & PRR_READY_STATUS)?
4157                                                         "PRR_READY_STATUS ":""),
4158                                                 ((prrd & PRR_BVD2_STATUS)?
4159                                                         "PRR_BVD2_STATUS ":""),
4160                                                 ((prrd & PRR_BVD1_STATUS)?
4161                                                         "PRR_BVD1_STATUS ":""),
4162                                                 ((prrd & PRR_WP_EVENT)?
4163                                                         "PRR_WP_EVENT ":""),
4164                                                 ((prrd & PRR_READY_EVENT)?
4165                                                         "PRR_READY_EVENT ":""),
4166                                                 ((prrd & PRR_BVD2_EVENT)?
4167                                                         "PRR_BVD2_EVENT ":""),
4168                                                 ((prrd & PRR_BVD1_EVENT)?
4169                                                         "PRR_BVD1_EVENT ":""));
4170                     }
4171 #endif
4172 
4173                         /*
4174                          * The caller wants the event changes sent back and
4175                          * the PRR event change bits cleared.
4176                          */
4177                     if (revent) {
4178                         get_socket_t get_socket;
4179                         set_socket_t set_socket;
4180 
4181                         /*
4182                          * Bug ID: 1193636 - Card Services sends bogus
4183                          *      events on CS_EVENT_STATUS_CHANGE events
4184                          * Clear this before we OR-in any values.
4185                          */
4186                         *revent = 0;
4187 
4188                         PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS,
4189                                         CS_EVENT_WRITE_PROTECT, *revent);
4190 
4191                         PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS,
4192                                         CS_EVENT_CARD_READY, *revent);
4193 
4194                         PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS,
4195                                         CS_EVENT_BATTERY_LOW, *revent);
4196 
4197                         PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS,
4198                                         CS_EVENT_BATTERY_DEAD, *revent);
4199 
4200 
4201 #ifdef  CS_DEBUG
4202                         if (cs_debug > 1) {
4203 
4204                             cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n",
4205                                                 ((prrd & PRR_WP_STATUS)?
4206                                                         "PRR_WP_STATUS ":""),
4207                                                 ((prrd & PRR_READY_STATUS)?
4208                                                         "PRR_READY_STATUS ":""),
4209                                                 ((prrd & PRR_BVD2_STATUS)?
4210                                                         "PRR_BVD2_STATUS ":""),
4211                                                 ((prrd & PRR_BVD1_STATUS)?
4212                                                         "PRR_BVD1_STATUS ":""),
4213                                                 ((prrd & PRR_WP_EVENT)?
4214                                                         "PRR_WP_EVENT ":""),
4215                                                 ((prrd & PRR_READY_EVENT)?
4216                                                         "PRR_READY_EVENT ":""),
4217                                                 ((prrd & PRR_BVD2_EVENT)?
4218                                                         "PRR_BVD2_EVENT ":""),
4219                                                 ((prrd & PRR_BVD1_EVENT)?
4220                                                         "PRR_BVD1_EVENT ":""));
4221                         }
4222 #endif
4223 
4224                         if (prrd)
4225                             csx_Put8(cis_handle, client->config_regs.prr_p,
4226                                 prrd);
4227 
4228                         /*
4229                          * We now have to reenable the status change interrupts
4230                          *      if there are any valid bits in the PRR. Since
4231                          *      the BVD1 signal becomes the STATUS_CHANGE
4232                          *      signal when the socket is in IO mode, we just
4233                          *      have to set the SBM_BVD1 enable bit in the
4234                          *      event mask.
4235                          */
4236                         if (client->pin) {
4237                             get_socket.socket = sp->socket_num;
4238                             SocketServices(SS_GetSocket, &get_socket);
4239                             set_socket.socket = sp->socket_num;
4240                             set_socket.SCIntMask =
4241                                         get_socket.SCIntMask | SBM_BVD1;
4242                             set_socket.VccLevel = get_socket.VccLevel;
4243                             set_socket.Vpp1Level = get_socket.Vpp1Level;
4244                             set_socket.Vpp2Level = get_socket.Vpp2Level;
4245                             set_socket.IREQRouting = get_socket.IRQRouting;
4246                             set_socket.IFType = get_socket.IFType;
4247                             set_socket.CtlInd = get_socket.CtlInd;
4248                             set_socket.State = get_socket.state;
4249                             SocketServices(SS_SetSocket, &set_socket);
4250                         } /* if (client->pin) */
4251                     } /* if (revent) */
4252 
4253                 } /* if (CONFIG_PINREPL_REG_PRESENT) */
4254             } /* if (SOCKET_IS_IO) */
4255 
4256         /*
4257          * The caller wants the current card state; we just read
4258          *      it and return a copy of it but do not clear any of
4259          *      the event changed bits (if we're reading the PRR).
4260          */
4261             if (gs) {
4262                 gs->socket = sp->socket_num;
4263                 gs->CardState = 0;
4264                 if (SocketServices(SS_GetStatus, gs) != SUCCESS)
4265                     return (CS_BAD_SOCKET);
4266                 if (sp->flags & SOCKET_IS_IO) {
4267                 /*
4268                  * If the socket is in IO mode, then clear the
4269                  *      gs->CardState bits that are now in the PRR
4270                  */
4271                     gs->CardState &= ~(SBM_WP | SBM_BVD1 |
4272                                                 SBM_BVD2 | SBM_RDYBSY);
4273 
4274                 /*
4275                  * Convert PRR status to SS_GetStatus status
4276                  */
4277                     if (prrd & PRR_WP_STATUS)
4278                         gs->CardState |= SBM_WP;
4279                     if (prrd & PRR_BVD2_STATUS)
4280                         gs->CardState |= SBM_BVD2;
4281                     if (prrd & PRR_BVD1_STATUS)
4282                         gs->CardState |= SBM_BVD1;
4283 
4284                 /*
4285                  * If the client has indicated that there is no
4286                  *      PRR or that the READY bit in the PRR isn't
4287                  *      valid, then we simulate the READY bit by
4288                  *      always returning READY.
4289                  */
4290                     if (!(client->present & CONFIG_PINREPL_REG_PRESENT) ||
4291                         ((client->present & CONFIG_PINREPL_REG_PRESENT) &&
4292                         !((client->pin &
4293                             (PRR_READY_STATUS | PRR_READY_EVENT)) ==
4294                                 (PRR_READY_STATUS | PRR_READY_EVENT))) ||
4295                                 (prrd & PRR_READY_STATUS))
4296                         gs->CardState |= SBM_RDYBSY;
4297 
4298 #ifdef  CS_DEBUG
4299                         if (cs_debug > 1) {
4300                             cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x "
4301                                 "client->pin 0x%x "
4302                                 "gs->CardState 0x%x\n",
4303                                 prrd, client->pin, gs->CardState);
4304                         }
4305 #endif
4306 
4307                 } /* if (SOCKET_IS_IO) */
4308             } /* if (gs) */
4309             return (CS_SUCCESS);
4310         } /* if (SOCKET_CARD_INSERTED) */
4311 
4312         return (CS_NO_CARD);
4313 }
4314 
4315 /*
4316  * cs_get_status - gets live card status and latched card status changes
4317  *                      supports the GetStatus CS call
4318  *
4319  *      returns: CS_SUCCESS
4320  *               CS_BAD_HANDLE if the passed client handle is invalid
4321  *
4322  *      Note: This function resets the latched status values maintained
4323  *              by Socket Services
4324  */
4325 static int
4326 cs_get_status(client_handle_t client_handle, get_status_t *gs)
4327 {
4328         cs_socket_t *sp;
4329         client_t *client;
4330         get_ss_status_t get_ss_status;
4331         get_socket_t get_socket;
4332         set_socket_t set_socket;
4333         int error;
4334         int client_lock_acquired;
4335 
4336         /*
4337          * Check to see if this is the Socket Services client handle; if it
4338          *      is, we don't do anything except for return success.
4339          */
4340         if (CLIENT_HANDLE_IS_SS(client_handle))
4341             return (CS_SUCCESS);
4342 
4343         /*
4344          * Get a pointer to this client's socket structure.
4345          */
4346         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4347             return (CS_BAD_SOCKET);
4348 
4349         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4350 
4351         /*
4352          *  Make sure that this is a valid client handle.
4353          */
4354         if (!(client = cs_find_client(client_handle, &error))) {
4355             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4356             return (error);
4357         }
4358 
4359         /*
4360          * Get the current card status as well as the latched card
4361          *      state.  Set the CS_RES_IGNORE_NO_CARD so that even
4362          *      if there is no card in the socket we'll still get
4363          *      a valid status.
4364          * Note that it is not necessary to initialize any values
4365          *      in the get_ss_status structure.
4366          */
4367         mutex_enter(&sp->cis_lock);
4368         if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status,
4369                                         CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
4370             mutex_exit(&sp->cis_lock);
4371             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4372             return (error);
4373         }
4374 
4375         mutex_exit(&sp->cis_lock);
4376 
4377         gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState);
4378 
4379         /*
4380          * Assign the "live" card state to the "real" card state. If there's
4381          *      no card in the socket or the card in the socket is not
4382          *      for this client, then we lie and tell the caller that the
4383          *      card is not inserted.
4384          */
4385         gs->CardState = gs->raw_CardState;
4386         if (!(client->flags & CLIENT_CARD_INSERTED))
4387             gs->CardState &= ~CS_EVENT_CARD_INSERTION;
4388 
4389         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4390 
4391         get_socket.socket = sp->socket_num;
4392         if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
4393             return (CS_BAD_SOCKET);
4394 
4395         gs->SocketState = cs_sbm2cse(get_socket.state);
4396 
4397         set_socket.socket = sp->socket_num;
4398         set_socket.SCIntMask = get_socket.SCIntMask;
4399         set_socket.VccLevel = get_socket.VccLevel;
4400         set_socket.Vpp1Level = get_socket.Vpp1Level;
4401         set_socket.Vpp2Level = get_socket.Vpp2Level;
4402         set_socket.IREQRouting = get_socket.IRQRouting;
4403         set_socket.IFType = get_socket.IFType;
4404         set_socket.CtlInd = get_socket.CtlInd;
4405         /* XXX (is ~0 correct here?) reset latched values */
4406         set_socket.State = (unsigned)~0;
4407 
4408         if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
4409             return (CS_BAD_SOCKET);
4410 
4411         return (CS_SUCCESS);
4412 }
4413 
4414 /*
4415  * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
4416  */
4417 static event_t
4418 cs_cse2sbm(event_t event_mask)
4419 {
4420         event_t sbm_event = 0;
4421 
4422         /*
4423          * XXX - we need to handle PM_CHANGE and RESET here as well
4424          */
4425         if (event_mask & CS_EVENT_WRITE_PROTECT)
4426             sbm_event |= SBM_WP;
4427         if (event_mask & CS_EVENT_BATTERY_DEAD)
4428             sbm_event |= SBM_BVD1;
4429         if (event_mask & CS_EVENT_BATTERY_LOW)
4430             sbm_event |= SBM_BVD2;
4431         if (event_mask & CS_EVENT_CARD_READY)
4432             sbm_event |= SBM_RDYBSY;
4433         if (event_mask & CS_EVENT_CARD_LOCK)
4434             sbm_event |= SBM_LOCKED;
4435         if (event_mask & CS_EVENT_EJECTION_REQUEST)
4436             sbm_event |= SBM_EJECT;
4437         if (event_mask & CS_EVENT_INSERTION_REQUEST)
4438             sbm_event |= SBM_INSERT;
4439         if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL))
4440             sbm_event |= SBM_CD;
4441 
4442         return (sbm_event);
4443 }
4444 
4445 /*
4446  * cs_sbm2cse - converts SBM_xxx state to CS event bits
4447  *
4448  * This function should never set any of the following bits:
4449  *
4450  *              CS_EVENT_MTD_REQUEST
4451  *              CS_EVENT_CLIENT_INFO
4452  *              CS_EVENT_TIMER_EXPIRED
4453  *              CS_EVENT_CARD_REMOVAL
4454  *              CS_EVENT_CARD_REMOVAL_LOWP
4455  *              CS_EVENT_ALL_CLIENTS
4456  *              CS_EVENT_READY_TIMEOUT
4457  *
4458  *      These bits are defined in the CS_STATUS_XXX series and are
4459  *      used by GetStatus.
4460  */
4461 static uint32_t
4462 cs_sbm2cse(uint32_t state)
4463 {
4464         uint32_t rstate = 0;
4465 
4466         /*
4467          * XXX - we need to handle PM_CHANGE and RESET here as well
4468          */
4469         if (state & SBM_WP)
4470             rstate |= CS_EVENT_WRITE_PROTECT;
4471         if (state & SBM_BVD1)
4472             rstate |= CS_EVENT_BATTERY_DEAD;
4473         if (state & SBM_BVD2)
4474             rstate |= CS_EVENT_BATTERY_LOW;
4475         if (state & SBM_RDYBSY)
4476             rstate |= CS_EVENT_CARD_READY;
4477         if (state & SBM_LOCKED)
4478             rstate |= CS_EVENT_CARD_LOCK;
4479         if (state & SBM_EJECT)
4480             rstate |= CS_EVENT_EJECTION_REQUEST;
4481         if (state & SBM_INSERT)
4482             rstate |= CS_EVENT_INSERTION_REQUEST;
4483         if (state & SBM_CD)
4484             rstate |= CS_EVENT_CARD_INSERTION;
4485 
4486         return (rstate);
4487 }
4488 
4489 /*
4490  * cs_merge_event_masks - merge the CS global socket event mask with the
4491  *                              passed client's event masks
4492  */
4493 static unsigned
4494 cs_merge_event_masks(cs_socket_t *sp, client_t *client)
4495 {
4496         unsigned SCIntMask;
4497         uint32_t event_mask;
4498 
4499         /*
4500          * We always want to see card detect and status change events.
4501          */
4502         SCIntMask = SBM_CD;
4503 
4504         event_mask = client->event_mask | client->global_mask |
4505                                                         sp->event_mask;
4506 
4507         if (!(sp->flags & SOCKET_IS_IO)) {
4508             SCIntMask |= cs_cse2sbm(event_mask);
4509         } else {
4510                 /*
4511                  * If the socket is in IO mode and there is a PRR present,
4512                  *      then we may need to enable PCE_CARD_STATUS_CHANGE
4513                  *      events.
4514                  */
4515             if (client->present & CONFIG_PINREPL_REG_PRESENT) {
4516 
4517                 SCIntMask |= (cs_cse2sbm(event_mask) &
4518                                 ~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY));
4519 
4520                 if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) ==
4521                                         (PRR_WP_STATUS | PRR_WP_EVENT))
4522                     if (event_mask & CS_EVENT_WRITE_PROTECT)
4523                         SCIntMask |= SBM_BVD1;
4524 
4525                 if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) ==
4526                                         (PRR_READY_STATUS | PRR_READY_EVENT))
4527                     if (event_mask & CS_EVENT_CARD_READY)
4528                             SCIntMask |= SBM_BVD1;
4529 
4530                 if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) ==
4531                                         (PRR_BVD2_STATUS | PRR_BVD2_EVENT))
4532                     if (event_mask & CS_EVENT_BATTERY_LOW)
4533                             SCIntMask |= SBM_BVD1;
4534 
4535                 if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) ==
4536                                         (PRR_BVD1_STATUS | PRR_BVD1_EVENT))
4537                     if (event_mask & CS_EVENT_BATTERY_DEAD)
4538                             SCIntMask |= SBM_BVD1;
4539 
4540             } /* if (CONFIG_PINREPL_REG_PRESENT) */
4541         } /* if (!SOCKET_IS_IO) */
4542 
4543         return (SCIntMask);
4544 }
4545 
4546 /*
4547  * cs_set_socket_event_mask - set the event mask for the socket
4548  */
4549 static int
4550 cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask)
4551 {
4552         get_socket_t get_socket;
4553         set_socket_t set_socket;
4554 
4555         get_socket.socket = sp->socket_num;
4556         if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
4557             return (CS_BAD_SOCKET);
4558 
4559         set_socket.socket = sp->socket_num;
4560         set_socket.SCIntMask = event_mask;
4561         set_socket.VccLevel = get_socket.VccLevel;
4562         set_socket.Vpp1Level = get_socket.Vpp1Level;
4563         set_socket.Vpp2Level = get_socket.Vpp2Level;
4564         set_socket.IREQRouting = get_socket.IRQRouting;
4565         set_socket.IFType = get_socket.IFType;
4566         set_socket.CtlInd = get_socket.CtlInd;
4567         /* XXX (is ~0 correct here?) reset latched values */
4568         set_socket.State = (unsigned)~0;
4569 
4570         if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
4571             return (CS_BAD_SOCKET);
4572 
4573         return (CS_SUCCESS);
4574 }
4575 
4576 /*
4577  * ==== MTD handling section ====
4578  */
4579 static int
4580 cs_deregister_mtd(client_handle_t client_handle)
4581 {
4582 
4583         cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n",
4584                                                         (int)client_handle);
4585 
4586         return (CS_SUCCESS);
4587 }
4588 
4589 /*
4590  * ==== memory window handling section ====
4591  */
4592 
4593 /*
4594  * cs_request_window  - searches through window list for the socket to find a
4595  *                      memory window that matches the requested criteria;
4596  *                      this is RequestWindow
4597  *
4598  * calling:  cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
4599  *
4600  *      On sucessful return, the window_handle_t * pointed to will
4601  *              contain a valid window handle for this window.
4602  *
4603  *      returns: CS_SUCCESS - if window found
4604  *               CS_OUT_OF_RESOURCE - if no windows match requirements
4605  *               CS_BAD_HANDLE - client handle is invalid
4606  *               CS_BAD_SIZE - if requested size can not be met
4607  *               CS_BAD_WINDOW - if an internal error occured
4608  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
4609  *               CS_NO_CARD - if no card is in socket
4610  *               CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
4611  *                                      flags are set
4612  */
4613 static int
4614 cs_request_window(client_handle_t client_handle,
4615                                 window_handle_t *wh,
4616                                 win_req_t *rw)
4617 {
4618         cs_socket_t *sp;
4619         cs_window_t *cw;
4620         client_t *client;
4621         modify_win_t mw;
4622         inquire_window_t iw;
4623         uint32_t aw;
4624         int error;
4625         int client_lock_acquired;
4626         uint32_t socket_num;
4627 
4628         /*
4629          * Check to see if this is the Socket Services client handle; if it
4630          *      is, we don't support SS using this call.
4631          */
4632         if (CLIENT_HANDLE_IS_SS(client_handle))
4633             return (CS_UNSUPPORTED_FUNCTION);
4634 
4635         /*
4636          * Make sure that none of the unsupported flags are set.
4637          */
4638         if (rw->Attributes &   (/* Compatability */
4639                                 WIN_PAGED |
4640                                 WIN_SHARED |
4641                                 WIN_FIRST_SHARED |
4642                                 WIN_BINDING_SPECIFIC |
4643                                 /* CS internal */
4644                                 WIN_DATA_WIDTH_VALID |
4645                                 /* IO window flags */
4646                                 WIN_MEMORY_TYPE_IO |
4647                                 /* CardBus flags */
4648                                 WIN_DATA_WIDTH_32 |
4649                                 WIN_PREFETCH_CACHE_MASK |
4650                                 WIN_BAR_MASK))
4651             return (CS_BAD_ATTRIBUTE);
4652 
4653         mutex_enter(&cs_globals.window_lock);
4654 
4655         /*
4656          * Get a pointer to this client's socket structure.
4657          */
4658         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4659             return (CS_BAD_SOCKET);
4660 
4661         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4662 
4663         /*
4664          *  Make sure that this is a valid client handle.
4665          */
4666         if (!(client = cs_find_client(client_handle, &error))) {
4667             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4668             mutex_exit(&cs_globals.window_lock);
4669             return (error);
4670         }
4671 
4672         mutex_enter(&sp->lock);
4673 
4674         /*
4675          * If there's no card in the socket or the card in the socket is not
4676          *      for this client, then return an error.
4677          */
4678         if (!(client->flags & CLIENT_CARD_INSERTED)) {
4679             mutex_exit(&sp->lock);
4680             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4681             mutex_exit(&cs_globals.window_lock);
4682             return (CS_NO_CARD);
4683         }
4684 
4685         mutex_exit(&sp->lock);
4686 
4687         socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
4688             GET_CLIENT_FUNCTION(client_handle));
4689 
4690 
4691         /*
4692          * See if we can find a window that matches the caller's criteria.
4693          *      If we can't, then thre's not much more that we can do except
4694          *      for return an error.
4695          */
4696         if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) !=
4697                                                                 CS_SUCCESS) {
4698             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4699             mutex_exit(&cs_globals.window_lock);
4700             return (error);
4701         }
4702 
4703         /*
4704          * We got a window, now synthesize a new window handle for this
4705          *      client and get a pointer to the global window structs
4706          *      and assign this window to this client.
4707          * We don't have to check for errors from cs_create_window_handle
4708          *      since that function always returns a valid window handle
4709          *      if it is given a valid window number.
4710          */
4711         *wh = cs_create_window_handle(aw);
4712         if ((cw = cs_get_wp(aw)) == NULL) {
4713             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4714             mutex_exit(&cs_globals.window_lock);
4715             return (CS_BAD_WINDOW);
4716         }
4717 
4718         cw->window_handle = *wh;
4719         cw->client_handle = client_handle;
4720         cw->socket_num = sp->socket_num;
4721         cw->state |= (CW_ALLOCATED | CW_MEM);
4722 
4723         mw.Attributes = (
4724                                 rw->Attributes |
4725                                 WIN_DATA_WIDTH_VALID |
4726                                 WIN_ACCESS_SPEED_VALID);
4727         mw.AccessSpeed = rw->win_params.AccessSpeed;
4728 
4729         if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) !=
4730             CS_SUCCESS) {
4731             cw->state = 0;
4732             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4733             mutex_exit(&cs_globals.window_lock);
4734             return (error);
4735         }
4736 
4737         /*
4738          * Get any required card offset and pass it back to the client.
4739          *      This is not defined in the current PCMCIA spec.  It is
4740          *      an aid to clients that want to use it to generate an
4741          *      optimum card offset.
4742          */
4743         iw.window = GET_WINDOW_NUMBER(*wh);
4744         SocketServices(SS_InquireWindow, &iw);
4745 
4746         if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
4747             rw->ReqOffset = rw->Size;
4748         else
4749             rw->ReqOffset = iw.mem_win_char.ReqOffset;
4750 
4751         /*
4752          * Increment the client's memory window count; this is how we know
4753          *      when a client has any allocated memory windows.
4754          */
4755         client->memwin_count++;
4756 
4757         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4758         mutex_exit(&cs_globals.window_lock);
4759 
4760         return (CS_SUCCESS);
4761 }
4762 
4763 /*
4764  * cs_release_window - deallocates the window associated with the passed
4765  *                      window handle; this is ReleaseWindow
4766  *
4767  *      returns: CS_SUCCESS if window handle is valid and window was
4768  *                      sucessfully deallocated
4769  *               CS_BAD_HANDLE if window handle is invalid or if window
4770  *                      handle is valid but window is not allocated
4771  */
4772 static int
4773 cs_release_window(window_handle_t wh)
4774 {
4775         cs_socket_t *sp;
4776         cs_window_t *cw;
4777         client_t *client;
4778         int error;
4779         int client_lock_acquired;
4780 
4781         mutex_enter(&cs_globals.window_lock);
4782 
4783         if (!(cw = cs_find_window(wh))) {
4784             mutex_exit(&cs_globals.window_lock);
4785             return (CS_BAD_HANDLE);
4786         }
4787 
4788         /*
4789          * Check to see if this is the Socket Services client handle; if it
4790          *      is, we don't support SS using this call.
4791          */
4792         if (CLIENT_HANDLE_IS_SS(cw->client_handle)) {
4793             mutex_exit(&cs_globals.window_lock);
4794             return (CS_UNSUPPORTED_FUNCTION);
4795         }
4796 
4797         /*
4798          * Get a pointer to this client's socket structure.
4799          */
4800         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
4801             return (CS_BAD_SOCKET);
4802 
4803         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4804 
4805         /*
4806          *  Make sure that this is a valid client handle.
4807          */
4808         if (!(client = cs_find_client(cw->client_handle, &error))) {
4809             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4810             mutex_exit(&cs_globals.window_lock);
4811             return (error);
4812         }
4813 
4814         /*
4815          * Mark this window as not in use anymore.
4816          */
4817         cw->state &= ~CW_WIN_IN_USE;
4818 
4819         /*
4820          * Decrement the client's memory window count; this is how we know
4821          *      when a client has any allocated memory windows.
4822          */
4823         if (!(--(client->memwin_count)))
4824             client->flags &= ~CLIENT_WIN_ALLOCATED;
4825 
4826         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4827         mutex_exit(&cs_globals.window_lock);
4828 
4829         return (CS_SUCCESS);
4830 }
4831 
4832 /*
4833  * cs_modify_window - modifies a window's characteristics; this is ModifyWindow
4834  */
4835 static int
4836 cs_modify_window(window_handle_t wh, modify_win_t *mw)
4837 {
4838         cs_socket_t *sp;
4839         cs_window_t *cw;
4840         client_t *client;
4841         int error;
4842         int client_lock_acquired;
4843 
4844         mutex_enter(&cs_globals.window_lock);
4845 
4846         /*
4847          * Do some sanity checking - make sure that we can find a pointer
4848          *      to the window structure, and if we can, get the client that
4849          *      has allocated that window.
4850          */
4851         if (!(cw = cs_find_window(wh))) {
4852             mutex_exit(&cs_globals.window_lock);
4853             return (CS_BAD_HANDLE);
4854         }
4855 
4856         /*
4857          * Get a pointer to this client's socket structure.
4858          */
4859         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
4860             return (CS_BAD_SOCKET);
4861 
4862         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4863 
4864         if (!(client = cs_find_client(cw->client_handle, &error))) {
4865             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4866             mutex_exit(&cs_globals.window_lock);
4867             return (error);
4868         }
4869 
4870         mutex_enter(&sp->lock);
4871 
4872         /*
4873          * If there's no card in the socket or the card in the socket is not
4874          *      for this client, then return an error.
4875          */
4876         if (!(client->flags & CLIENT_CARD_INSERTED)) {
4877             mutex_exit(&sp->lock);
4878             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4879             mutex_exit(&cs_globals.window_lock);
4880             return (CS_NO_CARD);
4881         }
4882 
4883         mutex_exit(&sp->lock);
4884 
4885         mw->Attributes &= (
4886                                 WIN_MEMORY_TYPE_MASK |
4887                                 WIN_ENABLE |
4888                                 WIN_ACCESS_SPEED_VALID |
4889                                 WIN_ACC_ENDIAN_MASK |
4890                                 WIN_ACC_ORDER_MASK);
4891 
4892         mw->Attributes &= ~WIN_DATA_WIDTH_VALID;
4893 
4894         if ((error = cs_modify_mem_window(wh, mw, NULL, NULL)) != CS_SUCCESS) {
4895             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4896             mutex_exit(&cs_globals.window_lock);
4897             return (error);
4898         }
4899 
4900         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4901         mutex_exit(&cs_globals.window_lock);
4902 
4903         return (CS_SUCCESS);
4904 }
4905 
4906 /*
4907  * cs_modify_mem_window - modifies a window's characteristics; used internally
4908  *                              by Card Services
4909  *
4910  *    If *wr is NULL, it means that we're being called by ModifyWindow
4911  *    If *wr is non-NULL, it means that we are being called by RequestWindow
4912  *      and so we can't use SS_GetWindow.
4913  */
4914 static int
4915 cs_modify_mem_window(window_handle_t wh, modify_win_t *mw,
4916                                                 win_req_t *wr, int sn)
4917 {
4918         get_window_t gw;
4919         set_window_t sw;
4920         set_page_t set_page;
4921         get_page_t get_page;
4922 
4923         /*
4924          * If the win_req_t struct pointer is NULL, it means that
4925          *      we're being called by ModifyWindow, so get the
4926          *      current window characteristics.
4927          */
4928         if (!wr) {
4929             gw.window = GET_WINDOW_NUMBER(wh);
4930             if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
4931                 return (CS_BAD_WINDOW);
4932             sw.state = gw.state;
4933             sw.socket = gw.socket;
4934             sw.WindowSize = gw.size;
4935         } else {
4936             sw.state = 0;
4937             sw.socket = sn;
4938             sw.WindowSize = wr->Size;
4939         }
4940 
4941         /*
4942          * If we're being called by RequestWindow, we must always have
4943          *      WIN_ACCESS_SPEED_VALID set since get_window_t is not
4944          *      defined.
4945          */
4946         if (mw->Attributes & WIN_ACCESS_SPEED_VALID) {
4947             convert_speed_t convert_speed;
4948 
4949             convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS;
4950             convert_speed.devspeed = mw->AccessSpeed;
4951 
4952             if (cs_convert_speed(&convert_speed) != CS_SUCCESS)
4953                 return (CS_BAD_SPEED);
4954 
4955             sw.speed = convert_speed.nS;
4956         } else {
4957             sw.speed = gw.speed;
4958         }
4959 
4960         if (!wr) {
4961             get_page.window = GET_WINDOW_NUMBER(wh);
4962             get_page.page = 0;
4963             if (SocketServices(SS_GetPage, &get_page) != SUCCESS)
4964                 return (CS_BAD_WINDOW);
4965             set_page.state = get_page.state;
4966             set_page.offset = get_page.offset;
4967         } else {
4968             set_page.state = 0;
4969             set_page.offset = 0;
4970         }
4971 
4972         if (mw->Attributes & WIN_ENABLE) {
4973             sw.state |= WS_ENABLED;
4974             set_page.state |= PS_ENABLED;
4975         } else {
4976             sw.state &= ~WS_ENABLED;
4977             set_page.state &= ~PS_ENABLED;
4978         }
4979 
4980         if (mw->Attributes & WIN_DATA_WIDTH_VALID) {
4981             if (mw->Attributes & WIN_DATA_WIDTH_16)
4982                 sw.state |= WS_16BIT;
4983             else
4984                 sw.state &= ~WS_16BIT;
4985         }
4986 
4987         sw.window = GET_WINDOW_NUMBER(wh);
4988         sw.base = 0;
4989 
4990         cs_set_acc_attributes(&sw, mw->Attributes);
4991 
4992         if (SocketServices(SS_SetWindow, &sw) != SUCCESS)
4993             return (CS_BAD_WINDOW);
4994 
4995         if (mw->Attributes & WIN_MEMORY_TYPE_AM)
4996             set_page.state |= PS_ATTRIBUTE;
4997         else
4998             set_page.state &= ~PS_ATTRIBUTE;
4999 
5000         set_page.window = GET_WINDOW_NUMBER(wh);
5001         set_page.page = 0;
5002         if (SocketServices(SS_SetPage, &set_page) != SUCCESS)
5003             return (CS_BAD_OFFSET);
5004 
5005         /*
5006          * Return the current base address of this window
5007          */
5008         if (wr) {
5009             gw.window = GET_WINDOW_NUMBER(wh);
5010             if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
5011                 return (CS_BAD_WINDOW);
5012 
5013             wr->Base.handle = (acc_handle_t)gw.handle;
5014         }
5015 
5016         return (CS_SUCCESS);
5017 }
5018 
5019 /*
5020  * cs_map_mem_page - sets the card offset of the mapped window
5021  */
5022 static int
5023 cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp)
5024 {
5025         cs_socket_t *sp;
5026         cs_window_t *cw;
5027         client_t *client;
5028         inquire_window_t iw;
5029         get_window_t gw;
5030         set_page_t set_page;
5031         get_page_t get_page;
5032         int error;
5033         uint32_t size;
5034         int client_lock_acquired;
5035 
5036         /*
5037          * We don't support paged windows, so never allow a page number
5038          *      of other than 0
5039          */
5040         if (mmp->Page)
5041             return (CS_BAD_PAGE);
5042 
5043         mutex_enter(&cs_globals.window_lock);
5044 
5045         /*
5046          * Do some sanity checking - make sure that we can find a pointer
5047          *      to the window structure, and if we can, get the client that
5048          *      has allocated that window.
5049          */
5050         if (!(cw = cs_find_window(wh))) {
5051             mutex_exit(&cs_globals.window_lock);
5052             return (CS_BAD_HANDLE);
5053         }
5054 
5055         /*
5056          * Get a pointer to this client's socket structure.
5057          */
5058         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
5059             return (CS_BAD_SOCKET);
5060 
5061         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5062 
5063         if (!(client = cs_find_client(cw->client_handle, &error))) {
5064             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5065             mutex_exit(&cs_globals.window_lock);
5066             return (error);
5067         }
5068 
5069         mutex_enter(&sp->lock);
5070 
5071         /*
5072          * If there's no card in the socket or the card in the socket is not
5073          *      for this client, then return an error.
5074          */
5075         if (!(client->flags & CLIENT_CARD_INSERTED)) {
5076             mutex_exit(&sp->lock);
5077             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5078             mutex_exit(&cs_globals.window_lock);
5079             return (CS_NO_CARD);
5080         }
5081 
5082         mutex_exit(&sp->lock);
5083 
5084         gw.window = GET_WINDOW_NUMBER(wh);
5085         SocketServices(SS_GetWindow, &gw);
5086 
5087         iw.window = GET_WINDOW_NUMBER(wh);
5088         SocketServices(SS_InquireWindow, &iw);
5089 
5090         if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
5091             size = gw.size;
5092         else
5093             size = iw.mem_win_char.ReqOffset;
5094 
5095         if (((mmp->CardOffset/size)*size) != mmp->CardOffset) {
5096             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5097             mutex_exit(&cs_globals.window_lock);
5098             return (CS_BAD_OFFSET);
5099         }
5100 
5101         get_page.window = GET_WINDOW_NUMBER(wh);
5102         get_page.page = 0;
5103         SocketServices(SS_GetPage, &get_page);
5104 
5105         set_page.window = GET_WINDOW_NUMBER(wh);
5106         set_page.page = 0;
5107         set_page.state = get_page.state;
5108         set_page.offset = mmp->CardOffset;
5109         if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
5110             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5111             mutex_exit(&cs_globals.window_lock);
5112             return (CS_BAD_OFFSET);
5113         }
5114 
5115         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5116         mutex_exit(&cs_globals.window_lock);
5117 
5118         return (CS_SUCCESS);
5119 }
5120 
5121 /*
5122  * cs_find_window - finds the window associated with the passed window
5123  *                      handle; if the window handle is invalid or no
5124  *                      windows match the passed window handle, NULL
5125  *                      is returned.  Note that the window must be
5126  *                      allocated for this function to return a valid
5127  *                      window pointer.
5128  *
5129  *      returns: cs_window_t * pointer to the found window
5130  *               NULL if window handle invalid or window not allocated
5131  */
5132 cs_window_t *
5133 cs_find_window(window_handle_t wh)
5134 {
5135         cs_window_t *cw;
5136 
5137         if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) ||
5138                         (GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC))
5139             return ((cs_window_t *)NULL);
5140 
5141         if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL)
5142             return (NULL);
5143 
5144         if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM))
5145             return (cw);
5146 
5147         return ((cs_window_t *)NULL);
5148 }
5149 
5150 /*
5151  * cs_create_window_handle - creates a unique window handle based on the
5152  *                              passed window number.
5153  */
5154 static window_handle_t
5155 cs_create_window_handle(uint32_t aw)
5156 {
5157         return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK));
5158 }
5159 
5160 /*
5161  * cs_find_mem_window - tries to find a memory window matching the caller's
5162  *                      criteria
5163  *
5164  *      We return the first window that matches the requested criteria.
5165  *
5166  *      returns: CS_SUCCESS - if memory window found
5167  *               CS_OUT_OF_RESOURCE - if no windows match requirements
5168  *               CS_BAD_SIZE - if requested size can not be met
5169  *               CS_BAD_WINDOW - if an internal error occured
5170  */
5171 /* BEGIN CSTYLED */
5172 static int
5173 cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window)
5174 {
5175         uint32_t wn;
5176         int error = CS_OUT_OF_RESOURCE;
5177         uint32_t window_num = PCMCIA_MAX_WINDOWS;
5178         uint32_t min_size = UINT_MAX;
5179         inquire_window_t inquire_window, *iw;
5180         uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps;
5181         uint32_t tws;
5182 
5183         iw = &inquire_window;
5184 
5185         for (wn = 0; wn < cs_globals.num_windows; wn++) {
5186             cs_window_t *cw;
5187 
5188             /*
5189              * If we can't get a pointer to this window, we should contine
5190              *  with scanning the next window, since this window might have
5191              *  been dropped.
5192              */
5193             if ((cw = cs_get_wp(wn)) != NULL) {
5194               iw->window = wn;
5195 
5196               if (SocketServices(SS_InquireWindow, iw) != SUCCESS)
5197                 return (CS_BAD_WINDOW);
5198 
5199               MinSize = iw->mem_win_char.MinSize;
5200               MaxSize = iw->mem_win_char.MaxSize;
5201               ReqGran = iw->mem_win_char.ReqGran;
5202               MemWndCaps = iw->mem_win_char.MemWndCaps;
5203               WndCaps = iw->WndCaps;
5204 
5205               if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
5206                                         WINDOW_AVAILABLE_FOR_MEM(cw) &&
5207                                         WndCaps & (WC_COMMON|WC_ATTRIBUTE)) {
5208                 if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) ==
5209                                         CS_SUCCESS) {
5210                     error = CS_OUT_OF_RESOURCE;
5211                     if (cs_memwin_space_and_map_ok(iw, rw)) {
5212                         error = CS_BAD_SIZE;
5213                         if (!rw->Size) {
5214                             min_size = min(min_size, MinSize);
5215                             window_num = wn;
5216                             goto found_window;
5217                         } else {
5218                             if (!(MemWndCaps & WC_SIZE)) {
5219                                 if (rw->Size == MinSize) {
5220                                     min_size = MinSize;
5221                                     window_num = wn;
5222                                     goto found_window;
5223                                 }
5224                             } else { /* WC_SIZE */
5225                               if (!ReqGran) {
5226                                 error = CS_BAD_WINDOW;
5227                               } else {
5228                                 if ((rw->Size >= MinSize) &&
5229                                                         (rw->Size <= MaxSize)) {
5230                                     if (MemWndCaps & WC_POW2) {
5231                                       unsigned rg = ReqGran;
5232                                         for (tws = MinSize; tws <= MaxSize;
5233                                                                 rg = (rg<<1)) {
5234                                             if (rw->Size == tws) {
5235                                                 min_size = tws;
5236                                                 window_num = wn;
5237                                                 goto found_window;
5238                                             }
5239                                             tws += rg;
5240                                           } /* for (tws) */
5241                                     } else {
5242                                         for (tws = MinSize; tws <= MaxSize;
5243                                                         tws += ReqGran) {
5244                                             if (rw->Size == tws) {
5245                                                 min_size = tws;
5246                                                 window_num = wn;
5247                                                 goto found_window;
5248                                             }
5249                                           } /* for (tws) */
5250                                     } /* if (!WC_POW2) */
5251                                 } /* if (Size >= MinSize) */
5252                               } /* if (!ReqGran) */
5253                             } /* if (WC_SIZE) */
5254                         } /* if (rw->Size) */
5255                     } /* if (cs_space_and_map_ok) */
5256                 } /* if (cs_valid_window_speed) */
5257               } /* if (WINDOW_FOR_SOCKET) */
5258             } /* if (cs_get_wp) */
5259         } /* for (wn) */
5260 
5261         /*
5262          * If we got here and the window_num wasn't set by any window
5263          *       matches in the above code, it means that we didn't
5264          *      find a window matching the caller's criteria.
5265          * If the error is CS_BAD_TYPE, it means that the last reason
5266          *      that we couldn't match a window was because the caller's
5267          *      requested speed was out of range of the last window that
5268          *      we checked.  We convert this error code to CS_OUT_OF_RESOURCE
5269          *      to conform to the RequestWindow section of the PCMCIA
5270          *      Card Services spec.
5271          */
5272         if (window_num == PCMCIA_MAX_WINDOWS) {
5273             if (error == CS_BAD_TYPE)
5274                 error = CS_OUT_OF_RESOURCE;
5275             return (error);
5276         }
5277 
5278 found_window:
5279         rw->Size = min_size;
5280         *assigned_window = window_num;
5281         iw->window = window_num;
5282         SocketServices(SS_InquireWindow, iw);
5283         MemWndCaps = iw->mem_win_char.MemWndCaps;
5284 
5285         if (MemWndCaps & WC_CALIGN)
5286             rw->Attributes |= WIN_OFFSET_SIZE;
5287         else
5288             rw->Attributes &= ~WIN_OFFSET_SIZE;
5289         return (CS_SUCCESS);
5290 }
5291 /* END CSTYLED */
5292 
5293 /*
5294  * cs_memwin_space_and_map_ok - checks to see if the passed window mapping
5295  *                              capabilities and window speeds are in the
5296  *                              range of the passed window.
5297  *
5298  *      returns: 0 - if the capabilities are out of range
5299  *               1 - if the capabilities are in range
5300  */
5301 static int
5302 cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw)
5303 {
5304 
5305 #ifdef  CS_DEBUG
5306         if (cs_debug > 240)
5307             printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
5308                                         "WndCaps 0x%x MemWndCaps 0x%x\n",
5309                                         (int)rw->Attributes,
5310                                         (int)rw->win_params.AccessSpeed,
5311                                         iw->WndCaps,
5312                                         iw->mem_win_char.MemWndCaps);
5313 #endif
5314 
5315         if (rw->win_params.AccessSpeed & WIN_USE_WAIT) {
5316             if (!(iw->WndCaps & WC_WAIT))
5317                 return (0);
5318         }
5319 
5320         if (rw->Attributes & WIN_DATA_WIDTH_16) {
5321             if (!(iw->mem_win_char.MemWndCaps & WC_16BIT))
5322                 return (0);
5323         } else {
5324             if (!(iw->mem_win_char.MemWndCaps & WC_8BIT))
5325                 return (0);
5326         }
5327 
5328         if (rw->Attributes & WIN_MEMORY_TYPE_AM) {
5329             if (!(iw->WndCaps & WC_ATTRIBUTE))
5330                 return (0);
5331         }
5332 
5333         if (rw->Attributes & WIN_MEMORY_TYPE_CM) {
5334             if (!(iw->WndCaps & WC_COMMON))
5335                 return (0);
5336         }
5337 
5338         return (1);
5339 }
5340 
5341 /*
5342  * cs_valid_window_speed - checks to see if requested window speed
5343  *                              is in range of passed window
5344  *
5345  *      The inquire_window_t struct gives us speeds in nS, and we
5346  *      get speeds in the AccessSpeed variable as a devspeed code.
5347  *
5348  *      returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
5349  *               CS_BAD_TYPE -  if AccessSpeed is not in range of valid
5350  *                              speed for this window
5351  *               CS_SUCCESS -   if window speed is in range
5352  */
5353 static int
5354 cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed)
5355 {
5356         convert_speed_t convert_speed, *cs;
5357 
5358         cs = &convert_speed;
5359 
5360         cs->Attributes = CONVERT_DEVSPEED_TO_NS;
5361         cs->devspeed = AccessSpeed;
5362 
5363         if (cs_convert_speed(cs) != CS_SUCCESS)
5364             return (CS_BAD_SPEED);
5365 
5366         if ((cs->nS < iw->mem_win_char.Fastest) ||
5367                 (cs->nS > iw->mem_win_char.Slowest))
5368             return (CS_BAD_TYPE);
5369 
5370         return (CS_SUCCESS);
5371 }
5372 
5373 /*
5374  * ==== IO window handling section ====
5375  */
5376 
5377 /*
5378  * cs_request_io - provides IO resources for clients; this is RequestIO
5379  *
5380  *      calling: cs_request_io(client_handle_t, io_req_t *)
5381  *
5382  *      returns: CS_SUCCESS - if IO resources available for client
5383  *               CS_OUT_OF_RESOURCE - if no windows match requirements
5384  *               CS_BAD_HANDLE - client handle is invalid
5385  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
5386  *               CS_NO_CARD - if no card is in socket
5387  *               CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
5388  *                                      flags are set
5389  *               CS_BAD_BASE - if either or both base port addresses
5390  *                                      are invalid or out of range
5391  *               CS_CONFIGURATION_LOCKED - a RequestConfiguration has
5392  *                                      already been done
5393  *               CS_IN_USE - IO ports already in use or function has
5394  *                                      already been called
5395  *               CS_BAD_WINDOW - if failure while trying to set window
5396  *                                      characteristics
5397  */
5398 static int
5399 cs_request_io(client_handle_t client_handle, io_req_t *ior)
5400 {
5401         cs_socket_t *sp;
5402         client_t *client;
5403         int error;
5404         int client_lock_acquired;
5405         uint32_t socket_num;
5406 
5407         /*
5408          * Check to see if this is the Socket Services client handle; if it
5409          *      is, we don't support SS using this call.
5410          */
5411         if (CLIENT_HANDLE_IS_SS(client_handle))
5412             return (CS_UNSUPPORTED_FUNCTION);
5413 
5414         /*
5415          * If the client has only requested one IO range, then make sure
5416          *      that the Attributes2 filed is clear.
5417          */
5418         if (!ior->NumPorts2)
5419             ior->Attributes2 = 0;
5420 
5421         /*
5422          * Make sure that none of the unsupported or reserved flags are set.
5423          */
5424         if ((ior->Attributes1 | ior->Attributes2) &    (IO_SHARED |
5425                                                         IO_FIRST_SHARED |
5426                                                         IO_FORCE_ALIAS_ACCESS |
5427                                                         IO_DEALLOCATE_WINDOW |
5428                                                         IO_DISABLE_WINDOW))
5429             return (CS_BAD_ATTRIBUTE);
5430 
5431         /*
5432          * Make sure that we have a port count for the first region.
5433          */
5434         if (!ior->NumPorts1)
5435             return (CS_BAD_BASE);
5436 
5437         /*
5438          * If we're being asked for multiple IO ranges, then both base port
5439          *      members must be non-zero.
5440          */
5441         if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base))
5442             return (CS_BAD_BASE);
5443 
5444         mutex_enter(&cs_globals.window_lock);
5445 
5446         /*
5447          * Get a pointer to this client's socket structure.
5448          */
5449         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
5450             return (CS_BAD_SOCKET);
5451 
5452         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5453 
5454         /*
5455          *  Make sure that this is a valid client handle.
5456          */
5457         if (!(client = cs_find_client(client_handle, &error))) {
5458             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5459             mutex_exit(&cs_globals.window_lock);
5460             return (error);
5461         }
5462 
5463         /*
5464          * If RequestConfiguration has already been done, we don't allow
5465          *      this call.
5466          */
5467         if (client->flags & REQ_CONFIGURATION_DONE) {
5468             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5469             mutex_exit(&cs_globals.window_lock);
5470             return (CS_CONFIGURATION_LOCKED);
5471         }
5472 
5473         /*
5474          * If RequestIO has already been done, we don't allow this call.
5475          */
5476         if (client->flags & REQ_IO_DONE) {
5477             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5478             mutex_exit(&cs_globals.window_lock);
5479             return (CS_IN_USE);
5480         }
5481 
5482         mutex_enter(&sp->lock);
5483 
5484         /*
5485          * If there's no card in the socket or the card in the socket is not
5486          *      for this client, then return an error.
5487          */
5488         if (!(client->flags & CLIENT_CARD_INSERTED)) {
5489             mutex_exit(&sp->lock);
5490             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5491             mutex_exit(&cs_globals.window_lock);
5492             return (CS_NO_CARD);
5493         }
5494 
5495         mutex_exit(&sp->lock);
5496 
5497         /*
5498          * If we're only being asked for one IO range, then set BasePort2 to
5499          *      zero, since we use it later on.
5500          */
5501         if (!ior->NumPorts2)
5502             ior->BasePort2.base = 0;
5503 
5504         /*
5505          * See if we can allow Card Services to select the base address
5506          *      value for this card; if the client has specified a non-zero
5507          *      base IO address but the card doesn't decode enough IO
5508          *      address lines to uniquely use that address, then we have
5509          *      the flexibility to choose an alternative base address.
5510          * Note that if the client specifies that the card decodes zero
5511          *      IO address lines, then we have to use the NumPortsX
5512          *      values to figure out how many address lines the card
5513          *      actually decodes, and we have to round the NumPortsX
5514          *      values up to the closest power of two.
5515          */
5516         if (ior->IOAddrLines) {
5517             ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base,
5518                 ior->IOAddrLines);
5519             ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base,
5520                 ior->IOAddrLines);
5521         } else {
5522             ior->BasePort1.base = ior->BasePort1.base &
5523                                 ((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
5524                                 IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
5525             ior->BasePort2.base = ior->BasePort2.base &
5526                                 ((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
5527                                 IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
5528         }
5529 
5530         socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
5531             GET_CLIENT_FUNCTION(client_handle));
5532 
5533 
5534 #ifdef  USE_IOMMAP_WINDOW
5535         /*
5536          * Here is where the code diverges, depending on the type of IO windows
5537          *      that this socket supports.  If this socket supportes memory
5538          *      mapped IO windows, as determined by cs_init allocating an
5539          *      io_mmap_window_t structure on the socket structure, then we
5540          *      use one IO window for all the clients on this socket.  We can
5541          *      do this safely since a memory mapped IO window implies that
5542          *      only this socket shares the complete IO space of the card.
5543          * See the next major block of code for a description of what we do
5544          *      if a socket doesn't support memory mapped IO windows.
5545          */
5546         if (sp->io_mmap_window) {
5547             cs_window_t *cw;
5548             io_mmap_window_t *imw = sp->io_mmap_window;
5549             uint32_t offset;
5550 
5551                 /*
5552                  * If we haven't allocated an IO window yet, do it now.
5553                  * Try to allocate the IO window that cs_init found for us;
5554                  * if that fails, then call cs_find_io_win to find a window.
5555                  */
5556             if (!imw->count) {
5557                 set_window_t set_window;
5558 
5559                 if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) {
5560                     iowin_char_t iowin_char;
5561 
5562                     iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW |
5563                                             WC_8BIT |
5564                                             WC_16BIT);
5565                     if ((error = cs_find_io_win(sp->socket_num, &iowin_char,
5566                                     &imw->number, &imw->size)) != CS_SUCCESS) {
5567                         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5568                         mutex_exit(&cs_globals.window_lock);
5569                     } /* cs_find_io_win */
5570                 } /* if (!WINDOW_AVAILABLE_FOR_IO) */
5571 
5572                 set_window.socket = socket_num;
5573                 set_window.window = imw->number;
5574                 set_window.speed = IO_WIN_SPEED;
5575                 set_window.base.base = 0;
5576                 set_window.WindowSize = imw->size;
5577                 set_window.state = (WS_ENABLED | WS_16BIT |
5578                                     WS_EXACT_MAPIN | WS_IO);
5579 
5580                 /* XXX - what to d here? XXX */
5581                 cs_set_acc_attributes(&set_window, Attributes);
5582 
5583                 if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) {
5584                     (void) cs_setup_io_win(socket_num, imw->number,
5585                                                 NULL, NULL, NULL,
5586                                                 (IO_DEALLOCATE_WINDOW |
5587                                                 IO_DISABLE_WINDOW));
5588                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5589                     mutex_exit(&cs_globals.window_lock);
5590                     return (CS_BAD_WINDOW);
5591                 }
5592 
5593                 imw->handle = set_window.base.handle;
5594                 imw->size = set_window.WindowSize;
5595 
5596                 /*
5597                  * Check the caller's port requirements to be sure that they
5598                  *      fit within our found IO window.
5599                  */
5600                 if ((ior->BasePort1.base + ior->NumPorts1 +
5601                         ior->BasePort2.base + ior->NumPorts2) > imw->size) {
5602                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5603                     mutex_exit(&cs_globals.window_lock);
5604                     return (CS_BAD_BASE);
5605                 }
5606 
5607                 if ((cw = cs_get_wp(imw->number)) == NULL) {
5608                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5609                     mutex_exit(&cs_globals.window_lock);
5610                     return (CS_BAD_WINDOW)
5611                 }
5612                 cw->state |= (CW_ALLOCATED | CW_IO);
5613 
5614             } /* if (!imw->count) */
5615 
5616             imw->count++;
5617 
5618                 /*
5619                  * All common access handles for this type of adapter are
5620                  * duped.  We never give the original back to the caller.
5621                  */
5622             /* XXX need to set endianess and data ordering flags */
5623             csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0);
5624             csx_GetHandleOffset(ior->BasePort1.handle, &offset);
5625             csx_SetHandleOffset(ior->BasePort1.handle,
5626                 ior->BasePort1.base + offset);
5627 
5628             if (ior->NumPorts2) {
5629                 /* XXX need to set endianess and data ordering flags */
5630                 csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0);
5631                 csx_GetHandleOffset(ior->BasePort2.handle, &offset);
5632                 csx_SetHandleOffset(ior->BasePort2.handle,
5633                     ior->BasePort1.base + offset);
5634             }
5635 
5636                 /*
5637                  * We don't really use these two values if we've got a memory
5638                  * mapped IO window since the assigned window number is stored
5639                  * in imw->number.
5640                  */
5641             client->io_alloc.Window1 = imw->number;
5642             client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
5643 
5644         /*
5645          * This socket supports only IO port IO windows.
5646          */
5647         } else {
5648 #else   /* USE_IOMMAP_WINDOW */
5649         {
5650 #endif  /* USE_IOMMAP_WINDOW */
5651             baseaddru_t baseaddru;
5652 
5653             baseaddru.base = ior->BasePort1.base;
5654 
5655             if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1,
5656                 &client->io_alloc.Window1)) != CS_SUCCESS) {
5657 
5658                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5659                 mutex_exit(&cs_globals.window_lock);
5660                 return (error);
5661             } /* if (cs_allocate_io_win(1)) */
5662 
5663                 /*
5664                  * Setup the window hardware; if this fails, then we need to
5665                  *      deallocate the previously allocated window.
5666                  */
5667             if ((error = cs_setup_io_win(socket_num,
5668                                                 client->io_alloc.Window1,
5669                                                 &baseaddru,
5670                                                 &ior->NumPorts1,
5671                                                 ior->IOAddrLines,
5672                                                 ior->Attributes1)) !=
5673                                                                 CS_SUCCESS) {
5674                 (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5675                                         NULL, NULL, NULL,
5676                                         (
5677                                                 IO_DEALLOCATE_WINDOW |
5678                                                 IO_DISABLE_WINDOW));
5679 
5680                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5681                 mutex_exit(&cs_globals.window_lock);
5682                 return (error);
5683             } /* if (cs_setup_io_win(1)) */
5684 
5685             ior->BasePort1.handle = (acc_handle_t)baseaddru.handle;
5686             ior->BasePort1.base = baseaddru.base;
5687 
5688                 /*
5689                  * See if the client wants two IO ranges.
5690                  */
5691             if (ior->NumPorts2) {
5692                 baseaddru_t baseaddru;
5693 
5694                 baseaddru.base = ior->BasePort2.base;
5695 
5696                 /*
5697                  * If we fail to allocate this window, then we must deallocate
5698                  *      the previous IO window that is already allocated.
5699                  */
5700                 if ((error = cs_allocate_io_win(sp->socket_num,
5701                                                 ior->Attributes2,
5702                                                 &client->io_alloc.Window2)) !=
5703                                                                 CS_SUCCESS) {
5704                     (void) cs_setup_io_win(socket_num,
5705                                                 client->io_alloc.Window2,
5706                                                 NULL, NULL, NULL,
5707                                                 (
5708                                                         IO_DEALLOCATE_WINDOW |
5709                                                         IO_DISABLE_WINDOW));
5710                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5711                     mutex_exit(&cs_globals.window_lock);
5712                     return (error);
5713                 } /* if (cs_allocate_io_win(2)) */
5714                 /*
5715                  * Setup the window hardware; if this fails, then we need to
5716                  *      deallocate the previously allocated window.
5717                  */
5718                 if ((error = cs_setup_io_win(socket_num,
5719                                                 client->io_alloc.Window2,
5720                                                 &baseaddru,
5721                                                 &ior->NumPorts2,
5722                                                 ior->IOAddrLines,
5723                                                 ior->Attributes2)) !=
5724                                                                 CS_SUCCESS) {
5725                     (void) cs_setup_io_win(socket_num,
5726                                                 client->io_alloc.Window1,
5727                                                 NULL, NULL, NULL,
5728                                                 (
5729                                                         IO_DEALLOCATE_WINDOW |
5730                                                         IO_DISABLE_WINDOW));
5731                     (void) cs_setup_io_win(socket_num,
5732                                                 client->io_alloc.Window2,
5733                                                 NULL, NULL, NULL,
5734                                                 (
5735                                                         IO_DEALLOCATE_WINDOW |
5736                                                         IO_DISABLE_WINDOW));
5737                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5738                     mutex_exit(&cs_globals.window_lock);
5739                     return (error);
5740                 } /* if (cs_setup_io_win(2)) */
5741 
5742                 ior->BasePort2.handle = (acc_handle_t)baseaddru.handle;
5743                 ior->BasePort2.base = baseaddru.base;
5744 
5745             } else {
5746                 client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
5747             } /* if (ior->NumPorts2) */
5748         } /* if (sp->io_mmap_window) */
5749 
5750         /*
5751          * Save a copy of the client's port information so that we
5752          *      can use it in the RequestConfiguration call.  We set
5753          *      the IO window number(s) allocated in the respective
5754          *      section of code, above.
5755          */
5756         client->io_alloc.BasePort1.base = ior->BasePort1.base;
5757         client->io_alloc.BasePort1.handle = ior->BasePort1.handle;
5758         client->io_alloc.NumPorts1 = ior->NumPorts1;
5759         client->io_alloc.Attributes1 = ior->Attributes1;
5760         client->io_alloc.BasePort2.base = ior->BasePort2.base;
5761         client->io_alloc.BasePort2.handle = ior->BasePort2.handle;
5762         client->io_alloc.NumPorts2 = ior->NumPorts2;
5763         client->io_alloc.Attributes2 = ior->Attributes2;
5764         client->io_alloc.IOAddrLines = ior->IOAddrLines;
5765 
5766         /*
5767          * Mark this client as having done a successful RequestIO call.
5768          */
5769         client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED);
5770 
5771         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5772         mutex_exit(&cs_globals.window_lock);
5773 
5774         return (CS_SUCCESS);
5775 }
5776 
5777 /*
5778  * cs_release_io - releases IO resources allocated by RequestIO; this is
5779  *                      ReleaseIO
5780  *
5781  *      calling: cs_release_io(client_handle_t, io_req_t *)
5782  *
5783  *      returns: CS_SUCCESS - if IO resources sucessfully deallocated
5784  *               CS_BAD_HANDLE - client handle is invalid
5785  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
5786  *               CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
5787  *                              done without a ReleaseConfiguration
5788  *               CS_IN_USE - no RequestIO has been done
5789  */
5790 static int
5791 cs_release_io(client_handle_t client_handle, io_req_t *ior)
5792 {
5793         cs_socket_t *sp;
5794         client_t *client;
5795         int error;
5796         int client_lock_acquired;
5797         uint32_t socket_num;
5798 
5799 #ifdef  lint
5800         ior = NULL;
5801 #endif
5802 
5803         /*
5804          * Check to see if this is the Socket Services client handle; if it
5805          *      is, we don't support SS using this call.
5806          */
5807         if (CLIENT_HANDLE_IS_SS(client_handle))
5808             return (CS_UNSUPPORTED_FUNCTION);
5809 
5810         mutex_enter(&cs_globals.window_lock);
5811 
5812         /*
5813          * Get a pointer to this client's socket structure.
5814          */
5815         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
5816             return (CS_BAD_SOCKET);
5817 
5818         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5819 
5820         /*
5821          *  Make sure that this is a valid client handle.
5822          */
5823         if (!(client = cs_find_client(client_handle, &error))) {
5824             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5825             mutex_exit(&cs_globals.window_lock);
5826             return (error);
5827         }
5828 
5829         /*
5830          * If RequestConfiguration has already been done, we don't allow
5831          *      this call.
5832          */
5833         if (client->flags & REQ_CONFIGURATION_DONE) {
5834             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5835             mutex_exit(&cs_globals.window_lock);
5836             return (CS_CONFIGURATION_LOCKED);
5837         }
5838 
5839         /*
5840          * If RequestIO has not been done, we don't allow this call.
5841          */
5842         if (!(client->flags & REQ_IO_DONE)) {
5843             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5844             mutex_exit(&cs_globals.window_lock);
5845             return (CS_IN_USE);
5846         }
5847 
5848         socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
5849             GET_CLIENT_FUNCTION(client_handle));
5850 
5851 #ifdef  XXX
5852         /*
5853          * Check the passed IO allocation with the stored allocation; if
5854          *      they don't match, then return an error.
5855          */
5856         if ((client->io_alloc.BasePort1 != ior->BasePort1) ||
5857             (client->io_alloc.NumPorts1 != ior->NumPorts1) ||
5858             (client->io_alloc.Attributes1 != ior->Attributes1) ||
5859             (client->io_alloc.BasePort2 != ior->BasePort2) ||
5860             (client->io_alloc.NumPorts2 != ior->NumPorts2) ||
5861             (client->io_alloc.Attributes2 != ior->Attributes2) ||
5862             (client->io_alloc.IOAddrLines != ior->IOAddrLines)) {
5863                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5864                 mutex_exit(&cs_globals.window_lock);
5865                 return (CS_BAD_ARGS);
5866         }
5867 #endif
5868 
5869 #ifdef  USE_IOMMAP_WINDOW
5870         /*
5871          * The code diverges here depending on if this socket supports
5872          *      memory mapped IO windows or not.  See comments in the
5873          *      cs_request_io function for a description of what's
5874          *      going on here.
5875          */
5876         if (sp->io_mmap_window) {
5877             io_mmap_window_t *imw = sp->io_mmap_window;
5878 
5879                 /*
5880                  * We should never see this; if we do, it's an internal
5881                  *      consistency error.
5882                  */
5883             if (!imw->count) {
5884                 cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n",
5885                                                             sp->socket_num);
5886                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5887                 mutex_exit(&cs_globals.window_lock);
5888                 return (CS_GENERAL_FAILURE);
5889             }
5890 
5891                 /*
5892                  * All common access handles for this type of adapter are
5893                  *      duped. We never give the original back to the caller,
5894                  *      so it's OK to unconditionally free the handle here.
5895                  */
5896             csx_FreeHandle(&ior->BasePort1.handle);
5897 
5898                 /*
5899                  * If the IO window referance count is zero, then deallocate
5900                  * and disable this window.
5901                  */
5902             if (!--(imw->count)) {
5903                 (void) cs_setup_io_win(socket_num, imw->number, NULL,
5904                                                                 NULL, NULL,
5905                                                 (
5906                                                         IO_DEALLOCATE_WINDOW |
5907                                                         IO_DISABLE_WINDOW));
5908             } /* if (imw->count) */
5909         } else {
5910 #endif  /* USE_IOMMAP_WINDOW */
5911             (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5912                                                 NULL, NULL, NULL,
5913                                                 (
5914                                                         IO_DEALLOCATE_WINDOW |
5915                                                         IO_DISABLE_WINDOW));
5916             if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS)
5917                 (void) cs_setup_io_win(socket_num, client->io_alloc.Window2,
5918                                                 NULL, NULL, NULL,
5919                                                 (
5920                                                         IO_DEALLOCATE_WINDOW |
5921                                                         IO_DISABLE_WINDOW));
5922 #ifdef  USE_IOMMAP_WINDOW
5923         } /* if (sp->io_mmap_window) */
5924 #endif  /* USE_IOMMAP_WINDOW */
5925 
5926         /*
5927          * Mark the client as not having any IO resources allocated.
5928          */
5929         client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED);
5930 
5931         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5932         mutex_exit(&cs_globals.window_lock);
5933         return (CS_SUCCESS);
5934 }
5935 
5936 /*
5937  * cs_find_io_win - finds an IO window that matches the parameters specified
5938  *                      in the flags argument
5939  *
5940  *      calling: sn - socket number to look for IO window on
5941  *               *iwc - other window characteristics to match
5942  *               *assigned_window - pointer to where we return the assigned
5943  *                                      window number if we found a window or
5944  *                                      undefined otherwise
5945  *               *size - if non-NULL, the found window size will be stored here
5946  *
5947  *      returns: CS_SUCCESS - if IO window found
5948  *               CS_OUT_OF_RESOURCE - if no windows match requirements
5949  */
5950 static int
5951 cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window,
5952     uint32_t *size)
5953 {
5954         inquire_window_t inquire_window, *iw;
5955         unsigned wn;
5956 
5957         iw = &inquire_window;
5958 
5959         for (wn = 0; wn < cs_globals.num_windows; wn++) {
5960             iowin_char_t *iowc;
5961             cs_window_t *cw;
5962 
5963             if ((cw = cs_get_wp(wn)) != NULL) {
5964 
5965                 iw->window = wn;
5966                 SocketServices(SS_InquireWindow, iw);
5967 
5968                 iowc = &iw->iowin_char;
5969 
5970                 if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
5971                     WINDOW_AVAILABLE_FOR_IO(cw) &&
5972                     (iw->WndCaps & WC_IO) &&
5973                     ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) {
5974 
5975                         *assigned_window = wn;
5976 
5977                         if (size)
5978                             *size = iw->iowin_char.ReqGran;
5979                         return (CS_SUCCESS);
5980                     } /* if (WINDOW_FOR_SOCKET) */
5981             } /* cs_get_wp */
5982         } /* for (wn) */
5983 
5984         return (CS_OUT_OF_RESOURCE);
5985 }
5986 
5987 /*
5988  * cs_allocate_io_win - finds and allocates an IO window
5989  *
5990  *      calling: sn - socket number to look for window on
5991  *               Attributes - window attributes in io_req_t.Attributes format
5992  *               *assigned_window - pointer to return assigned window number
5993  *
5994  *      returns: CS_SUCCESS - IO window found and allocated
5995  *               CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
5996  *                              window that matches the passed criteria
5997  *
5998  * Note: This fucntion will find and allocate an IO window.  The caller is
5999  *      responsible for deallocating the window.
6000  */
6001 static int
6002 cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window)
6003 {
6004         iowin_char_t iowin_char;
6005         cs_window_t *cw;
6006 
6007         iowin_char.IOWndCaps =
6008                 ((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT);
6009 
6010         if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) ==
6011                                                                 CS_SUCCESS) {
6012             if ((cw = cs_get_wp(*assigned_window)) == NULL)
6013                 return (CS_OUT_OF_RESOURCE);
6014 
6015             cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO);
6016             return (CS_SUCCESS);
6017         }
6018 
6019         return (CS_OUT_OF_RESOURCE);
6020 }
6021 
6022 /*
6023  * cs_setup_io_win - setup and destroy an IO window
6024  *
6025  *      calling: sn - socket number
6026  *               wn - window number
6027  * XXX Base - pointer to XXX
6028  *               *NumPorts - pointer to number of allocated ports to return
6029  *               IOAddrLines - number of IO address lines decoded by this card
6030  *               Attributes - either io_req_t attributes, or a combination of
6031  *                              the following flags:
6032  *                                  IO_DEALLOCATE_WINDOW - deallocate the window
6033  *                                  IO_DISABLE_WINDOW - disable the window
6034  *                              When either of these two flags are set, *Base
6035  *                                  and NumPorts should be NULL.
6036  *
6037  *      returns: CS_SUCCESS - if no failure
6038  *               CS_BAD_WINDOW - if error while trying to configure window
6039  *
6040  * Note: We use the IOAddrLines value to determine what base address to pass
6041  *              to Socket Services.
6042  */
6043 static int
6044 cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts,
6045     uint32_t IOAddrLines, uint32_t Attributes)
6046 {
6047         set_window_t set_window;
6048 
6049         if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) {
6050 
6051             if (Attributes & IO_DEALLOCATE_WINDOW) {
6052                 cs_window_t *cw;
6053 
6054                 if ((cw = cs_get_wp(wn)) == NULL)
6055                     return (CS_BAD_WINDOW);
6056                 cw->state &= CW_WINDOW_VALID;
6057 
6058             } /* IO_DEALLOCATE_WINDOW */
6059 
6060             if (Attributes & IO_DISABLE_WINDOW) {
6061                 get_window_t get_window;
6062 
6063                 get_window.window = wn;
6064 
6065                 SocketServices(SS_GetWindow, &get_window);
6066 
6067                 set_window.socket = get_window.socket;
6068                 set_window.window = get_window.window;
6069                 set_window.speed = get_window.speed;
6070                 set_window.base = 0;
6071                 set_window.WindowSize = get_window.size;
6072                 set_window.state = get_window.state & ~WS_ENABLED;
6073 
6074                 cs_set_acc_attributes(&set_window, Attributes);
6075 
6076                 SocketServices(SS_SetWindow, &set_window);
6077             } /* IO_DISABLE_WINDOW */
6078 
6079             return (CS_SUCCESS);
6080 
6081         } /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
6082 
6083         /*
6084          * See if we can allow Socket Services to select the base address
6085          *      value for this card; if the client has specified a non-zero
6086          *      base IO address but the card doesn't decode enough IO
6087          *      address lines to uniquely use that address, then we have
6088          *      the flexibility to choose an alternative base address.
6089          * XXX - Is this really correct in all cases?
6090          */
6091         if (!IOAddrLines)
6092             Base->base = 0;
6093         else
6094             Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines);
6095 
6096         set_window.socket = sn;
6097         set_window.window = wn;
6098         set_window.speed = IO_WIN_SPEED;
6099         set_window.base = Base->base;
6100         set_window.WindowSize = *NumPorts;
6101         set_window.state = (WS_ENABLED | WS_IO |
6102                         ((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0));
6103 
6104         cs_set_acc_attributes(&set_window, Attributes);
6105 
6106         if (SocketServices(SS_SetWindow, &set_window) != SUCCESS)
6107             return (CS_BAD_WINDOW);
6108 
6109         Base->base = set_window.base;
6110         Base->handle = set_window.handle;
6111         *NumPorts = set_window.WindowSize;
6112 
6113         return (CS_SUCCESS);
6114 }
6115 
6116 /*
6117  * ==== IRQ handling functions ====
6118  */
6119 
6120 /*
6121  * cs_request_irq - add's client's IRQ handler; supports RequestIRQ
6122  *
6123  *      calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
6124  *                      flag set, and all other flags clear, or
6125  *                      CS_BAD_ATTRIBUTE will be returned
6126  *
6127  *      returns: CS_SUCCESS - if IRQ resources available for client
6128  *               CS_BAD_IRQ - if IRQ can not be allocated
6129  *               CS_BAD_HANDLE - client handle is invalid
6130  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6131  *               CS_NO_CARD - if no card is in socket
6132  *               CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
6133  *                                      flags are set
6134  *               CS_CONFIGURATION_LOCKED - a RequestConfiguration has
6135  *                                      already been done
6136  *               CS_IN_USE - IRQ ports already in use or function has
6137  *                                      already been called
6138  *
6139  * Note: We only allow level-mode interrupts.
6140  */
6141 static int
6142 cs_request_irq(client_handle_t client_handle, irq_req_t *irqr)
6143 {
6144         cs_socket_t *sp;
6145         client_t *client;
6146         set_irq_handler_t set_irq_handler;
6147         int error;
6148         int client_lock_acquired;
6149 
6150         /*
6151          * Check to see if this is the Socket Services client handle; if it
6152          *      is, we don't support SS using this call.
6153          */
6154         if (CLIENT_HANDLE_IS_SS(client_handle))
6155             return (CS_UNSUPPORTED_FUNCTION);
6156 
6157         /*
6158          * Make sure that none of the unsupported or reserved flags are set.
6159          */
6160         if ((irqr->Attributes &  (IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING |
6161                                 IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED |
6162                                 IRQ_FORCED_PULSE)) ||
6163                 !(irqr->Attributes & IRQ_TYPE_EXCLUSIVE))
6164             return (CS_BAD_ATTRIBUTE);
6165 
6166         /*
6167          * Get a pointer to this client's socket structure.
6168          */
6169         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6170             return (CS_BAD_SOCKET);
6171 
6172         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6173 
6174         /*
6175          *  Make sure that this is a valid client handle.
6176          */
6177         if (!(client = cs_find_client(client_handle, &error))) {
6178             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6179             return (error);
6180         }
6181 
6182         /*
6183          * If RequestConfiguration has already been done, we don't allow
6184          *      this call.
6185          */
6186         if (client->flags & REQ_CONFIGURATION_DONE) {
6187             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6188             return (CS_CONFIGURATION_LOCKED);
6189         }
6190 
6191         /*
6192          * If RequestIRQ has already been done, we don't allow this call.
6193          */
6194         if (client->flags & REQ_IRQ_DONE) {
6195             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6196             return (CS_IN_USE);
6197         }
6198 
6199         /*
6200          * If there's no card in the socket or the card in the socket is not
6201          *      for this client, then return an error.
6202          */
6203         if (!(client->flags & CLIENT_CARD_INSERTED)) {
6204             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6205             return (CS_NO_CARD);
6206         }
6207 
6208         /*
6209          * Set up the parameters and ask Socket Services to give us an IRQ
6210          *      for this client.  We don't really do much, since the IRQ
6211          *      resources are managed by SS and the kernel.  We also don't
6212          *      care which IRQ level we are given.
6213          */
6214         set_irq_handler.socket =
6215                 CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
6216                                         GET_CLIENT_FUNCTION(client_handle));
6217         set_irq_handler.irq = IRQ_ANY;
6218 
6219         set_irq_handler.handler_id = client_handle;
6220         set_irq_handler.handler = (f_t *)irqr->irq_handler;
6221         set_irq_handler.arg1 = irqr->irq_handler_arg;
6222         set_irq_handler.arg2 = NULL;
6223 
6224         if ((error = SocketServices(SS_SetIRQHandler,
6225                                         &set_irq_handler)) != SUCCESS) {
6226             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6227             return (CS_BAD_IRQ);
6228         }
6229 
6230         irqr->iblk_cookie = set_irq_handler.iblk_cookie;
6231         irqr->idev_cookie = set_irq_handler.idev_cookie;
6232 
6233         /*
6234          * Save the allocated IRQ information for this client.
6235          */
6236         client->irq_alloc.Attributes = irqr->Attributes;
6237         client->irq_alloc.irq = set_irq_handler.irq;
6238         client->irq_alloc.handler_id = set_irq_handler.handler_id;
6239         client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler;
6240         client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1;
6241         client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2;
6242 
6243 #ifdef  CS_DEBUG
6244         if (cs_debug > 0)
6245             cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x "
6246                                                 "set_irq_handler.irq 0x%x\n",
6247                                                 sp->socket_num,
6248                                                 (int)irqr->Attributes,
6249                                                 set_irq_handler.irq);
6250 #endif
6251 
6252         /*
6253          * Mark this client as having done a successful RequestIRQ call.
6254          */
6255         client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
6256 
6257         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6258         return (CS_SUCCESS);
6259 }
6260 
6261 /*
6262  * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
6263  *                      ReleaseIRQ
6264  *
6265  *      calling: cs_release_irq(client_handle_t, irq_req_t *)
6266  *
6267  *      returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
6268  *               CS_BAD_IRQ - if IRQ can not be deallocated
6269  *               CS_BAD_HANDLE - client handle is invalid
6270  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6271  *               CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
6272  *                              done without a ReleaseConfiguration
6273  *               CS_IN_USE - no RequestIRQ has been done
6274  */
6275 static int
6276 cs_release_irq(client_handle_t client_handle, irq_req_t *irqr)
6277 {
6278         cs_socket_t *sp;
6279         client_t *client;
6280         clear_irq_handler_t clear_irq_handler;
6281         int error;
6282         int client_lock_acquired;
6283 
6284 #ifdef  lint
6285         irqr = NULL;
6286 #endif
6287 
6288         /*
6289          * Check to see if this is the Socket Services client handle; if it
6290          *      is, we don't support SS using this call.
6291          */
6292         if (CLIENT_HANDLE_IS_SS(client_handle))
6293             return (CS_UNSUPPORTED_FUNCTION);
6294 
6295         /*
6296          * Get a pointer to this client's socket structure.
6297          */
6298         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6299             return (CS_BAD_SOCKET);
6300 
6301         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6302 
6303         /*
6304          *  Make sure that this is a valid client handle.
6305          */
6306         if (!(client = cs_find_client(client_handle, &error))) {
6307             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6308             return (error);
6309         }
6310 
6311         /*
6312          * If RequestConfiguration has already been done, we don't allow
6313          *      this call.
6314          */
6315         if (client->flags & REQ_CONFIGURATION_DONE) {
6316             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6317             return (CS_CONFIGURATION_LOCKED);
6318         }
6319 
6320         /*
6321          * If RequestIRQ has not been done, we don't allow this call.
6322          */
6323         if (!(client->flags & REQ_IRQ_DONE)) {
6324             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6325             return (CS_IN_USE);
6326         }
6327 
6328         /*
6329          * Tell Socket Services that we want to deregister this client's
6330          *      IRQ handler.
6331          */
6332         clear_irq_handler.socket =
6333                 CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
6334                                 GET_CLIENT_FUNCTION(client_handle));
6335         clear_irq_handler.handler_id = client->irq_alloc.handler_id;
6336         clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler;
6337 
6338         /*
6339          * At this point, we should never fail this SS call; if we do, it
6340          *      means that there is an internal consistancy error in either
6341          *      Card Services or Socket Services.
6342          */
6343         if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) !=
6344                                                                 SUCCESS) {
6345             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6346             return (CS_BAD_IRQ);
6347         }
6348 
6349         /*
6350          * Mark the client as not having any IRQ resources allocated.
6351          */
6352         client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
6353 
6354         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6355         return (CS_SUCCESS);
6356 }
6357 
6358 /*
6359  * ==== configuration handling functions ====
6360  */
6361 
6362 /*
6363  * cs_request_configuration - sets up socket and card configuration on behalf
6364  *              of the client; this is RequestConfiguration
6365  *
6366  *      returns: CS_SUCCESS - if configuration sucessfully set
6367  *               CS_BAD_SOCKET - if Socket Services returns an error
6368  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6369  *               CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
6370  *                                      are set
6371  *               CS_BAD_TYPE - if the socket doesn't support a mem and IO
6372  *                              interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
6373  *               CS_CONFIGURATION_LOCKED - a RequestConfiguration has
6374  *                                      already been done
6375  *               CS_BAD_VCC - if Vcc value is not supported by socket
6376  *               CS_BAD_VPP1 - if Vpp1 value is not supported by socket
6377  *               CS_BAD_VPP2 - if Vpp2 value is not supported by socket
6378  *
6379  * Bug ID: 1193637 - Card Services RequestConfiguration does not conform
6380  *      to PCMCIA standard
6381  * We allow clients to do a RequestConfiguration even if they haven't
6382  *      done a RequestIO or RequestIRQ.
6383  */
6384 static int
6385 cs_request_configuration(client_handle_t client_handle, config_req_t *cr)
6386 {
6387         cs_socket_t *sp;
6388         client_t *client;
6389         volatile config_regs_t *crt;
6390         set_socket_t set_socket;
6391         get_socket_t get_socket;
6392         acc_handle_t cis_handle;
6393         int error;
6394         uint32_t newoffset;
6395         int client_lock_acquired;
6396 
6397         /*
6398          * Check to see if this is the Socket Services client handle; if it
6399          *      is, we don't support SS using this call.
6400          */
6401         if (CLIENT_HANDLE_IS_SS(client_handle))
6402             return (CS_UNSUPPORTED_FUNCTION);
6403 
6404 #ifdef  XXX
6405         /*
6406          * If the client specifies Vcc = 0 and any non-zero value for
6407          *      either of the Vpp members, that's an illegal condition.
6408          */
6409         if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2))
6410             return (CS_BAD_VCC);
6411 #endif
6412 
6413         /*
6414          * Get a pointer to this client's socket structure.
6415          */
6416         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6417             return (CS_BAD_SOCKET);
6418 
6419         /*
6420          * If the client is asking for a memory and IO interface on this
6421          *      socket, then check the socket capabilities to be sure that
6422          *      this socket supports this configuration.
6423          */
6424         if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) {
6425             inquire_socket_t inquire_socket;
6426 
6427             inquire_socket.socket = sp->socket_num;
6428 
6429             if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS)
6430                 return (CS_BAD_SOCKET);
6431 
6432             if (!(inquire_socket.SocketCaps & IF_IO))
6433                 return (CS_BAD_TYPE);
6434 
6435         } /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
6436 
6437         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6438 
6439         /*
6440          *  Make sure that this is a valid client handle.
6441          */
6442         if (!(client = cs_find_client(client_handle, &error))) {
6443             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6444             return (error);
6445         }
6446 
6447         /*
6448          * If RequestConfiguration has already been done, we don't allow
6449          *      this call.
6450          */
6451         if (client->flags & REQ_CONFIGURATION_DONE) {
6452             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6453             return (CS_CONFIGURATION_LOCKED);
6454         }
6455 
6456         /*
6457          * If there's no card in the socket or the card in the socket is not
6458          *      for this client, then return an error.
6459          */
6460         if (!(client->flags & CLIENT_CARD_INSERTED)) {
6461             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6462             return (CS_NO_CARD);
6463         }
6464 
6465         /*
6466          * At this point, most of the client's calling parameters have been
6467          *      validated, so we can go ahead and configure the socket and
6468          *      the card.
6469          */
6470         mutex_enter(&sp->cis_lock);
6471 
6472         /*
6473          * Configure the socket with the interface type and voltages requested
6474          *      by the client.
6475          */
6476         get_socket.socket = sp->socket_num;
6477 
6478         if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
6479             mutex_exit(&sp->cis_lock);
6480             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6481             return (CS_BAD_SOCKET);
6482         }
6483 
6484 #ifdef  CS_DEBUG
6485         if (cs_debug > 0)
6486             cmn_err(CE_CONT, "cs_request_configuration: socket %d "
6487                                         "client->irq_alloc.irq 0x%x "
6488                                         "get_socket.IRQRouting 0x%x\n",
6489                                                 sp->socket_num,
6490                                                 (int)client->irq_alloc.irq,
6491                                                 get_socket.IRQRouting);
6492 #endif
6493 
6494         bzero(&set_socket, sizeof (set_socket));
6495         set_socket.socket = sp->socket_num;
6496         set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE;
6497 
6498         set_socket.CtlInd = get_socket.CtlInd;
6499         set_socket.State = 0;   /* don't reset latched values */
6500 
6501         if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC,
6502                                         &set_socket.VccLevel) != CS_SUCCESS) {
6503             mutex_exit(&sp->cis_lock);
6504             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6505             return (CS_BAD_VCC);
6506         }
6507 
6508         if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1,
6509                                         &set_socket.Vpp1Level) != CS_SUCCESS) {
6510             mutex_exit(&sp->cis_lock);
6511             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6512             return (CS_BAD_VPP);
6513         }
6514 
6515         if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2,
6516                                         &set_socket.Vpp2Level) != CS_SUCCESS) {
6517             mutex_exit(&sp->cis_lock);
6518             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6519             return (CS_BAD_VPP);
6520         }
6521 
6522         if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO))
6523                 set_socket.IFType = IF_MEMORY;
6524         else {
6525                 set_socket.IFType = IF_IO;
6526 
6527                 /*
6528                  * The Cirrus Logic PD6710/672X/others? adapters will write
6529                  * protect the CIS if the socket is in MEMORY mode and the
6530                  * WP/IOCS16 pin is true.  When this happens, the CIS registers
6531                  * will fail to be written.  Go ahead and set the socket,
6532                  * even though the event mask isn't complete yet, so we can
6533                  * configure the adapter.  Afterwards, set the socket again
6534                  * to make sure the event mask is correct.
6535                  */
6536                 if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6537                         sp->flags &= ~SOCKET_IS_IO;
6538                         mutex_exit(&sp->cis_lock);
6539                         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6540                         return (CS_BAD_SOCKET);
6541                 }
6542         }
6543 
6544         if (cs_rc2_delay)
6545             drv_usecwait(cs_rc2_delay * 1000);
6546 
6547         /*
6548          * Get a pointer to a window that contains the configuration
6549          *      registers.
6550          */
6551         mutex_enter(&sp->lock);
6552         client->config_regs_offset = cr->ConfigBase;
6553         newoffset = client->config_regs_offset;
6554         mutex_exit(&sp->lock);
6555         if (cs_init_cis_window(sp, &newoffset, &cis_handle,
6556                                         CISTPLF_AM_SPACE) != CS_SUCCESS) {
6557             mutex_exit(&sp->cis_lock);
6558             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6559             cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init "
6560                                 "CIS window\n", sp->socket_num);
6561             return (CS_GENERAL_FAILURE);
6562         }
6563 
6564         /*
6565          * Setup the config register pointers.
6566          * Note that these pointers are not the complete virtual address;
6567          *      the complete address is constructed each time the registers
6568          *      are accessed.
6569          */
6570         mutex_enter(&sp->lock);
6571         crt = &client->config_regs;
6572         client->present = cr->Present;
6573 
6574         bzero((char *)crt, sizeof (config_regs_t));
6575 
6576         /* Configuration Option Register */
6577         if (client->present & CONFIG_OPTION_REG_PRESENT)
6578             crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET);
6579 
6580         /* Configuration and Status Register */
6581         if (client->present & CONFIG_STATUS_REG_PRESENT)
6582             crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET);
6583 
6584         /* Pin Replacement Register */
6585         if (client->present & CONFIG_PINREPL_REG_PRESENT)
6586             crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET);
6587 
6588         /* Socket and Copy Register */
6589         if (client->present & CONFIG_COPY_REG_PRESENT)
6590             crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET);
6591 
6592         /* Extended Status Register */
6593         if (client->present & CONFIG_EXSTAT_REG_PRESENT)
6594             crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET);
6595 
6596         /* IO Base 0 Register */
6597         if (client->present & CONFIG_IOBASE0_REG_PRESENT)
6598             crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET);
6599 
6600         /* IO Base 1 Register */
6601         if (client->present & CONFIG_IOBASE1_REG_PRESENT)
6602             crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET);
6603 
6604         /* IO Base 2 Register */
6605         if (client->present & CONFIG_IOBASE2_REG_PRESENT)
6606             crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET);
6607 
6608         /* IO Base 3 Register */
6609         if (client->present & CONFIG_IOBASE3_REG_PRESENT)
6610             crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET);
6611 
6612         /* IO Limit Register */
6613         if (client->present & CONFIG_IOLIMIT_REG_PRESENT)
6614             crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET);
6615 
6616         /*
6617          * Setup the bits in the PRR mask that are valid; this is easy, just
6618          *      copy the Pin value that the client gave us.  Note that for
6619          *      this to work, the client must set both of the XXX_STATUS
6620          *      and the XXX_EVENT bits in the Pin member.
6621          */
6622         client->pin = cr->Pin;
6623 
6624 #ifdef  CS_DEBUG
6625         if (cs_debug > 128)
6626             cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x "
6627                 "client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
6628                 "ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
6629                 client->pin, (int)client->config_regs_offset, newoffset,
6630                 (int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p,
6631                 (int)crt->scr_p);
6632 #endif
6633 
6634         /*
6635          * If the socket isn't in IO mode, WP is asserted,  and we're going to
6636          * write any of the config registers, issue a warning.
6637          */
6638         if ((client->present != 0) &&
6639             (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) &&
6640             (get_socket.state & SBM_WP)) {
6641                 cmn_err(CE_NOTE, "!cs_request_configuration: attempting to "
6642                     "write CIS config regs with WP set\n");
6643         }
6644 
6645         /*
6646          * Write any configuration registers that the client tells us are
6647          *      present to the card; save a copy of what we wrote so that we
6648          *      can return them if the client calls GetConfigurationInfo.
6649          * The order in which we write the configuration registers is
6650          *      specified by the PCMCIA spec; we must write the socket/copy
6651          *      register first (if it exists), and then we can write the
6652          *      registers in any arbitrary order.
6653          */
6654         /* Socket and Copy Register */
6655         if (client->present & CONFIG_COPY_REG_PRESENT) {
6656             crt->scr = cr->Copy;
6657             csx_Put8(cis_handle, crt->scr_p, crt->scr);
6658         }
6659 
6660         /* Pin Replacement Register */
6661         if (client->present & CONFIG_PINREPL_REG_PRESENT) {
6662             crt->prr = cr->Pin;
6663             csx_Put8(cis_handle, crt->prr_p, crt->prr);
6664         }
6665 
6666         /* Configuration and Status Register */
6667         /* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
6668         if (client->present & CONFIG_STATUS_REG_PRESENT) {
6669             crt->ccsr = cr->Status;
6670             csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr);
6671         }
6672 
6673         /* Extended Status Register */
6674         if (client->present & CONFIG_EXSTAT_REG_PRESENT) {
6675             crt->exstat = cr->ExtendedStatus;
6676             csx_Put8(cis_handle, crt->exstat_p, crt->exstat);
6677         }
6678 
6679         /*
6680          * If any IO base and limit registers exist, and this client
6681          *      has done a RequestIO, setup the IO Base and IO Limit
6682          *      registers.
6683          */
6684         if (client->flags & REQ_IO_DONE) {
6685             if (client->present & CONFIG_IOBASE0_REG_PRESENT) {
6686                 uint32_t base = client->io_alloc.BasePort1.base;
6687                 uint32_t present = (client->present &
6688                                         CONFIG_IOBASE_REG_MASK) >>
6689                                                 CONFIG_IOBASE_REG_SHIFT;
6690                 uint32_t reg = crt->iobase0_p;
6691 
6692                 do {
6693                     csx_Put8(cis_handle, reg, base & 0x0ff);
6694                     reg = reg + 2;
6695                     base = base >> 8;
6696                     present = present >> 1;
6697                 } while (present);
6698             } /* CONFIG_IOBASE0_REG_PRESENT */
6699 
6700             if (client->present & CONFIG_IOLIMIT_REG_PRESENT) {
6701                 uint32_t np = client->io_alloc.NumPorts1 +
6702                                         client->io_alloc.NumPorts2;
6703                 uint32_t limit, do_bit = 0;
6704                 int lm;
6705 
6706                 limit = (IONUMPORTS_FROBNITZ(np) - 1);
6707 
6708                 for (lm = 7; lm >= 0; lm--) {
6709                     if (limit & (1 << lm))
6710                         do_bit = 1;
6711                     if (do_bit)
6712                         limit |= (1 << lm);
6713                 } /* for */
6714 
6715                 csx_Put8(cis_handle, crt->iolimit_p, limit);
6716             } /* CONFIG_IOLIMIT_REG_PRESENT */
6717         } /* REQ_IO_DONE */
6718 
6719         /*
6720          * Mark the socket as being in IO mode.
6721          */
6722         if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)
6723             sp->flags |= SOCKET_IS_IO;
6724 
6725         mutex_exit(&sp->lock);
6726 
6727         /*
6728          * Enable the interrupt if needed
6729          */
6730         if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
6731             set_socket.IREQRouting |= IRQ_ENABLE;
6732 
6733         /*
6734          * Now that we know if the PRR is present and if it is, which
6735          *      bits in the PRR are valid, we can construct the correct
6736          *      socket event mask.
6737          */
6738         set_socket.SCIntMask = cs_merge_event_masks(sp, client);
6739 
6740         /*
6741          * Configuration Option Register - we handle this specially since
6742          *      we don't allow the client to manipulate the RESET or
6743          *      INTERRUPT bits (although a client can manipulate these
6744          *      bits via an AccessConfigurationRegister call - explain
6745          *      THAT logic to me).
6746          * XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
6747          * XXX - we always enable the function on a multi-function card
6748          */
6749         if (client->present & CONFIG_OPTION_REG_PRESENT) {
6750             crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ;
6751             if (client->present & CONFIG_IOBASE0_REG_PRESENT)
6752                 crt->cor |= COR_ENABLE_BASE_LIMIT;
6753             if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
6754                 crt->cor |= COR_ENABLE_FUNCTION;
6755                 crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
6756                 if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
6757                     crt->cor |= COR_ENABLE_IREQ_ROUTING;
6758             } /* CW_MULTI_FUNCTION_CIS */
6759 
6760 #ifdef  CS_DEBUG
6761         if (cs_debug > 0)
6762                 cmn_err(CE_CONT, "cs_request_configuration "
6763                     "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
6764                     "present=x%x cis_handle=%p cor_p=x%x\n",
6765                     crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags,
6766                     client->present, cis_handle, crt->cor_p);
6767 #endif
6768 
6769             csx_Put8(cis_handle, crt->cor_p, crt->cor);
6770         } /* CONFIG_OPTION_REG_PRESENT */
6771 
6772         if (cs_rc1_delay)
6773             drv_usecwait(cs_rc1_delay * 1000);
6774 
6775         /*
6776          * Set the socket to the parameters that the client requested.
6777          */
6778         if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6779             if (client->present & CONFIG_OPTION_REG_PRESENT) {
6780                 crt->cor = 0; /* XXX is 0 the right thing here? */
6781                 csx_Put8(cis_handle, crt->cor_p, crt->cor);
6782             }
6783             sp->flags &= ~SOCKET_IS_IO;
6784             mutex_exit(&sp->cis_lock);
6785             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6786             return (CS_BAD_SOCKET);
6787         }
6788 
6789         if (cs_rc2_delay)
6790             drv_usecwait(cs_rc2_delay * 1000);
6791 
6792         /*
6793          * Mark this client as having done a successful RequestConfiguration
6794          *      call.
6795          */
6796         client->flags |= REQ_CONFIGURATION_DONE;
6797 
6798         mutex_exit(&sp->cis_lock);
6799         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6800 
6801         return (CS_SUCCESS);
6802 }
6803 
6804 /*
6805  * cs_release_configuration - releases configuration previously set via the
6806  *              RequestConfiguration call; this is ReleaseConfiguration
6807  *
6808  *      returns: CS_SUCCESS - if configuration sucessfully released
6809  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6810  *               CS_BAD_SOCKET - if Socket Services returns an error
6811  *               CS_BAD_HANDLE - a RequestConfiguration has not been done
6812  */
6813 /*ARGSUSED*/
6814 static int
6815 cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg)
6816 {
6817         cs_socket_t *sp;
6818         client_t *client;
6819         volatile config_regs_t *crt;
6820         set_socket_t set_socket;
6821         get_socket_t get_socket;
6822         acc_handle_t cis_handle;
6823         int error;
6824         uint32_t newoffset;
6825         int client_lock_acquired;
6826 
6827         /*
6828          * Check to see if this is the Socket Services client handle; if it
6829          *      is, we don't support SS using this call.
6830          */
6831         if (CLIENT_HANDLE_IS_SS(client_handle))
6832             return (CS_UNSUPPORTED_FUNCTION);
6833 
6834         /*
6835          * Get a pointer to this client's socket structure.
6836          */
6837         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6838             return (CS_BAD_SOCKET);
6839 
6840         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6841 
6842         /*
6843          *  Make sure that this is a valid client handle.
6844          */
6845         if (!(client = cs_find_client(client_handle, &error))) {
6846             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6847             return (error);
6848         }
6849 
6850         /*
6851          * If RequestConfiguration has not been done, we don't allow
6852          *      this call.
6853          */
6854         if (!(client->flags & REQ_CONFIGURATION_DONE)) {
6855             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6856             return (CS_BAD_HANDLE);
6857         }
6858 
6859 #ifdef  CS_DEBUG
6860         if (cs_debug > 0)
6861                 cmn_err(CE_CONT, "cs_release_configuration: "
6862                     "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
6863                     sp->cis_flags, CW_MULTI_FUNCTION_CIS);
6864 
6865 #endif
6866         mutex_enter(&sp->cis_lock);
6867 
6868         /*
6869          * Set the card back to a memory-only interface byte writing a zero
6870          *      to the COR.  Note that we don't update our soft copy of the
6871          *      COR state since the PCMCIA spec only requires us to maintain
6872          *      the last value that was written to that register during a
6873          *      call to RequestConfiguration.
6874          */
6875         crt = &client->config_regs;
6876 
6877         newoffset = client->config_regs_offset;
6878         if (cs_init_cis_window(sp, &newoffset, &cis_handle,
6879                                         CISTPLF_AM_SPACE) != CS_SUCCESS) {
6880             mutex_exit(&sp->cis_lock);
6881             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6882             cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init "
6883                                 "CIS window\n", sp->socket_num);
6884             return (CS_GENERAL_FAILURE);
6885         }
6886 
6887         if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
6888                 /*
6889                  * For the Multifunction cards do not reset the socket
6890                  * to a memory only interface but do clear the
6891                  * Configuration Option Register and  mark this client
6892                  * as not having a configuration by clearing the
6893                  * REQ_CONFIGURATION_DONE flag.
6894                  */
6895                 client->flags &= ~REQ_CONFIGURATION_DONE;
6896                 csx_Put8(cis_handle, crt->cor_p, 0);
6897 
6898                 mutex_exit(&sp->cis_lock);
6899                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6900                 return (CS_SUCCESS);
6901         }
6902 
6903         /*
6904          * Set the socket back to a memory-only interface; don't change
6905          *      any other parameter of the socket.
6906          */
6907         get_socket.socket = sp->socket_num;
6908 
6909         if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
6910             mutex_exit(&sp->cis_lock);
6911             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6912             return (CS_BAD_SOCKET);
6913         }
6914 
6915         mutex_enter(&sp->lock);
6916         sp->flags &= ~SOCKET_IS_IO;
6917         set_socket.SCIntMask = cs_merge_event_masks(sp, client);
6918         mutex_exit(&sp->lock);
6919 
6920         set_socket.socket = sp->socket_num;
6921         set_socket.IREQRouting = 0;
6922         set_socket.CtlInd = get_socket.CtlInd;
6923         set_socket.State = 0;   /* don't reset latched values */
6924         set_socket.VccLevel = get_socket.VccLevel;
6925         set_socket.Vpp1Level = get_socket.Vpp1Level;
6926         set_socket.Vpp2Level = get_socket.Vpp2Level;
6927         set_socket.IFType = IF_MEMORY;
6928 
6929         if (client->present & CONFIG_OPTION_REG_PRESENT)
6930             csx_Put8(cis_handle, crt->cor_p, 0);
6931 
6932         if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6933             mutex_exit(&sp->cis_lock);
6934             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6935             return (CS_BAD_SOCKET);
6936         }
6937 
6938         /*
6939          * Mark this client as not having a configuration.
6940          */
6941         client->flags &= ~REQ_CONFIGURATION_DONE;
6942 
6943         mutex_exit(&sp->cis_lock);
6944         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6945 
6946         return (CS_SUCCESS);
6947 }
6948 
6949 /*
6950  * cs_modify_configuration - modifies a configuration established by
6951  *              RequestConfiguration; this is ModifyConfiguration
6952  *
6953  *      returns: CS_SUCCESS - if configuration sucessfully modified
6954  *               CS_BAD_SOCKET - if Socket Services returns an error
6955  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6956  *               CS_BAD_HANDLE - a RequestConfiguration has not been done
6957  *               CS_NO_CARD - if no card in socket
6958  *               CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
6959  *                                      are set
6960  *               CS_BAD_VCC - if Vcc value is not supported by socket
6961  *               CS_BAD_VPP1 - if Vpp1 value is not supported by socket
6962  *               CS_BAD_VPP2 - if Vpp2 value is not supported by socket
6963  */
6964 static int
6965 cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
6966 {
6967         cs_socket_t *sp;
6968         client_t *client;
6969         set_socket_t set_socket;
6970         get_socket_t get_socket;
6971         int error;
6972         int client_lock_acquired;
6973 
6974         /*
6975          * Check to see if this is the Socket Services client handle; if it
6976          *      is, we don't support SS using this call.
6977          */
6978         if (CLIENT_HANDLE_IS_SS(client_handle))
6979             return (CS_UNSUPPORTED_FUNCTION);
6980 
6981         /*
6982          * Get a pointer to this client's socket structure.
6983          */
6984         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6985             return (CS_BAD_SOCKET);
6986 
6987         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6988 
6989         /*
6990          *  Make sure that this is a valid client handle.
6991          */
6992         if (!(client = cs_find_client(client_handle, &error))) {
6993             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6994             return (error);
6995         }
6996 
6997         /*
6998          * If RequestConfiguration has not been done, we don't allow
6999          *      this call.
7000          */
7001         if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7002             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7003             return (CS_BAD_HANDLE);
7004         }
7005 
7006         /*
7007          * If there's no card in the socket or the card in the socket is not
7008          *      for this client, then return an error.
7009          */
7010         if (!(client->flags & CLIENT_CARD_INSERTED)) {
7011             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7012             return (CS_NO_CARD);
7013         }
7014 
7015         /*
7016          * Get the current socket parameters so that we can modify them.
7017          */
7018         get_socket.socket = sp->socket_num;
7019 
7020         if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
7021             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7022             return (CS_BAD_SOCKET);
7023         }
7024 
7025 #ifdef  CS_DEBUG
7026         if (cs_debug > 0)
7027             cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
7028                                 "client->irq_alloc.irq 0x%x "
7029                                 "get_socket.IRQRouting 0x%x\n",
7030                                 sp->socket_num, (int)client->irq_alloc.irq,
7031                                 get_socket.IRQRouting);
7032 #endif
7033 
7034         set_socket.socket = sp->socket_num;
7035         set_socket.SCIntMask = get_socket.SCIntMask;
7036         set_socket.CtlInd = get_socket.CtlInd;
7037         set_socket.State = 0;   /* don't reset latched values */
7038         set_socket.IFType = get_socket.IFType;
7039 
7040         set_socket.IREQRouting = get_socket.IRQRouting;
7041 
7042         /*
7043          * Modify the IRQ routing if the client wants it modified.
7044          */
7045         if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
7046             set_socket.IREQRouting &= ~IRQ_ENABLE;
7047 
7048             if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
7049                         (client->present & CONFIG_OPTION_REG_PRESENT)) {
7050                 config_regs_t *crt = &client->config_regs;
7051                 acc_handle_t cis_handle;
7052                 uint32_t newoffset = client->config_regs_offset;
7053 
7054                 /*
7055                  * Get a pointer to a window that contains the configuration
7056                  *      registers.
7057                  */
7058                 if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7059                                         CISTPLF_AM_SPACE) != CS_SUCCESS) {
7060                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7061                     cmn_err(CE_CONT,
7062                         "cs_modify_configuration: socket %d can't init "
7063                         "CIS window\n", sp->socket_num);
7064                     return (CS_GENERAL_FAILURE);
7065                 } /* cs_init_cis_window */
7066 
7067                 crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
7068 
7069                 if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7070                     crt->cor |= COR_ENABLE_IREQ_ROUTING;
7071 
7072 #ifdef  CS_DEBUG
7073                 if (cs_debug > 0)
7074                         cmn_err(CE_CONT, "cs_modify_configuration:"
7075                             " cor_p=0x%x cor=0x%x\n",
7076                             crt->cor_p, crt->cor);
7077 #endif
7078                 csx_Put8(cis_handle, crt->cor_p, crt->cor);
7079 
7080             } /* CW_MULTI_FUNCTION_CIS */
7081 
7082             if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7083                 set_socket.IREQRouting |= IRQ_ENABLE;
7084 
7085         } /* CONF_IRQ_CHANGE_VALID */
7086 
7087         /*
7088          * Modify the voltage levels that the client specifies.
7089          */
7090         set_socket.VccLevel = get_socket.VccLevel;
7091 
7092         if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
7093             if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
7094                                         &set_socket.Vpp1Level) != CS_SUCCESS) {
7095                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7096                 return (CS_BAD_VPP);
7097             }
7098         } else {
7099             set_socket.Vpp1Level = get_socket.Vpp1Level;
7100         }
7101 
7102         if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
7103             if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
7104                                         &set_socket.Vpp2Level) != CS_SUCCESS) {
7105                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7106                 return (CS_BAD_VPP);
7107             }
7108         } else {
7109             set_socket.Vpp2Level = get_socket.Vpp2Level;
7110         }
7111 
7112         /*
7113          * Setup the modified socket configuration.
7114          */
7115         if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
7116             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7117             return (CS_BAD_SOCKET);
7118         }
7119 
7120         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7121         return (CS_SUCCESS);
7122 }
7123 
7124 /*
7125  * cs_access_configuration_register - provides a client access to the card's
7126  *              configuration registers; this is AccessConfigurationRegister
7127  *
7128  *      returns: CS_SUCCESS - if register accessed successfully
7129  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7130  *               CS_BAD_ARGS - if arguments are out of range
7131  *               CS_NO_CARD - if no card in socket
7132  *               CS_BAD_BASE - if no config registers base address
7133  *               CS_UNSUPPORTED_MODE - if no RequestConfiguration has
7134  *                              been done yet
7135  */
7136 static int
7137 cs_access_configuration_register(client_handle_t client_handle,
7138                                                 access_config_reg_t *acr)
7139 {
7140         cs_socket_t *sp;
7141         client_t *client;
7142         acc_handle_t cis_handle;
7143         int error;
7144         uint32_t newoffset;
7145         int client_lock_acquired;
7146 
7147         /*
7148          * Check to see if this is the Socket Services client handle; if it
7149          *      is, we don't support SS using this call.
7150          */
7151         if (CLIENT_HANDLE_IS_SS(client_handle))
7152             return (CS_UNSUPPORTED_FUNCTION);
7153 
7154         /*
7155          * Make sure that the specifed offset is in range.
7156          */
7157         if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
7158             return (CS_BAD_ARGS);
7159 
7160         /*
7161          * Get a pointer to this client's socket structure.
7162          */
7163         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7164             return (CS_BAD_SOCKET);
7165 
7166         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7167 
7168         /*
7169          *  Make sure that this is a valid client handle.
7170          */
7171         if (!(client = cs_find_client(client_handle, &error))) {
7172             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7173             return (error);
7174         }
7175 
7176         /*
7177          * If there's no card in the socket or the card in the socket is not
7178          *      for this client, then return an error.
7179          */
7180         if (!(client->flags & CLIENT_CARD_INSERTED)) {
7181             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7182             return (CS_NO_CARD);
7183         }
7184 
7185         /*
7186          * If RequestConfiguration has not been done, we don't allow
7187          *      this call.
7188          */
7189         if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7190             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7191             return (CS_UNSUPPORTED_MODE);
7192         }
7193 
7194         mutex_enter(&sp->cis_lock);
7195 
7196         /*
7197          * Get a pointer to the CIS window
7198          */
7199         newoffset = client->config_regs_offset + acr->Offset;
7200         if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7201                                         CISTPLF_AM_SPACE) != CS_SUCCESS) {
7202             mutex_exit(&sp->cis_lock);
7203             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7204             cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
7205                                                         sp->socket_num);
7206             return (CS_GENERAL_FAILURE);
7207         }
7208 
7209         /*
7210          * Create the address for the config register that the client
7211          *      wants to access.
7212          */
7213         mutex_enter(&sp->lock);
7214 
7215 #ifdef  CS_DEBUG
7216         if (cs_debug > 1) {
7217             cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
7218                 "Offset 0x%x newoffset 0x%x\n",
7219                 (int)client->config_regs_offset,
7220                 (int)acr->Offset, newoffset);
7221         }
7222 #endif
7223 
7224         /*
7225          * Determine what the client wants us to do.  The client is
7226          *      allowed to specify any valid offset, even if it would
7227          *      cause an unimplemented configuration register to be
7228          *      accessed.
7229          */
7230         error = CS_SUCCESS;
7231         switch (acr->Action) {
7232             case CONFIG_REG_READ:
7233                 acr->Value = csx_Get8(cis_handle, newoffset);
7234                 break;
7235             case CONFIG_REG_WRITE:
7236                 csx_Put8(cis_handle, newoffset, acr->Value);
7237                 break;
7238             default:
7239                 error = CS_BAD_ARGS;
7240                 break;
7241         } /* switch */
7242 
7243         mutex_exit(&sp->lock);
7244         mutex_exit(&sp->cis_lock);
7245         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7246 
7247         return (error);
7248 }
7249 
7250 /*
7251  * ==== RESET and general info functions ====
7252  */
7253 
7254 /*
7255  * cs_reset_function - RESET the requested function on the card; this
7256  *                      is ResetFunction
7257  *
7258  *    Note: We don't support this functionality yet, and the standard
7259  *              says it's OK to reutrn CS_IN_USE if we can't do this
7260  *              operation.
7261  */
7262 /*ARGSUSED*/
7263 static int
7264 cs_reset_function(client_handle_t ch, reset_function_t *rf)
7265 {
7266         return (CS_IN_USE);
7267 }
7268 
7269 /*
7270  * cs_get_configuration_info - return configuration info for the passed
7271  *                              socket and function number to the caller;
7272  *                              this is GetConfigurationInfo
7273  */
7274 /*ARGSUSED*/
7275 static int
7276 cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
7277 {
7278         cs_socket_t *sp;
7279         uint32_t fn;
7280         client_t *client;
7281         int client_lock_acquired;
7282 
7283         /*
7284          * Get a pointer to this client's socket structure.
7285          */
7286         if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
7287             return (CS_BAD_SOCKET);
7288 
7289         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7290         mutex_enter(&sp->lock);
7291 
7292         fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
7293 
7294         client = sp->client_list;
7295         while (client) {
7296 
7297             if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
7298 
7299                 /*
7300                  * If there's no card in the socket or the card in the
7301                  *      socket is not for this client, then return
7302                  *      an error.
7303                  */
7304                 if (!(client->flags & CLIENT_CARD_INSERTED)) {
7305                     mutex_exit(&sp->lock);
7306                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7307                     return (CS_NO_CARD);
7308                 }
7309 
7310                 mutex_exit(&sp->lock);
7311                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7312                 return (CS_SUCCESS);
7313 
7314             } /* GET_CLIENT_FUNCTION == fn */
7315 
7316             client = client->next;
7317         } /* while (client) */
7318 
7319         mutex_exit(&sp->lock);
7320         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7321 
7322         return (CS_BAD_SOCKET);
7323 }
7324 
7325 /*
7326  * cs_get_cardservices_info - return info about Card Services to the
7327  *      caller; this is GetCardServicesInfo
7328  */
7329 /*ARGSUSED*/
7330 static int
7331 cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
7332 {
7333         gcsi->Signature[0] = 'C';
7334         gcsi->Signature[1] = 'S';
7335         gcsi->NumSockets = cs_globals.num_sockets;
7336         gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
7337         gcsi->CSLevel = CS_VERSION;
7338         gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
7339         (void) strncpy(gcsi->VendorString,
7340                                         CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
7341                                         CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
7342 
7343         return (CS_SUCCESS);
7344 }
7345 
7346 /*
7347  * cs_get_physical_adapter_info - returns information about the requested
7348  *                                      physical adapter; this is
7349  *                                      GetPhysicalAdapterInfo
7350  *
7351  *      calling: client_handle_t:
7352  *                      NULL - use map_log_socket_t->LogSocket member
7353  *                              to specify logical socket number
7354  *                      !NULL - extract logical socket number from
7355  *                              client_handle_t
7356  *
7357  *      returns: CS_SUCCESS
7358  *               CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7359  *                                      socket number is specified in
7360  *                                      map_log_socket_t->LogSocket
7361  *               CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7362  *                                      client handle is specified
7363  */
7364 static int
7365 cs_get_physical_adapter_info(client_handle_t ch,
7366                                         get_physical_adapter_info_t *gpai)
7367 {
7368         cs_socket_t *sp;
7369         int client_lock_acquired;
7370 
7371         if (ch == NULL)
7372             gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
7373         else
7374             gpai->PhySocket = GET_CLIENT_SOCKET(ch);
7375 
7376         /*
7377          * Determine if the passed socket number is valid or not.
7378          */
7379         if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
7380             return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7381 
7382         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7383 
7384         /*
7385          * If we were passed a client handle, determine if it's valid or not.
7386          */
7387         if (ch != NULL) {
7388             if (cs_find_client(ch, NULL) == NULL) {
7389                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7390                 return (CS_BAD_HANDLE);
7391             } /* cs_find_client */
7392         } /* ch != NULL */
7393 
7394         gpai->flags = sp->adapter.flags;
7395         (void) strcpy(gpai->name, sp->adapter.name);
7396         gpai->major = sp->adapter.major;
7397         gpai->minor = sp->adapter.minor;
7398         gpai->instance = sp->adapter.instance;
7399         gpai->number = sp->adapter.number;
7400         gpai->num_sockets = sp->adapter.num_sockets;
7401         gpai->first_socket = sp->adapter.first_socket;
7402 
7403         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7404 
7405         return (CS_SUCCESS);
7406 }
7407 
7408 /*
7409  * ==== general functions ====
7410  */
7411 
7412 /*
7413  * cs_map_log_socket - returns the physical socket number associated with
7414  *                      either the passed client handle or the passed
7415  *                      logical socket number; this is MapLogSocket
7416  *
7417  *      calling: client_handle_t:
7418  *                      NULL - use map_log_socket_t->LogSocket member
7419  *                              to specify logical socket number
7420  *                      !NULL - extract logical socket number from
7421  *                              client_handle_t
7422  *
7423  *      returns: CS_SUCCESS
7424  *               CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7425  *                                      socket number is specified in
7426  *                                      map_log_socket_t->LogSocket
7427  *               CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7428  *                                      client handle is specified
7429  *
7430  * Note: We provide this function since the instance number of a client
7431  *              driver doesn't necessary correspond to the physical
7432  *              socket number
7433  */
7434 static int
7435 cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
7436 {
7437         cs_socket_t *sp;
7438         int client_lock_acquired;
7439 
7440         if (ch == NULL)
7441             mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
7442         else
7443             mls->PhySocket = GET_CLIENT_SOCKET(ch);
7444 
7445         /*
7446          * Determine if the passed socket number is valid or not.
7447          */
7448         if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
7449             return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7450 
7451         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7452 
7453         /*
7454          * If we were passed a client handle, determine if it's valid or not.
7455          */
7456         if (ch != NULL) {
7457             if (cs_find_client(ch, NULL) == NULL) {
7458                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7459                 return (CS_BAD_HANDLE);
7460             } /* cs_find_client */
7461         } /* ch != NULL */
7462 
7463         mls->PhyAdapter = sp->adapter.number;
7464 
7465         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7466 
7467         return (CS_SUCCESS);
7468 }
7469 
7470 /*
7471  * cs_convert_speed - convers nS to devspeed and devspeed to nS
7472  *
7473  * The actual function is is in the CIS parser module; this
7474  *      is only a wrapper.
7475  */
7476 static int
7477 cs_convert_speed(convert_speed_t *cs)
7478 {
7479         return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
7480 }
7481 
7482 /*
7483  * cs_convert_size - converts a devsize value to a size in bytes value
7484  *                      or a size in bytes value to a devsize value
7485  *
7486  * The actual function is is in the CIS parser module; this
7487  *      is only a wrapper.
7488  */
7489 static int
7490 cs_convert_size(convert_size_t *cs)
7491 {
7492         return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
7493 }
7494 
7495 /*
7496  * cs_convert_powerlevel - converts a power level in tenths of a volt
7497  *                      to a power table entry for the specified socket
7498  *
7499  *      returns: CS_SUCCESS - if volts converted to a valid power level
7500  *               CS_BAD_ADAPTER - if SS_InquireAdapter fails
7501  *               CS_BAD_ARGS - if volts are not supported on this socket
7502  *                              and adapter
7503  */
7504 static int
7505 cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
7506 {
7507         inquire_adapter_t inquire_adapter;
7508         int i;
7509 
7510 #ifdef  lint
7511         if (sn == 0)
7512             panic("lint panic");
7513 #endif
7514 
7515         *pl = 0;
7516 
7517         if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
7518             return (CS_BAD_ADAPTER);
7519 
7520         for (i = 0; (i < inquire_adapter.NumPower); i++) {
7521             if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
7522                 (inquire_adapter.power_entry[i].PowerLevel == volts)) {
7523                 *pl = i;
7524                 return (CS_SUCCESS);
7525             }
7526         }
7527 
7528         return (CS_BAD_ARGS);
7529 }
7530 
7531 /*
7532  * cs_event2text - returns text string(s) associated with the event; this
7533  *                      function supports the Event2Text CS call.
7534  *
7535  *      calling: event2text_t * - pointer to event2text struct
7536  *               int event_source - specifies event type in event2text_t:
7537  *                                      0 - SS event
7538  *                                      1 - CS event
7539  *
7540  *      returns: CS_SUCCESS
7541  */
7542 static int
7543 cs_event2text(event2text_t *e2t, int event_source)
7544 {
7545         event_t event;
7546         char *sepchar = "|";
7547 
7548         /*
7549          * If event_source is 0, this is a SS event
7550          */
7551         if (!event_source) {
7552             for (event = 0; event < MAX_SS_EVENTS; event++) {
7553                 if (cs_ss_event_text[event].ss_event == e2t->event) {
7554                     (void) strcpy(e2t->text, cs_ss_event_text[event].text);
7555                     return (CS_SUCCESS);
7556                 }
7557             }
7558             (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
7559             return (CS_SUCCESS);
7560         } else {
7561                 /*
7562                  * This is a CS event
7563                  */
7564             e2t->text[0] = '\0';
7565             for (event = 0; event < MAX_CS_EVENTS; event++) {
7566                 if (cs_ss_event_text[event].cs_event & e2t->event) {
7567                     (void) strcat(e2t->text, cs_ss_event_text[event].text);
7568                     (void) strcat(e2t->text, sepchar);
7569                 } /* if (cs_ss_event_text) */
7570             } /* for (event) */
7571             if (e2t->text[0])
7572                 e2t->text[strlen(e2t->text)-1] = NULL;
7573         } /* if (!event_source) */
7574 
7575         return (CS_SUCCESS);
7576 }
7577 
7578 /*
7579  * cs_error2text - returns a pointer to a text string containing the name
7580  *                      of the passed Card Services function or return code
7581  *
7582  *      This function supports the Error2Text CS call.
7583  */
7584 static char *
7585 cs_error2text(int function, int type)
7586 {
7587         cs_csfunc2text_strings_t *cfs;
7588         int end_marker;
7589 
7590         if (type == CSFUN2TEXT_FUNCTION) {
7591             cfs = cs_csfunc2text_funcstrings;
7592             end_marker = CSFuncListEnd;
7593         } else {
7594             cfs = cs_csfunc2text_returnstrings;
7595             end_marker = CS_ERRORLIST_END;
7596         }
7597 
7598         while (cfs->item != end_marker) {
7599             if (cfs->item == function)
7600                 return (cfs->text);
7601             cfs++;
7602         }
7603 
7604         return (cfs->text);
7605 }
7606 
7607 /*
7608  * cs_make_device_node - creates/removes device nodes on a client's behalf;
7609  *                              this is MakeDeviceNode and RemoveDeviceNode
7610  *
7611  *      returns: CS_SUCCESS - if all device nodes successfully created/removed
7612  *               CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
7613  *                              is REMOVAL_ALL_DEVICES
7614  *               CS_BAD_ARGS - if an invalid Action code is specified
7615  *               CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7616  *               CS_OUT_OF_RESOURCE - if can't create/remove device node
7617  */
7618 static int
7619 cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
7620 {
7621         cs_socket_t *sp;
7622         client_t *client;
7623         ss_make_device_node_t ss_make_device_node;
7624         int error, i;
7625         int client_lock_acquired;
7626 
7627         /*
7628          * Check to see if this is the Socket Services client handle; if it
7629          *      is, we don't support SS using this call.
7630          */
7631         if (CLIENT_HANDLE_IS_SS(client_handle))
7632             return (CS_UNSUPPORTED_FUNCTION);
7633 
7634         /*
7635          * Get a pointer to this client's socket structure.
7636          */
7637         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7638             return (CS_BAD_SOCKET);
7639 
7640         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7641 
7642         /*
7643          *  Make sure that this is a valid client handle.
7644          */
7645         if (!(client = cs_find_client(client_handle, &error))) {
7646             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7647             return (error);
7648         }
7649 
7650 #ifdef  XXX
7651         /*
7652          * If there's no card in the socket or the card in the socket is not
7653          *      for this client, then return an error.
7654          */
7655         if (!(client->flags & CLIENT_CARD_INSERTED)) {
7656             EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7657             return (CS_NO_CARD);
7658         }
7659 #endif
7660 
7661         /*
7662          * Setup the client's dip, since we use it later on.
7663          */
7664         ss_make_device_node.dip = client->dip;
7665 
7666         /*
7667          * Make sure that we're being given a valid Action.  Set the default
7668          *      error code as well.
7669          */
7670         error = CS_BAD_ARGS;    /* for default case */
7671         switch (mdn->Action) {
7672             case CREATE_DEVICE_NODE:
7673             case REMOVE_DEVICE_NODE:
7674                 break;
7675             case REMOVAL_ALL_DEVICE_NODES:
7676                 if (mdn->NumDevNodes) {
7677                     error = CS_BAD_ATTRIBUTE;
7678                 } else {
7679                     ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7680                     ss_make_device_node.name = NULL;
7681                     SocketServices(CSInitDev, &ss_make_device_node);
7682                     error = CS_SUCCESS;
7683                 }
7684                 /* fall-through case */
7685             default:
7686                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7687                 return (error);
7688                 /* NOTREACHED */
7689         } /* switch */
7690 
7691         /*
7692          * Loop through the device node descriptions and create or destroy
7693          *      the device node.
7694          */
7695         for (i = 0; i < mdn->NumDevNodes; i++) {
7696             devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
7697 
7698             ss_make_device_node.name = devnode_desc->name;
7699             ss_make_device_node.spec_type = devnode_desc->spec_type;
7700             ss_make_device_node.minor_num = devnode_desc->minor_num;
7701             ss_make_device_node.node_type = devnode_desc->node_type;
7702 
7703         /*
7704          * Set the appropriate flag for the action that we want
7705          *      SS to perform. Note that if we ever OR-in the flag
7706          *      here, we need to be sure to clear the flags member
7707          *      since we sometimes OR-in other flags below.
7708          */
7709             if (mdn->Action == CREATE_DEVICE_NODE) {
7710                 ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
7711             } else {
7712                 ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7713             }
7714 
7715         /*
7716          * If this is not the last device to process, then we need
7717          *      to tell SS that more device process requests are on
7718          *      their way after this one.
7719          */
7720             if (i < (mdn->NumDevNodes - 1))
7721                 ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
7722 
7723             if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
7724                 EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7725                 return (CS_OUT_OF_RESOURCE);
7726             } /* CSInitDev */
7727         } /* for (mdn->NumDevNodes) */
7728 
7729         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7730         return (CS_SUCCESS);
7731 }
7732 
7733 /*
7734  * cs_remove_device_node - removes device nodes
7735  *
7736  *      (see cs_make_device_node for a description of the calling
7737  *              and return parameters)
7738  */
7739 static int
7740 cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
7741 {
7742 
7743         /*
7744          * XXX - Note the assumption here that the make_device_node_t and
7745          *      remove_device_node_t structures are identical.
7746          */
7747         return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
7748 }
7749 
7750 /*
7751  * cs_ddi_info - this function is used by clients that need to support
7752  *                      the xxx_getinfo function; this is CS_DDI_Info
7753  */
7754 static int
7755 cs_ddi_info(cs_ddi_info_t *cdi)
7756 {
7757         cs_socket_t *sp;
7758         client_t *client;
7759         int client_lock_acquired;
7760 
7761         if (cdi->driver_name == NULL)
7762             return (CS_BAD_ATTRIBUTE);
7763 
7764 #ifdef  CS_DEBUG
7765         if (cs_debug > 0) {
7766             cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
7767                                         (int)cdi->Socket, cdi->driver_name);
7768         }
7769 #endif
7770 
7771         /*
7772          * Check to see if the socket number is in range - the system
7773          *      framework may cause a client driver to call us with
7774          *      a socket number that used to be present but isn't
7775          *      anymore. This is not a bug, and it's OK to return
7776          *      an error if the socket number is out of range.
7777          */
7778         if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
7779 
7780 #ifdef  CS_DEBUG
7781             if (cs_debug > 0) {
7782                 cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
7783                                                 "SOCKET IS OUT OF RANGE\n",
7784                                                         (int)cdi->Socket,
7785                                                         cdi->driver_name);
7786             }
7787 #endif
7788 
7789             return (CS_BAD_SOCKET);
7790         } /* if (!CHECK_SOCKET_NUM) */
7791 
7792         /*
7793          * Get a pointer to this client's socket structure.
7794          */
7795         if ((sp = cs_get_sp(cdi->Socket)) == NULL)
7796             return (CS_BAD_SOCKET);
7797 
7798         EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7799 
7800         client = sp->client_list;
7801         while (client) {
7802 
7803 #ifdef  CS_DEBUG
7804             if (cs_debug > 0) {
7805                 cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
7806                                                         "handle 0x%x\n",
7807                                                 (int)cdi->Socket,
7808                                                 client->driver_name,
7809                                                 (int)client->client_handle);
7810             }
7811 #endif
7812 
7813             if (client->driver_name != NULL) {
7814                 if (!(strcmp(client->driver_name, cdi->driver_name))) {
7815                     cdi->dip = client->dip;
7816                     cdi->instance = client->instance;
7817 
7818 #ifdef  CS_DEBUG
7819                     if (cs_debug > 0) {
7820                         cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
7821                                                 "instance %d handle 0x%x\n",
7822                                         client->driver_name, client->instance,
7823                                         (int)client->client_handle);
7824                     }
7825 #endif
7826 
7827                     EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7828                     return (CS_SUCCESS);
7829                 } /* strcmp */
7830             } /* driver_name != NULL */
7831             client = client->next;
7832         } /* while (client) */
7833 
7834         EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7835         return (CS_BAD_SOCKET);
7836 }
7837 
7838 /*
7839  * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
7840  */
7841 static int
7842 cs_sys_ctl(cs_sys_ctl_t *csc)
7843 {
7844         cs_socket_t *sp;
7845         client_t *cp;
7846         int sn, ret = CS_UNSUPPORTED_MODE;
7847 
7848         switch (csc->Action) {
7849             case CS_SYS_CTL_SEND_EVENT:
7850                 if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7851                     sn = CS_GET_SOCKET_NUMBER(csc->Socket);
7852                 else
7853                     sn = GET_CLIENT_SOCKET(csc->client_handle);
7854                 if ((sp = cs_get_sp(sn)) == NULL)
7855                     return (CS_BAD_SOCKET);
7856                 mutex_enter(&sp->client_lock);
7857                 mutex_enter(&sp->lock);
7858                 csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
7859                 if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7860                     sp->events |= csc->Events;
7861                 if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
7862                     if ((cp = cs_find_client(csc->client_handle, &ret)) ==
7863                                                                         NULL) {
7864                         mutex_exit(&sp->lock);
7865                         mutex_exit(&sp->client_lock);
7866                         return (ret);
7867                     } /* cs_find_client */
7868                         /*
7869                          * Setup the events that we want to send to the client.
7870                          */
7871                     cp->events |= (csc->Events &
7872                                         (cp->event_mask | cp->global_mask));
7873                 } /* CS_SYS_CTL_EVENT_CLIENT */
7874 
7875                 if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
7876                     sp->thread_state |= SOCKET_WAIT_SYNC;
7877                     mutex_exit(&sp->lock);
7878                     cv_broadcast(&sp->thread_cv);
7879                     cv_wait(&sp->caller_cv, &sp->client_lock);
7880                 } else {
7881                     mutex_exit(&sp->lock);
7882                     cv_broadcast(&sp->thread_cv);
7883                 } /* CS_SYS_CTL_WAIT_SYNC */
7884                 mutex_exit(&sp->client_lock);
7885                 ret = CS_SUCCESS;
7886                 break;
7887             default:
7888                 break;
7889         } /* switch */
7890 
7891         return (ret);
7892 }
7893 
7894 /*
7895  * cs_get_sp - returns pointer to per-socket structure for passed
7896  *              socket number
7897  *
7898  *      return: (cs_socket_t *) - pointer to socket structure
7899  *              NULL - invalid socket number passed in
7900  */
7901 static cs_socket_t *
7902 cs_get_sp(uint32_t sn)
7903 {
7904         cs_socket_t *sp = cs_globals.sp;
7905 
7906         if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7907             return (NULL);
7908 
7909         if ((sp = cs_find_sp(sn)) == NULL)
7910             return (NULL);
7911 
7912         if (sp->flags & SOCKET_IS_VALID)
7913             return (sp);
7914 
7915         return (NULL);
7916 }
7917 
7918 /*
7919  * cs_find_sp - searches socket list and returns pointer to passed socket
7920  *                      number
7921  *
7922  *      return: (cs_socket_t *) - pointer to socket structure if found
7923  *              NULL - socket not found
7924  */
7925 static cs_socket_t *
7926 cs_find_sp(uint32_t sn)
7927 {
7928         cs_socket_t *sp = cs_globals.sp;
7929 
7930         while (sp) {
7931             if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
7932                 return (sp);
7933             sp = sp->next;
7934         } /* while */
7935 
7936         return (NULL);
7937 }
7938 
7939 /*
7940  * cs_add_socket - add a socket
7941  *
7942  *      call:   sn - socket number to add
7943  *
7944  *      return: CS_SUCCESS - operation sucessful
7945  *              CS_BAD_SOCKET - unable to add socket
7946  *              CS_BAD_WINDOW - unable to get CIS window for socket
7947  *
7948  * We get called here once for each socket that the framework wants to
7949  *      add. When we are called, the framework guarentees that until we
7950  *      complete this routine, no other adapter instances will be allowed
7951  *      to attach and thus no other PCE_ADD_SOCKET events will occur.
7952  *      It is safe to call SS_InquireAdapter to get the number of
7953  *      windows that the framework currently knows about.
7954  */
7955 static uint32_t
7956 cs_add_socket(uint32_t sn)
7957 {
7958         cs_socket_t *sp;
7959         sservice_t sservice;
7960         get_cookies_and_dip_t *gcad;
7961         win_req_t win_req;
7962         convert_speed_t convert_speed;
7963         set_socket_t set_socket;
7964         cs_window_t *cw;
7965         inquire_adapter_t inquire_adapter;
7966         inquire_window_t inquire_window;
7967         int ret, added_windows;
7968 
7969         if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7970             return (CS_BAD_SOCKET);
7971 
7972         /*
7973          * See if this socket has already been added - if it has, we
7974          *      fail this. If we can't find the socket, then allocate
7975          *      a new socket structure. If we do find the socket, then
7976          *      check to see if it's already added; if it is, then
7977          *      this is an error and return CS_BAD_SOCKET; if not,
7978          *      then traverse the socket structure list and add this
7979          *      next socket strcture to the end of the list.
7980          * XXX What about locking this list while we update it? Is
7981          *      that necessary since we're using the SOCKET_IS_VALID
7982          *      flag and since we never delete a socket from the
7983          *      list once it's been added?
7984          */
7985         if ((sp = cs_find_sp(sn)) == NULL) {
7986             cs_socket_t *spp = cs_globals.sp;
7987 
7988             sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
7989 
7990             if (cs_globals.sp == NULL)
7991                 cs_globals.sp = sp;
7992             else
7993                 while (spp) {
7994                     if (spp->next == NULL) {
7995                         spp->next = sp;
7996                         break;
7997                     } /* if */
7998                     spp = spp->next;
7999                 } /* while */
8000 
8001         } else {
8002             if (sp->flags & SOCKET_IS_VALID)
8003                 return (CS_BAD_SOCKET);
8004         } /* cs_find_sp */
8005 
8006         /*
8007          * Setup the socket number
8008          */
8009         sp->socket_num = sn;
8010 
8011         /*
8012          * Find out how many windows the framework knows about
8013          *      so far. If this number of windows is greater
8014          *      than our current window count, bump up our
8015          *      current window count.
8016          * XXX Note that there is a BIG assumption here and that
8017          *      is that once the framework tells us that it has
8018          *      a window (as reflected in the NumWindows
8019          *      value) it can NEVER remove that window.
8020          *      When we really get the drop socket and drop
8021          *      window mechanism working correctly, we'll have
8022          *      to revisit this.
8023          */
8024         SocketServices(SS_InquireAdapter, &inquire_adapter);
8025 
8026         mutex_enter(&cs_globals.window_lock);
8027         added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
8028         if (added_windows > 0) {
8029             if (cs_add_windows(added_windows,
8030                                 cs_globals.num_windows) != CS_SUCCESS) {
8031                 mutex_exit(&cs_globals.window_lock);
8032                 return (CS_BAD_WINDOW);
8033             } /* cs_add_windows */
8034 
8035             cs_globals.num_windows = inquire_adapter.NumWindows;
8036 
8037         } /* if (added_windows) */
8038 
8039         /*
8040          * Find a window that we can use for this socket's CIS window.
8041          */
8042         sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8043 
8044         convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
8045         convert_speed.nS = CIS_DEFAULT_SPEED;
8046         (void) cs_convert_speed(&convert_speed);
8047 
8048         win_req.win_params.AccessSpeed = convert_speed.devspeed;
8049         win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
8050         win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
8051         win_req.Base.base = 0;
8052         win_req.Size = 0;
8053 
8054         if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
8055                                         &sp->cis_win_num)) != CS_SUCCESS) {
8056             mutex_exit(&cs_globals.window_lock);
8057             sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8058             cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
8059                                                 "window - error 0x%x\n",
8060                                                 sp->socket_num, ret);
8061             return (CS_BAD_WINDOW);
8062         } /* cs_find_mem_window */
8063 
8064         if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
8065             mutex_exit(&cs_globals.window_lock);
8066             return (CS_BAD_WINDOW);
8067         }
8068 
8069         inquire_window.window = sp->cis_win_num;
8070         SocketServices(SS_InquireWindow, &inquire_window);
8071 
8072         /*
8073          * If the CIS window is a variable sized window, then use
8074          *      the size that cs_find_mem_window returned to us,
8075          *      since this will be the minimum size that we can
8076          *      set this window to. If the CIS window is a fixed
8077          *      sized window, then use the system pagesize as the
8078          *      CIS window size.
8079          */
8080         if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
8081             sp->cis_win_size = win_req.Size;
8082         } else {
8083             sp->cis_win_size = PAGESIZE;
8084         }
8085 
8086         cw->state |= (CW_CIS | CW_ALLOCATED);
8087         cw->socket_num = sp->socket_num;
8088 
8089         mutex_exit(&cs_globals.window_lock);
8090 
8091 #if defined(CS_DEBUG)
8092             if (cs_debug > 1) {
8093                 cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
8094                                         "size 0x%x\n", (int)sp->socket_num,
8095                                         (int)sp->cis_win_num,
8096                                         (int)sp->cis_win_size);
8097             }
8098 #endif
8099 
8100         /*
8101          * Get the adapter information associated with this socket so
8102          *      that we can initialize the mutexes, condition variables,
8103          *      soft interrupt handler and per-socket adapter info.
8104          */
8105         gcad = &sservice.get_cookies;
8106         gcad->socket = sp->socket_num;
8107         if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
8108             cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
8109                                                 "failure\n", sp->socket_num);
8110             return (CS_BAD_SOCKET);
8111         } /* CSGetCookiesAndDip */
8112 
8113         /*
8114          * Save the iblock and idev cookies for RegisterClient
8115          */
8116         sp->iblk = gcad->iblock;
8117         sp->idev = gcad->idevice;
8118 
8119         /*
8120          * Setup the per-socket adapter info
8121          */
8122         sp->adapter.flags = 0;
8123         (void) strcpy(sp->adapter.name, gcad->adapter_info.name);
8124         sp->adapter.major = gcad->adapter_info.major;
8125         sp->adapter.minor = gcad->adapter_info.minor;
8126         sp->adapter.instance = ddi_get_instance(gcad->dip);
8127         sp->adapter.number = gcad->adapter_info.number;
8128         sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
8129         sp->adapter.first_socket = gcad->adapter_info.first_socket;
8130 
8131         /* Setup for cs_event and cs_event_thread */
8132         mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
8133         mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
8134         mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
8135 
8136         /* Setup for Socket Services work thread */
8137         mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
8138 
8139         sp->init_state |= SOCKET_INIT_STATE_MUTEX;
8140 
8141         /* Setup for cs_event_thread */
8142         cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
8143         cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
8144         cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
8145 
8146         /* Setup for Socket Services work thread */
8147         cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
8148         cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
8149 
8150         sp->init_state |= SOCKET_INIT_STATE_CV;
8151 
8152         /*
8153          * If we haven't installed it yet, then install the soft interrupt
8154          *      handler and save away the softint id.
8155          */
8156         if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
8157             if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
8158                                                 &sp->softint_id,
8159                                                 NULL, NULL,
8160                                                 cs_socket_event_softintr,
8161                                                 (caddr_t)NULL) != DDI_SUCCESS) {
8162                     cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
8163                                                 "softintr\n", sp->socket_num);
8164                     return (CS_BAD_SOCKET);
8165             } /* ddi_add_softintr */
8166 
8167             mutex_enter(&cs_globals.global_lock);
8168             cs_globals.softint_id = sp->softint_id;
8169             cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
8170             /* XXX this timer is hokey at best... */
8171             cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
8172                 NULL, SOFTINT_TIMEOUT_TIME);
8173             mutex_exit(&cs_globals.global_lock);
8174         } else {
8175                 /*
8176                  * We've already added the soft interrupt handler, so just
8177                  *      store away the softint id.
8178                  */
8179             sp->softint_id = cs_globals.softint_id;
8180         } /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
8181 
8182         /*
8183          * While this next flag doesn't really describe a per-socket
8184          *      resource, we still set it for each socket.  When the soft
8185          *      interrupt handler finally gets removed in cs_deinit, this
8186          *      flag will get cleared.
8187          */
8188         sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
8189 
8190         /*
8191          * Socket Services defaults all sockets to power off and
8192          *      clears all event masks.  We want to receive at least
8193          *      card insertion events, so enable them.  Turn off power
8194          *      to the socket as well.  We will turn it on again when
8195          *      we get a card insertion event.
8196          */
8197         sp->event_mask = CS_EVENT_CARD_INSERTION;
8198         set_socket.socket = sp->socket_num;
8199         set_socket.SCIntMask = SBM_CD;
8200         set_socket.IREQRouting = 0;
8201         set_socket.IFType = IF_MEMORY;
8202         set_socket.CtlInd = 0; /* turn off controls and indicators */
8203         set_socket.State = (unsigned)~0;        /* clear latched state bits */
8204 
8205         (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
8206                                                 &set_socket.VccLevel);
8207         (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
8208                                                 &set_socket.Vpp1Level);
8209         (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
8210                                                 &set_socket.Vpp2Level);
8211 
8212         if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
8213             cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
8214                                         "failure %d\n", sp->socket_num, ret);
8215                 return (CS_BAD_SOCKET);
8216         } /* SS_SetSocket */
8217 
8218         /*
8219          * The various socket-specific variables are now set up, so
8220          *      increment the global socket count and also mark the
8221          *      socket as available. We need to set this before we
8222          *      start any of the per-socket threads so that the threads
8223          *      can get a valid socket pointer when they start.
8224          */
8225         mutex_enter(&cs_globals.global_lock);
8226         cs_globals.num_sockets++;
8227         cs_globals.max_socket_num =
8228                         max(cs_globals.max_socket_num, sp->socket_num + 1);
8229         mutex_exit(&cs_globals.global_lock);
8230         sp->flags = SOCKET_IS_VALID;
8231 
8232         /*
8233          * Create the per-socket event handler thread.
8234          */
8235         sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
8236                 (uintptr_t)sn);
8237 
8238         mutex_enter(&sp->lock);
8239         sp->init_state |= SOCKET_INIT_STATE_THREAD;
8240         mutex_exit(&sp->lock);
8241 
8242         /*
8243          * Create the per-socket Socket Services work thread.
8244          */
8245         sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
8246                 (uintptr_t)sn);
8247 
8248         mutex_enter(&sp->lock);
8249         sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
8250                                                 SOCKET_INIT_STATE_READY);
8251         sp->event_mask = CS_EVENT_CARD_INSERTION;
8252         mutex_exit(&sp->lock);
8253 
8254         return (CS_SUCCESS);
8255 }
8256 
8257 /*
8258  * cs_drop_socket - drop a socket
8259  *
8260  *      call:   sn - socket number to drop
8261  *
8262  *      return: CS_SUCCESS - operation sucessful
8263  *              CS_BAD_SOCKET - unable to drop socket
8264  */
8265 /*ARGSUSED*/
8266 static uint32_t
8267 cs_drop_socket(uint32_t sn)
8268 {
8269 #ifdef  XXX
8270         cs_socket_t *sp;
8271 
8272         /*
8273          * Tell the socket event thread to exit and then wait for it
8274          *      to do so.
8275          */
8276         mutex_enter(&sp->client_lock);
8277         sp->thread_state |= SOCKET_THREAD_EXIT;
8278         cv_broadcast(&sp->thread_cv);
8279         cv_wait(&sp->caller_cv, &sp->client_lock);
8280         mutex_exit(&sp->client_lock);
8281 
8282         /*
8283          * Tell the socket SS thread to exit and then wait for it
8284          *      to do so.
8285          */
8286 
8287         /*
8288          * Mark the socket as dropped.
8289          */
8290         sp->flags &= ~SOCKET_IS_VALID;
8291 
8292 #endif  /* XXX */
8293 
8294         /* XXX for now don't allow dropping sockets XXX */
8295         return (CS_BAD_SOCKET);
8296 }
8297 
8298 /*
8299  * cs_get_socket - returns the socket and function numbers and a pointer
8300  *                      to the socket structure
8301  *
8302  * calling:     client_handle_t client_handle - client handle to extract
8303  *                                              socket number from
8304  *              uint32_t *socket -  pointer to socket number to use if
8305  *                                      client_handle is for the SS client;
8306  *                                      this value will be filled in on
8307  *                                      return with the correct socket
8308  *                                      and function numbers if we
8309  *                                      return CS_SUCCESS
8310  *              uint32_t *function - pointer to return function number into
8311  *                                      if not NULL
8312  *              cs_socket_t **sp - pointer to a pointer where a pointer
8313  *                                      to the socket struct will be
8314  *                                      placed if this is non-NULL
8315  *              client_t **clp - pointer to a pointer where a pointer
8316  *                                      to the client struct will be
8317  *                                      placed if this is non-NULL
8318  *
8319  *    The socket and function numbers are derived as follows:
8320  *
8321  *      Client Type             Socket Number           Function Number
8322  *      PC card client          From client_handle      From client_handle
8323  *      Socket Services client  From *socket            From *socket
8324  *      CSI client              From client_handle      From *socket
8325  */
8326 static uint32_t
8327 cs_get_socket(client_handle_t client_handle, uint32_t *socket,
8328     uint32_t *function, cs_socket_t **csp, client_t **clp)
8329 {
8330         cs_socket_t *sp;
8331         client_t *client;
8332         uint32_t sn, fn;
8333         int ret;
8334 
8335         sn = *socket;
8336 
8337         /*
8338          * If this is the Socket Services client, then return the
8339          *      socket and function numbers specified in the passed
8340          *      socket number parameter, otherwise extract the socket
8341          *      and function numbers from the client handle.
8342          */
8343         if (CLIENT_HANDLE_IS_SS(client_handle)) {
8344             fn = CS_GET_FUNCTION_NUMBER(sn);
8345             sn = CS_GET_SOCKET_NUMBER(sn);
8346         } else {
8347             fn = GET_CLIENT_FUNCTION(client_handle);
8348             sn = GET_CLIENT_SOCKET(client_handle);
8349         }
8350 
8351         /*
8352          * Check to be sure that the socket number is in range
8353          */
8354         if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
8355             return (CS_BAD_SOCKET);
8356 
8357         if ((sp = cs_get_sp(sn)) == NULL)
8358             return (CS_BAD_SOCKET);
8359 
8360         /*
8361          * If we were given a pointer, then fill it in with a pointer
8362          *      to this socket.
8363          */
8364         if (csp)
8365             *csp = sp;
8366 
8367         /*
8368          * Search for the client; if it's not found, return an error.
8369          */
8370         mutex_enter(&sp->lock);
8371         if (!(client = cs_find_client(client_handle, &ret))) {
8372             mutex_exit(&sp->lock);
8373             return (ret);
8374         }
8375 
8376         /*
8377          * If we're a CIS client, then extract the function number
8378          *      from the socket number.
8379          */
8380         if (client->flags & CLIENT_CSI_CLIENT)
8381             fn = CS_GET_FUNCTION_NUMBER(*socket);
8382 
8383         mutex_exit(&sp->lock);
8384 
8385         /*
8386          * Return the found client pointer if the caller wants it.
8387          */
8388         if (clp)
8389             *clp = client;
8390 
8391         /*
8392          * Return a socket number that is made up of the socket number
8393          *      and the function number.
8394          */
8395         *socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
8396 
8397         /*
8398          * Return the function number if the caller wants it.
8399          */
8400         if (function)
8401             *function = fn;
8402 
8403         return (CS_SUCCESS);
8404 }
8405 
8406 /*
8407  * cs_get_wp - returns pointer to passed window number
8408  *
8409  *      return: (cs_window_t *) - pointer to window structure
8410  *              NULL - if invalid window number passed in
8411  */
8412 static cs_window_t *
8413 cs_get_wp(uint32_t wn)
8414 {
8415         cs_window_t *cw;
8416 
8417         if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
8418             return (NULL);
8419 
8420         if ((cw = cs_find_wp(wn)) == NULL)
8421             return (NULL);
8422 
8423         if (cw->state & CW_WINDOW_VALID)
8424             return (cw);
8425 
8426 #ifdef  CS_DEBUG
8427         if (cs_debug > 0) {
8428                 cmn_err(CE_CONT, "cs_get_wp(): wn=%d  cw=%p\n",
8429                     (int)wn, (void *)cw);
8430         }
8431 #endif
8432 
8433         return (NULL);
8434 }
8435 
8436 /*
8437  * cs_find_wp - searches window list and returns pointer to passed window
8438  *                      number
8439  *
8440  *      return: (cs_window_t *) - pointer to window structure
8441  *              NULL - window not found
8442  */
8443 static cs_window_t *
8444 cs_find_wp(uint32_t wn)
8445 {
8446         cs_window_t *cw = cs_globals.cw;
8447 
8448         while (cw) {
8449             if (cw->window_num == wn)
8450                 return (cw);
8451             cw = cw->next;
8452         } /* while */
8453 
8454 #ifdef  CS_DEBUG
8455         if (cs_debug > 0) {
8456                 cmn_err(CE_CONT, "cs_find_wp(): wn=%d  window_num=%d cw=%p\n",
8457                     (int)wn, (int)cw->window_num, (void *)cw);
8458         }
8459 #endif
8460 
8461         return (NULL);
8462 }
8463 
8464 /*
8465  * cs_add_windows - adds number of windows specified in "aw" to
8466  *                      the global window list; start the window
8467  *                      numbering at "bn"
8468  *
8469  *      return: CS_SUCCESS - if windows added sucessfully
8470  *              CS_BAD_WINDOW - if unable to add windows
8471  *
8472  * Note: The window list must be protected by a lock by the caller.
8473  */
8474 static int
8475 cs_add_windows(int aw, uint32_t bn)
8476 {
8477         cs_window_t *cwp = cs_globals.cw;
8478         cs_window_t *cw, *cwpp;
8479 
8480         if (aw <= 0)
8481             return (CS_BAD_WINDOW);
8482 
8483         while (cwp) {
8484             cwpp = cwp;
8485             cwp = cwp->next;
8486         }
8487 
8488         while (aw--) {
8489             cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
8490 
8491             if (cs_globals.cw == NULL) {
8492                 cs_globals.cw = cw;
8493                 cwpp = cs_globals.cw;
8494             } else {
8495                 cwpp->next = cw;
8496                 cwpp = cwpp->next;
8497             }
8498 
8499             cwpp->window_num = bn++;
8500             cwpp->state = CW_WINDOW_VALID;
8501 
8502         } /* while (aw) */
8503 
8504         return (CS_SUCCESS);
8505 }
8506 
8507 /*
8508  * cs_ss_init - initialize CS items that need to wait until we receive
8509  *                      a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
8510  *
8511  *      return: CS_SUCESS - if sucessfully initialized
8512  *              (various) if error initializing
8513  *
8514  *      At this point, we expect that Socket Services has setup the
8515  *      following global variables for us:
8516  *
8517  *              cs_socket_services - Socket Services entry point
8518  *              cis_parser - CIS parser entry point
8519  */
8520 static uint32_t
8521 cs_ss_init()
8522 {
8523         cs_register_cardservices_t rcs;
8524         csregister_t csr;
8525         uint32_t ret;
8526 
8527         /*
8528          * Fill out the parameters for CISP_CIS_SETUP
8529          */
8530         csr.cs_magic = PCCS_MAGIC;
8531         csr.cs_version = PCCS_VERSION;
8532         csr.cs_card_services = CardServices;
8533         csr.cs_event = NULL;
8534 
8535         /*
8536          * Call into the CIS module and tell it what the private
8537          *      Card Services entry point is. The CIS module will
8538          *      call us back at CardServices(CISRegister, ...)
8539          *      with the address of various CIS-specific global
8540          *      data structures.
8541          */
8542         CIS_PARSER(CISP_CIS_SETUP, &csr);
8543 
8544         /*
8545          * Register with the Card Services kernel stubs module
8546          */
8547         rcs.magic = CS_STUBS_MAGIC;
8548         rcs.function = CS_ENTRY_REGISTER;
8549         rcs.cardservices = CardServices;
8550 
8551         if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
8552             cmn_err(CE_CONT, "cs_ss_init: can't register with "
8553                                         "cs_stubs, retcode = 0x%x\n", ret);
8554                 return (ret);
8555         } /* csx_register_cardservices */
8556 
8557         return (CS_SUCCESS);
8558 }
8559 
8560 /*
8561  * cs_create_cis - reads CIS on card in socket and creates CIS lists
8562  *
8563  * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
8564  *      function.
8565  *
8566  * This function returns:
8567  *
8568  *      CS_SUCCESS - if the CIS lists were created sucessfully
8569  *      CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
8570  *                      not be setup
8571  *      CS_BAD_CIS - if error creating CIS chains
8572  *      CS_BAD_OFFSET - if the CIS parser tried to read past the
8573  *                      boundries of the allocated CIS window
8574  */
8575 static int
8576 cs_create_cis(cs_socket_t *sp)
8577 {
8578         uint32_t ret;
8579 
8580         ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
8581             cis_cistpl_std_callout, sp);
8582 
8583 #ifdef  CS_DEBUG
8584         if (ret == CS_NO_CIS) {
8585             if (cs_debug > 0)
8586                 cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
8587                                                                 sp->socket_num);
8588         } else if (ret != CS_SUCCESS) {
8589             if (cs_debug > 0)
8590                 cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
8591                                                         sp->socket_num, ret);
8592             return (ret);
8593         }
8594 #else
8595         if (ret != CS_NO_CIS)
8596             if (ret != CS_SUCCESS)
8597                 return (ret);
8598 #endif
8599 
8600         /*
8601          * If this card didn't have any CIS at all, there's not much
8602          *      else for us to do.
8603          */
8604         if (!(sp->cis_flags & CW_VALID_CIS))
8605             return (CS_SUCCESS);
8606 
8607         /*
8608          * If this is a single-function card, we need to move the CIS list
8609          *      that is currently on CS_GLOBAL_CIS to the function zero
8610          *      CIS list.
8611          */
8612         if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
8613             bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
8614                                 (caddr_t)&sp->cis[0], sizeof (cis_info_t));
8615             bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
8616         } /* !CW_MULTI_FUNCTION_CIS */
8617 
8618         return (CS_SUCCESS);
8619 }
8620 
8621 /*
8622  * cs_destroy_cis - destroys CIS list for socket
8623  */
8624 static int
8625 cs_destroy_cis(cs_socket_t *sp)
8626 {
8627         CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
8628 
8629         return (CS_SUCCESS);
8630 }
8631 
8632 /*
8633  * cs_get_client_info - This function is GetClientInfo.
8634  *
8635  *    calling:  client_handle_t - client handle to get client info on
8636  *              client_info_t * - pointer to a client_info_t structure
8637  *                                      to return client information in
8638  *
8639  *    returns:  CS_SUCCESS - if client info retreived from client
8640  *              CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8641  *                                      handle passed in
8642  *              CS_NO_MORE_ITEMS - if client does not handle the
8643  *                                      CS_EVENT_CLIENT_INFO event
8644  *                                      or if invalid client info
8645  *                                      retreived from client
8646  */
8647 static int
8648 cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
8649 {
8650         cs_socket_t *sp;
8651         client_t *client;
8652         client_info_t *cinfo;
8653         int ret = CS_SUCCESS;
8654 
8655         if (CLIENT_HANDLE_IS_SS(client_handle)) {
8656             ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
8657                                                 CS_CLIENT_INFO_VALID);
8658             return (CS_SUCCESS);
8659         } /* CLIENT_HANDLE_IS_SS */
8660 
8661         if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
8662             return (CS_BAD_SOCKET);
8663 
8664         mutex_enter(&sp->client_lock);
8665         mutex_enter(&sp->lock);
8666 
8667         if ((client = cs_find_client(client_handle, &ret)) == NULL) {
8668             mutex_exit(&sp->lock);
8669             mutex_exit(&sp->client_lock);
8670             return (ret);
8671         } /* cs_find_client */
8672 
8673         /*
8674          * If this client is not handling CS_EVENT_CLIENT_INFO events,
8675          *      then don't bother to even wake up the event thread.
8676          */
8677         if (!((client->event_mask | client->global_mask) &
8678                                         CS_EVENT_CLIENT_INFO)) {
8679             mutex_exit(&sp->lock);
8680             mutex_exit(&sp->client_lock);
8681             return (CS_NO_MORE_ITEMS);
8682         } /* !CS_EVENT_CLIENT_INFO */
8683 
8684         cinfo = &client->event_callback_args.client_info;
8685 
8686         bzero((caddr_t)cinfo, sizeof (client_info_t));
8687         cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
8688 
8689         client->events |= CS_EVENT_CLIENT_INFO;
8690 
8691         sp->thread_state |= SOCKET_WAIT_SYNC;
8692         mutex_exit(&sp->lock);
8693         cv_broadcast(&sp->thread_cv);
8694         cv_wait(&sp->caller_cv, &sp->client_lock);
8695 
8696         if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
8697             bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
8698             ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
8699                                         CS_CLIENT_INFO_SUBSVC_MASK);
8700             ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
8701                                                 INFO_CARD_FLAGS_MASK |
8702                                                 CS_CLIENT_INFO_CLIENT_ACTIVE);
8703             ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
8704                                                 INFO_CARD_FLAGS_MASK));
8705             (void) strcpy(ci->DriverName, client->driver_name);
8706             if (cs_card_for_client(client))
8707                 ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
8708         } else {
8709             ret = CS_NO_MORE_ITEMS;
8710         } /* CS_CLIENT_INFO_VALID */
8711 
8712         mutex_exit(&sp->client_lock);
8713 
8714         return (ret);
8715 }
8716 
8717 /*
8718  * cs_get_firstnext_client - This function is GetFirstClient and
8719  *                              GetNextClient
8720  *
8721  *    calling:  get_firstnext_client_t * - pointer to a get_firstnext_client_t
8722  *                                      structure to return client handle and
8723  *                                      attributes in
8724  *              flags - one of the following:
8725  *                              CS_GET_FIRST_FLAG - get first client handle
8726  *                              CS_GET_NEXT_FLAG - get next client handle
8727  *
8728  *    returns:  CS_SUCCESS - if client info retreived from client
8729  *              CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8730  *                                      handle passed in
8731  *              CS_NO_MORE_ITEMS - if client does not handle the
8732  *                                      CS_EVENT_CLIENT_INFO event
8733  *                                      or if invalid client info
8734  *                                      retreived from client
8735  */
8736 static int
8737 cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
8738 {
8739         cs_socket_t *sp;
8740         client_t *client;
8741         uint32_t sn = 0;
8742         int ret = CS_SUCCESS;
8743 
8744         switch (flags) {
8745             case CS_GET_FIRST_FLAG:
8746                 if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8747                     while (sn < cs_globals.max_socket_num) {
8748                         if ((sp = cs_get_sp(sn)) != NULL) {
8749                             mutex_enter(&sp->client_lock);
8750                             if ((client = sp->client_list) != NULL)
8751                                 break;
8752                             mutex_exit(&sp->client_lock);
8753                         } /* if */
8754                         sn++;
8755                     } /* while */
8756 
8757                     if (sn == cs_globals.max_socket_num)
8758                         return (CS_NO_MORE_ITEMS);
8759                 } else if (fnc->Attributes &
8760                                         CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8761                     if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
8762                                                                         NULL)
8763                         return (CS_BAD_SOCKET);
8764                     mutex_enter(&sp->client_lock);
8765                     if ((client = sp->client_list) == NULL) {
8766                         mutex_exit(&sp->client_lock);
8767                         return (CS_NO_MORE_ITEMS);
8768                     }
8769                 } else {
8770                     return (CS_BAD_ATTRIBUTE);
8771                 }
8772 
8773                 fnc->client_handle = client->client_handle;
8774                 fnc->num_clients = sp->num_clients;
8775                 mutex_exit(&sp->client_lock);
8776                 break;
8777             case CS_GET_NEXT_FLAG:
8778                 if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8779                     sn = GET_CLIENT_SOCKET(fnc->client_handle);
8780 
8781                     if ((sp = cs_get_sp(sn)) == NULL)
8782                         return (CS_BAD_SOCKET);
8783 
8784                     mutex_enter(&sp->client_lock);
8785                     if ((client = cs_find_client(fnc->client_handle,
8786                                 &ret)) == NULL) {
8787                         mutex_exit(&sp->client_lock);
8788                         return (ret);
8789                     }
8790                     if ((client = client->next) == NULL) {
8791                         mutex_exit(&sp->client_lock);
8792                         sn++;
8793                         while (sn < cs_globals.max_socket_num) {
8794                             if ((sp = cs_get_sp(sn)) != NULL) {
8795                                 mutex_enter(&sp->client_lock);
8796                                 if ((client = sp->client_list) != NULL)
8797                                     break;
8798                                 mutex_exit(&sp->client_lock);
8799                             } /* if */
8800                             sn++;
8801                         } /* while */
8802 
8803                         if (sn == cs_globals.max_socket_num)
8804                             return (CS_NO_MORE_ITEMS);
8805                     } /* client = client->next */
8806 
8807                 } else if (fnc->Attributes &
8808                                         CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8809                     sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
8810                     if (sp == NULL)
8811                         return (CS_BAD_SOCKET);
8812                     mutex_enter(&sp->client_lock);
8813                     if ((client = cs_find_client(fnc->client_handle,
8814                                 &ret)) == NULL) {
8815                         mutex_exit(&sp->client_lock);
8816                         return (ret);
8817                     }
8818                     if ((client = client->next) == NULL) {
8819                         mutex_exit(&sp->client_lock);
8820                         return (CS_NO_MORE_ITEMS);
8821                     }
8822                 } else {
8823                     return (CS_BAD_ATTRIBUTE);
8824                 }
8825 
8826                 fnc->client_handle = client->client_handle;
8827                 fnc->num_clients = sp->num_clients;
8828                 mutex_exit(&sp->client_lock);
8829                 break;
8830             default:
8831                 ret = CS_BAD_ATTRIBUTE;
8832                 break;
8833 
8834         } /* switch */
8835 
8836         return (ret);
8837 }
8838 
8839 /*
8840  * cs_set_acc_attributes - converts Card Services endianness and
8841  *                              data ordering values to values
8842  *                              that Socket Services understands
8843  *
8844  *      calling: *sw - pointer to a set_window_t to set attributes in
8845  *               Attributes - CS attributes
8846  */
8847 static void
8848 cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
8849 {
8850         sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8851 
8852         switch (Attributes & WIN_ACC_ENDIAN_MASK) {
8853             case WIN_ACC_LITTLE_ENDIAN:
8854                 sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8855                 break;
8856             case WIN_ACC_BIG_ENDIAN:
8857                 sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
8858                 break;
8859             case WIN_ACC_NEVER_SWAP:
8860             default:
8861                 sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
8862                 break;
8863         } /* switch */
8864 
8865         switch (Attributes & WIN_ACC_ORDER_MASK) {
8866             case WIN_ACC_UNORDERED_OK:
8867                 sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
8868                 break;
8869             case WIN_ACC_MERGING_OK:
8870                 sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
8871                 break;
8872             case WIN_ACC_LOADCACHING_OK:
8873                 sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
8874                 break;
8875             case WIN_ACC_STORECACHING_OK:
8876                 sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
8877                 break;
8878             case WIN_ACC_STRICT_ORDER:
8879             default:
8880                 sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8881                 break;
8882         } /* switch */
8883 }