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 */
95int CardServices(int function, ...);
96
97/*
98 * functions and globals used by Socket Services
99 *
100 * WAS: void *(*cis_parser)(int, ...) = NULL;
101 */
102void *(*cis_parser)(int, ...) = NULL;
103csfunction_t *cs_socket_services = NULL;
104
105/*
106 * event handling functions
107 */
108static event_t ss_to_cs_events(cs_socket_t *, event_t);
109static event_t cs_cse2sbm(event_t);
110static void cs_event_thread(uint32_t);
111static int cs_card_insertion(cs_socket_t *, event_t);
112static int cs_card_removal(cs_socket_t *);
113static void cs_ss_thread(uint32_t);
114void cs_ready_timeout(void *);
115static int cs_card_for_client(client_t *);
116static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
117static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
118static int cs_get_event_mask(client_handle_t, sockevent_t *);
119static int cs_set_event_mask(client_handle_t, sockevent_t *);
120static int cs_event2text(event2text_t *, int);
121static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
122						get_ss_status_t *, int);
123uint32_t cs_socket_event_softintr(caddr_t);
124void cs_event_softintr_timeout(void *);
125static int cs_get_status(client_handle_t, get_status_t *);
126static uint32_t cs_sbm2cse(uint32_t);
127static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
128static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
129
130/*
131 * SS<->CS communication and internal socket and window  handling functions
132 */
133static uint32_t cs_add_socket(uint32_t);
134static uint32_t cs_drop_socket(uint32_t);
135static cs_socket_t *cs_get_sp(uint32_t);
136static cs_socket_t *cs_find_sp(uint32_t);
137static cs_window_t *cs_get_wp(uint32_t);
138static cs_window_t *cs_find_wp(uint32_t);
139static int cs_add_windows(int, uint32_t);
140static uint32_t cs_ss_init();
141static void cs_set_acc_attributes(set_window_t *, uint32_t);
142
143/*
144 * CIS handling functions
145 */
146cistpl_callout_t *cis_cistpl_std_callout;
147static int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
148static int cs_get_tuple_data(client_handle_t, tuple_t *);
149static int cs_validate_cis(client_handle_t, cisinfo_t *);
150static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
151static int cs_create_cis(cs_socket_t *);
152static int cs_destroy_cis(cs_socket_t *);
153
154/*
155 * client handling functions
156 */
157unsigned cs_create_next_client_minor(unsigned, unsigned);
158static client_t *cs_find_client(client_handle_t, int *);
159static client_handle_t cs_create_client_handle(unsigned, client_t *);
160static int cs_destroy_client_handle(client_handle_t);
161static int cs_register_client(client_handle_t *, client_reg_t *);
162static int cs_deregister_client(client_handle_t);
163static int cs_deregister_mtd(client_handle_t);
164static void cs_clear_superclient_lock(int);
165static int cs_add_client_to_socket(unsigned, client_handle_t *,
166						client_reg_t *, int);
167static int cs_get_client_info(client_handle_t, client_info_t *);
168static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
169
170/*
171 * window handling functions
172 */
173static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
174static int cs_release_window(window_handle_t);
175static int cs_modify_window(window_handle_t, modify_win_t *);
176static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
177									int);
178static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
179static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
180static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
181static int cs_valid_window_speed(inquire_window_t *, uint32_t);
182static window_handle_t cs_create_window_handle(uint32_t);
183static cs_window_t *cs_find_window(window_handle_t);
184static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
185
186/*
187 * IO, IRQ and configuration handling functions
188 */
189static int cs_request_io(client_handle_t, io_req_t *);
190static int cs_release_io(client_handle_t, io_req_t *);
191static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
192static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
193					uint32_t *, uint32_t, uint32_t);
194static int cs_request_irq(client_handle_t, irq_req_t *);
195static int cs_release_irq(client_handle_t, irq_req_t *);
196static int cs_request_configuration(client_handle_t, config_req_t *);
197static int cs_release_configuration(client_handle_t, release_config_t *);
198static int cs_modify_configuration(client_handle_t, modify_config_t *);
199static int cs_access_configuration_register(client_handle_t,
200						access_config_reg_t *);
201
202/*
203 * RESET and general info functions
204 */
205static int cs_reset_function(client_handle_t, reset_function_t *);
206static int cs_get_configuration_info(client_handle_t *,
207						get_configuration_info_t *);
208static int cs_get_cardservices_info(client_handle_t,
209						get_cardservices_info_t *);
210static int cs_get_physical_adapter_info(client_handle_t,
211						get_physical_adapter_info_t *);
212
213/*
214 * general functions
215 */
216static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
217					cs_socket_t **, client_t **);
218static int cs_convert_speed(convert_speed_t *);
219static int cs_convert_size(convert_size_t *);
220static char *cs_error2text(int, int);
221static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
222static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
223static int cs_make_device_node(client_handle_t, make_device_node_t *);
224static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
225static int cs_ddi_info(cs_ddi_info_t *);
226static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
227				uint32_t);
228static int cs_sys_ctl(cs_sys_ctl_t *);
229
230/*
231 * global variables
232 */
233static int cs_max_client_handles = CS_MAX_CLIENTS;
234static client_t cs_socket_services_client;	/* global SS client */
235static client_types_t client_types[MAX_CLIENT_TYPES];
236static cs_globals_t cs_globals;
237int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
238int cs_rc1_delay = CS_RC1_DELAY;
239int cs_rc2_delay = CS_RC2_DELAY;
240int cs_rq_delay = CS_RQ_DELAY;
241
242#ifdef	CS_DEBUG
243int	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 */
254int
255cs_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 */
309int
310cs_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 */
536int
537CardServices(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 */
919static int
920cs_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 */
1059static int
1060cs_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 */
1234static int
1235cs_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 */
1420static int
1421cs_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 */
1489int
1490cs_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 */
1632static int
1633cs_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 */
1828static int
1829cs_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 */
2053static int
2054cs_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 */
2143unsigned
2144cs_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 */
2180static client_t *
2181cs_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 */
2235static int
2236cs_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 */
2307static client_handle_t
2308cs_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 */
2395static void
2396cs_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*/
2447uint32_t
2448cs_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 */
2640static int
2641cs_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 */
2924static int
2925cs_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 */
3015static event_t
3016ss_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 */
3105void
3106cs_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 */
3147void
3148cs_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*/
3176uint32_t
3177cs_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 */
3238static void
3239cs_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 */
3585static int
3586cs_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 */
3638static void
3639cs_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 */
3742static int
3743cs_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*/
3851static int
3852cs_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 */
3921static int
3922cs_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 */
3999static int
4000cs_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 */
4111static int
4112cs_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 */
4323static int
4324cs_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 */
4415static event_t
4416cs_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 */
4459static uint32_t
4460cs_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 */
4491static unsigned
4492cs_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 */
4547static int
4548cs_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 */
4577static int
4578cs_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 */
4611static int
4612cs_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 */
4770static int
4771cs_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 */
4833static int
4834cs_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 */
4912static int
4913cs_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 */
5020static int
5021cs_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 */
5130cs_window_t *
5131cs_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 */
5152static window_handle_t
5153cs_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 */
5170static int
5171cs_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
5276found_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 */
5299static int
5300cs_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 */
5351static int
5352cs_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 */
5396static int
5397cs_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 */
5788static int
5789cs_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 */
5948static int
5949cs_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 */
5999static int
6000cs_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 */
6041static int
6042cs_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 */
6139static int
6140cs_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 */
6273static int
6274cs_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 */
6382static int
6383cs_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*/
6812static int
6813cs_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<