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