xref: /illumos-gate/usr/src/uts/common/pcmcia/cs/cs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * PCMCIA 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 defined(__i386) || defined(__amd64)
6930 	/*
6931 	 * Some adapters (PD67xx) can write-protect the CIS when the
6932 	 * socket is in memory mode
6933 	 */
6934 	if (client->present & CONFIG_OPTION_REG_PRESENT)
6935 	    csx_Put8(cis_handle, crt->cor_p, COR_SOFT_RESET);
6936 
6937 	if (cs_rq_delay)
6938 	    drv_usecwait(cs_rq_delay * 1000);
6939 #endif
6940 
6941 	if (client->present & CONFIG_OPTION_REG_PRESENT)
6942 	    csx_Put8(cis_handle, crt->cor_p, 0);
6943 
6944 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6945 	    mutex_exit(&sp->cis_lock);
6946 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6947 	    return (CS_BAD_SOCKET);
6948 	}
6949 
6950 	/*
6951 	 * Mark this client as not having a configuration.
6952 	 */
6953 	client->flags &= ~REQ_CONFIGURATION_DONE;
6954 
6955 	mutex_exit(&sp->cis_lock);
6956 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6957 
6958 	return (CS_SUCCESS);
6959 }
6960 
6961 /*
6962  * cs_modify_configuration - modifies a configuration established by
6963  *		RequestConfiguration; this is ModifyConfiguration
6964  *
6965  *	returns: CS_SUCCESS - if configuration sucessfully modified
6966  *		 CS_BAD_SOCKET - if Socket Services returns an error
6967  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6968  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
6969  *		 CS_NO_CARD - if no card in socket
6970  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
6971  *					are set
6972  *		 CS_BAD_VCC - if Vcc value is not supported by socket
6973  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
6974  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
6975  */
6976 static int
6977 cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
6978 {
6979 	cs_socket_t *sp;
6980 	client_t *client;
6981 	set_socket_t set_socket;
6982 	get_socket_t get_socket;
6983 	int error;
6984 	int client_lock_acquired;
6985 
6986 	/*
6987 	 * Check to see if this is the Socket Services client handle; if it
6988 	 *	is, we don't support SS using this call.
6989 	 */
6990 	if (CLIENT_HANDLE_IS_SS(client_handle))
6991 	    return (CS_UNSUPPORTED_FUNCTION);
6992 
6993 	/*
6994 	 * Get a pointer to this client's socket structure.
6995 	 */
6996 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6997 	    return (CS_BAD_SOCKET);
6998 
6999 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7000 
7001 	/*
7002 	 *  Make sure that this is a valid client handle.
7003 	 */
7004 	if (!(client = cs_find_client(client_handle, &error))) {
7005 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7006 	    return (error);
7007 	}
7008 
7009 	/*
7010 	 * If RequestConfiguration has not been done, we don't allow
7011 	 *	this call.
7012 	 */
7013 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7014 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7015 	    return (CS_BAD_HANDLE);
7016 	}
7017 
7018 	/*
7019 	 * If there's no card in the socket or the card in the socket is not
7020 	 *	for this client, then return an error.
7021 	 */
7022 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7023 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7024 	    return (CS_NO_CARD);
7025 	}
7026 
7027 	/*
7028 	 * Get the current socket parameters so that we can modify them.
7029 	 */
7030 	get_socket.socket = sp->socket_num;
7031 
7032 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
7033 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7034 	    return (CS_BAD_SOCKET);
7035 	}
7036 
7037 #ifdef	CS_DEBUG
7038 	if (cs_debug > 0)
7039 	    cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
7040 				"client->irq_alloc.irq 0x%x "
7041 				"get_socket.IRQRouting 0x%x\n",
7042 				sp->socket_num, (int)client->irq_alloc.irq,
7043 				get_socket.IRQRouting);
7044 #endif
7045 
7046 	set_socket.socket = sp->socket_num;
7047 	set_socket.SCIntMask = get_socket.SCIntMask;
7048 	set_socket.CtlInd = get_socket.CtlInd;
7049 	set_socket.State = 0;	/* don't reset latched values */
7050 	set_socket.IFType = get_socket.IFType;
7051 
7052 	set_socket.IREQRouting = get_socket.IRQRouting;
7053 
7054 	/*
7055 	 * Modify the IRQ routing if the client wants it modified.
7056 	 */
7057 	if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
7058 	    set_socket.IREQRouting &= ~IRQ_ENABLE;
7059 
7060 	    if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
7061 			(client->present & CONFIG_OPTION_REG_PRESENT)) {
7062 		config_regs_t *crt = &client->config_regs;
7063 		acc_handle_t cis_handle;
7064 		uint32_t newoffset = client->config_regs_offset;
7065 
7066 		/*
7067 		 * Get a pointer to a window that contains the configuration
7068 		 *	registers.
7069 		 */
7070 		if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7071 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
7072 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7073 		    cmn_err(CE_CONT,
7074 			"cs_modify_configuration: socket %d can't init "
7075 			"CIS window\n", sp->socket_num);
7076 		    return (CS_GENERAL_FAILURE);
7077 		} /* cs_init_cis_window */
7078 
7079 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
7080 
7081 		if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7082 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
7083 
7084 #ifdef  CS_DEBUG
7085 		if (cs_debug > 0)
7086 			cmn_err(CE_CONT, "cs_modify_configuration:"
7087 			    " cor_p=0x%x cor=0x%x\n",
7088 			    crt->cor_p, crt->cor);
7089 #endif
7090 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
7091 
7092 	    } /* CW_MULTI_FUNCTION_CIS */
7093 
7094 	    if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7095 		set_socket.IREQRouting |= IRQ_ENABLE;
7096 
7097 	} /* CONF_IRQ_CHANGE_VALID */
7098 
7099 	/*
7100 	 * Modify the voltage levels that the client specifies.
7101 	 */
7102 	set_socket.VccLevel = get_socket.VccLevel;
7103 
7104 	if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
7105 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
7106 					&set_socket.Vpp1Level) != CS_SUCCESS) {
7107 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7108 		return (CS_BAD_VPP);
7109 	    }
7110 	} else {
7111 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
7112 	}
7113 
7114 	if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
7115 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
7116 					&set_socket.Vpp2Level) != CS_SUCCESS) {
7117 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7118 		return (CS_BAD_VPP);
7119 	    }
7120 	} else {
7121 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
7122 	}
7123 
7124 	/*
7125 	 * Setup the modified socket configuration.
7126 	 */
7127 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
7128 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7129 	    return (CS_BAD_SOCKET);
7130 	}
7131 
7132 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7133 	return (CS_SUCCESS);
7134 }
7135 
7136 /*
7137  * cs_access_configuration_register - provides a client access to the card's
7138  *		configuration registers; this is AccessConfigurationRegister
7139  *
7140  *	returns: CS_SUCCESS - if register accessed successfully
7141  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7142  *		 CS_BAD_ARGS - if arguments are out of range
7143  *		 CS_NO_CARD - if no card in socket
7144  *		 CS_BAD_BASE - if no config registers base address
7145  *		 CS_UNSUPPORTED_MODE - if no RequestConfiguration has
7146  *				been done yet
7147  */
7148 static int
7149 cs_access_configuration_register(client_handle_t client_handle,
7150 						access_config_reg_t *acr)
7151 {
7152 	cs_socket_t *sp;
7153 	client_t *client;
7154 	acc_handle_t cis_handle;
7155 	int error;
7156 	uint32_t newoffset;
7157 	int client_lock_acquired;
7158 
7159 	/*
7160 	 * Check to see if this is the Socket Services client handle; if it
7161 	 *	is, we don't support SS using this call.
7162 	 */
7163 	if (CLIENT_HANDLE_IS_SS(client_handle))
7164 	    return (CS_UNSUPPORTED_FUNCTION);
7165 
7166 	/*
7167 	 * Make sure that the specifed offset is in range.
7168 	 */
7169 	if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
7170 	    return (CS_BAD_ARGS);
7171 
7172 	/*
7173 	 * Get a pointer to this client's socket structure.
7174 	 */
7175 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7176 	    return (CS_BAD_SOCKET);
7177 
7178 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7179 
7180 	/*
7181 	 *  Make sure that this is a valid client handle.
7182 	 */
7183 	if (!(client = cs_find_client(client_handle, &error))) {
7184 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7185 	    return (error);
7186 	}
7187 
7188 	/*
7189 	 * If there's no card in the socket or the card in the socket is not
7190 	 *	for this client, then return an error.
7191 	 */
7192 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7193 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7194 	    return (CS_NO_CARD);
7195 	}
7196 
7197 	/*
7198 	 * If RequestConfiguration has not been done, we don't allow
7199 	 *	this call.
7200 	 */
7201 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7202 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7203 	    return (CS_UNSUPPORTED_MODE);
7204 	}
7205 
7206 	mutex_enter(&sp->cis_lock);
7207 
7208 	/*
7209 	 * Get a pointer to the CIS window
7210 	 */
7211 	newoffset = client->config_regs_offset + acr->Offset;
7212 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7213 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
7214 	    mutex_exit(&sp->cis_lock);
7215 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7216 	    cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
7217 							sp->socket_num);
7218 	    return (CS_GENERAL_FAILURE);
7219 	}
7220 
7221 	/*
7222 	 * Create the address for the config register that the client
7223 	 *	wants to access.
7224 	 */
7225 	mutex_enter(&sp->lock);
7226 
7227 #ifdef	CS_DEBUG
7228 	if (cs_debug > 1) {
7229 	    cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
7230 		"Offset 0x%x newoffset 0x%x\n",
7231 		(int)client->config_regs_offset,
7232 		(int)acr->Offset, newoffset);
7233 	}
7234 #endif
7235 
7236 	/*
7237 	 * Determine what the client wants us to do.  The client is
7238 	 *	allowed to specify any valid offset, even if it would
7239 	 *	cause an unimplemented configuration register to be
7240 	 *	accessed.
7241 	 */
7242 	error = CS_SUCCESS;
7243 	switch (acr->Action) {
7244 	    case CONFIG_REG_READ:
7245 		acr->Value = csx_Get8(cis_handle, newoffset);
7246 		break;
7247 	    case CONFIG_REG_WRITE:
7248 		csx_Put8(cis_handle, newoffset, acr->Value);
7249 		break;
7250 	    default:
7251 		error = CS_BAD_ARGS;
7252 		break;
7253 	} /* switch */
7254 
7255 	mutex_exit(&sp->lock);
7256 	mutex_exit(&sp->cis_lock);
7257 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7258 
7259 	return (error);
7260 }
7261 
7262 /*
7263  * ==== RESET and general info functions ====
7264  */
7265 
7266 /*
7267  * cs_reset_function - RESET the requested function on the card; this
7268  *			is ResetFunction
7269  *
7270  *    Note: We don't support this functionality yet, and the standard
7271  *		says it's OK to reutrn CS_IN_USE if we can't do this
7272  *		operation.
7273  */
7274 /*ARGSUSED*/
7275 static int
7276 cs_reset_function(client_handle_t ch, reset_function_t *rf)
7277 {
7278 	return (CS_IN_USE);
7279 }
7280 
7281 /*
7282  * cs_get_configuration_info - return configuration info for the passed
7283  *				socket and function number to the caller;
7284  *				this is GetConfigurationInfo
7285  */
7286 /*ARGSUSED*/
7287 static int
7288 cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
7289 {
7290 	cs_socket_t *sp;
7291 	uint32_t fn;
7292 	client_t *client;
7293 	int client_lock_acquired;
7294 
7295 	/*
7296 	 * Get a pointer to this client's socket structure.
7297 	 */
7298 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
7299 	    return (CS_BAD_SOCKET);
7300 
7301 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7302 	mutex_enter(&sp->lock);
7303 
7304 	fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
7305 
7306 	client = sp->client_list;
7307 	while (client) {
7308 
7309 	    if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
7310 
7311 		/*
7312 		 * If there's no card in the socket or the card in the
7313 		 *	socket is not for this client, then return
7314 		 *	an error.
7315 		 */
7316 		if (!(client->flags & CLIENT_CARD_INSERTED)) {
7317 		    mutex_exit(&sp->lock);
7318 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7319 		    return (CS_NO_CARD);
7320 		}
7321 
7322 		mutex_exit(&sp->lock);
7323 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7324 		return (CS_SUCCESS);
7325 
7326 	    } /* GET_CLIENT_FUNCTION == fn */
7327 
7328 	    client = client->next;
7329 	} /* while (client) */
7330 
7331 	mutex_exit(&sp->lock);
7332 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7333 
7334 	return (CS_BAD_SOCKET);
7335 }
7336 
7337 /*
7338  * cs_get_cardservices_info - return info about Card Services to the
7339  *	caller; this is GetCardServicesInfo
7340  */
7341 /*ARGSUSED*/
7342 static int
7343 cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
7344 {
7345 	gcsi->Signature[0] = 'C';
7346 	gcsi->Signature[1] = 'S';
7347 	gcsi->NumSockets = cs_globals.num_sockets;
7348 	gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
7349 	gcsi->CSLevel = CS_VERSION;
7350 	gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
7351 	(void) strncpy(gcsi->VendorString,
7352 					CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
7353 					CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
7354 
7355 	return (CS_SUCCESS);
7356 }
7357 
7358 /*
7359  * cs_get_physical_adapter_info - returns information about the requested
7360  *					physical adapter; this is
7361  *					GetPhysicalAdapterInfo
7362  *
7363  *	calling: client_handle_t:
7364  *			NULL - use map_log_socket_t->LogSocket member
7365  *				to specify logical socket number
7366  *			!NULL - extract logical socket number from
7367  *				client_handle_t
7368  *
7369  *	returns: CS_SUCCESS
7370  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7371  *					socket number is specified in
7372  *					map_log_socket_t->LogSocket
7373  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7374  *					client handle is specified
7375  */
7376 static int
7377 cs_get_physical_adapter_info(client_handle_t ch,
7378 					get_physical_adapter_info_t *gpai)
7379 {
7380 	cs_socket_t *sp;
7381 	int client_lock_acquired;
7382 
7383 	if (ch == NULL)
7384 	    gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
7385 	else
7386 	    gpai->PhySocket = GET_CLIENT_SOCKET(ch);
7387 
7388 	/*
7389 	 * Determine if the passed socket number is valid or not.
7390 	 */
7391 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
7392 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7393 
7394 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7395 
7396 	/*
7397 	 * If we were passed a client handle, determine if it's valid or not.
7398 	 */
7399 	if (ch != NULL) {
7400 	    if (cs_find_client(ch, NULL) == NULL) {
7401 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7402 		return (CS_BAD_HANDLE);
7403 	    } /* cs_find_client */
7404 	} /* ch != NULL */
7405 
7406 	gpai->flags = sp->adapter.flags;
7407 	(void) strcpy(gpai->name, sp->adapter.name);
7408 	gpai->major = sp->adapter.major;
7409 	gpai->minor = sp->adapter.minor;
7410 	gpai->instance = sp->adapter.instance;
7411 	gpai->number = sp->adapter.number;
7412 	gpai->num_sockets = sp->adapter.num_sockets;
7413 	gpai->first_socket = sp->adapter.first_socket;
7414 
7415 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7416 
7417 	return (CS_SUCCESS);
7418 }
7419 
7420 /*
7421  * ==== general functions ====
7422  */
7423 
7424 /*
7425  * cs_map_log_socket - returns the physical socket number associated with
7426  *			either the passed client handle or the passed
7427  *			logical socket number; this is MapLogSocket
7428  *
7429  *	calling: client_handle_t:
7430  *			NULL - use map_log_socket_t->LogSocket member
7431  *				to specify logical socket number
7432  *			!NULL - extract logical socket number from
7433  *				client_handle_t
7434  *
7435  *	returns: CS_SUCCESS
7436  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7437  *					socket number is specified in
7438  *					map_log_socket_t->LogSocket
7439  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7440  *					client handle is specified
7441  *
7442  * Note: We provide this function since the instance number of a client
7443  *		driver doesn't necessary correspond to the physical
7444  *		socket number
7445  */
7446 static int
7447 cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
7448 {
7449 	cs_socket_t *sp;
7450 	int client_lock_acquired;
7451 
7452 	if (ch == NULL)
7453 	    mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
7454 	else
7455 	    mls->PhySocket = GET_CLIENT_SOCKET(ch);
7456 
7457 	/*
7458 	 * Determine if the passed socket number is valid or not.
7459 	 */
7460 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
7461 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7462 
7463 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7464 
7465 	/*
7466 	 * If we were passed a client handle, determine if it's valid or not.
7467 	 */
7468 	if (ch != NULL) {
7469 	    if (cs_find_client(ch, NULL) == NULL) {
7470 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7471 		return (CS_BAD_HANDLE);
7472 	    } /* cs_find_client */
7473 	} /* ch != NULL */
7474 
7475 	mls->PhyAdapter = sp->adapter.number;
7476 
7477 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7478 
7479 	return (CS_SUCCESS);
7480 }
7481 
7482 /*
7483  * cs_convert_speed - convers nS to devspeed and devspeed to nS
7484  *
7485  * The actual function is is in the CIS parser module; this
7486  *	is only a wrapper.
7487  */
7488 static int
7489 cs_convert_speed(convert_speed_t *cs)
7490 {
7491 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
7492 }
7493 
7494 /*
7495  * cs_convert_size - converts a devsize value to a size in bytes value
7496  *			or a size in bytes value to a devsize value
7497  *
7498  * The actual function is is in the CIS parser module; this
7499  *	is only a wrapper.
7500  */
7501 static int
7502 cs_convert_size(convert_size_t *cs)
7503 {
7504 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
7505 }
7506 
7507 /*
7508  * cs_convert_powerlevel - converts a power level in tenths of a volt
7509  *			to a power table entry for the specified socket
7510  *
7511  *	returns: CS_SUCCESS - if volts converted to a valid power level
7512  *		 CS_BAD_ADAPTER - if SS_InquireAdapter fails
7513  *		 CS_BAD_ARGS - if volts are not supported on this socket
7514  *				and adapter
7515  */
7516 static int
7517 cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
7518 {
7519 	inquire_adapter_t inquire_adapter;
7520 	int i;
7521 
7522 #ifdef	lint
7523 	if (sn == 0)
7524 	    panic("lint panic");
7525 #endif
7526 
7527 	*pl = 0;
7528 
7529 	if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
7530 	    return (CS_BAD_ADAPTER);
7531 
7532 	for (i = 0; (i < inquire_adapter.NumPower); i++) {
7533 	    if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
7534 		(inquire_adapter.power_entry[i].PowerLevel == volts)) {
7535 		*pl = i;
7536 		return (CS_SUCCESS);
7537 	    }
7538 	}
7539 
7540 	return (CS_BAD_ARGS);
7541 }
7542 
7543 /*
7544  * cs_event2text - returns text string(s) associated with the event; this
7545  *			function supports the Event2Text CS call.
7546  *
7547  *	calling: event2text_t * - pointer to event2text struct
7548  *		 int event_source - specifies event type in event2text_t:
7549  *					0 - SS event
7550  *					1 - CS event
7551  *
7552  *	returns: CS_SUCCESS
7553  */
7554 static int
7555 cs_event2text(event2text_t *e2t, int event_source)
7556 {
7557 	event_t event;
7558 	char *sepchar = "|";
7559 
7560 	/*
7561 	 * If event_source is 0, this is a SS event
7562 	 */
7563 	if (!event_source) {
7564 	    for (event = 0; event < MAX_SS_EVENTS; event++) {
7565 		if (cs_ss_event_text[event].ss_event == e2t->event) {
7566 		    (void) strcpy(e2t->text, cs_ss_event_text[event].text);
7567 		    return (CS_SUCCESS);
7568 		}
7569 	    }
7570 	    (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
7571 	    return (CS_SUCCESS);
7572 	} else {
7573 		/*
7574 		 * This is a CS event
7575 		 */
7576 	    e2t->text[0] = '\0';
7577 	    for (event = 0; event < MAX_CS_EVENTS; event++) {
7578 		if (cs_ss_event_text[event].cs_event & e2t->event) {
7579 		    (void) strcat(e2t->text, cs_ss_event_text[event].text);
7580 		    (void) strcat(e2t->text, sepchar);
7581 		} /* if (cs_ss_event_text) */
7582 	    } /* for (event) */
7583 	    if (e2t->text[0])
7584 		e2t->text[strlen(e2t->text)-1] = NULL;
7585 	} /* if (!event_source) */
7586 
7587 	return (CS_SUCCESS);
7588 }
7589 
7590 /*
7591  * cs_error2text - returns a pointer to a text string containing the name
7592  *			of the passed Card Services function or return code
7593  *
7594  *	This function supports the Error2Text CS call.
7595  */
7596 static char *
7597 cs_error2text(int function, int type)
7598 {
7599 	cs_csfunc2text_strings_t *cfs;
7600 	int end_marker;
7601 
7602 	if (type == CSFUN2TEXT_FUNCTION) {
7603 	    cfs = cs_csfunc2text_funcstrings;
7604 	    end_marker = CSFuncListEnd;
7605 	} else {
7606 	    cfs = cs_csfunc2text_returnstrings;
7607 	    end_marker = CS_ERRORLIST_END;
7608 	}
7609 
7610 	while (cfs->item != end_marker) {
7611 	    if (cfs->item == function)
7612 		return (cfs->text);
7613 	    cfs++;
7614 	}
7615 
7616 	return (cfs->text);
7617 }
7618 
7619 /*
7620  * cs_make_device_node - creates/removes device nodes on a client's behalf;
7621  *				this is MakeDeviceNode and RemoveDeviceNode
7622  *
7623  *	returns: CS_SUCCESS - if all device nodes successfully created/removed
7624  *		 CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
7625  *				is REMOVAL_ALL_DEVICES
7626  *		 CS_BAD_ARGS - if an invalid Action code is specified
7627  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7628  *		 CS_OUT_OF_RESOURCE - if can't create/remove device node
7629  */
7630 static int
7631 cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
7632 {
7633 	cs_socket_t *sp;
7634 	client_t *client;
7635 	ss_make_device_node_t ss_make_device_node;
7636 	int error, i;
7637 	int client_lock_acquired;
7638 
7639 	/*
7640 	 * Check to see if this is the Socket Services client handle; if it
7641 	 *	is, we don't support SS using this call.
7642 	 */
7643 	if (CLIENT_HANDLE_IS_SS(client_handle))
7644 	    return (CS_UNSUPPORTED_FUNCTION);
7645 
7646 	/*
7647 	 * Get a pointer to this client's socket structure.
7648 	 */
7649 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7650 	    return (CS_BAD_SOCKET);
7651 
7652 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7653 
7654 	/*
7655 	 *  Make sure that this is a valid client handle.
7656 	 */
7657 	if (!(client = cs_find_client(client_handle, &error))) {
7658 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7659 	    return (error);
7660 	}
7661 
7662 #ifdef	XXX
7663 	/*
7664 	 * If there's no card in the socket or the card in the socket is not
7665 	 *	for this client, then return an error.
7666 	 */
7667 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7668 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7669 	    return (CS_NO_CARD);
7670 	}
7671 #endif
7672 
7673 	/*
7674 	 * Setup the client's dip, since we use it later on.
7675 	 */
7676 	ss_make_device_node.dip = client->dip;
7677 
7678 	/*
7679 	 * Make sure that we're being given a valid Action.  Set the default
7680 	 *	error code as well.
7681 	 */
7682 	error = CS_BAD_ARGS;	/* for default case */
7683 	switch (mdn->Action) {
7684 	    case CREATE_DEVICE_NODE:
7685 	    case REMOVE_DEVICE_NODE:
7686 		break;
7687 	    case REMOVAL_ALL_DEVICE_NODES:
7688 		if (mdn->NumDevNodes) {
7689 		    error = CS_BAD_ATTRIBUTE;
7690 		} else {
7691 		    ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7692 		    ss_make_device_node.name = NULL;
7693 		    SocketServices(CSInitDev, &ss_make_device_node);
7694 		    error = CS_SUCCESS;
7695 		}
7696 		/* fall-through case */
7697 	    default:
7698 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7699 		return (error);
7700 		/* NOTREACHED */
7701 	} /* switch */
7702 
7703 	/*
7704 	 * Loop through the device node descriptions and create or destroy
7705 	 *	the device node.
7706 	 */
7707 	for (i = 0; i < mdn->NumDevNodes; i++) {
7708 	    devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
7709 
7710 	    ss_make_device_node.name = devnode_desc->name;
7711 	    ss_make_device_node.spec_type = devnode_desc->spec_type;
7712 	    ss_make_device_node.minor_num = devnode_desc->minor_num;
7713 	    ss_make_device_node.node_type = devnode_desc->node_type;
7714 
7715 	/*
7716 	 * Set the appropriate flag for the action that we want
7717 	 *	SS to perform. Note that if we ever OR-in the flag
7718 	 *	here, we need to be sure to clear the flags member
7719 	 *	since we sometimes OR-in other flags below.
7720 	 */
7721 	    if (mdn->Action == CREATE_DEVICE_NODE) {
7722 		ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
7723 	    } else {
7724 		ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7725 	    }
7726 
7727 	/*
7728 	 * If this is not the last device to process, then we need
7729 	 *	to tell SS that more device process requests are on
7730 	 *	their way after this one.
7731 	 */
7732 	    if (i < (mdn->NumDevNodes - 1))
7733 		ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
7734 
7735 	    if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
7736 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7737 		return (CS_OUT_OF_RESOURCE);
7738 	    } /* CSInitDev */
7739 	} /* for (mdn->NumDevNodes) */
7740 
7741 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7742 	return (CS_SUCCESS);
7743 }
7744 
7745 /*
7746  * cs_remove_device_node - removes device nodes
7747  *
7748  *	(see cs_make_device_node for a description of the calling
7749  *		and return parameters)
7750  */
7751 static int
7752 cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
7753 {
7754 
7755 	/*
7756 	 * XXX - Note the assumption here that the make_device_node_t and
7757 	 *	remove_device_node_t structures are identical.
7758 	 */
7759 	return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
7760 }
7761 
7762 /*
7763  * cs_ddi_info - this function is used by clients that need to support
7764  *			the xxx_getinfo function; this is CS_DDI_Info
7765  */
7766 static int
7767 cs_ddi_info(cs_ddi_info_t *cdi)
7768 {
7769 	cs_socket_t *sp;
7770 	client_t *client;
7771 	int client_lock_acquired;
7772 
7773 	if (cdi->driver_name == NULL)
7774 	    return (CS_BAD_ATTRIBUTE);
7775 
7776 #ifdef	CS_DEBUG
7777 	if (cs_debug > 0) {
7778 	    cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
7779 					(int)cdi->Socket, cdi->driver_name);
7780 	}
7781 #endif
7782 
7783 	/*
7784 	 * Check to see if the socket number is in range - the system
7785 	 *	framework may cause a client driver to call us with
7786 	 *	a socket number that used to be present but isn't
7787 	 *	anymore. This is not a bug, and it's OK to return
7788 	 *	an error if the socket number is out of range.
7789 	 */
7790 	if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
7791 
7792 #ifdef	CS_DEBUG
7793 	    if (cs_debug > 0) {
7794 		cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
7795 						"SOCKET IS OUT OF RANGE\n",
7796 							(int)cdi->Socket,
7797 							cdi->driver_name);
7798 	    }
7799 #endif
7800 
7801 	    return (CS_BAD_SOCKET);
7802 	} /* if (!CHECK_SOCKET_NUM) */
7803 
7804 	/*
7805 	 * Get a pointer to this client's socket structure.
7806 	 */
7807 	if ((sp = cs_get_sp(cdi->Socket)) == NULL)
7808 	    return (CS_BAD_SOCKET);
7809 
7810 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7811 
7812 	client = sp->client_list;
7813 	while (client) {
7814 
7815 #ifdef	CS_DEBUG
7816 	    if (cs_debug > 0) {
7817 		cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
7818 							"handle 0x%x\n",
7819 						(int)cdi->Socket,
7820 						client->driver_name,
7821 						(int)client->client_handle);
7822 	    }
7823 #endif
7824 
7825 	    if (client->driver_name != NULL) {
7826 		if (!(strcmp(client->driver_name, cdi->driver_name))) {
7827 		    cdi->dip = client->dip;
7828 		    cdi->instance = client->instance;
7829 
7830 #ifdef	CS_DEBUG
7831 		    if (cs_debug > 0) {
7832 			cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
7833 						"instance %d handle 0x%x\n",
7834 					client->driver_name, client->instance,
7835 					(int)client->client_handle);
7836 		    }
7837 #endif
7838 
7839 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7840 		    return (CS_SUCCESS);
7841 		} /* strcmp */
7842 	    } /* driver_name != NULL */
7843 	    client = client->next;
7844 	} /* while (client) */
7845 
7846 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7847 	return (CS_BAD_SOCKET);
7848 }
7849 
7850 /*
7851  * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
7852  */
7853 static int
7854 cs_sys_ctl(cs_sys_ctl_t *csc)
7855 {
7856 	cs_socket_t *sp;
7857 	client_t *cp;
7858 	int sn, ret = CS_UNSUPPORTED_MODE;
7859 
7860 	switch (csc->Action) {
7861 	    case CS_SYS_CTL_SEND_EVENT:
7862 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7863 		    sn = CS_GET_SOCKET_NUMBER(csc->Socket);
7864 		else
7865 		    sn = GET_CLIENT_SOCKET(csc->client_handle);
7866 		if ((sp = cs_get_sp(sn)) == NULL)
7867 		    return (CS_BAD_SOCKET);
7868 		mutex_enter(&sp->client_lock);
7869 		mutex_enter(&sp->lock);
7870 		csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
7871 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7872 		    sp->events |= csc->Events;
7873 		if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
7874 		    if ((cp = cs_find_client(csc->client_handle, &ret)) ==
7875 									NULL) {
7876 			mutex_exit(&sp->lock);
7877 			mutex_exit(&sp->client_lock);
7878 			return (ret);
7879 		    } /* cs_find_client */
7880 			/*
7881 			 * Setup the events that we want to send to the client.
7882 			 */
7883 		    cp->events |= (csc->Events &
7884 					(cp->event_mask | cp->global_mask));
7885 		} /* CS_SYS_CTL_EVENT_CLIENT */
7886 
7887 		if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
7888 		    sp->thread_state |= SOCKET_WAIT_SYNC;
7889 		    mutex_exit(&sp->lock);
7890 		    cv_broadcast(&sp->thread_cv);
7891 		    cv_wait(&sp->caller_cv, &sp->client_lock);
7892 		} else {
7893 		    mutex_exit(&sp->lock);
7894 		    cv_broadcast(&sp->thread_cv);
7895 		} /* CS_SYS_CTL_WAIT_SYNC */
7896 		mutex_exit(&sp->client_lock);
7897 		ret = CS_SUCCESS;
7898 		break;
7899 	    default:
7900 		break;
7901 	} /* switch */
7902 
7903 	return (ret);
7904 }
7905 
7906 /*
7907  * cs_get_sp - returns pointer to per-socket structure for passed
7908  *		socket number
7909  *
7910  *	return:	(cs_socket_t *) - pointer to socket structure
7911  *		NULL - invalid socket number passed in
7912  */
7913 static cs_socket_t *
7914 cs_get_sp(uint32_t sn)
7915 {
7916 	cs_socket_t *sp = cs_globals.sp;
7917 
7918 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7919 	    return (NULL);
7920 
7921 	if ((sp = cs_find_sp(sn)) == NULL)
7922 	    return (NULL);
7923 
7924 	if (sp->flags & SOCKET_IS_VALID)
7925 	    return (sp);
7926 
7927 	return (NULL);
7928 }
7929 
7930 /*
7931  * cs_find_sp - searches socket list and returns pointer to passed socket
7932  *			number
7933  *
7934  *	return:	(cs_socket_t *) - pointer to socket structure if found
7935  *		NULL - socket not found
7936  */
7937 static cs_socket_t *
7938 cs_find_sp(uint32_t sn)
7939 {
7940 	cs_socket_t *sp = cs_globals.sp;
7941 
7942 	while (sp) {
7943 	    if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
7944 		return (sp);
7945 	    sp = sp->next;
7946 	} /* while */
7947 
7948 	return (NULL);
7949 }
7950 
7951 /*
7952  * cs_add_socket - add a socket
7953  *
7954  *	call:	sn - socket number to add
7955  *
7956  *	return:	CS_SUCCESS - operation sucessful
7957  *		CS_BAD_SOCKET - unable to add socket
7958  *		CS_BAD_WINDOW - unable to get CIS window for socket
7959  *
7960  * We get called here once for each socket that the framework wants to
7961  *	add. When we are called, the framework guarentees that until we
7962  *	complete this routine, no other adapter instances will be allowed
7963  *	to attach and thus no other PCE_ADD_SOCKET events will occur.
7964  *	It is safe to call SS_InquireAdapter to get the number of
7965  *	windows that the framework currently knows about.
7966  */
7967 static uint32_t
7968 cs_add_socket(uint32_t sn)
7969 {
7970 	cs_socket_t *sp;
7971 	sservice_t sservice;
7972 	get_cookies_and_dip_t *gcad;
7973 	win_req_t win_req;
7974 	convert_speed_t convert_speed;
7975 	set_socket_t set_socket;
7976 	cs_window_t *cw;
7977 	inquire_adapter_t inquire_adapter;
7978 	inquire_window_t inquire_window;
7979 	int ret, added_windows;
7980 
7981 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7982 	    return (CS_BAD_SOCKET);
7983 
7984 	/*
7985 	 * See if this socket has already been added - if it has, we
7986 	 *	fail this. If we can't find the socket, then allocate
7987 	 *	a new socket structure. If we do find the socket, then
7988 	 *	check to see if it's already added; if it is, then
7989 	 *	this is an error and return CS_BAD_SOCKET; if not,
7990 	 *	then traverse the socket structure list and add this
7991 	 *	next socket strcture to the end of the list.
7992 	 * XXX What about locking this list while we update it? Is
7993 	 *	that necessary since we're using the SOCKET_IS_VALID
7994 	 *	flag and since we never delete a socket from the
7995 	 *	list once it's been added?
7996 	 */
7997 	if ((sp = cs_find_sp(sn)) == NULL) {
7998 	    cs_socket_t *spp = cs_globals.sp;
7999 
8000 	    sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
8001 
8002 	    if (cs_globals.sp == NULL)
8003 		cs_globals.sp = sp;
8004 	    else
8005 		while (spp) {
8006 		    if (spp->next == NULL) {
8007 			spp->next = sp;
8008 			break;
8009 		    } /* if */
8010 		    spp = spp->next;
8011 		} /* while */
8012 
8013 	} else {
8014 	    if (sp->flags & SOCKET_IS_VALID)
8015 		return (CS_BAD_SOCKET);
8016 	} /* cs_find_sp */
8017 
8018 	/*
8019 	 * Setup the socket number
8020 	 */
8021 	sp->socket_num = sn;
8022 
8023 	/*
8024 	 * Find out how many windows the framework knows about
8025 	 *	so far. If this number of windows is greater
8026 	 *	than our current window count, bump up our
8027 	 *	current window count.
8028 	 * XXX Note that there is a BIG assumption here and that
8029 	 *	is that once the framework tells us that it has
8030 	 *	a window (as reflected in the NumWindows
8031 	 *	value) it can NEVER remove that window.
8032 	 *	When we really get the drop socket and drop
8033 	 *	window mechanism working correctly, we'll have
8034 	 *	to revisit this.
8035 	 */
8036 	SocketServices(SS_InquireAdapter, &inquire_adapter);
8037 
8038 	mutex_enter(&cs_globals.window_lock);
8039 	added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
8040 	if (added_windows > 0) {
8041 	    if (cs_add_windows(added_windows,
8042 				cs_globals.num_windows) != CS_SUCCESS) {
8043 		mutex_exit(&cs_globals.window_lock);
8044 		return (CS_BAD_WINDOW);
8045 	    } /* cs_add_windows */
8046 
8047 	    cs_globals.num_windows = inquire_adapter.NumWindows;
8048 
8049 	} /* if (added_windows) */
8050 
8051 	/*
8052 	 * Find a window that we can use for this socket's CIS window.
8053 	 */
8054 	sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8055 
8056 	convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
8057 	convert_speed.nS = CIS_DEFAULT_SPEED;
8058 	(void) cs_convert_speed(&convert_speed);
8059 
8060 	win_req.win_params.AccessSpeed = convert_speed.devspeed;
8061 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
8062 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
8063 	win_req.Base.base = 0;
8064 	win_req.Size = 0;
8065 
8066 	if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
8067 					&sp->cis_win_num)) != CS_SUCCESS) {
8068 	    mutex_exit(&cs_globals.window_lock);
8069 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8070 	    cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
8071 						"window - error 0x%x\n",
8072 						sp->socket_num, ret);
8073 	    return (CS_BAD_WINDOW);
8074 	} /* cs_find_mem_window */
8075 
8076 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
8077 	    mutex_exit(&cs_globals.window_lock);
8078 	    return (CS_BAD_WINDOW);
8079 	}
8080 
8081 	inquire_window.window = sp->cis_win_num;
8082 	SocketServices(SS_InquireWindow, &inquire_window);
8083 
8084 	/*
8085 	 * If the CIS window is a variable sized window, then use
8086 	 *	the size that cs_find_mem_window returned to us,
8087 	 *	since this will be the minimum size that we can
8088 	 *	set this window to. If the CIS window is a fixed
8089 	 *	sized window, then use the system pagesize as the
8090 	 *	CIS window size.
8091 	 */
8092 	if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
8093 	    sp->cis_win_size = win_req.Size;
8094 	} else {
8095 	    sp->cis_win_size = PAGESIZE;
8096 	}
8097 
8098 	cw->state |= (CW_CIS | CW_ALLOCATED);
8099 	cw->socket_num = sp->socket_num;
8100 
8101 	mutex_exit(&cs_globals.window_lock);
8102 
8103 #if defined(CS_DEBUG)
8104 	    if (cs_debug > 1) {
8105 		cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
8106 					"size 0x%x\n", (int)sp->socket_num,
8107 					(int)sp->cis_win_num,
8108 					(int)sp->cis_win_size);
8109 	    }
8110 #endif
8111 
8112 	/*
8113 	 * Get the adapter information associated with this socket so
8114 	 *	that we can initialize the mutexes, condition variables,
8115 	 *	soft interrupt handler and per-socket adapter info.
8116 	 */
8117 	gcad = &sservice.get_cookies;
8118 	gcad->socket = sp->socket_num;
8119 	if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
8120 	    cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
8121 						"failure\n", sp->socket_num);
8122 	    return (CS_BAD_SOCKET);
8123 	} /* CSGetCookiesAndDip */
8124 
8125 	/*
8126 	 * Save the iblock and idev cookies for RegisterClient
8127 	 */
8128 	sp->iblk = gcad->iblock;
8129 	sp->idev = gcad->idevice;
8130 
8131 	/*
8132 	 * Setup the per-socket adapter info
8133 	 */
8134 	sp->adapter.flags = 0;
8135 	(void) strcpy(sp->adapter.name, gcad->adapter_info.name);
8136 	sp->adapter.major = gcad->adapter_info.major;
8137 	sp->adapter.minor = gcad->adapter_info.minor;
8138 	sp->adapter.instance = ddi_get_instance(gcad->dip);
8139 	sp->adapter.number = gcad->adapter_info.number;
8140 	sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
8141 	sp->adapter.first_socket = gcad->adapter_info.first_socket;
8142 
8143 	/* Setup for cs_event and cs_event_thread */
8144 	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
8145 	mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
8146 	mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
8147 
8148 	/* Setup for Socket Services work thread */
8149 	mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
8150 
8151 	sp->init_state |= SOCKET_INIT_STATE_MUTEX;
8152 
8153 	/* Setup for cs_event_thread */
8154 	cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
8155 	cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
8156 	cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
8157 
8158 	/* Setup for Socket Services work thread */
8159 	cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
8160 	cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
8161 
8162 	sp->init_state |= SOCKET_INIT_STATE_CV;
8163 
8164 	/*
8165 	 * If we haven't installed it yet, then install the soft interrupt
8166 	 *	handler and save away the softint id.
8167 	 */
8168 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
8169 	    if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
8170 						&sp->softint_id,
8171 						NULL, NULL,
8172 						cs_socket_event_softintr,
8173 						(caddr_t)NULL) != DDI_SUCCESS) {
8174 		    cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
8175 						"softintr\n", sp->socket_num);
8176 		    return (CS_BAD_SOCKET);
8177 	    } /* ddi_add_softintr */
8178 
8179 	    mutex_enter(&cs_globals.global_lock);
8180 	    cs_globals.softint_id = sp->softint_id;
8181 	    cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
8182 	    /* XXX this timer is hokey at best... */
8183 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
8184 		NULL, SOFTINT_TIMEOUT_TIME);
8185 	    mutex_exit(&cs_globals.global_lock);
8186 	} else {
8187 		/*
8188 		 * We've already added the soft interrupt handler, so just
8189 		 *	store away the softint id.
8190 		 */
8191 	    sp->softint_id = cs_globals.softint_id;
8192 	} /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
8193 
8194 	/*
8195 	 * While this next flag doesn't really describe a per-socket
8196 	 *	resource, we still set it for each socket.  When the soft
8197 	 *	interrupt handler finally gets removed in cs_deinit, this
8198 	 *	flag will get cleared.
8199 	 */
8200 	sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
8201 
8202 	/*
8203 	 * Socket Services defaults all sockets to power off and
8204 	 *	clears all event masks.  We want to receive at least
8205 	 *	card insertion events, so enable them.  Turn off power
8206 	 *	to the socket as well.  We will turn it on again when
8207 	 *	we get a card insertion event.
8208 	 */
8209 	sp->event_mask = CS_EVENT_CARD_INSERTION;
8210 	set_socket.socket = sp->socket_num;
8211 	set_socket.SCIntMask = SBM_CD;
8212 	set_socket.IREQRouting = 0;
8213 	set_socket.IFType = IF_MEMORY;
8214 	set_socket.CtlInd = 0; /* turn off controls and indicators */
8215 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
8216 
8217 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
8218 						&set_socket.VccLevel);
8219 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
8220 						&set_socket.Vpp1Level);
8221 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
8222 						&set_socket.Vpp2Level);
8223 
8224 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
8225 	    cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
8226 					"failure %d\n", sp->socket_num, ret);
8227 		return (CS_BAD_SOCKET);
8228 	} /* SS_SetSocket */
8229 
8230 	/*
8231 	 * The various socket-specific variables are now set up, so
8232 	 *	increment the global socket count and also mark the
8233 	 *	socket as available. We need to set this before we
8234 	 *	start any of the per-socket threads so that the threads
8235 	 *	can get a valid socket pointer when they start.
8236 	 */
8237 	mutex_enter(&cs_globals.global_lock);
8238 	cs_globals.num_sockets++;
8239 	cs_globals.max_socket_num =
8240 			max(cs_globals.max_socket_num, sp->socket_num + 1);
8241 	mutex_exit(&cs_globals.global_lock);
8242 	sp->flags = SOCKET_IS_VALID;
8243 
8244 	/*
8245 	 * Create the per-socket event handler thread.
8246 	 */
8247 	sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
8248 		(uintptr_t)sn);
8249 
8250 	mutex_enter(&sp->lock);
8251 	sp->init_state |= SOCKET_INIT_STATE_THREAD;
8252 	mutex_exit(&sp->lock);
8253 
8254 	/*
8255 	 * Create the per-socket Socket Services work thread.
8256 	 */
8257 	sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
8258 		(uintptr_t)sn);
8259 
8260 	mutex_enter(&sp->lock);
8261 	sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
8262 						SOCKET_INIT_STATE_READY);
8263 	sp->event_mask = CS_EVENT_CARD_INSERTION;
8264 	mutex_exit(&sp->lock);
8265 
8266 	return (CS_SUCCESS);
8267 }
8268 
8269 /*
8270  * cs_drop_socket - drop a socket
8271  *
8272  *	call:	sn - socket number to drop
8273  *
8274  *	return:	CS_SUCCESS - operation sucessful
8275  *		CS_BAD_SOCKET - unable to drop socket
8276  */
8277 /*ARGSUSED*/
8278 static uint32_t
8279 cs_drop_socket(uint32_t sn)
8280 {
8281 #ifdef	XXX
8282 	cs_socket_t *sp;
8283 
8284 	/*
8285 	 * Tell the socket event thread to exit and then wait for it
8286 	 *	to do so.
8287 	 */
8288 	mutex_enter(&sp->client_lock);
8289 	sp->thread_state |= SOCKET_THREAD_EXIT;
8290 	cv_broadcast(&sp->thread_cv);
8291 	cv_wait(&sp->caller_cv, &sp->client_lock);
8292 	mutex_exit(&sp->client_lock);
8293 
8294 	/*
8295 	 * Tell the socket SS thread to exit and then wait for it
8296 	 *	to do so.
8297 	 */
8298 
8299 	/*
8300 	 * Mark the socket as dropped.
8301 	 */
8302 	sp->flags &= ~SOCKET_IS_VALID;
8303 
8304 #endif	/* XXX */
8305 
8306 	/* XXX for now don't allow dropping sockets XXX */
8307 	return (CS_BAD_SOCKET);
8308 }
8309 
8310 /*
8311  * cs_get_socket - returns the socket and function numbers and a pointer
8312  *			to the socket structure
8313  *
8314  * calling:	client_handle_t client_handle - client handle to extract
8315  *						socket number from
8316  *		uint32_t *socket -  pointer to socket number to use if
8317  *					client_handle is for the SS client;
8318  *					this value will be filled in on
8319  *					return with the correct socket
8320  *					and function numbers if we
8321  *					return CS_SUCCESS
8322  *		uint32_t *function - pointer to return function number into
8323  *					if not NULL
8324  *		cs_socket_t **sp - pointer to a pointer where a pointer
8325  *					to the socket struct will be
8326  *					placed if this is non-NULL
8327  *		client_t **clp - pointer to a pointer where a pointer
8328  *					to the client struct will be
8329  *					placed if this is non-NULL
8330  *
8331  *    The socket and function numbers are derived as follows:
8332  *
8333  *	Client Type		Socket Number		Function Number
8334  *	PC card client		From client_handle	From client_handle
8335  *	Socket Services client	From *socket		From *socket
8336  *	CSI client		From client_handle	From *socket
8337  */
8338 static uint32_t
8339 cs_get_socket(client_handle_t client_handle, uint32_t *socket,
8340     uint32_t *function, cs_socket_t **csp, client_t **clp)
8341 {
8342 	cs_socket_t *sp;
8343 	client_t *client;
8344 	uint32_t sn, fn;
8345 	int ret;
8346 
8347 	sn = *socket;
8348 
8349 	/*
8350 	 * If this is the Socket Services client, then return the
8351 	 *	socket and function numbers specified in the passed
8352 	 *	socket number parameter, otherwise extract the socket
8353 	 *	and function numbers from the client handle.
8354 	 */
8355 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
8356 	    fn = CS_GET_FUNCTION_NUMBER(sn);
8357 	    sn = CS_GET_SOCKET_NUMBER(sn);
8358 	} else {
8359 	    fn = GET_CLIENT_FUNCTION(client_handle);
8360 	    sn = GET_CLIENT_SOCKET(client_handle);
8361 	}
8362 
8363 	/*
8364 	 * Check to be sure that the socket number is in range
8365 	 */
8366 	if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
8367 	    return (CS_BAD_SOCKET);
8368 
8369 	if ((sp = cs_get_sp(sn)) == NULL)
8370 	    return (CS_BAD_SOCKET);
8371 
8372 	/*
8373 	 * If we were given a pointer, then fill it in with a pointer
8374 	 *	to this socket.
8375 	 */
8376 	if (csp)
8377 	    *csp = sp;
8378 
8379 	/*
8380 	 * Search for the client; if it's not found, return an error.
8381 	 */
8382 	mutex_enter(&sp->lock);
8383 	if (!(client = cs_find_client(client_handle, &ret))) {
8384 	    mutex_exit(&sp->lock);
8385 	    return (ret);
8386 	}
8387 
8388 	/*
8389 	 * If we're a CIS client, then extract the function number
8390 	 *	from the socket number.
8391 	 */
8392 	if (client->flags & CLIENT_CSI_CLIENT)
8393 	    fn = CS_GET_FUNCTION_NUMBER(*socket);
8394 
8395 	mutex_exit(&sp->lock);
8396 
8397 	/*
8398 	 * Return the found client pointer if the caller wants it.
8399 	 */
8400 	if (clp)
8401 	    *clp = client;
8402 
8403 	/*
8404 	 * Return a socket number that is made up of the socket number
8405 	 *	and the function number.
8406 	 */
8407 	*socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
8408 
8409 	/*
8410 	 * Return the function number if the caller wants it.
8411 	 */
8412 	if (function)
8413 	    *function = fn;
8414 
8415 	return (CS_SUCCESS);
8416 }
8417 
8418 /*
8419  * cs_get_wp - returns pointer to passed window number
8420  *
8421  *	return: (cs_window_t *) - pointer to window structure
8422  *		NULL - if invalid window number passed in
8423  */
8424 static cs_window_t *
8425 cs_get_wp(uint32_t wn)
8426 {
8427 	cs_window_t *cw;
8428 
8429 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
8430 	    return (NULL);
8431 
8432 	if ((cw = cs_find_wp(wn)) == NULL)
8433 	    return (NULL);
8434 
8435 	if (cw->state & CW_WINDOW_VALID)
8436 	    return (cw);
8437 
8438 #ifdef  CS_DEBUG
8439 	if (cs_debug > 0) {
8440 		cmn_err(CE_CONT, "cs_get_wp(): wn=%d  cw=%p\n",
8441 		    (int)wn, (void *)cw);
8442 	}
8443 #endif
8444 
8445 	return (NULL);
8446 }
8447 
8448 /*
8449  * cs_find_wp - searches window list and returns pointer to passed window
8450  *			number
8451  *
8452  *	return: (cs_window_t *) - pointer to window structure
8453  *		NULL - window not found
8454  */
8455 static cs_window_t *
8456 cs_find_wp(uint32_t wn)
8457 {
8458 	cs_window_t *cw = cs_globals.cw;
8459 
8460 	while (cw) {
8461 	    if (cw->window_num == wn)
8462 		return (cw);
8463 	    cw = cw->next;
8464 	} /* while */
8465 
8466 #ifdef  CS_DEBUG
8467 	if (cs_debug > 0) {
8468 		cmn_err(CE_CONT, "cs_find_wp(): wn=%d  window_num=%d cw=%p\n",
8469 		    (int)wn, (int)cw->window_num, (void *)cw);
8470 	}
8471 #endif
8472 
8473 	return (NULL);
8474 }
8475 
8476 /*
8477  * cs_add_windows - adds number of windows specified in "aw" to
8478  *			the global window list; start the window
8479  *			numbering at "bn"
8480  *
8481  *	return: CS_SUCCESS - if windows added sucessfully
8482  *		CS_BAD_WINDOW - if unable to add windows
8483  *
8484  * Note: The window list must be protected by a lock by the caller.
8485  */
8486 static int
8487 cs_add_windows(int aw, uint32_t bn)
8488 {
8489 	cs_window_t *cwp = cs_globals.cw;
8490 	cs_window_t *cw, *cwpp;
8491 
8492 	if (aw <= 0)
8493 	    return (CS_BAD_WINDOW);
8494 
8495 	while (cwp) {
8496 	    cwpp = cwp;
8497 	    cwp = cwp->next;
8498 	}
8499 
8500 	while (aw--) {
8501 	    cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
8502 
8503 	    if (cs_globals.cw == NULL) {
8504 		cs_globals.cw = cw;
8505 		cwpp = cs_globals.cw;
8506 	    } else {
8507 		cwpp->next = cw;
8508 		cwpp = cwpp->next;
8509 	    }
8510 
8511 	    cwpp->window_num = bn++;
8512 	    cwpp->state = CW_WINDOW_VALID;
8513 
8514 	} /* while (aw) */
8515 
8516 	return (CS_SUCCESS);
8517 }
8518 
8519 /*
8520  * cs_ss_init - initialize CS items that need to wait until we receive
8521  *			a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
8522  *
8523  *	return: CS_SUCESS - if sucessfully initialized
8524  *		(various) if error initializing
8525  *
8526  *	At this point, we expect that Socket Services has setup the
8527  *	following global variables for us:
8528  *
8529  *		cs_socket_services - Socket Services entry point
8530  *		cis_parser - CIS parser entry point
8531  */
8532 static uint32_t
8533 cs_ss_init()
8534 {
8535 	cs_register_cardservices_t rcs;
8536 	csregister_t csr;
8537 	uint32_t ret;
8538 
8539 	/*
8540 	 * Fill out the parameters for CISP_CIS_SETUP
8541 	 */
8542 	csr.cs_magic = PCCS_MAGIC;
8543 	csr.cs_version = PCCS_VERSION;
8544 	csr.cs_card_services = CardServices;
8545 	csr.cs_event = NULL;
8546 
8547 	/*
8548 	 * Call into the CIS module and tell it what the private
8549 	 *	Card Services entry point is. The CIS module will
8550 	 *	call us back at CardServices(CISRegister, ...)
8551 	 *	with the address of various CIS-specific global
8552 	 *	data structures.
8553 	 */
8554 	CIS_PARSER(CISP_CIS_SETUP, &csr);
8555 
8556 	/*
8557 	 * Register with the Card Services kernel stubs module
8558 	 */
8559 	rcs.magic = CS_STUBS_MAGIC;
8560 	rcs.function = CS_ENTRY_REGISTER;
8561 	rcs.cardservices = CardServices;
8562 
8563 	if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
8564 	    cmn_err(CE_CONT, "cs_ss_init: can't register with "
8565 					"cs_stubs, retcode = 0x%x\n", ret);
8566 		return (ret);
8567 	} /* csx_register_cardservices */
8568 
8569 	return (CS_SUCCESS);
8570 }
8571 
8572 /*
8573  * cs_create_cis - reads CIS on card in socket and creates CIS lists
8574  *
8575  * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
8576  *	function.
8577  *
8578  * This function returns:
8579  *
8580  *	CS_SUCCESS - if the CIS lists were created sucessfully
8581  *	CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
8582  *			not be setup
8583  *	CS_BAD_CIS - if error creating CIS chains
8584  *	CS_BAD_OFFSET - if the CIS parser tried to read past the
8585  *			boundries of the allocated CIS window
8586  */
8587 static int
8588 cs_create_cis(cs_socket_t *sp)
8589 {
8590 	uint32_t ret;
8591 
8592 	ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
8593 	    cis_cistpl_std_callout, sp);
8594 
8595 #ifdef	CS_DEBUG
8596 	if (ret == CS_NO_CIS) {
8597 	    if (cs_debug > 0)
8598 		cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
8599 								sp->socket_num);
8600 	} else if (ret != CS_SUCCESS) {
8601 	    if (cs_debug > 0)
8602 		cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
8603 							sp->socket_num, ret);
8604 	    return (ret);
8605 	}
8606 #else
8607 	if (ret != CS_NO_CIS)
8608 	    if (ret != CS_SUCCESS)
8609 		return (ret);
8610 #endif
8611 
8612 	/*
8613 	 * If this card didn't have any CIS at all, there's not much
8614 	 *	else for us to do.
8615 	 */
8616 	if (!(sp->cis_flags & CW_VALID_CIS))
8617 	    return (CS_SUCCESS);
8618 
8619 	/*
8620 	 * If this is a single-function card, we need to move the CIS list
8621 	 *	that is currently on CS_GLOBAL_CIS to the function zero
8622 	 *	CIS list.
8623 	 */
8624 	if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
8625 	    bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
8626 				(caddr_t)&sp->cis[0], sizeof (cis_info_t));
8627 	    bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
8628 	} /* !CW_MULTI_FUNCTION_CIS */
8629 
8630 	return (CS_SUCCESS);
8631 }
8632 
8633 /*
8634  * cs_destroy_cis - destroys CIS list for socket
8635  */
8636 static int
8637 cs_destroy_cis(cs_socket_t *sp)
8638 {
8639 	CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
8640 
8641 	return (CS_SUCCESS);
8642 }
8643 
8644 /*
8645  * cs_get_client_info - This function is GetClientInfo.
8646  *
8647  *    calling:	client_handle_t - client handle to get client info on
8648  *		client_info_t * - pointer to a client_info_t structure
8649  *					to return client information in
8650  *
8651  *    returns:	CS_SUCCESS - if client info retreived from client
8652  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8653  *					handle passed in
8654  *		CS_NO_MORE_ITEMS - if client does not handle the
8655  *					CS_EVENT_CLIENT_INFO event
8656  *					or if invalid client info
8657  *					retreived from client
8658  */
8659 static int
8660 cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
8661 {
8662 	cs_socket_t *sp;
8663 	client_t *client;
8664 	client_info_t *cinfo;
8665 	int ret = CS_SUCCESS;
8666 
8667 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
8668 	    ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
8669 						CS_CLIENT_INFO_VALID);
8670 	    return (CS_SUCCESS);
8671 	} /* CLIENT_HANDLE_IS_SS */
8672 
8673 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
8674 	    return (CS_BAD_SOCKET);
8675 
8676 	mutex_enter(&sp->client_lock);
8677 	mutex_enter(&sp->lock);
8678 
8679 	if ((client = cs_find_client(client_handle, &ret)) == NULL) {
8680 	    mutex_exit(&sp->lock);
8681 	    mutex_exit(&sp->client_lock);
8682 	    return (ret);
8683 	} /* cs_find_client */
8684 
8685 	/*
8686 	 * If this client is not handling CS_EVENT_CLIENT_INFO events,
8687 	 *	then don't bother to even wake up the event thread.
8688 	 */
8689 	if (!((client->event_mask | client->global_mask) &
8690 					CS_EVENT_CLIENT_INFO)) {
8691 	    mutex_exit(&sp->lock);
8692 	    mutex_exit(&sp->client_lock);
8693 	    return (CS_NO_MORE_ITEMS);
8694 	} /* !CS_EVENT_CLIENT_INFO */
8695 
8696 	cinfo = &client->event_callback_args.client_info;
8697 
8698 	bzero((caddr_t)cinfo, sizeof (client_info_t));
8699 	cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
8700 
8701 	client->events |= CS_EVENT_CLIENT_INFO;
8702 
8703 	sp->thread_state |= SOCKET_WAIT_SYNC;
8704 	mutex_exit(&sp->lock);
8705 	cv_broadcast(&sp->thread_cv);
8706 	cv_wait(&sp->caller_cv, &sp->client_lock);
8707 
8708 	if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
8709 	    bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
8710 	    ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
8711 					CS_CLIENT_INFO_SUBSVC_MASK);
8712 	    ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
8713 						INFO_CARD_FLAGS_MASK |
8714 						CS_CLIENT_INFO_CLIENT_ACTIVE);
8715 	    ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
8716 						INFO_CARD_FLAGS_MASK));
8717 	    (void) strcpy(ci->DriverName, client->driver_name);
8718 	    if (cs_card_for_client(client))
8719 		ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
8720 	} else {
8721 	    ret = CS_NO_MORE_ITEMS;
8722 	} /* CS_CLIENT_INFO_VALID */
8723 
8724 	mutex_exit(&sp->client_lock);
8725 
8726 	return (ret);
8727 }
8728 
8729 /*
8730  * cs_get_firstnext_client - This function is GetFirstClient and
8731  *				GetNextClient
8732  *
8733  *    calling:	get_firstnext_client_t * - pointer to a get_firstnext_client_t
8734  *					structure to return client handle and
8735  *					attributes in
8736  *		flags - one of the following:
8737  *				CS_GET_FIRST_FLAG - get first client handle
8738  *				CS_GET_NEXT_FLAG - get next client handle
8739  *
8740  *    returns:	CS_SUCCESS - if client info retreived from client
8741  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8742  *					handle passed in
8743  *		CS_NO_MORE_ITEMS - if client does not handle the
8744  *					CS_EVENT_CLIENT_INFO event
8745  *					or if invalid client info
8746  *					retreived from client
8747  */
8748 static int
8749 cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
8750 {
8751 	cs_socket_t *sp;
8752 	client_t *client;
8753 	uint32_t sn = 0;
8754 	int ret = CS_SUCCESS;
8755 
8756 	switch (flags) {
8757 	    case CS_GET_FIRST_FLAG:
8758 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8759 		    while (sn < cs_globals.max_socket_num) {
8760 			if ((sp = cs_get_sp(sn)) != NULL) {
8761 			    mutex_enter(&sp->client_lock);
8762 			    if ((client = sp->client_list) != NULL)
8763 				break;
8764 			    mutex_exit(&sp->client_lock);
8765 			} /* if */
8766 			sn++;
8767 		    } /* while */
8768 
8769 		    if (sn == cs_globals.max_socket_num)
8770 			return (CS_NO_MORE_ITEMS);
8771 		} else if (fnc->Attributes &
8772 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8773 		    if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
8774 									NULL)
8775 			return (CS_BAD_SOCKET);
8776 		    mutex_enter(&sp->client_lock);
8777 		    if ((client = sp->client_list) == NULL) {
8778 			mutex_exit(&sp->client_lock);
8779 			return (CS_NO_MORE_ITEMS);
8780 		    }
8781 		} else {
8782 		    return (CS_BAD_ATTRIBUTE);
8783 		}
8784 
8785 		fnc->client_handle = client->client_handle;
8786 		fnc->num_clients = sp->num_clients;
8787 		mutex_exit(&sp->client_lock);
8788 		break;
8789 	    case CS_GET_NEXT_FLAG:
8790 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8791 		    sn = GET_CLIENT_SOCKET(fnc->client_handle);
8792 
8793 		    if ((sp = cs_get_sp(sn)) == NULL)
8794 			return (CS_BAD_SOCKET);
8795 
8796 		    mutex_enter(&sp->client_lock);
8797 		    if ((client = cs_find_client(fnc->client_handle,
8798 				&ret)) == NULL) {
8799 			mutex_exit(&sp->client_lock);
8800 			return (ret);
8801 		    }
8802 		    if ((client = client->next) == NULL) {
8803 			mutex_exit(&sp->client_lock);
8804 			sn++;
8805 			while (sn < cs_globals.max_socket_num) {
8806 			    if ((sp = cs_get_sp(sn)) != NULL) {
8807 				mutex_enter(&sp->client_lock);
8808 				if ((client = sp->client_list) != NULL)
8809 				    break;
8810 				mutex_exit(&sp->client_lock);
8811 			    } /* if */
8812 			    sn++;
8813 			} /* while */
8814 
8815 			if (sn == cs_globals.max_socket_num)
8816 			    return (CS_NO_MORE_ITEMS);
8817 		    } /* client = client->next */
8818 
8819 		} else if (fnc->Attributes &
8820 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8821 		    sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
8822 		    if (sp == NULL)
8823 			return (CS_BAD_SOCKET);
8824 		    mutex_enter(&sp->client_lock);
8825 		    if ((client = cs_find_client(fnc->client_handle,
8826 				&ret)) == NULL) {
8827 			mutex_exit(&sp->client_lock);
8828 			return (ret);
8829 		    }
8830 		    if ((client = client->next) == NULL) {
8831 			mutex_exit(&sp->client_lock);
8832 			return (CS_NO_MORE_ITEMS);
8833 		    }
8834 		} else {
8835 		    return (CS_BAD_ATTRIBUTE);
8836 		}
8837 
8838 		fnc->client_handle = client->client_handle;
8839 		fnc->num_clients = sp->num_clients;
8840 		mutex_exit(&sp->client_lock);
8841 		break;
8842 	    default:
8843 		ret = CS_BAD_ATTRIBUTE;
8844 		break;
8845 
8846 	} /* switch */
8847 
8848 	return (ret);
8849 }
8850 
8851 /*
8852  * cs_set_acc_attributes - converts Card Services endianness and
8853  *				data ordering values to values
8854  *				that Socket Services understands
8855  *
8856  *	calling: *sw - pointer to a set_window_t to set attributes in
8857  *		 Attributes - CS attributes
8858  */
8859 static void
8860 cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
8861 {
8862 	sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8863 
8864 	switch (Attributes & WIN_ACC_ENDIAN_MASK) {
8865 	    case WIN_ACC_LITTLE_ENDIAN:
8866 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8867 		break;
8868 	    case WIN_ACC_BIG_ENDIAN:
8869 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
8870 		break;
8871 	    case WIN_ACC_NEVER_SWAP:
8872 	    default:
8873 		sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
8874 		break;
8875 	} /* switch */
8876 
8877 	switch (Attributes & WIN_ACC_ORDER_MASK) {
8878 	    case WIN_ACC_UNORDERED_OK:
8879 		sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
8880 		break;
8881 	    case WIN_ACC_MERGING_OK:
8882 		sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
8883 		break;
8884 	    case WIN_ACC_LOADCACHING_OK:
8885 		sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
8886 		break;
8887 	    case WIN_ACC_STORECACHING_OK:
8888 		sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
8889 		break;
8890 	    case WIN_ACC_STRICT_ORDER:
8891 	    default:
8892 		sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8893 		break;
8894 	} /* switch */
8895 }
8896