17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
235f9e250hx * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*
287c478bdstevel@tonic-gate * PCMCIA Card Services
297c478bdstevel@tonic-gate *	The PCMCIA Card Services is a loadable module which
307c478bdstevel@tonic-gate *	presents the Card Services interface to client device
317c478bdstevel@tonic-gate *	drivers.
327c478bdstevel@tonic-gate *
337c478bdstevel@tonic-gate *	Card Services uses Socket Services-like calls into the
347c478bdstevel@tonic-gate *	PCMCIA nexus driver to manipulate socket and adapter
357c478bdstevel@tonic-gate *	resources.
367c478bdstevel@tonic-gate *
377c478bdstevel@tonic-gate * Note that a bunch of comments are not indented correctly with the
387c478bdstevel@tonic-gate *	code that they are commenting on. This is because cstyle is
397c478bdstevel@tonic-gate *	is inflexible concerning 4-column indenting.
407c478bdstevel@tonic-gate */
417c478bdstevel@tonic-gate
427c478bdstevel@tonic-gate#if defined(DEBUG)
437c478bdstevel@tonic-gate#define	CS_DEBUG
447c478bdstevel@tonic-gate#endif
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#include <sys/types.h>
477c478bdstevel@tonic-gate#include <sys/systm.h>
487c478bdstevel@tonic-gate#include <sys/user.h>
497c478bdstevel@tonic-gate#include <sys/buf.h>
507c478bdstevel@tonic-gate#include <sys/file.h>
517c478bdstevel@tonic-gate#include <sys/uio.h>
527c478bdstevel@tonic-gate#include <sys/conf.h>
537c478bdstevel@tonic-gate#include <sys/stat.h>
547c478bdstevel@tonic-gate#include <sys/autoconf.h>
557c478bdstevel@tonic-gate#include <sys/vtoc.h>
567c478bdstevel@tonic-gate#include <sys/dkio.h>
577c478bdstevel@tonic-gate#include <sys/ddi.h>
587c478bdstevel@tonic-gate#include <sys/sunddi.h>
597c478bdstevel@tonic-gate#include <sys/debug.h>
607c478bdstevel@tonic-gate#include <sys/varargs.h>
617c478bdstevel@tonic-gate#include <sys/var.h>
627c478bdstevel@tonic-gate#include <sys/proc.h>
637c478bdstevel@tonic-gate#include <sys/thread.h>
647c478bdstevel@tonic-gate#include <sys/utsname.h>
657c478bdstevel@tonic-gate#include <sys/vtrace.h>
667c478bdstevel@tonic-gate#include <sys/kstat.h>
677c478bdstevel@tonic-gate#include <sys/kmem.h>
687c478bdstevel@tonic-gate#include <sys/modctl.h>
697c478bdstevel@tonic-gate#include <sys/kobj.h>
707c478bdstevel@tonic-gate#include <sys/callb.h>
717c478bdstevel@tonic-gate#include <sys/time.h>
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate#include <sys/pctypes.h>
747c478bdstevel@tonic-gate#include <pcmcia/sys/cs_types.h>
757c478bdstevel@tonic-gate#include <sys/pcmcia.h>
767c478bdstevel@tonic-gate#include <sys/sservice.h>
777c478bdstevel@tonic-gate#include <pcmcia/sys/cis.h>
787c478bdstevel@tonic-gate#include <pcmcia/sys/cis_handlers.h>
797c478bdstevel@tonic-gate#include <pcmcia/sys/cs.h>
807c478bdstevel@tonic-gate#include <pcmcia/sys/cs_priv.h>
817c478bdstevel@tonic-gate#include <pcmcia/sys/cs_stubs.h>
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gate/*
847c478bdstevel@tonic-gate * The cs_strings header file is where all of the major strings that
857c478bdstevel@tonic-gate *	Card Services uses are located.
867c478bdstevel@tonic-gate */
877c478bdstevel@tonic-gate#include <pcmcia/sys/cs_strings.h>
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate
907c478bdstevel@tonic-gate/*
917c478bdstevel@tonic-gate * Function declarations
927c478bdstevel@tonic-gate *
937c478bdstevel@tonic-gate * The main Card Services entry point
947c478bdstevel@tonic-gate */
957c478bdstevel@tonic-gateint CardServices(int function, ...);
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate/*
987c478bdstevel@tonic-gate * functions and globals used by Socket Services
997c478bdstevel@tonic-gate *
1007c478bdstevel@tonic-gate * WAS: void *(*cis_parser)(int, ...) = NULL;
1017c478bdstevel@tonic-gate */
1027c478bdstevel@tonic-gatevoid *(*cis_parser)(int, ...) = NULL;
1037c478bdstevel@tonic-gatecsfunction_t *cs_socket_services = NULL;
1047c478bdstevel@tonic-gate
1057c478bdstevel@tonic-gate/*
1067c478bdstevel@tonic-gate * event handling functions
1077c478bdstevel@tonic-gate */
1087c478bdstevel@tonic-gatestatic event_t ss_to_cs_events(cs_socket_t *, event_t);
1097c478bdstevel@tonic-gatestatic event_t cs_cse2sbm(event_t);
1107c478bdstevel@tonic-gatestatic void cs_event_thread(uint32_t);
1117c478bdstevel@tonic-gatestatic int cs_card_insertion(cs_socket_t *, event_t);
1127c478bdstevel@tonic-gatestatic int cs_card_removal(cs_socket_t *);
1137c478bdstevel@tonic-gatestatic void cs_ss_thread(uint32_t);
1147c478bdstevel@tonic-gatevoid cs_ready_timeout(void *);
1157c478bdstevel@tonic-gatestatic int cs_card_for_client(client_t *);
1167c478bdstevel@tonic-gatestatic int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
1177c478bdstevel@tonic-gatestatic int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
1187c478bdstevel@tonic-gatestatic int cs_get_event_mask(client_handle_t, sockevent_t *);
1197c478bdstevel@tonic-gatestatic int cs_set_event_mask(client_handle_t, sockevent_t *);
1207c478bdstevel@tonic-gatestatic int cs_event2text(event2text_t *, int);
1217c478bdstevel@tonic-gatestatic int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
1227c478bdstevel@tonic-gate						get_ss_status_t *, int);
1237c478bdstevel@tonic-gateuint32_t cs_socket_event_softintr(caddr_t);
1247c478bdstevel@tonic-gatevoid cs_event_softintr_timeout(void *);
1257c478bdstevel@tonic-gatestatic int cs_get_status(client_handle_t, get_status_t *);
1267c478bdstevel@tonic-gatestatic uint32_t cs_sbm2cse(uint32_t);
1277c478bdstevel@tonic-gatestatic unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
1287c478bdstevel@tonic-gatestatic int cs_set_socket_event_mask(cs_socket_t *, unsigned);
1297c478bdstevel@tonic-gate
1307c478bdstevel@tonic-gate/*
1317c478bdstevel@tonic-gate * SS<->CS communication and internal socket and window  handling functions
1327c478bdstevel@tonic-gate */
1337c478bdstevel@tonic-gatestatic uint32_t cs_add_socket(uint32_t);
1347c478bdstevel@tonic-gatestatic uint32_t cs_drop_socket(uint32_t);
1357c478bdstevel@tonic-gatestatic cs_socket_t *cs_get_sp(uint32_t);
1367c478bdstevel@tonic-gatestatic cs_socket_t *cs_find_sp(uint32_t);
1377c478bdstevel@tonic-gatestatic cs_window_t *cs_get_wp(uint32_t);
1387c478bdstevel@tonic-gatestatic cs_window_t *cs_find_wp(uint32_t);
1397c478bdstevel@tonic-gatestatic int cs_add_windows(int, uint32_t);
1407c478bdstevel@tonic-gatestatic uint32_t cs_ss_init();
1417c478bdstevel@tonic-gatestatic void cs_set_acc_attributes(set_window_t *, uint32_t);
1427c478bdstevel@tonic-gate
1437c478bdstevel@tonic-gate/*
1447c478bdstevel@tonic-gate * CIS handling functions
1457c478bdstevel@tonic-gate */
1467c478bdstevel@tonic-gatecistpl_callout_t *cis_cistpl_std_callout;
1477c478bdstevel@tonic-gatestatic int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
1487c478bdstevel@tonic-gatestatic int cs_get_tuple_data(client_handle_t, tuple_t *);
1497c478bdstevel@tonic-gatestatic int cs_validate_cis(client_handle_t, cisinfo_t *);
1507c478bdstevel@tonic-gatestatic int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
1517c478bdstevel@tonic-gatestatic int cs_create_cis(cs_socket_t *);
1527c478bdstevel@tonic-gatestatic int cs_destroy_cis(cs_socket_t *);
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gate/*
1557c478bdstevel@tonic-gate * client handling functions
1567c478bdstevel@tonic-gate */
1577c478bdstevel@tonic-gateunsigned cs_create_next_client_minor(unsigned, unsigned);
1587c478bdstevel@tonic-gatestatic client_t *cs_find_client(client_handle_t, int *);
1597c478bdstevel@tonic-gatestatic client_handle_t cs_create_client_handle(unsigned, client_t *);
1607c478bdstevel@tonic-gatestatic int cs_destroy_client_handle(client_handle_t);
1617c478bdstevel@tonic-gatestatic int cs_register_client(client_handle_t *, client_reg_t *);
1627c478bdstevel@tonic-gatestatic int cs_deregister_client(client_handle_t);
1637c478bdstevel@tonic-gatestatic int cs_deregister_mtd(client_handle_t);
1647c478bdstevel@tonic-gatestatic void cs_clear_superclient_lock(int);
1657c478bdstevel@tonic-gatestatic int cs_add_client_to_socket(unsigned, client_handle_t *,
1667c478bdstevel@tonic-gate						client_reg_t *, int);
1677c478bdstevel@tonic-gatestatic int cs_get_client_info(client_handle_t, client_info_t *);
1687c478bdstevel@tonic-gatestatic int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate/*
1717c478bdstevel@tonic-gate * window handling functions
1727c478bdstevel@tonic-gate */
1737c478bdstevel@tonic-gatestatic int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
1747c478bdstevel@tonic-gatestatic int cs_release_window(window_handle_t);
1757c478bdstevel@tonic-gatestatic int cs_modify_window(window_handle_t, modify_win_t *);
1767c478bdstevel@tonic-gatestatic int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
1777c478bdstevel@tonic-gate									int);
1787c478bdstevel@tonic-gatestatic int cs_map_mem_page(window_handle_t, map_mem_page_t *);
1797c478bdstevel@tonic-gatestatic int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
1807c478bdstevel@tonic-gatestatic int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
1817c478bdstevel@tonic-gatestatic int cs_valid_window_speed(inquire_window_t *, uint32_t);
1827c478bdstevel@tonic-gatestatic window_handle_t cs_create_window_handle(uint32_t);
1837c478bdstevel@tonic-gatestatic cs_window_t *cs_find_window(window_handle_t);
1847c478bdstevel@tonic-gatestatic int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate/*
1877c478bdstevel@tonic-gate * IO, IRQ and configuration handling functions
1887c478bdstevel@tonic-gate */
1897c478bdstevel@tonic-gatestatic int cs_request_io(client_handle_t, io_req_t *);
1907c478bdstevel@tonic-gatestatic int cs_release_io(client_handle_t, io_req_t *);
1917c478bdstevel@tonic-gatestatic int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
1927c478bdstevel@tonic-gatestatic int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
1937c478bdstevel@tonic-gate					uint32_t *, uint32_t, uint32_t);
1947c478bdstevel@tonic-gatestatic int cs_request_irq(client_handle_t, irq_req_t *);
1957c478bdstevel@tonic-gatestatic int cs_release_irq(client_handle_t, irq_req_t *);
1967c478bdstevel@tonic-gatestatic int cs_request_configuration(client_handle_t, config_req_t *);
1977c478bdstevel@tonic-gatestatic int cs_release_configuration(client_handle_t, release_config_t *);
1987c478bdstevel@tonic-gatestatic int cs_modify_configuration(client_handle_t, modify_config_t *);
1997c478bdstevel@tonic-gatestatic int cs_access_configuration_register(client_handle_t,
2007c478bdstevel@tonic-gate						access_config_reg_t *);
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate/*
2037c478bdstevel@tonic-gate * RESET and general info functions
2047c478bdstevel@tonic-gate */
2057c478bdstevel@tonic-gatestatic int cs_reset_function(client_handle_t, reset_function_t *);
2067c478bdstevel@tonic-gatestatic int cs_get_configuration_info(client_handle_t *,
2077c478bdstevel@tonic-gate						get_configuration_info_t *);
2087c478bdstevel@tonic-gatestatic int cs_get_cardservices_info(client_handle_t,
2097c478bdstevel@tonic-gate						get_cardservices_info_t *);
2107c478bdstevel@tonic-gatestatic int cs_get_physical_adapter_info(client_handle_t,
2117c478bdstevel@tonic-gate						get_physical_adapter_info_t *);
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gate/*
2147c478bdstevel@tonic-gate * general functions
2157c478bdstevel@tonic-gate */
2167c478bdstevel@tonic-gatestatic uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
2177c478bdstevel@tonic-gate					cs_socket_t **, client_t **);
2187c478bdstevel@tonic-gatestatic int cs_convert_speed(convert_speed_t *);
2197c478bdstevel@tonic-gatestatic int cs_convert_size(convert_size_t *);
2207c478bdstevel@tonic-gatestatic char *cs_error2text(int, int);
2217c478bdstevel@tonic-gatestatic int cs_map_log_socket(client_handle_t, map_log_socket_t *);
2227c478bdstevel@tonic-gatestatic int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
2237c478bdstevel@tonic-gatestatic int cs_make_device_node(client_handle_t, make_device_node_t *);
2247c478bdstevel@tonic-gatestatic int cs_remove_device_node(client_handle_t, remove_device_node_t *);
2257c478bdstevel@tonic-gatestatic int cs_ddi_info(cs_ddi_info_t *);
2267c478bdstevel@tonic-gatestatic int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
2277c478bdstevel@tonic-gate				uint32_t);
2287c478bdstevel@tonic-gatestatic int cs_sys_ctl(cs_sys_ctl_t *);
2297c478bdstevel@tonic-gate
2307c478bdstevel@tonic-gate/*
2317c478bdstevel@tonic-gate * global variables
2327c478bdstevel@tonic-gate */
2337c478bdstevel@tonic-gatestatic int cs_max_client_handles = CS_MAX_CLIENTS;
2347c478bdstevel@tonic-gatestatic client_t cs_socket_services_client;	/* global SS client */
2357c478bdstevel@tonic-gatestatic client_types_t client_types[MAX_CLIENT_TYPES];
2367c478bdstevel@tonic-gatestatic cs_globals_t cs_globals;
2377c478bdstevel@tonic-gateint cs_reset_timeout_time = RESET_TIMEOUT_TIME;
2387c478bdstevel@tonic-gateint cs_rc1_delay = CS_RC1_DELAY;
2397c478bdstevel@tonic-gateint cs_rc2_delay = CS_RC2_DELAY;
2407c478bdstevel@tonic-gateint cs_rq_delay = CS_RQ_DELAY;
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate#ifdef	CS_DEBUG
2437c478bdstevel@tonic-gateint	cs_debug = 0;
2447c478bdstevel@tonic-gate#endif
2457c478bdstevel@tonic-gate
2467c478bdstevel@tonic-gate/*
2477c478bdstevel@tonic-gate * cs_init - Initialize CS internal structures, databases, and state,
2487c478bdstevel@tonic-gate *		and register with SS
2497c478bdstevel@tonic-gate *
2507c478bdstevel@tonic-gate * XXX - Need to make sure that if we fail at any point that we free
2517c478bdstevel@tonic-gate *		any resources that we allocated, as well as kill any
2527c478bdstevel@tonic-gate *		threads that may have been started.
2537c478bdstevel@tonic-gate */
2547c478bdstevel@tonic-gateint
2557c478bdstevel@tonic-gatecs_init()
2567c478bdstevel@tonic-gate{
2577c478bdstevel@tonic-gate	client_types_t *ct;
2587c478bdstevel@tonic-gate	client_t *client;
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate	/*
2617c478bdstevel@tonic-gate	 * Initialize the CS global structure
2627c478bdstevel@tonic-gate	 */
2637c478bdstevel@tonic-gate	bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate	mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
2667c478bdstevel@tonic-gate	mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
2677c478bdstevel@tonic-gate
2687c478bdstevel@tonic-gate	cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate	/*
2717c478bdstevel@tonic-gate	 * Set up the global Socket Services client, since we're going to
2727c478bdstevel@tonic-gate	 *	need it once we register with SS.
2737c478bdstevel@tonic-gate	 */
2747c478bdstevel@tonic-gate	client = &cs_socket_services_client;
2757c478bdstevel@tonic-gate	bzero((caddr_t)client, sizeof (client_t));
2767c478bdstevel@tonic-gate	client->client_handle = CS_SS_CLIENT_HANDLE;
2777c478bdstevel@tonic-gate	client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
2787c478bdstevel@tonic-gate
2797c478bdstevel@tonic-gate	/*
2807c478bdstevel@tonic-gate	 * Setup the client type structure - this is used in the socket event
2817c478bdstevel@tonic-gate	 *	thread to sequence the delivery of events to all clients on
2827c478bdstevel@tonic-gate	 *	the socket.
2837c478bdstevel@tonic-gate	 */
2847c478bdstevel@tonic-gate	ct = &client_types[0];
2857c478bdstevel@tonic-gate	ct->type = INFO_IO_CLIENT;
2867c478bdstevel@tonic-gate	ct->order = CLIENT_EVENTS_LIFO;
2877c478bdstevel@tonic-gate	ct->next = &client_types[1];
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gate	ct = ct->next;
2907c478bdstevel@tonic-gate	ct->type = INFO_MTD_CLIENT;
2917c478bdstevel@tonic-gate	ct->order = CLIENT_EVENTS_FIFO;
2927c478bdstevel@tonic-gate	ct->next = &client_types[2];
2937c478bdstevel@tonic-gate
2947c478bdstevel@tonic-gate	ct = ct->next;
2957c478bdstevel@tonic-gate	ct->type = INFO_MEM_CLIENT;
2967c478bdstevel@tonic-gate	ct->order = CLIENT_EVENTS_FIFO;
2977c478bdstevel@tonic-gate	ct->next = NULL;
2987c478bdstevel@tonic-gate
2997c478bdstevel@tonic-gate	return (CS_SUCCESS);
3007c478bdstevel@tonic-gate}
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate/*
3037c478bdstevel@tonic-gate * cs_deinit - Deinitialize CS
3047c478bdstevel@tonic-gate *
3057c478bdstevel@tonic-gate * This function cleans up any allocated resources, stops any running threads,
3067c478bdstevel@tonic-gate *	destroys any mutexes and condition variables, and finally frees up the
3077c478bdstevel@tonic-gate *	global socket and window structure arrays.
3087c478bdstevel@tonic-gate */
3097c478bdstevel@tonic-gateint
3107c478bdstevel@tonic-gatecs_deinit()
3117c478bdstevel@tonic-gate{
3127c478bdstevel@tonic-gate	cs_socket_t *sp;
3137c478bdstevel@tonic-gate	int sn, have_clients = 0, have_sockets = 0;
3147c478bdstevel@tonic-gate	cs_register_cardservices_t rcs;
3157c478bdstevel@tonic-gate
3167c478bdstevel@tonic-gate#if defined(CS_DEBUG)
3177c478bdstevel@tonic-gate	if (cs_debug > 1)
3187c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "CS: cs_deinit\n");
3197c478bdstevel@tonic-gate#endif
3207c478bdstevel@tonic-gate
3217c478bdstevel@tonic-gate	/*
3227c478bdstevel@tonic-gate	 * Deregister with the Card Services kernel stubs module
3237c478bdstevel@tonic-gate	 */
3247c478bdstevel@tonic-gate	rcs.magic = CS_STUBS_MAGIC;
3257c478bdstevel@tonic-gate	rcs.function = CS_ENTRY_DEREGISTER;
3267c478bdstevel@tonic-gate	(void) csx_register_cardservices(&rcs);
3277c478bdstevel@tonic-gate
3287c478bdstevel@tonic-gate	/*
3297c478bdstevel@tonic-gate	 * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
3307c478bdstevel@tonic-gate	 *	from registering.
3317c478bdstevel@tonic-gate	 */
3327c478bdstevel@tonic-gate	mutex_enter(&cs_globals.global_lock);
3337c478bdstevel@tonic-gate	cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
3347c478bdstevel@tonic-gate	mutex_exit(&cs_globals.global_lock);
3357c478bdstevel@tonic-gate
3367c478bdstevel@tonic-gate	/*
3377c478bdstevel@tonic-gate	 * Go through each socket and make sure that there are no clients
3387c478bdstevel@tonic-gate	 *	on any of the sockets.  If there are, we can't deinit until
3397c478bdstevel@tonic-gate	 *	all the clients for every socket are gone.
3407c478bdstevel@tonic-gate	 */
3417c478bdstevel@tonic-gate	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3427c478bdstevel@tonic-gate	    if ((sp = cs_get_sp(sn)) != NULL) {
3437c478bdstevel@tonic-gate		have_sockets++;
3447c478bdstevel@tonic-gate		if (sp->client_list) {
3457c478bdstevel@tonic-gate		    cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
3467c478bdstevel@tonic-gate				"socket %d has registered clients\n", sn);
3477c478bdstevel@tonic-gate		    have_clients++;
3487c478bdstevel@tonic-gate		}
3497c478bdstevel@tonic-gate	    }
3507c478bdstevel@tonic-gate	}
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gate	/*
3537c478bdstevel@tonic-gate	 * We don't allow unload if there are any clients registered
3547c478bdstevel@tonic-gate	 *	or if there are still sockets that are active.
3557c478bdstevel@tonic-gate	 */
3567c478bdstevel@tonic-gate	if ((have_clients > 0) || (have_sockets > 0))
3577c478bdstevel@tonic-gate	    return (BAD_FUNCTION);
3587c478bdstevel@tonic-gate
3597c478bdstevel@tonic-gate#ifdef	XXX
3607c478bdstevel@tonic-gate	/*
3617c478bdstevel@tonic-gate	 * If one or more sockets have been added, we need to deallocate
3627c478bdstevel@tonic-gate	 *	the resources associated with those sockets.
3637c478bdstevel@tonic-gate	 */
3647c478bdstevel@tonic-gate
3657c478bdstevel@tonic-gate	/*
3667c478bdstevel@tonic-gate	 * First, tell Socket Services that we're leaving, so that we
3677c478bdstevel@tonic-gate	 *	don't get any more event callbacks.
3687c478bdstevel@tonic-gate	 */
3697c478bdstevel@tonic-gate	SocketServices(CSUnregister);
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gate	/*
3727c478bdstevel@tonic-gate	 * Wait for the soft int timer to tell us it's done
3737c478bdstevel@tonic-gate	 */
3747c478bdstevel@tonic-gate	mutex_enter(&cs_globals.global_lock);
3757c478bdstevel@tonic-gate	cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
3767c478bdstevel@tonic-gate	mutex_exit(&cs_globals.global_lock);
3777c478bdstevel@tonic-gate	UNTIMEOUT(cs_globals.sotfint_tmo);
3787c478bdstevel@tonic-gate
3797c478bdstevel@tonic-gate	/*
3807c478bdstevel@tonic-gate	 * Remove the soft interrupt handler.
3817c478bdstevel@tonic-gate	 */
3827c478bdstevel@tonic-gate	mutex_enter(&cs_globals.global_lock);
3837c478bdstevel@tonic-gate	if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
3847c478bdstevel@tonic-gate	    ddi_remove_softintr(cs_globals.softint_id);
3857c478bdstevel@tonic-gate	    cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
3867c478bdstevel@tonic-gate	}
3877c478bdstevel@tonic-gate	mutex_exit(&cs_globals.global_lock);
3887c478bdstevel@tonic-gate
3897c478bdstevel@tonic-gate	return (CS_SUCCESS);
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate	/*
3927c478bdstevel@tonic-gate	 * Go through each socket and free any resource allocated to that
3937c478bdstevel@tonic-gate	 *	socket, as well as any mutexs and condition variables.
3947c478bdstevel@tonic-gate	 */
3957c478bdstevel@tonic-gate	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3967c478bdstevel@tonic-gate	    set_socket_t set_socket;
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gate	    if ((sp = cs_get_sp(sn)) != NULL) {
3997c478bdstevel@tonic-gate
4007c478bdstevel@tonic-gate		/*
4017c478bdstevel@tonic-gate		 * untimeout possible pending ready/busy timer
4027c478bdstevel@tonic-gate		 */
4037c478bdstevel@tonic-gate		UNTIMEOUT(sp->rdybsy_tmo_id);
4047c478bdstevel@tonic-gate
4057c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4067c478bdstevel@tonic-gate		    mutex_enter(&sp->lock);
4077c478bdstevel@tonic-gate		sp->flags = SOCKET_UNLOAD_MODULE;
4087c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
4097c478bdstevel@tonic-gate		    sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
4107c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4117c478bdstevel@tonic-gate		    mutex_exit(&sp->lock);
4127c478bdstevel@tonic-gate
4137c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4147c478bdstevel@tonic-gate		    mutex_enter(&sp->cis_lock);
4157c478bdstevel@tonic-gate		(void) cs_destroy_cis(sp);
4167c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4177c478bdstevel@tonic-gate		    mutex_exit(&sp->cis_lock);
4187c478bdstevel@tonic-gate
4197c478bdstevel@tonic-gate		/*
4207c478bdstevel@tonic-gate		 * Tell the event handler thread that we want it to exit, then
4217c478bdstevel@tonic-gate		 *	wait around until it tells us that it has exited.
4227c478bdstevel@tonic-gate		 */
4237c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4247c478bdstevel@tonic-gate		    mutex_enter(&sp->client_lock);
4257c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
4267c478bdstevel@tonic-gate		    sp->thread_state = SOCKET_THREAD_EXIT;
4277c478bdstevel@tonic-gate		    cv_broadcast(&sp->thread_cv);
4287c478bdstevel@tonic-gate		    cv_wait(&sp->caller_cv, &sp->client_lock);
4297c478bdstevel@tonic-gate		}
4307c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4317c478bdstevel@tonic-gate		    mutex_exit(&sp->client_lock);
4327c478bdstevel@tonic-gate
4337c478bdstevel@tonic-gate		/*
4347c478bdstevel@tonic-gate		 * Tell the SS work thread that we want it to exit, then
4357c478bdstevel@tonic-gate		 *	wait around until it tells us that it has exited.
4367c478bdstevel@tonic-gate		 */
4377c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4387c478bdstevel@tonic-gate		    mutex_enter(&sp->ss_thread_lock);
4397c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
4407c478bdstevel@tonic-gate		    sp->ss_thread_state = SOCKET_THREAD_EXIT;
4417c478bdstevel@tonic-gate		    cv_broadcast(&sp->ss_thread_cv);
4427c478bdstevel@tonic-gate		    cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
4437c478bdstevel@tonic-gate		}
4447c478bdstevel@tonic-gate
4457c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4467c478bdstevel@tonic-gate		    mutex_exit(&sp->ss_thread_lock);
4477c478bdstevel@tonic-gate
4487c478bdstevel@tonic-gate		/*
4497c478bdstevel@tonic-gate		 * Free the mutexii and condition variables that we used.
4507c478bdstevel@tonic-gate		 */
4517c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
4527c478bdstevel@tonic-gate		    mutex_destroy(&sp->lock);
4537c478bdstevel@tonic-gate		    mutex_destroy(&sp->client_lock);
4547c478bdstevel@tonic-gate		    mutex_destroy(&sp->cis_lock);
4557c478bdstevel@tonic-gate		    mutex_destroy(&sp->ss_thread_lock);
4567c478bdstevel@tonic-gate		}
4577c478bdstevel@tonic-gate
4587c478bdstevel@tonic-gate		if (sp->init_state & SOCKET_INIT_STATE_CV) {
4597c478bdstevel@tonic-gate		    cv_destroy(&sp->thread_cv);
4607c478bdstevel@tonic-gate		    cv_destroy(&sp->caller_cv);
4617c478bdstevel@tonic-gate		    cv_destroy(&sp->reset_cv);
4627c478bdstevel@tonic-gate		    cv_destroy(&sp->ss_thread_cv);
4637c478bdstevel@tonic-gate		    cv_destroy(&sp->ss_caller_cv);
4647c478bdstevel@tonic-gate		}
4657c478bdstevel@tonic-gate
4667c478bdstevel@tonic-gate#ifdef	USE_IOMMAP_WINDOW
4677c478bdstevel@tonic-gate		/*
4687c478bdstevel@tonic-gate		 * Free the memory-mapped IO structure if we allocated one.
4697c478bdstevel@tonic-gate		 */
4707c478bdstevel@tonic-gate		if (sp->io_mmap_window)
4717c478bdstevel@tonic-gate		    kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
4727c478bdstevel@tonic-gate#endif	/* USE_IOMMAP_WINDOW */
4737c478bdstevel@tonic-gate
4747c478bdstevel@tonic-gate		/*
4757c478bdstevel@tonic-gate		 * Return the socket to memory-only mode and turn off the
4767c478bdstevel@tonic-gate		 *	socket power.
4777c478bdstevel@tonic-gate		 */
4787c478bdstevel@tonic-gate		sp->event_mask = 0;
4797c478bdstevel@tonic-gate		set_socket.socket = sp->socket_num;
4807c478bdstevel@tonic-gate		set_socket.SCIntMask = 0;
4817c478bdstevel@tonic-gate		set_socket.IREQRouting = 0;
4827c478bdstevel@tonic-gate		set_socket.IFType = IF_MEMORY;
4837c478bdstevel@tonic-gate		set_socket.CtlInd = 0; /* turn off controls and indicators */
4847c478bdstevel@tonic-gate		set_socket.State = (unsigned)~0; /* clear latched state bits */
4857c478bdstevel@tonic-gate
4867c478bdstevel@tonic-gate		(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
4877c478bdstevel@tonic-gate						&set_socket.VccLevel);
4887c478bdstevel@tonic-gate		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
4897c478bdstevel@tonic-gate						&set_socket.Vpp1Level);
4907c478bdstevel@tonic-gate		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
4917c478bdstevel@tonic-gate						&set_socket.Vpp2Level);
4927c478bdstevel@tonic-gate
4937c478bdstevel@tonic-gate		/*
4947c478bdstevel@tonic-gate		 * If we fail this call, there's not much we can do, so
4957c478bdstevel@tonic-gate		 *	just continue with the resource deallocation.
4967c478bdstevel@tonic-gate		 */
4977c478bdstevel@tonic-gate		if ((ret =
4987c478bdstevel@tonic-gate			SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
4997c478bdstevel@tonic-gate		    cmn_err(CE_CONT,
5007c478bdstevel@tonic-gate			"cs_deinit: socket %d SS_SetSocket failure %d\n",
5017c478bdstevel@tonic-gate							sp->socket_num, ret);
5027c478bdstevel@tonic-gate		}
5037c478bdstevel@tonic-gate	    } /* cs_get_sp */
5047c478bdstevel@tonic-gate	} /* for (sn) */
5057c478bdstevel@tonic-gate#endif	/* XXX */
5067c478bdstevel@tonic-gate
5077c478bdstevel@tonic-gate	/*
5087c478bdstevel@tonic-gate	 * Destroy the global mutexii.
5097c478bdstevel@tonic-gate	 */
5107c478bdstevel@tonic-gate	mutex_destroy(&cs_globals.global_lock);
5117c478bdstevel@tonic-gate	mutex_destroy(&cs_globals.window_lock);
5127c478bdstevel@tonic-gate
5137c478bdstevel@tonic-gate#ifdef	XXX
5147c478bdstevel@tonic-gate	/*
5157c478bdstevel@tonic-gate	 * Free the global "super-client" structure
5167c478bdstevel@tonic-gate	 */
5177c478bdstevel@tonic-gate	if (cs_globals.sclient_list)
5187c478bdstevel@tonic-gate	    kmem_free(cs_globals.sclient_list,
5197c478bdstevel@tonic-gate		(cs_globals.num_sockets * sizeof (struct sclient_list_t)));
5207c478bdstevel@tonic-gate	cs_globals.sclient_list = NULL;
5217c478bdstevel@tonic-gate#endif	/* XXX */
5227c478bdstevel@tonic-gate
5237c478bdstevel@tonic-gate	return (CS_SUCCESS);
5247c478bdstevel@tonic-gate}
5257c478bdstevel@tonic-gate
5267c478bdstevel@tonic-gate/*
5277c478bdstevel@tonic-gate * ==== drip, drip, drip - the Card Services waterfall :-) ====
5287c478bdstevel@tonic-gate */
5297c478bdstevel@tonic-gate
5307c478bdstevel@tonic-gate/*
5317c478bdstevel@tonic-gate * CardServices - general Card Services entry point for CS clients
5327c478bdstevel@tonic-gate *			and Socket Services; the address of this
5337c478bdstevel@tonic-gate *			function is handed to SS via the CSRegister
5347c478bdstevel@tonic-gate *			SS call
5357c478bdstevel@tonic-gate */
5367c478bdstevel@tonic-gateint
5377c478bdstevel@tonic-gateCardServices(int function, ...)
5387c478bdstevel@tonic-gate{
5397c478bdstevel@tonic-gate	va_list arglist;
5407c478bdstevel@tonic-gate	int retcode = CS_UNSUPPORTED_FUNCTION;
5417c478bdstevel@tonic-gate
5427c478bdstevel@tonic-gate	cs_socket_t	*socp;
5437c478bdstevel@tonic-gate	uint32_t	*offp;
5447c478bdstevel@tonic-gate	acc_handle_t	*hp;
5457c478bdstevel@tonic-gate	client_handle_t	ch;
5467c478bdstevel@tonic-gate	client_handle_t	*chp;
5477c478bdstevel@tonic-gate	window_handle_t	wh;
5487c478bdstevel@tonic-gate	window_handle_t	*whp;
5497c478bdstevel@tonic-gate	tuple_t		*tuple;
5507c478bdstevel@tonic-gate	cisparse_t	*cisparse;
5517c478bdstevel@tonic-gate
5527c478bdstevel@tonic-gate#ifdef	CS_DEBUG
5537c478bdstevel@tonic-gate	if (cs_debug > 127) {
5547c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
5557c478bdstevel@tonic-gate				cs_error2text(function, CSFUN2TEXT_FUNCTION),
5567c478bdstevel@tonic-gate				function);
5577c478bdstevel@tonic-gate	}
5587c478bdstevel@tonic-gate#endif
5597c478bdstevel@tonic-gate
5607c478bdstevel@tonic-gate	va_start(arglist, function);
5617c478bdstevel@tonic-gate
5627c478bdstevel@tonic-gate	/*
5637c478bdstevel@tonic-gate	 * Here's the Card Services waterfall
5647c478bdstevel@tonic-gate	 */
5657c478bdstevel@tonic-gate	switch (function) {
5667c478bdstevel@tonic-gate	/*
5677c478bdstevel@tonic-gate	 * We got here as a result of the CIS module calling us
5687c478bdstevel@tonic-gate	 *	in response to cs_ss_init() calling the CIS module
5697c478bdstevel@tonic-gate	 *	at CIS_PARSER(CISP_CIS_SETUP, ...)
5707c478bdstevel@tonic-gate	 */
5717c478bdstevel@tonic-gate	    case CISRegister: {
5727c478bdstevel@tonic-gate		cisregister_t *cisr;
5737c478bdstevel@tonic-gate
5747c478bdstevel@tonic-gate		    cisr = va_arg(arglist, cisregister_t *);
5757c478bdstevel@tonic-gate
5767c478bdstevel@tonic-gate		    if (cisr->cis_magic != PCCS_MAGIC ||
5777c478bdstevel@tonic-gate			cisr->cis_version != PCCS_VERSION) {
5787c478bdstevel@tonic-gate			    cmn_err(CE_WARN,
5797c478bdstevel@tonic-gate				"CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
5807c478bdstevel@tonic-gate					(long)cisr->cis_magic,
5817c478bdstevel@tonic-gate					(long)cisr->cis_version,
5827c478bdstevel@tonic-gate					(long)cisr->cis_parser,
5837c478bdstevel@tonic-gate					(long)cisr->cistpl_std_callout);
5847c478bdstevel@tonic-gate			retcode = CS_BAD_ARGS;
5857c478bdstevel@tonic-gate		    } else {
5867c478bdstevel@tonic-gate			/*
5877c478bdstevel@tonic-gate			 * Replace the CIS Parser entry point if
5887c478bdstevel@tonic-gate			 *	necessary.
5897c478bdstevel@tonic-gate			 */
5907c478bdstevel@tonic-gate			if (cisr->cis_parser != NULL)
5917c478bdstevel@tonic-gate			    cis_parser = cisr->cis_parser;
5927c478bdstevel@tonic-gate			cis_cistpl_std_callout = cisr->cistpl_std_callout;
5937c478bdstevel@tonic-gate			retcode = CS_SUCCESS;
5947c478bdstevel@tonic-gate		    }
5957c478bdstevel@tonic-gate		}
5967c478bdstevel@tonic-gate		break;
5977c478bdstevel@tonic-gate	    case CISUnregister:	/* XXX - should we do some more checking */
5987c478bdstevel@tonic-gate		/* XXX - need to protect this by a mutex */
5997c478bdstevel@tonic-gate		cis_parser = NULL;
6007c478bdstevel@tonic-gate		cis_cistpl_std_callout = NULL;
6017c478bdstevel@tonic-gate		retcode = CS_SUCCESS;
6027c478bdstevel@tonic-gate		break;
6037c478bdstevel@tonic-gate	    case InitCISWindow:
6047c478bdstevel@tonic-gate		socp	= va_arg(arglist, cs_socket_t *);
6057c478bdstevel@tonic-gate		offp	= va_arg(arglist, uint32_t *);
6067c478bdstevel@tonic-gate		hp	= va_arg(arglist, acc_handle_t *);
6077c478bdstevel@tonic-gate		retcode = cs_init_cis_window(socp, offp, hp,
6087c478bdstevel@tonic-gate				va_arg(arglist, uint32_t));
6097c478bdstevel@tonic-gate		break;
6107c478bdstevel@tonic-gate	    case RegisterClient:
6117c478bdstevel@tonic-gate		chp = va_arg(arglist, client_handle_t *),
6127c478bdstevel@tonic-gate		retcode = cs_register_client(chp,
6137c478bdstevel@tonic-gate				va_arg(arglist, client_reg_t *));
6147c478bdstevel@tonic-gate		break;
6157c478bdstevel@tonic-gate	    case DeregisterClient:
6167c478bdstevel@tonic-gate		retcode = cs_deregister_client(
6177c478bdstevel@tonic-gate				va_arg(arglist, client_handle_t));
6187c478bdstevel@tonic-gate		break;
6197c478bdstevel@tonic-gate	    case GetStatus:
6207c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6217c478bdstevel@tonic-gate		retcode = cs_get_status(ch,
6227c478bdstevel@tonic-gate				va_arg(arglist, get_status_t *));
6237c478bdstevel@tonic-gate		break;
6247c478bdstevel@tonic-gate	    case ResetFunction:
6257c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6267c478bdstevel@tonic-gate		retcode = cs_reset_function(ch,
6277c478bdstevel@tonic-gate				va_arg(arglist, reset_function_t *));
6287c478bdstevel@tonic-gate		break;
6297c478bdstevel@tonic-gate	    case SetEventMask:
6307c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6317c478bdstevel@tonic-gate		retcode = cs_set_event_mask(ch,
6327c478bdstevel@tonic-gate				va_arg(arglist, sockevent_t *));
6337c478bdstevel@tonic-gate		break;
6347c478bdstevel@tonic-gate	    case GetEventMask:
6357c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6367c478bdstevel@tonic-gate		retcode = cs_get_event_mask(ch,
6377c478bdstevel@tonic-gate				va_arg(arglist, sockevent_t *));
6387c478bdstevel@tonic-gate		break;
6397c478bdstevel@tonic-gate	    case RequestIO:
6407c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6417c478bdstevel@tonic-gate		retcode = cs_request_io(ch,
6427c478bdstevel@tonic-gate				va_arg(arglist, io_req_t *));
6437c478bdstevel@tonic-gate		break;
6447c478bdstevel@tonic-gate	    case ReleaseIO:
6457c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6467c478bdstevel@tonic-gate		retcode = cs_release_io(ch,
6477c478bdstevel@tonic-gate				va_arg(arglist, io_req_t *));
6487c478bdstevel@tonic-gate		break;
6497c478bdstevel@tonic-gate	    case RequestIRQ:
6507c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6517c478bdstevel@tonic-gate		retcode = cs_request_irq(ch,
6527c478bdstevel@tonic-gate				va_arg(arglist, irq_req_t *));
6537c478bdstevel@tonic-gate		break;
6547c478bdstevel@tonic-gate	    case ReleaseIRQ:
6557c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6567c478bdstevel@tonic-gate		retcode = cs_release_irq(ch,
6577c478bdstevel@tonic-gate				va_arg(arglist, irq_req_t *));
6587c478bdstevel@tonic-gate		break;
6597c478bdstevel@tonic-gate	    case RequestWindow:
6607c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6617c478bdstevel@tonic-gate		whp = va_arg(arglist, window_handle_t *);
6627c478bdstevel@tonic-gate		retcode = cs_request_window(ch, whp,
6637c478bdstevel@tonic-gate				va_arg(arglist, win_req_t *));
6647c478bdstevel@tonic-gate		break;
6657c478bdstevel@tonic-gate	    case ReleaseWindow:
6667c478bdstevel@tonic-gate		retcode = cs_release_window(
6677c478bdstevel@tonic-gate				va_arg(arglist, window_handle_t));
6687c478bdstevel@tonic-gate		break;
6697c478bdstevel@tonic-gate	    case ModifyWindow:
6707c478bdstevel@tonic-gate		wh = va_arg(arglist, window_handle_t);
6717c478bdstevel@tonic-gate		retcode = cs_modify_window(wh,
6727c478bdstevel@tonic-gate				va_arg(arglist, modify_win_t *));
6737c478bdstevel@tonic-gate		break;
6747c478bdstevel@tonic-gate	    case MapMemPage:
6757c478bdstevel@tonic-gate		wh = va_arg(arglist, window_handle_t);
6767c478bdstevel@tonic-gate		retcode = cs_map_mem_page(wh,
6777c478bdstevel@tonic-gate				va_arg(arglist, map_mem_page_t *));
6787c478bdstevel@tonic-gate		break;
6797c478bdstevel@tonic-gate	    case RequestSocketMask:
6807c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6817c478bdstevel@tonic-gate		retcode = cs_request_socket_mask(ch,
6827c478bdstevel@tonic-gate				va_arg(arglist, request_socket_mask_t *));
6837c478bdstevel@tonic-gate		break;
6847c478bdstevel@tonic-gate	    case ReleaseSocketMask:
6857c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6867c478bdstevel@tonic-gate		retcode = cs_release_socket_mask(ch,
6877c478bdstevel@tonic-gate				va_arg(arglist, release_socket_mask_t *));
6887c478bdstevel@tonic-gate		break;
6897c478bdstevel@tonic-gate	    case RequestConfiguration:
6907c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6917c478bdstevel@tonic-gate		retcode = cs_request_configuration(ch,
6927c478bdstevel@tonic-gate				va_arg(arglist, config_req_t *));
6937c478bdstevel@tonic-gate		break;
6947c478bdstevel@tonic-gate	    case GetPhysicalAdapterInfo:
6957c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
6967c478bdstevel@tonic-gate		retcode = cs_get_physical_adapter_info(ch,
6977c478bdstevel@tonic-gate				va_arg(arglist, get_physical_adapter_info_t *));
6987c478bdstevel@tonic-gate		break;
6997c478bdstevel@tonic-gate	    case GetCardServicesInfo:
7007c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
7017c478bdstevel@tonic-gate		retcode = cs_get_cardservices_info(ch,
7027c478bdstevel@tonic-gate				va_arg(arglist, get_cardservices_info_t *));
7037c478bdstevel@tonic-gate		break;
7047c478bdstevel@tonic-gate	    case GetConfigurationInfo:
7057c478bdstevel@tonic-gate		chp = va_arg(arglist, client_handle_t *);
7067c478bdstevel@tonic-gate		retcode = cs_get_configuration_info(chp,
7077c478bdstevel@tonic-gate				va_arg(arglist, get_configuration_info_t *));
7087c478bdstevel@tonic-gate		break;
7097c478bdstevel@tonic-gate	    case ModifyConfiguration:
7107c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
7117c478bdstevel@tonic-gate		retcode = cs_modify_configuration(ch,
7127c478bdstevel@tonic-gate				va_arg(arglist, modify_config_t *));
7137c478bdstevel@tonic-gate		break;
7147c478bdstevel@tonic-gate	    case AccessConfigurationRegister:
7157c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
7167c478bdstevel@tonic-gate		retcode = cs_access_configuration_register(ch,
7177c478bdstevel@tonic-gate				va_arg(arglist, access_config_reg_t *));
7187c478bdstevel@tonic-gate		break;
7197c478bdstevel@tonic-gate	    case ReleaseConfiguration:
7207c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
7217c478bdstevel@tonic-gate		retcode = cs_release_configuration(ch,
7227c478bdstevel@tonic-gate				va_arg(arglist, release_config_t *));
7237c478bdstevel@tonic-gate		break;
7247c478bdstevel@tonic-gate	    case OpenMemory:
7257c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: OpenMemory\n");
7267c478bdstevel@tonic-gate		break;
7277c478bdstevel@tonic-gate	    case ReadMemory:
7287c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: ReadMemory\n");
7297c478bdstevel@tonic-gate		break;
7307c478bdstevel@tonic-gate	    case WriteMemory:
7317c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: WriteMemory\n");
7327c478bdstevel@tonic-gate		break;
7337c478bdstevel@tonic-gate	    case CopyMemory:
7347c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: CopyMemory\n");
7357c478bdstevel@tonic-gate		break;
7367c478bdstevel@tonic-gate	    case RegisterEraseQueue:
7377c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
7387c478bdstevel@tonic-gate		break;
7397c478bdstevel@tonic-gate	    case CheckEraseQueue:
7407c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
7417c478bdstevel@tonic-gate		break;
7427c478bdstevel@tonic-gate	    case DeregisterEraseQueue:
7437c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
7447c478bdstevel@tonic-gate		break;
7457c478bdstevel@tonic-gate	    case CloseMemory:
7467c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: CloseMemory\n");
7477c478bdstevel@tonic-gate		break;
7487c478bdstevel@tonic-gate	    case GetFirstRegion:
7497c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: GetFirstRegion\n");
7507c478bdstevel@tonic-gate		break;
7517c478bdstevel@tonic-gate	    case GetNextRegion:
7527c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: GetNextRegion\n");
7537c478bdstevel@tonic-gate		break;
7547c478bdstevel@tonic-gate	    case GetFirstPartition:
7557c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: GetFirstPartition\n");
7567c478bdstevel@tonic-gate		break;
7577c478bdstevel@tonic-gate	    case GetNextPartition:
7587c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: GetNextPartition\n");
7597c478bdstevel@tonic-gate		break;
7607c478bdstevel@tonic-gate	    case ReturnSSEntry:
7617c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
7627c478bdstevel@tonic-gate		break;
7637c478bdstevel@tonic-gate	    case MapLogSocket:
7647c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
7657c478bdstevel@tonic-gate		retcode = cs_map_log_socket(ch,
7667c478bdstevel@tonic-gate				va_arg(arglist, map_log_socket_t *));
7677c478bdstevel@tonic-gate		break;
7687c478bdstevel@tonic-gate	    case MapPhySocket:
7697c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: MapPhySocket\n");
7707c478bdstevel@tonic-gate		break;
7717c478bdstevel@tonic-gate	    case MapLogWindow:
7727c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: MapLogWindow\n");
7737c478bdstevel@tonic-gate		break;
7747c478bdstevel@tonic-gate	    case MapPhyWindow:
7757c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: MapPhyWindow\n");
7767c478bdstevel@tonic-gate		break;
7777c478bdstevel@tonic-gate	    case RegisterMTD:
7787c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: RegisterMTD\n");
7797c478bdstevel@tonic-gate		break;
7807c478bdstevel@tonic-gate	    case RegisterTimer:
7817c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: RegisterTimer\n");
7827c478bdstevel@tonic-gate		break;
7837c478bdstevel@tonic-gate	    case SetRegion:
7847c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: SetRegion\n");
7857c478bdstevel@tonic-gate		break;
7867c478bdstevel@tonic-gate	    case RequestExclusive:
7877c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: RequestExclusive\n");
7887c478bdstevel@tonic-gate		break;
7897c478bdstevel@tonic-gate	    case ReleaseExclusive:
7907c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
7917c478bdstevel@tonic-gate		break;
7927c478bdstevel@tonic-gate	    case GetFirstClient:
7937c478bdstevel@tonic-gate		retcode = cs_get_firstnext_client(
7947c478bdstevel@tonic-gate				va_arg(arglist, get_firstnext_client_t *),
7957c478bdstevel@tonic-gate				CS_GET_FIRST_FLAG);
7967c478bdstevel@tonic-gate		break;
7977c478bdstevel@tonic-gate	    case GetNextClient:
7987c478bdstevel@tonic-gate		retcode = cs_get_firstnext_client(
7997c478bdstevel@tonic-gate				va_arg(arglist, get_firstnext_client_t *),
8007c478bdstevel@tonic-gate				CS_GET_NEXT_FLAG);
8017c478bdstevel@tonic-gate		break;
8027c478bdstevel@tonic-gate	    case GetClientInfo:
8037c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8047c478bdstevel@tonic-gate		retcode = cs_get_client_info(ch,
8057c478bdstevel@tonic-gate				va_arg(arglist, client_info_t *));
8067c478bdstevel@tonic-gate		break;
8077c478bdstevel@tonic-gate	    case AddSocketServices:
8087c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: AddSocketServices\n");
8097c478bdstevel@tonic-gate		break;
8107c478bdstevel@tonic-gate	    case ReplaceSocketServices:
8117c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
8127c478bdstevel@tonic-gate		break;
8137c478bdstevel@tonic-gate	    case VendorSpecific:
8147c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: VendorSpecific\n");
8157c478bdstevel@tonic-gate		break;
8167c478bdstevel@tonic-gate	    case AdjustResourceInfo:
8177c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
8187c478bdstevel@tonic-gate		break;
8197c478bdstevel@tonic-gate	    case ValidateCIS:
8207c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8217c478bdstevel@tonic-gate		retcode = cs_validate_cis(ch,
8227c478bdstevel@tonic-gate				va_arg(arglist, cisinfo_t *));
8237c478bdstevel@tonic-gate		break;
8247c478bdstevel@tonic-gate	    case GetFirstTuple:
8257c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8267c478bdstevel@tonic-gate		retcode = cs_get_firstnext_tuple(ch,
8277c478bdstevel@tonic-gate				va_arg(arglist, tuple_t *),
8287c478bdstevel@tonic-gate				CS_GET_FIRST_FLAG);
8297c478bdstevel@tonic-gate		break;
8307c478bdstevel@tonic-gate	    case GetNextTuple:
8317c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8327c478bdstevel@tonic-gate		retcode = cs_get_firstnext_tuple(ch,
8337c478bdstevel@tonic-gate				va_arg(arglist, tuple_t *),
8347c478bdstevel@tonic-gate				CS_GET_NEXT_FLAG);
8357c478bdstevel@tonic-gate		break;
8367c478bdstevel@tonic-gate	    case GetTupleData:
8377c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8387c478bdstevel@tonic-gate		retcode = cs_get_tuple_data(ch,
8397c478bdstevel@tonic-gate				va_arg(arglist, tuple_t *));
8407c478bdstevel@tonic-gate		break;
8417c478bdstevel@tonic-gate	    case ParseTuple:
8427c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8437c478bdstevel@tonic-gate		tuple = va_arg(arglist, tuple_t *);
8447c478bdstevel@tonic-gate		cisparse = va_arg(arglist, cisparse_t *);
8457c478bdstevel@tonic-gate		retcode = cs_parse_tuple(ch, tuple, cisparse,
8467c478bdstevel@tonic-gate				va_arg(arglist, uint_t));
8477c478bdstevel@tonic-gate		break;
8487c478bdstevel@tonic-gate	    case MakeDeviceNode:
8497c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8507c478bdstevel@tonic-gate		retcode = cs_make_device_node(ch,
8517c478bdstevel@tonic-gate				va_arg(arglist, make_device_node_t *));
8527c478bdstevel@tonic-gate		break;
8537c478bdstevel@tonic-gate	    case RemoveDeviceNode:
8547c478bdstevel@tonic-gate		ch = va_arg(arglist, client_handle_t);
8557c478bdstevel@tonic-gate		retcode = cs_remove_device_node(ch,
8567c478bdstevel@tonic-gate				va_arg(arglist, remove_device_node_t *));
8577c478bdstevel@tonic-gate		break;
8587c478bdstevel@tonic-gate	    case ConvertSpeed:
8597c478bdstevel@tonic-gate		retcode = cs_convert_speed(
8607c478bdstevel@tonic-gate				va_arg(arglist, convert_speed_t *));
8617c478bdstevel@tonic-gate		break;
8627c478bdstevel@tonic-gate	    case ConvertSize:
8637c478bdstevel@tonic-gate		retcode = cs_convert_size(
8647c478bdstevel@tonic-gate				va_arg(arglist, convert_size_t *));
8657c478bdstevel@tonic-gate		break;
8667c478bdstevel@tonic-gate	    case Event2Text:
8677c478bdstevel@tonic-gate		retcode = cs_event2text(
8687c478bdstevel@tonic-gate				va_arg(arglist, event2text_t *), 1);
8697c478bdstevel@tonic-gate		break;
8707c478bdstevel@tonic-gate	    case Error2Text: {
8717c478bdstevel@tonic-gate		error2text_t *cft;
8727c478bdstevel@tonic-gate
8737c478bdstevel@tonic-gate		cft = va_arg(arglist, error2text_t *);
8747c478bdstevel@tonic-gate		(void) strcpy(cft->text,
8757c478bdstevel@tonic-gate				cs_error2text(cft->item, CSFUN2TEXT_RETURN));
8767c478bdstevel@tonic-gate		retcode = CS_SUCCESS;
8777c478bdstevel@tonic-gate		}
8787c478bdstevel@tonic-gate		break;
8797c478bdstevel@tonic-gate	    case CS_DDI_Info:
8807c478bdstevel@tonic-gate		retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
8817c478bdstevel@tonic-gate		break;
8827c478bdstevel@tonic-gate	    case CS_Sys_Ctl:
8837c478bdstevel@tonic-gate		retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
8847c478bdstevel@tonic-gate		break;
8857c478bdstevel@tonic-gate	    default:
8867c478bdstevel@tonic-gate		cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
8877c478bdstevel@tonic-gate		break;
8887c478bdstevel@tonic-gate	} /* switch(function) */
8897c478bdstevel@tonic-gate
8907c478bdstevel@tonic-gate	va_end(arglist);
8917c478bdstevel@tonic-gate
8927c478bdstevel@tonic-gate#ifdef	CS_DEBUG
8937c478bdstevel@tonic-gate	if (cs_debug > 127) {
8947c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
8957c478bdstevel@tonic-gate				cs_error2text(retcode, CSFUN2TEXT_RETURN),
8967c478bdstevel@tonic-gate				retcode);
8977c478bdstevel@tonic-gate	}
8987c478bdstevel@tonic-gate#endif
8997c478bdstevel@tonic-gate
9007c478bdstevel@tonic-gate	return (retcode);
9017c478bdstevel@tonic-gate}
9027c478bdstevel@tonic-gate
9037c478bdstevel@tonic-gate/*
9047c478bdstevel@tonic-gate * ==== tuple and CIS handling section ====
9057c478bdstevel@tonic-gate */
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate/*
9087c478bdstevel@tonic-gate * cs_parse_tuple - This function supports the CS ParseTuple function call.
9097c478bdstevel@tonic-gate *
9107c478bdstevel@tonic-gate *    returns:	CS_SUCCESS - if tuple parsed sucessfully
9117c478bdstevel@tonic-gate *		CS_NO_CARD - if no card in socket
9127c478bdstevel@tonic-gate *		CS_BAD_ARGS - if passed CIS list pointer is NULL
9137c478bdstevel@tonic-gate *		CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
9147c478bdstevel@tonic-gate *		CS_BAD_CIS - if generic parser error
9157c478bdstevel@tonic-gate *		CS_NO_CIS - if no CIS for card/function
9167c478bdstevel@tonic-gate *
9177c478bdstevel@tonic-gate *    See notes for the cs_get_firstnext_tuple function.
9187c478bdstevel@tonic-gate */
9197c478bdstevel@tonic-gatestatic int
9207c478bdstevel@tonic-gatecs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
9217c478bdstevel@tonic-gate				cisparse_t *cisparse, cisdata_t cisdata)
9227c478bdstevel@tonic-gate{
9237c478bdstevel@tonic-gate	cs_socket_t *sp;
9247c478bdstevel@tonic-gate	client_t *client;
9257c478bdstevel@tonic-gate	uint32_t fn;
9267c478bdstevel@tonic-gate	int ret;
9277c478bdstevel@tonic-gate
9287c478bdstevel@tonic-gate	if ((ret = cs_get_socket(client_handle, &tuple->Socket,
9297c478bdstevel@tonic-gate					&fn, &sp, &client)) != CS_SUCCESS)
9307c478bdstevel@tonic-gate	    return (ret);
9317c478bdstevel@tonic-gate
9327c478bdstevel@tonic-gate	/*
9337c478bdstevel@tonic-gate	 * If there's no card in the socket or the card in the socket is not
9347c478bdstevel@tonic-gate	 *	for this client, then return an error.
9357c478bdstevel@tonic-gate	 */
9367c478bdstevel@tonic-gate	if (!(client->flags & CLIENT_CARD_INSERTED))
9377c478bdstevel@tonic-gate	    return (CS_NO_CARD);
9387c478bdstevel@tonic-gate
9397c478bdstevel@tonic-gate	/*
9407c478bdstevel@tonic-gate	 * Sanity check to be sure that we've got a non-NULL CIS list
9417c478bdstevel@tonic-gate	 *	pointer.
9427c478bdstevel@tonic-gate	 */
9437c478bdstevel@tonic-gate	if (!(tuple->CISOffset))
9447c478bdstevel@tonic-gate	    return (CS_BAD_ARGS);
9457c478bdstevel@tonic-gate
9467c478bdstevel@tonic-gate	mutex_enter(&sp->cis_lock);
9477c478bdstevel@tonic-gate
9487c478bdstevel@tonic-gate	/*
9497c478bdstevel@tonic-gate	 * Check to see if there is a valid CIS for this function.
9507c478bdstevel@tonic-gate	 *	There is an implicit assumption here that if this
9517c478bdstevel@tonic-gate	 *	is a multi-function CIS and the specified function
9527c478bdstevel@tonic-gate	 *	number is not CS_GLOBAL_CIS that in order for there
9537c478bdstevel@tonic-gate	 *	to be a valid function-specific CIS, there also must
9547c478bdstevel@tonic-gate	 *	be a valid global CIS. This means that we don't need
9557c478bdstevel@tonic-gate	 *	to know whether this tuple came from the global CIS
9567c478bdstevel@tonic-gate	 *	or from the function-specific CIS.
9577c478bdstevel@tonic-gate	 */
9587c478bdstevel@tonic-gate	if ((sp->cis_flags & CW_VALID_CIS) &&
9597c478bdstevel@tonic-gate				(sp->cis[fn].flags & CW_VALID_CIS)) {
9607c478bdstevel@tonic-gate	    ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
9617c478bdstevel@tonic-gate				cis_cistpl_std_callout,
9627c478bdstevel@tonic-gate				tuple->CISOffset,
9637c478bdstevel@tonic-gate				(tuple->Attributes & TUPLE_RETURN_NAME)?
9647c478bdstevel@tonic-gate							HANDTPL_RETURN_NAME:
9657c478bdstevel@tonic-gate							HANDTPL_PARSE_LTUPLE,
9667c478bdstevel@tonic-gate				cisparse, cisdata);
9677c478bdstevel@tonic-gate	    mutex_exit(&sp->cis_lock);
9687c478bdstevel@tonic-gate	    if (ret == CISTPLF_UNKNOWN)
9697c478bdstevel@tonic-gate		return (CS_UNKNOWN_TUPLE);
9707c478bdstevel@tonic-gate	    if (ret != CISTPLF_NOERROR)
9717c478bdstevel@tonic-gate		return (CS_BAD_CIS);
9727c478bdstevel@tonic-gate	    ret = CS_SUCCESS;
9737c478bdstevel@tonic-gate	} else {
9747c478bdstevel@tonic-gate	    mutex_exit(&sp->cis_lock);
9757c478bdstevel@tonic-gate	    ret = CS_NO_CIS;
9767c478bdstevel@tonic-gate	} /* if (CW_VALID_CIS) */
9777c478bdstevel@tonic-gate
9787c478bdstevel@tonic-gate	return (ret);
9797c478bdstevel@tonic-gate}
9807c478bdstevel@tonic-gate
9817c478bdstevel@tonic-gate/*
9827c478bdstevel@tonic-gate * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
9837c478bdstevel@tonic-gate *				this is to support the GetFirstTuple and
9847c478bdstevel@tonic-gate *				GetNextTuple function call
9857c478bdstevel@tonic-gate *
9867c478bdstevel@tonic-gate *    flags - one of:
9877c478bdstevel@tonic-gate *		CS_GET_FIRST_FLAG causes function to support GetFirstTuple
9887c478bdstevel@tonic-gate *		CS_GET_NEXT_FLAG causes function to support GetNextTuple
9897c478bdstevel@tonic-gate *
9907c478bdstevel@tonic-gate *	tuple_t->Attributes flags:
9917c478bdstevel@tonic-gate *		TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
9927c478bdstevel@tonic-gate *		TUPLE_RETURN_IGNORED_TUPLES - return tuples with
9937c478bdstevel@tonic-gate *				CISTPLF_IGNORE_TUPLE set in the
9947c478bdstevel@tonic-gate *				cistpl_t->flags member.
9957c478bdstevel@tonic-gate *
9967c478bdstevel@tonic-gate *    Notes for regular PC card driver callers:
9977c478bdstevel@tonic-gate *
9987c478bdstevel@tonic-gate *	On a single-function card, the caller will get back all the tuples in
9997c478bdstevel@tonic-gate *	the CIS.
10007c478bdstevel@tonic-gate *
10017c478bdstevel@tonic-gate *	On a multi-function card, the caller will get the tuples from the
10027c478bdstevel@tonic-gate *	global CIS followed by the tuples in the function-specific CIS. The
10037c478bdstevel@tonic-gate *	caller will not get any tuples from a function-specific CIS that
10047c478bdstevel@tonic-gate *	does not belong to the caller's function.
10057c478bdstevel@tonic-gate *
10067c478bdstevel@tonic-gate *    Notes for Socket Services, the "super-client" or CSI driver callers:
10077c478bdstevel@tonic-gate *
10087c478bdstevel@tonic-gate *	On a single-function card, the operation is the same as for regular
10097c478bdstevel@tonic-gate *	PC card driver callers with the addition that if the function number
10107c478bdstevel@tonic-gate *	is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
10117c478bdstevel@tonic-gate *
10127c478bdstevel@tonic-gate *	On a multi-function card, the operation is the same as for regular
10137c478bdstevel@tonic-gate *	PC card driver callers with the addition that if the function number
10147c478bdstevel@tonic-gate *	is set to CS_GLOBAL_CIS the caller will only get tuples from the
10157c478bdstevel@tonic-gate *	global CIS. If a particular function nubmer does not exist, this
10167c478bdstevel@tonic-gate *	function will return CS_NO_CIS for that function.
10177c478bdstevel@tonic-gate *
10187c478bdstevel@tonic-gate *    General notes:
10197c478bdstevel@tonic-gate *
10207c478bdstevel@tonic-gate *	On both a single-function card and a multi-function card, if the tuple
10217c478bdstevel@tonic-gate *	comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
10227c478bdstevel@tonic-gate *	set in the tuple_t->flags member.
10237c478bdstevel@tonic-gate *
10247c478bdstevel@tonic-gate *	On a multi-function card, if the tuple comes from the function-specific
10257c478bdstevel@tonic-gate *	CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
10267c478bdstevel@tonic-gate *	member.
10277c478bdstevel@tonic-gate *
10287c478bdstevel@tonic-gate *	For other flags that are set in the tuple_t->flags member, see the
10297c478bdstevel@tonic-gate *	comments for the cis_list_lcreate function in the cis.c file.
10307c478bdstevel@tonic-gate *
10317c478bdstevel@tonic-gate *	The CIS parser may not include all the tuples that are in the CIS in
10327c478bdstevel@tonic-gate *	the private CIS list that it creates and maintains. See the CIS
10337c478bdstevel@tonic-gate *	parser documentation for a list of tuples that the parser does not
10347c478bdstevel@tonic-gate *	include in the list.
10357c478bdstevel@tonic-gate *
10367c478bdstevel@tonic-gate *	If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
10377c478bdstevel@tonic-gate *	parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
10387c478bdstevel@tonic-gate *	be returned to the caller. Instead, the next tuple that matches
10397c478bdstevel@tonic-gate *	the calling criteria will be returned (or NULL if no other tuples
10407c478bdstevel@tonic-gate *	match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
10417c478bdstevel@tonic-gate *	the flags paramter, tuples in the CIS list that match the calling
10427c478bdstevel@tonic-gate *	criteria will be returned.
10437c478bdstevel@tonic-gate *
10447c478bdstevel@tonic-gate * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
10457c478bdstevel@tonic-gate *	the tuple_t->Attributes member is not set, then we don't return
10467c478bdstevel@tonic-gate *	any of the link tuples. This function ignores this flag and always
10477c478bdstevel@tonic-gate *	returns link tuples.
10487c478bdstevel@tonic-gate *
10497c478bdstevel@tonic-gate *    Return codes:
10507c478bdstevel@tonic-gate *		CS_SUCCESS - if tuple sucessfully found and returned
10517c478bdstevel@tonic-gate *		CS_NO_CARD - if no card inserted
10527c478bdstevel@tonic-gate *		CS_NO_CIS - if no CIS for the specified card/function
10537c478bdstevel@tonic-gate *		CS_NO_MORE_ITEMS - if tuple not found or no more tuples
10547c478bdstevel@tonic-gate *					to return
10557c478bdstevel@tonic-gate *
10567c478bdstevel@tonic-gate *    See notes for cs_get_socket for a description of valid client, socket
10577c478bdstevel@tonic-gate *	and function number combinations.
10587c478bdstevel@tonic-gate */
10597c478bdstevel@tonic-gatestatic int
10607c478bdstevel@tonic-gatecs_get_firstnext_tuple(client_handle_t client_handle,
10617c478bdstevel@tonic-gate    tuple_t *tuple, uint32_t flags)
10627c478bdstevel@tonic-gate{
10637c478bdstevel@tonic-gate	cs_socket_t *sp;
10647c478bdstevel@tonic-gate	client_t *client;
10657c478bdstevel@tonic-gate	uint32_t fn;
10667c478bdstevel@tonic-gate	int ret;
10677c478bdstevel@tonic-gate
10687c478bdstevel@tonic-gate	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
10697c478bdstevel@tonic-gate						&sp, &client)) != CS_SUCCESS)
10707c478bdstevel@tonic-gate	    return (ret);
10717c478bdstevel@tonic-gate
10727c478bdstevel@tonic-gate	/*
10737c478bdstevel@tonic-gate	 * If there's no card in the socket or the card in the socket is not
10747c478bdstevel@tonic-gate	 *	for this client, then return an error.
10757c478bdstevel@tonic-gate	 */
10767c478bdstevel@tonic-gate	if (!(client->flags & CLIENT_CARD_INSERTED))
10777c478bdstevel@tonic-gate	    return (CS_NO_CARD);
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate	mutex_enter(&sp->cis_lock);
10807c478bdstevel@tonic-gate
10817c478bdstevel@tonic-gate	/*
10827c478bdstevel@tonic-gate	 * If there's no CIS on this card or no CIS for the specified
10837c478bdstevel@tonic-gate	 *	function, then we can't do much.
10847c478bdstevel@tonic-gate	 */
10857c478bdstevel@tonic-gate	if ((!(sp->cis_flags & CW_VALID_CIS)) ||
10867c478bdstevel@tonic-gate				(!(sp->cis[fn].flags & CW_VALID_CIS))) {
10877c478bdstevel@tonic-gate	    mutex_exit(&sp->cis_lock);
10887c478bdstevel@tonic-gate	    return (CS_NO_CIS);
10897c478bdstevel@tonic-gate	}
10907c478bdstevel@tonic-gate
10917c478bdstevel@tonic-gate	/*
10927c478bdstevel@tonic-gate	 * This will set the CIS_GET_LTUPLE_IGNORE flag if the
10937c478bdstevel@tonic-gate	 *	TUPLE_RETURN_IGNORED_TUPLES flag is set. The
10947c478bdstevel@tonic-gate	 *	assumption here is that the CIS_GET_LTUPLE_IGNORE
10957c478bdstevel@tonic-gate	 *	flag and the TUPLE_RETURN_IGNORED_TUPLES flag
10967c478bdstevel@tonic-gate	 *	shares the same bit position. If this ever changes,
10977c478bdstevel@tonic-gate	 *	we'll ahve to re-work this section of code.
10987c478bdstevel@tonic-gate	 */
10997c478bdstevel@tonic-gate	if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
11007c478bdstevel@tonic-gate	    flags |= CIS_GET_LTUPLE_IGNORE;
11017c478bdstevel@tonic-gate
11027c478bdstevel@tonic-gate	/*
11037c478bdstevel@tonic-gate	 * Are we GetFirstTuple or GetNextTuple?
11047c478bdstevel@tonic-gate	 */
11057c478bdstevel@tonic-gate	if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
11067c478bdstevel@tonic-gate	/*
11077c478bdstevel@tonic-gate	 * Initialize the tuple structure; we need this information when
11087c478bdstevel@tonic-gate	 *	we have to process a GetNextTuple or ParseTuple call.
11097c478bdstevel@tonic-gate	 * If this card has a multi-function CIS, then we always start out
11107c478bdstevel@tonic-gate	 *	delivering tuples from the global CIS chain. If this card does
11117c478bdstevel@tonic-gate	 *	not have a multi-function CIS, then the function 0 CIS chain
11127c478bdstevel@tonic-gate	 *	will contain the complete CIS list.
11137c478bdstevel@tonic-gate	 * If this is a multi-function card, then use the GET_FIRST_LTUPLE
11147c478bdstevel@tonic-gate	 *	macro to return the first tuple in the CIS list - we do this
11157c478bdstevel@tonic-gate	 *	since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
11167c478bdstevel@tonic-gate	 *	set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
11177c478bdstevel@tonic-gate	 * Note that we don't have to cross over into the fucntion-specific
11187c478bdstevel@tonic-gate	 *	CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
11197c478bdstevel@tonic-gate	 *	always have at least a CISTPL_LONGLINK_MFC tuple in the global
11207c478bdstevel@tonic-gate	 *	CIS chain - the test for NULL is just a sanity check.
11217c478bdstevel@tonic-gate	 */
11227c478bdstevel@tonic-gate	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11237c478bdstevel@tonic-gate		if ((tuple->CISOffset =
11247c478bdstevel@tonic-gate			GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
11257c478bdstevel@tonic-gate							flags)) == NULL) {
11267c478bdstevel@tonic-gate		    mutex_exit(&sp->cis_lock);
11277c478bdstevel@tonic-gate		    return (CS_NO_MORE_ITEMS);
11287c478bdstevel@tonic-gate		} /* GET_FIRST_LTUPLE */
11297c478bdstevel@tonic-gate	    } else {
11307c478bdstevel@tonic-gate		tuple->CISOffset = sp->cis[0].cis;
11317c478bdstevel@tonic-gate	    } /* CW_MULTI_FUNCTION_CIS */
11327c478bdstevel@tonic-gate	} else {
11337c478bdstevel@tonic-gate	    cistpl_t *tp;
11347c478bdstevel@tonic-gate
11357c478bdstevel@tonic-gate		/*
11367c478bdstevel@tonic-gate		 * Check to be sure that we have a non-NULL tuple list pointer.
11377c478bdstevel@tonic-gate		 *	This is necessary in the case where the caller calls us
11387c478bdstevel@tonic-gate		 *	with get next tuple requests but we don't have any more
11397c478bdstevel@tonic-gate		 *	tuples to give back.
11407c478bdstevel@tonic-gate		 */
11417c478bdstevel@tonic-gate	    if (tuple->CISOffset == NULL) {
11427c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
11437c478bdstevel@tonic-gate		return (CS_NO_MORE_ITEMS);
11447c478bdstevel@tonic-gate	    }
11457c478bdstevel@tonic-gate
11467c478bdstevel@tonic-gate		/*
11477c478bdstevel@tonic-gate		 * Point to the next tuple in the list.  If we're searching for
11487c478bdstevel@tonic-gate		 *	a particular tuple, FIND_LTUPLE_FWD will find it.
11497c478bdstevel@tonic-gate		 *
11507c478bdstevel@tonic-gate		 * If there are no more tuples in the chain that we're looking
11517c478bdstevel@tonic-gate		 *	at, then if we're looking at the global portion of a
11527c478bdstevel@tonic-gate		 *	multi-function CIS, switch to the function-specific list
11537c478bdstevel@tonic-gate		 *	and start looking there.
11547c478bdstevel@tonic-gate		 */
11557c478bdstevel@tonic-gate	    if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
11567c478bdstevel@tonic-gate		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11577c478bdstevel@tonic-gate		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11587c478bdstevel@tonic-gate							(fn != CS_GLOBAL_CIS)) {
11597c478bdstevel@tonic-gate			tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
11607c478bdstevel@tonic-gate		    } /* CISTPLF_GLOBAL_CIS */
11617c478bdstevel@tonic-gate		} /* CW_MULTI_FUNCTION_CIS */
11627c478bdstevel@tonic-gate	    } /* GET_NEXT_TUPLE */
11637c478bdstevel@tonic-gate
11647c478bdstevel@tonic-gate		/*
11657c478bdstevel@tonic-gate		 * If there are no more tuples in the chain, then return.
11667c478bdstevel@tonic-gate		 */
11677c478bdstevel@tonic-gate	    if ((tuple->CISOffset = tp) == NULL) {
11687c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
11697c478bdstevel@tonic-gate		return (CS_NO_MORE_ITEMS);
11707c478bdstevel@tonic-gate	    }
11717c478bdstevel@tonic-gate	} /* CS_GET_FIRST_FLAG */
11727c478bdstevel@tonic-gate
11737c478bdstevel@tonic-gate	/*
11747c478bdstevel@tonic-gate	 * Check if we want to get the first of a particular type of tuple
11757c478bdstevel@tonic-gate	 *	or just the first tuple in the chain.
11767c478bdstevel@tonic-gate	 * If there are no more tuples of the type we're searching for in
11777c478bdstevel@tonic-gate	 *	the chain that we're looking at, then if we're looking at
11787c478bdstevel@tonic-gate	 *	the global portion of a multi-function CIS, switch to the
11797c478bdstevel@tonic-gate	 *	function-specific list and start looking there.
11807c478bdstevel@tonic-gate	 */
11817c478bdstevel@tonic-gate	if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
11827c478bdstevel@tonic-gate	    cistpl_t *tp;
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	    if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
11857c478bdstevel@tonic-gate					tuple->DesiredTuple, flags)) == NULL) {
11867c478bdstevel@tonic-gate		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11877c478bdstevel@tonic-gate		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11887c478bdstevel@tonic-gate							(fn != CS_GLOBAL_CIS)) {
11897c478bdstevel@tonic-gate			tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
11907c478bdstevel@tonic-gate						tuple->DesiredTuple, flags);
11917c478bdstevel@tonic-gate		    } /* CISTPLF_GLOBAL_CIS */
11927c478bdstevel@tonic-gate		} /* CW_MULTI_FUNCTION_CIS */
11937c478bdstevel@tonic-gate	    } /* FIND_LTUPLE_FWD */
11947c478bdstevel@tonic-gate
11957c478bdstevel@tonic-gate		/*
11967c478bdstevel@tonic-gate		 * If there are no more tuples in the chain, then return.
11977c478bdstevel@tonic-gate		 */
11987c478bdstevel@tonic-gate	    if ((tuple->CISOffset = tp) == NULL) {
11997c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
12007c478bdstevel@tonic-gate		return (CS_NO_MORE_ITEMS);
12017c478bdstevel@tonic-gate	    }
12027c478bdstevel@tonic-gate	} /* !RETURN_FIRST_TUPLE */
12037c478bdstevel@tonic-gate
12047c478bdstevel@tonic-gate	/*
12057c478bdstevel@tonic-gate	 * We've got a tuple, now fill out the rest of the tuple_t
12067c478bdstevel@tonic-gate	 *	structure.  Callers can use the flags member to
12077c478bdstevel@tonic-gate	 *	determine whether or not the tuple data was copied
12087c478bdstevel@tonic-gate	 *	to the linked list or if it's still on the card.
12097c478bdstevel@tonic-gate	 */
12107c478bdstevel@tonic-gate	tuple->Flags = tuple->CISOffset->flags;
12117c478bdstevel@tonic-gate	tuple->TupleCode = tuple->CISOffset->type;
12127c478bdstevel@tonic-gate	tuple->TupleLink = tuple->CISOffset->len;
12137c478bdstevel@tonic-gate	tuple->TupleDataLen = tuple->CISOffset->len;
12147c478bdstevel@tonic-gate
12157c478bdstevel@tonic-gate	mutex_exit(&sp->cis_lock);
12167c478bdstevel@tonic-gate
12177c478bdstevel@tonic-gate	return (CS_SUCCESS);
12187c478bdstevel@tonic-gate}
12197c478bdstevel@tonic-gate
12207c478bdstevel@tonic-gate/*
12217c478bdstevel@tonic-gate * cs_get_tuple_data - get the data portion of a tuple; this is to
12227c478bdstevel@tonic-gate *	support the GetTupleData function call.
12237c478bdstevel@tonic-gate *
12247c478bdstevel@tonic-gate *    Note that if the data body of a tuple was not read from the CIS,
12257c478bdstevel@tonic-gate *	then this function will return CS_NO_MORE_ITEMS.
12267c478bdstevel@tonic-gate *
12277c478bdstevel@tonic-gate *    For flags that are set in the tuple_t->flags member, see the
12287c478bdstevel@tonic-gate *	comments for the cis_list_lcreate function in the cis.c file.
12297c478bdstevel@tonic-gate *	These flags are copied into the tuple_t->flags member by the
12307c478bdstevel@tonic-gate *	cs_get_firstnext_tuple function call.
12317c478bdstevel@tonic-gate *
12327c478bdstevel@tonic-gate *    See notes for the cs_get_firstnext_tuple function.
12337c478bdstevel@tonic-gate */
12347c478bdstevel@tonic-gatestatic int
12357c478bdstevel@tonic-gatecs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
12367c478bdstevel@tonic-gate{
12377c478bdstevel@tonic-gate	cs_socket_t *sp;
12387c478bdstevel@tonic-gate	client_t *client;
12397c478bdstevel@tonic-gate	int ret, nbytes;
12407c478bdstevel@tonic-gate	uint32_t fn, flags;
12417c478bdstevel@tonic-gate	cisdata_t *tsd, *tdd;
12427c478bdstevel@tonic-gate	uint32_t newoffset;
12437c478bdstevel@tonic-gate	acc_handle_t cis_handle;
12447c478bdstevel@tonic-gate
12457c478bdstevel@tonic-gate	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
12467c478bdstevel@tonic-gate						&sp, &client)) != CS_SUCCESS)
12477c478bdstevel@tonic-gate	    return (ret);
12487c478bdstevel@tonic-gate
12497c478bdstevel@tonic-gate	/*
12507c478bdstevel@tonic-gate	 * If there's no card in the socket or the card in the socket is not
12517c478bdstevel@tonic-gate	 *	for this client, then return an error.
12527c478bdstevel@tonic-gate	 */
12537c478bdstevel@tonic-gate	if (!(client->flags & CLIENT_CARD_INSERTED))
12547c478bdstevel@tonic-gate	    return (CS_NO_CARD);
12557c478bdstevel@tonic-gate
12567c478bdstevel@tonic-gate	mutex_enter(&sp->cis_lock);
12577c478bdstevel@tonic-gate
12587c478bdstevel@tonic-gate	if ((sp->cis_flags & CW_VALID_CIS) &&
12597c478bdstevel@tonic-gate				(sp->cis[fn].flags & CW_VALID_CIS)) {
12607c478bdstevel@tonic-gate
12617c478bdstevel@tonic-gate		/*
12627c478bdstevel@tonic-gate		 * Check to be sure that we have a non-NULL pointer to
12637c478bdstevel@tonic-gate		 *	a CIS list.
12647c478bdstevel@tonic-gate		 */
12657c478bdstevel@tonic-gate	    if (!(tuple->CISOffset)) {
12667c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
12677c478bdstevel@tonic-gate		return (CS_NO_MORE_ITEMS);
12687c478bdstevel@tonic-gate	    }
12697c478bdstevel@tonic-gate
12707c478bdstevel@tonic-gate	/*
12717c478bdstevel@tonic-gate	 * Since the tuple data buffer that the caller calls us with
12727c478bdstevel@tonic-gate	 *	is preallocated in the tuple_t structure, we ignore any
12737c478bdstevel@tonic-gate	 *	TupleDataMax value that the caller has setup and use the
12747c478bdstevel@tonic-gate	 *	actual size of the tuple data buffer in the structure.
12757c478bdstevel@tonic-gate	 */
12767c478bdstevel@tonic-gate	    tuple->TupleDataMax = sizeof (tuple->TupleData);
12777c478bdstevel@tonic-gate
12787c478bdstevel@tonic-gate	/*
12797c478bdstevel@tonic-gate	 * Make sure the requested offset is not past the end of the
12807c478bdstevel@tonic-gate	 *	tuple data body nor past the end of the user-supplied
12817c478bdstevel@tonic-gate	 *	buffer.
12827c478bdstevel@tonic-gate	 */
12837c478bdstevel@tonic-gate	    if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
12847c478bdstevel@tonic-gate						(int)tuple->TupleDataMax)) {
12857c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
12867c478bdstevel@tonic-gate		return (CS_NO_MORE_ITEMS);
12877c478bdstevel@tonic-gate	    }
12887c478bdstevel@tonic-gate
12897c478bdstevel@tonic-gate	    tuple->TupleDataLen = tuple->TupleLink;
12907c478bdstevel@tonic-gate
12917c478bdstevel@tonic-gate	    if ((nbytes = min((int)tuple->TupleDataMax -
12927c478bdstevel@tonic-gate						(int)tuple->TupleOffset,
12937c478bdstevel@tonic-gate						(int)tuple->TupleDataLen -
12947c478bdstevel@tonic-gate						(int)tuple->TupleOffset)) < 1) {
12957c478bdstevel@tonic-gate		mutex_exit(&sp->cis_lock);
12967c478bdstevel@tonic-gate		return (CS_BAD_ARGS);
12977c478bdstevel@tonic-gate	    }
12987c478bdstevel@tonic-gate
12997c478bdstevel@tonic-gate	/*
13007c478bdstevel@tonic-gate	 * The tuple data destination is always the tuple_t->TupleData
13017c478bdstevel@tonic-gate	 *	buffer in the tuple_t structure no matter where we read the
13027c478bdstevel@tonic-gate	 *	tuple data from.
13037c478bdstevel@tonic-gate	 */
13047c478bdstevel@tonic-gate	    tdd = tuple->TupleData;
13057c478bdstevel@tonic-gate	    bzero((caddr_t)tdd, sizeof (tuple->TupleData));
13067c478bdstevel@tonic-gate
13077c478bdstevel@tonic-gate	/*
13087c478bdstevel@tonic-gate	 * Do we have a copy of the tuple data?  If not, we have to
13097c478bdstevel@tonic-gate	 *	get a pointer to the CIS and read the tuple data from the
13107c478bdstevel@tonic-gate	 *	card itself.
13117c478bdstevel@tonic-gate	 */
13127c478bdstevel@tonic-gate	    switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
13137c478bdstevel@tonic-gate		case CISTPLF_LM_SPACE:
13147c478bdstevel@tonic-gate		    tsd = (tuple->CISOffset->data +
13157c478bdstevel@tonic-gate					(unsigned)tuple->TupleOffset);
13167c478bdstevel@tonic-gate		    while (nbytes--)
13177c478bdstevel@tonic-gate			*tdd++ = *tsd++;
13187c478bdstevel@tonic-gate		    break;
13197c478bdstevel@tonic-gate		case CISTPLF_AM_SPACE:
13207c478bdstevel@tonic-gate		case CISTPLF_CM_SPACE:
13217c478bdstevel@tonic-gate		    newoffset = tuple->CISOffset->offset;
13227c478bdstevel@tonic-gate
13237c478bdstevel@tonic-gate		/*
13247c478bdstevel@tonic-gate		 * Setup the proper space flags as well as setup the
13257c478bdstevel@tonic-gate		 *	address offset to point to the start of the tuple
13267c478bdstevel@tonic-gate		 *	data area; we need to do the latter since the
13277c478bdstevel@tonic-gate		 *	cis_store_cis_addr function in cis.c sets up the
13287c478bdstevel@tonic-gate		 *	tuple->CISOffset->offset offset to point to the
13297c478bdstevel@tonic-gate		 *	start of the tuple.
13307c478bdstevel@tonic-gate		 */
13317c478bdstevel@tonic-gate		    if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
13327c478bdstevel@tonic-gate			flags = CISTPLF_AM_SPACE;
13337c478bdstevel@tonic-gate			newoffset += ((tuple->TupleOffset * 2) + 4);
13347c478bdstevel@tonic-gate		    } else {
13357c478bdstevel@tonic-gate			flags = CISTPLF_CM_SPACE;
13367c478bdstevel@tonic-gate			newoffset += (tuple->TupleOffset + 2);
13377c478bdstevel@tonic-gate		    }
13387c478bdstevel@tonic-gate
13397c478bdstevel@tonic-gate		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
13407c478bdstevel@tonic-gate							flags) != CS_SUCCESS) {
13417c478bdstevel@tonic-gate			mutex_exit(&sp->cis_lock);
13427c478bdstevel@tonic-gate			cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
13437c478bdstevel@tonic-gate						"can't init CIS window\n",
13447c478bdstevel@tonic-gate							sp->socket_num);
13457c478bdstevel@tonic-gate			return (CS_GENERAL_FAILURE);
13467c478bdstevel@tonic-gate		    } /* cs_init_cis_window */
13477c478bdstevel@tonic-gate		    while (nbytes--) {
13487c478bdstevel@tonic-gate			*tdd++ = csx_Get8(cis_handle, newoffset++);
13497c478bdstevel@tonic-gate			if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
13507c478bdstevel@tonic-gate			    newoffset++;
13517c478bdstevel@tonic-gate		    } /* while */
13527c478bdstevel@tonic-gate		    break;
13537c478bdstevel@tonic-gate		default:
13547c478bdstevel@tonic-gate		    mutex_exit(&sp->cis_lock);
13557c478bdstevel@tonic-gate		    return (CS_GENERAL_FAILURE);
13567c478bdstevel@tonic-gate	    } /* switch */
13577c478bdstevel@tonic-gate
13587c478bdstevel@tonic-gate	    ret = CS_SUCCESS;
13597c478bdstevel@tonic-gate	} else {
13607c478bdstevel@tonic-gate	    ret = CS_NO_CIS;
13617c478bdstevel@tonic-gate	} /* if (CW_VALID_CIS) */
13627c478bdstevel@tonic-gate
13637c478bdstevel@tonic-gate	mutex_exit(&sp->cis_lock);
13647c478bdstevel@tonic-gate
13657c478bdstevel@tonic-gate	return (ret);
13667c478bdstevel@tonic-gate}
13677c478bdstevel@tonic-gate
13687c478bdstevel@tonic-gate/*
13697c478bdstevel@tonic-gate * cs_validate_cis - validates the CIS on a card in the given socket; this
13707c478bdstevel@tonic-gate *			is to support the ValidateCIS function call.
13717c478bdstevel@tonic-gate *
13727c478bdstevel@tonic-gate *    Notes for regular PC card driver callers:
13737c478bdstevel@tonic-gate *
13747c478bdstevel@tonic-gate *	Regular PC card drivers calling ValidateCIS will get the meaning of
13757c478bdstevel@tonic-gate *	the structure members as specified in the standard.
13767c478bdstevel@tonic-gate *
13777c478bdstevel@tonic-gate *    Notes for Socket Services, the "super-client" or CSI driver callers:
13787c478bdstevel@tonic-gate *
13797c478bdstevel@tonic-gate *		with: Function Number = CS_GLOBAL_CIS
13807c478bdstevel@tonic-gate *
13817c478bdstevel@tonic-gate *	For a single-function card, CS_NO_CIS will be returned and the
13827c478bdstevel@tonic-gate *	cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
13837c478bdstevel@tonic-gate *
13847c478bdstevel@tonic-gate *	For a multi-function card, cisinfo_t->Chains will contain a count of
13857c478bdstevel@tonic-gate *	the number of CIS chains in the global portion of the CIS, and
13867c478bdstevel@tonic-gate *	cisinfo_t->Tuples will contain a count of the number of tuples in
13877c478bdstevel@tonic-gate *	the global portion of the CIS.
13887c478bdstevel@tonic-gate *
13897c478bdstevel@tonic-gate *		with: 0 <= Function Number < CIS_MAX_FUNCTIONS
13907c478bdstevel@tonic-gate *
13917c478bdstevel@tonic-gate *	For a single-function card, if the function number is equal to 0 and
13927c478bdstevel@tonic-gate *	has a CIS, cisinfo_t->Chains will contain a count of the number of
13937c478bdstevel@tonic-gate *	CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
13947c478bdstevel@tonic-gate *	the number of tuples in the CIS. If the card does not have a CIS, or
13957c478bdstevel@tonic-gate *	if the function number is not equal to 0, CS_NO_CIS will be returned
13967c478bdstevel@tonic-gate *	and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
13977c478bdstevel@tonic-gate *	to 0.
13987c478bdstevel@tonic-gate *
13997c478bdstevel@tonic-gate *	For a multi-function card, cisinfo_t->Chains will contain a count of
14007c478bdstevel@tonic-gate *	the number of CIS chains in the global and function-specific
14017c478bdstevel@tonic-gate *	portions of the CIS, and cisinfo_t->Tuples will contain a count of
14027c478bdstevel@tonic-gate *	the number of tuples in the global and function-specific portions of
14037c478bdstevel@tonic-gate *	the CIS. If the function does not exist or has no CIS, CS_NO_CIS
14047c478bdstevel@tonic-gate *	will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
14057c478bdstevel@tonic-gate *	members will be set to 0.
14067c478bdstevel@tonic-gate *
14077c478bdstevel@tonic-gate *    General notes:
14087c478bdstevel@tonic-gate *
14097c478bdstevel@tonic-gate *	If the card does not have a CIS, or if the function does not exist
14107c478bdstevel@tonic-gate *	or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
14117c478bdstevel@tonic-gate *	and cisinfo_t->Tuples members will be set to 0.
14127c478bdstevel@tonic-gate *
14137c478bdstevel@tonic-gate *	Most of the work of validating the CIS has already been done by the
14147c478bdstevel@tonic-gate *	CIS parser module, so we don't have to do much here except for
14157c478bdstevel@tonic-gate *	looking at the various flags and tuple/chain counts that were already
14167c478bdstevel@tonic-gate *	setup by the CIS parser.
14177c478bdstevel@tonic-gate *
14187c478bdstevel@tonic-gate *    See notes for the cs_get_firstnext_tuple function.
14197c478bdstevel@tonic-gate */
14207c478bdstevel@tonic-gatestatic int
14217c478bdstevel@tonic-gatecs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
14227c478bdstevel@tonic-gate{
14237c478bdstevel@tonic-gate	cs_socket_t *sp;
14247c478bdstevel@tonic-gate	client_t *client;
14257c478bdstevel@tonic-gate	uint32_t fn;
14267c478bdstevel@tonic-gate	int ret;
14277c478bdstevel@tonic-gate
14287c478bdstevel@tonic-gate	if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
14297c478bdstevel@tonic-gate						&sp, &client)) != CS_SUCCESS)
14307c478bdstevel@tonic-gate	    return (ret);
14317c478bdstevel@tonic-gate
14327c478bdstevel@tonic-gate	/*
14337c478bdstevel@tonic-gate	 * If there's no card in the socket or the card in the socket is not
14347c478bdstevel@tonic-gate	 *	for this client, then return an error.
14357c478bdstevel@tonic-gate	 */
14367c478bdstevel@tonic-gate	if (!(client->flags & CLIENT_CARD_INSERTED))
14377c478bdstevel@tonic-gate	    return (CS_NO_CARD);
14387c478bdstevel@tonic-gate
14397c478bdstevel@tonic-gate	mutex_enter(&sp->cis_lock);
14407c478bdstevel@tonic-gate	if ((sp->cis_flags & CW_VALID_CIS) &&
14417c478bdstevel@tonic-gate				(sp->cis[fn].flags & CW_VALID_CIS)) {
14427c478bdstevel@tonic-gate	    cisinfo->Chains = sp->cis[fn].nchains;
14437c478bdstevel@tonic-gate	    cisinfo->Tuples = sp->cis[fn].ntuples;
14447c478bdstevel@tonic-gate
14457c478bdstevel@tonic-gate	    if ((fn != CS_GLOBAL_CIS) &&
14467c478bdstevel@tonic-gate			(sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
14477c478bdstevel@tonic-gate		cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
14487c478bdstevel@tonic-gate		cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
14497c478bdstevel@tonic-gate	    } /* !CS_GLOBAL_CIS */
14507c478bdstevel@tonic-gate
14517c478bdstevel@tonic-gate	    ret = CS_SUCCESS;
14527c478bdstevel@tonic-gate	} else {
14537c478bdstevel@tonic-gate	    cisinfo->Chains = 0;
14547c478bdstevel@tonic-gate	    cisinfo->Tuples = 0;
14557c478bdstevel@tonic-gate	    ret = CS_NO_CIS;
14567c478bdstevel@tonic-gate	}
14577c478bdstevel@tonic-gate	mutex_exit(&sp->cis_lock);
14587c478bdstevel@tonic-gate
14597c478bdstevel@tonic-gate	return (ret);
14607c478bdstevel@tonic-gate}
14617c478bdstevel@tonic-gate
14627c478bdstevel@tonic-gate/*
14637c478bdstevel@tonic-gate * cs_init_cis_window - initializes the CIS window for the passed socket
14647c478bdstevel@tonic-gate *
14657c478bdstevel@tonic-gate *	calling: *sp - pointer to the per-socket structure
14667c478bdstevel@tonic-gate *		 *offset - offset from start of AM or CM space
14677c478bdstevel@tonic-gate *		 *hp - pointer to acc_handle_t to store modified
14687c478bdstevel@tonic-gate *				window access handle in
14697c478bdstevel@tonic-gate *		 flags - one of:
14707c478bdstevel@tonic-gate *				CISTPLF_AM_SPACE - set window to AM space
14717c478bdstevel@tonic-gate *				CISTPLF_CM_SPACE - set window to CM space
14727c478bdstevel@tonic-gate *
14737c478bdstevel@tonic-gate *	returns: CS_SUCCESS if CIS window was set up
14747c478bdstevel@tonic-gate *		 *offset - contains adjusted offset to use to access
14757c478bdstevel@tonic-gate *				requested space
14767c478bdstevel@tonic-gate *		 CS_BAD_WINDOW if CIS window could not be setup
14777c478bdstevel@tonic-gate *		 CS_GENERAL_FAILURE if socket has a CIS window number
14787c478bdstevel@tonic-gate *					but the window flags are wrong
14797c478bdstevel@tonic-gate *
14807c478bdstevel@tonic-gate *	Note: This function will check to be sure that there is a valid
14817c478bdstevel@tonic-gate *		CIS window allocated to this socket.
14827c478bdstevel@tonic-gate *	      If there is an error in setting up the window hardware, the
14837c478bdstevel@tonic-gate *		CIS window information for this socket is cleared.
14847c478bdstevel@tonic-gate *	      This function is also used by routines that need to get
14857c478bdstevel@tonic-gate *		a pointer to the base of AM space to access the card's
14867c478bdstevel@tonic-gate *		configuration registers.
14877c478bdstevel@tonic-gate *	      The passed offset is the un-window-size-aligned offset.
14887c478bdstevel@tonic-gate */
14897c478bdstevel@tonic-gateint
14907c478bdstevel@tonic-gatecs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
14917c478bdstevel@tonic-gate    acc_handle_t *hp, uint32_t flags)
14927c478bdstevel@tonic-gate{
14937c478bdstevel@tonic-gate	set_window_t sw;
14947c478bdstevel@tonic-gate	get_window_t gw;
14957c478bdstevel@tonic-gate	inquire_window_t iw;
14967c478bdstevel@tonic-gate	set_page_t set_page;
14977c478bdstevel@tonic-gate	cs_window_t *cw;
14987c478bdstevel@tonic-gate
14997c478bdstevel@tonic-gate	/*
15007c478bdstevel@tonic-gate	 * Check to be sure that we have a valid CIS window
15017c478bdstevel@tonic-gate	 */
15027c478bdstevel@tonic-gate	if (!SOCKET_HAS_CIS_WINDOW(sp)) {
15037c478bdstevel@tonic-gate	    cmn_err(CE_CONT,
15047c478bdstevel@tonic-gate			"cs_init_cis_window: socket %d has no CIS window\n",
15057c478bdstevel@tonic-gate				sp->socket_num);
15067c478bdstevel@tonic-gate	    return (CS_BAD_WINDOW);
15077c478bdstevel@tonic-gate	}
15087c478bdstevel@tonic-gate
15097c478bdstevel@tonic-gate	/*
15107c478bdstevel@tonic-gate	 * Check to be sure that this window is allocated for CIS use
15117c478bdstevel@tonic-gate	 */
15127c478bdstevel@tonic-gate	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
15137c478bdstevel@tonic-gate	    return (CS_BAD_WINDOW);
15147c478bdstevel@tonic-gate
15157c478bdstevel@tonic-gate	if (!(cw->state & CW_CIS)) {
15167c478bdstevel@tonic-gate	    cmn_err(CE_CONT,
15177c478bdstevel@tonic-gate		"cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
15187c478bdstevel@tonic-gate				sp->socket_num, cw->state);
15197c478bdstevel@tonic-gate	    return (CS_BAD_WINDOW);
15207c478bdstevel@tonic-gate	}
15217c478bdstevel@tonic-gate
15227c478bdstevel@tonic-gate	/*
15237c478bdstevel@tonic-gate	 * Get the characteristics of this window - we use this to
15247c478bdstevel@tonic-gate	 *	determine whether we need to re-map the window or
15257c478bdstevel@tonic-gate	 *	just move the window offset on the card.
15267c478bdstevel@tonic-gate	 */
15277c478bdstevel@tonic-gate	iw.window = sp->cis_win_num;
15287c478bdstevel@tonic-gate	SocketServices(SS_InquireWindow, &iw);
15297c478bdstevel@tonic-gate
15307c478bdstevel@tonic-gate	/*
15317c478bdstevel@tonic-gate	 * We've got a window, now set up the hardware. If we've got
15327c478bdstevel@tonic-gate	 *	a variable sized window, then all we need to do is to
15337c478bdstevel@tonic-gate	 *	get a valid mapping to the base of the window using
15347c478bdstevel@tonic-gate	 *	the current window size; if we've got a fixed-size
15357c478bdstevel@tonic-gate	 *	window, then we need to get a mapping to the window
15367c478bdstevel@tonic-gate	 *	starting at offset zero of the window.
15377c478bdstevel@tonic-gate	 */
15387c478bdstevel@tonic-gate	if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
15397c478bdstevel@tonic-gate	    sw.WindowSize = sp->cis_win_size;
15407c478bdstevel@tonic-gate	    set_page.offset = ((*offset / sp->cis_win_size) *
15417c478bdstevel@tonic-gate						sp->cis_win_size);
15427c478bdstevel@tonic-gate	} else {
15437c478bdstevel@tonic-gate	    set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
15447c478bdstevel@tonic-gate						iw.mem_win_char.MinSize);
15457c478bdstevel@tonic-gate	    sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
15467c478bdstevel@tonic-gate					(set_page.offset - 1)) + PAGESIZE);
15477c478bdstevel@tonic-gate	}
15487c478bdstevel@tonic-gate
15497c478bdstevel@tonic-gate	/*
15507c478bdstevel@tonic-gate	 * Return a normalized base offset; this takes care of the case
15517c478bdstevel@tonic-gate	 *	where the required offset is greater than the window size.
15527c478bdstevel@tonic-gate	 * BugID 1236404
15537c478bdstevel@tonic-gate	 *	code was:
15547c478bdstevel@tonic-gate	 *		*offset = *offset & (set_page.offset - 1);
15557c478bdstevel@tonic-gate	 */
15567c478bdstevel@tonic-gate	*offset = *offset - set_page.offset;
15577c478bdstevel@tonic-gate
15587c478bdstevel@tonic-gate#ifdef	CS_DEBUG
15597c478bdstevel@tonic-gate	if (cs_debug > 1)
15607c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
15617c478bdstevel@tonic-gate							"offset 0x%x\n",
15627c478bdstevel@tonic-gate							(int)sw.WindowSize,
15637c478bdstevel@tonic-gate							(int)set_page.offset);
15647c478bdstevel@tonic-gate	if (cs_debug > 1)
15657c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
15667c478bdstevel@tonic-gate							(int)*offset,
15677c478bdstevel@tonic-gate					(flags & CISTPLF_AM_SPACE)?
15687c478bdstevel@tonic-gate					"CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
15697c478bdstevel@tonic-gate#endif
15707c478bdstevel@tonic-gate
15717c478bdstevel@tonic-gate	sw.window = sp->cis_win_num;
15727c478bdstevel@tonic-gate	sw.socket = sp->socket_num;
15737c478bdstevel@tonic-gate	sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
15747c478bdstevel@tonic-gate	sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15757c478bdstevel@tonic-gate	sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
15767c478bdstevel@tonic-gate	sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15777c478bdstevel@tonic-gate
15787c478bdstevel@tonic-gate	/*
15797c478bdstevel@tonic-gate	 * The PCMCIA SS spec specifies this be expressed in
15807c478bdstevel@tonic-gate	 *	a device speed format per 5.2.7.1.3 but
15817c478bdstevel@tonic-gate	 *	our implementation of SS_SetWindow uses
15827c478bdstevel@tonic-gate	 *	actual nanoseconds.
15837c478bdstevel@tonic-gate	 */
15847c478bdstevel@tonic-gate	sw.speed = CIS_DEFAULT_SPEED;
15857c478bdstevel@tonic-gate	sw.base = 0;
15867c478bdstevel@tonic-gate	/*
15877c478bdstevel@tonic-gate	 * Set up the window - if this fails, then just set the
15887c478bdstevel@tonic-gate	 *	CIS window number back to it's initialized value so
15897c478bdstevel@tonic-gate	 *	that we'll fail when we break out of the loop.
15907c478bdstevel@tonic-gate	 */
15917c478bdstevel@tonic-gate	if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
15927c478bdstevel@tonic-gate	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
15937c478bdstevel@tonic-gate	    cw->state = 0; /* XXX do we really want to do this? */
15947c478bdstevel@tonic-gate	    return (CS_BAD_WINDOW);
15957c478bdstevel@tonic-gate	} else {
15967c478bdstevel@tonic-gate		set_page.window = sp->cis_win_num;
15977c478bdstevel@tonic-gate		set_page.page = 0;
15987c478bdstevel@tonic-gate		set_page.state = PS_ENABLED;
15997c478bdstevel@tonic-gate		if (flags & CISTPLF_AM_SPACE)
16007c478bdstevel@tonic-gate		    set_page.state |= PS_ATTRIBUTE;
16017c478bdstevel@tonic-gate
16027c478bdstevel@tonic-gate		if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
16037c478bdstevel@tonic-gate		    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
16047c478bdstevel@tonic-gate		    cw->state = 0; /* XXX do we really want to do this? */
16057c478bdstevel@tonic-gate		    return (CS_BAD_WINDOW);
16067c478bdstevel@tonic-gate		} /* if (SS_SetPage) */
16077c478bdstevel@tonic-gate	} /* if (SS_SetWindow) */
16087c478bdstevel@tonic-gate
16097c478bdstevel@tonic-gate	/*
16107c478bdstevel@tonic-gate	 * Get the window information for the CIS window for this socket.
16117c478bdstevel@tonic-gate	 */
16127c478bdstevel@tonic-gate	gw.window = sp->cis_win_num;
16137c478bdstevel@tonic-gate	gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
16147c478bdstevel@tonic-gate	if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
16157c478bdstevel@tonic-gate	    return (CS_BAD_WINDOW);
16167c478bdstevel@tonic-gate
16177c478bdstevel@tonic-gate	*hp = (acc_handle_t)gw.handle;
16187c478bdstevel@tonic-gate
16197c478bdstevel@tonic-gate	return (CS_SUCCESS);
16207c478bdstevel@tonic-gate}
16217c478bdstevel@tonic-gate
16227c478bdstevel@tonic-gate/*
16237c478bdstevel@tonic-gate * ==== client registration/deregistration section ====
16247c478bdstevel@tonic-gate */
16257c478bdstevel@tonic-gate
16267c478bdstevel@tonic-gate/*
16277c478bdstevel@tonic-gate * cs_register_client - This supports the RegisterClient call.
16287c478bdstevel@tonic-gate *
16297c478bdstevel@tonic-gate * Upon successful registration, the client_handle_t * handle argument will
16307c478bdstevel@tonic-gate *	contain the new client handle and we return CS_SUCCESS.
16317c478bdstevel@tonic-gate */
16327c478bdstevel@tonic-gatestatic int
16337c478bdstevel@tonic-gatecs_register_client(client_handle_t *ch, client_reg_t *cr)
16347c478bdstevel@tonic-gate{
16357c478bdstevel@tonic-gate	uint32_t sn;
16367c478bdstevel@tonic-gate	int super_client = 0;
16377c478bdstevel@tonic-gate	sclient_reg_t *scr = cr->priv;
16387c478bdstevel@tonic-gate	struct sclient_list_t *scli;
16397c478bdstevel@tonic-gate
16407c478bdstevel@tonic-gate	/*
16417c478bdstevel@tonic-gate	 * See if we're not supposed to register any new clients.
16427c478bdstevel@tonic-gate	 */
16437c478bdstevel@tonic-gate	if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
16447c478bdstevel@tonic-gate	    return (CS_OUT_OF_RESOURCE);
16457c478bdstevel@tonic-gate
16467c478bdstevel@tonic-gate	/*
16477c478bdstevel@tonic-gate	 * Do a version check - if the client expects a later version of
16487c478bdstevel@tonic-gate	 *	Card Services than what we are, return CS_BAD_VERSION.
16497c478bdstevel@tonic-gate	 * XXX - How do we specify just a PARTICULAR version of CS??
16507c478bdstevel@tonic-gate	 */
16517c478bdstevel@tonic-gate	if (CS_VERSION < cr->Version)
16527c478bdstevel@tonic-gate	    return (CS_BAD_VERSION);
16537c478bdstevel@tonic-gate
16547c478bdstevel@tonic-gate	/*
16557c478bdstevel@tonic-gate	 * Check to be sure that the client has given us a valid set of
16567c478bdstevel@tonic-gate	 *	client type flags.  We also use this opportunity to see
16577c478bdstevel@tonic-gate	 *	if the registering client is Socket Services or is a
16587c478bdstevel@tonic-gate	 *	"super-client" or a CSI client.
16597c478bdstevel@tonic-gate	 *
16607c478bdstevel@tonic-gate	 * Note that SS can not set any flag in the Attributes field other
16617c478bdstevel@tonic-gate	 *	than the INFO_SOCKET_SERVICES flag.
16627c478bdstevel@tonic-gate	 *
16637c478bdstevel@tonic-gate	 * Valid combinations of cr->Attributes and cr->EventMask flags:
16647c478bdstevel@tonic-gate	 *
16657c478bdstevel@tonic-gate	 *  for Socket Services:
16667c478bdstevel@tonic-gate	 *	cr->Attributes:
16677c478bdstevel@tonic-gate	 *	    set:
16687c478bdstevel@tonic-gate	 *		INFO_SOCKET_SERVICES
16697c478bdstevel@tonic-gate	 *	    clear:
16707c478bdstevel@tonic-gate	 *		{all other flags}
16717c478bdstevel@tonic-gate	 *	cr->EventMask:
16727c478bdstevel@tonic-gate	 *	    don't care:
16737c478bdstevel@tonic-gate	 *		{all flags}
16747c478bdstevel@tonic-gate	 *
16757c478bdstevel@tonic-gate	 *  for regular clients:
16767c478bdstevel@tonic-gate	 *	cr->Attributes:
16777c478bdstevel@tonic-gate	 *	    only one of:
16787c478bdstevel@tonic-gate	 *		INFO_IO_CLIENT
16797c478bdstevel@tonic-gate	 *		INFO_MTD_CLIENT
16807c478bdstevel@tonic-gate	 *		INFO_MEM_CLIENT
16817c478bdstevel@tonic-gate	 *	    don't care:
16827c478bdstevel@tonic-gate	 *		INFO_CARD_SHARE
16837c478bdstevel@tonic-gate	 *		INFO_CARD_EXCL
16847c478bdstevel@tonic-gate	 *	cr->EventMask:
16857c478bdstevel@tonic-gate	 *	    clear:
16867c478bdstevel@tonic-gate	 *		CS_EVENT_ALL_CLIENTS
16877c478bdstevel@tonic-gate	 *	    don't care:
16887c478bdstevel@tonic-gate	 *		{all other flags}
16897c478bdstevel@tonic-gate	 *
16907c478bdstevel@tonic-gate	 *  for CSI clients:
16917c478bdstevel@tonic-gate	 *	cr->Attributes:
16927c478bdstevel@tonic-gate	 *	    set:
16937c478bdstevel@tonic-gate	 *		INFO_IO_CLIENT
16947c478bdstevel@tonic-gate	 *		INFO_CSI_CLIENT
16957c478bdstevel@tonic-gate	 *	    clear:
16967c478bdstevel@tonic-gate	 *		INFO_MTD_CLIENT
16977c478bdstevel@tonic-gate	 *		INFO_MEM_CLIENT
16987c478bdstevel@tonic-gate	 *	    don't care:
16997c478bdstevel@tonic-gate	 *		INFO_CARD_SHARE
17007c478bdstevel@tonic-gate	 *		INFO_CARD_EXCL
17017c478bdstevel@tonic-gate	 *	cr->EventMask:
17027c478bdstevel@tonic-gate	 *	    don't care:
17037c478bdstevel@tonic-gate	 *		{all flags}
17047c478bdstevel@tonic-gate	 *
17057c478bdstevel@tonic-gate	 *  for "super-clients":
17067c478bdstevel@tonic-gate	 *	cr->Attributes:
17077c478bdstevel@tonic-gate	 *	    set:
17087c478bdstevel@tonic-gate	 *		INFO_IO_CLIENT
17097c478bdstevel@tonic-gate	 *		INFO_MTD_CLIENT
17107c478bdstevel@tonic-gate	 *		INFO_SOCKET_SERVICES
17117c478bdstevel@tonic-gate	 *		INFO_CARD_SHARE
17127c478bdstevel@tonic-gate	 *	    clear:
17137c478bdstevel@tonic-gate	 *		INFO_MEM_CLIENT
17147c478bdstevel@tonic-gate	 *		INFO_CARD_EXCL
17157c478bdstevel@tonic-gate	 *	cr->EventMask:
17167c478bdstevel@tonic-gate	 *	    don't care:
17177c478bdstevel@tonic-gate	 *		{all flags}
17187c478bdstevel@tonic-gate	 */
17197c478bdstevel@tonic-gate	switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
17207c478bdstevel@tonic-gate	/*
17217c478bdstevel@tonic-gate	 * Check first to see if this is Socket Services registering; if
17227c478bdstevel@tonic-gate	 *	so, we don't do anything but return the client handle that is
17237c478bdstevel@tonic-gate	 *	in the global SS client.
17247c478bdstevel@tonic-gate	 */
17257c478bdstevel@tonic-gate	    case INFO_SOCKET_SERVICES:
17267c478bdstevel@tonic-gate		*ch = cs_socket_services_client.client_handle;
17277c478bdstevel@tonic-gate		return (CS_SUCCESS);
17287c478bdstevel@tonic-gate		/* NOTREACHED */
17297c478bdstevel@tonic-gate	    /* CSI clients */
17307c478bdstevel@tonic-gate	    case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
17317c478bdstevel@tonic-gate		break;
17327c478bdstevel@tonic-gate	    /* regular clients */
17337c478bdstevel@tonic-gate	    case INFO_IO_CLIENT:
17347c478bdstevel@tonic-gate	    case INFO_MTD_CLIENT:
17357c478bdstevel@tonic-gate	    case INFO_MEM_CLIENT:
17367c478bdstevel@tonic-gate		if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
17377c478bdstevel@tonic-gate		    return (CS_BAD_ATTRIBUTE);
17387c478bdstevel@tonic-gate		break;
17397c478bdstevel@tonic-gate	    /* "super-client" clients */
17407c478bdstevel@tonic-gate	    case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
17417c478bdstevel@tonic-gate		if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
17427c478bdstevel@tonic-gate				(cr->Attributes & INFO_CARD_EXCL))
17437c478bdstevel@tonic-gate		    return (CS_BAD_ATTRIBUTE);
17447c478bdstevel@tonic-gate		/*
17457c478bdstevel@tonic-gate		 * We only allow one "super-client" per system.
17467c478bdstevel@tonic-gate		 */
17477c478bdstevel@tonic-gate		mutex_enter(&cs_globals.global_lock);
17487c478bdstevel@tonic-gate		if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
17497c478bdstevel@tonic-gate		    mutex_exit(&cs_globals.global_lock);
17507c478bdstevel@tonic-gate		    return (CS_NO_MORE_ITEMS);
17517c478bdstevel@tonic-gate		}
17527c478bdstevel@tonic-gate		cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
17537c478bdstevel@tonic-gate		mutex_exit(&cs_globals.global_lock);
17547c478bdstevel@tonic-gate		super_client = CLIENT_SUPER_CLIENT;
17557c478bdstevel@tonic-gate		break;
17567c478bdstevel@tonic-gate	    default:
17577c478bdstevel@tonic-gate		return (CS_BAD_ATTRIBUTE);
17587c478bdstevel@tonic-gate	} /* switch (cr->Attributes) */
17597c478bdstevel@tonic-gate
17607c478bdstevel@tonic-gate	/*
17617c478bdstevel@tonic-gate	 * Now, actually create the client node on the socket; this will
17627c478bdstevel@tonic-gate	 *	also return the new client handle if there were no errors
17637c478bdstevel@tonic-gate	 *	creating the client node.
17647c478bdstevel@tonic-gate	 * The DIP2SOCKET_NUM macro will return the socket and function
17657c478bdstevel@tonic-gate	 *	number using the encoding specified in the cs_priv.h file.
17667c478bdstevel@tonic-gate	 */
17677c478bdstevel@tonic-gate	if (super_client != CLIENT_SUPER_CLIENT) {
17687c478bdstevel@tonic-gate	    if (cr->Attributes & INFO_CSI_CLIENT)
17697c478bdstevel@tonic-gate		sn = (uint32_t)(uintptr_t)cr->priv;
17707c478bdstevel@tonic-gate	    else
17717c478bdstevel@tonic-gate		sn = DIP2SOCKET_NUM(cr->dip);
17727c478bdstevel@tonic-gate	    return (cs_add_client_to_socket(sn, ch, cr, super_client));
17737c478bdstevel@tonic-gate	} /* CLIENT_SUPER_CLIENT */
17747c478bdstevel@tonic-gate
17757c478bdstevel@tonic-gate	/*
17767c478bdstevel@tonic-gate	 * This registering client is a "super-client", so we create one
17777c478bdstevel@tonic-gate	 *	client node for each socket in the system.  We use the
17787c478bdstevel@tonic-gate	 *	client_reg_t.priv structure member to point to a struct
17797c478bdstevel@tonic-gate	 *	that the "super-client" client knows about.  The client
17807c478bdstevel@tonic-gate	 *	handle pointer is not used in this case.
17817c478bdstevel@tonic-gate	 * We return CS_SUCCESS if at least one client node could be
17827c478bdstevel@tonic-gate	 *	created.  The client must check the error codes in the
17837c478bdstevel@tonic-gate	 *	error code array to determine which clients could not
17847c478bdstevel@tonic-gate	 *	be created on which sockets.
17857c478bdstevel@tonic-gate	 * We return CS_BAD_HANDLE if no client nodes could be created.
17867c478bdstevel@tonic-gate	 */
17877c478bdstevel@tonic-gate	scr->num_clients = 0;
17887c478bdstevel@tonic-gate	scr->max_socket_num = cs_globals.max_socket_num;
17897c478bdstevel@tonic-gate	scr->num_sockets = cs_globals.num_sockets;
17907c478bdstevel@tonic-gate	scr->num_windows = cs_globals.num_windows;
17917c478bdstevel@tonic-gate
17927c478bdstevel@tonic-gate	*(scr->sclient_list) = cs_globals.sclient_list;
17937c478bdstevel@tonic-gate
17947c478bdstevel@tonic-gate	for (sn = 0; sn < scr->num_sockets; sn++) {
17957c478bdstevel@tonic-gate	    scli = scr->sclient_list[sn];
17967c478bdstevel@tonic-gate	    if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
17977c478bdstevel@tonic-gate					    cr, super_client)) == CS_SUCCESS) {
17987c478bdstevel@tonic-gate		scr->num_clients++;
17997c478bdstevel@tonic-gate	    }
18007c478bdstevel@tonic-gate	}
18017c478bdstevel@tonic-gate
18027c478bdstevel@tonic-gate	/*
18037c478bdstevel@tonic-gate	 * If we couldn't create any client nodes at all, then
18047c478bdstevel@tonic-gate	 *	return an error.
18057c478bdstevel@tonic-gate	 */
18067c478bdstevel@tonic-gate	if (!scr->num_clients) {
18077c478bdstevel@tonic-gate	/*
18087c478bdstevel@tonic-gate	 * XXX - The global superclient lock now gets
18097c478bdstevel@tonic-gate	 * cleared in cs_deregister_client
18107c478bdstevel@tonic-gate	 */
18117c478bdstevel@tonic-gate	    /* cs_clear_superclient_lock(super_client); */
18127c478bdstevel@tonic-gate	    return (CS_BAD_HANDLE);
18137c478bdstevel@tonic-gate	}
18147c478bdstevel@tonic-gate
18157c478bdstevel@tonic-gate	return (CS_SUCCESS);
18167c478bdstevel@tonic-gate}
18177c478bdstevel@tonic-gate
18187c478bdstevel@tonic-gate/*
18197c478bdstevel@tonic-gate * cs_add_client_to_socket - this function creates the client node on the
18207c478bdstevel@tonic-gate *				requested socket.
18217c478bdstevel@tonic-gate *
18227c478bdstevel@tonic-gate * Note that if we return an error, there is no state that can be cleaned
18237c478bdstevel@tonic-gate *	up.  The only way that we can return an error with allocated resources
18247c478bdstevel@tonic-gate *	would be if one of the client handle functions had an internal error.
18257c478bdstevel@tonic-gate *	Since we wouldn't get a valid client handle in this case anyway, there
18267c478bdstevel@tonic-gate *	would be no way to find out what was allocated and what wasn't.
18277c478bdstevel@tonic-gate */
18287c478bdstevel@tonic-gatestatic int
18297c478bdstevel@tonic-gatecs_add_client_to_socket(unsigned sn, client_handle_t *ch,
18307c478bdstevel@tonic-gate					client_reg_t *cr, int super_client)
18317c478bdstevel@tonic-gate{
18327c478bdstevel@tonic-gate	cs_socket_t *sp;
18337c478bdstevel@tonic-gate	client_t *client, *cclp;
18347c478bdstevel@tonic-gate	int error, cie = 1;
18357c478bdstevel@tonic-gate	int client_lock_acquired;
18367c478bdstevel@tonic-gate
18377c478bdstevel@tonic-gate	if (cr->event_handler == NULL)
18387c478bdstevel@tonic-gate	    return (CS_BAD_ARGS);
18397c478bdstevel@tonic-gate
18407c478bdstevel@tonic-gate	if ((sp = cs_get_sp(sn)) == NULL)
18417c478bdstevel@tonic-gate	    return (CS_BAD_SOCKET);
18427c478bdstevel@tonic-gate
18437c478bdstevel@tonic-gate	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
18447c478bdstevel@tonic-gate
18457c478bdstevel@tonic-gate	/*
18467c478bdstevel@tonic-gate	 * Run through all of the registered clients and compare the passed
18477c478bdstevel@tonic-gate	 *	dip to the dip of each client to make sure that this client
18487c478bdstevel@tonic-gate	 *	is not trying to register more than once.  If they are, then
18497c478bdstevel@tonic-gate	 *	display a message and return an error.
18507c478bdstevel@tonic-gate	 * XXX - we should really check all the sockets in case the client
18517c478bdstevel@tonic-gate	 *	manipulates the instance number in the dip.
18527c478bdstevel@tonic-gate	 * XXX - if we check each socket, we ned to also check for the
18537c478bdstevel@tonic-gate	 *	"super-client" since it will use the same dip for all
18547c478bdstevel@tonic-gate	 *	of it's client nodes.
18557c478bdstevel@tonic-gate	 */
18567c478bdstevel@tonic-gate	mutex_enter(&sp->lock);
18577c478bdstevel@tonic-gate	client = sp->client_list;
18587c478bdstevel@tonic-gate	while (client) {
18597c478bdstevel@tonic-gate	    if (!(cr->Attributes & INFO_CSI_CLIENT) &&
18607c478bdstevel@tonic-gate						(client->dip == cr->dip)) {
18617c478bdstevel@tonic-gate		mutex_exit(&sp->lock);
18627c478bdstevel@tonic-gate		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18637c478bdstevel@tonic-gate		cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
18647c478bdstevel@tonic-gate					"function 0x%x\n"
18657c478bdstevel@tonic-gate					"\tclient already registered with "
18667c478bdstevel@tonic-gate					"handle 0x%x\n",
18677c478bdstevel@tonic-gate						(int)CS_GET_SOCKET_NUMBER(sn),
18687c478bdstevel@tonic-gate						(int)CS_GET_FUNCTION_NUMBER(sn),
18697c478bdstevel@tonic-gate						(int)client->client_handle);
18707c478bdstevel@tonic-gate		return (CS_BAD_HANDLE);
18717c478bdstevel@tonic-gate	    }
18727c478bdstevel@tonic-gate	    client = client->next;
18737c478bdstevel@tonic-gate	} /* while (client) */
18747c478bdstevel@tonic-gate	mutex_exit(&sp->lock);
18757c478bdstevel@tonic-gate
18767c478bdstevel@tonic-gate	/*
18777c478bdstevel@tonic-gate	 * Create a unique client handle then make sure that we can find it.
18787c478bdstevel@tonic-gate	 *	This has the side effect of getting us a pointer to the
18797c478bdstevel@tonic-gate	 *	client structure as well.
18807c478bdstevel@tonic-gate	 * Create a client list entry - cs_create_client_handle will use this
18817c478bdstevel@tonic-gate	 *	as the new client node.
18827c478bdstevel@tonic-gate	 * We do it here so that we can grab the sp->lock mutex for the
18837c478bdstevel@tonic-gate	 *	duration of our manipulation of the client list.
18847c478bdstevel@tonic-gate	 * If this function fails, then it will not have added the newly
18857c478bdstevel@tonic-gate	 *	allocated client node to the client list on this socket,
18867c478bdstevel@tonic-gate	 *	so we have to free the node that we allocated.
18877c478bdstevel@tonic-gate	 */
18887c478bdstevel@tonic-gate	cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
18897c478bdstevel@tonic-gate
18907c478bdstevel@tonic-gate	mutex_enter(&sp->lock);
18917c478bdstevel@tonic-gate	if (!(*ch = cs_create_client_handle(sn, cclp))) {
18927c478bdstevel@tonic-gate	    mutex_exit(&sp->lock);
18937c478bdstevel@tonic-gate	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18947c478bdstevel@tonic-gate	    kmem_free(cclp, sizeof (client_t));
18957c478bdstevel@tonic-gate	    return (CS_OUT_OF_RESOURCE);
18967c478bdstevel@tonic-gate	}
18977c478bdstevel@tonic-gate
18987c478bdstevel@tonic-gate	/*
18997c478bdstevel@tonic-gate	 *  Make sure that this is a valid client handle.  We should never
19007c478bdstevel@tonic-gate	 *	fail this since we just got a valid client handle.
19017c478bdstevel@tonic-gate	 * If this fails, then we have an internal error so don't bother
19027c478bdstevel@tonic-gate	 *	trying to clean up the allocated client handle since the
19037c478bdstevel@tonic-gate	 *	whole system is probably hosed anyway and will shortly
19047c478bdstevel@tonic-gate	 *	esplode.
19057c478bdstevel@tonic-gate	 * It doesn't make sense to call cs_deregister_client at this point
19067c478bdstevel@tonic-gate	 *	to clean up this broken client since the deregistration
19077c478bdstevel@tonic-gate	 *	code will also call cs_find_client and most likely fail.
19087c478bdstevel@tonic-gate	 */
19097c478bdstevel@tonic-gate	if (!(client = cs_find_client(*ch, &error))) {
19107c478bdstevel@tonic-gate	    mutex_exit(&sp->lock);
19117c478bdstevel@tonic-gate	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
19127c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
19137c478bdstevel@tonic-gate				"invalid client handle created handle 0x%x\n",
19147c478bdstevel@tonic-gate						(int)CS_GET_SOCKET_NUMBER(sn),
19157c478bdstevel@tonic-gate						(int)CS_GET_FUNCTION_NUMBER(sn),
19167c478bdstevel@tonic-gate						(int)*ch);
19177c478bdstevel@tonic-gate	    return (error);
19187c478bdstevel@tonic-gate	}
19197c478bdstevel@tonic-gate
19207c478bdstevel@tonic-gate	/*
19217c478bdstevel@tonic-gate	 * Save the DDI information.
19227c478bdstevel@tonic-gate	 */
19237c478bdstevel@tonic-gate	client->dip = cr->dip;
1924c48c304Toomas Soome	cr->driver_name[MODMAXNAMELEN - 1] = '\0';
1925c48c304Toomas Soome	client->driver_name = kmem_zalloc(strlen(cr->driver_name) + 1,
1926c48c304Toomas Soome	    KM_SLEEP);
19277c478bdstevel@tonic-gate	(void) strcpy(client->driver_name, cr->driver_name);
19287c478bdstevel@tonic-gate	client->instance = ddi_get_instance(cr->dip);
19297c478bdstevel@tonic-gate
19307c478bdstevel@tonic-gate	/*
19317c478bdstevel@tonic-gate	 * Copy over the interesting items that the client gave us.
19327c478bdstevel@tonic-gate	 */
19337c478bdstevel@tonic-gate	client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
19347c478bdstevel@tonic-gate	client->event_callback_handler = cr->event_handler;
19357c478bdstevel@tonic-gate	bcopy((caddr_t)&cr->event_callback_args,
19367c478bdstevel@tonic-gate				(caddr_t)&client->event_callback_args,
19377c478bdstevel@tonic-gate				sizeof (event_callback_args_t));
19387c478bdstevel@tonic-gate	/*
19397c478bdstevel@tonic-gate	 * Set the client handle since the client needs a client handle
19407c478bdstevel@tonic-gate	 *	when they call us for their event handler.
19417c478bdstevel@tonic-gate	 */
19427c478bdstevel@tonic-gate	client->event_callback_args.client_handle = *ch;
19437c478bdstevel@tonic-gate
19447c478bdstevel@tonic-gate	/*
19457c478bdstevel@tonic-gate	 * Initialize the IO window numbers; if an IO window number is equal
19467c478bdstevel@tonic-gate	 *	to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
19477c478bdstevel@tonic-gate	 */
19487c478bdstevel@tonic-gate	client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
19497c478bdstevel@tonic-gate	client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
19507c478bdstevel@tonic-gate
19517c478bdstevel@tonic-gate	/*
19527c478bdstevel@tonic-gate	 * Give the client the iblock and idevice cookies to use in
19537c478bdstevel@tonic-gate	 *	the client's event handler high priority mutex.
19547c478bdstevel@tonic-gate	 */
19557c478bdstevel@tonic-gate	cr->iblk_cookie = sp->iblk;
19567c478bdstevel@tonic-gate	cr->idev_cookie = sp->idev;
19577c478bdstevel@tonic-gate
19587c478bdstevel@tonic-gate	/*
19597c478bdstevel@tonic-gate	 * Set up the global event mask information; we copy this directly
19607c478bdstevel@tonic-gate	 *	from the client; since we are the only source of events,
19617c478bdstevel@tonic-gate	 *	any bogus bits that the client puts in here won't matter
19627c478bdstevel@tonic-gate	 *	because we'll never look at them.
19637c478bdstevel@tonic-gate	 */
19647c478bdstevel@tonic-gate	client->global_mask = cr->EventMask;
19657c478bdstevel@tonic-gate
19667c478bdstevel@tonic-gate	/*
19677c478bdstevel@tonic-gate	 * If this client registered as a CSI client, set the appropriate
19687c478bdstevel@tonic-gate	 *	flag in the client's flags area.
19697c478bdstevel@tonic-gate	 */
19707c478bdstevel@tonic-gate	if (cr->Attributes & INFO_CSI_CLIENT)
19717c478bdstevel@tonic-gate	    client->flags |= CLIENT_CSI_CLIENT;
19727c478bdstevel@tonic-gate
19737c478bdstevel@tonic-gate	/*
19747c478bdstevel@tonic-gate	 * If this client registered as a "super-client" set the appropriate
19757c478bdstevel@tonic-gate	 *	flag in the client's flags area.
19767c478bdstevel@tonic-gate	 */
19777c478bdstevel@tonic-gate	if (super_client == CLIENT_SUPER_CLIENT)
19787c478bdstevel@tonic-gate	    client->flags |= CLIENT_SUPER_CLIENT;
19797c478bdstevel@tonic-gate
19807c478bdstevel@tonic-gate	/*
19817c478bdstevel@tonic-gate	 * Save other misc information that this client gave us - it is
19827c478bdstevel@tonic-gate	 *	used in the GetClientInfo function.
19837c478bdstevel@tonic-gate	 */
19847c478bdstevel@tonic-gate	client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
19857c478bdstevel@tonic-gate
19867c478bdstevel@tonic-gate	/*
19877c478bdstevel@tonic-gate	 * Determine if we should give artificial card insertion events and
19887c478bdstevel@tonic-gate	 *	a registration complete event. Since we don't differentiate
19897c478bdstevel@tonic-gate	 *	between sharable and exclusive use cards when giving clients
19907c478bdstevel@tonic-gate	 *	event notification, we modify the definition of the share/excl
19917c478bdstevel@tonic-gate	 *	flags as follows:
19927c478bdstevel@tonic-gate	 *
19937c478bdstevel@tonic-gate	 *	    If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
19947c478bdstevel@tonic-gate	 *	    the client will receive artificial card insertion
19957c478bdstevel@tonic-gate	 *	    events (if the client's card is currently in the
19967c478bdstevel@tonic-gate	 *	    socket) and a registration complete event.
19977c478bdstevel@tonic-gate	 *
19987c478bdstevel@tonic-gate	 *	    If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
19997c478bdstevel@tonic-gate	 *	    set, the client will not receive an artificial card
20007c478bdstevel@tonic-gate	 *	    insertion event nor a registration complete event
20017c478bdstevel@tonic-gate	 *	    due to the client's call to register client.
20027c478bdstevel@tonic-gate	 *
20037c478bdstevel@tonic-gate	 *	    The client's event mask is not affected by the setting
20047c478bdstevel@tonic-gate	 *	    of these two bits.
20057c478bdstevel@tonic-gate	 */
20067c478bdstevel@tonic-gate	if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
20077c478bdstevel@tonic-gate	    client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
20087c478bdstevel@tonic-gate
20097c478bdstevel@tonic-gate	/*
20107c478bdstevel@tonic-gate	 * Check to see if the card for this client is currently in
20117c478bdstevel@tonic-gate	 *	the socket. If it is, then set CLIENT_CARD_INSERTED
20127c478bdstevel@tonic-gate	 *	since clients that are calling GetStatus at attach
20137c478bdstevel@tonic-gate	 *	time will typically check to see if their card is
20147c478bdstevel@tonic-gate	 *	currently installed.
20157c478bdstevel@tonic-gate	 * If this is the CSI client, we also need to check to see
20167c478bdstevel@tonic-gate	 *	if there is any card inserted in the socket, since
20177c478bdstevel@tonic-gate	 *	the cs_card_for_client function will always return
20187c478bdstevel@tonic-gate	 *	TRUE for a CSI client.
20197c478bdstevel@tonic-gate	 * XXX What about super-clients?
20207c478bdstevel@tonic-gate	 */
20217c478bdstevel@tonic-gate	if (client->flags & CLIENT_CSI_CLIENT) {
20227c478bdstevel@tonic-gate	    get_ss_status_t get_ss_status;
20237c478bdstevel@tonic-gate
20247c478bdstevel@tonic-gate	    get_ss_status.socket = sp->socket_num;
20257c478bdstevel@tonic-gate
20267c478bdstevel@tonic-gate	    if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
20277c478bdstevel@tonic-gate		mutex_exit(&sp->lock);
20287c478bdstevel@tonic-gate		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20297c478bdstevel@tonic-gate		return (CS_BAD_SOCKET);
20307c478bdstevel@tonic-gate	    } /* SS_GetStatus */
20317c478bdstevel@tonic-gate
20327c478bdstevel@tonic-gate	    if (!(cs_sbm2cse(get_ss_status.CardState) &
20337c478bdstevel@tonic-gate			CS_EVENT_CARD_INSERTION))
20347c478bdstevel@tonic-gate		cie = 0;
20357c478bdstevel@tonic-gate
20367c478bdstevel@tonic-gate	} /* CLIENT_CSI_CLIENT */
20377c478bdstevel@tonic-gate
20387c478bdstevel@tonic-gate	if (cs_card_for_client(client) && (cie != 0)) {
20397c478bdstevel@tonic-gate	    client->pending_events |= CS_EVENT_CARD_INSERTION;
20407c478bdstevel@tonic-gate	    client->flags |= CLIENT_CARD_INSERTED;
20417c478bdstevel@tonic-gate	} /* cs_card_for_client */
20427c478bdstevel@tonic-gate
20437c478bdstevel@tonic-gate	sp->num_clients++;
20447c478bdstevel@tonic-gate	mutex_exit(&sp->lock);
20457c478bdstevel@tonic-gate	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20467c478bdstevel@tonic-gate
20477c478bdstevel@tonic-gate	return (CS_SUCCESS);
20487c478bdstevel@tonic-gate}
20497c478bdstevel@tonic-gate
20507c478bdstevel@tonic-gate/*
20517c478bdstevel@tonic-gate * cs_deregister_client - This supports the DeregisterClient call.
20527c478bdstevel@tonic-gate */
20537c478bdstevel@tonic-gatestatic int
20547c478bdstevel@tonic-gatecs_deregister_client(client_handle_t client_handle)
20557c478bdstevel@tonic-gate{
20567c478bdstevel@tonic-gate	cs_socket_t *sp;
20577c478bdstevel@tonic-gate	client_t *client;
20587c478bdstevel@tonic-gate	int error, super_client = 0;
20597c478bdstevel@tonic-gate	int client_lock_acquired;
20607c478bdstevel@tonic-gate
20617c478bdstevel@tonic-gate	/*
20627c478bdstevel@tonic-gate	 * Check to see if this is the Socket Services client handle; if it
20637c478bdstevel@tonic-gate	 *	is, we don't do anything except for return success.
20647c478bdstevel@tonic-gate	 */
20657c478bdstevel@tonic-gate	if (CLIENT_HANDLE_IS_SS(client_handle))
20667c478bdstevel@tonic-gate	    return (CS_SUCCESS);
20677c478bdstevel@tonic-gate
20687c478bdstevel@tonic-gate	/*
20697c478bdstevel@tonic-gate	 * Get a pointer to this client's socket structure.
20707c478bdstevel@tonic-gate	 */
20717c478bdstevel@tonic-gate	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
20727c478bdstevel@tonic-gate	    return (CS_BAD_SOCKET);
20737c478bdstevel@tonic-gate
20747c478bdstevel@tonic-gate	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
20757c478bdstevel@tonic-gate
20767c478bdstevel@tonic-gate	/*
20777c478bdstevel@tonic-gate	 *  Make sure that this is a valid client handle.
20787c478bdstevel@tonic-gate	 */
20797c478bdstevel@tonic-gate	if (!(client = cs_find_client(client_handle, &error))) {
20807c478bdstevel@tonic-gate	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20817c478bdstevel@tonic-gate	    return (error);
20827c478bdstevel@tonic-gate	}
20837c478bdstevel@tonic-gate
20847c478bdstevel@tonic-gate	/*
20857c478bdstevel@tonic-gate	 * Make sure that any resources allocated by this client are
20867c478bdstevel@tonic-gate	 *	not still allocated, and that if this is an MTD that
20877c478bdstevel@tonic-gate	 *	no MTD operations are still in progress.
20887c478bdstevel@tonic-gate	 */
20897c478bdstevel@tonic-gate	if (client->flags &    (CLIENT_IO_ALLOCATED	|
20907c478bdstevel@tonic-gate				CLIENT_IRQ_ALLOCATED	|
20917c478bdstevel@tonic-gate				CLIENT_WIN_ALLOCATED	|
20927c478bdstevel@tonic-gate				REQ_CONFIGURATION_DONE	|
20937c478bdstevel@tonic-gate				REQ_SOCKET_MASK_DONE	|
20947c478bdstevel@tonic-gate				REQ_IO_DONE		|
20957c478bdstevel@tonic-gate				REQ_IRQ_DONE)) {
20967c478bdstevel@tonic-gate	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20977c478bdstevel@tonic-gate	    return (CS_BUSY);
20987c478bdstevel@tonic-gate	}
20997c478bdstevel@tonic-gate
21007c478bdstevel@tonic-gate	if (client->flags & CLIENT_MTD_IN_PROGRESS) {
21017c478bdstevel@tonic-gate	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21027c478bdstevel@tonic-gate	    return (CS_IN_USE);
21037c478bdstevel@tonic-gate	}
21047c478bdstevel@tonic-gate
21057c478bdstevel@tonic-gate	/*
21067c478bdstevel@tonic-gate	 * Any previously allocated resources are not allocated anymore, and
21077c478bdstevel@tonic-gate	 *	no MTD operations are in progress, so if this is an MTD client
21087c478bdstevel@tonic-gate	 *	then do any MTD-specific client deregistration, and then
21097c478bdstevel@tonic-gate	 *	nuke this client.
21107c478bdstevel@tonic-gate	 * We expect cs_deregister_mtd to never fail.
21117c478bdstevel@tonic-gate	 */
21127c478bdstevel@tonic-gate	if (client->flags & INFO_MTD_CLIENT)
21137c478bdstevel@tonic-gate	    (void) cs_deregister_mtd(client_handle);
21147c478bdstevel@tonic-gate
21157c478bdstevel@tonic-gate	if (client->flags & CLIENT_SUPER_CLIENT)
21167c478bdstevel@tonic-gate	    super_client = CLIENT_SUPER_CLIENT;
21177c478bdstevel@tonic-gate
21187c478bdstevel@tonic-gate	kmem_free(client->driver_name, strlen(client->driver_name) + 1);
21197c478bdstevel@tonic-gate
21207c478bdstevel@tonic-gate	error = cs_destroy_client_handle(client_handle);
21217c478bdstevel@tonic-gate
21227c478bdstevel@tonic-gate	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21237c478bdstevel@tonic-gate
21247c478bdstevel@tonic-gate	/*
21257c478bdstevel@tonic-gate	 * If this was the "super-client" deregistering, then this
21267c478bdstevel@tonic-gate	 *	will clear the global "super-client" lock.
21277c478bdstevel@tonic-gate	 * XXX - move this outside the per-socket code.
21287c478bdstevel@tonic-gate	 */
21297c478bdstevel@tonic-gate	cs_clear_superclient_lock(super_client);
21307c478bdstevel@tonic-gate
21317c478bdstevel@tonic-gate	return (error);
21327c478bdstevel@tonic-gate}
21337c478bdstevel@tonic-gate
21347c478bdstevel@tonic-gate/*
21357c478bdstevel@tonic-gate * cs_create_next_client_minor - returns the next available client minor
21367c478bdstevel@tonic-gate *					number or 0 if none available
21377c478bdstevel@tonic-gate *
21387c478bdstevel@tonic-gate * Note that cs_find_client will always return a valid pointer to the
21397c478bdstevel@tonic-gate *	global Socket Services client which has a client minor number
21407c478bdstevel@tonic-gate *	of 0; this means that this function can never return a 0 as the
21417c478bdstevel@tonic-gate *	next valid available client minor number.
21427c478bdstevel@tonic-gate */
21437c478bdstevel@tonic-gateunsigned
21447c478bdstevel@tonic-gatecs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
21457c478bdstevel@tonic-gate{
21467c478bdstevel@tonic-gate	unsigned max_client_handles = cs_max_client_handles;
21477c478bdstevel@tonic-gate
21487c478bdstevel@tonic-gate	do {
21497c478bdstevel@tonic-gate	    next_minor &= CS_MAX_CLIENTS_MASK;
21507c478bdstevel@tonic-gate	    if (!cs_find_client(MAKE_CLIENT_HANDLE(
21517c478bdstevel@tonic-gate					CS_GET_SOCKET_NUMBER(socket_num),
21527c478bdstevel@tonic-gate					CS_GET_FUNCTION_NUMBER(socket_num),
21537c478bdstevel@tonic-gate							next_minor), NULL)) {
21547c478bdstevel@tonic-gate		return (next_minor);
21557c478bdstevel@tonic-gate	    }
21567c478bdstevel@tonic-gate	    next_minor++;
21577c478bdstevel@tonic-gate	} while (max_client_handles--);
21587c478bdstevel@tonic-gate
21597c478bdstevel@tonic-gate	return (0);
21607c478bdstevel@tonic-gate}
21617c478bdstevel@tonic-gate
21627c478bdstevel@tonic-gate/*
21637c478bdstevel@tonic-gate * cs_find_client - finds the client pointer associated with the client handle
21647c478bdstevel@tonic-gate *			or NULL if client not found
21657c478bdstevel@tonic-gate *
21667c478bdstevel@tonic-gate * returns:	(client_t *)NULL - if client not found or an error occured
21677c478bdstevel@tonic-gate *					If the error argument is not NULL,
21687c478bdstevel@tonic-gate *					it is set to:
21697c478bdstevel@tonic-gate *			CS_BAD_SOCKET - socket number in client_handle_t is
21707c478bdstevel@tonic-gate *						invalid
21717c478bdstevel@tonic-gate *			CS_BAD_HANDLE - client not found
21727c478bdstevel@tonic-gate *			If no error, the error argument is not modified.
21737c478bdstevel@tonic-gate *		(client_t *) - pointer to client_t structure
21747c478bdstevel@tonic-gate *
21757c478bdstevel@tonic-gate * Note that each socket always has a pseudo client with a client minor number
21767c478bdstevel@tonic-gate *	of 0; this client minor number is used for Socket Services access to
21777c478bdstevel@tonic-gate *	Card Services functions. The client pointer returned for client minor
21787c478bdstevel@tonic-gate *	number 0 is the global Socket Services client pointer.
21797c478bdstevel@tonic-gate */
21807c478bdstevel@tonic-gatestatic client_t *
21817c478bdstevel@tonic-gatecs_find_client(client_handle_t client_handle, int *error)
21827c478bdstevel@tonic-gate{
21837c478bdstevel@tonic-gate	cs_socket_t *sp;
21847c478bdstevel@tonic-gate	client_t *clp;
21857c478bdstevel@tonic-gate
21867c478bdstevel@tonic-gate	/*
21877c478bdstevel@tonic-gate	 * If we are being asked to see if a client with a minor number
21887c478bdstevel@tonic-gate	 *	of 0 exists, always return a pointer to the global Socket
21897c478bdstevel@tonic-gate	 *	Services client, since this client always exists, and is
21907c478bdstevel@tonic-gate	 *	only for use by Socket Services.  There is no socket
21917c478bdstevel@tonic-gate	 *	associated with this special client handle.
21927c478bdstevel@tonic-gate	 */
21937c478bdstevel@tonic-gate	if (CLIENT_HANDLE_IS_SS(client_handle))
21947c478bdstevel@tonic-gate	    return (&cs_socket_services_client);
21957c478bdstevel@tonic-gate
21967c478bdstevel@tonic-gate	/*
21977c478bdstevel@tonic-gate	 * Check to be sure that the socket number is in range
21987c478bdstevel@tonic-gate	 */
21997c478bdstevel@tonic-gate	if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
22007c478bdstevel@tonic-gate					cs_globals.max_socket_num))) {
22017c478bdstevel@tonic-gate	    if (error)
22027c478bdstevel@tonic-gate		*error = CS_BAD_SOCKET;
22037c478bdstevel@tonic-gate	    return (NULL);
22047c478bdstevel@tonic-gate	}
22057c478bdstevel@tonic-gate
22067c478bdstevel@tonic-gate	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
22077c478bdstevel@tonic-gate	    if (error)
22087c478bdstevel@tonic-gate		*error = CS_BAD_SOCKET;
22097c478bdstevel@tonic-gate	    return (NULL);
22107c478bdstevel@tonic-gate	}
22117c478bdstevel@tonic-gate
22127c478bdstevel@tonic-gate	clp = sp->client_list;
22137c478bdstevel@tonic-gate
22147c478bdstevel@tonic-gate	while (clp) {
22157c478bdstevel@tonic-gate	    if (clp->client_handle == client_handle)
22167c478bdstevel@tonic-gate		return (clp);
22177c478bdstevel@tonic-gate	    clp = clp->next;
22187c478bdstevel@tonic-gate	}
22197c478bdstevel@tonic-gate
22207c478bdstevel@tonic-gate	if (error)
22217c478bdstevel@tonic-gate	    *error = CS_BAD_HANDLE;
22227c478bdstevel@tonic-gate
22237c478bdstevel@tonic-gate	return (NULL);
22247c478bdstevel@tonic-gate}
22257c478bdstevel@tonic-gate
22267c478bdstevel@tonic-gate/*
22277c478bdstevel@tonic-gate * cs_destroy_client_handle - destroys client handle and client structure of
22287c478bdstevel@tonic-gate *				passed client handle
22297c478bdstevel@tonic-gate *
22307c478bdstevel@tonic-gate * returns:	CS_SUCCESS - if client handle sucessfully destroyed
22317c478bdstevel@tonic-gate *		CS_BAD_HANDLE - if client handle is invalid or if trying
22327c478bdstevel@tonic-gate *					to destroy global SS client
22337c478bdstevel@tonic-gate *		{other errors} - other errors from cs_find_client()
22347c478bdstevel@tonic-gate */
22357c478bdstevel@tonic-gatestatic int
22367c478bdstevel@tonic-gatecs_destroy_client_handle(client_handle_t client_handle)
22377c478bdstevel@tonic-gate{
22387c478bdstevel@tonic-gate	client_t *clp;
22397c478bdstevel@tonic-gate	cs_socket_t *sp;
22407c478bdstevel@tonic-gate	int error = CS_BAD_HANDLE;
22417c478bdstevel@tonic-gate
22427c478bdstevel@tonic-gate	/*
22437c478bdstevel@tonic-gate	 * See if we were passed a valid client handle or if we're being asked
22447c478bdstevel@tonic-gate	 *	to destroy the Socket Services client
22457c478bdstevel@tonic-gate	 */
22467c478bdstevel@tonic-gate	if ((!(clp = cs_find_client(client_handle, &error))) ||
22477c478bdstevel@tonic-gate			(CLIENT_HANDLE_IS_SS(client_handle)))
22487c478bdstevel@tonic-gate	    return (error);
22497c478bdstevel@tonic-gate
22507c478bdstevel@tonic-gate	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
22517c478bdstevel@tonic-gate	    return (CS_BAD_SOCKET);
22527c478bdstevel@tonic-gate
22537c478bdstevel@tonic-gate	/*
22547c478bdstevel@tonic-gate	 * Recycle this client's minor number.  This will most likely
22557c478bdstevel@tonic-gate	 *	be the next client minor number we use, but it is also
22567c478bdstevel@tonic-gate	 *	a hint to cs_create_client_handle, and that function
22577c478bdstevel@tonic-gate	 *	may actually create a new client handle using a minor
22587c478bdstevel@tonic-gate	 *	number different that this number.
22597c478bdstevel@tonic-gate	 */
22607c478bdstevel@tonic-gate	mutex_enter(&sp->lock);
22617c478bdstevel@tonic-gate	sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
22627c478bdstevel@tonic-gate
22637c478bdstevel@tonic-gate	/*
22647c478bdstevel@tonic-gate	 * See if we're the first or not in the client list; if we're
22657c478bdstevel@tonic-gate	 *	not first, then just adjust the client behind us to
22667c478bdstevel@tonic-gate	 *	point to the client ahead of us; this could be NULL
22677c478bdstevel@tonic-gate	 *	if we're the last client in the list.
22687c478bdstevel@tonic-gate	 */
22697c478bdstevel@tonic-gate	if (clp->prev) {
22707c478bdstevel@tonic-gate	    clp->prev->next = clp->next;
22717c478bdstevel@tonic-gate	} else {
22727c478bdstevel@tonic-gate	/*
22737c478bdstevel@tonic-gate	 * We are first, so adjust the client list head pointer
22747c478bdstevel@tonic-gate	 *	in the socket to point to the client structure that
22757c478bdstevel@tonic-gate	 *	follows us; this could turn out to be NULL if we're
22767c478bdstevel@tonic-gate	 *	the only client on this socket.
22777c478bdstevel@tonic-gate	 */
22787c478bdstevel@tonic-gate	    sp->client_list = clp->next;
22797c478bdstevel@tonic-gate	}
22807c478bdstevel@tonic-gate
22817c478bdstevel@tonic-gate	/*
22827c478bdstevel@tonic-gate	 * If we're not the last client in the list, point the next
22837c478bdstevel@tonic-gate	 *	client to the client behind us; this could turn out
22847c478bdstevel@tonic-gate	 *	to be NULL if we're the first client on this socket.
22857c478bdstevel@tonic-gate	 */
22867c478bdstevel@tonic-gate	if (clp->next)
22877c478bdstevel@tonic-gate	    clp->next->prev = clp->prev;
22887c478bdstevel@tonic-gate
22897c478bdstevel@tonic-gate	sp->num_clients--;
22907c478bdstevel@tonic-gate	mutex_exit(&sp->lock);
22917c478bdstevel@tonic-gate
22927c478bdstevel@tonic-gate	/*
22937c478bdstevel@tonic-gate	 * Free this client's memory.
22947c478bdstevel@tonic-gate	 */
22957c478bdstevel@tonic-gate	kmem_free(clp, sizeof (client_t));
22967c478bdstevel@tonic-gate
22977c478bdstevel@tonic-gate	return (CS_SUCCESS);
22987c478bdstevel@tonic-gate}
22997c478bdstevel@tonic-gate
23007c478bdstevel@tonic-gate/*
23017c478bdstevel@tonic-gate * cs_create_client_handle - create a new client handle for the passed
23027c478bdstevel@tonic-gate *				socket and function number
23037c478bdstevel@tonic-gate *
23047c478bdstevel@tonic-gate * returns:	0 -  if can't create client for some reason
23057c478bdstevel@tonic-gate *		client_handle_t - new client handle
23067c478bdstevel@tonic-gate */
23077c478bdstevel@tonic-gatestatic client_handle_t
23087c478bdstevel@tonic-gatecs_create_client_handle(unsigned socket_num, client_t *cclp)
23097c478bdstevel@tonic-gate{
23107c478bdstevel@tonic-gate	client_t *clp;
23117c478bdstevel@tonic-gate	cs_socket_t *sp;
23127c478bdstevel@tonic-gate	unsigned next_minor;
23137c478bdstevel@tonic-gate	client_handle_t client_handle;
23147c478bdstevel@tonic-gate
23157c478bdstevel@tonic-gate	if ((sp = cs_get_sp(socket_num)) == NULL)
23167c478bdstevel@tonic-gate	    return (0);
23177c478bdstevel@tonic-gate
23187c478bdstevel@tonic-gate	/*
23197c478bdstevel@tonic-gate	 * Get the next available minor number that we can use.  We use the
23207c478bdstevel@tonic-gate	 *	next_cl_minor number as a hint to cs_create_next_client_minor
23217c478bdstevel@tonic-gate	 *	and in most cases this will be the minor number we get back.
23227c478bdstevel@tonic-gate	 * If for some reason we can't get a minor number, return an error.
23237c478bdstevel@tonic-gate	 *	The only way we could get an error would be if there are
23247c478bdstevel@tonic-gate	 *	already the maximum number of clients for this socket. Since
23257c478bdstevel@tonic-gate	 *	the maximum number of clients per socket is pretty large,
23267c478bdstevel@tonic-gate	 *	this error is unlikely to occur.
23277c478bdstevel@tonic-gate	 */
23287c478bdstevel@tonic-gate	if (!(next_minor =
23297c478bdstevel@tonic-gate		cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
23307c478bdstevel@tonic-gate	    return (0);
23317c478bdstevel@tonic-gate
23327c478bdstevel@tonic-gate	/*
23337c478bdstevel@tonic-gate	 * Got a new client minor number, now create a new client handle.
23347c478bdstevel@tonic-gate	 */
23357c478bdstevel@tonic-gate	client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
23367c478bdstevel@tonic-gate					CS_GET_FUNCTION_NUMBER(socket_num),
23377c478bdstevel@tonic-gate					next_minor);
23387c478bdstevel@tonic-gate
23397c478bdstevel@tonic-gate	/*
23407c478bdstevel@tonic-gate	 * If this client handle exists, then we have an internal
23417c478bdstevel@tonic-gate	 *	error; this should never happen, BTW.  This is really
23427c478bdstevel@tonic-gate	 *	a double-check on the cs_create_next_client_minor
23437c478bdstevel@tonic-gate	 *	function, which also calls cs_find_client.
23447c478bdstevel@tonic-gate	 */
23457c478bdstevel@tonic-gate	if (cs_find_client(client_handle, NULL)) {
23467c478bdstevel@tonic-gate	    cmn_err(CE_CONT,
23477c478bdstevel@tonic-gate		"cs_create_client_handle: duplicate client handle 0x%x\n",
23487c478bdstevel@tonic-gate							(int)client_handle);
23497c478bdstevel@tonic-gate	    return (0);
23507c478bdstevel@tonic-gate	}
23517c478bdstevel@tonic-gate
23527c478bdstevel@tonic-gate	/*
23537c478bdstevel@tonic-gate	 * If we don't have any clients on this socket yet, create
23547c478bdstevel@tonic-gate	 *	a new client and hang it on the socket client list.
23557c478bdstevel@tonic-gate	 */
23567c478bdstevel@tonic-gate	if (!sp->client_list) {
23577c478bdstevel@tonic-gate	    sp->client_list = cclp;
23587c478bdstevel@tonic-gate	    clp = sp->client_list;
23597c478bdstevel@tonic-gate	} else {
23607c478bdstevel@tonic-gate	/*
23617c478bdstevel@tonic-gate	 * There are other clients on this socket, so look for
23627c478bdstevel@tonic-gate	 *	the last client and add our new client after it.
23637c478bdstevel@tonic-gate	 */
23647c478bdstevel@tonic-gate	    clp = sp->client_list;
23657c478bdstevel@tonic-gate	    while (clp->next) {
23667c478bdstevel@tonic-gate		clp = clp->next;
23677c478bdstevel@tonic-gate	    }
23687c478bdstevel@tonic-gate
23697c478bdstevel@tonic-gate	    clp->next = cclp;
23707c478bdstevel@tonic-gate	    clp->next->prev = clp;
23717c478bdstevel@tonic-gate	    clp = clp->next;
23727c478bdstevel@tonic-gate	} /* if (!sp->client_list) */
23737c478bdstevel@tonic-gate
23747c478bdstevel@tonic-gate	/*
23757c478bdstevel@tonic-gate	 * Assign the new client handle to this new client structure.
23767c478bdstevel@tonic-gate	 */
23777c478bdstevel@tonic-gate	clp->client_handle = client_handle;
23787c478bdstevel@tonic-gate
23797c478bdstevel@tonic-gate	/*
23807c478bdstevel@tonic-gate	 * Create the next available client minor number for this socket
23817c478bdstevel@tonic-gate	 *	and save it away.
23827c478bdstevel@tonic-gate	 */
23837c478bdstevel@tonic-gate	sp->next_cl_minor =
23847c478bdstevel@tonic-gate		cs_create_next_client_minor(socket_num, sp->next_cl_minor);
23857c478bdstevel@tonic-gate
23867c478bdstevel@tonic-gate	return (client_handle);
23877c478bdstevel@tonic-gate}
23887c478bdstevel@tonic-gate
23897c478bdstevel@tonic-gate/*
23907c478bdstevel@tonic-gate * cs_clear_superclient_lock - clears the global "super-client" lock
23917c478bdstevel@tonic-gate *
23927c478bdstevel@tonic-gate * Note: this function uses the cs_globals.global_lock so observe proper
23937c478bdstevel@tonic-gate *		nexting of locks!!
23947c478bdstevel@tonic-gate */
23957c478bdstevel@tonic-gatestatic void
23967c478bdstevel@tonic-gatecs_clear_superclient_lock(int super_client)
23977c478bdstevel@tonic-gate{
23987c478bdstevel@tonic-gate
23997c478bdstevel@tonic-gate	/*
24007c478bdstevel@tonic-gate	 * If this was a "super-client" registering then we need
24017c478bdstevel@tonic-gate	 *	to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
24027c478bdstevel@tonic-gate	 *	so that other "super-clients" can register.
24037c478bdstevel@tonic-gate	 */
24047c478bdstevel@tonic-gate	if (super_client == CLIENT_SUPER_CLIENT) {
24057c478bdstevel@tonic-gate	    mutex_enter(&cs_globals.global_lock);
24067c478bdstevel@tonic-gate	    cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
24077c478bdstevel@tonic-gate	    mutex_exit(&cs_globals.global_lock);
24087c478bdstevel@tonic-gate	}
24097c478bdstevel@tonic-gate}
24107c478bdstevel@tonic-gate
24117c478bdstevel@tonic-gate/*
24127c478bdstevel@tonic-gate * ==== event handling section ====
24137c478bdstevel@tonic-gate */
24147c478bdstevel@tonic-gate
24157c478bdstevel@tonic-gate/*
24167c478bdstevel@tonic-gate * cs_event - CS event hi-priority callback handler
24177c478bdstevel@tonic-gate *
24187c478bdstevel@tonic-gate *	This function gets called by SS and is passed the event type in
24197c478bdstevel@tonic-gate *		the "event" argument, and the socket number in the "sn"
24207c478bdstevel@tonic-gate *		argument. The "sn" argument is a valid logical socket
24217c478bdstevel@tonic-gate *		number for all events except the PCE_SS_READY event.
24227c478bdstevel@tonic-gate *
24237c478bdstevel@tonic-gate *	The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
24247c478bdstevel@tonic-gate *		are never called at high priority. These events return
24257c478bdstevel@tonic-gate *		the following return codes:
24267c478bdstevel@tonic-gate *
24277c478bdstevel@tonic-gate *			CS_SUCCESS - operation sucessful
24287c478bdstevel@tonic-gate *			CS_BAD_SOCKET - unable to complete operation
24297c478bdstevel@tonic-gate *			CS_UNSUPPORTED_FUNCTION - bad subfunction of
24307c478bdstevel@tonic-gate *							PCE_SS_INIT_STATE
24317c478bdstevel@tonic-gate *
24327c478bdstevel@tonic-gate *		The caller MUST look at these return codes!
24337c478bdstevel@tonic-gate *
24347c478bdstevel@tonic-gate *	This function is called at high-priority interrupt time for standard
24357c478bdstevel@tonic-gate *		Card Services events, and the only standard Card Services
24367c478bdstevel@tonic-gate *		event that it handles directly is the CS_EVENT_CARD_REMOVAL
24377c478bdstevel@tonic-gate *		event, which gets shuttled right into the client's event
24387c478bdstevel@tonic-gate *		handler.  All other events are just queued up and the socket
24397c478bdstevel@tonic-gate *		event thread is woken up via the soft interrupt handler.
24407c478bdstevel@tonic-gate *	Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
24417c478bdstevel@tonic-gate *		event field, since the CS card insertion/card ready processing
24427c478bdstevel@tonic-gate *		code is responsible for setting this event in a client's
24437c478bdstevel@tonic-gate *		event field.
24447c478bdstevel@tonic-gate *
24457c478bdstevel@tonic-gate */
24467c478bdstevel@tonic-gate/*ARGSUSED*/
24477c478bdstevel@tonic-gateuint32_t
24487c478bdstevel@tonic-gatecs_event(event_t event, uint32_t sn, uint32_t arg)
24497c478bdstevel@tonic-gate{
24507c478bdstevel@tonic-gate	client_t *client;
24517c478bdstevel@tonic-gate	cs_socket_t *sp;
24527c478bdstevel@tonic-gate	client_types_t *ct;
24537c478bdstevel@tonic-gate	uint32_t ret = CS_SUCCESS;
24547c478bdstevel@tonic-gate
24557c478bdstevel@tonic-gate	/*
24567c478bdstevel@tonic-gate	 * Handle special SS<->CS events
24577c478bdstevel@tonic-gate	 */
24587c478bdstevel@tonic-gate	switch (event) {
24597c478bdstevel@tonic-gate	    case PCE_SS_INIT_STATE:
24607c478bdstevel@tonic-gate		mutex_enter(&cs_globals.global_lock);
24617c478bdstevel@tonic-gate		switch (sn) {
24627c478bdstevel@tonic-gate		    case PCE_SS_STATE_INIT:
24637c478bdstevel@tonic-gate			if ((ret = cs_ss_init()) == CS_SUCCESS)
24647c478bdstevel@tonic-gate			    cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
24657c478bdstevel@tonic-gate			break;
24667c478bdstevel@tonic-gate		    case PCE_SS_STATE_DEINIT:
24677c478bdstevel@tonic-gate			cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
24687c478bdstevel@tonic-gate			break;
24697c478bdstevel@tonic-gate		    default:
24707c478bdstevel@tonic-gate			ret = CS_UNSUPPORTED_FUNCTION;
24717c478bdstevel@tonic-gate			cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
24727c478bdstevel@tonic-gate						"directive: 0x%x\n", sn);
24737c478bdstevel@tonic-gate			break;
24747c478bdstevel@tonic-gate		} /* switch (sn) */
24757c478bdstevel@tonic-gate		mutex_exit(&cs_globals.global_lock);
24767c478bdstevel@tonic-gate		return (ret);
24777c478bdstevel@tonic-gate	    case PCE_ADD_SOCKET:
24787c478bdstevel@tonic-gate		return (cs_add_socket(sn));
24797c478bdstevel@tonic-gate	    case PCE_DROP_SOCKET:
24807c478bdstevel@tonic-gate		return (cs_drop_socket(sn));
24817c478bdstevel@tonic-gate	} /* switch (event) */
24827c478bdstevel@tonic-gate
24837c478bdstevel@tonic-gate	if ((sp = cs_get_sp(sn)) == NULL)
24847c478bdstevel@tonic-gate	    return (CS_BAD_SOCKET);
24857c478bdstevel@tonic-gate
24867c478bdstevel@tonic-gate	/*
24877c478bdstevel@tonic-gate	 * Check to see if CS wants to unload - we do this since it's possible
24887c478bdstevel@tonic-gate	 *	to disable certain sockets.  Do NOT acquire any locks yet.
24897c478bdstevel@tonic-gate	 */
24907c478bdstevel@tonic-gate	if (sp->flags & SOCKET_UNLOAD_MODULE) {
24917c478bdstevel@tonic-gate	    if (event == PCE_CARD_INSERT)
24927c478bdstevel@tonic-gate		cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
24937c478bdstevel@tonic-gate							"remove card\n", sn);
24947c478bdstevel@tonic-gate	    return (CS_SUCCESS);
24957c478bdstevel@tonic-gate	}
24967c478bdstevel@tonic-gate
24977c478bdstevel@tonic-gate	mutex_enter(&sp->lock);
24987c478bdstevel@tonic-gate
24997c478bdstevel@tonic-gate#ifdef	CS_DEBUG
25007c478bdstevel@tonic-gate	if (cs_debug > 1) {
25017c478bdstevel@tonic-gate	    event2text_t event2text;
25027c478bdstevel@tonic-gate
25037c478bdstevel@tonic-gate	    event2text.event = event;
25047c478bdstevel@tonic-gate	    (void) cs_event2text(&event2text, 0);
25057c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
25067c478bdstevel@tonic-gate				event2text.text, (int)event, (int)sn);
25077c478bdstevel@tonic-gate	}
25087c478bdstevel@tonic-gate#endif
25097c478bdstevel@tonic-gate
25107c478bdstevel@tonic-gate	/*
25117c478bdstevel@tonic-gate	 * Convert SS events to CS events; handle the PRR if necessary.
25127c478bdstevel@tonic-gate	 */
25137c478bdstevel@tonic-gate	sp->events |= ss_to_cs_events(sp, event);
25147c478bdstevel@tonic-gate
25157c478bdstevel@tonic-gate	/*
25167c478bdstevel@tonic-gate	 * We want to maintain the required event dispatching order as
25177c478bdstevel@tonic-gate	 *	specified in the PCMCIA spec, so we cycle through all
25187c478bdstevel@tonic-gate	 *	clients on this socket to make sure that they are
25197c478bdstevel@tonic-gate	 *	notified in the correct order of any high-priority
25207c478bdstevel@tonic-gate	 *	events.
25217c478bdstevel@tonic-gate	 */
25227c478bdstevel@tonic-gate	ct = &client_types[0];
25237c478bdstevel@tonic-gate	while (ct) {
25247c478bdstevel@tonic-gate	/*
25257c478bdstevel@tonic-gate	 * Point to the head of the client list for this socket, and go
25267c478bdstevel@tonic-gate	 *	through each client to set up the client events as well as
25277c478bdstevel@tonic-gate	 *	call the client's event handler directly if we have a high
25287c478bdstevel@tonic-gate	 *	priority event that we need to tell the client about.
25297c478bdstevel@tonic-gate	 */
25307c478bdstevel@tonic-gate	    client = sp->client_list;
25317c478bdstevel@tonic-gate
25327c478bdstevel@tonic-gate	    if (ct->order & CLIENT_EVENTS_LIFO) {
25337c478bdstevel@tonic-gate		client_t *clp = NULL;
25347c478bdstevel@tonic-gate
25357c478bdstevel@tonic-gate		while (client) {
25367c478bdstevel@tonic-gate		    clp = client;
25377c478bdstevel@tonic-gate		    client = client->next;
25387c478bdstevel@tonic-gate		}
25397c478bdstevel@tonic-gate		client = clp;
25407c478bdstevel@tonic-gate	    }
25417c478bdstevel@tonic-gate
25427c478bdstevel@tonic-gate	    while (client) {
25437c478bdstevel@tonic-gate		client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
25447c478bdstevel@tonic-gate				    (client->event_mask | client->global_mask));
25457c478bdstevel@tonic-gate		if (client->flags & ct->type) {
25467c478bdstevel@tonic-gate#ifdef	CS_DEBUG
25477c478bdstevel@tonic-gate		    if (cs_debug > 1) {
25487c478bdstevel@tonic-gate			cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
25497c478bdstevel@tonic-gate						"events 0x%x flags 0x%x\n",
25507c478bdstevel@tonic-gate						sn, client->driver_name,
25517c478bdstevel@tonic-gate						(int)client->events,
25527c478bdstevel@tonic-gate						(int)client->flags);
25537c478bdstevel@tonic-gate		    }
25547c478bdstevel@tonic-gate#endif
25557c478bdstevel@tonic-gate
25567c478bdstevel@tonic-gate		/*
25577c478bdstevel@tonic-gate		 * Handle the suspend and card removal events
25587c478bdstevel@tonic-gate		 *	specially here so that the client can receive
25597c478bdstevel@tonic-gate		 *	these events at high-priority.
25607c478bdstevel@tonic-gate		 */
25617c478bdstevel@tonic-gate		    if (client->events & CS_EVENT_PM_SUSPEND) {
25627c478bdstevel@tonic-gate			if (client->flags & CLIENT_CARD_INSERTED) {
25637c478bdstevel@tonic-gate			    CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
25647c478bdstevel@tonic-gate							CS_EVENT_PRI_HIGH);
25657c478bdstevel@tonic-gate			} /* if (CLIENT_CARD_INSERTED) */
25667c478bdstevel@tonic-gate			client->events &= ~CS_EVENT_PM_SUSPEND;
25677c478bdstevel@tonic-gate		    } /* if (CS_EVENT_PM_SUSPEND) */
25687c478bdstevel@tonic-gate
25697c478bdstevel@tonic-gate		    if (client->events & CS_EVENT_CARD_REMOVAL) {
25707c478bdstevel@tonic-gate			if (client->flags & CLIENT_CARD_INSERTED) {
25717c478bdstevel@tonic-gate			    client->flags &= ~(CLIENT_CARD_INSERTED |
25727c478bdstevel@tonic-gate						CLIENT_SENT_INSERTION);
25737c478bdstevel@tonic-gate			    CLIENT_EVENT_CALLBACK(client,
25747c478bdstevel@tonic-gate							CS_EVENT_CARD_REMOVAL,
25757c478bdstevel@tonic-gate							CS_EVENT_PRI_HIGH);
25767c478bdstevel@tonic-gate			/*
25777c478bdstevel@tonic-gate			 * Check to see if the client wants low priority
25787c478bdstevel@tonic-gate			 *	removal events as well.
25797c478bdstevel@tonic-gate			 */
25807c478bdstevel@tonic-gate			    if ((client->event_mask | client->global_mask) &
25817c478bdstevel@tonic-gate						CS_EVENT_CARD_REMOVAL_LOWP) {
25827c478bdstevel@tonic-gate				client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
25837c478bdstevel@tonic-gate			    }
25847c478bdstevel@tonic-gate			} /* if (CLIENT_CARD_INSERTED) */
25857c478bdstevel@tonic-gate			client->events &= ~CS_EVENT_CARD_REMOVAL;
25867c478bdstevel@tonic-gate		    } /* if (CS_EVENT_CARD_REMOVAL) */
25877c478bdstevel@tonic-gate
25887c478bdstevel@tonic-gate		} /* if (ct->type) */
25897c478bdstevel@tonic-gate		if (ct->order & CLIENT_EVENTS_LIFO) {
25907c478bdstevel@tonic-gate		    client = client->prev;
25917c478bdstevel@tonic-gate		} else {
25927c478bdstevel@tonic-gate		    client = client->next;
25937c478bdstevel@tonic-gate		}
25947c478bdstevel@tonic-gate	    } /* while (client) */
25957c478bdstevel@tonic-gate
25967c478bdstevel@tonic-gate	    ct = ct->next;
25977c478bdstevel@tonic-gate	} /* while (ct) */
25987c478bdstevel@tonic-gate
25997c478bdstevel@tonic-gate	/*
26007c478bdstevel@tonic-gate	 * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
26017c478bdstevel@tonic-gate	 *	handler will wakeup this socket's event thread.
26027c478bdstevel@tonic-gate	 */
26037c478bdstevel@tonic-gate	if (sp->events)
26047c478bdstevel@tonic-gate	    sp->flags |= SOCKET_NEEDS_THREAD;
26057c478bdstevel@tonic-gate
26067c478bdstevel@tonic-gate	/*
26077c478bdstevel@tonic-gate	 * Fire off a soft interrupt that will cause the socket thread
26087c478bdstevel@tonic-gate	 *	to be woken up and any remaining events to be sent to
26097c478bdstevel@tonic-gate	 *	the clients on this socket.
26107c478bdstevel@tonic-gate	 */
26117c478bdstevel@tonic-gate	if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
26127c478bdstevel@tonic-gate			!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
26137c478bdstevel@tonic-gate	    ddi_trigger_softintr(sp->softint_id);
26147c478bdstevel@tonic-gate
26157c478bdstevel@tonic-gate	mutex_exit(&sp->lock);
26167c478bdstevel@tonic-gate
26177c478bdstevel@tonic-gate	return (CS_SUCCESS);
26187c478bdstevel@tonic-gate}
26197c478bdstevel@tonic-gate
26207c478bdstevel@tonic-gate/*
26217c478bdstevel@tonic-gate * cs_card_insertion - handle card insertion and card ready events
26227c478bdstevel@tonic-gate *
26237c478bdstevel@tonic-gate * We read the CIS, if present, and store it away, then tell SS that
26247c478bdstevel@tonic-gate *	we have read the CIS and it's ready to be parsed.  Since card
26257c478bdstevel@tonic-gate *	insertion and card ready events are pretty closely intertwined,
26267c478bdstevel@tonic-gate *	we handle both here.  For card ready events that are not the
26277c478bdstevel@tonic-gate *	result of a card insertion event, we expect that the caller has
26287c478bdstevel@tonic-gate *	already done the appropriate processing and that we will not be
26297c478bdstevel@tonic-gate *	called unless we received a card ready event right after a card
26307c478bdstevel@tonic-gate *	insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
26317c478bdstevel@tonic-gate *	sp->thread_state was set or if we get a CARD_READY event right
26327c478bdstevel@tonic-gate *	after a CARD_INSERTION event.
26337c478bdstevel@tonic-gate *
26347c478bdstevel@tonic-gate *    calling:	sp - pointer to socket structure
26357c478bdstevel@tonic-gate *		event - event to handle, one of:
26367c478bdstevel@tonic-gate *				CS_EVENT_CARD_INSERTION
26377c478bdstevel@tonic-gate *				CS_EVENT_CARD_READY
26387c478bdstevel@tonic-gate *				CS_EVENT_SS_UPDATED
26397c478bdstevel@tonic-gate */
26407c478bdstevel@tonic-gatestatic int
26417c478bdstevel@tonic-gatecs_card_insertion(cs_socket_t *sp, event_t event)
26427c478bdstevel@tonic-gate{
26437c478bdstevel@tonic-gate	int ret;
26447c478bdstevel@tonic-gate
26457c478bdstevel@tonic-gate	/*
26467c478bdstevel@tonic-gate	 * Since we're only called while waiting for the card insertion
26477c478bdstevel@tonic-gate	 *	and card ready sequence to occur, we may have a pending
26487c478bdstevel@tonic-gate	 *	card ready timer that hasn't gone off yet if we got a
26497c478bdstevel@tonic-gate	 *	real card ready event.
26507c478bdstevel@tonic-gate	 */
26517c478bdstevel@tonic-gate	UNTIMEOUT(sp->rdybsy_tmo_id);
26527c478bdstevel@tonic-gate
26537c478bdstevel@tonic-gate#ifdef	CS_DEBUG
26547c478bdstevel@tonic-gate	if (cs_debug > 1) {
26557c478bdstevel@tonic-gate	    cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
26567c478bdstevel@tonic-gate						(int)event, sp->socket_num);
26577c478bdstevel@tonic-gate	}
26587c478bdstevel@tonic-gate#endif
26597c478bdstevel@tonic-gate
26607c478bdstevel@tonic-gate	/*
26617c478bdstevel@tonic-gate	 * Handle card insertion processing
26627c478bdstevel@tonic-gate	 */
26637c478bdstevel@tonic-gate	if (event & CS_EVENT_CARD_INSERTION) {
26647c478bdstevel@tonic-gate	    set_socket_t set_socket;
26657c478bdstevel@tonic-gate	    get_ss_status_t gs;
26667c478bdstevel@tonic-gate
26677c478bdstevel@tonic-gate	/*
26687c478bdstevel@tonic-gate	 * Check to be sure that we have a valid CIS window
26697c478bdstevel@tonic-gate	 */
26707c478bdstevel@tonic-gate	    if (!SOCKET_HAS_CIS_WINDOW(sp)) {
26717c478bdstevel@tonic-gate		cmn_err(CE_CONT,
26727c478bdstevel@tonic-gate			"cs_card_insertion: socket %d has no "
26737c478bdstevel@tonic-gate							"CIS window\n",
26747c478bdstevel@tonic-gate				sp->socket_num);
26757c478bdstevel@tonic-gate		return (CS_GENERAL_FAILURE);
26767c478bdstevel@tonic-gate	    }
26777c478bdstevel@tonic-gate
26787c478bdstevel@tonic-gate	/*
26797c478bdstevel@tonic-gate	 * Apply power to the socket, enable card detect and card ready
26807c478bdstevel@tonic-gate	 *	events, then reset the socket.
26817c478bdstevel@tonic-gate	 */
26827c478bdstevel@tonic-gate	    mutex_enter(&sp->lock);
26837c478bdstevel@tonic-gate	    sp->event_mask =   (CS_EVENT_CARD_REMOVAL   |
26847c478bdstevel@tonic-gate				CS_EVENT_CARD_READY);
26857c478bdstevel@tonic-gate	    mutex_exit(&sp->lock);
26867c478bdstevel@tonic-gate	    set_socket.socket = sp->socket_num;
26877c478bdstevel@tonic-gate	    set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
26887c478bdstevel@tonic-gate	    set_socket.IREQRouting = 0;
26897c478bdstevel@tonic-gate	    set_socket.IFType = IF_MEMORY;
26907c478bdstevel@tonic-gate	    set_socket.CtlInd = 0; /* turn off controls and indicators */
26917c478bdstevel@tonic-gate	    set_socket.State = (unsigned)~0;	/* clear latched state bits */
26927c478bdstevel@tonic-gate
26937c478bdstevel@tonic-gate	    (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
26947c478bdstevel@tonic-gate						&set_socket.VccLevel);
26957c478bdstevel@tonic-gate	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
26967c478bdstevel@tonic-gate						&set_socket.Vpp1Level);
26977c478bdstevel@tonic-gate	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
26987c478bdstevel@tonic-gate						&set_socket.Vpp2Level);
26997c478bdstevel@tonic-gate
27007c478bdstevel@tonic-gate	    if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
27017c478bdstevel@tonic-gate		cmn_err(CE_CONT,
27027c478bdstevel@tonic-gate		    "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
27037c478bdstevel@tonic-gate				sp->socket_num, ret);
27047c478bdstevel@tonic-gate		return (ret);
27057c478bdstevel@tonic-gate	    }
27067c478bdstevel@tonic-gate
27077c478bdstevel@tonic-gate	/*
27087c478bdstevel@tonic-gate	 * Clear the ready and ready_timeout events since they are now
27097c478bdstevel@tonic-gate	 *	bogus since we're about to reset the socket.
27107c478bdstevel@tonic-gate	 * XXX - should these be cleared right after the RESET??
27117c478bdstevel@tonic-gate	 */
27127c478bdstevel@tonic-gate	    mutex_enter(&sp->lock);
27137c478bdstevel@tonic-gate
27147c478bdstevel@tonic-gate	    sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
27157c478bdstevel@tonic-gate	    mutex_exit(&sp->lock);
27167c478bdstevel@tonic-gate
27177c478bdstevel@tonic-gate	    SocketServices(SS_ResetSocket, sp->socket_num,
27187c478bdstevel@tonic-gate						RESET_MODE_CARD_ONLY);
27197c478bdstevel@tonic-gate
27207c478bdstevel@tonic-gate	/*
27217c478bdstevel@tonic-gate	 * We are required by the PCMCIA spec to wait some number of
27227c478bdstevel@tonic-gate	 *	milliseconds after reset before we access the card, so
27237c478bdstevel@tonic-gate	 *	we set up a timer here that will wake us up and allow us
27247c478bdstevel@tonic-gate	 *	to continue with our card initialization.
27257c478bdstevel@tonic-gate	 */
27267c478bdstevel@tonic-gate	    mutex_enter(&sp->lock);
27277c478bdstevel@tonic-gate	    sp->thread_state |= SOCKET_RESET_TIMER;
27287c478bdstevel@tonic-gate	    (void) timeout(cs_ready_timeout, sp,
27297c478bdstevel@tonic-gate		drv_usectohz(cs_reset_timeout_time * 1000));
27307c478bdstevel@tonic-gate	    cv_wait(&sp->reset_cv, &sp->lock);
27317c478bdstevel@tonic-gate	    sp->thread_state &= ~SOCKET_RESET_TIMER;
27327c478bdstevel@tonic-gate	    mutex_exit(&sp->lock);
27337c478bdstevel@tonic-gate
27347c478bdstevel@tonic-gate#ifdef	CS_DEBUG
27357c478bdstevel@tonic-gate	    if (cs_debug > 2) {
27367c478bdstevel@tonic-gate		cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
27377c478bdstevel@tonic-gate		    "for %d mS sp->events 0x%x\n",
27387c478bdstevel@tonic-gate		    sp->socket_num, cs_reset_timeout_time, (int)sp->events);
27397c478bdstevel@tonic-gate	    }
27407c478bdstevel@tonic-gate#endif
27417c478bdstevel@tonic-gate
27427c478bdstevel@tonic-gate	/*
27437c478bdstevel@tonic-gate	 * If we have a pending CS_EVENT_CARD_REMOVAL event it
27447c478bdstevel@tonic-gate	 *	means that we likely got CD line bounce on the
27457c478bdstevel@tonic-gate	 *	insertion, so terminate this processing.
27467c478bdstevel@tonic-gate	 */
27477c478bdstevel@tonic-gate	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
27487c478bdstevel@tonic-gate#ifdef	CS_DEBUG
27497c478bdstevel@tonic-gate		if (cs_debug > 0) {
27507c478bdstevel@tonic-gate		    cmn_err(CE_CONT, "cs_card_insertion: socket %d "
27517c478bdstevel@tonic-gate						"CS_EVENT_CARD_REMOVAL event "
27527c478bdstevel@tonic-gate						"terminating insertion "
27537c478bdstevel@tonic-gate						"processing\n",
27547c478bdstevel@tonic-gate							sp->socket_num);
27557c478bdstevel@tonic-gate		}
27567c478bdstevel@tonic-gate#endif
27577c478bdstevel@tonic-gate	    return (CS_SUCCESS);
27587c478bdstevel@tonic-gate	    } /* if (CS_EVENT_CARD_REMOVAL) */
27597c478bdstevel@tonic-gate
2760