10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*1278Shx147065 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * PCMCIA Card Services
310Sstevel@tonic-gate * The PCMCIA Card Services is a loadable module which
320Sstevel@tonic-gate * presents the Card Services interface to client device
330Sstevel@tonic-gate * drivers.
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * Card Services uses Socket Services-like calls into the
360Sstevel@tonic-gate * PCMCIA nexus driver to manipulate socket and adapter
370Sstevel@tonic-gate * resources.
380Sstevel@tonic-gate *
390Sstevel@tonic-gate * Note that a bunch of comments are not indented correctly with the
400Sstevel@tonic-gate * code that they are commenting on. This is because cstyle is
410Sstevel@tonic-gate * is inflexible concerning 4-column indenting.
420Sstevel@tonic-gate */
430Sstevel@tonic-gate
440Sstevel@tonic-gate #if defined(DEBUG)
450Sstevel@tonic-gate #define CS_DEBUG
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate
480Sstevel@tonic-gate #include <sys/types.h>
490Sstevel@tonic-gate #include <sys/systm.h>
500Sstevel@tonic-gate #include <sys/user.h>
510Sstevel@tonic-gate #include <sys/buf.h>
520Sstevel@tonic-gate #include <sys/file.h>
530Sstevel@tonic-gate #include <sys/uio.h>
540Sstevel@tonic-gate #include <sys/conf.h>
550Sstevel@tonic-gate #include <sys/stat.h>
560Sstevel@tonic-gate #include <sys/autoconf.h>
570Sstevel@tonic-gate #include <sys/vtoc.h>
580Sstevel@tonic-gate #include <sys/dkio.h>
590Sstevel@tonic-gate #include <sys/ddi.h>
600Sstevel@tonic-gate #include <sys/sunddi.h>
610Sstevel@tonic-gate #include <sys/debug.h>
620Sstevel@tonic-gate #include <sys/varargs.h>
630Sstevel@tonic-gate #include <sys/var.h>
640Sstevel@tonic-gate #include <sys/proc.h>
650Sstevel@tonic-gate #include <sys/thread.h>
660Sstevel@tonic-gate #include <sys/utsname.h>
670Sstevel@tonic-gate #include <sys/vtrace.h>
680Sstevel@tonic-gate #include <sys/kstat.h>
690Sstevel@tonic-gate #include <sys/kmem.h>
700Sstevel@tonic-gate #include <sys/modctl.h>
710Sstevel@tonic-gate #include <sys/kobj.h>
720Sstevel@tonic-gate #include <sys/callb.h>
730Sstevel@tonic-gate #include <sys/time.h>
740Sstevel@tonic-gate
750Sstevel@tonic-gate #include <sys/pctypes.h>
760Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
770Sstevel@tonic-gate #include <sys/pcmcia.h>
780Sstevel@tonic-gate #include <sys/sservice.h>
790Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
800Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
810Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
820Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
830Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h>
840Sstevel@tonic-gate
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * The cs_strings header file is where all of the major strings that
870Sstevel@tonic-gate * Card Services uses are located.
880Sstevel@tonic-gate */
890Sstevel@tonic-gate #include <pcmcia/sys/cs_strings.h>
900Sstevel@tonic-gate
910Sstevel@tonic-gate
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate * Function declarations
940Sstevel@tonic-gate *
950Sstevel@tonic-gate * The main Card Services entry point
960Sstevel@tonic-gate */
970Sstevel@tonic-gate int CardServices(int function, ...);
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * functions and globals used by Socket Services
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * WAS: void *(*cis_parser)(int, ...) = NULL;
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate void *(*cis_parser)(int, ...) = NULL;
1050Sstevel@tonic-gate csfunction_t *cs_socket_services = NULL;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * event handling functions
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate static event_t ss_to_cs_events(cs_socket_t *, event_t);
1110Sstevel@tonic-gate static event_t cs_cse2sbm(event_t);
1120Sstevel@tonic-gate static void cs_event_thread(uint32_t);
1130Sstevel@tonic-gate static int cs_card_insertion(cs_socket_t *, event_t);
1140Sstevel@tonic-gate static int cs_card_removal(cs_socket_t *);
1150Sstevel@tonic-gate static void cs_ss_thread(uint32_t);
1160Sstevel@tonic-gate void cs_ready_timeout(void *);
1170Sstevel@tonic-gate static int cs_card_for_client(client_t *);
1180Sstevel@tonic-gate static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
1190Sstevel@tonic-gate static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
1200Sstevel@tonic-gate static int cs_get_event_mask(client_handle_t, sockevent_t *);
1210Sstevel@tonic-gate static int cs_set_event_mask(client_handle_t, sockevent_t *);
1220Sstevel@tonic-gate static int cs_event2text(event2text_t *, int);
1230Sstevel@tonic-gate static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
1240Sstevel@tonic-gate get_ss_status_t *, int);
1250Sstevel@tonic-gate uint32_t cs_socket_event_softintr(caddr_t);
1260Sstevel@tonic-gate void cs_event_softintr_timeout(void *);
1270Sstevel@tonic-gate static int cs_get_status(client_handle_t, get_status_t *);
1280Sstevel@tonic-gate static uint32_t cs_sbm2cse(uint32_t);
1290Sstevel@tonic-gate static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
1300Sstevel@tonic-gate static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate * SS<->CS communication and internal socket and window handling functions
1340Sstevel@tonic-gate */
1350Sstevel@tonic-gate static uint32_t cs_add_socket(uint32_t);
1360Sstevel@tonic-gate static uint32_t cs_drop_socket(uint32_t);
1370Sstevel@tonic-gate static cs_socket_t *cs_get_sp(uint32_t);
1380Sstevel@tonic-gate static cs_socket_t *cs_find_sp(uint32_t);
1390Sstevel@tonic-gate static cs_window_t *cs_get_wp(uint32_t);
1400Sstevel@tonic-gate static cs_window_t *cs_find_wp(uint32_t);
1410Sstevel@tonic-gate static int cs_add_windows(int, uint32_t);
1420Sstevel@tonic-gate static uint32_t cs_ss_init();
1430Sstevel@tonic-gate static void cs_set_acc_attributes(set_window_t *, uint32_t);
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate * CIS handling functions
1470Sstevel@tonic-gate */
1480Sstevel@tonic-gate cistpl_callout_t *cis_cistpl_std_callout;
1490Sstevel@tonic-gate static int cs_parse_tuple(client_handle_t, tuple_t *, cisparse_t *, cisdata_t);
1500Sstevel@tonic-gate static int cs_get_tuple_data(client_handle_t, tuple_t *);
1510Sstevel@tonic-gate static int cs_validate_cis(client_handle_t, cisinfo_t *);
1520Sstevel@tonic-gate static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
1530Sstevel@tonic-gate static int cs_create_cis(cs_socket_t *);
1540Sstevel@tonic-gate static int cs_destroy_cis(cs_socket_t *);
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate * client handling functions
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate unsigned cs_create_next_client_minor(unsigned, unsigned);
1600Sstevel@tonic-gate static client_t *cs_find_client(client_handle_t, int *);
1610Sstevel@tonic-gate static client_handle_t cs_create_client_handle(unsigned, client_t *);
1620Sstevel@tonic-gate static int cs_destroy_client_handle(client_handle_t);
1630Sstevel@tonic-gate static int cs_register_client(client_handle_t *, client_reg_t *);
1640Sstevel@tonic-gate static int cs_deregister_client(client_handle_t);
1650Sstevel@tonic-gate static int cs_deregister_mtd(client_handle_t);
1660Sstevel@tonic-gate static void cs_clear_superclient_lock(int);
1670Sstevel@tonic-gate static int cs_add_client_to_socket(unsigned, client_handle_t *,
1680Sstevel@tonic-gate client_reg_t *, int);
1690Sstevel@tonic-gate static int cs_get_client_info(client_handle_t, client_info_t *);
1700Sstevel@tonic-gate static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate * window handling functions
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
1760Sstevel@tonic-gate static int cs_release_window(window_handle_t);
1770Sstevel@tonic-gate static int cs_modify_window(window_handle_t, modify_win_t *);
1780Sstevel@tonic-gate static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
1790Sstevel@tonic-gate int);
1800Sstevel@tonic-gate static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
1810Sstevel@tonic-gate static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
1820Sstevel@tonic-gate static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
1830Sstevel@tonic-gate static int cs_valid_window_speed(inquire_window_t *, uint32_t);
1840Sstevel@tonic-gate static window_handle_t cs_create_window_handle(uint32_t);
1850Sstevel@tonic-gate static cs_window_t *cs_find_window(window_handle_t);
1860Sstevel@tonic-gate static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate * IO, IRQ and configuration handling functions
1900Sstevel@tonic-gate */
1910Sstevel@tonic-gate static int cs_request_io(client_handle_t, io_req_t *);
1920Sstevel@tonic-gate static int cs_release_io(client_handle_t, io_req_t *);
1930Sstevel@tonic-gate static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
1940Sstevel@tonic-gate static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
1950Sstevel@tonic-gate uint32_t *, uint32_t, uint32_t);
1960Sstevel@tonic-gate static int cs_request_irq(client_handle_t, irq_req_t *);
1970Sstevel@tonic-gate static int cs_release_irq(client_handle_t, irq_req_t *);
1980Sstevel@tonic-gate static int cs_request_configuration(client_handle_t, config_req_t *);
1990Sstevel@tonic-gate static int cs_release_configuration(client_handle_t, release_config_t *);
2000Sstevel@tonic-gate static int cs_modify_configuration(client_handle_t, modify_config_t *);
2010Sstevel@tonic-gate static int cs_access_configuration_register(client_handle_t,
2020Sstevel@tonic-gate access_config_reg_t *);
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate * RESET and general info functions
2060Sstevel@tonic-gate */
2070Sstevel@tonic-gate static int cs_reset_function(client_handle_t, reset_function_t *);
2080Sstevel@tonic-gate static int cs_get_configuration_info(client_handle_t *,
2090Sstevel@tonic-gate get_configuration_info_t *);
2100Sstevel@tonic-gate static int cs_get_cardservices_info(client_handle_t,
2110Sstevel@tonic-gate get_cardservices_info_t *);
2120Sstevel@tonic-gate static int cs_get_physical_adapter_info(client_handle_t,
2130Sstevel@tonic-gate get_physical_adapter_info_t *);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate * general functions
2170Sstevel@tonic-gate */
2180Sstevel@tonic-gate static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
2190Sstevel@tonic-gate cs_socket_t **, client_t **);
2200Sstevel@tonic-gate static int cs_convert_speed(convert_speed_t *);
2210Sstevel@tonic-gate static int cs_convert_size(convert_size_t *);
2220Sstevel@tonic-gate static char *cs_error2text(int, int);
2230Sstevel@tonic-gate static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
2240Sstevel@tonic-gate static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
2250Sstevel@tonic-gate static int cs_make_device_node(client_handle_t, make_device_node_t *);
2260Sstevel@tonic-gate static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
2270Sstevel@tonic-gate static int cs_ddi_info(cs_ddi_info_t *);
2280Sstevel@tonic-gate static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
2290Sstevel@tonic-gate uint32_t);
2300Sstevel@tonic-gate static int cs_sys_ctl(cs_sys_ctl_t *);
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate * global variables
2340Sstevel@tonic-gate */
2350Sstevel@tonic-gate static int cs_max_client_handles = CS_MAX_CLIENTS;
2360Sstevel@tonic-gate static client_t cs_socket_services_client; /* global SS client */
2370Sstevel@tonic-gate static client_types_t client_types[MAX_CLIENT_TYPES];
2380Sstevel@tonic-gate static cs_globals_t cs_globals;
2390Sstevel@tonic-gate int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
2400Sstevel@tonic-gate int cs_rc1_delay = CS_RC1_DELAY;
2410Sstevel@tonic-gate int cs_rc2_delay = CS_RC2_DELAY;
2420Sstevel@tonic-gate int cs_rq_delay = CS_RQ_DELAY;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate #ifdef CS_DEBUG
2450Sstevel@tonic-gate int cs_debug = 0;
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate * cs_init - Initialize CS internal structures, databases, and state,
2500Sstevel@tonic-gate * and register with SS
2510Sstevel@tonic-gate *
2520Sstevel@tonic-gate * XXX - Need to make sure that if we fail at any point that we free
2530Sstevel@tonic-gate * any resources that we allocated, as well as kill any
2540Sstevel@tonic-gate * threads that may have been started.
2550Sstevel@tonic-gate */
2560Sstevel@tonic-gate int
cs_init()2570Sstevel@tonic-gate cs_init()
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate client_types_t *ct;
2600Sstevel@tonic-gate client_t *client;
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * Initialize the CS global structure
2640Sstevel@tonic-gate */
2650Sstevel@tonic-gate bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
2680Sstevel@tonic-gate mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Set up the global Socket Services client, since we're going to
2740Sstevel@tonic-gate * need it once we register with SS.
2750Sstevel@tonic-gate */
2760Sstevel@tonic-gate client = &cs_socket_services_client;
2770Sstevel@tonic-gate bzero((caddr_t)client, sizeof (client_t));
2780Sstevel@tonic-gate client->client_handle = CS_SS_CLIENT_HANDLE;
2790Sstevel@tonic-gate client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * Setup the client type structure - this is used in the socket event
2830Sstevel@tonic-gate * thread to sequence the delivery of events to all clients on
2840Sstevel@tonic-gate * the socket.
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate ct = &client_types[0];
2870Sstevel@tonic-gate ct->type = INFO_IO_CLIENT;
2880Sstevel@tonic-gate ct->order = CLIENT_EVENTS_LIFO;
2890Sstevel@tonic-gate ct->next = &client_types[1];
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate ct = ct->next;
2920Sstevel@tonic-gate ct->type = INFO_MTD_CLIENT;
2930Sstevel@tonic-gate ct->order = CLIENT_EVENTS_FIFO;
2940Sstevel@tonic-gate ct->next = &client_types[2];
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate ct = ct->next;
2970Sstevel@tonic-gate ct->type = INFO_MEM_CLIENT;
2980Sstevel@tonic-gate ct->order = CLIENT_EVENTS_FIFO;
2990Sstevel@tonic-gate ct->next = NULL;
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate return (CS_SUCCESS);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate * cs_deinit - Deinitialize CS
3060Sstevel@tonic-gate *
3070Sstevel@tonic-gate * This function cleans up any allocated resources, stops any running threads,
3080Sstevel@tonic-gate * destroys any mutexes and condition variables, and finally frees up the
3090Sstevel@tonic-gate * global socket and window structure arrays.
3100Sstevel@tonic-gate */
3110Sstevel@tonic-gate int
cs_deinit()3120Sstevel@tonic-gate cs_deinit()
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate cs_socket_t *sp;
3150Sstevel@tonic-gate int sn, have_clients = 0, have_sockets = 0;
3160Sstevel@tonic-gate cs_register_cardservices_t rcs;
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate #if defined(CS_DEBUG)
3190Sstevel@tonic-gate if (cs_debug > 1)
3200Sstevel@tonic-gate cmn_err(CE_CONT, "CS: cs_deinit\n");
3210Sstevel@tonic-gate #endif
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * Deregister with the Card Services kernel stubs module
3250Sstevel@tonic-gate */
3260Sstevel@tonic-gate rcs.magic = CS_STUBS_MAGIC;
3270Sstevel@tonic-gate rcs.function = CS_ENTRY_DEREGISTER;
3280Sstevel@tonic-gate (void) csx_register_cardservices(&rcs);
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
3320Sstevel@tonic-gate * from registering.
3330Sstevel@tonic-gate */
3340Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
3350Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
3360Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate * Go through each socket and make sure that there are no clients
3400Sstevel@tonic-gate * on any of the sockets. If there are, we can't deinit until
3410Sstevel@tonic-gate * all the clients for every socket are gone.
3420Sstevel@tonic-gate */
3430Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3440Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) {
3450Sstevel@tonic-gate have_sockets++;
3460Sstevel@tonic-gate if (sp->client_list) {
3470Sstevel@tonic-gate cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
3480Sstevel@tonic-gate "socket %d has registered clients\n", sn);
3490Sstevel@tonic-gate have_clients++;
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * We don't allow unload if there are any clients registered
3560Sstevel@tonic-gate * or if there are still sockets that are active.
3570Sstevel@tonic-gate */
3580Sstevel@tonic-gate if ((have_clients > 0) || (have_sockets > 0))
3590Sstevel@tonic-gate return (BAD_FUNCTION);
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate #ifdef XXX
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate * If one or more sockets have been added, we need to deallocate
3640Sstevel@tonic-gate * the resources associated with those sockets.
3650Sstevel@tonic-gate */
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate * First, tell Socket Services that we're leaving, so that we
3690Sstevel@tonic-gate * don't get any more event callbacks.
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate SocketServices(CSUnregister);
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate * Wait for the soft int timer to tell us it's done
3750Sstevel@tonic-gate */
3760Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
3770Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
3780Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
3790Sstevel@tonic-gate UNTIMEOUT(cs_globals.sotfint_tmo);
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Remove the soft interrupt handler.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
3850Sstevel@tonic-gate if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
3860Sstevel@tonic-gate ddi_remove_softintr(cs_globals.softint_id);
3870Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate return (CS_SUCCESS);
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate * Go through each socket and free any resource allocated to that
3950Sstevel@tonic-gate * socket, as well as any mutexs and condition variables.
3960Sstevel@tonic-gate */
3970Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3980Sstevel@tonic-gate set_socket_t set_socket;
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) {
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * untimeout possible pending ready/busy timer
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id);
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4080Sstevel@tonic-gate mutex_enter(&sp->lock);
4090Sstevel@tonic-gate sp->flags = SOCKET_UNLOAD_MODULE;
4100Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
4110Sstevel@tonic-gate sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
4120Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4130Sstevel@tonic-gate mutex_exit(&sp->lock);
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4160Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
4170Sstevel@tonic-gate (void) cs_destroy_cis(sp);
4180Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4190Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate /*
4220Sstevel@tonic-gate * Tell the event handler thread that we want it to exit, then
4230Sstevel@tonic-gate * wait around until it tells us that it has exited.
4240Sstevel@tonic-gate */
4250Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4260Sstevel@tonic-gate mutex_enter(&sp->client_lock);
4270Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
4280Sstevel@tonic-gate sp->thread_state = SOCKET_THREAD_EXIT;
4290Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
4300Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4330Sstevel@tonic-gate mutex_exit(&sp->client_lock);
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * Tell the SS work thread that we want it to exit, then
4370Sstevel@tonic-gate * wait around until it tells us that it has exited.
4380Sstevel@tonic-gate */
4390Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4400Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock);
4410Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
4420Sstevel@tonic-gate sp->ss_thread_state = SOCKET_THREAD_EXIT;
4430Sstevel@tonic-gate cv_broadcast(&sp->ss_thread_cv);
4440Sstevel@tonic-gate cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4480Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * Free the mutexii and condition variables that we used.
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
4540Sstevel@tonic-gate mutex_destroy(&sp->lock);
4550Sstevel@tonic-gate mutex_destroy(&sp->client_lock);
4560Sstevel@tonic-gate mutex_destroy(&sp->cis_lock);
4570Sstevel@tonic-gate mutex_destroy(&sp->ss_thread_lock);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_CV) {
4610Sstevel@tonic-gate cv_destroy(&sp->thread_cv);
4620Sstevel@tonic-gate cv_destroy(&sp->caller_cv);
4630Sstevel@tonic-gate cv_destroy(&sp->reset_cv);
4640Sstevel@tonic-gate cv_destroy(&sp->ss_thread_cv);
4650Sstevel@tonic-gate cv_destroy(&sp->ss_caller_cv);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * Free the memory-mapped IO structure if we allocated one.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate if (sp->io_mmap_window)
4730Sstevel@tonic-gate kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
4740Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * Return the socket to memory-only mode and turn off the
4780Sstevel@tonic-gate * socket power.
4790Sstevel@tonic-gate */
4800Sstevel@tonic-gate sp->event_mask = 0;
4810Sstevel@tonic-gate set_socket.socket = sp->socket_num;
4820Sstevel@tonic-gate set_socket.SCIntMask = 0;
4830Sstevel@tonic-gate set_socket.IREQRouting = 0;
4840Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
4850Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */
4860Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
4890Sstevel@tonic-gate &set_socket.VccLevel);
4900Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
4910Sstevel@tonic-gate &set_socket.Vpp1Level);
4920Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
4930Sstevel@tonic-gate &set_socket.Vpp2Level);
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * If we fail this call, there's not much we can do, so
4970Sstevel@tonic-gate * just continue with the resource deallocation.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate if ((ret =
5000Sstevel@tonic-gate SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
5010Sstevel@tonic-gate cmn_err(CE_CONT,
5020Sstevel@tonic-gate "cs_deinit: socket %d SS_SetSocket failure %d\n",
5030Sstevel@tonic-gate sp->socket_num, ret);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate } /* cs_get_sp */
5060Sstevel@tonic-gate } /* for (sn) */
5070Sstevel@tonic-gate #endif /* XXX */
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate * Destroy the global mutexii.
5110Sstevel@tonic-gate */
5120Sstevel@tonic-gate mutex_destroy(&cs_globals.global_lock);
5130Sstevel@tonic-gate mutex_destroy(&cs_globals.window_lock);
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate #ifdef XXX
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate * Free the global "super-client" structure
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate if (cs_globals.sclient_list)
5200Sstevel@tonic-gate kmem_free(cs_globals.sclient_list,
5210Sstevel@tonic-gate (cs_globals.num_sockets * sizeof (struct sclient_list_t)));
5220Sstevel@tonic-gate cs_globals.sclient_list = NULL;
5230Sstevel@tonic-gate #endif /* XXX */
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate return (CS_SUCCESS);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate * ==== drip, drip, drip - the Card Services waterfall :-) ====
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate * CardServices - general Card Services entry point for CS clients
5340Sstevel@tonic-gate * and Socket Services; the address of this
5350Sstevel@tonic-gate * function is handed to SS via the CSRegister
5360Sstevel@tonic-gate * SS call
5370Sstevel@tonic-gate */
5380Sstevel@tonic-gate int
CardServices(int function,...)5390Sstevel@tonic-gate CardServices(int function, ...)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate va_list arglist;
5420Sstevel@tonic-gate int retcode = CS_UNSUPPORTED_FUNCTION;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate cs_socket_t *socp;
5450Sstevel@tonic-gate uint32_t *offp;
5460Sstevel@tonic-gate acc_handle_t *hp;
5470Sstevel@tonic-gate client_handle_t ch;
5480Sstevel@tonic-gate client_handle_t *chp;
5490Sstevel@tonic-gate window_handle_t wh;
5500Sstevel@tonic-gate window_handle_t *whp;
5510Sstevel@tonic-gate tuple_t *tuple;
5520Sstevel@tonic-gate cisparse_t *cisparse;
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate #ifdef CS_DEBUG
5550Sstevel@tonic-gate if (cs_debug > 127) {
5560Sstevel@tonic-gate cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
5570Sstevel@tonic-gate cs_error2text(function, CSFUN2TEXT_FUNCTION),
5580Sstevel@tonic-gate function);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate #endif
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate va_start(arglist, function);
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate * Here's the Card Services waterfall
5660Sstevel@tonic-gate */
5670Sstevel@tonic-gate switch (function) {
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate * We got here as a result of the CIS module calling us
5700Sstevel@tonic-gate * in response to cs_ss_init() calling the CIS module
5710Sstevel@tonic-gate * at CIS_PARSER(CISP_CIS_SETUP, ...)
5720Sstevel@tonic-gate */
5730Sstevel@tonic-gate case CISRegister: {
5740Sstevel@tonic-gate cisregister_t *cisr;
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate cisr = va_arg(arglist, cisregister_t *);
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate if (cisr->cis_magic != PCCS_MAGIC ||
5790Sstevel@tonic-gate cisr->cis_version != PCCS_VERSION) {
5800Sstevel@tonic-gate cmn_err(CE_WARN,
5810Sstevel@tonic-gate "CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
5820Sstevel@tonic-gate (long)cisr->cis_magic,
5830Sstevel@tonic-gate (long)cisr->cis_version,
5840Sstevel@tonic-gate (long)cisr->cis_parser,
5850Sstevel@tonic-gate (long)cisr->cistpl_std_callout);
5860Sstevel@tonic-gate retcode = CS_BAD_ARGS;
5870Sstevel@tonic-gate } else {
5880Sstevel@tonic-gate /*
5890Sstevel@tonic-gate * Replace the CIS Parser entry point if
5900Sstevel@tonic-gate * necessary.
5910Sstevel@tonic-gate */
5920Sstevel@tonic-gate if (cisr->cis_parser != NULL)
5930Sstevel@tonic-gate cis_parser = cisr->cis_parser;
5940Sstevel@tonic-gate cis_cistpl_std_callout = cisr->cistpl_std_callout;
5950Sstevel@tonic-gate retcode = CS_SUCCESS;
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate break;
5990Sstevel@tonic-gate case CISUnregister: /* XXX - should we do some more checking */
6000Sstevel@tonic-gate /* XXX - need to protect this by a mutex */
6010Sstevel@tonic-gate cis_parser = NULL;
6020Sstevel@tonic-gate cis_cistpl_std_callout = NULL;
6030Sstevel@tonic-gate retcode = CS_SUCCESS;
6040Sstevel@tonic-gate break;
6050Sstevel@tonic-gate case InitCISWindow:
6060Sstevel@tonic-gate socp = va_arg(arglist, cs_socket_t *);
6070Sstevel@tonic-gate offp = va_arg(arglist, uint32_t *);
6080Sstevel@tonic-gate hp = va_arg(arglist, acc_handle_t *);
6090Sstevel@tonic-gate retcode = cs_init_cis_window(socp, offp, hp,
6100Sstevel@tonic-gate va_arg(arglist, uint32_t));
6110Sstevel@tonic-gate break;
6120Sstevel@tonic-gate case RegisterClient:
6130Sstevel@tonic-gate chp = va_arg(arglist, client_handle_t *),
6140Sstevel@tonic-gate retcode = cs_register_client(chp,
6150Sstevel@tonic-gate va_arg(arglist, client_reg_t *));
6160Sstevel@tonic-gate break;
6170Sstevel@tonic-gate case DeregisterClient:
6180Sstevel@tonic-gate retcode = cs_deregister_client(
6190Sstevel@tonic-gate va_arg(arglist, client_handle_t));
6200Sstevel@tonic-gate break;
6210Sstevel@tonic-gate case GetStatus:
6220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6230Sstevel@tonic-gate retcode = cs_get_status(ch,
6240Sstevel@tonic-gate va_arg(arglist, get_status_t *));
6250Sstevel@tonic-gate break;
6260Sstevel@tonic-gate case ResetFunction:
6270Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6280Sstevel@tonic-gate retcode = cs_reset_function(ch,
6290Sstevel@tonic-gate va_arg(arglist, reset_function_t *));
6300Sstevel@tonic-gate break;
6310Sstevel@tonic-gate case SetEventMask:
6320Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6330Sstevel@tonic-gate retcode = cs_set_event_mask(ch,
6340Sstevel@tonic-gate va_arg(arglist, sockevent_t *));
6350Sstevel@tonic-gate break;
6360Sstevel@tonic-gate case GetEventMask:
6370Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6380Sstevel@tonic-gate retcode = cs_get_event_mask(ch,
6390Sstevel@tonic-gate va_arg(arglist, sockevent_t *));
6400Sstevel@tonic-gate break;
6410Sstevel@tonic-gate case RequestIO:
6420Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6430Sstevel@tonic-gate retcode = cs_request_io(ch,
6440Sstevel@tonic-gate va_arg(arglist, io_req_t *));
6450Sstevel@tonic-gate break;
6460Sstevel@tonic-gate case ReleaseIO:
6470Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6480Sstevel@tonic-gate retcode = cs_release_io(ch,
6490Sstevel@tonic-gate va_arg(arglist, io_req_t *));
6500Sstevel@tonic-gate break;
6510Sstevel@tonic-gate case RequestIRQ:
6520Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6530Sstevel@tonic-gate retcode = cs_request_irq(ch,
6540Sstevel@tonic-gate va_arg(arglist, irq_req_t *));
6550Sstevel@tonic-gate break;
6560Sstevel@tonic-gate case ReleaseIRQ:
6570Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6580Sstevel@tonic-gate retcode = cs_release_irq(ch,
6590Sstevel@tonic-gate va_arg(arglist, irq_req_t *));
6600Sstevel@tonic-gate break;
6610Sstevel@tonic-gate case RequestWindow:
6620Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6630Sstevel@tonic-gate whp = va_arg(arglist, window_handle_t *);
6640Sstevel@tonic-gate retcode = cs_request_window(ch, whp,
6650Sstevel@tonic-gate va_arg(arglist, win_req_t *));
6660Sstevel@tonic-gate break;
6670Sstevel@tonic-gate case ReleaseWindow:
6680Sstevel@tonic-gate retcode = cs_release_window(
6690Sstevel@tonic-gate va_arg(arglist, window_handle_t));
6700Sstevel@tonic-gate break;
6710Sstevel@tonic-gate case ModifyWindow:
6720Sstevel@tonic-gate wh = va_arg(arglist, window_handle_t);
6730Sstevel@tonic-gate retcode = cs_modify_window(wh,
6740Sstevel@tonic-gate va_arg(arglist, modify_win_t *));
6750Sstevel@tonic-gate break;
6760Sstevel@tonic-gate case MapMemPage:
6770Sstevel@tonic-gate wh = va_arg(arglist, window_handle_t);
6780Sstevel@tonic-gate retcode = cs_map_mem_page(wh,
6790Sstevel@tonic-gate va_arg(arglist, map_mem_page_t *));
6800Sstevel@tonic-gate break;
6810Sstevel@tonic-gate case RequestSocketMask:
6820Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6830Sstevel@tonic-gate retcode = cs_request_socket_mask(ch,
6840Sstevel@tonic-gate va_arg(arglist, request_socket_mask_t *));
6850Sstevel@tonic-gate break;
6860Sstevel@tonic-gate case ReleaseSocketMask:
6870Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6880Sstevel@tonic-gate retcode = cs_release_socket_mask(ch,
6890Sstevel@tonic-gate va_arg(arglist, release_socket_mask_t *));
6900Sstevel@tonic-gate break;
6910Sstevel@tonic-gate case RequestConfiguration:
6920Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6930Sstevel@tonic-gate retcode = cs_request_configuration(ch,
6940Sstevel@tonic-gate va_arg(arglist, config_req_t *));
6950Sstevel@tonic-gate break;
6960Sstevel@tonic-gate case GetPhysicalAdapterInfo:
6970Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
6980Sstevel@tonic-gate retcode = cs_get_physical_adapter_info(ch,
6990Sstevel@tonic-gate va_arg(arglist, get_physical_adapter_info_t *));
7000Sstevel@tonic-gate break;
7010Sstevel@tonic-gate case GetCardServicesInfo:
7020Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
7030Sstevel@tonic-gate retcode = cs_get_cardservices_info(ch,
7040Sstevel@tonic-gate va_arg(arglist, get_cardservices_info_t *));
7050Sstevel@tonic-gate break;
7060Sstevel@tonic-gate case GetConfigurationInfo:
7070Sstevel@tonic-gate chp = va_arg(arglist, client_handle_t *);
7080Sstevel@tonic-gate retcode = cs_get_configuration_info(chp,
7090Sstevel@tonic-gate va_arg(arglist, get_configuration_info_t *));
7100Sstevel@tonic-gate break;
7110Sstevel@tonic-gate case ModifyConfiguration:
7120Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
7130Sstevel@tonic-gate retcode = cs_modify_configuration(ch,
7140Sstevel@tonic-gate va_arg(arglist, modify_config_t *));
7150Sstevel@tonic-gate break;
7160Sstevel@tonic-gate case AccessConfigurationRegister:
7170Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
7180Sstevel@tonic-gate retcode = cs_access_configuration_register(ch,
7190Sstevel@tonic-gate va_arg(arglist, access_config_reg_t *));
7200Sstevel@tonic-gate break;
7210Sstevel@tonic-gate case ReleaseConfiguration:
7220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
7230Sstevel@tonic-gate retcode = cs_release_configuration(ch,
7240Sstevel@tonic-gate va_arg(arglist, release_config_t *));
7250Sstevel@tonic-gate break;
7260Sstevel@tonic-gate case OpenMemory:
7270Sstevel@tonic-gate cmn_err(CE_CONT, "CS: OpenMemory\n");
7280Sstevel@tonic-gate break;
7290Sstevel@tonic-gate case ReadMemory:
7300Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReadMemory\n");
7310Sstevel@tonic-gate break;
7320Sstevel@tonic-gate case WriteMemory:
7330Sstevel@tonic-gate cmn_err(CE_CONT, "CS: WriteMemory\n");
7340Sstevel@tonic-gate break;
7350Sstevel@tonic-gate case CopyMemory:
7360Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CopyMemory\n");
7370Sstevel@tonic-gate break;
7380Sstevel@tonic-gate case RegisterEraseQueue:
7390Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
7400Sstevel@tonic-gate break;
7410Sstevel@tonic-gate case CheckEraseQueue:
7420Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
7430Sstevel@tonic-gate break;
7440Sstevel@tonic-gate case DeregisterEraseQueue:
7450Sstevel@tonic-gate cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
7460Sstevel@tonic-gate break;
7470Sstevel@tonic-gate case CloseMemory:
7480Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CloseMemory\n");
7490Sstevel@tonic-gate break;
7500Sstevel@tonic-gate case GetFirstRegion:
7510Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetFirstRegion\n");
7520Sstevel@tonic-gate break;
7530Sstevel@tonic-gate case GetNextRegion:
7540Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetNextRegion\n");
7550Sstevel@tonic-gate break;
7560Sstevel@tonic-gate case GetFirstPartition:
7570Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetFirstPartition\n");
7580Sstevel@tonic-gate break;
7590Sstevel@tonic-gate case GetNextPartition:
7600Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetNextPartition\n");
7610Sstevel@tonic-gate break;
7620Sstevel@tonic-gate case ReturnSSEntry:
7630Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
7640Sstevel@tonic-gate break;
7650Sstevel@tonic-gate case MapLogSocket:
7660Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
7670Sstevel@tonic-gate retcode = cs_map_log_socket(ch,
7680Sstevel@tonic-gate va_arg(arglist, map_log_socket_t *));
7690Sstevel@tonic-gate break;
7700Sstevel@tonic-gate case MapPhySocket:
7710Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapPhySocket\n");
7720Sstevel@tonic-gate break;
7730Sstevel@tonic-gate case MapLogWindow:
7740Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapLogWindow\n");
7750Sstevel@tonic-gate break;
7760Sstevel@tonic-gate case MapPhyWindow:
7770Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapPhyWindow\n");
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate case RegisterMTD:
7800Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterMTD\n");
7810Sstevel@tonic-gate break;
7820Sstevel@tonic-gate case RegisterTimer:
7830Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterTimer\n");
7840Sstevel@tonic-gate break;
7850Sstevel@tonic-gate case SetRegion:
7860Sstevel@tonic-gate cmn_err(CE_CONT, "CS: SetRegion\n");
7870Sstevel@tonic-gate break;
7880Sstevel@tonic-gate case RequestExclusive:
7890Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RequestExclusive\n");
7900Sstevel@tonic-gate break;
7910Sstevel@tonic-gate case ReleaseExclusive:
7920Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
7930Sstevel@tonic-gate break;
7940Sstevel@tonic-gate case GetFirstClient:
7950Sstevel@tonic-gate retcode = cs_get_firstnext_client(
7960Sstevel@tonic-gate va_arg(arglist, get_firstnext_client_t *),
7970Sstevel@tonic-gate CS_GET_FIRST_FLAG);
7980Sstevel@tonic-gate break;
7990Sstevel@tonic-gate case GetNextClient:
8000Sstevel@tonic-gate retcode = cs_get_firstnext_client(
8010Sstevel@tonic-gate va_arg(arglist, get_firstnext_client_t *),
8020Sstevel@tonic-gate CS_GET_NEXT_FLAG);
8030Sstevel@tonic-gate break;
8040Sstevel@tonic-gate case GetClientInfo:
8050Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8060Sstevel@tonic-gate retcode = cs_get_client_info(ch,
8070Sstevel@tonic-gate va_arg(arglist, client_info_t *));
8080Sstevel@tonic-gate break;
8090Sstevel@tonic-gate case AddSocketServices:
8100Sstevel@tonic-gate cmn_err(CE_CONT, "CS: AddSocketServices\n");
8110Sstevel@tonic-gate break;
8120Sstevel@tonic-gate case ReplaceSocketServices:
8130Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
8140Sstevel@tonic-gate break;
8150Sstevel@tonic-gate case VendorSpecific:
8160Sstevel@tonic-gate cmn_err(CE_CONT, "CS: VendorSpecific\n");
8170Sstevel@tonic-gate break;
8180Sstevel@tonic-gate case AdjustResourceInfo:
8190Sstevel@tonic-gate cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
8200Sstevel@tonic-gate break;
8210Sstevel@tonic-gate case ValidateCIS:
8220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8230Sstevel@tonic-gate retcode = cs_validate_cis(ch,
8240Sstevel@tonic-gate va_arg(arglist, cisinfo_t *));
8250Sstevel@tonic-gate break;
8260Sstevel@tonic-gate case GetFirstTuple:
8270Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8280Sstevel@tonic-gate retcode = cs_get_firstnext_tuple(ch,
8290Sstevel@tonic-gate va_arg(arglist, tuple_t *),
8300Sstevel@tonic-gate CS_GET_FIRST_FLAG);
8310Sstevel@tonic-gate break;
8320Sstevel@tonic-gate case GetNextTuple:
8330Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8340Sstevel@tonic-gate retcode = cs_get_firstnext_tuple(ch,
8350Sstevel@tonic-gate va_arg(arglist, tuple_t *),
8360Sstevel@tonic-gate CS_GET_NEXT_FLAG);
8370Sstevel@tonic-gate break;
8380Sstevel@tonic-gate case GetTupleData:
8390Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8400Sstevel@tonic-gate retcode = cs_get_tuple_data(ch,
8410Sstevel@tonic-gate va_arg(arglist, tuple_t *));
8420Sstevel@tonic-gate break;
8430Sstevel@tonic-gate case ParseTuple:
8440Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8450Sstevel@tonic-gate tuple = va_arg(arglist, tuple_t *);
8460Sstevel@tonic-gate cisparse = va_arg(arglist, cisparse_t *);
8470Sstevel@tonic-gate retcode = cs_parse_tuple(ch, tuple, cisparse,
8480Sstevel@tonic-gate va_arg(arglist, uint_t));
8490Sstevel@tonic-gate break;
8500Sstevel@tonic-gate case MakeDeviceNode:
8510Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8520Sstevel@tonic-gate retcode = cs_make_device_node(ch,
8530Sstevel@tonic-gate va_arg(arglist, make_device_node_t *));
8540Sstevel@tonic-gate break;
8550Sstevel@tonic-gate case RemoveDeviceNode:
8560Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t);
8570Sstevel@tonic-gate retcode = cs_remove_device_node(ch,
8580Sstevel@tonic-gate va_arg(arglist, remove_device_node_t *));
8590Sstevel@tonic-gate break;
8600Sstevel@tonic-gate case ConvertSpeed:
8610Sstevel@tonic-gate retcode = cs_convert_speed(
8620Sstevel@tonic-gate va_arg(arglist, convert_speed_t *));
8630Sstevel@tonic-gate break;
8640Sstevel@tonic-gate case ConvertSize:
8650Sstevel@tonic-gate retcode = cs_convert_size(
8660Sstevel@tonic-gate va_arg(arglist, convert_size_t *));
8670Sstevel@tonic-gate break;
8680Sstevel@tonic-gate case Event2Text:
8690Sstevel@tonic-gate retcode = cs_event2text(
8700Sstevel@tonic-gate va_arg(arglist, event2text_t *), 1);
8710Sstevel@tonic-gate break;
8720Sstevel@tonic-gate case Error2Text: {
8730Sstevel@tonic-gate error2text_t *cft;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate cft = va_arg(arglist, error2text_t *);
8760Sstevel@tonic-gate (void) strcpy(cft->text,
8770Sstevel@tonic-gate cs_error2text(cft->item, CSFUN2TEXT_RETURN));
8780Sstevel@tonic-gate retcode = CS_SUCCESS;
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate break;
8810Sstevel@tonic-gate case CS_DDI_Info:
8820Sstevel@tonic-gate retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
8830Sstevel@tonic-gate break;
8840Sstevel@tonic-gate case CS_Sys_Ctl:
8850Sstevel@tonic-gate retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
8860Sstevel@tonic-gate break;
8870Sstevel@tonic-gate default:
8880Sstevel@tonic-gate cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
8890Sstevel@tonic-gate break;
8900Sstevel@tonic-gate } /* switch(function) */
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate va_end(arglist);
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate #ifdef CS_DEBUG
8950Sstevel@tonic-gate if (cs_debug > 127) {
8960Sstevel@tonic-gate cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
8970Sstevel@tonic-gate cs_error2text(retcode, CSFUN2TEXT_RETURN),
8980Sstevel@tonic-gate retcode);
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate #endif
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate return (retcode);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate * ==== tuple and CIS handling section ====
9070Sstevel@tonic-gate */
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * cs_parse_tuple - This function supports the CS ParseTuple function call.
9110Sstevel@tonic-gate *
9120Sstevel@tonic-gate * returns: CS_SUCCESS - if tuple parsed sucessfully
9130Sstevel@tonic-gate * CS_NO_CARD - if no card in socket
9140Sstevel@tonic-gate * CS_BAD_ARGS - if passed CIS list pointer is NULL
9150Sstevel@tonic-gate * CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
9160Sstevel@tonic-gate * CS_BAD_CIS - if generic parser error
9170Sstevel@tonic-gate * CS_NO_CIS - if no CIS for card/function
9180Sstevel@tonic-gate *
9190Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function.
9200Sstevel@tonic-gate */
9210Sstevel@tonic-gate static int
cs_parse_tuple(client_handle_t client_handle,tuple_t * tuple,cisparse_t * cisparse,cisdata_t cisdata)9220Sstevel@tonic-gate cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
9230Sstevel@tonic-gate cisparse_t *cisparse, cisdata_t cisdata)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate cs_socket_t *sp;
9260Sstevel@tonic-gate client_t *client;
9270Sstevel@tonic-gate uint32_t fn;
9280Sstevel@tonic-gate int ret;
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket,
9310Sstevel@tonic-gate &fn, &sp, &client)) != CS_SUCCESS)
9320Sstevel@tonic-gate return (ret);
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate /*
9350Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
9360Sstevel@tonic-gate * for this client, then return an error.
9370Sstevel@tonic-gate */
9380Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED))
9390Sstevel@tonic-gate return (CS_NO_CARD);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate * Sanity check to be sure that we've got a non-NULL CIS list
9430Sstevel@tonic-gate * pointer.
9440Sstevel@tonic-gate */
9450Sstevel@tonic-gate if (!(tuple->CISOffset))
9460Sstevel@tonic-gate return (CS_BAD_ARGS);
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate /*
9510Sstevel@tonic-gate * Check to see if there is a valid CIS for this function.
9520Sstevel@tonic-gate * There is an implicit assumption here that if this
9530Sstevel@tonic-gate * is a multi-function CIS and the specified function
9540Sstevel@tonic-gate * number is not CS_GLOBAL_CIS that in order for there
9550Sstevel@tonic-gate * to be a valid function-specific CIS, there also must
9560Sstevel@tonic-gate * be a valid global CIS. This means that we don't need
9570Sstevel@tonic-gate * to know whether this tuple came from the global CIS
9580Sstevel@tonic-gate * or from the function-specific CIS.
9590Sstevel@tonic-gate */
9600Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) &&
9610Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) {
9620Sstevel@tonic-gate ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
9630Sstevel@tonic-gate cis_cistpl_std_callout,
9640Sstevel@tonic-gate tuple->CISOffset,
9650Sstevel@tonic-gate (tuple->Attributes & TUPLE_RETURN_NAME)?
9660Sstevel@tonic-gate HANDTPL_RETURN_NAME:
9670Sstevel@tonic-gate HANDTPL_PARSE_LTUPLE,
9680Sstevel@tonic-gate cisparse, cisdata);
9690Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
9700Sstevel@tonic-gate if (ret == CISTPLF_UNKNOWN)
9710Sstevel@tonic-gate return (CS_UNKNOWN_TUPLE);
9720Sstevel@tonic-gate if (ret != CISTPLF_NOERROR)
9730Sstevel@tonic-gate return (CS_BAD_CIS);
9740Sstevel@tonic-gate ret = CS_SUCCESS;
9750Sstevel@tonic-gate } else {
9760Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
9770Sstevel@tonic-gate ret = CS_NO_CIS;
9780Sstevel@tonic-gate } /* if (CW_VALID_CIS) */
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate return (ret);
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate /*
9840Sstevel@tonic-gate * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
9850Sstevel@tonic-gate * this is to support the GetFirstTuple and
9860Sstevel@tonic-gate * GetNextTuple function call
9870Sstevel@tonic-gate *
9880Sstevel@tonic-gate * flags - one of:
9890Sstevel@tonic-gate * CS_GET_FIRST_FLAG causes function to support GetFirstTuple
9900Sstevel@tonic-gate * CS_GET_NEXT_FLAG causes function to support GetNextTuple
9910Sstevel@tonic-gate *
9920Sstevel@tonic-gate * tuple_t->Attributes flags:
9930Sstevel@tonic-gate * TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
9940Sstevel@tonic-gate * TUPLE_RETURN_IGNORED_TUPLES - return tuples with
9950Sstevel@tonic-gate * CISTPLF_IGNORE_TUPLE set in the
9960Sstevel@tonic-gate * cistpl_t->flags member.
9970Sstevel@tonic-gate *
9980Sstevel@tonic-gate * Notes for regular PC card driver callers:
9990Sstevel@tonic-gate *
10000Sstevel@tonic-gate * On a single-function card, the caller will get back all the tuples in
10010Sstevel@tonic-gate * the CIS.
10020Sstevel@tonic-gate *
10030Sstevel@tonic-gate * On a multi-function card, the caller will get the tuples from the
10040Sstevel@tonic-gate * global CIS followed by the tuples in the function-specific CIS. The
10050Sstevel@tonic-gate * caller will not get any tuples from a function-specific CIS that
10060Sstevel@tonic-gate * does not belong to the caller's function.
10070Sstevel@tonic-gate *
10080Sstevel@tonic-gate * Notes for Socket Services, the "super-client" or CSI driver callers:
10090Sstevel@tonic-gate *
10100Sstevel@tonic-gate * On a single-function card, the operation is the same as for regular
10110Sstevel@tonic-gate * PC card driver callers with the addition that if the function number
10120Sstevel@tonic-gate * is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
10130Sstevel@tonic-gate *
10140Sstevel@tonic-gate * On a multi-function card, the operation is the same as for regular
10150Sstevel@tonic-gate * PC card driver callers with the addition that if the function number
10160Sstevel@tonic-gate * is set to CS_GLOBAL_CIS the caller will only get tuples from the
10170Sstevel@tonic-gate * global CIS. If a particular function nubmer does not exist, this
10180Sstevel@tonic-gate * function will return CS_NO_CIS for that function.
10190Sstevel@tonic-gate *
10200Sstevel@tonic-gate * General notes:
10210Sstevel@tonic-gate *
10220Sstevel@tonic-gate * On both a single-function card and a multi-function card, if the tuple
10230Sstevel@tonic-gate * comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
10240Sstevel@tonic-gate * set in the tuple_t->flags member.
10250Sstevel@tonic-gate *
10260Sstevel@tonic-gate * On a multi-function card, if the tuple comes from the function-specific
10270Sstevel@tonic-gate * CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
10280Sstevel@tonic-gate * member.
10290Sstevel@tonic-gate *
10300Sstevel@tonic-gate * For other flags that are set in the tuple_t->flags member, see the
10310Sstevel@tonic-gate * comments for the cis_list_lcreate function in the cis.c file.
10320Sstevel@tonic-gate *
10330Sstevel@tonic-gate * The CIS parser may not include all the tuples that are in the CIS in
10340Sstevel@tonic-gate * the private CIS list that it creates and maintains. See the CIS
10350Sstevel@tonic-gate * parser documentation for a list of tuples that the parser does not
10360Sstevel@tonic-gate * include in the list.
10370Sstevel@tonic-gate *
10380Sstevel@tonic-gate * If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
10390Sstevel@tonic-gate * parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
10400Sstevel@tonic-gate * be returned to the caller. Instead, the next tuple that matches
10410Sstevel@tonic-gate * the calling criteria will be returned (or NULL if no other tuples
10420Sstevel@tonic-gate * match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
10430Sstevel@tonic-gate * the flags paramter, tuples in the CIS list that match the calling
10440Sstevel@tonic-gate * criteria will be returned.
10450Sstevel@tonic-gate *
10460Sstevel@tonic-gate * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
10470Sstevel@tonic-gate * the tuple_t->Attributes member is not set, then we don't return
10480Sstevel@tonic-gate * any of the link tuples. This function ignores this flag and always
10490Sstevel@tonic-gate * returns link tuples.
10500Sstevel@tonic-gate *
10510Sstevel@tonic-gate * Return codes:
10520Sstevel@tonic-gate * CS_SUCCESS - if tuple sucessfully found and returned
10530Sstevel@tonic-gate * CS_NO_CARD - if no card inserted
10540Sstevel@tonic-gate * CS_NO_CIS - if no CIS for the specified card/function
10550Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if tuple not found or no more tuples
10560Sstevel@tonic-gate * to return
10570Sstevel@tonic-gate *
10580Sstevel@tonic-gate * See notes for cs_get_socket for a description of valid client, socket
10590Sstevel@tonic-gate * and function number combinations.
10600Sstevel@tonic-gate */
10610Sstevel@tonic-gate static int
cs_get_firstnext_tuple(client_handle_t client_handle,tuple_t * tuple,uint32_t flags)10620Sstevel@tonic-gate cs_get_firstnext_tuple(client_handle_t client_handle,
10630Sstevel@tonic-gate tuple_t *tuple, uint32_t flags)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate cs_socket_t *sp;
10660Sstevel@tonic-gate client_t *client;
10670Sstevel@tonic-gate uint32_t fn;
10680Sstevel@tonic-gate int ret;
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
10710Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS)
10720Sstevel@tonic-gate return (ret);
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate /*
10750Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
10760Sstevel@tonic-gate * for this client, then return an error.
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED))
10790Sstevel@tonic-gate return (CS_NO_CARD);
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate /*
10840Sstevel@tonic-gate * If there's no CIS on this card or no CIS for the specified
10850Sstevel@tonic-gate * function, then we can't do much.
10860Sstevel@tonic-gate */
10870Sstevel@tonic-gate if ((!(sp->cis_flags & CW_VALID_CIS)) ||
10880Sstevel@tonic-gate (!(sp->cis[fn].flags & CW_VALID_CIS))) {
10890Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
10900Sstevel@tonic-gate return (CS_NO_CIS);
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate /*
10940Sstevel@tonic-gate * This will set the CIS_GET_LTUPLE_IGNORE flag if the
10950Sstevel@tonic-gate * TUPLE_RETURN_IGNORED_TUPLES flag is set. The
10960Sstevel@tonic-gate * assumption here is that the CIS_GET_LTUPLE_IGNORE
10970Sstevel@tonic-gate * flag and the TUPLE_RETURN_IGNORED_TUPLES flag
10980Sstevel@tonic-gate * shares the same bit position. If this ever changes,
10990Sstevel@tonic-gate * we'll ahve to re-work this section of code.
11000Sstevel@tonic-gate */
11010Sstevel@tonic-gate if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
11020Sstevel@tonic-gate flags |= CIS_GET_LTUPLE_IGNORE;
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate * Are we GetFirstTuple or GetNextTuple?
11060Sstevel@tonic-gate */
11070Sstevel@tonic-gate if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
11080Sstevel@tonic-gate /*
11090Sstevel@tonic-gate * Initialize the tuple structure; we need this information when
11100Sstevel@tonic-gate * we have to process a GetNextTuple or ParseTuple call.
11110Sstevel@tonic-gate * If this card has a multi-function CIS, then we always start out
11120Sstevel@tonic-gate * delivering tuples from the global CIS chain. If this card does
11130Sstevel@tonic-gate * not have a multi-function CIS, then the function 0 CIS chain
11140Sstevel@tonic-gate * will contain the complete CIS list.
11150Sstevel@tonic-gate * If this is a multi-function card, then use the GET_FIRST_LTUPLE
11160Sstevel@tonic-gate * macro to return the first tuple in the CIS list - we do this
11170Sstevel@tonic-gate * since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
11180Sstevel@tonic-gate * set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
11190Sstevel@tonic-gate * Note that we don't have to cross over into the fucntion-specific
11200Sstevel@tonic-gate * CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
11210Sstevel@tonic-gate * always have at least a CISTPL_LONGLINK_MFC tuple in the global
11220Sstevel@tonic-gate * CIS chain - the test for NULL is just a sanity check.
11230Sstevel@tonic-gate */
11240Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11250Sstevel@tonic-gate if ((tuple->CISOffset =
11260Sstevel@tonic-gate GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
11270Sstevel@tonic-gate flags)) == NULL) {
11280Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
11290Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
11300Sstevel@tonic-gate } /* GET_FIRST_LTUPLE */
11310Sstevel@tonic-gate } else {
11320Sstevel@tonic-gate tuple->CISOffset = sp->cis[0].cis;
11330Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */
11340Sstevel@tonic-gate } else {
11350Sstevel@tonic-gate cistpl_t *tp;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate /*
11380Sstevel@tonic-gate * Check to be sure that we have a non-NULL tuple list pointer.
11390Sstevel@tonic-gate * This is necessary in the case where the caller calls us
11400Sstevel@tonic-gate * with get next tuple requests but we don't have any more
11410Sstevel@tonic-gate * tuples to give back.
11420Sstevel@tonic-gate */
11430Sstevel@tonic-gate if (tuple->CISOffset == NULL) {
11440Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
11450Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate /*
11490Sstevel@tonic-gate * Point to the next tuple in the list. If we're searching for
11500Sstevel@tonic-gate * a particular tuple, FIND_LTUPLE_FWD will find it.
11510Sstevel@tonic-gate *
11520Sstevel@tonic-gate * If there are no more tuples in the chain that we're looking
11530Sstevel@tonic-gate * at, then if we're looking at the global portion of a
11540Sstevel@tonic-gate * multi-function CIS, switch to the function-specific list
11550Sstevel@tonic-gate * and start looking there.
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
11580Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11590Sstevel@tonic-gate if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11600Sstevel@tonic-gate (fn != CS_GLOBAL_CIS)) {
11610Sstevel@tonic-gate tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
11620Sstevel@tonic-gate } /* CISTPLF_GLOBAL_CIS */
11630Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */
11640Sstevel@tonic-gate } /* GET_NEXT_TUPLE */
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate * If there are no more tuples in the chain, then return.
11680Sstevel@tonic-gate */
11690Sstevel@tonic-gate if ((tuple->CISOffset = tp) == NULL) {
11700Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
11710Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate } /* CS_GET_FIRST_FLAG */
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate /*
11760Sstevel@tonic-gate * Check if we want to get the first of a particular type of tuple
11770Sstevel@tonic-gate * or just the first tuple in the chain.
11780Sstevel@tonic-gate * If there are no more tuples of the type we're searching for in
11790Sstevel@tonic-gate * the chain that we're looking at, then if we're looking at
11800Sstevel@tonic-gate * the global portion of a multi-function CIS, switch to the
11810Sstevel@tonic-gate * function-specific list and start looking there.
11820Sstevel@tonic-gate */
11830Sstevel@tonic-gate if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
11840Sstevel@tonic-gate cistpl_t *tp;
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
11870Sstevel@tonic-gate tuple->DesiredTuple, flags)) == NULL) {
11880Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11890Sstevel@tonic-gate if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11900Sstevel@tonic-gate (fn != CS_GLOBAL_CIS)) {
11910Sstevel@tonic-gate tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
11920Sstevel@tonic-gate tuple->DesiredTuple, flags);
11930Sstevel@tonic-gate } /* CISTPLF_GLOBAL_CIS */
11940Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */
11950Sstevel@tonic-gate } /* FIND_LTUPLE_FWD */
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate /*
11980Sstevel@tonic-gate * If there are no more tuples in the chain, then return.
11990Sstevel@tonic-gate */
12000Sstevel@tonic-gate if ((tuple->CISOffset = tp) == NULL) {
12010Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
12020Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate } /* !RETURN_FIRST_TUPLE */
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate /*
12070Sstevel@tonic-gate * We've got a tuple, now fill out the rest of the tuple_t
12080Sstevel@tonic-gate * structure. Callers can use the flags member to
12090Sstevel@tonic-gate * determine whether or not the tuple data was copied
12100Sstevel@tonic-gate * to the linked list or if it's still on the card.
12110Sstevel@tonic-gate */
12120Sstevel@tonic-gate tuple->Flags = tuple->CISOffset->flags;
12130Sstevel@tonic-gate tuple->TupleCode = tuple->CISOffset->type;
12140Sstevel@tonic-gate tuple->TupleLink = tuple->CISOffset->len;
12150Sstevel@tonic-gate tuple->TupleDataLen = tuple->CISOffset->len;
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate return (CS_SUCCESS);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate /*
12230Sstevel@tonic-gate * cs_get_tuple_data - get the data portion of a tuple; this is to
12240Sstevel@tonic-gate * support the GetTupleData function call.
12250Sstevel@tonic-gate *
12260Sstevel@tonic-gate * Note that if the data body of a tuple was not read from the CIS,
12270Sstevel@tonic-gate * then this function will return CS_NO_MORE_ITEMS.
12280Sstevel@tonic-gate *
12290Sstevel@tonic-gate * For flags that are set in the tuple_t->flags member, see the
12300Sstevel@tonic-gate * comments for the cis_list_lcreate function in the cis.c file.
12310Sstevel@tonic-gate * These flags are copied into the tuple_t->flags member by the
12320Sstevel@tonic-gate * cs_get_firstnext_tuple function call.
12330Sstevel@tonic-gate *
12340Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function.
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate static int
cs_get_tuple_data(client_handle_t client_handle,tuple_t * tuple)12370Sstevel@tonic-gate cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
12380Sstevel@tonic-gate {
12390Sstevel@tonic-gate cs_socket_t *sp;
12400Sstevel@tonic-gate client_t *client;
12410Sstevel@tonic-gate int ret, nbytes;
12420Sstevel@tonic-gate uint32_t fn, flags;
12430Sstevel@tonic-gate cisdata_t *tsd, *tdd;
12440Sstevel@tonic-gate uint32_t newoffset;
12450Sstevel@tonic-gate acc_handle_t cis_handle;
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
12480Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS)
12490Sstevel@tonic-gate return (ret);
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate /*
12520Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
12530Sstevel@tonic-gate * for this client, then return an error.
12540Sstevel@tonic-gate */
12550Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED))
12560Sstevel@tonic-gate return (CS_NO_CARD);
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) &&
12610Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) {
12620Sstevel@tonic-gate
12630Sstevel@tonic-gate /*
12640Sstevel@tonic-gate * Check to be sure that we have a non-NULL pointer to
12650Sstevel@tonic-gate * a CIS list.
12660Sstevel@tonic-gate */
12670Sstevel@tonic-gate if (!(tuple->CISOffset)) {
12680Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
12690Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate /*
12730Sstevel@tonic-gate * Since the tuple data buffer that the caller calls us with
12740Sstevel@tonic-gate * is preallocated in the tuple_t structure, we ignore any
12750Sstevel@tonic-gate * TupleDataMax value that the caller has setup and use the
12760Sstevel@tonic-gate * actual size of the tuple data buffer in the structure.
12770Sstevel@tonic-gate */
12780Sstevel@tonic-gate tuple->TupleDataMax = sizeof (tuple->TupleData);
12790Sstevel@tonic-gate
12800Sstevel@tonic-gate /*
12810Sstevel@tonic-gate * Make sure the requested offset is not past the end of the
12820Sstevel@tonic-gate * tuple data body nor past the end of the user-supplied
12830Sstevel@tonic-gate * buffer.
12840Sstevel@tonic-gate */
12850Sstevel@tonic-gate if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
12860Sstevel@tonic-gate (int)tuple->TupleDataMax)) {
12870Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
12880Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate tuple->TupleDataLen = tuple->TupleLink;
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate if ((nbytes = min((int)tuple->TupleDataMax -
12940Sstevel@tonic-gate (int)tuple->TupleOffset,
12950Sstevel@tonic-gate (int)tuple->TupleDataLen -
12960Sstevel@tonic-gate (int)tuple->TupleOffset)) < 1) {
12970Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
12980Sstevel@tonic-gate return (CS_BAD_ARGS);
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate /*
13020Sstevel@tonic-gate * The tuple data destination is always the tuple_t->TupleData
13030Sstevel@tonic-gate * buffer in the tuple_t structure no matter where we read the
13040Sstevel@tonic-gate * tuple data from.
13050Sstevel@tonic-gate */
13060Sstevel@tonic-gate tdd = tuple->TupleData;
13070Sstevel@tonic-gate bzero((caddr_t)tdd, sizeof (tuple->TupleData));
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate /*
13100Sstevel@tonic-gate * Do we have a copy of the tuple data? If not, we have to
13110Sstevel@tonic-gate * get a pointer to the CIS and read the tuple data from the
13120Sstevel@tonic-gate * card itself.
13130Sstevel@tonic-gate */
13140Sstevel@tonic-gate switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
13150Sstevel@tonic-gate case CISTPLF_LM_SPACE:
13160Sstevel@tonic-gate tsd = (tuple->CISOffset->data +
13170Sstevel@tonic-gate (unsigned)tuple->TupleOffset);
13180Sstevel@tonic-gate while (nbytes--)
13190Sstevel@tonic-gate *tdd++ = *tsd++;
13200Sstevel@tonic-gate break;
13210Sstevel@tonic-gate case CISTPLF_AM_SPACE:
13220Sstevel@tonic-gate case CISTPLF_CM_SPACE:
13230Sstevel@tonic-gate newoffset = tuple->CISOffset->offset;
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate /*
13260Sstevel@tonic-gate * Setup the proper space flags as well as setup the
13270Sstevel@tonic-gate * address offset to point to the start of the tuple
13280Sstevel@tonic-gate * data area; we need to do the latter since the
13290Sstevel@tonic-gate * cis_store_cis_addr function in cis.c sets up the
13300Sstevel@tonic-gate * tuple->CISOffset->offset offset to point to the
13310Sstevel@tonic-gate * start of the tuple.
13320Sstevel@tonic-gate */
13330Sstevel@tonic-gate if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
13340Sstevel@tonic-gate flags = CISTPLF_AM_SPACE;
13350Sstevel@tonic-gate newoffset += ((tuple->TupleOffset * 2) + 4);
13360Sstevel@tonic-gate } else {
13370Sstevel@tonic-gate flags = CISTPLF_CM_SPACE;
13380Sstevel@tonic-gate newoffset += (tuple->TupleOffset + 2);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
13420Sstevel@tonic-gate flags) != CS_SUCCESS) {
13430Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
13440Sstevel@tonic-gate cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
13450Sstevel@tonic-gate "can't init CIS window\n",
13460Sstevel@tonic-gate sp->socket_num);
13470Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
13480Sstevel@tonic-gate } /* cs_init_cis_window */
13490Sstevel@tonic-gate while (nbytes--) {
13500Sstevel@tonic-gate *tdd++ = csx_Get8(cis_handle, newoffset++);
13510Sstevel@tonic-gate if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
13520Sstevel@tonic-gate newoffset++;
13530Sstevel@tonic-gate } /* while */
13540Sstevel@tonic-gate break;
13550Sstevel@tonic-gate default:
13560Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
13570Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
13580Sstevel@tonic-gate } /* switch */
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate ret = CS_SUCCESS;
13610Sstevel@tonic-gate } else {
13620Sstevel@tonic-gate ret = CS_NO_CIS;
13630Sstevel@tonic-gate } /* if (CW_VALID_CIS) */
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate return (ret);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate /*
13710Sstevel@tonic-gate * cs_validate_cis - validates the CIS on a card in the given socket; this
13720Sstevel@tonic-gate * is to support the ValidateCIS function call.
13730Sstevel@tonic-gate *
13740Sstevel@tonic-gate * Notes for regular PC card driver callers:
13750Sstevel@tonic-gate *
13760Sstevel@tonic-gate * Regular PC card drivers calling ValidateCIS will get the meaning of
13770Sstevel@tonic-gate * the structure members as specified in the standard.
13780Sstevel@tonic-gate *
13790Sstevel@tonic-gate * Notes for Socket Services, the "super-client" or CSI driver callers:
13800Sstevel@tonic-gate *
13810Sstevel@tonic-gate * with: Function Number = CS_GLOBAL_CIS
13820Sstevel@tonic-gate *
13830Sstevel@tonic-gate * For a single-function card, CS_NO_CIS will be returned and the
13840Sstevel@tonic-gate * cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
13850Sstevel@tonic-gate *
13860Sstevel@tonic-gate * For a multi-function card, cisinfo_t->Chains will contain a count of
13870Sstevel@tonic-gate * the number of CIS chains in the global portion of the CIS, and
13880Sstevel@tonic-gate * cisinfo_t->Tuples will contain a count of the number of tuples in
13890Sstevel@tonic-gate * the global portion of the CIS.
13900Sstevel@tonic-gate *
13910Sstevel@tonic-gate * with: 0 <= Function Number < CIS_MAX_FUNCTIONS
13920Sstevel@tonic-gate *
13930Sstevel@tonic-gate * For a single-function card, if the function number is equal to 0 and
13940Sstevel@tonic-gate * has a CIS, cisinfo_t->Chains will contain a count of the number of
13950Sstevel@tonic-gate * CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
13960Sstevel@tonic-gate * the number of tuples in the CIS. If the card does not have a CIS, or
13970Sstevel@tonic-gate * if the function number is not equal to 0, CS_NO_CIS will be returned
13980Sstevel@tonic-gate * and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
13990Sstevel@tonic-gate * to 0.
14000Sstevel@tonic-gate *
14010Sstevel@tonic-gate * For a multi-function card, cisinfo_t->Chains will contain a count of
14020Sstevel@tonic-gate * the number of CIS chains in the global and function-specific
14030Sstevel@tonic-gate * portions of the CIS, and cisinfo_t->Tuples will contain a count of
14040Sstevel@tonic-gate * the number of tuples in the global and function-specific portions of
14050Sstevel@tonic-gate * the CIS. If the function does not exist or has no CIS, CS_NO_CIS
14060Sstevel@tonic-gate * will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
14070Sstevel@tonic-gate * members will be set to 0.
14080Sstevel@tonic-gate *
14090Sstevel@tonic-gate * General notes:
14100Sstevel@tonic-gate *
14110Sstevel@tonic-gate * If the card does not have a CIS, or if the function does not exist
14120Sstevel@tonic-gate * or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
14130Sstevel@tonic-gate * and cisinfo_t->Tuples members will be set to 0.
14140Sstevel@tonic-gate *
14150Sstevel@tonic-gate * Most of the work of validating the CIS has already been done by the
14160Sstevel@tonic-gate * CIS parser module, so we don't have to do much here except for
14170Sstevel@tonic-gate * looking at the various flags and tuple/chain counts that were already
14180Sstevel@tonic-gate * setup by the CIS parser.
14190Sstevel@tonic-gate *
14200Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function.
14210Sstevel@tonic-gate */
14220Sstevel@tonic-gate static int
cs_validate_cis(client_handle_t client_handle,cisinfo_t * cisinfo)14230Sstevel@tonic-gate cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
14240Sstevel@tonic-gate {
14250Sstevel@tonic-gate cs_socket_t *sp;
14260Sstevel@tonic-gate client_t *client;
14270Sstevel@tonic-gate uint32_t fn;
14280Sstevel@tonic-gate int ret;
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
14310Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS)
14320Sstevel@tonic-gate return (ret);
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /*
14350Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
14360Sstevel@tonic-gate * for this client, then return an error.
14370Sstevel@tonic-gate */
14380Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED))
14390Sstevel@tonic-gate return (CS_NO_CARD);
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
14420Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) &&
14430Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) {
14440Sstevel@tonic-gate cisinfo->Chains = sp->cis[fn].nchains;
14450Sstevel@tonic-gate cisinfo->Tuples = sp->cis[fn].ntuples;
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate if ((fn != CS_GLOBAL_CIS) &&
14480Sstevel@tonic-gate (sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
14490Sstevel@tonic-gate cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
14500Sstevel@tonic-gate cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
14510Sstevel@tonic-gate } /* !CS_GLOBAL_CIS */
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate ret = CS_SUCCESS;
14540Sstevel@tonic-gate } else {
14550Sstevel@tonic-gate cisinfo->Chains = 0;
14560Sstevel@tonic-gate cisinfo->Tuples = 0;
14570Sstevel@tonic-gate ret = CS_NO_CIS;
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate return (ret);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate * cs_init_cis_window - initializes the CIS window for the passed socket
14660Sstevel@tonic-gate *
14670Sstevel@tonic-gate * calling: *sp - pointer to the per-socket structure
14680Sstevel@tonic-gate * *offset - offset from start of AM or CM space
14690Sstevel@tonic-gate * *hp - pointer to acc_handle_t to store modified
14700Sstevel@tonic-gate * window access handle in
14710Sstevel@tonic-gate * flags - one of:
14720Sstevel@tonic-gate * CISTPLF_AM_SPACE - set window to AM space
14730Sstevel@tonic-gate * CISTPLF_CM_SPACE - set window to CM space
14740Sstevel@tonic-gate *
14750Sstevel@tonic-gate * returns: CS_SUCCESS if CIS window was set up
14760Sstevel@tonic-gate * *offset - contains adjusted offset to use to access
14770Sstevel@tonic-gate * requested space
14780Sstevel@tonic-gate * CS_BAD_WINDOW if CIS window could not be setup
14790Sstevel@tonic-gate * CS_GENERAL_FAILURE if socket has a CIS window number
14800Sstevel@tonic-gate * but the window flags are wrong
14810Sstevel@tonic-gate *
14820Sstevel@tonic-gate * Note: This function will check to be sure that there is a valid
14830Sstevel@tonic-gate * CIS window allocated to this socket.
14840Sstevel@tonic-gate * If there is an error in setting up the window hardware, the
14850Sstevel@tonic-gate * CIS window information for this socket is cleared.
14860Sstevel@tonic-gate * This function is also used by routines that need to get
14870Sstevel@tonic-gate * a pointer to the base of AM space to access the card's
14880Sstevel@tonic-gate * configuration registers.
14890Sstevel@tonic-gate * The passed offset is the un-window-size-aligned offset.
14900Sstevel@tonic-gate */
14910Sstevel@tonic-gate int
cs_init_cis_window(cs_socket_t * sp,uint32_t * offset,acc_handle_t * hp,uint32_t flags)14920Sstevel@tonic-gate cs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
14930Sstevel@tonic-gate acc_handle_t *hp, uint32_t flags)
14940Sstevel@tonic-gate {
14950Sstevel@tonic-gate set_window_t sw;
14960Sstevel@tonic-gate get_window_t gw;
14970Sstevel@tonic-gate inquire_window_t iw;
14980Sstevel@tonic-gate set_page_t set_page;
14990Sstevel@tonic-gate cs_window_t *cw;
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate /*
15020Sstevel@tonic-gate * Check to be sure that we have a valid CIS window
15030Sstevel@tonic-gate */
15040Sstevel@tonic-gate if (!SOCKET_HAS_CIS_WINDOW(sp)) {
15050Sstevel@tonic-gate cmn_err(CE_CONT,
15060Sstevel@tonic-gate "cs_init_cis_window: socket %d has no CIS window\n",
15070Sstevel@tonic-gate sp->socket_num);
15080Sstevel@tonic-gate return (CS_BAD_WINDOW);
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate /*
15120Sstevel@tonic-gate * Check to be sure that this window is allocated for CIS use
15130Sstevel@tonic-gate */
15140Sstevel@tonic-gate if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
15150Sstevel@tonic-gate return (CS_BAD_WINDOW);
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate if (!(cw->state & CW_CIS)) {
15180Sstevel@tonic-gate cmn_err(CE_CONT,
15190Sstevel@tonic-gate "cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
15200Sstevel@tonic-gate sp->socket_num, cw->state);
15210Sstevel@tonic-gate return (CS_BAD_WINDOW);
15220Sstevel@tonic-gate }
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate /*
15250Sstevel@tonic-gate * Get the characteristics of this window - we use this to
15260Sstevel@tonic-gate * determine whether we need to re-map the window or
15270Sstevel@tonic-gate * just move the window offset on the card.
15280Sstevel@tonic-gate */
15290Sstevel@tonic-gate iw.window = sp->cis_win_num;
15300Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw);
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate /*
15330Sstevel@tonic-gate * We've got a window, now set up the hardware. If we've got
15340Sstevel@tonic-gate * a variable sized window, then all we need to do is to
15350Sstevel@tonic-gate * get a valid mapping to the base of the window using
15360Sstevel@tonic-gate * the current window size; if we've got a fixed-size
15370Sstevel@tonic-gate * window, then we need to get a mapping to the window
15380Sstevel@tonic-gate * starting at offset zero of the window.
15390Sstevel@tonic-gate */
15400Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
15410Sstevel@tonic-gate sw.WindowSize = sp->cis_win_size;
15420Sstevel@tonic-gate set_page.offset = ((*offset / sp->cis_win_size) *
15430Sstevel@tonic-gate sp->cis_win_size);
15440Sstevel@tonic-gate } else {
15450Sstevel@tonic-gate set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
15460Sstevel@tonic-gate iw.mem_win_char.MinSize);
15470Sstevel@tonic-gate sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
15480Sstevel@tonic-gate (set_page.offset - 1)) + PAGESIZE);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate /*
15520Sstevel@tonic-gate * Return a normalized base offset; this takes care of the case
15530Sstevel@tonic-gate * where the required offset is greater than the window size.
15540Sstevel@tonic-gate * BugID 1236404
15550Sstevel@tonic-gate * code was:
15560Sstevel@tonic-gate * *offset = *offset & (set_page.offset - 1);
15570Sstevel@tonic-gate */
15580Sstevel@tonic-gate *offset = *offset - set_page.offset;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate #ifdef CS_DEBUG
15610Sstevel@tonic-gate if (cs_debug > 1)
15620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
15630Sstevel@tonic-gate "offset 0x%x\n",
15640Sstevel@tonic-gate (int)sw.WindowSize,
15650Sstevel@tonic-gate (int)set_page.offset);
15660Sstevel@tonic-gate if (cs_debug > 1)
15670Sstevel@tonic-gate cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
15680Sstevel@tonic-gate (int)*offset,
15690Sstevel@tonic-gate (flags & CISTPLF_AM_SPACE)?
15700Sstevel@tonic-gate "CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
15710Sstevel@tonic-gate #endif
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate sw.window = sp->cis_win_num;
15740Sstevel@tonic-gate sw.socket = sp->socket_num;
15750Sstevel@tonic-gate sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
15760Sstevel@tonic-gate sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15770Sstevel@tonic-gate sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
15780Sstevel@tonic-gate sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate /*
15810Sstevel@tonic-gate * The PCMCIA SS spec specifies this be expressed in
15820Sstevel@tonic-gate * a device speed format per 5.2.7.1.3 but
15830Sstevel@tonic-gate * our implementation of SS_SetWindow uses
15840Sstevel@tonic-gate * actual nanoseconds.
15850Sstevel@tonic-gate */
15860Sstevel@tonic-gate sw.speed = CIS_DEFAULT_SPEED;
15870Sstevel@tonic-gate sw.base = 0;
15880Sstevel@tonic-gate /*
15890Sstevel@tonic-gate * Set up the window - if this fails, then just set the
15900Sstevel@tonic-gate * CIS window number back to it's initialized value so
15910Sstevel@tonic-gate * that we'll fail when we break out of the loop.
15920Sstevel@tonic-gate */
15930Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
15940Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS;
15950Sstevel@tonic-gate cw->state = 0; /* XXX do we really want to do this? */
15960Sstevel@tonic-gate return (CS_BAD_WINDOW);
15970Sstevel@tonic-gate } else {
15980Sstevel@tonic-gate set_page.window = sp->cis_win_num;
15990Sstevel@tonic-gate set_page.page = 0;
16000Sstevel@tonic-gate set_page.state = PS_ENABLED;
16010Sstevel@tonic-gate if (flags & CISTPLF_AM_SPACE)
16020Sstevel@tonic-gate set_page.state |= PS_ATTRIBUTE;
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
16050Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS;
16060Sstevel@tonic-gate cw->state = 0; /* XXX do we really want to do this? */
16070Sstevel@tonic-gate return (CS_BAD_WINDOW);
16080Sstevel@tonic-gate } /* if (SS_SetPage) */
16090Sstevel@tonic-gate } /* if (SS_SetWindow) */
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate /*
16120Sstevel@tonic-gate * Get the window information for the CIS window for this socket.
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate gw.window = sp->cis_win_num;
16150Sstevel@tonic-gate gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
16160Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
16170Sstevel@tonic-gate return (CS_BAD_WINDOW);
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate *hp = (acc_handle_t)gw.handle;
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate return (CS_SUCCESS);
16220Sstevel@tonic-gate }
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate /*
16250Sstevel@tonic-gate * ==== client registration/deregistration section ====
16260Sstevel@tonic-gate */
16270Sstevel@tonic-gate
16280Sstevel@tonic-gate /*
16290Sstevel@tonic-gate * cs_register_client - This supports the RegisterClient call.
16300Sstevel@tonic-gate *
16310Sstevel@tonic-gate * Upon successful registration, the client_handle_t * handle argument will
16320Sstevel@tonic-gate * contain the new client handle and we return CS_SUCCESS.
16330Sstevel@tonic-gate */
16340Sstevel@tonic-gate static int
cs_register_client(client_handle_t * ch,client_reg_t * cr)16350Sstevel@tonic-gate cs_register_client(client_handle_t *ch, client_reg_t *cr)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate uint32_t sn;
16380Sstevel@tonic-gate int super_client = 0;
16390Sstevel@tonic-gate sclient_reg_t *scr = cr->priv;
16400Sstevel@tonic-gate struct sclient_list_t *scli;
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate /*
16430Sstevel@tonic-gate * See if we're not supposed to register any new clients.
16440Sstevel@tonic-gate */
16450Sstevel@tonic-gate if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
16460Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate /*
16490Sstevel@tonic-gate * Do a version check - if the client expects a later version of
16500Sstevel@tonic-gate * Card Services than what we are, return CS_BAD_VERSION.
16510Sstevel@tonic-gate * XXX - How do we specify just a PARTICULAR version of CS??
16520Sstevel@tonic-gate */
16530Sstevel@tonic-gate if (CS_VERSION < cr->Version)
16540Sstevel@tonic-gate return (CS_BAD_VERSION);
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate /*
16570Sstevel@tonic-gate * Check to be sure that the client has given us a valid set of
16580Sstevel@tonic-gate * client type flags. We also use this opportunity to see
16590Sstevel@tonic-gate * if the registering client is Socket Services or is a
16600Sstevel@tonic-gate * "super-client" or a CSI client.
16610Sstevel@tonic-gate *
16620Sstevel@tonic-gate * Note that SS can not set any flag in the Attributes field other
16630Sstevel@tonic-gate * than the INFO_SOCKET_SERVICES flag.
16640Sstevel@tonic-gate *
16650Sstevel@tonic-gate * Valid combinations of cr->Attributes and cr->EventMask flags:
16660Sstevel@tonic-gate *
16670Sstevel@tonic-gate * for Socket Services:
16680Sstevel@tonic-gate * cr->Attributes:
16690Sstevel@tonic-gate * set:
16700Sstevel@tonic-gate * INFO_SOCKET_SERVICES
16710Sstevel@tonic-gate * clear:
16720Sstevel@tonic-gate * {all other flags}
16730Sstevel@tonic-gate * cr->EventMask:
16740Sstevel@tonic-gate * don't care:
16750Sstevel@tonic-gate * {all flags}
16760Sstevel@tonic-gate *
16770Sstevel@tonic-gate * for regular clients:
16780Sstevel@tonic-gate * cr->Attributes:
16790Sstevel@tonic-gate * only one of:
16800Sstevel@tonic-gate * INFO_IO_CLIENT
16810Sstevel@tonic-gate * INFO_MTD_CLIENT
16820Sstevel@tonic-gate * INFO_MEM_CLIENT
16830Sstevel@tonic-gate * don't care:
16840Sstevel@tonic-gate * INFO_CARD_SHARE
16850Sstevel@tonic-gate * INFO_CARD_EXCL
16860Sstevel@tonic-gate * cr->EventMask:
16870Sstevel@tonic-gate * clear:
16880Sstevel@tonic-gate * CS_EVENT_ALL_CLIENTS
16890Sstevel@tonic-gate * don't care:
16900Sstevel@tonic-gate * {all other flags}
16910Sstevel@tonic-gate *
16920Sstevel@tonic-gate * for CSI clients:
16930Sstevel@tonic-gate * cr->Attributes:
16940Sstevel@tonic-gate * set:
16950Sstevel@tonic-gate * INFO_IO_CLIENT
16960Sstevel@tonic-gate * INFO_CSI_CLIENT
16970Sstevel@tonic-gate * clear:
16980Sstevel@tonic-gate * INFO_MTD_CLIENT
16990Sstevel@tonic-gate * INFO_MEM_CLIENT
17000Sstevel@tonic-gate * don't care:
17010Sstevel@tonic-gate * INFO_CARD_SHARE
17020Sstevel@tonic-gate * INFO_CARD_EXCL
17030Sstevel@tonic-gate * cr->EventMask:
17040Sstevel@tonic-gate * don't care:
17050Sstevel@tonic-gate * {all flags}
17060Sstevel@tonic-gate *
17070Sstevel@tonic-gate * for "super-clients":
17080Sstevel@tonic-gate * cr->Attributes:
17090Sstevel@tonic-gate * set:
17100Sstevel@tonic-gate * INFO_IO_CLIENT
17110Sstevel@tonic-gate * INFO_MTD_CLIENT
17120Sstevel@tonic-gate * INFO_SOCKET_SERVICES
17130Sstevel@tonic-gate * INFO_CARD_SHARE
17140Sstevel@tonic-gate * clear:
17150Sstevel@tonic-gate * INFO_MEM_CLIENT
17160Sstevel@tonic-gate * INFO_CARD_EXCL
17170Sstevel@tonic-gate * cr->EventMask:
17180Sstevel@tonic-gate * don't care:
17190Sstevel@tonic-gate * {all flags}
17200Sstevel@tonic-gate */
17210Sstevel@tonic-gate switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
17220Sstevel@tonic-gate /*
17230Sstevel@tonic-gate * Check first to see if this is Socket Services registering; if
17240Sstevel@tonic-gate * so, we don't do anything but return the client handle that is
17250Sstevel@tonic-gate * in the global SS client.
17260Sstevel@tonic-gate */
17270Sstevel@tonic-gate case INFO_SOCKET_SERVICES:
17280Sstevel@tonic-gate *ch = cs_socket_services_client.client_handle;
17290Sstevel@tonic-gate return (CS_SUCCESS);
17300Sstevel@tonic-gate /* NOTREACHED */
17310Sstevel@tonic-gate /* CSI clients */
17320Sstevel@tonic-gate case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
17330Sstevel@tonic-gate break;
17340Sstevel@tonic-gate /* regular clients */
17350Sstevel@tonic-gate case INFO_IO_CLIENT:
17360Sstevel@tonic-gate case INFO_MTD_CLIENT:
17370Sstevel@tonic-gate case INFO_MEM_CLIENT:
17380Sstevel@tonic-gate if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
17390Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
17400Sstevel@tonic-gate break;
17410Sstevel@tonic-gate /* "super-client" clients */
17420Sstevel@tonic-gate case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
17430Sstevel@tonic-gate if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
17440Sstevel@tonic-gate (cr->Attributes & INFO_CARD_EXCL))
17450Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate * We only allow one "super-client" per system.
17480Sstevel@tonic-gate */
17490Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
17500Sstevel@tonic-gate if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
17510Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
17520Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
17550Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
17560Sstevel@tonic-gate super_client = CLIENT_SUPER_CLIENT;
17570Sstevel@tonic-gate break;
17580Sstevel@tonic-gate default:
17590Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
17600Sstevel@tonic-gate } /* switch (cr->Attributes) */
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate * Now, actually create the client node on the socket; this will
17640Sstevel@tonic-gate * also return the new client handle if there were no errors
17650Sstevel@tonic-gate * creating the client node.
17660Sstevel@tonic-gate * The DIP2SOCKET_NUM macro will return the socket and function
17670Sstevel@tonic-gate * number using the encoding specified in the cs_priv.h file.
17680Sstevel@tonic-gate */
17690Sstevel@tonic-gate if (super_client != CLIENT_SUPER_CLIENT) {
17700Sstevel@tonic-gate if (cr->Attributes & INFO_CSI_CLIENT)
17710Sstevel@tonic-gate sn = (uint32_t)(uintptr_t)cr->priv;
17720Sstevel@tonic-gate else
17730Sstevel@tonic-gate sn = DIP2SOCKET_NUM(cr->dip);
17740Sstevel@tonic-gate return (cs_add_client_to_socket(sn, ch, cr, super_client));
17750Sstevel@tonic-gate } /* CLIENT_SUPER_CLIENT */
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate /*
17780Sstevel@tonic-gate * This registering client is a "super-client", so we create one
17790Sstevel@tonic-gate * client node for each socket in the system. We use the
17800Sstevel@tonic-gate * client_reg_t.priv structure member to point to a struct
17810Sstevel@tonic-gate * that the "super-client" client knows about. The client
17820Sstevel@tonic-gate * handle pointer is not used in this case.
17830Sstevel@tonic-gate * We return CS_SUCCESS if at least one client node could be
17840Sstevel@tonic-gate * created. The client must check the error codes in the
17850Sstevel@tonic-gate * error code array to determine which clients could not
17860Sstevel@tonic-gate * be created on which sockets.
17870Sstevel@tonic-gate * We return CS_BAD_HANDLE if no client nodes could be created.
17880Sstevel@tonic-gate */
17890Sstevel@tonic-gate scr->num_clients = 0;
17900Sstevel@tonic-gate scr->max_socket_num = cs_globals.max_socket_num;
17910Sstevel@tonic-gate scr->num_sockets = cs_globals.num_sockets;
17920Sstevel@tonic-gate scr->num_windows = cs_globals.num_windows;
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate *(scr->sclient_list) = cs_globals.sclient_list;
17950Sstevel@tonic-gate
17960Sstevel@tonic-gate for (sn = 0; sn < scr->num_sockets; sn++) {
17970Sstevel@tonic-gate scli = scr->sclient_list[sn];
17980Sstevel@tonic-gate if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
17990Sstevel@tonic-gate cr, super_client)) == CS_SUCCESS) {
18000Sstevel@tonic-gate scr->num_clients++;
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate /*
18050Sstevel@tonic-gate * If we couldn't create any client nodes at all, then
18060Sstevel@tonic-gate * return an error.
18070Sstevel@tonic-gate */
18080Sstevel@tonic-gate if (!scr->num_clients) {
18090Sstevel@tonic-gate /*
18100Sstevel@tonic-gate * XXX - The global superclient lock now gets
18110Sstevel@tonic-gate * cleared in cs_deregister_client
18120Sstevel@tonic-gate */
18130Sstevel@tonic-gate /* cs_clear_superclient_lock(super_client); */
18140Sstevel@tonic-gate return (CS_BAD_HANDLE);
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate return (CS_SUCCESS);
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate
18200Sstevel@tonic-gate /*
18210Sstevel@tonic-gate * cs_add_client_to_socket - this function creates the client node on the
18220Sstevel@tonic-gate * requested socket.
18230Sstevel@tonic-gate *
18240Sstevel@tonic-gate * Note that if we return an error, there is no state that can be cleaned
18250Sstevel@tonic-gate * up. The only way that we can return an error with allocated resources
18260Sstevel@tonic-gate * would be if one of the client handle functions had an internal error.
18270Sstevel@tonic-gate * Since we wouldn't get a valid client handle in this case anyway, there
18280Sstevel@tonic-gate * would be no way to find out what was allocated and what wasn't.
18290Sstevel@tonic-gate */
18300Sstevel@tonic-gate static int
cs_add_client_to_socket(unsigned sn,client_handle_t * ch,client_reg_t * cr,int super_client)18310Sstevel@tonic-gate cs_add_client_to_socket(unsigned sn, client_handle_t *ch,
18320Sstevel@tonic-gate client_reg_t *cr, int super_client)
18330Sstevel@tonic-gate {
18340Sstevel@tonic-gate cs_socket_t *sp;
18350Sstevel@tonic-gate client_t *client, *cclp;
18360Sstevel@tonic-gate int error, cie = 1;
18370Sstevel@tonic-gate int client_lock_acquired;
18380Sstevel@tonic-gate
18390Sstevel@tonic-gate if (cr->event_handler == NULL)
18400Sstevel@tonic-gate return (CS_BAD_ARGS);
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
18430Sstevel@tonic-gate return (CS_BAD_SOCKET);
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
18460Sstevel@tonic-gate
18470Sstevel@tonic-gate /*
18480Sstevel@tonic-gate * Run through all of the registered clients and compare the passed
18490Sstevel@tonic-gate * dip to the dip of each client to make sure that this client
18500Sstevel@tonic-gate * is not trying to register more than once. If they are, then
18510Sstevel@tonic-gate * display a message and return an error.
18520Sstevel@tonic-gate * XXX - we should really check all the sockets in case the client
18530Sstevel@tonic-gate * manipulates the instance number in the dip.
18540Sstevel@tonic-gate * XXX - if we check each socket, we ned to also check for the
18550Sstevel@tonic-gate * "super-client" since it will use the same dip for all
18560Sstevel@tonic-gate * of it's client nodes.
18570Sstevel@tonic-gate */
18580Sstevel@tonic-gate mutex_enter(&sp->lock);
18590Sstevel@tonic-gate client = sp->client_list;
18600Sstevel@tonic-gate while (client) {
18610Sstevel@tonic-gate if (!(cr->Attributes & INFO_CSI_CLIENT) &&
18620Sstevel@tonic-gate (client->dip == cr->dip)) {
18630Sstevel@tonic-gate mutex_exit(&sp->lock);
18640Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18650Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
18660Sstevel@tonic-gate "function 0x%x\n"
18670Sstevel@tonic-gate "\tclient already registered with "
18680Sstevel@tonic-gate "handle 0x%x\n",
18690Sstevel@tonic-gate (int)CS_GET_SOCKET_NUMBER(sn),
18700Sstevel@tonic-gate (int)CS_GET_FUNCTION_NUMBER(sn),
18710Sstevel@tonic-gate (int)client->client_handle);
18720Sstevel@tonic-gate return (CS_BAD_HANDLE);
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate client = client->next;
18750Sstevel@tonic-gate } /* while (client) */
18760Sstevel@tonic-gate mutex_exit(&sp->lock);
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate /*
18790Sstevel@tonic-gate * Create a unique client handle then make sure that we can find it.
18800Sstevel@tonic-gate * This has the side effect of getting us a pointer to the
18810Sstevel@tonic-gate * client structure as well.
18820Sstevel@tonic-gate * Create a client list entry - cs_create_client_handle will use this
18830Sstevel@tonic-gate * as the new client node.
18840Sstevel@tonic-gate * We do it here so that we can grab the sp->lock mutex for the
18850Sstevel@tonic-gate * duration of our manipulation of the client list.
18860Sstevel@tonic-gate * If this function fails, then it will not have added the newly
18870Sstevel@tonic-gate * allocated client node to the client list on this socket,
18880Sstevel@tonic-gate * so we have to free the node that we allocated.
18890Sstevel@tonic-gate */
18900Sstevel@tonic-gate cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate mutex_enter(&sp->lock);
18930Sstevel@tonic-gate if (!(*ch = cs_create_client_handle(sn, cclp))) {
18940Sstevel@tonic-gate mutex_exit(&sp->lock);
18950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18960Sstevel@tonic-gate kmem_free(cclp, sizeof (client_t));
18970Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate
19000Sstevel@tonic-gate /*
19010Sstevel@tonic-gate * Make sure that this is a valid client handle. We should never
19020Sstevel@tonic-gate * fail this since we just got a valid client handle.
19030Sstevel@tonic-gate * If this fails, then we have an internal error so don't bother
19040Sstevel@tonic-gate * trying to clean up the allocated client handle since the
19050Sstevel@tonic-gate * whole system is probably hosed anyway and will shortly
19060Sstevel@tonic-gate * esplode.
19070Sstevel@tonic-gate * It doesn't make sense to call cs_deregister_client at this point
19080Sstevel@tonic-gate * to clean up this broken client since the deregistration
19090Sstevel@tonic-gate * code will also call cs_find_client and most likely fail.
19100Sstevel@tonic-gate */
19110Sstevel@tonic-gate if (!(client = cs_find_client(*ch, &error))) {
19120Sstevel@tonic-gate mutex_exit(&sp->lock);
19130Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
19140Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
19150Sstevel@tonic-gate "invalid client handle created handle 0x%x\n",
19160Sstevel@tonic-gate (int)CS_GET_SOCKET_NUMBER(sn),
19170Sstevel@tonic-gate (int)CS_GET_FUNCTION_NUMBER(sn),
19180Sstevel@tonic-gate (int)*ch);
19190Sstevel@tonic-gate return (error);
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate
19220Sstevel@tonic-gate /*
19230Sstevel@tonic-gate * Save the DDI information.
19240Sstevel@tonic-gate */
19250Sstevel@tonic-gate client->dip = cr->dip;
19260Sstevel@tonic-gate cr->driver_name[MODMAXNAMELEN - 1] = NULL;
19270Sstevel@tonic-gate client->driver_name = (char *)kmem_zalloc(strlen(cr->driver_name) + 1,
19280Sstevel@tonic-gate KM_SLEEP);
19290Sstevel@tonic-gate (void) strcpy(client->driver_name, cr->driver_name);
19300Sstevel@tonic-gate client->instance = ddi_get_instance(cr->dip);
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate /*
19330Sstevel@tonic-gate * Copy over the interesting items that the client gave us.
19340Sstevel@tonic-gate */
19350Sstevel@tonic-gate client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
19360Sstevel@tonic-gate client->event_callback_handler = cr->event_handler;
19370Sstevel@tonic-gate bcopy((caddr_t)&cr->event_callback_args,
19380Sstevel@tonic-gate (caddr_t)&client->event_callback_args,
19390Sstevel@tonic-gate sizeof (event_callback_args_t));
19400Sstevel@tonic-gate /*
19410Sstevel@tonic-gate * Set the client handle since the client needs a client handle
19420Sstevel@tonic-gate * when they call us for their event handler.
19430Sstevel@tonic-gate */
19440Sstevel@tonic-gate client->event_callback_args.client_handle = *ch;
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate /*
19470Sstevel@tonic-gate * Initialize the IO window numbers; if an IO window number is equal
19480Sstevel@tonic-gate * to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
19490Sstevel@tonic-gate */
19500Sstevel@tonic-gate client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
19510Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate /*
19540Sstevel@tonic-gate * Give the client the iblock and idevice cookies to use in
19550Sstevel@tonic-gate * the client's event handler high priority mutex.
19560Sstevel@tonic-gate */
19570Sstevel@tonic-gate cr->iblk_cookie = sp->iblk;
19580Sstevel@tonic-gate cr->idev_cookie = sp->idev;
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate /*
19610Sstevel@tonic-gate * Set up the global event mask information; we copy this directly
19620Sstevel@tonic-gate * from the client; since we are the only source of events,
19630Sstevel@tonic-gate * any bogus bits that the client puts in here won't matter
19640Sstevel@tonic-gate * because we'll never look at them.
19650Sstevel@tonic-gate */
19660Sstevel@tonic-gate client->global_mask = cr->EventMask;
19670Sstevel@tonic-gate
19680Sstevel@tonic-gate /*
19690Sstevel@tonic-gate * If this client registered as a CSI client, set the appropriate
19700Sstevel@tonic-gate * flag in the client's flags area.
19710Sstevel@tonic-gate */
19720Sstevel@tonic-gate if (cr->Attributes & INFO_CSI_CLIENT)
19730Sstevel@tonic-gate client->flags |= CLIENT_CSI_CLIENT;
19740Sstevel@tonic-gate
19750Sstevel@tonic-gate /*
19760Sstevel@tonic-gate * If this client registered as a "super-client" set the appropriate
19770Sstevel@tonic-gate * flag in the client's flags area.
19780Sstevel@tonic-gate */
19790Sstevel@tonic-gate if (super_client == CLIENT_SUPER_CLIENT)
19800Sstevel@tonic-gate client->flags |= CLIENT_SUPER_CLIENT;
19810Sstevel@tonic-gate
19820Sstevel@tonic-gate /*
19830Sstevel@tonic-gate * Save other misc information that this client gave us - it is
19840Sstevel@tonic-gate * used in the GetClientInfo function.
19850Sstevel@tonic-gate */
19860Sstevel@tonic-gate client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate /*
19890Sstevel@tonic-gate * Determine if we should give artificial card insertion events and
19900Sstevel@tonic-gate * a registration complete event. Since we don't differentiate
19910Sstevel@tonic-gate * between sharable and exclusive use cards when giving clients
19920Sstevel@tonic-gate * event notification, we modify the definition of the share/excl
19930Sstevel@tonic-gate * flags as follows:
19940Sstevel@tonic-gate *
19950Sstevel@tonic-gate * If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
19960Sstevel@tonic-gate * the client will receive artificial card insertion
19970Sstevel@tonic-gate * events (if the client's card is currently in the
19980Sstevel@tonic-gate * socket) and a registration complete event.
19990Sstevel@tonic-gate *
20000Sstevel@tonic-gate * If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
20010Sstevel@tonic-gate * set, the client will not receive an artificial card
20020Sstevel@tonic-gate * insertion event nor a registration complete event
20030Sstevel@tonic-gate * due to the client's call to register client.
20040Sstevel@tonic-gate *
20050Sstevel@tonic-gate * The client's event mask is not affected by the setting
20060Sstevel@tonic-gate * of these two bits.
20070Sstevel@tonic-gate */
20080Sstevel@tonic-gate if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
20090Sstevel@tonic-gate client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate /*
20120Sstevel@tonic-gate * Check to see if the card for this client is currently in
20130Sstevel@tonic-gate * the socket. If it is, then set CLIENT_CARD_INSERTED
20140Sstevel@tonic-gate * since clients that are calling GetStatus at attach
20150Sstevel@tonic-gate * time will typically check to see if their card is
20160Sstevel@tonic-gate * currently installed.
20170Sstevel@tonic-gate * If this is the CSI client, we also need to check to see
20180Sstevel@tonic-gate * if there is any card inserted in the socket, since
20190Sstevel@tonic-gate * the cs_card_for_client function will always return
20200Sstevel@tonic-gate * TRUE for a CSI client.
20210Sstevel@tonic-gate * XXX What about super-clients?
20220Sstevel@tonic-gate */
20230Sstevel@tonic-gate if (client->flags & CLIENT_CSI_CLIENT) {
20240Sstevel@tonic-gate get_ss_status_t get_ss_status;
20250Sstevel@tonic-gate
20260Sstevel@tonic-gate get_ss_status.socket = sp->socket_num;
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
20290Sstevel@tonic-gate mutex_exit(&sp->lock);
20300Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20310Sstevel@tonic-gate return (CS_BAD_SOCKET);
20320Sstevel@tonic-gate } /* SS_GetStatus */
20330Sstevel@tonic-gate
20340Sstevel@tonic-gate if (!(cs_sbm2cse(get_ss_status.CardState) &
20350Sstevel@tonic-gate CS_EVENT_CARD_INSERTION))
20360Sstevel@tonic-gate cie = 0;
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate } /* CLIENT_CSI_CLIENT */
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate if (cs_card_for_client(client) && (cie != 0)) {
20410Sstevel@tonic-gate client->pending_events |= CS_EVENT_CARD_INSERTION;
20420Sstevel@tonic-gate client->flags |= CLIENT_CARD_INSERTED;
20430Sstevel@tonic-gate } /* cs_card_for_client */
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate sp->num_clients++;
20460Sstevel@tonic-gate mutex_exit(&sp->lock);
20470Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate return (CS_SUCCESS);
20500Sstevel@tonic-gate }
20510Sstevel@tonic-gate
20520Sstevel@tonic-gate /*
20530Sstevel@tonic-gate * cs_deregister_client - This supports the DeregisterClient call.
20540Sstevel@tonic-gate */
20550Sstevel@tonic-gate static int
cs_deregister_client(client_handle_t client_handle)20560Sstevel@tonic-gate cs_deregister_client(client_handle_t client_handle)
20570Sstevel@tonic-gate {
20580Sstevel@tonic-gate cs_socket_t *sp;
20590Sstevel@tonic-gate client_t *client;
20600Sstevel@tonic-gate int error, super_client = 0;
20610Sstevel@tonic-gate int client_lock_acquired;
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate /*
20640Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
20650Sstevel@tonic-gate * is, we don't do anything except for return success.
20660Sstevel@tonic-gate */
20670Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
20680Sstevel@tonic-gate return (CS_SUCCESS);
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate /*
20710Sstevel@tonic-gate * Get a pointer to this client's socket structure.
20720Sstevel@tonic-gate */
20730Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
20740Sstevel@tonic-gate return (CS_BAD_SOCKET);
20750Sstevel@tonic-gate
20760Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate /*
20790Sstevel@tonic-gate * Make sure that this is a valid client handle.
20800Sstevel@tonic-gate */
20810Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
20820Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20830Sstevel@tonic-gate return (error);
20840Sstevel@tonic-gate }
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate /*
20870Sstevel@tonic-gate * Make sure that any resources allocated by this client are
20880Sstevel@tonic-gate * not still allocated, and that if this is an MTD that
20890Sstevel@tonic-gate * no MTD operations are still in progress.
20900Sstevel@tonic-gate */
20910Sstevel@tonic-gate if (client->flags & (CLIENT_IO_ALLOCATED |
20920Sstevel@tonic-gate CLIENT_IRQ_ALLOCATED |
20930Sstevel@tonic-gate CLIENT_WIN_ALLOCATED |
20940Sstevel@tonic-gate REQ_CONFIGURATION_DONE |
20950Sstevel@tonic-gate REQ_SOCKET_MASK_DONE |
20960Sstevel@tonic-gate REQ_IO_DONE |
20970Sstevel@tonic-gate REQ_IRQ_DONE)) {
20980Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20990Sstevel@tonic-gate return (CS_BUSY);
21000Sstevel@tonic-gate }
21010Sstevel@tonic-gate
21020Sstevel@tonic-gate if (client->flags & CLIENT_MTD_IN_PROGRESS) {
21030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21040Sstevel@tonic-gate return (CS_IN_USE);
21050Sstevel@tonic-gate }
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate /*
21080Sstevel@tonic-gate * Any previously allocated resources are not allocated anymore, and
21090Sstevel@tonic-gate * no MTD operations are in progress, so if this is an MTD client
21100Sstevel@tonic-gate * then do any MTD-specific client deregistration, and then
21110Sstevel@tonic-gate * nuke this client.
21120Sstevel@tonic-gate * We expect cs_deregister_mtd to never fail.
21130Sstevel@tonic-gate */
21140Sstevel@tonic-gate if (client->flags & INFO_MTD_CLIENT)
21150Sstevel@tonic-gate (void) cs_deregister_mtd(client_handle);
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate if (client->flags & CLIENT_SUPER_CLIENT)
21180Sstevel@tonic-gate super_client = CLIENT_SUPER_CLIENT;
21190Sstevel@tonic-gate
21200Sstevel@tonic-gate kmem_free(client->driver_name, strlen(client->driver_name) + 1);
21210Sstevel@tonic-gate
21220Sstevel@tonic-gate error = cs_destroy_client_handle(client_handle);
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21250Sstevel@tonic-gate
21260Sstevel@tonic-gate /*
21270Sstevel@tonic-gate * If this was the "super-client" deregistering, then this
21280Sstevel@tonic-gate * will clear the global "super-client" lock.
21290Sstevel@tonic-gate * XXX - move this outside the per-socket code.
21300Sstevel@tonic-gate */
21310Sstevel@tonic-gate cs_clear_superclient_lock(super_client);
21320Sstevel@tonic-gate
21330Sstevel@tonic-gate return (error);
21340Sstevel@tonic-gate }
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate /*
21370Sstevel@tonic-gate * cs_create_next_client_minor - returns the next available client minor
21380Sstevel@tonic-gate * number or 0 if none available
21390Sstevel@tonic-gate *
21400Sstevel@tonic-gate * Note that cs_find_client will always return a valid pointer to the
21410Sstevel@tonic-gate * global Socket Services client which has a client minor number
21420Sstevel@tonic-gate * of 0; this means that this function can never return a 0 as the
21430Sstevel@tonic-gate * next valid available client minor number.
21440Sstevel@tonic-gate */
21450Sstevel@tonic-gate unsigned
cs_create_next_client_minor(unsigned socket_num,unsigned next_minor)21460Sstevel@tonic-gate cs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
21470Sstevel@tonic-gate {
21480Sstevel@tonic-gate unsigned max_client_handles = cs_max_client_handles;
21490Sstevel@tonic-gate
21500Sstevel@tonic-gate do {
21510Sstevel@tonic-gate next_minor &= CS_MAX_CLIENTS_MASK;
21520Sstevel@tonic-gate if (!cs_find_client(MAKE_CLIENT_HANDLE(
21530Sstevel@tonic-gate CS_GET_SOCKET_NUMBER(socket_num),
21540Sstevel@tonic-gate CS_GET_FUNCTION_NUMBER(socket_num),
21550Sstevel@tonic-gate next_minor), NULL)) {
21560Sstevel@tonic-gate return (next_minor);
21570Sstevel@tonic-gate }
21580Sstevel@tonic-gate next_minor++;
21590Sstevel@tonic-gate } while (max_client_handles--);
21600Sstevel@tonic-gate
21610Sstevel@tonic-gate return (0);
21620Sstevel@tonic-gate }
21630Sstevel@tonic-gate
21640Sstevel@tonic-gate /*
21650Sstevel@tonic-gate * cs_find_client - finds the client pointer associated with the client handle
21660Sstevel@tonic-gate * or NULL if client not found
21670Sstevel@tonic-gate *
21680Sstevel@tonic-gate * returns: (client_t *)NULL - if client not found or an error occured
21690Sstevel@tonic-gate * If the error argument is not NULL,
21700Sstevel@tonic-gate * it is set to:
21710Sstevel@tonic-gate * CS_BAD_SOCKET - socket number in client_handle_t is
21720Sstevel@tonic-gate * invalid
21730Sstevel@tonic-gate * CS_BAD_HANDLE - client not found
21740Sstevel@tonic-gate * If no error, the error argument is not modified.
21750Sstevel@tonic-gate * (client_t *) - pointer to client_t structure
21760Sstevel@tonic-gate *
21770Sstevel@tonic-gate * Note that each socket always has a pseudo client with a client minor number
21780Sstevel@tonic-gate * of 0; this client minor number is used for Socket Services access to
21790Sstevel@tonic-gate * Card Services functions. The client pointer returned for client minor
21800Sstevel@tonic-gate * number 0 is the global Socket Services client pointer.
21810Sstevel@tonic-gate */
21820Sstevel@tonic-gate static client_t *
cs_find_client(client_handle_t client_handle,int * error)21830Sstevel@tonic-gate cs_find_client(client_handle_t client_handle, int *error)
21840Sstevel@tonic-gate {
21850Sstevel@tonic-gate cs_socket_t *sp;
21860Sstevel@tonic-gate client_t *clp;
21870Sstevel@tonic-gate
21880Sstevel@tonic-gate /*
21890Sstevel@tonic-gate * If we are being asked to see if a client with a minor number
21900Sstevel@tonic-gate * of 0 exists, always return a pointer to the global Socket
21910Sstevel@tonic-gate * Services client, since this client always exists, and is
21920Sstevel@tonic-gate * only for use by Socket Services. There is no socket
21930Sstevel@tonic-gate * associated with this special client handle.
21940Sstevel@tonic-gate */
21950Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
21960Sstevel@tonic-gate return (&cs_socket_services_client);
21970Sstevel@tonic-gate
21980Sstevel@tonic-gate /*
21990Sstevel@tonic-gate * Check to be sure that the socket number is in range
22000Sstevel@tonic-gate */
22010Sstevel@tonic-gate if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
22020Sstevel@tonic-gate cs_globals.max_socket_num))) {
22030Sstevel@tonic-gate if (error)
22040Sstevel@tonic-gate *error = CS_BAD_SOCKET;
22050Sstevel@tonic-gate return (NULL);
22060Sstevel@tonic-gate }
22070Sstevel@tonic-gate
22080Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
22090Sstevel@tonic-gate if (error)
22100Sstevel@tonic-gate *error = CS_BAD_SOCKET;
22110Sstevel@tonic-gate return (NULL);
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate
22140Sstevel@tonic-gate clp = sp->client_list;
22150Sstevel@tonic-gate
22160Sstevel@tonic-gate while (clp) {
22170Sstevel@tonic-gate if (clp->client_handle == client_handle)
22180Sstevel@tonic-gate return (clp);
22190Sstevel@tonic-gate clp = clp->next;
22200Sstevel@tonic-gate }
22210Sstevel@tonic-gate
22220Sstevel@tonic-gate if (error)
22230Sstevel@tonic-gate *error = CS_BAD_HANDLE;
22240Sstevel@tonic-gate
22250Sstevel@tonic-gate return (NULL);
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate
22280Sstevel@tonic-gate /*
22290Sstevel@tonic-gate * cs_destroy_client_handle - destroys client handle and client structure of
22300Sstevel@tonic-gate * passed client handle
22310Sstevel@tonic-gate *
22320Sstevel@tonic-gate * returns: CS_SUCCESS - if client handle sucessfully destroyed
22330Sstevel@tonic-gate * CS_BAD_HANDLE - if client handle is invalid or if trying
22340Sstevel@tonic-gate * to destroy global SS client
22350Sstevel@tonic-gate * {other errors} - other errors from cs_find_client()
22360Sstevel@tonic-gate */
22370Sstevel@tonic-gate static int
cs_destroy_client_handle(client_handle_t client_handle)22380Sstevel@tonic-gate cs_destroy_client_handle(client_handle_t client_handle)
22390Sstevel@tonic-gate {
22400Sstevel@tonic-gate client_t *clp;
22410Sstevel@tonic-gate cs_socket_t *sp;
22420Sstevel@tonic-gate int error = CS_BAD_HANDLE;
22430Sstevel@tonic-gate
22440Sstevel@tonic-gate /*
22450Sstevel@tonic-gate * See if we were passed a valid client handle or if we're being asked
22460Sstevel@tonic-gate * to destroy the Socket Services client
22470Sstevel@tonic-gate */
22480Sstevel@tonic-gate if ((!(clp = cs_find_client(client_handle, &error))) ||
22490Sstevel@tonic-gate (CLIENT_HANDLE_IS_SS(client_handle)))
22500Sstevel@tonic-gate return (error);
22510Sstevel@tonic-gate
22520Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
22530Sstevel@tonic-gate return (CS_BAD_SOCKET);
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate /*
22560Sstevel@tonic-gate * Recycle this client's minor number. This will most likely
22570Sstevel@tonic-gate * be the next client minor number we use, but it is also
22580Sstevel@tonic-gate * a hint to cs_create_client_handle, and that function
22590Sstevel@tonic-gate * may actually create a new client handle using a minor
22600Sstevel@tonic-gate * number different that this number.
22610Sstevel@tonic-gate */
22620Sstevel@tonic-gate mutex_enter(&sp->lock);
22630Sstevel@tonic-gate sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
22640Sstevel@tonic-gate
22650Sstevel@tonic-gate /*
22660Sstevel@tonic-gate * See if we're the first or not in the client list; if we're
22670Sstevel@tonic-gate * not first, then just adjust the client behind us to
22680Sstevel@tonic-gate * point to the client ahead of us; this could be NULL
22690Sstevel@tonic-gate * if we're the last client in the list.
22700Sstevel@tonic-gate */
22710Sstevel@tonic-gate if (clp->prev) {
22720Sstevel@tonic-gate clp->prev->next = clp->next;
22730Sstevel@tonic-gate } else {
22740Sstevel@tonic-gate /*
22750Sstevel@tonic-gate * We are first, so adjust the client list head pointer
22760Sstevel@tonic-gate * in the socket to point to the client structure that
22770Sstevel@tonic-gate * follows us; this could turn out to be NULL if we're
22780Sstevel@tonic-gate * the only client on this socket.
22790Sstevel@tonic-gate */
22800Sstevel@tonic-gate sp->client_list = clp->next;
22810Sstevel@tonic-gate }
22820Sstevel@tonic-gate
22830Sstevel@tonic-gate /*
22840Sstevel@tonic-gate * If we're not the last client in the list, point the next
22850Sstevel@tonic-gate * client to the client behind us; this could turn out
22860Sstevel@tonic-gate * to be NULL if we're the first client on this socket.
22870Sstevel@tonic-gate */
22880Sstevel@tonic-gate if (clp->next)
22890Sstevel@tonic-gate clp->next->prev = clp->prev;
22900Sstevel@tonic-gate
22910Sstevel@tonic-gate sp->num_clients--;
22920Sstevel@tonic-gate mutex_exit(&sp->lock);
22930Sstevel@tonic-gate
22940Sstevel@tonic-gate /*
22950Sstevel@tonic-gate * Free this client's memory.
22960Sstevel@tonic-gate */
22970Sstevel@tonic-gate kmem_free(clp, sizeof (client_t));
22980Sstevel@tonic-gate
22990Sstevel@tonic-gate return (CS_SUCCESS);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate /*
23030Sstevel@tonic-gate * cs_create_client_handle - create a new client handle for the passed
23040Sstevel@tonic-gate * socket and function number
23050Sstevel@tonic-gate *
23060Sstevel@tonic-gate * returns: 0 - if can't create client for some reason
23070Sstevel@tonic-gate * client_handle_t - new client handle
23080Sstevel@tonic-gate */
23090Sstevel@tonic-gate static client_handle_t
cs_create_client_handle(unsigned socket_num,client_t * cclp)23100Sstevel@tonic-gate cs_create_client_handle(unsigned socket_num, client_t *cclp)
23110Sstevel@tonic-gate {
23120Sstevel@tonic-gate client_t *clp;
23130Sstevel@tonic-gate cs_socket_t *sp;
23140Sstevel@tonic-gate unsigned next_minor;
23150Sstevel@tonic-gate client_handle_t client_handle;
23160Sstevel@tonic-gate
23170Sstevel@tonic-gate if ((sp = cs_get_sp(socket_num)) == NULL)
23180Sstevel@tonic-gate return (0);
23190Sstevel@tonic-gate
23200Sstevel@tonic-gate /*
23210Sstevel@tonic-gate * Get the next available minor number that we can use. We use the
23220Sstevel@tonic-gate * next_cl_minor number as a hint to cs_create_next_client_minor
23230Sstevel@tonic-gate * and in most cases this will be the minor number we get back.
23240Sstevel@tonic-gate * If for some reason we can't get a minor number, return an error.
23250Sstevel@tonic-gate * The only way we could get an error would be if there are
23260Sstevel@tonic-gate * already the maximum number of clients for this socket. Since
23270Sstevel@tonic-gate * the maximum number of clients per socket is pretty large,
23280Sstevel@tonic-gate * this error is unlikely to occur.
23290Sstevel@tonic-gate */
23300Sstevel@tonic-gate if (!(next_minor =
23310Sstevel@tonic-gate cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
23320Sstevel@tonic-gate return (0);
23330Sstevel@tonic-gate
23340Sstevel@tonic-gate /*
23350Sstevel@tonic-gate * Got a new client minor number, now create a new client handle.
23360Sstevel@tonic-gate */
23370Sstevel@tonic-gate client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
23380Sstevel@tonic-gate CS_GET_FUNCTION_NUMBER(socket_num),
23390Sstevel@tonic-gate next_minor);
23400Sstevel@tonic-gate
23410Sstevel@tonic-gate /*
23420Sstevel@tonic-gate * If this client handle exists, then we have an internal
23430Sstevel@tonic-gate * error; this should never happen, BTW. This is really
23440Sstevel@tonic-gate * a double-check on the cs_create_next_client_minor
23450Sstevel@tonic-gate * function, which also calls cs_find_client.
23460Sstevel@tonic-gate */
23470Sstevel@tonic-gate if (cs_find_client(client_handle, NULL)) {
23480Sstevel@tonic-gate cmn_err(CE_CONT,
23490Sstevel@tonic-gate "cs_create_client_handle: duplicate client handle 0x%x\n",
23500Sstevel@tonic-gate (int)client_handle);
23510Sstevel@tonic-gate return (0);
23520Sstevel@tonic-gate }
23530Sstevel@tonic-gate
23540Sstevel@tonic-gate /*
23550Sstevel@tonic-gate * If we don't have any clients on this socket yet, create
23560Sstevel@tonic-gate * a new client and hang it on the socket client list.
23570Sstevel@tonic-gate */
23580Sstevel@tonic-gate if (!sp->client_list) {
23590Sstevel@tonic-gate sp->client_list = cclp;
23600Sstevel@tonic-gate clp = sp->client_list;
23610Sstevel@tonic-gate } else {
23620Sstevel@tonic-gate /*
23630Sstevel@tonic-gate * There are other clients on this socket, so look for
23640Sstevel@tonic-gate * the last client and add our new client after it.
23650Sstevel@tonic-gate */
23660Sstevel@tonic-gate clp = sp->client_list;
23670Sstevel@tonic-gate while (clp->next) {
23680Sstevel@tonic-gate clp = clp->next;
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate
23710Sstevel@tonic-gate clp->next = cclp;
23720Sstevel@tonic-gate clp->next->prev = clp;
23730Sstevel@tonic-gate clp = clp->next;
23740Sstevel@tonic-gate } /* if (!sp->client_list) */
23750Sstevel@tonic-gate
23760Sstevel@tonic-gate /*
23770Sstevel@tonic-gate * Assign the new client handle to this new client structure.
23780Sstevel@tonic-gate */
23790Sstevel@tonic-gate clp->client_handle = client_handle;
23800Sstevel@tonic-gate
23810Sstevel@tonic-gate /*
23820Sstevel@tonic-gate * Create the next available client minor number for this socket
23830Sstevel@tonic-gate * and save it away.
23840Sstevel@tonic-gate */
23850Sstevel@tonic-gate sp->next_cl_minor =
23860Sstevel@tonic-gate cs_create_next_client_minor(socket_num, sp->next_cl_minor);
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate return (client_handle);
23890Sstevel@tonic-gate }
23900Sstevel@tonic-gate
23910Sstevel@tonic-gate /*
23920Sstevel@tonic-gate * cs_clear_superclient_lock - clears the global "super-client" lock
23930Sstevel@tonic-gate *
23940Sstevel@tonic-gate * Note: this function uses the cs_globals.global_lock so observe proper
23950Sstevel@tonic-gate * nexting of locks!!
23960Sstevel@tonic-gate */
23970Sstevel@tonic-gate static void
cs_clear_superclient_lock(int super_client)23980Sstevel@tonic-gate cs_clear_superclient_lock(int super_client)
23990Sstevel@tonic-gate {
24000Sstevel@tonic-gate
24010Sstevel@tonic-gate /*
24020Sstevel@tonic-gate * If this was a "super-client" registering then we need
24030Sstevel@tonic-gate * to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
24040Sstevel@tonic-gate * so that other "super-clients" can register.
24050Sstevel@tonic-gate */
24060Sstevel@tonic-gate if (super_client == CLIENT_SUPER_CLIENT) {
24070Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
24080Sstevel@tonic-gate cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
24090Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
24100Sstevel@tonic-gate }
24110Sstevel@tonic-gate }
24120Sstevel@tonic-gate
24130Sstevel@tonic-gate /*
24140Sstevel@tonic-gate * ==== event handling section ====
24150Sstevel@tonic-gate */
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate /*
24180Sstevel@tonic-gate * cs_event - CS event hi-priority callback handler
24190Sstevel@tonic-gate *
24200Sstevel@tonic-gate * This function gets called by SS and is passed the event type in
24210Sstevel@tonic-gate * the "event" argument, and the socket number in the "sn"
24220Sstevel@tonic-gate * argument. The "sn" argument is a valid logical socket
24230Sstevel@tonic-gate * number for all events except the PCE_SS_READY event.
24240Sstevel@tonic-gate *
24250Sstevel@tonic-gate * The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
24260Sstevel@tonic-gate * are never called at high priority. These events return
24270Sstevel@tonic-gate * the following return codes:
24280Sstevel@tonic-gate *
24290Sstevel@tonic-gate * CS_SUCCESS - operation sucessful
24300Sstevel@tonic-gate * CS_BAD_SOCKET - unable to complete operation
24310Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - bad subfunction of
24320Sstevel@tonic-gate * PCE_SS_INIT_STATE
24330Sstevel@tonic-gate *
24340Sstevel@tonic-gate * The caller MUST look at these return codes!
24350Sstevel@tonic-gate *
24360Sstevel@tonic-gate * This function is called at high-priority interrupt time for standard
24370Sstevel@tonic-gate * Card Services events, and the only standard Card Services
24380Sstevel@tonic-gate * event that it handles directly is the CS_EVENT_CARD_REMOVAL
24390Sstevel@tonic-gate * event, which gets shuttled right into the client's event
24400Sstevel@tonic-gate * handler. All other events are just queued up and the socket
24410Sstevel@tonic-gate * event thread is woken up via the soft interrupt handler.
24420Sstevel@tonic-gate * Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
24430Sstevel@tonic-gate * event field, since the CS card insertion/card ready processing
24440Sstevel@tonic-gate * code is responsible for setting this event in a client's
24450Sstevel@tonic-gate * event field.
24460Sstevel@tonic-gate *
24470Sstevel@tonic-gate */
24480Sstevel@tonic-gate /*ARGSUSED*/
24490Sstevel@tonic-gate uint32_t
cs_event(event_t event,uint32_t sn,uint32_t arg)24500Sstevel@tonic-gate cs_event(event_t event, uint32_t sn, uint32_t arg)
24510Sstevel@tonic-gate {
24520Sstevel@tonic-gate client_t *client;
24530Sstevel@tonic-gate cs_socket_t *sp;
24540Sstevel@tonic-gate client_types_t *ct;
24550Sstevel@tonic-gate uint32_t ret = CS_SUCCESS;
24560Sstevel@tonic-gate
24570Sstevel@tonic-gate /*
24580Sstevel@tonic-gate * Handle special SS<->CS events
24590Sstevel@tonic-gate */
24600Sstevel@tonic-gate switch (event) {
24610Sstevel@tonic-gate case PCE_SS_INIT_STATE:
24620Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
24630Sstevel@tonic-gate switch (sn) {
24640Sstevel@tonic-gate case PCE_SS_STATE_INIT:
24650Sstevel@tonic-gate if ((ret = cs_ss_init()) == CS_SUCCESS)
24660Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
24670Sstevel@tonic-gate break;
24680Sstevel@tonic-gate case PCE_SS_STATE_DEINIT:
24690Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
24700Sstevel@tonic-gate break;
24710Sstevel@tonic-gate default:
24720Sstevel@tonic-gate ret = CS_UNSUPPORTED_FUNCTION;
24730Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
24740Sstevel@tonic-gate "directive: 0x%x\n", sn);
24750Sstevel@tonic-gate break;
24760Sstevel@tonic-gate } /* switch (sn) */
24770Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
24780Sstevel@tonic-gate return (ret);
24790Sstevel@tonic-gate case PCE_ADD_SOCKET:
24800Sstevel@tonic-gate return (cs_add_socket(sn));
24810Sstevel@tonic-gate case PCE_DROP_SOCKET:
24820Sstevel@tonic-gate return (cs_drop_socket(sn));
24830Sstevel@tonic-gate } /* switch (event) */
24840Sstevel@tonic-gate
24850Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
24860Sstevel@tonic-gate return (CS_BAD_SOCKET);
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate /*
24890Sstevel@tonic-gate * Check to see if CS wants to unload - we do this since it's possible
24900Sstevel@tonic-gate * to disable certain sockets. Do NOT acquire any locks yet.
24910Sstevel@tonic-gate */
24920Sstevel@tonic-gate if (sp->flags & SOCKET_UNLOAD_MODULE) {
24930Sstevel@tonic-gate if (event == PCE_CARD_INSERT)
24940Sstevel@tonic-gate cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
24950Sstevel@tonic-gate "remove card\n", sn);
24960Sstevel@tonic-gate return (CS_SUCCESS);
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate
24990Sstevel@tonic-gate mutex_enter(&sp->lock);
25000Sstevel@tonic-gate
25010Sstevel@tonic-gate #ifdef CS_DEBUG
25020Sstevel@tonic-gate if (cs_debug > 1) {
25030Sstevel@tonic-gate event2text_t event2text;
25040Sstevel@tonic-gate
25050Sstevel@tonic-gate event2text.event = event;
25060Sstevel@tonic-gate (void) cs_event2text(&event2text, 0);
25070Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
25080Sstevel@tonic-gate event2text.text, (int)event, (int)sn);
25090Sstevel@tonic-gate }
25100Sstevel@tonic-gate #endif
25110Sstevel@tonic-gate
25120Sstevel@tonic-gate /*
25130Sstevel@tonic-gate * Convert SS events to CS events; handle the PRR if necessary.
25140Sstevel@tonic-gate */
25150Sstevel@tonic-gate sp->events |= ss_to_cs_events(sp, event);
25160Sstevel@tonic-gate
25170Sstevel@tonic-gate /*
25180Sstevel@tonic-gate * We want to maintain the required event dispatching order as
25190Sstevel@tonic-gate * specified in the PCMCIA spec, so we cycle through all
25200Sstevel@tonic-gate * clients on this socket to make sure that they are
25210Sstevel@tonic-gate * notified in the correct order of any high-priority
25220Sstevel@tonic-gate * events.
25230Sstevel@tonic-gate */
25240Sstevel@tonic-gate ct = &client_types[0];
25250Sstevel@tonic-gate while (ct) {
25260Sstevel@tonic-gate /*
25270Sstevel@tonic-gate * Point to the head of the client list for this socket, and go
25280Sstevel@tonic-gate * through each client to set up the client events as well as
25290Sstevel@tonic-gate * call the client's event handler directly if we have a high
25300Sstevel@tonic-gate * priority event that we need to tell the client about.
25310Sstevel@tonic-gate */
25320Sstevel@tonic-gate client = sp->client_list;
25330Sstevel@tonic-gate
25340Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) {
25350Sstevel@tonic-gate client_t *clp = NULL;
25360Sstevel@tonic-gate
25370Sstevel@tonic-gate while (client) {
25380Sstevel@tonic-gate clp = client;
25390Sstevel@tonic-gate client = client->next;
25400Sstevel@tonic-gate }
25410Sstevel@tonic-gate client = clp;
25420Sstevel@tonic-gate }
25430Sstevel@tonic-gate
25440Sstevel@tonic-gate while (client) {
25450Sstevel@tonic-gate client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
25460Sstevel@tonic-gate (client->event_mask | client->global_mask));
25470Sstevel@tonic-gate if (client->flags & ct->type) {
25480Sstevel@tonic-gate #ifdef CS_DEBUG
25490Sstevel@tonic-gate if (cs_debug > 1) {
25500Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
25510Sstevel@tonic-gate "events 0x%x flags 0x%x\n",
25520Sstevel@tonic-gate sn, client->driver_name,
25530Sstevel@tonic-gate (int)client->events,
25540Sstevel@tonic-gate (int)client->flags);
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate #endif
25570Sstevel@tonic-gate
25580Sstevel@tonic-gate /*
25590Sstevel@tonic-gate * Handle the suspend and card removal events
25600Sstevel@tonic-gate * specially here so that the client can receive
25610Sstevel@tonic-gate * these events at high-priority.
25620Sstevel@tonic-gate */
25630Sstevel@tonic-gate if (client->events & CS_EVENT_PM_SUSPEND) {
25640Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
25650Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
25660Sstevel@tonic-gate CS_EVENT_PRI_HIGH);
25670Sstevel@tonic-gate } /* if (CLIENT_CARD_INSERTED) */
25680Sstevel@tonic-gate client->events &= ~CS_EVENT_PM_SUSPEND;
25690Sstevel@tonic-gate } /* if (CS_EVENT_PM_SUSPEND) */
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate if (client->events & CS_EVENT_CARD_REMOVAL) {
25720Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
25730Sstevel@tonic-gate client->flags &= ~(CLIENT_CARD_INSERTED |
25740Sstevel@tonic-gate CLIENT_SENT_INSERTION);
25750Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client,
25760Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL,
25770Sstevel@tonic-gate CS_EVENT_PRI_HIGH);
25780Sstevel@tonic-gate /*
25790Sstevel@tonic-gate * Check to see if the client wants low priority
25800Sstevel@tonic-gate * removal events as well.
25810Sstevel@tonic-gate */
25820Sstevel@tonic-gate if ((client->event_mask | client->global_mask) &
25830Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL_LOWP) {
25840Sstevel@tonic-gate client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
25850Sstevel@tonic-gate }
25860Sstevel@tonic-gate } /* if (CLIENT_CARD_INSERTED) */
25870Sstevel@tonic-gate client->events &= ~CS_EVENT_CARD_REMOVAL;
25880Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */
25890Sstevel@tonic-gate
25900Sstevel@tonic-gate } /* if (ct->type) */
25910Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) {
25920Sstevel@tonic-gate client = client->prev;
25930Sstevel@tonic-gate } else {
25940Sstevel@tonic-gate client = client->next;
25950Sstevel@tonic-gate }
25960Sstevel@tonic-gate } /* while (client) */
25970Sstevel@tonic-gate
25980Sstevel@tonic-gate ct = ct->next;
25990Sstevel@tonic-gate } /* while (ct) */
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate /*
26020Sstevel@tonic-gate * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
26030Sstevel@tonic-gate * handler will wakeup this socket's event thread.
26040Sstevel@tonic-gate */
26050Sstevel@tonic-gate if (sp->events)
26060Sstevel@tonic-gate sp->flags |= SOCKET_NEEDS_THREAD;
26070Sstevel@tonic-gate
26080Sstevel@tonic-gate /*
26090Sstevel@tonic-gate * Fire off a soft interrupt that will cause the socket thread
26100Sstevel@tonic-gate * to be woken up and any remaining events to be sent to
26110Sstevel@tonic-gate * the clients on this socket.
26120Sstevel@tonic-gate */
26130Sstevel@tonic-gate if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
26140Sstevel@tonic-gate !(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
26150Sstevel@tonic-gate ddi_trigger_softintr(sp->softint_id);
26160Sstevel@tonic-gate
26170Sstevel@tonic-gate mutex_exit(&sp->lock);
26180Sstevel@tonic-gate
26190Sstevel@tonic-gate return (CS_SUCCESS);
26200Sstevel@tonic-gate }
26210Sstevel@tonic-gate
26220Sstevel@tonic-gate /*
26230Sstevel@tonic-gate * cs_card_insertion - handle card insertion and card ready events
26240Sstevel@tonic-gate *
26250Sstevel@tonic-gate * We read the CIS, if present, and store it away, then tell SS that
26260Sstevel@tonic-gate * we have read the CIS and it's ready to be parsed. Since card
26270Sstevel@tonic-gate * insertion and card ready events are pretty closely intertwined,
26280Sstevel@tonic-gate * we handle both here. For card ready events that are not the
26290Sstevel@tonic-gate * result of a card insertion event, we expect that the caller has
26300Sstevel@tonic-gate * already done the appropriate processing and that we will not be
26310Sstevel@tonic-gate * called unless we received a card ready event right after a card
26320Sstevel@tonic-gate * insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
26330Sstevel@tonic-gate * sp->thread_state was set or if we get a CARD_READY event right
26340Sstevel@tonic-gate * after a CARD_INSERTION event.
26350Sstevel@tonic-gate *
26360Sstevel@tonic-gate * calling: sp - pointer to socket structure
26370Sstevel@tonic-gate * event - event to handle, one of:
26380Sstevel@tonic-gate * CS_EVENT_CARD_INSERTION
26390Sstevel@tonic-gate * CS_EVENT_CARD_READY
26400Sstevel@tonic-gate * CS_EVENT_SS_UPDATED
26410Sstevel@tonic-gate */
26420Sstevel@tonic-gate static int
cs_card_insertion(cs_socket_t * sp,event_t event)26430Sstevel@tonic-gate cs_card_insertion(cs_socket_t *sp, event_t event)
26440Sstevel@tonic-gate {
26450Sstevel@tonic-gate int ret;
26460Sstevel@tonic-gate
26470Sstevel@tonic-gate /*
26480Sstevel@tonic-gate * Since we're only called while waiting for the card insertion
26490Sstevel@tonic-gate * and card ready sequence to occur, we may have a pending
26500Sstevel@tonic-gate * card ready timer that hasn't gone off yet if we got a
26510Sstevel@tonic-gate * real card ready event.
26520Sstevel@tonic-gate */
26530Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id);
26540Sstevel@tonic-gate
26550Sstevel@tonic-gate #ifdef CS_DEBUG
26560Sstevel@tonic-gate if (cs_debug > 1) {
26570Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
26580Sstevel@tonic-gate (int)event, sp->socket_num);
26590Sstevel@tonic-gate }
26600Sstevel@tonic-gate #endif
26610Sstevel@tonic-gate
26620Sstevel@tonic-gate /*
26630Sstevel@tonic-gate * Handle card insertion processing
26640Sstevel@tonic-gate */
26650Sstevel@tonic-gate if (event & CS_EVENT_CARD_INSERTION) {
26660Sstevel@tonic-gate set_socket_t set_socket;
26670Sstevel@tonic-gate get_ss_status_t gs;
26680Sstevel@tonic-gate
26690Sstevel@tonic-gate /*
26700Sstevel@tonic-gate * Check to be sure that we have a valid CIS window
26710Sstevel@tonic-gate */
26720Sstevel@tonic-gate if (!SOCKET_HAS_CIS_WINDOW(sp)) {
26730Sstevel@tonic-gate cmn_err(CE_CONT,
26740Sstevel@tonic-gate "cs_card_insertion: socket %d has no "
26750Sstevel@tonic-gate "CIS window\n",
26760Sstevel@tonic-gate sp->socket_num);
26770Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
26780Sstevel@tonic-gate }
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate /*
26810Sstevel@tonic-gate * Apply power to the socket, enable card detect and card ready
26820Sstevel@tonic-gate * events, then reset the socket.
26830Sstevel@tonic-gate */
26840Sstevel@tonic-gate mutex_enter(&sp->lock);
26850Sstevel@tonic-gate sp->event_mask = (CS_EVENT_CARD_REMOVAL |
26860Sstevel@tonic-gate CS_EVENT_CARD_READY);
26870Sstevel@tonic-gate mutex_exit(&sp->lock);
26880Sstevel@tonic-gate set_socket.socket = sp->socket_num;
26890Sstevel@tonic-gate set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
26900Sstevel@tonic-gate set_socket.IREQRouting = 0;
26910Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
26920Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */
26930Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */
26940Sstevel@tonic-gate
26950Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
26960Sstevel@tonic-gate &set_socket.VccLevel);
26970Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
26980Sstevel@tonic-gate &set_socket.Vpp1Level);
26990Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
27000Sstevel@tonic-gate &set_socket.Vpp2Level);
27010Sstevel@tonic-gate
27020Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
27030Sstevel@tonic-gate cmn_err(CE_CONT,
27040Sstevel@tonic-gate "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
27050Sstevel@tonic-gate sp->socket_num, ret);
27060Sstevel@tonic-gate return (ret);
27070Sstevel@tonic-gate }
27080Sstevel@tonic-gate
27090Sstevel@tonic-gate /*
27100Sstevel@tonic-gate * Clear the ready and ready_timeout events since they are now
27110Sstevel@tonic-gate * bogus since we're about to reset the socket.
27120Sstevel@tonic-gate * XXX - should these be cleared right after the RESET??
27130Sstevel@tonic-gate */
27140Sstevel@tonic-gate mutex_enter(&sp->lock);
27150Sstevel@tonic-gate
27160Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
27170Sstevel@tonic-gate mutex_exit(&sp->lock);
27180Sstevel@tonic-gate
27190Sstevel@tonic-gate SocketServices(SS_ResetSocket, sp->socket_num,
27200Sstevel@tonic-gate RESET_MODE_CARD_ONLY);
27210Sstevel@tonic-gate
27220Sstevel@tonic-gate /*
27230Sstevel@tonic-gate * We are required by the PCMCIA spec to wait some number of
27240Sstevel@tonic-gate * milliseconds after reset before we access the card, so
27250Sstevel@tonic-gate * we set up a timer here that will wake us up and allow us
27260Sstevel@tonic-gate * to continue with our card initialization.
27270Sstevel@tonic-gate */
27280Sstevel@tonic-gate mutex_enter(&sp->lock);
27290Sstevel@tonic-gate sp->thread_state |= SOCKET_RESET_TIMER;
27300Sstevel@tonic-gate (void) timeout(cs_ready_timeout, sp,
27310Sstevel@tonic-gate drv_usectohz(cs_reset_timeout_time * 1000));
27320Sstevel@tonic-gate cv_wait(&sp->reset_cv, &sp->lock);
27330Sstevel@tonic-gate sp->thread_state &= ~SOCKET_RESET_TIMER;
27340Sstevel@tonic-gate mutex_exit(&sp->lock);
27350Sstevel@tonic-gate
27360Sstevel@tonic-gate #ifdef CS_DEBUG
27370Sstevel@tonic-gate if (cs_debug > 2) {
27380Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
27390Sstevel@tonic-gate "for %d mS sp->events 0x%x\n",
27400Sstevel@tonic-gate sp->socket_num, cs_reset_timeout_time, (int)sp->events);
27410Sstevel@tonic-gate }
27420Sstevel@tonic-gate #endif
27430Sstevel@tonic-gate
27440Sstevel@tonic-gate /*
27450Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it
27460Sstevel@tonic-gate * means that we likely got CD line bounce on the
27470Sstevel@tonic-gate * insertion, so terminate this processing.
27480Sstevel@tonic-gate */
27490Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) {
27500Sstevel@tonic-gate #ifdef CS_DEBUG
27510Sstevel@tonic-gate if (cs_debug > 0) {
27520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d "
27530Sstevel@tonic-gate "CS_EVENT_CARD_REMOVAL event "
27540Sstevel@tonic-gate "terminating insertion "
27550Sstevel@tonic-gate "processing\n",
27560Sstevel@tonic-gate sp->socket_num);
27570Sstevel@tonic-gate }
27580Sstevel@tonic-gate #endif
27590Sstevel@tonic-gate return (CS_SUCCESS);
27600Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */
27610Sstevel@tonic-gate
27620Sstevel@tonic-gate /*
27630Sstevel@tonic-gate * If we got a card ready event after the reset, then don't
27640Sstevel@tonic-gate * bother setting up a card ready timer, since we'll blast
27650Sstevel@tonic-gate * right on through to the card ready processing.
27660Sstevel@tonic-gate * Get the current card status to see if it's ready; if it
27670Sstevel@tonic-gate * is, we probably won't get a card ready event.
27680Sstevel@tonic-gate */
27690Sstevel@tonic-gate gs.socket = sp->socket_num;
27700Sstevel@tonic-gate gs.CardState = 0;
27710Sstevel@tonic-gate if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) {
27720Sstevel@tonic-gate cmn_err(CE_CONT,
27730Sstevel@tonic-gate "cs_card_insertion: socket %d SS_GetStatus failure %d\n",
27740Sstevel@tonic-gate sp->socket_num, ret);
27750Sstevel@tonic-gate return (ret);
27760Sstevel@tonic-gate }
27770Sstevel@tonic-gate
27780Sstevel@tonic-gate mutex_enter(&sp->lock);
27790Sstevel@tonic-gate if ((sp->events & CS_EVENT_CARD_READY) ||
27800Sstevel@tonic-gate (gs.CardState & SBM_RDYBSY)) {
27810Sstevel@tonic-gate event = CS_EVENT_CARD_READY;
27820Sstevel@tonic-gate #ifdef CS_DEBUG
27830Sstevel@tonic-gate if (cs_debug > 1) {
27840Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d card "
27850Sstevel@tonic-gate "READY\n", sp->socket_num);
27860Sstevel@tonic-gate }
27870Sstevel@tonic-gate #endif
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate } else {
27900Sstevel@tonic-gate #ifdef CS_DEBUG
27910Sstevel@tonic-gate if (cs_debug > 1) {
27920Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d setting "
27930Sstevel@tonic-gate "READY timer\n", sp->socket_num);
27940Sstevel@tonic-gate }
27950Sstevel@tonic-gate #endif
27960Sstevel@tonic-gate
27970Sstevel@tonic-gate sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp,
27980Sstevel@tonic-gate READY_TIMEOUT_TIME);
27990Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_FOR_READY;
28000Sstevel@tonic-gate
28010Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */
28020Sstevel@tonic-gate
28030Sstevel@tonic-gate mutex_exit(&sp->lock);
28040Sstevel@tonic-gate
28050Sstevel@tonic-gate } /* if (CS_EVENT_CARD_INSERTION) */
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate /*
28080Sstevel@tonic-gate * Handle card ready processing. This is only card ready processing
28090Sstevel@tonic-gate * for card ready events in conjunction with a card insertion.
28100Sstevel@tonic-gate */
28110Sstevel@tonic-gate if (event == CS_EVENT_CARD_READY) {
28120Sstevel@tonic-gate get_socket_t get_socket;
28130Sstevel@tonic-gate set_socket_t set_socket;
28140Sstevel@tonic-gate
28150Sstevel@tonic-gate /*
28160Sstevel@tonic-gate * The only events that we want to see now are card removal
28170Sstevel@tonic-gate * events.
28180Sstevel@tonic-gate */
28190Sstevel@tonic-gate mutex_enter(&sp->lock);
28200Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_REMOVAL;
28210Sstevel@tonic-gate mutex_exit(&sp->lock);
28220Sstevel@tonic-gate get_socket.socket = sp->socket_num;
28230Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
28240Sstevel@tonic-gate cmn_err(CE_CONT,
28250Sstevel@tonic-gate "cs_card_insertion: socket %d SS_GetSocket failed\n",
28260Sstevel@tonic-gate sp->socket_num);
28270Sstevel@tonic-gate return (CS_BAD_SOCKET);
28280Sstevel@tonic-gate }
28290Sstevel@tonic-gate
28300Sstevel@tonic-gate set_socket.socket = sp->socket_num;
28310Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD;
28320Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
28330Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
28340Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
28350Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting;
28360Sstevel@tonic-gate set_socket.IFType = get_socket.IFType;
28370Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
28380Sstevel@tonic-gate /* XXX (is ~0 correct here?) to reset latched values */
28390Sstevel@tonic-gate set_socket.State = (unsigned)~0;
28400Sstevel@tonic-gate
28410Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
28420Sstevel@tonic-gate cmn_err(CE_CONT,
28430Sstevel@tonic-gate "cs_card_insertion: socket %d SS_SetSocket failed\n",
28440Sstevel@tonic-gate sp->socket_num);
28450Sstevel@tonic-gate
28460Sstevel@tonic-gate return (CS_BAD_SOCKET);
28470Sstevel@tonic-gate }
28480Sstevel@tonic-gate
28490Sstevel@tonic-gate /*
28500Sstevel@tonic-gate * Grab the cis_lock mutex to protect the CIS-to-be and
28510Sstevel@tonic-gate * the CIS window, then fire off the CIS parser to
28520Sstevel@tonic-gate * create a local copy of the card's CIS.
28530Sstevel@tonic-gate */
28540Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
28550Sstevel@tonic-gate
28560Sstevel@tonic-gate if ((ret = cs_create_cis(sp)) != CS_SUCCESS) {
28570Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
28580Sstevel@tonic-gate return (ret);
28590Sstevel@tonic-gate }
28600Sstevel@tonic-gate
28610Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
28620Sstevel@tonic-gate
28630Sstevel@tonic-gate /*
28640Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it
28650Sstevel@tonic-gate * means that we likely got CD line bounce on the
28660Sstevel@tonic-gate * insertion, so destroy the CIS and terminate this
28670Sstevel@tonic-gate * processing. We'll get called back to handle the
28680Sstevel@tonic-gate * insertion again later.
28690Sstevel@tonic-gate */
28700Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) {
28710Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
28720Sstevel@tonic-gate (void) cs_destroy_cis(sp);
28730Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
28740Sstevel@tonic-gate } else {
28750Sstevel@tonic-gate /*
28760Sstevel@tonic-gate * Schedule the call to the Socket Services work thread.
28770Sstevel@tonic-gate */
28780Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock);
28790Sstevel@tonic-gate sp->ss_thread_state |= SOCKET_THREAD_CSCISInit;
28800Sstevel@tonic-gate cv_broadcast(&sp->ss_thread_cv);
28810Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock);
28820Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */
28830Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */
28840Sstevel@tonic-gate
28850Sstevel@tonic-gate /*
28860Sstevel@tonic-gate * Socket Services has parsed the CIS and has done any other
28870Sstevel@tonic-gate * work to get the client driver loaded and attached if
28880Sstevel@tonic-gate * necessary, so setup the per-client state.
28890Sstevel@tonic-gate */
28900Sstevel@tonic-gate if (event == CS_EVENT_SS_UPDATED) {
28910Sstevel@tonic-gate client_t *client;
28920Sstevel@tonic-gate
28930Sstevel@tonic-gate /*
28940Sstevel@tonic-gate * Now that we and SS are done handling the card insertion
28950Sstevel@tonic-gate * semantics, go through each client on this socket and set
28960Sstevel@tonic-gate * the CS_EVENT_CARD_INSERTION event in each client's event
28970Sstevel@tonic-gate * field. We do this here instead of in cs_event so that
28980Sstevel@tonic-gate * when a client gets a CS_EVENT_CARD_INSERTION event, the
28990Sstevel@tonic-gate * card insertion and ready processing has already been done
29000Sstevel@tonic-gate * and SocketServices has had a chance to create a dip for
29010Sstevel@tonic-gate * the card in this socket.
29020Sstevel@tonic-gate */
29030Sstevel@tonic-gate mutex_enter(&sp->lock);
29040Sstevel@tonic-gate client = sp->client_list;
29050Sstevel@tonic-gate while (client) {
29060Sstevel@tonic-gate client->events |= (CS_EVENT_CARD_INSERTION &
29070Sstevel@tonic-gate (client->event_mask | client->global_mask));
29080Sstevel@tonic-gate client = client->next;
29090Sstevel@tonic-gate } /* while (client) */
29100Sstevel@tonic-gate
29110Sstevel@tonic-gate mutex_exit(&sp->lock);
29120Sstevel@tonic-gate
29130Sstevel@tonic-gate } /* if (CS_EVENT_SS_UPDATED) */
29140Sstevel@tonic-gate
29150Sstevel@tonic-gate return (CS_SUCCESS);
29160Sstevel@tonic-gate }
29170Sstevel@tonic-gate
29180Sstevel@tonic-gate /*
29190Sstevel@tonic-gate * cs_card_removal - handle card removal events
29200Sstevel@tonic-gate *
29210Sstevel@tonic-gate * Destroy the CIS.
29220Sstevel@tonic-gate *
29230Sstevel@tonic-gate * calling: sp - pointer to socket structure
29240Sstevel@tonic-gate *
29250Sstevel@tonic-gate */
29260Sstevel@tonic-gate static int
cs_card_removal(cs_socket_t * sp)29270Sstevel@tonic-gate cs_card_removal(cs_socket_t *sp)
29280Sstevel@tonic-gate {
29290Sstevel@tonic-gate set_socket_t set_socket;
29300Sstevel@tonic-gate int ret;
29310Sstevel@tonic-gate
29320Sstevel@tonic-gate #ifdef CS_DEBUG
29330Sstevel@tonic-gate if (cs_debug > 0) {
29340Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num);
29350Sstevel@tonic-gate }
29360Sstevel@tonic-gate #endif
29370Sstevel@tonic-gate
29380Sstevel@tonic-gate /*
29390Sstevel@tonic-gate * Remove any pending card ready timer
29400Sstevel@tonic-gate */
29410Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id);
29420Sstevel@tonic-gate
29430Sstevel@tonic-gate /*
29440Sstevel@tonic-gate * Clear various flags so that everyone else knows that there's
29450Sstevel@tonic-gate * nothing on this socket anymore. Note that we clear the
29460Sstevel@tonic-gate * SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
29470Sstevel@tonic-gate * ss_to_cs_events event mapping function.
29480Sstevel@tonic-gate */
29490Sstevel@tonic-gate mutex_enter(&sp->lock);
29500Sstevel@tonic-gate sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER);
29510Sstevel@tonic-gate
29520Sstevel@tonic-gate /*
29530Sstevel@tonic-gate * Turn off socket power and set the socket back to memory mode.
29540Sstevel@tonic-gate * Disable all socket events except for CARD_INSERTION events.
29550Sstevel@tonic-gate */
29560Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION;
29570Sstevel@tonic-gate mutex_exit(&sp->lock);
29580Sstevel@tonic-gate set_socket.socket = sp->socket_num;
29590Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD;
29600Sstevel@tonic-gate set_socket.IREQRouting = 0;
29610Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
29620Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */
29630Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */
29640Sstevel@tonic-gate
29650Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
29660Sstevel@tonic-gate &set_socket.VccLevel);
29670Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
29680Sstevel@tonic-gate &set_socket.Vpp1Level);
29690Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
29700Sstevel@tonic-gate &set_socket.Vpp2Level);
29710Sstevel@tonic-gate
29720Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
29730Sstevel@tonic-gate cmn_err(CE_CONT,
29740Sstevel@tonic-gate "cs_card_removal: socket %d SS_SetSocket failure %d\n",
29750Sstevel@tonic-gate sp->socket_num, ret);
29760Sstevel@tonic-gate return (ret);
29770Sstevel@tonic-gate }
29780Sstevel@tonic-gate
29790Sstevel@tonic-gate #ifdef CS_DEBUG
29800Sstevel@tonic-gate if (cs_debug > 2) {
29810Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: socket %d "
29820Sstevel@tonic-gate "calling cs_destroy_cis\n",
29830Sstevel@tonic-gate sp->socket_num);
29840Sstevel@tonic-gate }
29850Sstevel@tonic-gate #endif
29860Sstevel@tonic-gate
29870Sstevel@tonic-gate /*
29880Sstevel@tonic-gate * Destroy the CIS and tell Socket Services that we're done
29890Sstevel@tonic-gate * handling the card removal event.
29900Sstevel@tonic-gate */
29910Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
29920Sstevel@tonic-gate (void) cs_destroy_cis(sp);
29930Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
29940Sstevel@tonic-gate
29950Sstevel@tonic-gate #ifdef CS_DEBUG
29960Sstevel@tonic-gate if (cs_debug > 2) {
29970Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n");
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate #endif
30000Sstevel@tonic-gate
30010Sstevel@tonic-gate SocketServices(CSCardRemoved, sp->socket_num);
30020Sstevel@tonic-gate
30030Sstevel@tonic-gate return (CS_SUCCESS);
30040Sstevel@tonic-gate }
30050Sstevel@tonic-gate
30060Sstevel@tonic-gate /*
30070Sstevel@tonic-gate * ss_to_cs_events - convert Socket Services events to Card Services event
30080Sstevel@tonic-gate * masks; this function will not read the PRR if the
30090Sstevel@tonic-gate * socket is in IO mode; this happens in cs_event_thread
30100Sstevel@tonic-gate *
30110Sstevel@tonic-gate * This function returns a bit mask of events.
30120Sstevel@tonic-gate *
30130Sstevel@tonic-gate * Note that we do some simple hysterious on card insertion and card removal
30140Sstevel@tonic-gate * events to prevent spurious insertion and removal events from being
30150Sstevel@tonic-gate * propogated down the chain.
30160Sstevel@tonic-gate */
30170Sstevel@tonic-gate static event_t
ss_to_cs_events(cs_socket_t * sp,event_t event)30180Sstevel@tonic-gate ss_to_cs_events(cs_socket_t *sp, event_t event)
30190Sstevel@tonic-gate {
30200Sstevel@tonic-gate event_t revent = 0;
30210Sstevel@tonic-gate
30220Sstevel@tonic-gate switch (event) {
30230Sstevel@tonic-gate case PCE_CARD_STATUS_CHANGE:
30240Sstevel@tonic-gate revent |= CS_EVENT_STATUS_CHANGE;
30250Sstevel@tonic-gate break;
30260Sstevel@tonic-gate case PCE_CARD_REMOVAL:
30270Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) {
30280Sstevel@tonic-gate sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO);
30290Sstevel@tonic-gate revent |= CS_EVENT_CARD_REMOVAL;
30300Sstevel@tonic-gate /*
30310Sstevel@tonic-gate * If we're processing a removal event, it makes
30320Sstevel@tonic-gate * no sense to keep any insertion or ready events,
30330Sstevel@tonic-gate * so nuke them here. This will not clear any
30340Sstevel@tonic-gate * insertion events in the per-client event field.
30350Sstevel@tonic-gate */
30360Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_INSERTION |
30370Sstevel@tonic-gate CS_EVENT_CARD_READY |
30380Sstevel@tonic-gate CS_EVENT_READY_TIMEOUT);
30390Sstevel@tonic-gate
30400Sstevel@tonic-gate /*
30410Sstevel@tonic-gate * We also don't need to wait for READY anymore since
30420Sstevel@tonic-gate * it probably won't show up, or if it does, it will
30430Sstevel@tonic-gate * be a bogus READY event as the card is sliding out
30440Sstevel@tonic-gate * of the socket. Since we never do a cv_wait on the
30450Sstevel@tonic-gate * card ready timer, it's OK for that timer to either
30460Sstevel@tonic-gate * never go off (via an UNTIMEOUT in cs_card_removal)
30470Sstevel@tonic-gate * or to go off but not do a cv_broadcast (since the
30480Sstevel@tonic-gate * SOCKET_WAIT_FOR_READY flag is cleared here).
30490Sstevel@tonic-gate */
30500Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
30510Sstevel@tonic-gate
30520Sstevel@tonic-gate }
30530Sstevel@tonic-gate break;
30540Sstevel@tonic-gate case PCE_CARD_INSERT:
30550Sstevel@tonic-gate if (!(sp->flags & SOCKET_CARD_INSERTED)) {
30560Sstevel@tonic-gate sp->flags |= SOCKET_CARD_INSERTED;
30570Sstevel@tonic-gate revent |= CS_EVENT_CARD_INSERTION;
30580Sstevel@tonic-gate }
30590Sstevel@tonic-gate break;
30600Sstevel@tonic-gate case PCE_CARD_READY:
30610Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED)
30620Sstevel@tonic-gate revent |= CS_EVENT_CARD_READY;
30630Sstevel@tonic-gate break;
30640Sstevel@tonic-gate case PCE_CARD_BATTERY_WARN:
30650Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED)
30660Sstevel@tonic-gate revent |= CS_EVENT_BATTERY_LOW;
30670Sstevel@tonic-gate break;
30680Sstevel@tonic-gate case PCE_CARD_BATTERY_DEAD:
30690Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED)
30700Sstevel@tonic-gate revent |= CS_EVENT_BATTERY_DEAD;
30710Sstevel@tonic-gate break;
30720Sstevel@tonic-gate case PCE_CARD_WRITE_PROTECT:
30730Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED)
30740Sstevel@tonic-gate revent |= CS_EVENT_WRITE_PROTECT;
30750Sstevel@tonic-gate break;
30760Sstevel@tonic-gate case PCE_PM_RESUME:
30770Sstevel@tonic-gate revent |= CS_EVENT_PM_RESUME;
30780Sstevel@tonic-gate break;
30790Sstevel@tonic-gate case PCE_PM_SUSPEND:
30800Sstevel@tonic-gate revent |= CS_EVENT_PM_SUSPEND;
30810Sstevel@tonic-gate break;
30820Sstevel@tonic-gate default:
30830Sstevel@tonic-gate cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n",
30840Sstevel@tonic-gate (int)event);
30850Sstevel@tonic-gate break;
30860Sstevel@tonic-gate } /* switch(event) */
30870Sstevel@tonic-gate
30880Sstevel@tonic-gate return (revent);
30890Sstevel@tonic-gate }
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate /*
30920Sstevel@tonic-gate * cs_ready_timeout - general purpose READY/BUSY and RESET timer
30930Sstevel@tonic-gate *
30940Sstevel@tonic-gate * Note that we really only expect one of the two events to be asserted when
30950Sstevel@tonic-gate * we are called. XXX - Perhaps this might be a problem later on??
30960Sstevel@tonic-gate *
30970Sstevel@tonic-gate * There is also the problem of cv_broadcast dropping the interrupt
30980Sstevel@tonic-gate * priority, even though we have our high-priority mutex held. If
30990Sstevel@tonic-gate * we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
31000Sstevel@tonic-gate * we get a high-priority interrupt during this time, the system will
31010Sstevel@tonic-gate * deadlock or panic. Thanks to Andy Banta for finding this out in
31020Sstevel@tonic-gate * the SPC/S (stc.c) driver.
31030Sstevel@tonic-gate *
31040Sstevel@tonic-gate * This callback routine can not grab the sp->client_lock mutex or deadlock
31050Sstevel@tonic-gate * will result.
31060Sstevel@tonic-gate */
31070Sstevel@tonic-gate void
cs_ready_timeout(void * arg)31080Sstevel@tonic-gate cs_ready_timeout(void *arg)
31090Sstevel@tonic-gate {
31100Sstevel@tonic-gate cs_socket_t *sp = arg;
31110Sstevel@tonic-gate kcondvar_t *cvp = NULL;
31120Sstevel@tonic-gate
31130Sstevel@tonic-gate mutex_enter(&sp->lock);
31140Sstevel@tonic-gate
31150Sstevel@tonic-gate if (sp->thread_state & SOCKET_RESET_TIMER) {
31160Sstevel@tonic-gate #ifdef CS_DEBUG
31170Sstevel@tonic-gate if (cs_debug > 1) {
31180Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n",
31190Sstevel@tonic-gate sp->socket_num);
31200Sstevel@tonic-gate }
31210Sstevel@tonic-gate #endif
31220Sstevel@tonic-gate
31230Sstevel@tonic-gate cvp = &sp->reset_cv;
31240Sstevel@tonic-gate }
31250Sstevel@tonic-gate
31260Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
31270Sstevel@tonic-gate sp->events |= CS_EVENT_READY_TIMEOUT;
31280Sstevel@tonic-gate cvp = &sp->thread_cv;
31290Sstevel@tonic-gate
31300Sstevel@tonic-gate #ifdef CS_DEBUG
31310Sstevel@tonic-gate if (cs_debug > 1) {
31320Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY "
31330Sstevel@tonic-gate "socket %d\n", sp->socket_num);
31340Sstevel@tonic-gate }
31350Sstevel@tonic-gate #endif
31360Sstevel@tonic-gate
31370Sstevel@tonic-gate }
31380Sstevel@tonic-gate
31390Sstevel@tonic-gate mutex_exit(&sp->lock);
31400Sstevel@tonic-gate
31410Sstevel@tonic-gate if (cvp)
31420Sstevel@tonic-gate cv_broadcast(cvp);
31430Sstevel@tonic-gate }
31440Sstevel@tonic-gate
31450Sstevel@tonic-gate /*
31460Sstevel@tonic-gate * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
31470Sstevel@tonic-gate */
31480Sstevel@tonic-gate /* ARGSUSED */
31490Sstevel@tonic-gate void
cs_event_softintr_timeout(void * arg)31500Sstevel@tonic-gate cs_event_softintr_timeout(void *arg)
31510Sstevel@tonic-gate {
31520Sstevel@tonic-gate
31530Sstevel@tonic-gate /*
31540Sstevel@tonic-gate * If we're trying to unload this module, then don't do
31550Sstevel@tonic-gate * anything but exit.
31560Sstevel@tonic-gate * We acquire the cs_globals.global_lock mutex here so that
31570Sstevel@tonic-gate * we can correctly synchronize with cs_deinit when it
31580Sstevel@tonic-gate * is telling us to shut down. XXX - is this bogus??
31590Sstevel@tonic-gate */
31600Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
31610Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) {
31620Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
31630Sstevel@tonic-gate (void) cs_socket_event_softintr(NULL);
31640Sstevel@tonic-gate cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
31650Sstevel@tonic-gate NULL, SOFTINT_TIMEOUT_TIME);
31660Sstevel@tonic-gate } else {
31670Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
31680Sstevel@tonic-gate }
31690Sstevel@tonic-gate }
31700Sstevel@tonic-gate
31710Sstevel@tonic-gate /*
31720Sstevel@tonic-gate * cs_socket_event_softintr - This function just does a cv_broadcast on behalf
31730Sstevel@tonic-gate * of the high-priority interrupt handler.
31740Sstevel@tonic-gate *
31750Sstevel@tonic-gate * Note: There is no calling argument.
31760Sstevel@tonic-gate */
31770Sstevel@tonic-gate /*ARGSUSED*/
31780Sstevel@tonic-gate uint32_t
cs_socket_event_softintr(caddr_t notused)31790Sstevel@tonic-gate cs_socket_event_softintr(caddr_t notused)
31800Sstevel@tonic-gate {
31810Sstevel@tonic-gate cs_socket_t *sp;
31820Sstevel@tonic-gate uint32_t sn;
31830Sstevel@tonic-gate int ret = DDI_INTR_UNCLAIMED;
31840Sstevel@tonic-gate
31850Sstevel@tonic-gate /*
31860Sstevel@tonic-gate * If the module is on it's way out, then don't bother
31870Sstevel@tonic-gate * to do anything else except return.
31880Sstevel@tonic-gate */
31890Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
31900Sstevel@tonic-gate if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) ||
31910Sstevel@tonic-gate (cs_globals.init_state & GLOBAL_IN_SOFTINTR)) {
31920Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
31930Sstevel@tonic-gate
31940Sstevel@tonic-gate /*
31950Sstevel@tonic-gate * Note that we return DDI_INTR_UNCLAIMED here
31960Sstevel@tonic-gate * since we don't want to be constantly
31970Sstevel@tonic-gate * called back.
31980Sstevel@tonic-gate */
31990Sstevel@tonic-gate return (ret);
32000Sstevel@tonic-gate } else {
32010Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_IN_SOFTINTR;
32020Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
32030Sstevel@tonic-gate }
32040Sstevel@tonic-gate
32050Sstevel@tonic-gate /*
32060Sstevel@tonic-gate * Go through each socket and dispatch the appropriate events.
32070Sstevel@tonic-gate * We have to funnel everything through this one routine because
32080Sstevel@tonic-gate * we can't do a cv_broadcast from a high level interrupt handler
32090Sstevel@tonic-gate * and we also can't have more than one soft interrupt handler
32100Sstevel@tonic-gate * on a single dip and using the same handler address.
32110Sstevel@tonic-gate */
32120Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
32130Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) {
32140Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_READY) {
32150Sstevel@tonic-gate /*
32160Sstevel@tonic-gate * If we're being asked to unload CS, then don't bother
32170Sstevel@tonic-gate * waking up the socket event thread handler.
32180Sstevel@tonic-gate */
32190Sstevel@tonic-gate if (!(sp->flags & SOCKET_UNLOAD_MODULE) &&
32200Sstevel@tonic-gate (sp->flags & SOCKET_NEEDS_THREAD)) {
32210Sstevel@tonic-gate ret = DDI_INTR_CLAIMED;
32220Sstevel@tonic-gate mutex_enter(&sp->client_lock);
32230Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
32240Sstevel@tonic-gate mutex_exit(&sp->client_lock);
32250Sstevel@tonic-gate } /* if (SOCKET_NEEDS_THREAD) */
32260Sstevel@tonic-gate } /* if (SOCKET_INIT_STATE_READY) */
32270Sstevel@tonic-gate } /* cs_get_sp */
32280Sstevel@tonic-gate } /* for (sn) */
32290Sstevel@tonic-gate
32300Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
32310Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR;
32320Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
32330Sstevel@tonic-gate
32340Sstevel@tonic-gate return (ret);
32350Sstevel@tonic-gate }
32360Sstevel@tonic-gate
32370Sstevel@tonic-gate /*
32380Sstevel@tonic-gate * cs_event_thread - This is the per-socket event thread.
32390Sstevel@tonic-gate */
32400Sstevel@tonic-gate static void
cs_event_thread(uint32_t sn)32410Sstevel@tonic-gate cs_event_thread(uint32_t sn)
32420Sstevel@tonic-gate {
32430Sstevel@tonic-gate cs_socket_t *sp;
32440Sstevel@tonic-gate client_t *client;
32450Sstevel@tonic-gate client_types_t *ct;
32460Sstevel@tonic-gate
32470Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
32480Sstevel@tonic-gate return;
32490Sstevel@tonic-gate
32500Sstevel@tonic-gate #ifdef CS_DEBUG
32510Sstevel@tonic-gate if (cs_debug > 1) {
32520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n",
32530Sstevel@tonic-gate sp->socket_num);
32540Sstevel@tonic-gate }
32550Sstevel@tonic-gate #endif
32560Sstevel@tonic-gate
32570Sstevel@tonic-gate CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock,
32580Sstevel@tonic-gate callb_generic_cpr, "cs_event_thread");
32590Sstevel@tonic-gate
32600Sstevel@tonic-gate mutex_enter(&sp->client_lock);
32610Sstevel@tonic-gate
32620Sstevel@tonic-gate for (;;) {
32630Sstevel@tonic-gate
32640Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs);
32650Sstevel@tonic-gate cv_wait(&sp->thread_cv, &sp->client_lock);
32660Sstevel@tonic-gate CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock);
32670Sstevel@tonic-gate
32680Sstevel@tonic-gate mutex_enter(&sp->lock);
32690Sstevel@tonic-gate sp->flags &= ~SOCKET_NEEDS_THREAD;
32700Sstevel@tonic-gate mutex_exit(&sp->lock);
32710Sstevel@tonic-gate
32720Sstevel@tonic-gate /*
32730Sstevel@tonic-gate * Check to see if there are any special thread operations that
32740Sstevel@tonic-gate * we are being asked to perform.
32750Sstevel@tonic-gate */
32760Sstevel@tonic-gate if (sp->thread_state & SOCKET_THREAD_EXIT) {
32770Sstevel@tonic-gate #ifdef CS_DEBUG
32780Sstevel@tonic-gate if (cs_debug > 1) {
32790Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d "
32800Sstevel@tonic-gate "SOCKET_THREAD_EXIT\n",
32810Sstevel@tonic-gate sp->socket_num);
32820Sstevel@tonic-gate }
32830Sstevel@tonic-gate #endif
32840Sstevel@tonic-gate CALLB_CPR_EXIT(&sp->cprinfo_cs);
32850Sstevel@tonic-gate cv_broadcast(&sp->caller_cv); /* wakes up cs_deinit */
32860Sstevel@tonic-gate mutex_exit(&sp->client_lock);
32870Sstevel@tonic-gate return;
32880Sstevel@tonic-gate } /* if (SOCKET_THREAD_EXIT) */
32890Sstevel@tonic-gate
32900Sstevel@tonic-gate #ifdef CS_DEBUG
32910Sstevel@tonic-gate if (cs_debug > 1) {
32920Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n",
32930Sstevel@tonic-gate sp->socket_num,
32940Sstevel@tonic-gate (int)sp->events);
32950Sstevel@tonic-gate }
32960Sstevel@tonic-gate #endif
32970Sstevel@tonic-gate
32980Sstevel@tonic-gate /*
32990Sstevel@tonic-gate * Handle CS_EVENT_CARD_INSERTION events
33000Sstevel@tonic-gate */
33010Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_INSERTION) {
33020Sstevel@tonic-gate mutex_enter(&sp->lock);
33030Sstevel@tonic-gate sp->events &= ~CS_EVENT_CARD_INSERTION;
33040Sstevel@tonic-gate mutex_exit(&sp->lock);
33050Sstevel@tonic-gate
33060Sstevel@tonic-gate /*
33070Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it
33080Sstevel@tonic-gate * means that we likely got CD line bounce on the
33090Sstevel@tonic-gate * insertion, so terminate this processing.
33100Sstevel@tonic-gate */
33110Sstevel@tonic-gate if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) {
33120Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION);
33130Sstevel@tonic-gate }
33140Sstevel@tonic-gate #ifdef CS_DEBUG
33150Sstevel@tonic-gate else if (cs_debug > 0) {
33160Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d "
33170Sstevel@tonic-gate "CS_EVENT_CARD_REMOVAL event "
33180Sstevel@tonic-gate "terminating "
33190Sstevel@tonic-gate "CS_EVENT_CARD_INSERTION "
33200Sstevel@tonic-gate "processing\n", sp->socket_num);
33210Sstevel@tonic-gate }
33220Sstevel@tonic-gate #endif
33230Sstevel@tonic-gate } /* if (CS_EVENT_CARD_INSERTION) */
33240Sstevel@tonic-gate
33250Sstevel@tonic-gate /*
33260Sstevel@tonic-gate * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
33270Sstevel@tonic-gate */
33280Sstevel@tonic-gate if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) {
33290Sstevel@tonic-gate mutex_enter(&sp->lock);
33300Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
33310Sstevel@tonic-gate mutex_exit(&sp->lock);
33320Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
33330Sstevel@tonic-gate mutex_enter(&sp->lock);
33340Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
33350Sstevel@tonic-gate mutex_exit(&sp->lock);
33360Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_CARD_READY);
33370Sstevel@tonic-gate } /* if (SOCKET_WAIT_FOR_READY) */
33380Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */
33390Sstevel@tonic-gate
33400Sstevel@tonic-gate /*
33410Sstevel@tonic-gate * Handle CS_EVENT_SS_UPDATED events
33420Sstevel@tonic-gate */
33430Sstevel@tonic-gate if (sp->events & CS_EVENT_SS_UPDATED) {
33440Sstevel@tonic-gate mutex_enter(&sp->lock);
33450Sstevel@tonic-gate sp->events &= ~CS_EVENT_SS_UPDATED;
33460Sstevel@tonic-gate mutex_exit(&sp->lock);
33470Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED);
33480Sstevel@tonic-gate } /* if (CS_EVENT_SS_UPDATED) */
33490Sstevel@tonic-gate
33500Sstevel@tonic-gate /*
33510Sstevel@tonic-gate * Handle CS_EVENT_STATUS_CHANGE events
33520Sstevel@tonic-gate */
33530Sstevel@tonic-gate if (sp->events & CS_EVENT_STATUS_CHANGE) {
33540Sstevel@tonic-gate event_t revent;
33550Sstevel@tonic-gate
33560Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
33570Sstevel@tonic-gate mutex_enter(&sp->lock);
33580Sstevel@tonic-gate sp->events &= ~CS_EVENT_STATUS_CHANGE;
33590Sstevel@tonic-gate
33600Sstevel@tonic-gate /*
33610Sstevel@tonic-gate * Go through each client and add any events that we saw to
33620Sstevel@tonic-gate * the client's event list if the client has that event
33630Sstevel@tonic-gate * enabled in their event mask.
33640Sstevel@tonic-gate * Remove any events that may be pending for this client if
33650Sstevel@tonic-gate * the client's event mask says that the client doesn't
33660Sstevel@tonic-gate * want to see those events anymore. This handles the
33670Sstevel@tonic-gate * case where the client had an event enabled in it's
33680Sstevel@tonic-gate * event mask when the event came in but between that
33690Sstevel@tonic-gate * time and the time we're called here the client
33700Sstevel@tonic-gate * disabled that event.
33710Sstevel@tonic-gate */
33720Sstevel@tonic-gate client = sp->client_list;
33730Sstevel@tonic-gate
33740Sstevel@tonic-gate while (client) {
33750Sstevel@tonic-gate /*
33760Sstevel@tonic-gate * Read the PRR (if it exists) and check for any events.
33770Sstevel@tonic-gate * The PRR will only be read if the socket is in IO
33780Sstevel@tonic-gate * mode, if there is a card in the socket, and if there
33790Sstevel@tonic-gate * is a PRR.
33800Sstevel@tonic-gate * We don't have to clear revent before we call the
33810Sstevel@tonic-gate * cs_read_event_status function since it will
33820Sstevel@tonic-gate * clear it before adding any current events.
33830Sstevel@tonic-gate */
33840Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
33850Sstevel@tonic-gate (void) cs_read_event_status(sp, client,
33860Sstevel@tonic-gate &revent, NULL, 0);
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate client->events = ((client->events | revent) &
33890Sstevel@tonic-gate (client->event_mask |
33900Sstevel@tonic-gate client->global_mask));
33910Sstevel@tonic-gate } /* CLIENT_CARD_INSERTED */
33920Sstevel@tonic-gate client = client->next;
33930Sstevel@tonic-gate } /* while (client) */
33940Sstevel@tonic-gate
33950Sstevel@tonic-gate mutex_exit(&sp->lock);
33960Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
33970Sstevel@tonic-gate } /* if (CS_EVENT_STATUS_CHANGE) */
33980Sstevel@tonic-gate
33990Sstevel@tonic-gate /*
34000Sstevel@tonic-gate * We want to maintain the required event dispatching order as
34010Sstevel@tonic-gate * specified in the PCMCIA spec, so we cycle through all
34020Sstevel@tonic-gate * clients on this socket to make sure that they are
34030Sstevel@tonic-gate * notified in the correct order.
34040Sstevel@tonic-gate */
34050Sstevel@tonic-gate ct = &client_types[0];
34060Sstevel@tonic-gate while (ct) {
34070Sstevel@tonic-gate /*
34080Sstevel@tonic-gate * Point to the head of the client list for this socket, and go
34090Sstevel@tonic-gate * through each client to set up the client events as well
34100Sstevel@tonic-gate * as call the client's event handler directly if we have
34110Sstevel@tonic-gate * a high priority event that we need to tell the client
34120Sstevel@tonic-gate * about.
34130Sstevel@tonic-gate */
34140Sstevel@tonic-gate client = sp->client_list;
34150Sstevel@tonic-gate
34160Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) {
34170Sstevel@tonic-gate client_t *clp = NULL;
34180Sstevel@tonic-gate
34190Sstevel@tonic-gate while (client) {
34200Sstevel@tonic-gate clp = client;
34210Sstevel@tonic-gate client = client->next;
34220Sstevel@tonic-gate }
34230Sstevel@tonic-gate client = clp;
34240Sstevel@tonic-gate }
34250Sstevel@tonic-gate
34260Sstevel@tonic-gate while (client) {
34270Sstevel@tonic-gate if (client->flags & ct->type) {
34280Sstevel@tonic-gate uint32_t bit = 0;
34290Sstevel@tonic-gate event_t event;
34300Sstevel@tonic-gate
34310Sstevel@tonic-gate while (client->events) {
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate switch (event = CS_BIT_GET(client->events, bit)) {
34340Sstevel@tonic-gate /*
34350Sstevel@tonic-gate * Clients always receive registration complete
34360Sstevel@tonic-gate * events, even if there is no card of
34370Sstevel@tonic-gate * their type currently in the socket.
34380Sstevel@tonic-gate */
34390Sstevel@tonic-gate case CS_EVENT_REGISTRATION_COMPLETE:
34400Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event,
34410Sstevel@tonic-gate CS_EVENT_PRI_LOW);
34420Sstevel@tonic-gate break;
34430Sstevel@tonic-gate /*
34440Sstevel@tonic-gate * The client only gets a card insertion event
34450Sstevel@tonic-gate * if there is currently a card in the
34460Sstevel@tonic-gate * socket that the client can control.
34470Sstevel@tonic-gate * The nexus determines this. We also
34480Sstevel@tonic-gate * prevent the client from receiving
34490Sstevel@tonic-gate * multiple CS_EVENT_CARD_INSERTION
34500Sstevel@tonic-gate * events without receiving intervening
34510Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL events.
34520Sstevel@tonic-gate */
34530Sstevel@tonic-gate case CS_EVENT_CARD_INSERTION:
34540Sstevel@tonic-gate if (cs_card_for_client(client)) {
34550Sstevel@tonic-gate int send_insertion;
34560Sstevel@tonic-gate
34570Sstevel@tonic-gate mutex_enter(&sp->lock);
34580Sstevel@tonic-gate send_insertion = client->flags;
34590Sstevel@tonic-gate client->flags |=
34600Sstevel@tonic-gate (CLIENT_CARD_INSERTED |
34610Sstevel@tonic-gate CLIENT_SENT_INSERTION);
34620Sstevel@tonic-gate mutex_exit(&sp->lock);
34630Sstevel@tonic-gate if (!(send_insertion &
34640Sstevel@tonic-gate CLIENT_SENT_INSERTION)) {
34650Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client,
34660Sstevel@tonic-gate event, CS_EVENT_PRI_LOW);
34670Sstevel@tonic-gate } /* if (!CLIENT_SENT_INSERTION) */
34680Sstevel@tonic-gate }
34690Sstevel@tonic-gate break;
34700Sstevel@tonic-gate /*
34710Sstevel@tonic-gate * The CS_EVENT_CARD_REMOVAL_LOWP is a low
34720Sstevel@tonic-gate * priority CS_EVENT_CARD_REMOVAL event.
34730Sstevel@tonic-gate */
34740Sstevel@tonic-gate case CS_EVENT_CARD_REMOVAL_LOWP:
34750Sstevel@tonic-gate mutex_enter(&sp->lock);
34760Sstevel@tonic-gate client->flags &= ~CLIENT_SENT_INSERTION;
34770Sstevel@tonic-gate mutex_exit(&sp->lock);
34780Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client,
34790Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL,
34800Sstevel@tonic-gate CS_EVENT_PRI_LOW);
34810Sstevel@tonic-gate break;
34820Sstevel@tonic-gate /*
34830Sstevel@tonic-gate * The hardware card removal events are handed
34840Sstevel@tonic-gate * to the client in cs_event at high
34850Sstevel@tonic-gate * priority interrupt time; this card
34860Sstevel@tonic-gate * removal event is a software-generated
34870Sstevel@tonic-gate * event.
34880Sstevel@tonic-gate */
34890Sstevel@tonic-gate case CS_EVENT_CARD_REMOVAL:
34900Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
34910Sstevel@tonic-gate mutex_enter(&sp->lock);
34920Sstevel@tonic-gate client->flags &=
34930Sstevel@tonic-gate ~(CLIENT_CARD_INSERTED |
34940Sstevel@tonic-gate CLIENT_SENT_INSERTION);
34950Sstevel@tonic-gate mutex_exit(&sp->lock);
34960Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event,
34970Sstevel@tonic-gate CS_EVENT_PRI_LOW);
34980Sstevel@tonic-gate }
34990Sstevel@tonic-gate break;
35000Sstevel@tonic-gate /*
35010Sstevel@tonic-gate * Write protect events require the info field
35020Sstevel@tonic-gate * of the client's event callback args to
35030Sstevel@tonic-gate * be zero if the card is not write
35040Sstevel@tonic-gate * protected and one if it is.
35050Sstevel@tonic-gate */
35060Sstevel@tonic-gate case CS_EVENT_WRITE_PROTECT:
35070Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
35080Sstevel@tonic-gate get_ss_status_t gs;
35090Sstevel@tonic-gate
35100Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
35110Sstevel@tonic-gate mutex_enter(&sp->lock);
35120Sstevel@tonic-gate (void) cs_read_event_status(sp, client,
35130Sstevel@tonic-gate NULL,
35140Sstevel@tonic-gate &gs, 0);
35150Sstevel@tonic-gate if (gs.CardState & SBM_WP) {
35160Sstevel@tonic-gate client->event_callback_args.info =
35170Sstevel@tonic-gate (void *)
35180Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT_WPON;
35190Sstevel@tonic-gate } else {
35200Sstevel@tonic-gate client->event_callback_args.info =
35210Sstevel@tonic-gate (void *)
35220Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT_WPOFF;
35230Sstevel@tonic-gate }
35240Sstevel@tonic-gate mutex_exit(&sp->lock);
35250Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
35260Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event,
35270Sstevel@tonic-gate CS_EVENT_PRI_LOW);
35280Sstevel@tonic-gate } /* CLIENT_CARD_INSERTED */
35290Sstevel@tonic-gate break;
35300Sstevel@tonic-gate case CS_EVENT_CLIENT_INFO:
35310Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event,
35320Sstevel@tonic-gate CS_EVENT_PRI_LOW);
35330Sstevel@tonic-gate break;
35340Sstevel@tonic-gate case 0:
35350Sstevel@tonic-gate break;
35360Sstevel@tonic-gate default:
35370Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) {
35380Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event,
35390Sstevel@tonic-gate CS_EVENT_PRI_LOW);
35400Sstevel@tonic-gate }
35410Sstevel@tonic-gate break;
35420Sstevel@tonic-gate } /* switch */
35430Sstevel@tonic-gate mutex_enter(&sp->lock);
35440Sstevel@tonic-gate CS_BIT_CLEAR(client->events, bit);
35450Sstevel@tonic-gate mutex_exit(&sp->lock);
35460Sstevel@tonic-gate bit++;
35470Sstevel@tonic-gate } /* while (client->events) */
35480Sstevel@tonic-gate } /* if (ct->type) */
35490Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) {
35500Sstevel@tonic-gate client = client->prev;
35510Sstevel@tonic-gate } else {
35520Sstevel@tonic-gate client = client->next;
35530Sstevel@tonic-gate }
35540Sstevel@tonic-gate } /* while (client) */
35550Sstevel@tonic-gate
35560Sstevel@tonic-gate ct = ct->next;
35570Sstevel@tonic-gate } /* while (ct) */
35580Sstevel@tonic-gate
35590Sstevel@tonic-gate /*
35600Sstevel@tonic-gate * Handle CS_EVENT_CARD_REMOVAL events
35610Sstevel@tonic-gate */
35620Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) {
35630Sstevel@tonic-gate mutex_enter(&sp->lock);
35640Sstevel@tonic-gate sp->events &= ~CS_EVENT_CARD_REMOVAL;
35650Sstevel@tonic-gate mutex_exit(&sp->lock);
35660Sstevel@tonic-gate (void) cs_card_removal(sp);
35670Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */
35680Sstevel@tonic-gate
35690Sstevel@tonic-gate /*
35700Sstevel@tonic-gate * If someone is waiting for us to complete, signal them now.
35710Sstevel@tonic-gate */
35720Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_SYNC) {
35730Sstevel@tonic-gate mutex_enter(&sp->lock);
35740Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_SYNC;
35750Sstevel@tonic-gate mutex_exit(&sp->lock);
35760Sstevel@tonic-gate cv_broadcast(&sp->caller_cv);
35770Sstevel@tonic-gate } /* SOCKET_WAIT_SYNC */
35780Sstevel@tonic-gate
35790Sstevel@tonic-gate } /* for (;;) */
35800Sstevel@tonic-gate }
35810Sstevel@tonic-gate
35820Sstevel@tonic-gate /*
35830Sstevel@tonic-gate * cs_card_for_client - checks to see if a card that the client can control
35840Sstevel@tonic-gate * is currently inserted in the socket. Socket Services
35850Sstevel@tonic-gate * has to tell us if this is the case.
35860Sstevel@tonic-gate */
35870Sstevel@tonic-gate static int
cs_card_for_client(client_t * client)35880Sstevel@tonic-gate cs_card_for_client(client_t *client)
35890Sstevel@tonic-gate {
35900Sstevel@tonic-gate
35910Sstevel@tonic-gate /*
35920Sstevel@tonic-gate * If the client has set the CS_EVENT_ALL_CLIENTS it means that they
35930Sstevel@tonic-gate * want to get all events for all clients, irrespective of
35940Sstevel@tonic-gate * whether or not there is a card in the socket. Such clients
35950Sstevel@tonic-gate * have to be very careful if they touch the card hardware in
35960Sstevel@tonic-gate * any way to prevent causing problems for other clients on the
35970Sstevel@tonic-gate * same socket. This flag will typically only be set by the
35980Sstevel@tonic-gate * "super-client" or CSI types of clients that wish to get
35990Sstevel@tonic-gate * information on other clients or cards in the system.
36000Sstevel@tonic-gate * Note that the CS_EVENT_ALL_CLIENTS must be set in either the
36010Sstevel@tonic-gate * client's global event mask or client event mask.
36020Sstevel@tonic-gate * The client must also have registered as a "super-client" or as a
36030Sstevel@tonic-gate * CSI client for this socket.
36040Sstevel@tonic-gate */
36050Sstevel@tonic-gate if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) &&
36060Sstevel@tonic-gate ((client->global_mask | client->event_mask) &
36070Sstevel@tonic-gate CS_EVENT_ALL_CLIENTS))
36080Sstevel@tonic-gate return (1);
36090Sstevel@tonic-gate
36100Sstevel@tonic-gate /*
36110Sstevel@tonic-gate * Look for the PCM_DEV_ACTIVE property on this client's dip; if
36120Sstevel@tonic-gate * it's found, it means that this client can control the card
36130Sstevel@tonic-gate * that is currently in the socket. This is a boolean
36140Sstevel@tonic-gate * property managed by Socket Services.
36150Sstevel@tonic-gate */
36160Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, client->dip, (DDI_PROP_CANSLEEP |
36170Sstevel@tonic-gate DDI_PROP_NOTPROM),
36180Sstevel@tonic-gate PCM_DEV_ACTIVE, NULL)) {
36190Sstevel@tonic-gate #ifdef CS_DEBUG
36200Sstevel@tonic-gate if (cs_debug > 1) {
36210Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x "
36220Sstevel@tonic-gate "driver [%s] says %s found\n",
36230Sstevel@tonic-gate (int)client->client_handle,
36240Sstevel@tonic-gate client->driver_name,
36250Sstevel@tonic-gate PCM_DEV_ACTIVE);
36260Sstevel@tonic-gate }
36270Sstevel@tonic-gate #endif
36280Sstevel@tonic-gate return (1);
36290Sstevel@tonic-gate }
36300Sstevel@tonic-gate
36310Sstevel@tonic-gate return (0);
36320Sstevel@tonic-gate }
36330Sstevel@tonic-gate
36340Sstevel@tonic-gate /*
36350Sstevel@tonic-gate * cs_ss_thread - This is the Socket Services work thread. We fire off
36360Sstevel@tonic-gate * any calls to Socket Services here that we want
36370Sstevel@tonic-gate * to run on a thread that is seperate from the
36380Sstevel@tonic-gate * per-socket event thread.
36390Sstevel@tonic-gate */
36400Sstevel@tonic-gate static void
cs_ss_thread(uint32_t sn)36410Sstevel@tonic-gate cs_ss_thread(uint32_t sn)
36420Sstevel@tonic-gate {
36430Sstevel@tonic-gate cs_socket_t *sp;
36440Sstevel@tonic-gate
36450Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
36460Sstevel@tonic-gate return;
36470Sstevel@tonic-gate
36480Sstevel@tonic-gate /*
36490Sstevel@tonic-gate * Tell CPR that we've started a new thread.
36500Sstevel@tonic-gate */
36510Sstevel@tonic-gate CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock,
36520Sstevel@tonic-gate callb_generic_cpr, "cs_ss_thread");
36530Sstevel@tonic-gate
36540Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock);
36550Sstevel@tonic-gate
36560Sstevel@tonic-gate for (;;) {
36570Sstevel@tonic-gate
36580Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss);
36590Sstevel@tonic-gate cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock);
36600Sstevel@tonic-gate CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock);
36610Sstevel@tonic-gate
36620Sstevel@tonic-gate /*
36630Sstevel@tonic-gate * Check to see if there are any special thread operations
36640Sstevel@tonic-gate * that we are being asked to perform.
36650Sstevel@tonic-gate */
36660Sstevel@tonic-gate if (sp->ss_thread_state & SOCKET_THREAD_EXIT) {
36670Sstevel@tonic-gate #ifdef CS_DEBUG
36680Sstevel@tonic-gate if (cs_debug > 1) {
36690Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36700Sstevel@tonic-gate "SOCKET_THREAD_EXIT\n",
36710Sstevel@tonic-gate sp->socket_num);
36720Sstevel@tonic-gate }
36730Sstevel@tonic-gate #endif
36740Sstevel@tonic-gate CALLB_CPR_EXIT(&sp->cprinfo_ss);
36750Sstevel@tonic-gate cv_broadcast(&sp->ss_caller_cv); /* wake up cs_deinit */
36760Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock);
36770Sstevel@tonic-gate return;
36780Sstevel@tonic-gate } /* if (SOCKET_THREAD_EXIT) */
36790Sstevel@tonic-gate
36800Sstevel@tonic-gate #ifdef CS_DEBUG
36810Sstevel@tonic-gate if (cs_debug > 1) {
36820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36830Sstevel@tonic-gate "ss_thread_state = 0x%x\n",
36840Sstevel@tonic-gate (int)sp->socket_num,
36850Sstevel@tonic-gate (int)sp->ss_thread_state);
36860Sstevel@tonic-gate }
36870Sstevel@tonic-gate #endif
36880Sstevel@tonic-gate
36890Sstevel@tonic-gate /*
36900Sstevel@tonic-gate * Call SocketServices(CSCISInit) to have SS parse the
36910Sstevel@tonic-gate * CIS and load/attach any client drivers necessary.
36920Sstevel@tonic-gate */
36930Sstevel@tonic-gate if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) {
36940Sstevel@tonic-gate
36950Sstevel@tonic-gate sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit;
36960Sstevel@tonic-gate
36970Sstevel@tonic-gate if (!(sp->flags & SOCKET_CARD_INSERTED)) {
36980Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread %d "
36990Sstevel@tonic-gate "card NOT inserted\n",
37000Sstevel@tonic-gate sp->socket_num);
37010Sstevel@tonic-gate }
37020Sstevel@tonic-gate
37030Sstevel@tonic-gate #ifdef CS_DEBUG
37040Sstevel@tonic-gate if (cs_debug > 1) {
37050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d calling "
37060Sstevel@tonic-gate "CSCISInit\n", sp->socket_num);
37070Sstevel@tonic-gate }
37080Sstevel@tonic-gate #endif
37090Sstevel@tonic-gate
37100Sstevel@tonic-gate /*
37110Sstevel@tonic-gate * Tell SS that we have a complete CIS and that it can now
37120Sstevel@tonic-gate * be parsed.
37130Sstevel@tonic-gate * Note that in some cases the client driver may block in
37140Sstevel@tonic-gate * their attach routine, causing this call to block until
37150Sstevel@tonic-gate * the client completes their attach.
37160Sstevel@tonic-gate */
37170Sstevel@tonic-gate SocketServices(CSCISInit, sp->socket_num);
37180Sstevel@tonic-gate
37190Sstevel@tonic-gate /*
37200Sstevel@tonic-gate * Set the CS_EVENT_SS_UPDATED event for this socket so that the
37210Sstevel@tonic-gate * event thread can continue any card insertion processing
37220Sstevel@tonic-gate * that it has to do.
37230Sstevel@tonic-gate */
37240Sstevel@tonic-gate mutex_enter(&sp->lock);
37250Sstevel@tonic-gate sp->events |= CS_EVENT_SS_UPDATED;
37260Sstevel@tonic-gate mutex_exit(&sp->lock);
37270Sstevel@tonic-gate
37280Sstevel@tonic-gate /*
37290Sstevel@tonic-gate * Wake up this socket's event thread so that clients can
37300Sstevel@tonic-gate * continue any card insertion or attach processing
37310Sstevel@tonic-gate * that they need to do.
37320Sstevel@tonic-gate */
37330Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
37340Sstevel@tonic-gate } /* if ST_CSCISInit */
37350Sstevel@tonic-gate
37360Sstevel@tonic-gate } /* for (;;) */
37370Sstevel@tonic-gate }
37380Sstevel@tonic-gate
37390Sstevel@tonic-gate /*
37400Sstevel@tonic-gate * cs_request_socket_mask - set the client's event mask as well as causes
37410Sstevel@tonic-gate * any events pending from RegisterClient to
37420Sstevel@tonic-gate * be scheduled to be sent to the client
37430Sstevel@tonic-gate */
37440Sstevel@tonic-gate static int
cs_request_socket_mask(client_handle_t client_handle,request_socket_mask_t * se)37450Sstevel@tonic-gate cs_request_socket_mask(client_handle_t client_handle,
37460Sstevel@tonic-gate request_socket_mask_t *se)
37470Sstevel@tonic-gate {
37480Sstevel@tonic-gate cs_socket_t *sp;
37490Sstevel@tonic-gate client_t *client;
37500Sstevel@tonic-gate int error;
37510Sstevel@tonic-gate int client_lock_acquired;
37520Sstevel@tonic-gate
37530Sstevel@tonic-gate /*
37540Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
37550Sstevel@tonic-gate * is, we don't do anything except for return success.
37560Sstevel@tonic-gate */
37570Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
37580Sstevel@tonic-gate return (CS_SUCCESS);
37590Sstevel@tonic-gate
37600Sstevel@tonic-gate /*
37610Sstevel@tonic-gate * Get a pointer to this client's socket structure.
37620Sstevel@tonic-gate */
37630Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
37640Sstevel@tonic-gate return (CS_BAD_SOCKET);
37650Sstevel@tonic-gate
37660Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
37670Sstevel@tonic-gate
37680Sstevel@tonic-gate /*
37690Sstevel@tonic-gate * Make sure that this is a valid client handle.
37700Sstevel@tonic-gate */
37710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
37720Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37730Sstevel@tonic-gate return (error);
37740Sstevel@tonic-gate }
37750Sstevel@tonic-gate
37760Sstevel@tonic-gate mutex_enter(&sp->lock);
37770Sstevel@tonic-gate
37780Sstevel@tonic-gate /*
37790Sstevel@tonic-gate * If this client has already done a RequestSocketMask without
37800Sstevel@tonic-gate * a corresponding ReleaseSocketMask, then return an error.
37810Sstevel@tonic-gate */
37820Sstevel@tonic-gate if (client->flags & REQ_SOCKET_MASK_DONE) {
37830Sstevel@tonic-gate mutex_exit(&sp->lock);
37840Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37850Sstevel@tonic-gate return (CS_IN_USE);
37860Sstevel@tonic-gate }
37870Sstevel@tonic-gate
37880Sstevel@tonic-gate /*
37890Sstevel@tonic-gate * Set up the event mask information; we copy this directly from
37900Sstevel@tonic-gate * the client; since we are the only source of events, any
37910Sstevel@tonic-gate * bogus bits that the client puts in here won't matter
37920Sstevel@tonic-gate * because we'll never look at them.
37930Sstevel@tonic-gate */
37940Sstevel@tonic-gate client->event_mask = se->EventMask;
37950Sstevel@tonic-gate
37960Sstevel@tonic-gate /*
37970Sstevel@tonic-gate * If RegisterClient left us some events to process, set these
37980Sstevel@tonic-gate * events up here.
37990Sstevel@tonic-gate */
38000Sstevel@tonic-gate if (client->pending_events) {
38010Sstevel@tonic-gate client->events |= client->pending_events;
38020Sstevel@tonic-gate client->pending_events = 0;
38030Sstevel@tonic-gate #ifdef CS_DEBUG
38040Sstevel@tonic-gate if (cs_debug > 1) {
38050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x "
38060Sstevel@tonic-gate "driver_name = [%s] events = 0x%x\n",
38070Sstevel@tonic-gate (int)client->client_handle,
38080Sstevel@tonic-gate client->driver_name,
38090Sstevel@tonic-gate (int)client->events);
38100Sstevel@tonic-gate }
38110Sstevel@tonic-gate #endif
38120Sstevel@tonic-gate }
38130Sstevel@tonic-gate
38140Sstevel@tonic-gate client->flags |= REQ_SOCKET_MASK_DONE;
38150Sstevel@tonic-gate
38160Sstevel@tonic-gate /*
38170Sstevel@tonic-gate * Merge all the clients' event masks and set the socket
38180Sstevel@tonic-gate * to generate the appropriate events.
38190Sstevel@tonic-gate */
38200Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
38210Sstevel@tonic-gate
38220Sstevel@tonic-gate mutex_exit(&sp->lock);
38230Sstevel@tonic-gate
38240Sstevel@tonic-gate /*
38250Sstevel@tonic-gate * Wakeup the event thread if there are any client events to process.
38260Sstevel@tonic-gate */
38270Sstevel@tonic-gate if (client->events) {
38280Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
38290Sstevel@tonic-gate #ifdef CS_DEBUG
38300Sstevel@tonic-gate if (cs_debug > 1) {
38310Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for "
38320Sstevel@tonic-gate "client_handle = 0x%x "
38330Sstevel@tonic-gate "driver_name = [%s] events = 0x%x\n",
38340Sstevel@tonic-gate (int)client->client_handle,
38350Sstevel@tonic-gate client->driver_name,
38360Sstevel@tonic-gate (int)client->events);
38370Sstevel@tonic-gate }
38380Sstevel@tonic-gate #endif
38390Sstevel@tonic-gate
38400Sstevel@tonic-gate }
38410Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38420Sstevel@tonic-gate
38430Sstevel@tonic-gate return (CS_SUCCESS);
38440Sstevel@tonic-gate }
38450Sstevel@tonic-gate
38460Sstevel@tonic-gate /*
38470Sstevel@tonic-gate * cs_release_socket_mask - clear the client's event mask
38480Sstevel@tonic-gate *
38490Sstevel@tonic-gate * Once this function returns, the client is guaranteed
38500Sstevel@tonic-gate * not to get any more event callbacks.
38510Sstevel@tonic-gate */
38520Sstevel@tonic-gate /*ARGSUSED*/
38530Sstevel@tonic-gate static int
cs_release_socket_mask(client_handle_t client_handle,release_socket_mask_t * rsm)38540Sstevel@tonic-gate cs_release_socket_mask(client_handle_t client_handle,
38550Sstevel@tonic-gate release_socket_mask_t *rsm)
38560Sstevel@tonic-gate {
38570Sstevel@tonic-gate cs_socket_t *sp;
38580Sstevel@tonic-gate client_t *client;
38590Sstevel@tonic-gate int error;
38600Sstevel@tonic-gate int client_lock_acquired;
38610Sstevel@tonic-gate
38620Sstevel@tonic-gate /*
38630Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
38640Sstevel@tonic-gate * is, we don't do anything except for return success.
38650Sstevel@tonic-gate */
38660Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
38670Sstevel@tonic-gate return (CS_SUCCESS);
38680Sstevel@tonic-gate
38690Sstevel@tonic-gate /*
38700Sstevel@tonic-gate * Get a pointer to this client's socket structure.
38710Sstevel@tonic-gate */
38720Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
38730Sstevel@tonic-gate return (CS_BAD_SOCKET);
38740Sstevel@tonic-gate
38750Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
38760Sstevel@tonic-gate
38770Sstevel@tonic-gate /*
38780Sstevel@tonic-gate * Make sure that this is a valid client handle.
38790Sstevel@tonic-gate */
38800Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
38810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38820Sstevel@tonic-gate return (error);
38830Sstevel@tonic-gate }
38840Sstevel@tonic-gate
38850Sstevel@tonic-gate mutex_enter(&sp->lock);
38860Sstevel@tonic-gate
38870Sstevel@tonic-gate /*
38880Sstevel@tonic-gate * If this client has already done a RequestSocketMask without
38890Sstevel@tonic-gate * a corresponding ReleaseSocketMask, then return an error.
38900Sstevel@tonic-gate */
38910Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
38920Sstevel@tonic-gate mutex_exit(&sp->lock);
38930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38940Sstevel@tonic-gate return (CS_BAD_SOCKET);
38950Sstevel@tonic-gate }
38960Sstevel@tonic-gate
38970Sstevel@tonic-gate /*
38980Sstevel@tonic-gate * Clear both the client event mask and the global event mask.
38990Sstevel@tonic-gate * We clear both since the semantics of this function are
39000Sstevel@tonic-gate * that once it returns, the client will not be called at
39010Sstevel@tonic-gate * it's event handler for any events until RequestSocketMask
39020Sstevel@tonic-gate * is called again.
39030Sstevel@tonic-gate */
39040Sstevel@tonic-gate client->event_mask = 0;
39050Sstevel@tonic-gate client->global_mask = 0;
39060Sstevel@tonic-gate client->flags &= ~REQ_SOCKET_MASK_DONE;
39070Sstevel@tonic-gate
39080Sstevel@tonic-gate /*
39090Sstevel@tonic-gate * Merge all the clients' event masks and set the socket
39100Sstevel@tonic-gate * to generate the appropriate events.
39110Sstevel@tonic-gate */
39120Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
39130Sstevel@tonic-gate
39140Sstevel@tonic-gate mutex_exit(&sp->lock);
39150Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39160Sstevel@tonic-gate
39170Sstevel@tonic-gate return (CS_SUCCESS);
39180Sstevel@tonic-gate }
39190Sstevel@tonic-gate
39200Sstevel@tonic-gate /*
39210Sstevel@tonic-gate * cs_get_event_mask - return the event mask for this client
39220Sstevel@tonic-gate */
39230Sstevel@tonic-gate static int
cs_get_event_mask(client_handle_t client_handle,sockevent_t * se)39240Sstevel@tonic-gate cs_get_event_mask(client_handle_t client_handle, sockevent_t *se)
39250Sstevel@tonic-gate {
39260Sstevel@tonic-gate cs_socket_t *sp;
39270Sstevel@tonic-gate client_t *client;
39280Sstevel@tonic-gate int error;
39290Sstevel@tonic-gate int client_lock_acquired;
39300Sstevel@tonic-gate
39310Sstevel@tonic-gate /*
39320Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
39330Sstevel@tonic-gate * is, we don't do anything except for return success.
39340Sstevel@tonic-gate */
39350Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
39360Sstevel@tonic-gate return (CS_SUCCESS);
39370Sstevel@tonic-gate
39380Sstevel@tonic-gate /*
39390Sstevel@tonic-gate * Get a pointer to this client's socket structure.
39400Sstevel@tonic-gate */
39410Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
39420Sstevel@tonic-gate return (CS_BAD_SOCKET);
39430Sstevel@tonic-gate
39440Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
39450Sstevel@tonic-gate
39460Sstevel@tonic-gate /*
39470Sstevel@tonic-gate * Make sure that this is a valid client handle.
39480Sstevel@tonic-gate */
39490Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
39500Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39510Sstevel@tonic-gate return (error);
39520Sstevel@tonic-gate }
39530Sstevel@tonic-gate
39540Sstevel@tonic-gate mutex_enter(&sp->lock);
39550Sstevel@tonic-gate
39560Sstevel@tonic-gate #ifdef XXX
39570Sstevel@tonic-gate /*
39580Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
39590Sstevel@tonic-gate * for this client, then return an error.
39600Sstevel@tonic-gate * XXX - how can a client get their event masks if their card
39610Sstevel@tonic-gate * goes away?
39620Sstevel@tonic-gate */
39630Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
39640Sstevel@tonic-gate mutex_exit(&sp->lock);
39650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39660Sstevel@tonic-gate return (CS_NO_CARD);
39670Sstevel@tonic-gate }
39680Sstevel@tonic-gate #endif
39690Sstevel@tonic-gate
39700Sstevel@tonic-gate /*
39710Sstevel@tonic-gate * We are only allowed to get the client event mask if a
39720Sstevel@tonic-gate * RequestSocketMask has been called previously. We
39730Sstevel@tonic-gate * are allowed to get the global event mask at any
39740Sstevel@tonic-gate * time.
39750Sstevel@tonic-gate * The global event mask is initially set by the client
39760Sstevel@tonic-gate * in the call to RegisterClient. The client event
39770Sstevel@tonic-gate * mask is set by the client in calls to SetEventMask
39780Sstevel@tonic-gate * and RequestSocketMask and gotten in calls to
39790Sstevel@tonic-gate * GetEventMask.
39800Sstevel@tonic-gate */
39810Sstevel@tonic-gate if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
39820Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
39830Sstevel@tonic-gate mutex_exit(&sp->lock);
39840Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39850Sstevel@tonic-gate return (CS_BAD_SOCKET);
39860Sstevel@tonic-gate }
39870Sstevel@tonic-gate se->EventMask = client->event_mask;
39880Sstevel@tonic-gate } else {
39890Sstevel@tonic-gate se->EventMask = client->global_mask;
39900Sstevel@tonic-gate }
39910Sstevel@tonic-gate
39920Sstevel@tonic-gate mutex_exit(&sp->lock);
39930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39940Sstevel@tonic-gate
39950Sstevel@tonic-gate return (CS_SUCCESS);
39960Sstevel@tonic-gate }
39970Sstevel@tonic-gate
39980Sstevel@tonic-gate /*
39990Sstevel@tonic-gate * cs_set_event_mask - set the event mask for this client
40000Sstevel@tonic-gate */
40010Sstevel@tonic-gate static int
cs_set_event_mask(client_handle_t client_handle,sockevent_t * se)40020Sstevel@tonic-gate cs_set_event_mask(client_handle_t client_handle, sockevent_t *se)
40030Sstevel@tonic-gate {
40040Sstevel@tonic-gate cs_socket_t *sp;
40050Sstevel@tonic-gate client_t *client;
40060Sstevel@tonic-gate int error;
40070Sstevel@tonic-gate int client_lock_acquired;
40080Sstevel@tonic-gate
40090Sstevel@tonic-gate /*
40100Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
40110Sstevel@tonic-gate * is, we don't do anything except for return success.
40120Sstevel@tonic-gate */
40130Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
40140Sstevel@tonic-gate return (CS_SUCCESS);
40150Sstevel@tonic-gate
40160Sstevel@tonic-gate /*
40170Sstevel@tonic-gate * Get a pointer to this client's socket structure.
40180Sstevel@tonic-gate */
40190Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
40200Sstevel@tonic-gate return (CS_BAD_SOCKET);
40210Sstevel@tonic-gate
40220Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
40230Sstevel@tonic-gate
40240Sstevel@tonic-gate /*
40250Sstevel@tonic-gate * Make sure that this is a valid client handle.
40260Sstevel@tonic-gate */
40270Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
40280Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40290Sstevel@tonic-gate return (error);
40300Sstevel@tonic-gate }
40310Sstevel@tonic-gate
40320Sstevel@tonic-gate mutex_enter(&sp->lock);
40330Sstevel@tonic-gate
40340Sstevel@tonic-gate #ifdef XXX
40350Sstevel@tonic-gate /*
40360Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
40370Sstevel@tonic-gate * for this client, then return an error.
40380Sstevel@tonic-gate */
40390Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
40400Sstevel@tonic-gate mutex_exit(&sp->lock);
40410Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40420Sstevel@tonic-gate return (CS_NO_CARD);
40430Sstevel@tonic-gate }
40440Sstevel@tonic-gate #endif
40450Sstevel@tonic-gate
40460Sstevel@tonic-gate /*
40470Sstevel@tonic-gate * We are only allowed to set the client event mask if a
40480Sstevel@tonic-gate * RequestSocketMask has been called previously. We
40490Sstevel@tonic-gate * are allowed to set the global event mask at any
40500Sstevel@tonic-gate * time.
40510Sstevel@tonic-gate * The global event mask is initially set by the client
40520Sstevel@tonic-gate * in the call to RegisterClient. The client event
40530Sstevel@tonic-gate * mask is set by the client in calls to SetEventMask
40540Sstevel@tonic-gate * and RequestSocketMask and gotten in calls to
40550Sstevel@tonic-gate * GetEventMask.
40560Sstevel@tonic-gate */
40570Sstevel@tonic-gate if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
40580Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
40590Sstevel@tonic-gate mutex_exit(&sp->lock);
40600Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40610Sstevel@tonic-gate return (CS_BAD_SOCKET);
40620Sstevel@tonic-gate }
40630Sstevel@tonic-gate client->event_mask = se->EventMask;
40640Sstevel@tonic-gate } else {
40650Sstevel@tonic-gate client->global_mask = se->EventMask;
40660Sstevel@tonic-gate }
40670Sstevel@tonic-gate
40680Sstevel@tonic-gate /*
40690Sstevel@tonic-gate * Merge all the clients' event masks and set the socket
40700Sstevel@tonic-gate * to generate the appropriate events.
40710Sstevel@tonic-gate */
40720Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
40730Sstevel@tonic-gate
40740Sstevel@tonic-gate mutex_exit(&sp->lock);
40750Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40760Sstevel@tonic-gate
40770Sstevel@tonic-gate return (CS_SUCCESS);
40780Sstevel@tonic-gate }
40790Sstevel@tonic-gate
40800Sstevel@tonic-gate /*
40810Sstevel@tonic-gate * cs_read_event_status - handles PRR events and returns card status
40820Sstevel@tonic-gate *
40830Sstevel@tonic-gate * calling: *sp - socket struct point
40840Sstevel@tonic-gate * *client - client to check events on
40850Sstevel@tonic-gate * *revent - pointer to event mask to update; if NULL, will
40860Sstevel@tonic-gate * not be updated, if non-NULL, will be updated
40870Sstevel@tonic-gate * with CS-format events; it is NOT necessary
40880Sstevel@tonic-gate * to clear this value before calling this
40890Sstevel@tonic-gate * function
40900Sstevel@tonic-gate * *gs - pointer to a get_ss_status_t used for the SS GetStatus
40910Sstevel@tonic-gate * call; it is not necessary to initialize any
40920Sstevel@tonic-gate * members in this structure; set to NULL if
40930Sstevel@tonic-gate * not used
40940Sstevel@tonic-gate * flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
40950Sstevel@tonic-gate * card present will not be done
40960Sstevel@tonic-gate *
40970Sstevel@tonic-gate * returns: CS_SUCCESS
40980Sstevel@tonic-gate * CS_NO_CARD - if no card is in the socket and the flags arg
40990Sstevel@tonic-gate * is not set to CS_RES_IGNORE_NO_CARD
41000Sstevel@tonic-gate * CS_BAD_SOCKET - if the SS_GetStatus function returned an
41010Sstevel@tonic-gate * error
41020Sstevel@tonic-gate *
41030Sstevel@tonic-gate * Note that if the client that configured this socket has told us that
41040Sstevel@tonic-gate * the READY pin in the PRR isn't valid and the socket is in IO
41050Sstevel@tonic-gate * mode, we always return that the card is READY.
41060Sstevel@tonic-gate *
41070Sstevel@tonic-gate * Note that if gs is not NULL, the current card state will be returned
41080Sstevel@tonic-gate * in the gs->CardState member; this will always reflect the
41090Sstevel@tonic-gate * current card state and the state will come from both the
41100Sstevel@tonic-gate * SS_GetStatus call and the PRR, whichever is appropriate for
41110Sstevel@tonic-gate * the mode that the socket is currently in.
41120Sstevel@tonic-gate */
41130Sstevel@tonic-gate static int
cs_read_event_status(cs_socket_t * sp,client_t * client,event_t * revent,get_ss_status_t * gs,int flags)41140Sstevel@tonic-gate cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent,
41150Sstevel@tonic-gate get_ss_status_t *gs, int flags)
41160Sstevel@tonic-gate {
41170Sstevel@tonic-gate cfg_regs_t prrd = 0;
41180Sstevel@tonic-gate
41190Sstevel@tonic-gate /*
41200Sstevel@tonic-gate * SOCKET_IS_IO will only be set if a RequestConfiguration
41210Sstevel@tonic-gate * has been done by at least one client on this socket.
41220Sstevel@tonic-gate * If there isn't a card in the socket or the caller wants to ignore
41230Sstevel@tonic-gate * whether the card is in the socket or not, get the current
41240Sstevel@tonic-gate * card status.
41250Sstevel@tonic-gate */
41260Sstevel@tonic-gate if ((sp->flags & SOCKET_CARD_INSERTED) ||
41270Sstevel@tonic-gate (flags & CS_RES_IGNORE_NO_CARD)) {
41280Sstevel@tonic-gate if (sp->flags & SOCKET_IS_IO) {
41290Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) {
41300Sstevel@tonic-gate acc_handle_t cis_handle;
41310Sstevel@tonic-gate uint32_t newoffset = client->config_regs_offset;
41320Sstevel@tonic-gate
41330Sstevel@tonic-gate /*
41340Sstevel@tonic-gate * Get a handle to the CIS window
41350Sstevel@tonic-gate */
41360Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
41370Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) {
41380Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: socket %d "
41390Sstevel@tonic-gate "can't init CIS window\n",
41400Sstevel@tonic-gate sp->socket_num);
41410Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
41420Sstevel@tonic-gate } /* cs_init_cis_window */
41430Sstevel@tonic-gate
41440Sstevel@tonic-gate prrd = csx_Get8(cis_handle, client->config_regs.prr_p);
41450Sstevel@tonic-gate prrd &= client->pin;
41460Sstevel@tonic-gate
41470Sstevel@tonic-gate #ifdef CS_DEBUG
41480Sstevel@tonic-gate if (cs_debug > 1) {
41490Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: "
41500Sstevel@tonic-gate "prrd 0x%x client->pin 0x%x\n",
41510Sstevel@tonic-gate (int)prrd,
41520Sstevel@tonic-gate client->pin);
41530Sstevel@tonic-gate cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n",
41540Sstevel@tonic-gate ((prrd & PRR_WP_STATUS)?
41550Sstevel@tonic-gate "PRR_WP_STATUS ":""),
41560Sstevel@tonic-gate ((prrd & PRR_READY_STATUS)?
41570Sstevel@tonic-gate "PRR_READY_STATUS ":""),
41580Sstevel@tonic-gate ((prrd & PRR_BVD2_STATUS)?
41590Sstevel@tonic-gate "PRR_BVD2_STATUS ":""),
41600Sstevel@tonic-gate ((prrd & PRR_BVD1_STATUS)?
41610Sstevel@tonic-gate "PRR_BVD1_STATUS ":""),
41620Sstevel@tonic-gate ((prrd & PRR_WP_EVENT)?
41630Sstevel@tonic-gate "PRR_WP_EVENT ":""),
41640Sstevel@tonic-gate ((prrd & PRR_READY_EVENT)?
41650Sstevel@tonic-gate "PRR_READY_EVENT ":""),
41660Sstevel@tonic-gate ((prrd & PRR_BVD2_EVENT)?
41670Sstevel@tonic-gate "PRR_BVD2_EVENT ":""),
41680Sstevel@tonic-gate ((prrd & PRR_BVD1_EVENT)?
41690Sstevel@tonic-gate "PRR_BVD1_EVENT ":""));
41700Sstevel@tonic-gate }
41710Sstevel@tonic-gate #endif
41720Sstevel@tonic-gate
41730Sstevel@tonic-gate /*
41740Sstevel@tonic-gate * The caller wants the event changes sent back and
41750Sstevel@tonic-gate * the PRR event change bits cleared.
41760Sstevel@tonic-gate */
41770Sstevel@tonic-gate if (revent) {
41780Sstevel@tonic-gate get_socket_t get_socket;
41790Sstevel@tonic-gate set_socket_t set_socket;
41800Sstevel@tonic-gate
41810Sstevel@tonic-gate /*
41820Sstevel@tonic-gate * Bug ID: 1193636 - Card Services sends bogus
41830Sstevel@tonic-gate * events on CS_EVENT_STATUS_CHANGE events
41840Sstevel@tonic-gate * Clear this before we OR-in any values.
41850Sstevel@tonic-gate */
41860Sstevel@tonic-gate *revent = 0;
41870Sstevel@tonic-gate
41880Sstevel@tonic-gate PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS,
41890Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT, *revent);
41900Sstevel@tonic-gate
41910Sstevel@tonic-gate PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS,
41920Sstevel@tonic-gate CS_EVENT_CARD_READY, *revent);
41930Sstevel@tonic-gate
41940Sstevel@tonic-gate PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS,
41950Sstevel@tonic-gate CS_EVENT_BATTERY_LOW, *revent);
41960Sstevel@tonic-gate
41970Sstevel@tonic-gate PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS,
41980Sstevel@tonic-gate CS_EVENT_BATTERY_DEAD, *revent);
41990Sstevel@tonic-gate
42000Sstevel@tonic-gate
42010Sstevel@tonic-gate #ifdef CS_DEBUG
42020Sstevel@tonic-gate if (cs_debug > 1) {
42030Sstevel@tonic-gate
42040Sstevel@tonic-gate cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n",
42050Sstevel@tonic-gate ((prrd & PRR_WP_STATUS)?
42060Sstevel@tonic-gate "PRR_WP_STATUS ":""),
42070Sstevel@tonic-gate ((prrd & PRR_READY_STATUS)?
42080Sstevel@tonic-gate "PRR_READY_STATUS ":""),
42090Sstevel@tonic-gate ((prrd & PRR_BVD2_STATUS)?
42100Sstevel@tonic-gate "PRR_BVD2_STATUS ":""),
42110Sstevel@tonic-gate ((prrd & PRR_BVD1_STATUS)?
42120Sstevel@tonic-gate "PRR_BVD1_STATUS ":""),
42130Sstevel@tonic-gate ((prrd & PRR_WP_EVENT)?
42140Sstevel@tonic-gate "PRR_WP_EVENT ":""),
42150Sstevel@tonic-gate ((prrd & PRR_READY_EVENT)?
42160Sstevel@tonic-gate "PRR_READY_EVENT ":""),
42170Sstevel@tonic-gate ((prrd & PRR_BVD2_EVENT)?
42180Sstevel@tonic-gate "PRR_BVD2_EVENT ":""),
42190Sstevel@tonic-gate ((prrd & PRR_BVD1_EVENT)?
42200Sstevel@tonic-gate "PRR_BVD1_EVENT ":""));
42210Sstevel@tonic-gate }
42220Sstevel@tonic-gate #endif
42230Sstevel@tonic-gate
42240Sstevel@tonic-gate if (prrd)
42250Sstevel@tonic-gate csx_Put8(cis_handle, client->config_regs.prr_p,
42260Sstevel@tonic-gate prrd);
42270Sstevel@tonic-gate
42280Sstevel@tonic-gate /*
42290Sstevel@tonic-gate * We now have to reenable the status change interrupts
42300Sstevel@tonic-gate * if there are any valid bits in the PRR. Since
42310Sstevel@tonic-gate * the BVD1 signal becomes the STATUS_CHANGE
42320Sstevel@tonic-gate * signal when the socket is in IO mode, we just
42330Sstevel@tonic-gate * have to set the SBM_BVD1 enable bit in the
42340Sstevel@tonic-gate * event mask.
42350Sstevel@tonic-gate */
42360Sstevel@tonic-gate if (client->pin) {
42370Sstevel@tonic-gate get_socket.socket = sp->socket_num;
42380Sstevel@tonic-gate SocketServices(SS_GetSocket, &get_socket);
42390Sstevel@tonic-gate set_socket.socket = sp->socket_num;
42400Sstevel@tonic-gate set_socket.SCIntMask =
42410Sstevel@tonic-gate get_socket.SCIntMask | SBM_BVD1;
42420Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
42430Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
42440Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
42450Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting;
42460Sstevel@tonic-gate set_socket.IFType = get_socket.IFType;
42470Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
42480Sstevel@tonic-gate set_socket.State = get_socket.state;
42490Sstevel@tonic-gate SocketServices(SS_SetSocket, &set_socket);
42500Sstevel@tonic-gate } /* if (client->pin) */
42510Sstevel@tonic-gate } /* if (revent) */
42520Sstevel@tonic-gate
42530Sstevel@tonic-gate } /* if (CONFIG_PINREPL_REG_PRESENT) */
42540Sstevel@tonic-gate } /* if (SOCKET_IS_IO) */
42550Sstevel@tonic-gate
42560Sstevel@tonic-gate /*
42570Sstevel@tonic-gate * The caller wants the current card state; we just read
42580Sstevel@tonic-gate * it and return a copy of it but do not clear any of
42590Sstevel@tonic-gate * the event changed bits (if we're reading the PRR).
42600Sstevel@tonic-gate */
42610Sstevel@tonic-gate if (gs) {
42620Sstevel@tonic-gate gs->socket = sp->socket_num;
42630Sstevel@tonic-gate gs->CardState = 0;
42640Sstevel@tonic-gate if (SocketServices(SS_GetStatus, gs) != SUCCESS)
42650Sstevel@tonic-gate return (CS_BAD_SOCKET);
42660Sstevel@tonic-gate if (sp->flags & SOCKET_IS_IO) {
42670Sstevel@tonic-gate /*
42680Sstevel@tonic-gate * If the socket is in IO mode, then clear the
42690Sstevel@tonic-gate * gs->CardState bits that are now in the PRR
42700Sstevel@tonic-gate */
42710Sstevel@tonic-gate gs->CardState &= ~(SBM_WP | SBM_BVD1 |
42720Sstevel@tonic-gate SBM_BVD2 | SBM_RDYBSY);
42730Sstevel@tonic-gate
42740Sstevel@tonic-gate /*
42750Sstevel@tonic-gate * Convert PRR status to SS_GetStatus status
42760Sstevel@tonic-gate */
42770Sstevel@tonic-gate if (prrd & PRR_WP_STATUS)
42780Sstevel@tonic-gate gs->CardState |= SBM_WP;
42790Sstevel@tonic-gate if (prrd & PRR_BVD2_STATUS)
42800Sstevel@tonic-gate gs->CardState |= SBM_BVD2;
42810Sstevel@tonic-gate if (prrd & PRR_BVD1_STATUS)
42820Sstevel@tonic-gate gs->CardState |= SBM_BVD1;
42830Sstevel@tonic-gate
42840Sstevel@tonic-gate /*
42850Sstevel@tonic-gate * If the client has indicated that there is no
42860Sstevel@tonic-gate * PRR or that the READY bit in the PRR isn't
42870Sstevel@tonic-gate * valid, then we simulate the READY bit by
42880Sstevel@tonic-gate * always returning READY.
42890Sstevel@tonic-gate */
42900Sstevel@tonic-gate if (!(client->present & CONFIG_PINREPL_REG_PRESENT) ||
42910Sstevel@tonic-gate ((client->present & CONFIG_PINREPL_REG_PRESENT) &&
42920Sstevel@tonic-gate !((client->pin &
42930Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT)) ==
42940Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT))) ||
42950Sstevel@tonic-gate (prrd & PRR_READY_STATUS))
42960Sstevel@tonic-gate gs->CardState |= SBM_RDYBSY;
42970Sstevel@tonic-gate
42980Sstevel@tonic-gate #ifdef CS_DEBUG
42990Sstevel@tonic-gate if (cs_debug > 1) {
43000Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x "
43010Sstevel@tonic-gate "client->pin 0x%x "
43020Sstevel@tonic-gate "gs->CardState 0x%x\n",
43030Sstevel@tonic-gate prrd, client->pin, gs->CardState);
43040Sstevel@tonic-gate }
43050Sstevel@tonic-gate #endif
43060Sstevel@tonic-gate
43070Sstevel@tonic-gate } /* if (SOCKET_IS_IO) */
43080Sstevel@tonic-gate } /* if (gs) */
43090Sstevel@tonic-gate return (CS_SUCCESS);
43100Sstevel@tonic-gate } /* if (SOCKET_CARD_INSERTED) */
43110Sstevel@tonic-gate
43120Sstevel@tonic-gate return (CS_NO_CARD);
43130Sstevel@tonic-gate }
43140Sstevel@tonic-gate
43150Sstevel@tonic-gate /*
43160Sstevel@tonic-gate * cs_get_status - gets live card status and latched card status changes
43170Sstevel@tonic-gate * supports the GetStatus CS call
43180Sstevel@tonic-gate *
43190Sstevel@tonic-gate * returns: CS_SUCCESS
43200Sstevel@tonic-gate * CS_BAD_HANDLE if the passed client handle is invalid
43210Sstevel@tonic-gate *
43220Sstevel@tonic-gate * Note: This function resets the latched status values maintained
43230Sstevel@tonic-gate * by Socket Services
43240Sstevel@tonic-gate */
43250Sstevel@tonic-gate static int
cs_get_status(client_handle_t client_handle,get_status_t * gs)43260Sstevel@tonic-gate cs_get_status(client_handle_t client_handle, get_status_t *gs)
43270Sstevel@tonic-gate {
43280Sstevel@tonic-gate cs_socket_t *sp;
43290Sstevel@tonic-gate client_t *client;
43300Sstevel@tonic-gate get_ss_status_t get_ss_status;
43310Sstevel@tonic-gate get_socket_t get_socket;
43320Sstevel@tonic-gate set_socket_t set_socket;
43330Sstevel@tonic-gate int error;
43340Sstevel@tonic-gate int client_lock_acquired;
43350Sstevel@tonic-gate
43360Sstevel@tonic-gate /*
43370Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
43380Sstevel@tonic-gate * is, we don't do anything except for return success.
43390Sstevel@tonic-gate */
43400Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
43410Sstevel@tonic-gate return (CS_SUCCESS);
43420Sstevel@tonic-gate
43430Sstevel@tonic-gate /*
43440Sstevel@tonic-gate * Get a pointer to this client's socket structure.
43450Sstevel@tonic-gate */
43460Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
43470Sstevel@tonic-gate return (CS_BAD_SOCKET);
43480Sstevel@tonic-gate
43490Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
43500Sstevel@tonic-gate
43510Sstevel@tonic-gate /*
43520Sstevel@tonic-gate * Make sure that this is a valid client handle.
43530Sstevel@tonic-gate */
43540Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
43550Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43560Sstevel@tonic-gate return (error);
43570Sstevel@tonic-gate }
43580Sstevel@tonic-gate
43590Sstevel@tonic-gate /*
43600Sstevel@tonic-gate * Get the current card status as well as the latched card
43610Sstevel@tonic-gate * state. Set the CS_RES_IGNORE_NO_CARD so that even
43620Sstevel@tonic-gate * if there is no card in the socket we'll still get
43630Sstevel@tonic-gate * a valid status.
43640Sstevel@tonic-gate * Note that it is not necessary to initialize any values
43650Sstevel@tonic-gate * in the get_ss_status structure.
43660Sstevel@tonic-gate */
43670Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
43680Sstevel@tonic-gate if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status,
43690Sstevel@tonic-gate CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
43700Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
43710Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43720Sstevel@tonic-gate return (error);
43730Sstevel@tonic-gate }
43740Sstevel@tonic-gate
43750Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
43760Sstevel@tonic-gate
43770Sstevel@tonic-gate gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState);
43780Sstevel@tonic-gate
43790Sstevel@tonic-gate /*
43800Sstevel@tonic-gate * Assign the "live" card state to the "real" card state. If there's
43810Sstevel@tonic-gate * no card in the socket or the card in the socket is not
43820Sstevel@tonic-gate * for this client, then we lie and tell the caller that the
43830Sstevel@tonic-gate * card is not inserted.
43840Sstevel@tonic-gate */
43850Sstevel@tonic-gate gs->CardState = gs->raw_CardState;
43860Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED))
43870Sstevel@tonic-gate gs->CardState &= ~CS_EVENT_CARD_INSERTION;
43880Sstevel@tonic-gate
43890Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43900Sstevel@tonic-gate
43910Sstevel@tonic-gate get_socket.socket = sp->socket_num;
43920Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
43930Sstevel@tonic-gate return (CS_BAD_SOCKET);
43940Sstevel@tonic-gate
43950Sstevel@tonic-gate gs->SocketState = cs_sbm2cse(get_socket.state);
43960Sstevel@tonic-gate
43970Sstevel@tonic-gate set_socket.socket = sp->socket_num;
43980Sstevel@tonic-gate set_socket.SCIntMask = get_socket.SCIntMask;
43990Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
44000Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
44010Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
44020Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting;
44030Sstevel@tonic-gate set_socket.IFType = get_socket.IFType;
44040Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
44050Sstevel@tonic-gate /* XXX (is ~0 correct here?) reset latched values */
44060Sstevel@tonic-gate set_socket.State = (unsigned)~0;
44070Sstevel@tonic-gate
44080Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
44090Sstevel@tonic-gate return (CS_BAD_SOCKET);
44100Sstevel@tonic-gate
44110Sstevel@tonic-gate return (CS_SUCCESS);
44120Sstevel@tonic-gate }
44130Sstevel@tonic-gate
44140Sstevel@tonic-gate /*
44150Sstevel@tonic-gate * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
44160Sstevel@tonic-gate */
44170Sstevel@tonic-gate static event_t
cs_cse2sbm(event_t event_mask)44180Sstevel@tonic-gate cs_cse2sbm(event_t event_mask)
44190Sstevel@tonic-gate {
44200Sstevel@tonic-gate event_t sbm_event = 0;
44210Sstevel@tonic-gate
44220Sstevel@tonic-gate /*
44230Sstevel@tonic-gate * XXX - we need to handle PM_CHANGE and RESET here as well
44240Sstevel@tonic-gate */
44250Sstevel@tonic-gate if (event_mask & CS_EVENT_WRITE_PROTECT)
44260Sstevel@tonic-gate sbm_event |= SBM_WP;
44270Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_DEAD)
44280Sstevel@tonic-gate sbm_event |= SBM_BVD1;
44290Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_LOW)
44300Sstevel@tonic-gate sbm_event |= SBM_BVD2;
44310Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_READY)
44320Sstevel@tonic-gate sbm_event |= SBM_RDYBSY;
44330Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_LOCK)
44340Sstevel@tonic-gate sbm_event |= SBM_LOCKED;
44350Sstevel@tonic-gate if (event_mask & CS_EVENT_EJECTION_REQUEST)
44360Sstevel@tonic-gate sbm_event |= SBM_EJECT;
44370Sstevel@tonic-gate if (event_mask & CS_EVENT_INSERTION_REQUEST)
44380Sstevel@tonic-gate sbm_event |= SBM_INSERT;
44390Sstevel@tonic-gate if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL))
44400Sstevel@tonic-gate sbm_event |= SBM_CD;
44410Sstevel@tonic-gate
44420Sstevel@tonic-gate return (sbm_event);
44430Sstevel@tonic-gate }
44440Sstevel@tonic-gate
44450Sstevel@tonic-gate /*
44460Sstevel@tonic-gate * cs_sbm2cse - converts SBM_xxx state to CS event bits
44470Sstevel@tonic-gate *
44480Sstevel@tonic-gate * This function should never set any of the following bits:
44490Sstevel@tonic-gate *
44500Sstevel@tonic-gate * CS_EVENT_MTD_REQUEST
44510Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO
44520Sstevel@tonic-gate * CS_EVENT_TIMER_EXPIRED
44530Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL
44540Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL_LOWP
44550Sstevel@tonic-gate * CS_EVENT_ALL_CLIENTS
44560Sstevel@tonic-gate * CS_EVENT_READY_TIMEOUT
44570Sstevel@tonic-gate *
44580Sstevel@tonic-gate * These bits are defined in the CS_STATUS_XXX series and are
44590Sstevel@tonic-gate * used by GetStatus.
44600Sstevel@tonic-gate */
44610Sstevel@tonic-gate static uint32_t
cs_sbm2cse(uint32_t state)44620Sstevel@tonic-gate cs_sbm2cse(uint32_t state)
44630Sstevel@tonic-gate {
44640Sstevel@tonic-gate uint32_t rstate = 0;
44650Sstevel@tonic-gate
44660Sstevel@tonic-gate /*
44670Sstevel@tonic-gate * XXX - we need to handle PM_CHANGE and RESET here as well
44680Sstevel@tonic-gate */
44690Sstevel@tonic-gate if (state & SBM_WP)
44700Sstevel@tonic-gate rstate |= CS_EVENT_WRITE_PROTECT;
44710Sstevel@tonic-gate if (state & SBM_BVD1)
44720Sstevel@tonic-gate rstate |= CS_EVENT_BATTERY_DEAD;
44730Sstevel@tonic-gate if (state & SBM_BVD2)
44740Sstevel@tonic-gate rstate |= CS_EVENT_BATTERY_LOW;
44750Sstevel@tonic-gate if (state & SBM_RDYBSY)
44760Sstevel@tonic-gate rstate |= CS_EVENT_CARD_READY;
44770Sstevel@tonic-gate if (state & SBM_LOCKED)
44780Sstevel@tonic-gate rstate |= CS_EVENT_CARD_LOCK;
44790Sstevel@tonic-gate if (state & SBM_EJECT)
44800Sstevel@tonic-gate rstate |= CS_EVENT_EJECTION_REQUEST;
44810Sstevel@tonic-gate if (state & SBM_INSERT)
44820Sstevel@tonic-gate rstate |= CS_EVENT_INSERTION_REQUEST;
44830Sstevel@tonic-gate if (state & SBM_CD)
44840Sstevel@tonic-gate rstate |= CS_EVENT_CARD_INSERTION;
44850Sstevel@tonic-gate
44860Sstevel@tonic-gate return (rstate);
44870Sstevel@tonic-gate }
44880Sstevel@tonic-gate
44890Sstevel@tonic-gate /*
44900Sstevel@tonic-gate * cs_merge_event_masks - merge the CS global socket event mask with the
44910Sstevel@tonic-gate * passed client's event masks
44920Sstevel@tonic-gate */
44930Sstevel@tonic-gate static unsigned
cs_merge_event_masks(cs_socket_t * sp,client_t * client)44940Sstevel@tonic-gate cs_merge_event_masks(cs_socket_t *sp, client_t *client)
44950Sstevel@tonic-gate {
44960Sstevel@tonic-gate unsigned SCIntMask;
44970Sstevel@tonic-gate uint32_t event_mask;
44980Sstevel@tonic-gate
44990Sstevel@tonic-gate /*
45000Sstevel@tonic-gate * We always want to see card detect and status change events.
45010Sstevel@tonic-gate */
45020Sstevel@tonic-gate SCIntMask = SBM_CD;
45030Sstevel@tonic-gate
45040Sstevel@tonic-gate event_mask = client->event_mask | client->global_mask |
45050Sstevel@tonic-gate sp->event_mask;
45060Sstevel@tonic-gate
45070Sstevel@tonic-gate if (!(sp->flags & SOCKET_IS_IO)) {
45080Sstevel@tonic-gate SCIntMask |= cs_cse2sbm(event_mask);
45090Sstevel@tonic-gate } else {
45100Sstevel@tonic-gate /*
45110Sstevel@tonic-gate * If the socket is in IO mode and there is a PRR present,
45120Sstevel@tonic-gate * then we may need to enable PCE_CARD_STATUS_CHANGE
45130Sstevel@tonic-gate * events.
45140Sstevel@tonic-gate */
45150Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) {
45160Sstevel@tonic-gate
45170Sstevel@tonic-gate SCIntMask |= (cs_cse2sbm(event_mask) &
45180Sstevel@tonic-gate ~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY));
45190Sstevel@tonic-gate
45200Sstevel@tonic-gate if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) ==
45210Sstevel@tonic-gate (PRR_WP_STATUS | PRR_WP_EVENT))
45220Sstevel@tonic-gate if (event_mask & CS_EVENT_WRITE_PROTECT)
45230Sstevel@tonic-gate SCIntMask |= SBM_BVD1;
45240Sstevel@tonic-gate
45250Sstevel@tonic-gate if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) ==
45260Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT))
45270Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_READY)
45280Sstevel@tonic-gate SCIntMask |= SBM_BVD1;
45290Sstevel@tonic-gate
45300Sstevel@tonic-gate if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) ==
45310Sstevel@tonic-gate (PRR_BVD2_STATUS | PRR_BVD2_EVENT))
45320Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_LOW)
45330Sstevel@tonic-gate SCIntMask |= SBM_BVD1;
45340Sstevel@tonic-gate
45350Sstevel@tonic-gate if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) ==
45360Sstevel@tonic-gate (PRR_BVD1_STATUS | PRR_BVD1_EVENT))
45370Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_DEAD)
45380Sstevel@tonic-gate SCIntMask |= SBM_BVD1;
45390Sstevel@tonic-gate
45400Sstevel@tonic-gate } /* if (CONFIG_PINREPL_REG_PRESENT) */
45410Sstevel@tonic-gate } /* if (!SOCKET_IS_IO) */
45420Sstevel@tonic-gate
45430Sstevel@tonic-gate return (SCIntMask);
45440Sstevel@tonic-gate }
45450Sstevel@tonic-gate
45460Sstevel@tonic-gate /*
45470Sstevel@tonic-gate * cs_set_socket_event_mask - set the event mask for the socket
45480Sstevel@tonic-gate */
45490Sstevel@tonic-gate static int
cs_set_socket_event_mask(cs_socket_t * sp,unsigned event_mask)45500Sstevel@tonic-gate cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask)
45510Sstevel@tonic-gate {
45520Sstevel@tonic-gate get_socket_t get_socket;
45530Sstevel@tonic-gate set_socket_t set_socket;
45540Sstevel@tonic-gate
45550Sstevel@tonic-gate get_socket.socket = sp->socket_num;
45560Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
45570Sstevel@tonic-gate return (CS_BAD_SOCKET);
45580Sstevel@tonic-gate
45590Sstevel@tonic-gate set_socket.socket = sp->socket_num;
45600Sstevel@tonic-gate set_socket.SCIntMask = event_mask;
45610Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
45620Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
45630Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
45640Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting;
45650Sstevel@tonic-gate set_socket.IFType = get_socket.IFType;
45660Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
45670Sstevel@tonic-gate /* XXX (is ~0 correct here?) reset latched values */
45680Sstevel@tonic-gate set_socket.State = (unsigned)~0;
45690Sstevel@tonic-gate
45700Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
45710Sstevel@tonic-gate return (CS_BAD_SOCKET);
45720Sstevel@tonic-gate
45730Sstevel@tonic-gate return (CS_SUCCESS);
45740Sstevel@tonic-gate }
45750Sstevel@tonic-gate
45760Sstevel@tonic-gate /*
45770Sstevel@tonic-gate * ==== MTD handling section ====
45780Sstevel@tonic-gate */
45790Sstevel@tonic-gate static int
cs_deregister_mtd(client_handle_t client_handle)45800Sstevel@tonic-gate cs_deregister_mtd(client_handle_t client_handle)
45810Sstevel@tonic-gate {
45820Sstevel@tonic-gate
45830Sstevel@tonic-gate cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n",
45840Sstevel@tonic-gate (int)client_handle);
45850Sstevel@tonic-gate
45860Sstevel@tonic-gate return (CS_SUCCESS);
45870Sstevel@tonic-gate }
45880Sstevel@tonic-gate
45890Sstevel@tonic-gate /*
45900Sstevel@tonic-gate * ==== memory window handling section ====
45910Sstevel@tonic-gate */
45920Sstevel@tonic-gate
45930Sstevel@tonic-gate /*
45940Sstevel@tonic-gate * cs_request_window - searches through window list for the socket to find a
45950Sstevel@tonic-gate * memory window that matches the requested criteria;
45960Sstevel@tonic-gate * this is RequestWindow
45970Sstevel@tonic-gate *
45980Sstevel@tonic-gate * calling: cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
45990Sstevel@tonic-gate *
46000Sstevel@tonic-gate * On sucessful return, the window_handle_t * pointed to will
46010Sstevel@tonic-gate * contain a valid window handle for this window.
46020Sstevel@tonic-gate *
46030Sstevel@tonic-gate * returns: CS_SUCCESS - if window found
46040Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements
46050Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid
46060Sstevel@tonic-gate * CS_BAD_SIZE - if requested size can not be met
46070Sstevel@tonic-gate * CS_BAD_WINDOW - if an internal error occured
46080Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
46090Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket
46100Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
46110Sstevel@tonic-gate * flags are set
46120Sstevel@tonic-gate */
46130Sstevel@tonic-gate static int
cs_request_window(client_handle_t client_handle,window_handle_t * wh,win_req_t * rw)46140Sstevel@tonic-gate cs_request_window(client_handle_t client_handle,
46150Sstevel@tonic-gate window_handle_t *wh,
46160Sstevel@tonic-gate win_req_t *rw)
46170Sstevel@tonic-gate {
46180Sstevel@tonic-gate cs_socket_t *sp;
46190Sstevel@tonic-gate cs_window_t *cw;
46200Sstevel@tonic-gate client_t *client;
46210Sstevel@tonic-gate modify_win_t mw;
46220Sstevel@tonic-gate inquire_window_t iw;
46230Sstevel@tonic-gate uint32_t aw;
46240Sstevel@tonic-gate int error;
46250Sstevel@tonic-gate int client_lock_acquired;
46260Sstevel@tonic-gate uint32_t socket_num;
46270Sstevel@tonic-gate
46280Sstevel@tonic-gate /*
46290Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
46300Sstevel@tonic-gate * is, we don't support SS using this call.
46310Sstevel@tonic-gate */
46320Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
46330Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
46340Sstevel@tonic-gate
46350Sstevel@tonic-gate /*
46360Sstevel@tonic-gate * Make sure that none of the unsupported flags are set.
46370Sstevel@tonic-gate */
46380Sstevel@tonic-gate if (rw->Attributes & (/* Compatability */
46390Sstevel@tonic-gate WIN_PAGED |
46400Sstevel@tonic-gate WIN_SHARED |
46410Sstevel@tonic-gate WIN_FIRST_SHARED |
46420Sstevel@tonic-gate WIN_BINDING_SPECIFIC |
46430Sstevel@tonic-gate /* CS internal */
46440Sstevel@tonic-gate WIN_DATA_WIDTH_VALID |
46450Sstevel@tonic-gate /* IO window flags */
46460Sstevel@tonic-gate WIN_MEMORY_TYPE_IO |
46470Sstevel@tonic-gate /* CardBus flags */
46480Sstevel@tonic-gate WIN_DATA_WIDTH_32 |
46490Sstevel@tonic-gate WIN_PREFETCH_CACHE_MASK |
46500Sstevel@tonic-gate WIN_BAR_MASK))
46510Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
46520Sstevel@tonic-gate
46530Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
46540Sstevel@tonic-gate
46550Sstevel@tonic-gate /*
46560Sstevel@tonic-gate * Get a pointer to this client's socket structure.
46570Sstevel@tonic-gate */
46580Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
46590Sstevel@tonic-gate return (CS_BAD_SOCKET);
46600Sstevel@tonic-gate
46610Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
46620Sstevel@tonic-gate
46630Sstevel@tonic-gate /*
46640Sstevel@tonic-gate * Make sure that this is a valid client handle.
46650Sstevel@tonic-gate */
46660Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
46670Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46680Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
46690Sstevel@tonic-gate return (error);
46700Sstevel@tonic-gate }
46710Sstevel@tonic-gate
46720Sstevel@tonic-gate mutex_enter(&sp->lock);
46730Sstevel@tonic-gate
46740Sstevel@tonic-gate /*
46750Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
46760Sstevel@tonic-gate * for this client, then return an error.
46770Sstevel@tonic-gate */
46780Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
46790Sstevel@tonic-gate mutex_exit(&sp->lock);
46800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46810Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
46820Sstevel@tonic-gate return (CS_NO_CARD);
46830Sstevel@tonic-gate }
46840Sstevel@tonic-gate
46850Sstevel@tonic-gate mutex_exit(&sp->lock);
46860Sstevel@tonic-gate
46870Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
46880Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle));
46890Sstevel@tonic-gate
46900Sstevel@tonic-gate
46910Sstevel@tonic-gate /*
46920Sstevel@tonic-gate * See if we can find a window that matches the caller's criteria.
46930Sstevel@tonic-gate * If we can't, then thre's not much more that we can do except
46940Sstevel@tonic-gate * for return an error.
46950Sstevel@tonic-gate */
46960Sstevel@tonic-gate if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) !=
46970Sstevel@tonic-gate CS_SUCCESS) {
46980Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46990Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47000Sstevel@tonic-gate return (error);
47010Sstevel@tonic-gate }
47020Sstevel@tonic-gate
47030Sstevel@tonic-gate /*
47040Sstevel@tonic-gate * We got a window, now synthesize a new window handle for this
47050Sstevel@tonic-gate * client and get a pointer to the global window structs
47060Sstevel@tonic-gate * and assign this window to this client.
47070Sstevel@tonic-gate * We don't have to check for errors from cs_create_window_handle
47080Sstevel@tonic-gate * since that function always returns a valid window handle
47090Sstevel@tonic-gate * if it is given a valid window number.
47100Sstevel@tonic-gate */
47110Sstevel@tonic-gate *wh = cs_create_window_handle(aw);
47120Sstevel@tonic-gate if ((cw = cs_get_wp(aw)) == NULL) {
47130Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47140Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47150Sstevel@tonic-gate return (CS_BAD_WINDOW);
47160Sstevel@tonic-gate }
47170Sstevel@tonic-gate
47180Sstevel@tonic-gate cw->window_handle = *wh;
47190Sstevel@tonic-gate cw->client_handle = client_handle;
47200Sstevel@tonic-gate cw->socket_num = sp->socket_num;
47210Sstevel@tonic-gate cw->state |= (CW_ALLOCATED | CW_MEM);
47220Sstevel@tonic-gate
47230Sstevel@tonic-gate mw.Attributes = (
47240Sstevel@tonic-gate rw->Attributes |
47250Sstevel@tonic-gate WIN_DATA_WIDTH_VALID |
47260Sstevel@tonic-gate WIN_ACCESS_SPEED_VALID);
47270Sstevel@tonic-gate mw.AccessSpeed = rw->win_params.AccessSpeed;
47280Sstevel@tonic-gate
47290Sstevel@tonic-gate if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) !=
47300Sstevel@tonic-gate CS_SUCCESS) {
47310Sstevel@tonic-gate cw->state = 0;
47320Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47330Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47340Sstevel@tonic-gate return (error);
47350Sstevel@tonic-gate }
47360Sstevel@tonic-gate
47370Sstevel@tonic-gate /*
47380Sstevel@tonic-gate * Get any required card offset and pass it back to the client.
47390Sstevel@tonic-gate * This is not defined in the current PCMCIA spec. It is
47400Sstevel@tonic-gate * an aid to clients that want to use it to generate an
47410Sstevel@tonic-gate * optimum card offset.
47420Sstevel@tonic-gate */
47430Sstevel@tonic-gate iw.window = GET_WINDOW_NUMBER(*wh);
47440Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw);
47450Sstevel@tonic-gate
47460Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
47470Sstevel@tonic-gate rw->ReqOffset = rw->Size;
47480Sstevel@tonic-gate else
47490Sstevel@tonic-gate rw->ReqOffset = iw.mem_win_char.ReqOffset;
47500Sstevel@tonic-gate
47510Sstevel@tonic-gate /*
47520Sstevel@tonic-gate * Increment the client's memory window count; this is how we know
47530Sstevel@tonic-gate * when a client has any allocated memory windows.
47540Sstevel@tonic-gate */
47550Sstevel@tonic-gate client->memwin_count++;
47560Sstevel@tonic-gate
47570Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47580Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47590Sstevel@tonic-gate
47600Sstevel@tonic-gate return (CS_SUCCESS);
47610Sstevel@tonic-gate }
47620Sstevel@tonic-gate
47630Sstevel@tonic-gate /*
47640Sstevel@tonic-gate * cs_release_window - deallocates the window associated with the passed
47650Sstevel@tonic-gate * window handle; this is ReleaseWindow
47660Sstevel@tonic-gate *
47670Sstevel@tonic-gate * returns: CS_SUCCESS if window handle is valid and window was
47680Sstevel@tonic-gate * sucessfully deallocated
47690Sstevel@tonic-gate * CS_BAD_HANDLE if window handle is invalid or if window
47700Sstevel@tonic-gate * handle is valid but window is not allocated
47710Sstevel@tonic-gate */
47720Sstevel@tonic-gate static int
cs_release_window(window_handle_t wh)47730Sstevel@tonic-gate cs_release_window(window_handle_t wh)
47740Sstevel@tonic-gate {
47750Sstevel@tonic-gate cs_socket_t *sp;
47760Sstevel@tonic-gate cs_window_t *cw;
47770Sstevel@tonic-gate client_t *client;
47780Sstevel@tonic-gate int error;
47790Sstevel@tonic-gate int client_lock_acquired;
47800Sstevel@tonic-gate
47810Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
47820Sstevel@tonic-gate
47830Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) {
47840Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47850Sstevel@tonic-gate return (CS_BAD_HANDLE);
47860Sstevel@tonic-gate }
47870Sstevel@tonic-gate
47880Sstevel@tonic-gate /*
47890Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
47900Sstevel@tonic-gate * is, we don't support SS using this call.
47910Sstevel@tonic-gate */
47920Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(cw->client_handle)) {
47930Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
47940Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
47950Sstevel@tonic-gate }
47960Sstevel@tonic-gate
47970Sstevel@tonic-gate /*
47980Sstevel@tonic-gate * Get a pointer to this client's socket structure.
47990Sstevel@tonic-gate */
48000Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
48010Sstevel@tonic-gate return (CS_BAD_SOCKET);
48020Sstevel@tonic-gate
48030Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48040Sstevel@tonic-gate
48050Sstevel@tonic-gate /*
48060Sstevel@tonic-gate * Make sure that this is a valid client handle.
48070Sstevel@tonic-gate */
48080Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) {
48090Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48100Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48110Sstevel@tonic-gate return (error);
48120Sstevel@tonic-gate }
48130Sstevel@tonic-gate
48140Sstevel@tonic-gate /*
48150Sstevel@tonic-gate * Mark this window as not in use anymore.
48160Sstevel@tonic-gate */
48170Sstevel@tonic-gate cw->state &= ~CW_WIN_IN_USE;
48180Sstevel@tonic-gate
48190Sstevel@tonic-gate /*
48200Sstevel@tonic-gate * Decrement the client's memory window count; this is how we know
48210Sstevel@tonic-gate * when a client has any allocated memory windows.
48220Sstevel@tonic-gate */
48230Sstevel@tonic-gate if (!(--(client->memwin_count)))
48240Sstevel@tonic-gate client->flags &= ~CLIENT_WIN_ALLOCATED;
48250Sstevel@tonic-gate
48260Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48270Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48280Sstevel@tonic-gate
48290Sstevel@tonic-gate return (CS_SUCCESS);
48300Sstevel@tonic-gate }
48310Sstevel@tonic-gate
48320Sstevel@tonic-gate /*
48330Sstevel@tonic-gate * cs_modify_window - modifies a window's characteristics; this is ModifyWindow
48340Sstevel@tonic-gate */
48350Sstevel@tonic-gate static int
cs_modify_window(window_handle_t wh,modify_win_t * mw)48360Sstevel@tonic-gate cs_modify_window(window_handle_t wh, modify_win_t *mw)
48370Sstevel@tonic-gate {
48380Sstevel@tonic-gate cs_socket_t *sp;
48390Sstevel@tonic-gate cs_window_t *cw;
48400Sstevel@tonic-gate client_t *client;
48410Sstevel@tonic-gate int error;
48420Sstevel@tonic-gate int client_lock_acquired;
48430Sstevel@tonic-gate
48440Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
48450Sstevel@tonic-gate
48460Sstevel@tonic-gate /*
48470Sstevel@tonic-gate * Do some sanity checking - make sure that we can find a pointer
48480Sstevel@tonic-gate * to the window structure, and if we can, get the client that
48490Sstevel@tonic-gate * has allocated that window.
48500Sstevel@tonic-gate */
48510Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) {
48520Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48530Sstevel@tonic-gate return (CS_BAD_HANDLE);
48540Sstevel@tonic-gate }
48550Sstevel@tonic-gate
48560Sstevel@tonic-gate /*
48570Sstevel@tonic-gate * Get a pointer to this client's socket structure.
48580Sstevel@tonic-gate */
48590Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
48600Sstevel@tonic-gate return (CS_BAD_SOCKET);
48610Sstevel@tonic-gate
48620Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48630Sstevel@tonic-gate
48640Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) {
48650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48660Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48670Sstevel@tonic-gate return (error);
48680Sstevel@tonic-gate }
48690Sstevel@tonic-gate
48700Sstevel@tonic-gate mutex_enter(&sp->lock);
48710Sstevel@tonic-gate
48720Sstevel@tonic-gate /*
48730Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
48740Sstevel@tonic-gate * for this client, then return an error.
48750Sstevel@tonic-gate */
48760Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
48770Sstevel@tonic-gate mutex_exit(&sp->lock);
48780Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48790Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48800Sstevel@tonic-gate return (CS_NO_CARD);
48810Sstevel@tonic-gate }
48820Sstevel@tonic-gate
48830Sstevel@tonic-gate mutex_exit(&sp->lock);
48840Sstevel@tonic-gate
48850Sstevel@tonic-gate mw->Attributes &= (
48860Sstevel@tonic-gate WIN_MEMORY_TYPE_MASK |
48870Sstevel@tonic-gate WIN_ENABLE |
48880Sstevel@tonic-gate WIN_ACCESS_SPEED_VALID |
48890Sstevel@tonic-gate WIN_ACC_ENDIAN_MASK |
48900Sstevel@tonic-gate WIN_ACC_ORDER_MASK);
48910Sstevel@tonic-gate
48920Sstevel@tonic-gate mw->Attributes &= ~WIN_DATA_WIDTH_VALID;
48930Sstevel@tonic-gate
48940Sstevel@tonic-gate if ((error = cs_modify_mem_window(wh, mw, NULL, NULL)) != CS_SUCCESS) {
48950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48960Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
48970Sstevel@tonic-gate return (error);
48980Sstevel@tonic-gate }
48990Sstevel@tonic-gate
49000Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
49010Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
49020Sstevel@tonic-gate
49030Sstevel@tonic-gate return (CS_SUCCESS);
49040Sstevel@tonic-gate }
49050Sstevel@tonic-gate
49060Sstevel@tonic-gate /*
49070Sstevel@tonic-gate * cs_modify_mem_window - modifies a window's characteristics; used internally
49080Sstevel@tonic-gate * by Card Services
49090Sstevel@tonic-gate *
49100Sstevel@tonic-gate * If *wr is NULL, it means that we're being called by ModifyWindow
49110Sstevel@tonic-gate * If *wr is non-NULL, it means that we are being called by RequestWindow
49120Sstevel@tonic-gate * and so we can't use SS_GetWindow.
49130Sstevel@tonic-gate */
49140Sstevel@tonic-gate static int
cs_modify_mem_window(window_handle_t wh,modify_win_t * mw,win_req_t * wr,int sn)49150Sstevel@tonic-gate cs_modify_mem_window(window_handle_t wh, modify_win_t *mw,
49160Sstevel@tonic-gate win_req_t *wr, int sn)
49170Sstevel@tonic-gate {
49180Sstevel@tonic-gate get_window_t gw;
49190Sstevel@tonic-gate set_window_t sw;
49200Sstevel@tonic-gate set_page_t set_page;
49210Sstevel@tonic-gate get_page_t get_page;
49220Sstevel@tonic-gate
49230Sstevel@tonic-gate /*
49240Sstevel@tonic-gate * If the win_req_t struct pointer is NULL, it means that
49250Sstevel@tonic-gate * we're being called by ModifyWindow, so get the
49260Sstevel@tonic-gate * current window characteristics.
49270Sstevel@tonic-gate */
49280Sstevel@tonic-gate if (!wr) {
49290Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh);
49300Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
49310Sstevel@tonic-gate return (CS_BAD_WINDOW);
49320Sstevel@tonic-gate sw.state = gw.state;
49330Sstevel@tonic-gate sw.socket = gw.socket;
49340Sstevel@tonic-gate sw.WindowSize = gw.size;
49350Sstevel@tonic-gate } else {
49360Sstevel@tonic-gate sw.state = 0;
49370Sstevel@tonic-gate sw.socket = sn;
49380Sstevel@tonic-gate sw.WindowSize = wr->Size;
49390Sstevel@tonic-gate }
49400Sstevel@tonic-gate
49410Sstevel@tonic-gate /*
49420Sstevel@tonic-gate * If we're being called by RequestWindow, we must always have
49430Sstevel@tonic-gate * WIN_ACCESS_SPEED_VALID set since get_window_t is not
49440Sstevel@tonic-gate * defined.
49450Sstevel@tonic-gate */
49460Sstevel@tonic-gate if (mw->Attributes & WIN_ACCESS_SPEED_VALID) {
49470Sstevel@tonic-gate convert_speed_t convert_speed;
49480Sstevel@tonic-gate
49490Sstevel@tonic-gate convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS;
49500Sstevel@tonic-gate convert_speed.devspeed = mw->AccessSpeed;
49510Sstevel@tonic-gate
49520Sstevel@tonic-gate if (cs_convert_speed(&convert_speed) != CS_SUCCESS)
49530Sstevel@tonic-gate return (CS_BAD_SPEED);
49540Sstevel@tonic-gate
49550Sstevel@tonic-gate sw.speed = convert_speed.nS;
49560Sstevel@tonic-gate } else {
49570Sstevel@tonic-gate sw.speed = gw.speed;
49580Sstevel@tonic-gate }
49590Sstevel@tonic-gate
49600Sstevel@tonic-gate if (!wr) {
49610Sstevel@tonic-gate get_page.window = GET_WINDOW_NUMBER(wh);
49620Sstevel@tonic-gate get_page.page = 0;
49630Sstevel@tonic-gate if (SocketServices(SS_GetPage, &get_page) != SUCCESS)
49640Sstevel@tonic-gate return (CS_BAD_WINDOW);
49650Sstevel@tonic-gate set_page.state = get_page.state;
49660Sstevel@tonic-gate set_page.offset = get_page.offset;
49670Sstevel@tonic-gate } else {
49680Sstevel@tonic-gate set_page.state = 0;
49690Sstevel@tonic-gate set_page.offset = 0;
49700Sstevel@tonic-gate }
49710Sstevel@tonic-gate
49720Sstevel@tonic-gate if (mw->Attributes & WIN_ENABLE) {
49730Sstevel@tonic-gate sw.state |= WS_ENABLED;
49740Sstevel@tonic-gate set_page.state |= PS_ENABLED;
49750Sstevel@tonic-gate } else {
49760Sstevel@tonic-gate sw.state &= ~WS_ENABLED;
49770Sstevel@tonic-gate set_page.state &= ~PS_ENABLED;
49780Sstevel@tonic-gate }
49790Sstevel@tonic-gate
49800Sstevel@tonic-gate if (mw->Attributes & WIN_DATA_WIDTH_VALID) {
49810Sstevel@tonic-gate if (mw->Attributes & WIN_DATA_WIDTH_16)
49820Sstevel@tonic-gate sw.state |= WS_16BIT;
49830Sstevel@tonic-gate else
49840Sstevel@tonic-gate sw.state &= ~WS_16BIT;
49850Sstevel@tonic-gate }
49860Sstevel@tonic-gate
49870Sstevel@tonic-gate sw.window = GET_WINDOW_NUMBER(wh);
49880Sstevel@tonic-gate sw.base = 0;
49890Sstevel@tonic-gate
49900Sstevel@tonic-gate cs_set_acc_attributes(&sw, mw->Attributes);
49910Sstevel@tonic-gate
49920Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &sw) != SUCCESS)
49930Sstevel@tonic-gate return (CS_BAD_WINDOW);
49940Sstevel@tonic-gate
49950Sstevel@tonic-gate if (mw->Attributes & WIN_MEMORY_TYPE_AM)
49960Sstevel@tonic-gate set_page.state |= PS_ATTRIBUTE;
49970Sstevel@tonic-gate else
49980Sstevel@tonic-gate set_page.state &= ~PS_ATTRIBUTE;
49990Sstevel@tonic-gate
50000Sstevel@tonic-gate set_page.window = GET_WINDOW_NUMBER(wh);
50010Sstevel@tonic-gate set_page.page = 0;
50020Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS)
50030Sstevel@tonic-gate return (CS_BAD_OFFSET);
50040Sstevel@tonic-gate
50050Sstevel@tonic-gate /*
50060Sstevel@tonic-gate * Return the current base address of this window
50070Sstevel@tonic-gate */
50080Sstevel@tonic-gate if (wr) {
50090Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh);
50100Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
50110Sstevel@tonic-gate return (CS_BAD_WINDOW);
50120Sstevel@tonic-gate
50130Sstevel@tonic-gate wr->Base.handle = (acc_handle_t)gw.handle;
50140Sstevel@tonic-gate }
50150Sstevel@tonic-gate
50160Sstevel@tonic-gate return (CS_SUCCESS);
50170Sstevel@tonic-gate }
50180Sstevel@tonic-gate
50190Sstevel@tonic-gate /*
50200Sstevel@tonic-gate * cs_map_mem_page - sets the card offset of the mapped window
50210Sstevel@tonic-gate */
50220Sstevel@tonic-gate static int
cs_map_mem_page(window_handle_t wh,map_mem_page_t * mmp)50230Sstevel@tonic-gate cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp)
50240Sstevel@tonic-gate {
50250Sstevel@tonic-gate cs_socket_t *sp;
50260Sstevel@tonic-gate cs_window_t *cw;
50270Sstevel@tonic-gate client_t *client;
50280Sstevel@tonic-gate inquire_window_t iw;
50290Sstevel@tonic-gate get_window_t gw;
50300Sstevel@tonic-gate set_page_t set_page;
50310Sstevel@tonic-gate get_page_t get_page;
50320Sstevel@tonic-gate int error;
50330Sstevel@tonic-gate uint32_t size;
50340Sstevel@tonic-gate int client_lock_acquired;
50350Sstevel@tonic-gate
50360Sstevel@tonic-gate /*
50370Sstevel@tonic-gate * We don't support paged windows, so never allow a page number
50380Sstevel@tonic-gate * of other than 0
50390Sstevel@tonic-gate */
50400Sstevel@tonic-gate if (mmp->Page)
50410Sstevel@tonic-gate return (CS_BAD_PAGE);
50420Sstevel@tonic-gate
50430Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
50440Sstevel@tonic-gate
50450Sstevel@tonic-gate /*
50460Sstevel@tonic-gate * Do some sanity checking - make sure that we can find a pointer
50470Sstevel@tonic-gate * to the window structure, and if we can, get the client that
50480Sstevel@tonic-gate * has allocated that window.
50490Sstevel@tonic-gate */
50500Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) {
50510Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
50520Sstevel@tonic-gate return (CS_BAD_HANDLE);
50530Sstevel@tonic-gate }
50540Sstevel@tonic-gate
50550Sstevel@tonic-gate /*
50560Sstevel@tonic-gate * Get a pointer to this client's socket structure.
50570Sstevel@tonic-gate */
50580Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
50590Sstevel@tonic-gate return (CS_BAD_SOCKET);
50600Sstevel@tonic-gate
50610Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
50620Sstevel@tonic-gate
50630Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) {
50640Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50650Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
50660Sstevel@tonic-gate return (error);
50670Sstevel@tonic-gate }
50680Sstevel@tonic-gate
50690Sstevel@tonic-gate mutex_enter(&sp->lock);
50700Sstevel@tonic-gate
50710Sstevel@tonic-gate /*
50720Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
50730Sstevel@tonic-gate * for this client, then return an error.
50740Sstevel@tonic-gate */
50750Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
50760Sstevel@tonic-gate mutex_exit(&sp->lock);
50770Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50780Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
50790Sstevel@tonic-gate return (CS_NO_CARD);
50800Sstevel@tonic-gate }
50810Sstevel@tonic-gate
50820Sstevel@tonic-gate mutex_exit(&sp->lock);
50830Sstevel@tonic-gate
50840Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh);
50850Sstevel@tonic-gate SocketServices(SS_GetWindow, &gw);
50860Sstevel@tonic-gate
50870Sstevel@tonic-gate iw.window = GET_WINDOW_NUMBER(wh);
50880Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw);
50890Sstevel@tonic-gate
50900Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
50910Sstevel@tonic-gate size = gw.size;
50920Sstevel@tonic-gate else
50930Sstevel@tonic-gate size = iw.mem_win_char.ReqOffset;
50940Sstevel@tonic-gate
50950Sstevel@tonic-gate if (((mmp->CardOffset/size)*size) != mmp->CardOffset) {
50960Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50970Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
50980Sstevel@tonic-gate return (CS_BAD_OFFSET);
50990Sstevel@tonic-gate }
51000Sstevel@tonic-gate
51010Sstevel@tonic-gate get_page.window = GET_WINDOW_NUMBER(wh);
51020Sstevel@tonic-gate get_page.page = 0;
51030Sstevel@tonic-gate SocketServices(SS_GetPage, &get_page);
51040Sstevel@tonic-gate
51050Sstevel@tonic-gate set_page.window = GET_WINDOW_NUMBER(wh);
51060Sstevel@tonic-gate set_page.page = 0;
51070Sstevel@tonic-gate set_page.state = get_page.state;
51080Sstevel@tonic-gate set_page.offset = mmp->CardOffset;
51090Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
51100Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51110Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
51120Sstevel@tonic-gate return (CS_BAD_OFFSET);
51130Sstevel@tonic-gate }
51140Sstevel@tonic-gate
51150Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51160Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
51170Sstevel@tonic-gate
51180Sstevel@tonic-gate return (CS_SUCCESS);
51190Sstevel@tonic-gate }
51200Sstevel@tonic-gate
51210Sstevel@tonic-gate /*
51220Sstevel@tonic-gate * cs_find_window - finds the window associated with the passed window
51230Sstevel@tonic-gate * handle; if the window handle is invalid or no
51240Sstevel@tonic-gate * windows match the passed window handle, NULL
51250Sstevel@tonic-gate * is returned. Note that the window must be
51260Sstevel@tonic-gate * allocated for this function to return a valid
51270Sstevel@tonic-gate * window pointer.
51280Sstevel@tonic-gate *
51290Sstevel@tonic-gate * returns: cs_window_t * pointer to the found window
51300Sstevel@tonic-gate * NULL if window handle invalid or window not allocated
51310Sstevel@tonic-gate */
51320Sstevel@tonic-gate cs_window_t *
cs_find_window(window_handle_t wh)51330Sstevel@tonic-gate cs_find_window(window_handle_t wh)
51340Sstevel@tonic-gate {
51350Sstevel@tonic-gate cs_window_t *cw;
51360Sstevel@tonic-gate
51370Sstevel@tonic-gate if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) ||
51380Sstevel@tonic-gate (GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC))
51390Sstevel@tonic-gate return ((cs_window_t *)NULL);
51400Sstevel@tonic-gate
51410Sstevel@tonic-gate if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL)
51420Sstevel@tonic-gate return (NULL);
51430Sstevel@tonic-gate
51440Sstevel@tonic-gate if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM))
51450Sstevel@tonic-gate return (cw);
51460Sstevel@tonic-gate
51470Sstevel@tonic-gate return ((cs_window_t *)NULL);
51480Sstevel@tonic-gate }
51490Sstevel@tonic-gate
51500Sstevel@tonic-gate /*
51510Sstevel@tonic-gate * cs_create_window_handle - creates a unique window handle based on the
51520Sstevel@tonic-gate * passed window number.
51530Sstevel@tonic-gate */
51540Sstevel@tonic-gate static window_handle_t
cs_create_window_handle(uint32_t aw)51550Sstevel@tonic-gate cs_create_window_handle(uint32_t aw)
51560Sstevel@tonic-gate {
51570Sstevel@tonic-gate return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK));
51580Sstevel@tonic-gate }
51590Sstevel@tonic-gate
51600Sstevel@tonic-gate /*
51610Sstevel@tonic-gate * cs_find_mem_window - tries to find a memory window matching the caller's
51620Sstevel@tonic-gate * criteria
51630Sstevel@tonic-gate *
51640Sstevel@tonic-gate * We return the first window that matches the requested criteria.
51650Sstevel@tonic-gate *
51660Sstevel@tonic-gate * returns: CS_SUCCESS - if memory window found
51670Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements
51680Sstevel@tonic-gate * CS_BAD_SIZE - if requested size can not be met
51690Sstevel@tonic-gate * CS_BAD_WINDOW - if an internal error occured
51700Sstevel@tonic-gate */
51710Sstevel@tonic-gate /* BEGIN CSTYLED */
51720Sstevel@tonic-gate static int
cs_find_mem_window(uint32_t sn,win_req_t * rw,uint32_t * assigned_window)51730Sstevel@tonic-gate cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window)
51740Sstevel@tonic-gate {
51750Sstevel@tonic-gate uint32_t wn;
51760Sstevel@tonic-gate int error = CS_OUT_OF_RESOURCE;
51770Sstevel@tonic-gate uint32_t window_num = PCMCIA_MAX_WINDOWS;
51780Sstevel@tonic-gate uint32_t min_size = UINT_MAX;
51790Sstevel@tonic-gate inquire_window_t inquire_window, *iw;
51800Sstevel@tonic-gate uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps;
51810Sstevel@tonic-gate uint32_t tws;
51820Sstevel@tonic-gate
51830Sstevel@tonic-gate iw = &inquire_window;
51840Sstevel@tonic-gate
51850Sstevel@tonic-gate for (wn = 0; wn < cs_globals.num_windows; wn++) {
51860Sstevel@tonic-gate cs_window_t *cw;
51870Sstevel@tonic-gate
51880Sstevel@tonic-gate /*
51890Sstevel@tonic-gate * If we can't get a pointer to this window, we should contine
51900Sstevel@tonic-gate * with scanning the next window, since this window might have
51910Sstevel@tonic-gate * been dropped.
51920Sstevel@tonic-gate */
51930Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) != NULL) {
51940Sstevel@tonic-gate iw->window = wn;
51950Sstevel@tonic-gate
51960Sstevel@tonic-gate if (SocketServices(SS_InquireWindow, iw) != SUCCESS)
51970Sstevel@tonic-gate return (CS_BAD_WINDOW);
51980Sstevel@tonic-gate
51990Sstevel@tonic-gate MinSize = iw->mem_win_char.MinSize;
52000Sstevel@tonic-gate MaxSize = iw->mem_win_char.MaxSize;
52010Sstevel@tonic-gate ReqGran = iw->mem_win_char.ReqGran;
52020Sstevel@tonic-gate MemWndCaps = iw->mem_win_char.MemWndCaps;
52030Sstevel@tonic-gate WndCaps = iw->WndCaps;
52040Sstevel@tonic-gate
52050Sstevel@tonic-gate if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
52060Sstevel@tonic-gate WINDOW_AVAILABLE_FOR_MEM(cw) &&
52070Sstevel@tonic-gate WndCaps & (WC_COMMON|WC_ATTRIBUTE)) {
52080Sstevel@tonic-gate if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) ==
52090Sstevel@tonic-gate CS_SUCCESS) {
52100Sstevel@tonic-gate error = CS_OUT_OF_RESOURCE;
52110Sstevel@tonic-gate if (cs_memwin_space_and_map_ok(iw, rw)) {
52120Sstevel@tonic-gate error = CS_BAD_SIZE;
52130Sstevel@tonic-gate if (!rw->Size) {
52140Sstevel@tonic-gate min_size = min(min_size, MinSize);
52150Sstevel@tonic-gate window_num = wn;
52160Sstevel@tonic-gate goto found_window;
52170Sstevel@tonic-gate } else {
52180Sstevel@tonic-gate if (!(MemWndCaps & WC_SIZE)) {
52190Sstevel@tonic-gate if (rw->Size == MinSize) {
52200Sstevel@tonic-gate min_size = MinSize;
52210Sstevel@tonic-gate window_num = wn;
52220Sstevel@tonic-gate goto found_window;
52230Sstevel@tonic-gate }
52240Sstevel@tonic-gate } else { /* WC_SIZE */
52250Sstevel@tonic-gate if (!ReqGran) {
52260Sstevel@tonic-gate error = CS_BAD_WINDOW;
52270Sstevel@tonic-gate } else {
52280Sstevel@tonic-gate if ((rw->Size >= MinSize) &&
52290Sstevel@tonic-gate (rw->Size <= MaxSize)) {
52300Sstevel@tonic-gate if (MemWndCaps & WC_POW2) {
52310Sstevel@tonic-gate unsigned rg = ReqGran;
52320Sstevel@tonic-gate for (tws = MinSize; tws <= MaxSize;
52330Sstevel@tonic-gate rg = (rg<<1)) {
52340Sstevel@tonic-gate if (rw->Size == tws) {
52350Sstevel@tonic-gate min_size = tws;
52360Sstevel@tonic-gate window_num = wn;
52370Sstevel@tonic-gate goto found_window;
52380Sstevel@tonic-gate }
52390Sstevel@tonic-gate tws += rg;
52400Sstevel@tonic-gate } /* for (tws) */
52410Sstevel@tonic-gate } else {
52420Sstevel@tonic-gate for (tws = MinSize; tws <= MaxSize;
52430Sstevel@tonic-gate tws += ReqGran) {
52440Sstevel@tonic-gate if (rw->Size == tws) {
52450Sstevel@tonic-gate min_size = tws;
52460Sstevel@tonic-gate window_num = wn;
52470Sstevel@tonic-gate goto found_window;
52480Sstevel@tonic-gate }
52490Sstevel@tonic-gate } /* for (tws) */
52500Sstevel@tonic-gate } /* if (!WC_POW2) */
52510Sstevel@tonic-gate } /* if (Size >= MinSize) */
52520Sstevel@tonic-gate } /* if (!ReqGran) */
52530Sstevel@tonic-gate } /* if (WC_SIZE) */
52540Sstevel@tonic-gate } /* if (rw->Size) */
52550Sstevel@tonic-gate } /* if (cs_space_and_map_ok) */
52560Sstevel@tonic-gate } /* if (cs_valid_window_speed) */
52570Sstevel@tonic-gate } /* if (WINDOW_FOR_SOCKET) */
52580Sstevel@tonic-gate } /* if (cs_get_wp) */
52590Sstevel@tonic-gate } /* for (wn) */
52600Sstevel@tonic-gate
52610Sstevel@tonic-gate /*
52620Sstevel@tonic-gate * If we got here and the window_num wasn't set by any window
52630Sstevel@tonic-gate * matches in the above code, it means that we didn't
52640Sstevel@tonic-gate * find a window matching the caller's criteria.
52650Sstevel@tonic-gate * If the error is CS_BAD_TYPE, it means that the last reason
52660Sstevel@tonic-gate * that we couldn't match a window was because the caller's
52670Sstevel@tonic-gate * requested speed was out of range of the last window that
52680Sstevel@tonic-gate * we checked. We convert this error code to CS_OUT_OF_RESOURCE
52690Sstevel@tonic-gate * to conform to the RequestWindow section of the PCMCIA
52700Sstevel@tonic-gate * Card Services spec.
52710Sstevel@tonic-gate */
52720Sstevel@tonic-gate if (window_num == PCMCIA_MAX_WINDOWS) {
52730Sstevel@tonic-gate if (error == CS_BAD_TYPE)
52740Sstevel@tonic-gate error = CS_OUT_OF_RESOURCE;
52750Sstevel@tonic-gate return (error);
52760Sstevel@tonic-gate }
52770Sstevel@tonic-gate
52780Sstevel@tonic-gate found_window:
52790Sstevel@tonic-gate rw->Size = min_size;
52800Sstevel@tonic-gate *assigned_window = window_num;
52810Sstevel@tonic-gate iw->window = window_num;
52820Sstevel@tonic-gate SocketServices(SS_InquireWindow, iw);
52830Sstevel@tonic-gate MemWndCaps = iw->mem_win_char.MemWndCaps;
52840Sstevel@tonic-gate
52850Sstevel@tonic-gate if (MemWndCaps & WC_CALIGN)
52860Sstevel@tonic-gate rw->Attributes |= WIN_OFFSET_SIZE;
52870Sstevel@tonic-gate else
52880Sstevel@tonic-gate rw->Attributes &= ~WIN_OFFSET_SIZE;
52890Sstevel@tonic-gate return (CS_SUCCESS);
52900Sstevel@tonic-gate }
52910Sstevel@tonic-gate /* END CSTYLED */
52920Sstevel@tonic-gate
52930Sstevel@tonic-gate /*
52940Sstevel@tonic-gate * cs_memwin_space_and_map_ok - checks to see if the passed window mapping
52950Sstevel@tonic-gate * capabilities and window speeds are in the
52960Sstevel@tonic-gate * range of the passed window.
52970Sstevel@tonic-gate *
52980Sstevel@tonic-gate * returns: 0 - if the capabilities are out of range
52990Sstevel@tonic-gate * 1 - if the capabilities are in range
53000Sstevel@tonic-gate */
53010Sstevel@tonic-gate static int
cs_memwin_space_and_map_ok(inquire_window_t * iw,win_req_t * rw)53020Sstevel@tonic-gate cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw)
53030Sstevel@tonic-gate {
53040Sstevel@tonic-gate
53050Sstevel@tonic-gate #ifdef CS_DEBUG
53060Sstevel@tonic-gate if (cs_debug > 240)
53070Sstevel@tonic-gate printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
53080Sstevel@tonic-gate "WndCaps 0x%x MemWndCaps 0x%x\n",
53090Sstevel@tonic-gate (int)rw->Attributes,
53100Sstevel@tonic-gate (int)rw->win_params.AccessSpeed,
53110Sstevel@tonic-gate iw->WndCaps,
53120Sstevel@tonic-gate iw->mem_win_char.MemWndCaps);
53130Sstevel@tonic-gate #endif
53140Sstevel@tonic-gate
53150Sstevel@tonic-gate if (rw->win_params.AccessSpeed & WIN_USE_WAIT) {
53160Sstevel@tonic-gate if (!(iw->WndCaps & WC_WAIT))
53170Sstevel@tonic-gate return (0);
53180Sstevel@tonic-gate }
53190Sstevel@tonic-gate
53200Sstevel@tonic-gate if (rw->Attributes & WIN_DATA_WIDTH_16) {
53210Sstevel@tonic-gate if (!(iw->mem_win_char.MemWndCaps & WC_16BIT))
53220Sstevel@tonic-gate return (0);
53230Sstevel@tonic-gate } else {
53240Sstevel@tonic-gate if (!(iw->mem_win_char.MemWndCaps & WC_8BIT))
53250Sstevel@tonic-gate return (0);
53260Sstevel@tonic-gate }
53270Sstevel@tonic-gate
53280Sstevel@tonic-gate if (rw->Attributes & WIN_MEMORY_TYPE_AM) {
53290Sstevel@tonic-gate if (!(iw->WndCaps & WC_ATTRIBUTE))
53300Sstevel@tonic-gate return (0);
53310Sstevel@tonic-gate }
53320Sstevel@tonic-gate
53330Sstevel@tonic-gate if (rw->Attributes & WIN_MEMORY_TYPE_CM) {
53340Sstevel@tonic-gate if (!(iw->WndCaps & WC_COMMON))
53350Sstevel@tonic-gate return (0);
53360Sstevel@tonic-gate }
53370Sstevel@tonic-gate
53380Sstevel@tonic-gate return (1);
53390Sstevel@tonic-gate }
53400Sstevel@tonic-gate
53410Sstevel@tonic-gate /*
53420Sstevel@tonic-gate * cs_valid_window_speed - checks to see if requested window speed
53430Sstevel@tonic-gate * is in range of passed window
53440Sstevel@tonic-gate *
53450Sstevel@tonic-gate * The inquire_window_t struct gives us speeds in nS, and we
53460Sstevel@tonic-gate * get speeds in the AccessSpeed variable as a devspeed code.
53470Sstevel@tonic-gate *
53480Sstevel@tonic-gate * returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
53490Sstevel@tonic-gate * CS_BAD_TYPE - if AccessSpeed is not in range of valid
53500Sstevel@tonic-gate * speed for this window
53510Sstevel@tonic-gate * CS_SUCCESS - if window speed is in range
53520Sstevel@tonic-gate */
53530Sstevel@tonic-gate static int
cs_valid_window_speed(inquire_window_t * iw,uint32_t AccessSpeed)53540Sstevel@tonic-gate cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed)
53550Sstevel@tonic-gate {
53560Sstevel@tonic-gate convert_speed_t convert_speed, *cs;
53570Sstevel@tonic-gate
53580Sstevel@tonic-gate cs = &convert_speed;
53590Sstevel@tonic-gate
53600Sstevel@tonic-gate cs->Attributes = CONVERT_DEVSPEED_TO_NS;
53610Sstevel@tonic-gate cs->devspeed = AccessSpeed;
53620Sstevel@tonic-gate
53630Sstevel@tonic-gate if (cs_convert_speed(cs) != CS_SUCCESS)
53640Sstevel@tonic-gate return (CS_BAD_SPEED);
53650Sstevel@tonic-gate
53660Sstevel@tonic-gate if ((cs->nS < iw->mem_win_char.Fastest) ||
53670Sstevel@tonic-gate (cs->nS > iw->mem_win_char.Slowest))
53680Sstevel@tonic-gate return (CS_BAD_TYPE);
53690Sstevel@tonic-gate
53700Sstevel@tonic-gate return (CS_SUCCESS);
53710Sstevel@tonic-gate }
53720Sstevel@tonic-gate
53730Sstevel@tonic-gate /*
53740Sstevel@tonic-gate * ==== IO window handling section ====
53750Sstevel@tonic-gate */
53760Sstevel@tonic-gate
53770Sstevel@tonic-gate /*
53780Sstevel@tonic-gate * cs_request_io - provides IO resources for clients; this is RequestIO
53790Sstevel@tonic-gate *
53800Sstevel@tonic-gate * calling: cs_request_io(client_handle_t, io_req_t *)
53810Sstevel@tonic-gate *
53820Sstevel@tonic-gate * returns: CS_SUCCESS - if IO resources available for client
53830Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements
53840Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid
53850Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
53860Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket
53870Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
53880Sstevel@tonic-gate * flags are set
53890Sstevel@tonic-gate * CS_BAD_BASE - if either or both base port addresses
53900Sstevel@tonic-gate * are invalid or out of range
53910Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has
53920Sstevel@tonic-gate * already been done
53930Sstevel@tonic-gate * CS_IN_USE - IO ports already in use or function has
53940Sstevel@tonic-gate * already been called
53950Sstevel@tonic-gate * CS_BAD_WINDOW - if failure while trying to set window
53960Sstevel@tonic-gate * characteristics
53970Sstevel@tonic-gate */
53980Sstevel@tonic-gate static int
cs_request_io(client_handle_t client_handle,io_req_t * ior)53990Sstevel@tonic-gate cs_request_io(client_handle_t client_handle, io_req_t *ior)
54000Sstevel@tonic-gate {
54010Sstevel@tonic-gate cs_socket_t *sp;
54020Sstevel@tonic-gate client_t *client;
54030Sstevel@tonic-gate int error;
54040Sstevel@tonic-gate int client_lock_acquired;
54050Sstevel@tonic-gate uint32_t socket_num;
54060Sstevel@tonic-gate
54070Sstevel@tonic-gate /*
54080Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
54090Sstevel@tonic-gate * is, we don't support SS using this call.
54100Sstevel@tonic-gate */
54110Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
54120Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
54130Sstevel@tonic-gate
54140Sstevel@tonic-gate /*
54150Sstevel@tonic-gate * If the client has only requested one IO range, then make sure
54160Sstevel@tonic-gate * that the Attributes2 filed is clear.
54170Sstevel@tonic-gate */
54180Sstevel@tonic-gate if (!ior->NumPorts2)
54190Sstevel@tonic-gate ior->Attributes2 = 0;
54200Sstevel@tonic-gate
54210Sstevel@tonic-gate /*
54220Sstevel@tonic-gate * Make sure that none of the unsupported or reserved flags are set.
54230Sstevel@tonic-gate */
54240Sstevel@tonic-gate if ((ior->Attributes1 | ior->Attributes2) & (IO_SHARED |
54250Sstevel@tonic-gate IO_FIRST_SHARED |
54260Sstevel@tonic-gate IO_FORCE_ALIAS_ACCESS |
54270Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
54280Sstevel@tonic-gate IO_DISABLE_WINDOW))
54290Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
54300Sstevel@tonic-gate
54310Sstevel@tonic-gate /*
54320Sstevel@tonic-gate * Make sure that we have a port count for the first region.
54330Sstevel@tonic-gate */
54340Sstevel@tonic-gate if (!ior->NumPorts1)
54350Sstevel@tonic-gate return (CS_BAD_BASE);
54360Sstevel@tonic-gate
54370Sstevel@tonic-gate /*
54380Sstevel@tonic-gate * If we're being asked for multiple IO ranges, then both base port
54390Sstevel@tonic-gate * members must be non-zero.
54400Sstevel@tonic-gate */
54410Sstevel@tonic-gate if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base))
54420Sstevel@tonic-gate return (CS_BAD_BASE);
54430Sstevel@tonic-gate
54440Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
54450Sstevel@tonic-gate
54460Sstevel@tonic-gate /*
54470Sstevel@tonic-gate * Get a pointer to this client's socket structure.
54480Sstevel@tonic-gate */
54490Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
54500Sstevel@tonic-gate return (CS_BAD_SOCKET);
54510Sstevel@tonic-gate
54520Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
54530Sstevel@tonic-gate
54540Sstevel@tonic-gate /*
54550Sstevel@tonic-gate * Make sure that this is a valid client handle.
54560Sstevel@tonic-gate */
54570Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
54580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54590Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
54600Sstevel@tonic-gate return (error);
54610Sstevel@tonic-gate }
54620Sstevel@tonic-gate
54630Sstevel@tonic-gate /*
54640Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow
54650Sstevel@tonic-gate * this call.
54660Sstevel@tonic-gate */
54670Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) {
54680Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54690Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
54700Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED);
54710Sstevel@tonic-gate }
54720Sstevel@tonic-gate
54730Sstevel@tonic-gate /*
54740Sstevel@tonic-gate * If RequestIO has already been done, we don't allow this call.
54750Sstevel@tonic-gate */
54760Sstevel@tonic-gate if (client->flags & REQ_IO_DONE) {
54770Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54780Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
54790Sstevel@tonic-gate return (CS_IN_USE);
54800Sstevel@tonic-gate }
54810Sstevel@tonic-gate
54820Sstevel@tonic-gate mutex_enter(&sp->lock);
54830Sstevel@tonic-gate
54840Sstevel@tonic-gate /*
54850Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
54860Sstevel@tonic-gate * for this client, then return an error.
54870Sstevel@tonic-gate */
54880Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
54890Sstevel@tonic-gate mutex_exit(&sp->lock);
54900Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54910Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
54920Sstevel@tonic-gate return (CS_NO_CARD);
54930Sstevel@tonic-gate }
54940Sstevel@tonic-gate
54950Sstevel@tonic-gate mutex_exit(&sp->lock);
54960Sstevel@tonic-gate
54970Sstevel@tonic-gate /*
54980Sstevel@tonic-gate * If we're only being asked for one IO range, then set BasePort2 to
54990Sstevel@tonic-gate * zero, since we use it later on.
55000Sstevel@tonic-gate */
55010Sstevel@tonic-gate if (!ior->NumPorts2)
55020Sstevel@tonic-gate ior->BasePort2.base = 0;
55030Sstevel@tonic-gate
55040Sstevel@tonic-gate /*
55050Sstevel@tonic-gate * See if we can allow Card Services to select the base address
55060Sstevel@tonic-gate * value for this card; if the client has specified a non-zero
55070Sstevel@tonic-gate * base IO address but the card doesn't decode enough IO
55080Sstevel@tonic-gate * address lines to uniquely use that address, then we have
55090Sstevel@tonic-gate * the flexibility to choose an alternative base address.
55100Sstevel@tonic-gate * Note that if the client specifies that the card decodes zero
55110Sstevel@tonic-gate * IO address lines, then we have to use the NumPortsX
55120Sstevel@tonic-gate * values to figure out how many address lines the card
55130Sstevel@tonic-gate * actually decodes, and we have to round the NumPortsX
55140Sstevel@tonic-gate * values up to the closest power of two.
55150Sstevel@tonic-gate */
55160Sstevel@tonic-gate if (ior->IOAddrLines) {
55170Sstevel@tonic-gate ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base,
55180Sstevel@tonic-gate ior->IOAddrLines);
55190Sstevel@tonic-gate ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base,
55200Sstevel@tonic-gate ior->IOAddrLines);
55210Sstevel@tonic-gate } else {
55220Sstevel@tonic-gate ior->BasePort1.base = ior->BasePort1.base &
55230Sstevel@tonic-gate ((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55240Sstevel@tonic-gate IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55250Sstevel@tonic-gate ior->BasePort2.base = ior->BasePort2.base &
55260Sstevel@tonic-gate ((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55270Sstevel@tonic-gate IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55280Sstevel@tonic-gate }
55290Sstevel@tonic-gate
55300Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
55310Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle));
55320Sstevel@tonic-gate
55330Sstevel@tonic-gate
55340Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW
55350Sstevel@tonic-gate /*
55360Sstevel@tonic-gate * Here is where the code diverges, depending on the type of IO windows
55370Sstevel@tonic-gate * that this socket supports. If this socket supportes memory
55380Sstevel@tonic-gate * mapped IO windows, as determined by cs_init allocating an
55390Sstevel@tonic-gate * io_mmap_window_t structure on the socket structure, then we
55400Sstevel@tonic-gate * use one IO window for all the clients on this socket. We can
55410Sstevel@tonic-gate * do this safely since a memory mapped IO window implies that
55420Sstevel@tonic-gate * only this socket shares the complete IO space of the card.
55430Sstevel@tonic-gate * See the next major block of code for a description of what we do
55440Sstevel@tonic-gate * if a socket doesn't support memory mapped IO windows.
55450Sstevel@tonic-gate */
55460Sstevel@tonic-gate if (sp->io_mmap_window) {
55470Sstevel@tonic-gate cs_window_t *cw;
55480Sstevel@tonic-gate io_mmap_window_t *imw = sp->io_mmap_window;
55490Sstevel@tonic-gate uint32_t offset;
55500Sstevel@tonic-gate
55510Sstevel@tonic-gate /*
55520Sstevel@tonic-gate * If we haven't allocated an IO window yet, do it now.
55530Sstevel@tonic-gate * Try to allocate the IO window that cs_init found for us;
55540Sstevel@tonic-gate * if that fails, then call cs_find_io_win to find a window.
55550Sstevel@tonic-gate */
55560Sstevel@tonic-gate if (!imw->count) {
55570Sstevel@tonic-gate set_window_t set_window;
55580Sstevel@tonic-gate
55590Sstevel@tonic-gate if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) {
55600Sstevel@tonic-gate iowin_char_t iowin_char;
55610Sstevel@tonic-gate
55620Sstevel@tonic-gate iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW |
55630Sstevel@tonic-gate WC_8BIT |
55640Sstevel@tonic-gate WC_16BIT);
55650Sstevel@tonic-gate if ((error = cs_find_io_win(sp->socket_num, &iowin_char,
55660Sstevel@tonic-gate &imw->number, &imw->size)) != CS_SUCCESS) {
55670Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55680Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
55690Sstevel@tonic-gate } /* cs_find_io_win */
55700Sstevel@tonic-gate } /* if (!WINDOW_AVAILABLE_FOR_IO) */
55710Sstevel@tonic-gate
55720Sstevel@tonic-gate set_window.socket = socket_num;
55730Sstevel@tonic-gate set_window.window = imw->number;
55740Sstevel@tonic-gate set_window.speed = IO_WIN_SPEED;
55750Sstevel@tonic-gate set_window.base.base = 0;
55760Sstevel@tonic-gate set_window.WindowSize = imw->size;
55770Sstevel@tonic-gate set_window.state = (WS_ENABLED | WS_16BIT |
55780Sstevel@tonic-gate WS_EXACT_MAPIN | WS_IO);
55790Sstevel@tonic-gate
55800Sstevel@tonic-gate /* XXX - what to d here? XXX */
55810Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes);
55820Sstevel@tonic-gate
55830Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) {
55840Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, imw->number,
55850Sstevel@tonic-gate NULL, NULL, NULL,
55860Sstevel@tonic-gate (IO_DEALLOCATE_WINDOW |
55870Sstevel@tonic-gate IO_DISABLE_WINDOW));
55880Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55890Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
55900Sstevel@tonic-gate return (CS_BAD_WINDOW);
55910Sstevel@tonic-gate }
55920Sstevel@tonic-gate
55930Sstevel@tonic-gate imw->handle = set_window.base.handle;
55940Sstevel@tonic-gate imw->size = set_window.WindowSize;
55950Sstevel@tonic-gate
55960Sstevel@tonic-gate /*
55970Sstevel@tonic-gate * Check the caller's port requirements to be sure that they
55980Sstevel@tonic-gate * fit within our found IO window.
55990Sstevel@tonic-gate */
56000Sstevel@tonic-gate if ((ior->BasePort1.base + ior->NumPorts1 +
56010Sstevel@tonic-gate ior->BasePort2.base + ior->NumPorts2) > imw->size) {
56020Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56030Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
56040Sstevel@tonic-gate return (CS_BAD_BASE);
56050Sstevel@tonic-gate }
56060Sstevel@tonic-gate
56070Sstevel@tonic-gate if ((cw = cs_get_wp(imw->number)) == NULL) {
56080Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56090Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
56100Sstevel@tonic-gate return (CS_BAD_WINDOW)
56110Sstevel@tonic-gate }
56120Sstevel@tonic-gate cw->state |= (CW_ALLOCATED | CW_IO);
56130Sstevel@tonic-gate
56140Sstevel@tonic-gate } /* if (!imw->count) */
56150Sstevel@tonic-gate
56160Sstevel@tonic-gate imw->count++;
56170Sstevel@tonic-gate
56180Sstevel@tonic-gate /*
56190Sstevel@tonic-gate * All common access handles for this type of adapter are
56200Sstevel@tonic-gate * duped. We never give the original back to the caller.
56210Sstevel@tonic-gate */
56220Sstevel@tonic-gate /* XXX need to set endianess and data ordering flags */
56230Sstevel@tonic-gate csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0);
56240Sstevel@tonic-gate csx_GetHandleOffset(ior->BasePort1.handle, &offset);
56250Sstevel@tonic-gate csx_SetHandleOffset(ior->BasePort1.handle,
56260Sstevel@tonic-gate ior->BasePort1.base + offset);
56270Sstevel@tonic-gate
56280Sstevel@tonic-gate if (ior->NumPorts2) {
56290Sstevel@tonic-gate /* XXX need to set endianess and data ordering flags */
56300Sstevel@tonic-gate csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0);
56310Sstevel@tonic-gate csx_GetHandleOffset(ior->BasePort2.handle, &offset);
56320Sstevel@tonic-gate csx_SetHandleOffset(ior->BasePort2.handle,
56330Sstevel@tonic-gate ior->BasePort1.base + offset);
56340Sstevel@tonic-gate }
56350Sstevel@tonic-gate
56360Sstevel@tonic-gate /*
56370Sstevel@tonic-gate * We don't really use these two values if we've got a memory
56380Sstevel@tonic-gate * mapped IO window since the assigned window number is stored
56390Sstevel@tonic-gate * in imw->number.
56400Sstevel@tonic-gate */
56410Sstevel@tonic-gate client->io_alloc.Window1 = imw->number;
56420Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
56430Sstevel@tonic-gate
56440Sstevel@tonic-gate /*
56450Sstevel@tonic-gate * This socket supports only IO port IO windows.
56460Sstevel@tonic-gate */
56470Sstevel@tonic-gate } else {
56480Sstevel@tonic-gate #else /* USE_IOMMAP_WINDOW */
56490Sstevel@tonic-gate {
56500Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */
56510Sstevel@tonic-gate baseaddru_t baseaddru;
56520Sstevel@tonic-gate
56530Sstevel@tonic-gate baseaddru.base = ior->BasePort1.base;
56540Sstevel@tonic-gate
56550Sstevel@tonic-gate if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1,
56560Sstevel@tonic-gate &client->io_alloc.Window1)) != CS_SUCCESS) {
56570Sstevel@tonic-gate
56580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56590Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
56600Sstevel@tonic-gate return (error);
56610Sstevel@tonic-gate } /* if (cs_allocate_io_win(1)) */
56620Sstevel@tonic-gate
56630Sstevel@tonic-gate /*
56640Sstevel@tonic-gate * Setup the window hardware; if this fails, then we need to
56650Sstevel@tonic-gate * deallocate the previously allocated window.
56660Sstevel@tonic-gate */
56670Sstevel@tonic-gate if ((error = cs_setup_io_win(socket_num,
56680Sstevel@tonic-gate client->io_alloc.Window1,
56690Sstevel@tonic-gate &baseaddru,
56700Sstevel@tonic-gate &ior->NumPorts1,
56710Sstevel@tonic-gate ior->IOAddrLines,
56720Sstevel@tonic-gate ior->Attributes1)) !=
56730Sstevel@tonic-gate CS_SUCCESS) {
56740Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
56750Sstevel@tonic-gate NULL, NULL, NULL,
56760Sstevel@tonic-gate (
56770Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
56780Sstevel@tonic-gate IO_DISABLE_WINDOW));
56790Sstevel@tonic-gate
56800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56810Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
56820Sstevel@tonic-gate return (error);
56830Sstevel@tonic-gate } /* if (cs_setup_io_win(1)) */
56840Sstevel@tonic-gate
56850Sstevel@tonic-gate ior->BasePort1.handle = (acc_handle_t)baseaddru.handle;
56860Sstevel@tonic-gate ior->BasePort1.base = baseaddru.base;
56870Sstevel@tonic-gate
56880Sstevel@tonic-gate /*
56890Sstevel@tonic-gate * See if the client wants two IO ranges.
56900Sstevel@tonic-gate */
56910Sstevel@tonic-gate if (ior->NumPorts2) {
56920Sstevel@tonic-gate baseaddru_t baseaddru;
56930Sstevel@tonic-gate
56940Sstevel@tonic-gate baseaddru.base = ior->BasePort2.base;
56950Sstevel@tonic-gate
56960Sstevel@tonic-gate /*
56970Sstevel@tonic-gate * If we fail to allocate this window, then we must deallocate
56980Sstevel@tonic-gate * the previous IO window that is already allocated.
56990Sstevel@tonic-gate */
57000Sstevel@tonic-gate if ((error = cs_allocate_io_win(sp->socket_num,
57010Sstevel@tonic-gate ior->Attributes2,
57020Sstevel@tonic-gate &client->io_alloc.Window2)) !=
57030Sstevel@tonic-gate CS_SUCCESS) {
57040Sstevel@tonic-gate (void) cs_setup_io_win(socket_num,
57050Sstevel@tonic-gate client->io_alloc.Window2,
57060Sstevel@tonic-gate NULL, NULL, NULL,
57070Sstevel@tonic-gate (
57080Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
57090Sstevel@tonic-gate IO_DISABLE_WINDOW));
57100Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57110Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
57120Sstevel@tonic-gate return (error);
57130Sstevel@tonic-gate } /* if (cs_allocate_io_win(2)) */
57140Sstevel@tonic-gate /*
57150Sstevel@tonic-gate * Setup the window hardware; if this fails, then we need to
57160Sstevel@tonic-gate * deallocate the previously allocated window.
57170Sstevel@tonic-gate */
57180Sstevel@tonic-gate if ((error = cs_setup_io_win(socket_num,
57190Sstevel@tonic-gate client->io_alloc.Window2,
57200Sstevel@tonic-gate &baseaddru,
57210Sstevel@tonic-gate &ior->NumPorts2,
57220Sstevel@tonic-gate ior->IOAddrLines,
57230Sstevel@tonic-gate ior->Attributes2)) !=
57240Sstevel@tonic-gate CS_SUCCESS) {
57250Sstevel@tonic-gate (void) cs_setup_io_win(socket_num,
57260Sstevel@tonic-gate client->io_alloc.Window1,
57270Sstevel@tonic-gate NULL, NULL, NULL,
57280Sstevel@tonic-gate (
57290Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
57300Sstevel@tonic-gate IO_DISABLE_WINDOW));
57310Sstevel@tonic-gate (void) cs_setup_io_win(socket_num,
57320Sstevel@tonic-gate client->io_alloc.Window2,
57330Sstevel@tonic-gate NULL, NULL, NULL,
57340Sstevel@tonic-gate (
57350Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
57360Sstevel@tonic-gate IO_DISABLE_WINDOW));
57370Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57380Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
57390Sstevel@tonic-gate return (error);
57400Sstevel@tonic-gate } /* if (cs_setup_io_win(2)) */
57410Sstevel@tonic-gate
57420Sstevel@tonic-gate ior->BasePort2.handle = (acc_handle_t)baseaddru.handle;
57430Sstevel@tonic-gate ior->BasePort2.base = baseaddru.base;
57440Sstevel@tonic-gate
57450Sstevel@tonic-gate } else {
57460Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
57470Sstevel@tonic-gate } /* if (ior->NumPorts2) */
57480Sstevel@tonic-gate } /* if (sp->io_mmap_window) */
57490Sstevel@tonic-gate
57500Sstevel@tonic-gate /*
57510Sstevel@tonic-gate * Save a copy of the client's port information so that we
57520Sstevel@tonic-gate * can use it in the RequestConfiguration call. We set
57530Sstevel@tonic-gate * the IO window number(s) allocated in the respective
57540Sstevel@tonic-gate * section of code, above.
57550Sstevel@tonic-gate */
57560Sstevel@tonic-gate client->io_alloc.BasePort1.base = ior->BasePort1.base;
57570Sstevel@tonic-gate client->io_alloc.BasePort1.handle = ior->BasePort1.handle;
57580Sstevel@tonic-gate client->io_alloc.NumPorts1 = ior->NumPorts1;
57590Sstevel@tonic-gate client->io_alloc.Attributes1 = ior->Attributes1;
57600Sstevel@tonic-gate client->io_alloc.BasePort2.base = ior->BasePort2.base;
57610Sstevel@tonic-gate client->io_alloc.BasePort2.handle = ior->BasePort2.handle;
57620Sstevel@tonic-gate client->io_alloc.NumPorts2 = ior->NumPorts2;
57630Sstevel@tonic-gate client->io_alloc.Attributes2 = ior->Attributes2;
57640Sstevel@tonic-gate client->io_alloc.IOAddrLines = ior->IOAddrLines;
57650Sstevel@tonic-gate
57660Sstevel@tonic-gate /*
57670Sstevel@tonic-gate * Mark this client as having done a successful RequestIO call.
57680Sstevel@tonic-gate */
57690Sstevel@tonic-gate client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED);
57700Sstevel@tonic-gate
57710Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57720Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
57730Sstevel@tonic-gate
57740Sstevel@tonic-gate return (CS_SUCCESS);
57750Sstevel@tonic-gate }
57760Sstevel@tonic-gate
57770Sstevel@tonic-gate /*
57780Sstevel@tonic-gate * cs_release_io - releases IO resources allocated by RequestIO; this is
57790Sstevel@tonic-gate * ReleaseIO
57800Sstevel@tonic-gate *
57810Sstevel@tonic-gate * calling: cs_release_io(client_handle_t, io_req_t *)
57820Sstevel@tonic-gate *
57830Sstevel@tonic-gate * returns: CS_SUCCESS - if IO resources sucessfully deallocated
57840Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid
57850Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
57860Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
57870Sstevel@tonic-gate * done without a ReleaseConfiguration
57880Sstevel@tonic-gate * CS_IN_USE - no RequestIO has been done
57890Sstevel@tonic-gate */
57900Sstevel@tonic-gate static int
57910Sstevel@tonic-gate cs_release_io(client_handle_t client_handle, io_req_t *ior)
57920Sstevel@tonic-gate {
57930Sstevel@tonic-gate cs_socket_t *sp;
57940Sstevel@tonic-gate client_t *client;
57950Sstevel@tonic-gate int error;
57960Sstevel@tonic-gate int client_lock_acquired;
57970Sstevel@tonic-gate uint32_t socket_num;
57980Sstevel@tonic-gate
57990Sstevel@tonic-gate #ifdef lint
58000Sstevel@tonic-gate ior = NULL;
58010Sstevel@tonic-gate #endif
58020Sstevel@tonic-gate
58030Sstevel@tonic-gate /*
58040Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
58050Sstevel@tonic-gate * is, we don't support SS using this call.
58060Sstevel@tonic-gate */
58070Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
58080Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
58090Sstevel@tonic-gate
58100Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
58110Sstevel@tonic-gate
58120Sstevel@tonic-gate /*
58130Sstevel@tonic-gate * Get a pointer to this client's socket structure.
58140Sstevel@tonic-gate */
58150Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
58160Sstevel@tonic-gate return (CS_BAD_SOCKET);
58170Sstevel@tonic-gate
58180Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
58190Sstevel@tonic-gate
58200Sstevel@tonic-gate /*
58210Sstevel@tonic-gate * Make sure that this is a valid client handle.
58220Sstevel@tonic-gate */
58230Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
58240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58250Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
58260Sstevel@tonic-gate return (error);
58270Sstevel@tonic-gate }
58280Sstevel@tonic-gate
58290Sstevel@tonic-gate /*
58300Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow
58310Sstevel@tonic-gate * this call.
58320Sstevel@tonic-gate */
58330Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) {
58340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58350Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
58360Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED);
58370Sstevel@tonic-gate }
58380Sstevel@tonic-gate
58390Sstevel@tonic-gate /*
58400Sstevel@tonic-gate * If RequestIO has not been done, we don't allow this call.
58410Sstevel@tonic-gate */
58420Sstevel@tonic-gate if (!(client->flags & REQ_IO_DONE)) {
58430Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58440Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
58450Sstevel@tonic-gate return (CS_IN_USE);
58460Sstevel@tonic-gate }
58470Sstevel@tonic-gate
58480Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
58490Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle));
58500Sstevel@tonic-gate
58510Sstevel@tonic-gate #ifdef XXX
58520Sstevel@tonic-gate /*
58530Sstevel@tonic-gate * Check the passed IO allocation with the stored allocation; if
58540Sstevel@tonic-gate * they don't match, then return an error.
58550Sstevel@tonic-gate */
58560Sstevel@tonic-gate if ((client->io_alloc.BasePort1 != ior->BasePort1) ||
58570Sstevel@tonic-gate (client->io_alloc.NumPorts1 != ior->NumPorts1) ||
58580Sstevel@tonic-gate (client->io_alloc.Attributes1 != ior->Attributes1) ||
58590Sstevel@tonic-gate (client->io_alloc.BasePort2 != ior->BasePort2) ||
58600Sstevel@tonic-gate (client->io_alloc.NumPorts2 != ior->NumPorts2) ||
58610Sstevel@tonic-gate (client->io_alloc.Attributes2 != ior->Attributes2) ||
58620Sstevel@tonic-gate (client->io_alloc.IOAddrLines != ior->IOAddrLines)) {
58630Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58640Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
58650Sstevel@tonic-gate return (CS_BAD_ARGS);
58660Sstevel@tonic-gate }
58670Sstevel@tonic-gate #endif
58680Sstevel@tonic-gate
58690Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW
58700Sstevel@tonic-gate /*
58710Sstevel@tonic-gate * The code diverges here depending on if this socket supports
58720Sstevel@tonic-gate * memory mapped IO windows or not. See comments in the
58730Sstevel@tonic-gate * cs_request_io function for a description of what's
58740Sstevel@tonic-gate * going on here.
58750Sstevel@tonic-gate */
58760Sstevel@tonic-gate if (sp->io_mmap_window) {
58770Sstevel@tonic-gate io_mmap_window_t *imw = sp->io_mmap_window;
58780Sstevel@tonic-gate
58790Sstevel@tonic-gate /*
58800Sstevel@tonic-gate * We should never see this; if we do, it's an internal
58810Sstevel@tonic-gate * consistency error.
58820Sstevel@tonic-gate */
58830Sstevel@tonic-gate if (!imw->count) {
58840Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n",
58850Sstevel@tonic-gate sp->socket_num);
58860Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58870Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
58880Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
58890Sstevel@tonic-gate }
58900Sstevel@tonic-gate
58910Sstevel@tonic-gate /*
58920Sstevel@tonic-gate * All common access handles for this type of adapter are
58930Sstevel@tonic-gate * duped. We never give the original back to the caller,
58940Sstevel@tonic-gate * so it's OK to unconditionally free the handle here.
58950Sstevel@tonic-gate */
58960Sstevel@tonic-gate csx_FreeHandle(&ior->BasePort1.handle);
58970Sstevel@tonic-gate
58980Sstevel@tonic-gate /*
58990Sstevel@tonic-gate * If the IO window referance count is zero, then deallocate
59000Sstevel@tonic-gate * and disable this window.
59010Sstevel@tonic-gate */
59020Sstevel@tonic-gate if (!--(imw->count)) {
59030Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, imw->number, NULL,
59040Sstevel@tonic-gate NULL, NULL,
59050Sstevel@tonic-gate (
59060Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
59070Sstevel@tonic-gate IO_DISABLE_WINDOW));
59080Sstevel@tonic-gate } /* if (imw->count) */
59090Sstevel@tonic-gate } else {
59100Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */
59110Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
59120Sstevel@tonic-gate NULL, NULL, NULL,
59130Sstevel@tonic-gate (
59140Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
59150Sstevel@tonic-gate IO_DISABLE_WINDOW));
59160Sstevel@tonic-gate if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS)
59170Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window2,
59180Sstevel@tonic-gate NULL, NULL, NULL,
59190Sstevel@tonic-gate (
59200Sstevel@tonic-gate IO_DEALLOCATE_WINDOW |
59210Sstevel@tonic-gate IO_DISABLE_WINDOW));
59220Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW
59230Sstevel@tonic-gate } /* if (sp->io_mmap_window) */
59240Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */
59250Sstevel@tonic-gate
59260Sstevel@tonic-gate /*
59270Sstevel@tonic-gate * Mark the client as not having any IO resources allocated.
59280Sstevel@tonic-gate */
59290Sstevel@tonic-gate client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED);
59300Sstevel@tonic-gate
59310Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
59320Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
59330Sstevel@tonic-gate return (CS_SUCCESS);
59340Sstevel@tonic-gate }
59350Sstevel@tonic-gate
59360Sstevel@tonic-gate /*
59370Sstevel@tonic-gate * cs_find_io_win - finds an IO window that matches the parameters specified
59380Sstevel@tonic-gate * in the flags argument
59390Sstevel@tonic-gate *
59400Sstevel@tonic-gate * calling: sn - socket number to look for IO window on
59410Sstevel@tonic-gate * *iwc - other window characteristics to match
59420Sstevel@tonic-gate * *assigned_window - pointer to where we return the assigned
59430Sstevel@tonic-gate * window number if we found a window or
59440Sstevel@tonic-gate * undefined otherwise
59450Sstevel@tonic-gate * *size - if non-NULL, the found window size will be stored here
59460Sstevel@tonic-gate *
59470Sstevel@tonic-gate * returns: CS_SUCCESS - if IO window found
59480Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements
59490Sstevel@tonic-gate */
59500Sstevel@tonic-gate static int
59510Sstevel@tonic-gate cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window,
59520Sstevel@tonic-gate uint32_t *size)
59530Sstevel@tonic-gate {
59540Sstevel@tonic-gate inquire_window_t inquire_window, *iw;
59550Sstevel@tonic-gate unsigned wn;
59560Sstevel@tonic-gate
59570Sstevel@tonic-gate iw = &inquire_window;
59580Sstevel@tonic-gate
59590Sstevel@tonic-gate for (wn = 0; wn < cs_globals.num_windows; wn++) {
59600Sstevel@tonic-gate iowin_char_t *iowc;
59610Sstevel@tonic-gate cs_window_t *cw;
59620Sstevel@tonic-gate
59630Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) != NULL) {
59640Sstevel@tonic-gate
59650Sstevel@tonic-gate iw->window = wn;
59660Sstevel@tonic-gate SocketServices(SS_InquireWindow, iw);
59670Sstevel@tonic-gate
59680Sstevel@tonic-gate iowc = &iw->iowin_char;
59690Sstevel@tonic-gate
59700Sstevel@tonic-gate if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
59710Sstevel@tonic-gate WINDOW_AVAILABLE_FOR_IO(cw) &&
59720Sstevel@tonic-gate (iw->WndCaps & WC_IO) &&
59730Sstevel@tonic-gate ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) {
59740Sstevel@tonic-gate
59750Sstevel@tonic-gate *assigned_window = wn;
59760Sstevel@tonic-gate
59770Sstevel@tonic-gate if (size)
59780Sstevel@tonic-gate *size = iw->iowin_char.ReqGran;
59790Sstevel@tonic-gate return (CS_SUCCESS);
59800Sstevel@tonic-gate } /* if (WINDOW_FOR_SOCKET) */
59810Sstevel@tonic-gate } /* cs_get_wp */
59820Sstevel@tonic-gate } /* for (wn) */
59830Sstevel@tonic-gate
59840Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
59850Sstevel@tonic-gate }
59860Sstevel@tonic-gate
59870Sstevel@tonic-gate /*
59880Sstevel@tonic-gate * cs_allocate_io_win - finds and allocates an IO window
59890Sstevel@tonic-gate *
59900Sstevel@tonic-gate * calling: sn - socket number to look for window on
59910Sstevel@tonic-gate * Attributes - window attributes in io_req_t.Attributes format
59920Sstevel@tonic-gate * *assigned_window - pointer to return assigned window number
59930Sstevel@tonic-gate *
59940Sstevel@tonic-gate * returns: CS_SUCCESS - IO window found and allocated
59950Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
59960Sstevel@tonic-gate * window that matches the passed criteria
59970Sstevel@tonic-gate *
59980Sstevel@tonic-gate * Note: This fucntion will find and allocate an IO window. The caller is
59990Sstevel@tonic-gate * responsible for deallocating the window.
60000Sstevel@tonic-gate */
60010Sstevel@tonic-gate static int
60020Sstevel@tonic-gate cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window)
60030Sstevel@tonic-gate {
60040Sstevel@tonic-gate iowin_char_t iowin_char;
60050Sstevel@tonic-gate cs_window_t *cw;
60060Sstevel@tonic-gate
60070Sstevel@tonic-gate iowin_char.IOWndCaps =
60080Sstevel@tonic-gate ((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT);
60090Sstevel@tonic-gate
60100Sstevel@tonic-gate if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) ==
60110Sstevel@tonic-gate CS_SUCCESS) {
60120Sstevel@tonic-gate if ((cw = cs_get_wp(*assigned_window)) == NULL)
60130Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
60140Sstevel@tonic-gate
60150Sstevel@tonic-gate cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO);
60160Sstevel@tonic-gate return (CS_SUCCESS);
60170Sstevel@tonic-gate }
60180Sstevel@tonic-gate
60190Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
60200Sstevel@tonic-gate }
60210Sstevel@tonic-gate
60220Sstevel@tonic-gate /*
60230Sstevel@tonic-gate * cs_setup_io_win - setup and destroy an IO window
60240Sstevel@tonic-gate *
60250Sstevel@tonic-gate * calling: sn - socket number
60260Sstevel@tonic-gate * wn - window number
60270Sstevel@tonic-gate * XXX Base - pointer to XXX
60280Sstevel@tonic-gate * *NumPorts - pointer to number of allocated ports to return
60290Sstevel@tonic-gate * IOAddrLines - number of IO address lines decoded by this card
60300Sstevel@tonic-gate * Attributes - either io_req_t attributes, or a combination of
60310Sstevel@tonic-gate * the following flags:
60320Sstevel@tonic-gate * IO_DEALLOCATE_WINDOW - deallocate the window
60330Sstevel@tonic-gate * IO_DISABLE_WINDOW - disable the window
60340Sstevel@tonic-gate * When either of these two flags are set, *Base
60350Sstevel@tonic-gate * and NumPorts should be NULL.
60360Sstevel@tonic-gate *
60370Sstevel@tonic-gate * returns: CS_SUCCESS - if no failure
60380Sstevel@tonic-gate * CS_BAD_WINDOW - if error while trying to configure window
60390Sstevel@tonic-gate *
60400Sstevel@tonic-gate * Note: We use the IOAddrLines value to determine what base address to pass
60410Sstevel@tonic-gate * to Socket Services.
60420Sstevel@tonic-gate */
60430Sstevel@tonic-gate static int
60440Sstevel@tonic-gate cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts,
60450Sstevel@tonic-gate uint32_t IOAddrLines, uint32_t Attributes)
60460Sstevel@tonic-gate {
60470Sstevel@tonic-gate set_window_t set_window;
60480Sstevel@tonic-gate
60490Sstevel@tonic-gate if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) {
60500Sstevel@tonic-gate
60510Sstevel@tonic-gate if (Attributes & IO_DEALLOCATE_WINDOW) {
60520Sstevel@tonic-gate cs_window_t *cw;
60530Sstevel@tonic-gate
60540Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) == NULL)
60550Sstevel@tonic-gate return (CS_BAD_WINDOW);
60560Sstevel@tonic-gate cw->state &= CW_WINDOW_VALID;
60570Sstevel@tonic-gate
60580Sstevel@tonic-gate } /* IO_DEALLOCATE_WINDOW */
60590Sstevel@tonic-gate
60600Sstevel@tonic-gate if (Attributes & IO_DISABLE_WINDOW) {
60610Sstevel@tonic-gate get_window_t get_window;
60620Sstevel@tonic-gate
60630Sstevel@tonic-gate get_window.window = wn;
60640Sstevel@tonic-gate
60650Sstevel@tonic-gate SocketServices(SS_GetWindow, &get_window);
60660Sstevel@tonic-gate
60670Sstevel@tonic-gate set_window.socket = get_window.socket;
60680Sstevel@tonic-gate set_window.window = get_window.window;
60690Sstevel@tonic-gate set_window.speed = get_window.speed;
60700Sstevel@tonic-gate set_window.base = 0;
60710Sstevel@tonic-gate set_window.WindowSize = get_window.size;
60720Sstevel@tonic-gate set_window.state = get_window.state & ~WS_ENABLED;
60730Sstevel@tonic-gate
60740Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes);
60750Sstevel@tonic-gate
60760Sstevel@tonic-gate SocketServices(SS_SetWindow, &set_window);
60770Sstevel@tonic-gate } /* IO_DISABLE_WINDOW */
60780Sstevel@tonic-gate
60790Sstevel@tonic-gate return (CS_SUCCESS);
60800Sstevel@tonic-gate
60810Sstevel@tonic-gate } /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
60820Sstevel@tonic-gate
60830Sstevel@tonic-gate /*
60840Sstevel@tonic-gate * See if we can allow Socket Services to select the base address
60850Sstevel@tonic-gate * value for this card; if the client has specified a non-zero
60860Sstevel@tonic-gate * base IO address but the card doesn't decode enough IO
60870Sstevel@tonic-gate * address lines to uniquely use that address, then we have
60880Sstevel@tonic-gate * the flexibility to choose an alternative base address.
60890Sstevel@tonic-gate * XXX - Is this really correct in all cases?
60900Sstevel@tonic-gate */
60910Sstevel@tonic-gate if (!IOAddrLines)
60920Sstevel@tonic-gate Base->base = 0;
60930Sstevel@tonic-gate else
60940Sstevel@tonic-gate Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines);
60950Sstevel@tonic-gate
60960Sstevel@tonic-gate set_window.socket = sn;
60970Sstevel@tonic-gate set_window.window = wn;
60980Sstevel@tonic-gate set_window.speed = IO_WIN_SPEED;
60990Sstevel@tonic-gate set_window.base = Base->base;
61000Sstevel@tonic-gate set_window.WindowSize = *NumPorts;
61010Sstevel@tonic-gate set_window.state = (WS_ENABLED | WS_IO |
61020Sstevel@tonic-gate ((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0));
61030Sstevel@tonic-gate
61040Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes);
61050Sstevel@tonic-gate
61060Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &set_window) != SUCCESS)
61070Sstevel@tonic-gate return (CS_BAD_WINDOW);
61080Sstevel@tonic-gate
61090Sstevel@tonic-gate Base->base = set_window.base;
61100Sstevel@tonic-gate Base->handle = set_window.handle;
61110Sstevel@tonic-gate *NumPorts = set_window.WindowSize;
61120Sstevel@tonic-gate
61130Sstevel@tonic-gate return (CS_SUCCESS);
61140Sstevel@tonic-gate }
61150Sstevel@tonic-gate
61160Sstevel@tonic-gate /*
61170Sstevel@tonic-gate * ==== IRQ handling functions ====
61180Sstevel@tonic-gate */
61190Sstevel@tonic-gate
61200Sstevel@tonic-gate /*
61210Sstevel@tonic-gate * cs_request_irq - add's client's IRQ handler; supports RequestIRQ
61220Sstevel@tonic-gate *
61230Sstevel@tonic-gate * calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
61240Sstevel@tonic-gate * flag set, and all other flags clear, or
61250Sstevel@tonic-gate * CS_BAD_ATTRIBUTE will be returned
61260Sstevel@tonic-gate *
61270Sstevel@tonic-gate * returns: CS_SUCCESS - if IRQ resources available for client
61280Sstevel@tonic-gate * CS_BAD_IRQ - if IRQ can not be allocated
61290Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid
61300Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
61310Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket
61320Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
61330Sstevel@tonic-gate * flags are set
61340Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has
61350Sstevel@tonic-gate * already been done
61360Sstevel@tonic-gate * CS_IN_USE - IRQ ports already in use or function has
61370Sstevel@tonic-gate * already been called
61380Sstevel@tonic-gate *
61390Sstevel@tonic-gate * Note: We only allow level-mode interrupts.
61400Sstevel@tonic-gate */
61410Sstevel@tonic-gate static int
61420Sstevel@tonic-gate cs_request_irq(client_handle_t client_handle, irq_req_t *irqr)
61430Sstevel@tonic-gate {
61440Sstevel@tonic-gate cs_socket_t *sp;
61450Sstevel@tonic-gate client_t *client;
61460Sstevel@tonic-gate set_irq_handler_t set_irq_handler;
61470Sstevel@tonic-gate int error;
61480Sstevel@tonic-gate int client_lock_acquired;
61490Sstevel@tonic-gate
61500Sstevel@tonic-gate /*
61510Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
61520Sstevel@tonic-gate * is, we don't support SS using this call.
61530Sstevel@tonic-gate */
61540Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
61550Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
61560Sstevel@tonic-gate
61570Sstevel@tonic-gate /*
61580Sstevel@tonic-gate * Make sure that none of the unsupported or reserved flags are set.
61590Sstevel@tonic-gate */
61600Sstevel@tonic-gate if ((irqr->Attributes & (IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING |
61610Sstevel@tonic-gate IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED |
61620Sstevel@tonic-gate IRQ_FORCED_PULSE)) ||
61630Sstevel@tonic-gate !(irqr->Attributes & IRQ_TYPE_EXCLUSIVE))
61640Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
61650Sstevel@tonic-gate
61660Sstevel@tonic-gate /*
61670Sstevel@tonic-gate * Get a pointer to this client's socket structure.
61680Sstevel@tonic-gate */
61690Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
61700Sstevel@tonic-gate return (CS_BAD_SOCKET);
61710Sstevel@tonic-gate
61720Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
61730Sstevel@tonic-gate
61740Sstevel@tonic-gate /*
61750Sstevel@tonic-gate * Make sure that this is a valid client handle.
61760Sstevel@tonic-gate */
61770Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
61780Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61790Sstevel@tonic-gate return (error);
61800Sstevel@tonic-gate }
61810Sstevel@tonic-gate
61820Sstevel@tonic-gate /*
61830Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow
61840Sstevel@tonic-gate * this call.
61850Sstevel@tonic-gate */
61860Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) {
61870Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61880Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED);
61890Sstevel@tonic-gate }
61900Sstevel@tonic-gate
61910Sstevel@tonic-gate /*
61920Sstevel@tonic-gate * If RequestIRQ has already been done, we don't allow this call.
61930Sstevel@tonic-gate */
61940Sstevel@tonic-gate if (client->flags & REQ_IRQ_DONE) {
61950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61960Sstevel@tonic-gate return (CS_IN_USE);
61970Sstevel@tonic-gate }
61980Sstevel@tonic-gate
61990Sstevel@tonic-gate /*
62000Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
62010Sstevel@tonic-gate * for this client, then return an error.
62020Sstevel@tonic-gate */
62030Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
62040Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62050Sstevel@tonic-gate return (CS_NO_CARD);
62060Sstevel@tonic-gate }
62070Sstevel@tonic-gate
62080Sstevel@tonic-gate /*
62090Sstevel@tonic-gate * Set up the parameters and ask Socket Services to give us an IRQ
62100Sstevel@tonic-gate * for this client. We don't really do much, since the IRQ
62110Sstevel@tonic-gate * resources are managed by SS and the kernel. We also don't
62120Sstevel@tonic-gate * care which IRQ level we are given.
62130Sstevel@tonic-gate */
62140Sstevel@tonic-gate set_irq_handler.socket =
62150Sstevel@tonic-gate CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
62160Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle));
62170Sstevel@tonic-gate set_irq_handler.irq = IRQ_ANY;
62180Sstevel@tonic-gate
62190Sstevel@tonic-gate set_irq_handler.handler_id = client_handle;
62200Sstevel@tonic-gate set_irq_handler.handler = (f_t *)irqr->irq_handler;
62210Sstevel@tonic-gate set_irq_handler.arg1 = irqr->irq_handler_arg;
62220Sstevel@tonic-gate set_irq_handler.arg2 = NULL;
62230Sstevel@tonic-gate
62240Sstevel@tonic-gate if ((error = SocketServices(SS_SetIRQHandler,
62250Sstevel@tonic-gate &set_irq_handler)) != SUCCESS) {
62260Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62270Sstevel@tonic-gate return (CS_BAD_IRQ);
62280Sstevel@tonic-gate }
62290Sstevel@tonic-gate
62300Sstevel@tonic-gate irqr->iblk_cookie = set_irq_handler.iblk_cookie;
62310Sstevel@tonic-gate irqr->idev_cookie = set_irq_handler.idev_cookie;
62320Sstevel@tonic-gate
62330Sstevel@tonic-gate /*
62340Sstevel@tonic-gate * Save the allocated IRQ information for this client.
62350Sstevel@tonic-gate */
62360Sstevel@tonic-gate client->irq_alloc.Attributes = irqr->Attributes;
62370Sstevel@tonic-gate client->irq_alloc.irq = set_irq_handler.irq;
62380Sstevel@tonic-gate client->irq_alloc.handler_id = set_irq_handler.handler_id;
62390Sstevel@tonic-gate client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler;
62400Sstevel@tonic-gate client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1;
62410Sstevel@tonic-gate client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2;
62420Sstevel@tonic-gate
62430Sstevel@tonic-gate #ifdef CS_DEBUG
62440Sstevel@tonic-gate if (cs_debug > 0)
62450Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x "
62460Sstevel@tonic-gate "set_irq_handler.irq 0x%x\n",
62470Sstevel@tonic-gate sp->socket_num,
62480Sstevel@tonic-gate (int)irqr->Attributes,
62490Sstevel@tonic-gate set_irq_handler.irq);
62500Sstevel@tonic-gate #endif
62510Sstevel@tonic-gate
62520Sstevel@tonic-gate /*
62530Sstevel@tonic-gate * Mark this client as having done a successful RequestIRQ call.
62540Sstevel@tonic-gate */
62550Sstevel@tonic-gate client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
62560Sstevel@tonic-gate
62570Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62580Sstevel@tonic-gate return (CS_SUCCESS);
62590Sstevel@tonic-gate }
62600Sstevel@tonic-gate
62610Sstevel@tonic-gate /*
62620Sstevel@tonic-gate * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
62630Sstevel@tonic-gate * ReleaseIRQ
62640Sstevel@tonic-gate *
62650Sstevel@tonic-gate * calling: cs_release_irq(client_handle_t, irq_req_t *)
62660Sstevel@tonic-gate *
62670Sstevel@tonic-gate * returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
62680Sstevel@tonic-gate * CS_BAD_IRQ - if IRQ can not be deallocated
62690Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid
62700Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
62710Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
62720Sstevel@tonic-gate * done without a ReleaseConfiguration
62730Sstevel@tonic-gate * CS_IN_USE - no RequestIRQ has been done
62740Sstevel@tonic-gate */
62750Sstevel@tonic-gate static int
62760Sstevel@tonic-gate cs_release_irq(client_handle_t client_handle, irq_req_t *irqr)
62770Sstevel@tonic-gate {
62780Sstevel@tonic-gate cs_socket_t *sp;
62790Sstevel@tonic-gate client_t *client;
62800Sstevel@tonic-gate clear_irq_handler_t clear_irq_handler;
62810Sstevel@tonic-gate int error;
62820Sstevel@tonic-gate int client_lock_acquired;
62830Sstevel@tonic-gate
62840Sstevel@tonic-gate #ifdef lint
62850Sstevel@tonic-gate irqr = NULL;
62860Sstevel@tonic-gate #endif
62870Sstevel@tonic-gate
62880Sstevel@tonic-gate /*
62890Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
62900Sstevel@tonic-gate * is, we don't support SS using this call.
62910Sstevel@tonic-gate */
62920Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
62930Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
62940Sstevel@tonic-gate
62950Sstevel@tonic-gate /*
62960Sstevel@tonic-gate * Get a pointer to this client's socket structure.
62970Sstevel@tonic-gate */
62980Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
62990Sstevel@tonic-gate return (CS_BAD_SOCKET);
63000Sstevel@tonic-gate
63010Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
63020Sstevel@tonic-gate
63030Sstevel@tonic-gate /*
63040Sstevel@tonic-gate * Make sure that this is a valid client handle.
63050Sstevel@tonic-gate */
63060Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
63070Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63080Sstevel@tonic-gate return (error);
63090Sstevel@tonic-gate }
63100Sstevel@tonic-gate
63110Sstevel@tonic-gate /*
63120Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow
63130Sstevel@tonic-gate * this call.
63140Sstevel@tonic-gate */
63150Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) {
63160Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63170Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED);
63180Sstevel@tonic-gate }
63190Sstevel@tonic-gate
63200Sstevel@tonic-gate /*
63210Sstevel@tonic-gate * If RequestIRQ has not been done, we don't allow this call.
63220Sstevel@tonic-gate */
63230Sstevel@tonic-gate if (!(client->flags & REQ_IRQ_DONE)) {
63240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63250Sstevel@tonic-gate return (CS_IN_USE);
63260Sstevel@tonic-gate }
63270Sstevel@tonic-gate
63280Sstevel@tonic-gate /*
63290Sstevel@tonic-gate * Tell Socket Services that we want to deregister this client's
63300Sstevel@tonic-gate * IRQ handler.
63310Sstevel@tonic-gate */
63320Sstevel@tonic-gate clear_irq_handler.socket =
63330Sstevel@tonic-gate CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
63340Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle));
63350Sstevel@tonic-gate clear_irq_handler.handler_id = client->irq_alloc.handler_id;
63360Sstevel@tonic-gate clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler;
63370Sstevel@tonic-gate
63380Sstevel@tonic-gate /*
63390Sstevel@tonic-gate * At this point, we should never fail this SS call; if we do, it
63400Sstevel@tonic-gate * means that there is an internal consistancy error in either
63410Sstevel@tonic-gate * Card Services or Socket Services.
63420Sstevel@tonic-gate */
63430Sstevel@tonic-gate if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) !=
63440Sstevel@tonic-gate SUCCESS) {
63450Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63460Sstevel@tonic-gate return (CS_BAD_IRQ);
63470Sstevel@tonic-gate }
63480Sstevel@tonic-gate
63490Sstevel@tonic-gate /*
63500Sstevel@tonic-gate * Mark the client as not having any IRQ resources allocated.
63510Sstevel@tonic-gate */
63520Sstevel@tonic-gate client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
63530Sstevel@tonic-gate
63540Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63550Sstevel@tonic-gate return (CS_SUCCESS);
63560Sstevel@tonic-gate }
63570Sstevel@tonic-gate
63580Sstevel@tonic-gate /*
63590Sstevel@tonic-gate * ==== configuration handling functions ====
63600Sstevel@tonic-gate */
63610Sstevel@tonic-gate
63620Sstevel@tonic-gate /*
63630Sstevel@tonic-gate * cs_request_configuration - sets up socket and card configuration on behalf
63640Sstevel@tonic-gate * of the client; this is RequestConfiguration
63650Sstevel@tonic-gate *
63660Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully set
63670Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error
63680Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
63690Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
63700Sstevel@tonic-gate * are set
63710Sstevel@tonic-gate * CS_BAD_TYPE - if the socket doesn't support a mem and IO
63720Sstevel@tonic-gate * interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
63730Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has
63740Sstevel@tonic-gate * already been done
63750Sstevel@tonic-gate * CS_BAD_VCC - if Vcc value is not supported by socket
63760Sstevel@tonic-gate * CS_BAD_VPP1 - if Vpp1 value is not supported by socket
63770Sstevel@tonic-gate * CS_BAD_VPP2 - if Vpp2 value is not supported by socket
63780Sstevel@tonic-gate *
63790Sstevel@tonic-gate * Bug ID: 1193637 - Card Services RequestConfiguration does not conform
63800Sstevel@tonic-gate * to PCMCIA standard
63810Sstevel@tonic-gate * We allow clients to do a RequestConfiguration even if they haven't
63820Sstevel@tonic-gate * done a RequestIO or RequestIRQ.
63830Sstevel@tonic-gate */
63840Sstevel@tonic-gate static int
63850Sstevel@tonic-gate cs_request_configuration(client_handle_t client_handle, config_req_t *cr)
63860Sstevel@tonic-gate {
63870Sstevel@tonic-gate cs_socket_t *sp;
63880Sstevel@tonic-gate client_t *client;
63890Sstevel@tonic-gate volatile config_regs_t *crt;
63900Sstevel@tonic-gate set_socket_t set_socket;
63910Sstevel@tonic-gate get_socket_t get_socket;
63920Sstevel@tonic-gate acc_handle_t cis_handle;
63930Sstevel@tonic-gate int error;
63940Sstevel@tonic-gate uint32_t newoffset;
63950Sstevel@tonic-gate int client_lock_acquired;
63960Sstevel@tonic-gate
63970Sstevel@tonic-gate /*
63980Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
63990Sstevel@tonic-gate * is, we don't support SS using this call.
64000Sstevel@tonic-gate */
64010Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
64020Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
64030Sstevel@tonic-gate
64040Sstevel@tonic-gate #ifdef XXX
64050Sstevel@tonic-gate /*
64060Sstevel@tonic-gate * If the client specifies Vcc = 0 and any non-zero value for
64070Sstevel@tonic-gate * either of the Vpp members, that's an illegal condition.
64080Sstevel@tonic-gate */
64090Sstevel@tonic-gate if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2))
64100Sstevel@tonic-gate return (CS_BAD_VCC);
64110Sstevel@tonic-gate #endif
64120Sstevel@tonic-gate
64130Sstevel@tonic-gate /*
64140Sstevel@tonic-gate * Get a pointer to this client's socket structure.
64150Sstevel@tonic-gate */
64160Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
64170Sstevel@tonic-gate return (CS_BAD_SOCKET);
64180Sstevel@tonic-gate
64190Sstevel@tonic-gate /*
64200Sstevel@tonic-gate * If the client is asking for a memory and IO interface on this
64210Sstevel@tonic-gate * socket, then check the socket capabilities to be sure that
64220Sstevel@tonic-gate * this socket supports this configuration.
64230Sstevel@tonic-gate */
64240Sstevel@tonic-gate if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) {
64250Sstevel@tonic-gate inquire_socket_t inquire_socket;
64260Sstevel@tonic-gate
64270Sstevel@tonic-gate inquire_socket.socket = sp->socket_num;
64280Sstevel@tonic-gate
64290Sstevel@tonic-gate if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS)
64300Sstevel@tonic-gate return (CS_BAD_SOCKET);
64310Sstevel@tonic-gate
64320Sstevel@tonic-gate if (!(inquire_socket.SocketCaps & IF_IO))
64330Sstevel@tonic-gate return (CS_BAD_TYPE);
64340Sstevel@tonic-gate
64350Sstevel@tonic-gate } /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
64360Sstevel@tonic-gate
64370Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
64380Sstevel@tonic-gate
64390Sstevel@tonic-gate /*
64400Sstevel@tonic-gate * Make sure that this is a valid client handle.
64410Sstevel@tonic-gate */
64420Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
64430Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64440Sstevel@tonic-gate return (error);
64450Sstevel@tonic-gate }
64460Sstevel@tonic-gate
64470Sstevel@tonic-gate /*
64480Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow
64490Sstevel@tonic-gate * this call.
64500Sstevel@tonic-gate */
64510Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) {
64520Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64530Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED);
64540Sstevel@tonic-gate }
64550Sstevel@tonic-gate
64560Sstevel@tonic-gate /*
64570Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
64580Sstevel@tonic-gate * for this client, then return an error.
64590Sstevel@tonic-gate */
64600Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
64610Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64620Sstevel@tonic-gate return (CS_NO_CARD);
64630Sstevel@tonic-gate }
64640Sstevel@tonic-gate
64650Sstevel@tonic-gate /*
64660Sstevel@tonic-gate * At this point, most of the client's calling parameters have been
64670Sstevel@tonic-gate * validated, so we can go ahead and configure the socket and
64680Sstevel@tonic-gate * the card.
64690Sstevel@tonic-gate */
64700Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
64710Sstevel@tonic-gate
64720Sstevel@tonic-gate /*
64730Sstevel@tonic-gate * Configure the socket with the interface type and voltages requested
64740Sstevel@tonic-gate * by the client.
64750Sstevel@tonic-gate */
64760Sstevel@tonic-gate get_socket.socket = sp->socket_num;
64770Sstevel@tonic-gate
64780Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
64790Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
64800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64810Sstevel@tonic-gate return (CS_BAD_SOCKET);
64820Sstevel@tonic-gate }
64830Sstevel@tonic-gate
64840Sstevel@tonic-gate #ifdef CS_DEBUG
64850Sstevel@tonic-gate if (cs_debug > 0)
64860Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: socket %d "
64870Sstevel@tonic-gate "client->irq_alloc.irq 0x%x "
64880Sstevel@tonic-gate "get_socket.IRQRouting 0x%x\n",
64890Sstevel@tonic-gate sp->socket_num,
64900Sstevel@tonic-gate (int)client->irq_alloc.irq,
64910Sstevel@tonic-gate get_socket.IRQRouting);
64920Sstevel@tonic-gate #endif
64930Sstevel@tonic-gate
64940Sstevel@tonic-gate bzero(&set_socket, sizeof (set_socket));
64950Sstevel@tonic-gate set_socket.socket = sp->socket_num;
64960Sstevel@tonic-gate set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE;
64970Sstevel@tonic-gate
64980Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
64990Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */
65000Sstevel@tonic-gate
65010Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC,
65020Sstevel@tonic-gate &set_socket.VccLevel) != CS_SUCCESS) {
65030Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
65040Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65050Sstevel@tonic-gate return (CS_BAD_VCC);
65060Sstevel@tonic-gate }
65070Sstevel@tonic-gate
65080Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1,
65090Sstevel@tonic-gate &set_socket.Vpp1Level) != CS_SUCCESS) {
65100Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
65110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65120Sstevel@tonic-gate return (CS_BAD_VPP);
65130Sstevel@tonic-gate }
65140Sstevel@tonic-gate
65150Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2,
65160Sstevel@tonic-gate &set_socket.Vpp2Level) != CS_SUCCESS) {
65170Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
65180Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65190Sstevel@tonic-gate return (CS_BAD_VPP);
65200Sstevel@tonic-gate }
65210Sstevel@tonic-gate
65220Sstevel@tonic-gate if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO))
65230Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
65240Sstevel@tonic-gate else {
65250Sstevel@tonic-gate set_socket.IFType = IF_IO;
65260Sstevel@tonic-gate
65270Sstevel@tonic-gate /*
65280Sstevel@tonic-gate * The Cirrus Logic PD6710/672X/others? adapters will write
65290Sstevel@tonic-gate * protect the CIS if the socket is in MEMORY mode and the
65300Sstevel@tonic-gate * WP/IOCS16 pin is true. When this happens, the CIS registers
65310Sstevel@tonic-gate * will fail to be written. Go ahead and set the socket,
65320Sstevel@tonic-gate * even though the event mask isn't complete yet, so we can
65330Sstevel@tonic-gate * configure the adapter. Afterwards, set the socket again
65340Sstevel@tonic-gate * to make sure the event mask is correct.
65350Sstevel@tonic-gate */
65360Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
65370Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO;
65380Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
65390Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65400Sstevel@tonic-gate return (CS_BAD_SOCKET);
65410Sstevel@tonic-gate }
65420Sstevel@tonic-gate }
65430Sstevel@tonic-gate
65440Sstevel@tonic-gate if (cs_rc2_delay)
65450Sstevel@tonic-gate drv_usecwait(cs_rc2_delay * 1000);
65460Sstevel@tonic-gate
65470Sstevel@tonic-gate /*
65480Sstevel@tonic-gate * Get a pointer to a window that contains the configuration
65490Sstevel@tonic-gate * registers.
65500Sstevel@tonic-gate */
65510Sstevel@tonic-gate mutex_enter(&sp->lock);
65520Sstevel@tonic-gate client->config_regs_offset = cr->ConfigBase;
65530Sstevel@tonic-gate newoffset = client->config_regs_offset;
65540Sstevel@tonic-gate mutex_exit(&sp->lock);
65550Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
65560Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) {
65570Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
65580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65590Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init "
65600Sstevel@tonic-gate "CIS window\n", sp->socket_num);
65610Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
65620Sstevel@tonic-gate }
65630Sstevel@tonic-gate
65640Sstevel@tonic-gate /*
65650Sstevel@tonic-gate * Setup the config register pointers.
65660Sstevel@tonic-gate * Note that these pointers are not the complete virtual address;
65670Sstevel@tonic-gate * the complete address is constructed each time the registers
65680Sstevel@tonic-gate * are accessed.
65690Sstevel@tonic-gate */
65700Sstevel@tonic-gate mutex_enter(&sp->lock);
65710Sstevel@tonic-gate crt = &client->config_regs;
65720Sstevel@tonic-gate client->present = cr->Present;
65730Sstevel@tonic-gate
65740Sstevel@tonic-gate bzero((char *)crt, sizeof (config_regs_t));
65750Sstevel@tonic-gate
65760Sstevel@tonic-gate /* Configuration Option Register */
65770Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT)
65780Sstevel@tonic-gate crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET);
65790Sstevel@tonic-gate
65800Sstevel@tonic-gate /* Configuration and Status Register */
65810Sstevel@tonic-gate if (client->present & CONFIG_STATUS_REG_PRESENT)
65820Sstevel@tonic-gate crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET);
65830Sstevel@tonic-gate
65840Sstevel@tonic-gate /* Pin Replacement Register */
65850Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT)
65860Sstevel@tonic-gate crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET);
65870Sstevel@tonic-gate
65880Sstevel@tonic-gate /* Socket and Copy Register */
65890Sstevel@tonic-gate if (client->present & CONFIG_COPY_REG_PRESENT)
65900Sstevel@tonic-gate crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET);
65910Sstevel@tonic-gate
65920Sstevel@tonic-gate /* Extended Status Register */
65930Sstevel@tonic-gate if (client->present & CONFIG_EXSTAT_REG_PRESENT)
65940Sstevel@tonic-gate crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET);
65950Sstevel@tonic-gate
65960Sstevel@tonic-gate /* IO Base 0 Register */
65970Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT)
65980Sstevel@tonic-gate crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET);
65990Sstevel@tonic-gate
66000Sstevel@tonic-gate /* IO Base 1 Register */
66010Sstevel@tonic-gate if (client->present & CONFIG_IOBASE1_REG_PRESENT)
66020Sstevel@tonic-gate crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET);
66030Sstevel@tonic-gate
66040Sstevel@tonic-gate /* IO Base 2 Register */
66050Sstevel@tonic-gate if (client->present & CONFIG_IOBASE2_REG_PRESENT)
66060Sstevel@tonic-gate crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET);
66070Sstevel@tonic-gate
66080Sstevel@tonic-gate /* IO Base 3 Register */
66090Sstevel@tonic-gate if (client->present & CONFIG_IOBASE3_REG_PRESENT)
66100Sstevel@tonic-gate crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET);
66110Sstevel@tonic-gate
66120Sstevel@tonic-gate /* IO Limit Register */
66130Sstevel@tonic-gate if (client->present & CONFIG_IOLIMIT_REG_PRESENT)
66140Sstevel@tonic-gate crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET);
66150Sstevel@tonic-gate
66160Sstevel@tonic-gate /*
66170Sstevel@tonic-gate * Setup the bits in the PRR mask that are valid; this is easy, just
66180Sstevel@tonic-gate * copy the Pin value that the client gave us. Note that for
66190Sstevel@tonic-gate * this to work, the client must set both of the XXX_STATUS
66200Sstevel@tonic-gate * and the XXX_EVENT bits in the Pin member.
66210Sstevel@tonic-gate */
66220Sstevel@tonic-gate client->pin = cr->Pin;
66230Sstevel@tonic-gate
66240Sstevel@tonic-gate #ifdef CS_DEBUG
66250Sstevel@tonic-gate if (cs_debug > 128)
66260Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x "
66270Sstevel@tonic-gate "client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
66280Sstevel@tonic-gate "ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
66290Sstevel@tonic-gate client->pin, (int)client->config_regs_offset, newoffset,
66300Sstevel@tonic-gate (int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p,
66310Sstevel@tonic-gate (int)crt->scr_p);
66320Sstevel@tonic-gate #endif
66330Sstevel@tonic-gate
66340Sstevel@tonic-gate /*
66350Sstevel@tonic-gate * If the socket isn't in IO mode, WP is asserted, and we're going to
66360Sstevel@tonic-gate * write any of the config registers, issue a warning.
66370Sstevel@tonic-gate */
66380Sstevel@tonic-gate if ((client->present != 0) &&
66390Sstevel@tonic-gate (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) &&
66400Sstevel@tonic-gate (get_socket.state & SBM_WP)) {
66410Sstevel@tonic-gate cmn_err(CE_NOTE, "!cs_request_configuration: attempting to "
66420Sstevel@tonic-gate "write CIS config regs with WP set\n");
66430Sstevel@tonic-gate }
66440Sstevel@tonic-gate
66450Sstevel@tonic-gate /*
66460Sstevel@tonic-gate * Write any configuration registers that the client tells us are
66470Sstevel@tonic-gate * present to the card; save a copy of what we wrote so that we
66480Sstevel@tonic-gate * can return them if the client calls GetConfigurationInfo.
66490Sstevel@tonic-gate * The order in which we write the configuration registers is
66500Sstevel@tonic-gate * specified by the PCMCIA spec; we must write the socket/copy
66510Sstevel@tonic-gate * register first (if it exists), and then we can write the
66520Sstevel@tonic-gate * registers in any arbitrary order.
66530Sstevel@tonic-gate */
66540Sstevel@tonic-gate /* Socket and Copy Register */
66550Sstevel@tonic-gate if (client->present & CONFIG_COPY_REG_PRESENT) {
66560Sstevel@tonic-gate crt->scr = cr->Copy;
66570Sstevel@tonic-gate csx_Put8(cis_handle, crt->scr_p, crt->scr);
66580Sstevel@tonic-gate }
66590Sstevel@tonic-gate
66600Sstevel@tonic-gate /* Pin Replacement Register */
66610Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) {
66620Sstevel@tonic-gate crt->prr = cr->Pin;
66630Sstevel@tonic-gate csx_Put8(cis_handle, crt->prr_p, crt->prr);
66640Sstevel@tonic-gate }
66650Sstevel@tonic-gate
66660Sstevel@tonic-gate /* Configuration and Status Register */
66670Sstevel@tonic-gate /* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
66680Sstevel@tonic-gate if (client->present & CONFIG_STATUS_REG_PRESENT) {
66690Sstevel@tonic-gate crt->ccsr = cr->Status;
66700Sstevel@tonic-gate csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr);
66710Sstevel@tonic-gate }
66720Sstevel@tonic-gate
66730Sstevel@tonic-gate /* Extended Status Register */
66740Sstevel@tonic-gate if (client->present & CONFIG_EXSTAT_REG_PRESENT) {
66750Sstevel@tonic-gate crt->exstat = cr->ExtendedStatus;
66760Sstevel@tonic-gate csx_Put8(cis_handle, crt->exstat_p, crt->exstat);
66770Sstevel@tonic-gate }
66780Sstevel@tonic-gate
66790Sstevel@tonic-gate /*
66800Sstevel@tonic-gate * If any IO base and limit registers exist, and this client
66810Sstevel@tonic-gate * has done a RequestIO, setup the IO Base and IO Limit
66820Sstevel@tonic-gate * registers.
66830Sstevel@tonic-gate */
66840Sstevel@tonic-gate if (client->flags & REQ_IO_DONE) {
66850Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT) {
66860Sstevel@tonic-gate uint32_t base = client->io_alloc.BasePort1.base;
66870Sstevel@tonic-gate uint32_t present = (client->present &
66880Sstevel@tonic-gate CONFIG_IOBASE_REG_MASK) >>
66890Sstevel@tonic-gate CONFIG_IOBASE_REG_SHIFT;
66900Sstevel@tonic-gate uint32_t reg = crt->iobase0_p;
66910Sstevel@tonic-gate
66920Sstevel@tonic-gate do {
66930Sstevel@tonic-gate csx_Put8(cis_handle, reg, base & 0x0ff);
66940Sstevel@tonic-gate reg = reg + 2;
66950Sstevel@tonic-gate base = base >> 8;
66960Sstevel@tonic-gate present = present >> 1;
66970Sstevel@tonic-gate } while (present);
66980Sstevel@tonic-gate } /* CONFIG_IOBASE0_REG_PRESENT */
66990Sstevel@tonic-gate
67000Sstevel@tonic-gate if (client->present & CONFIG_IOLIMIT_REG_PRESENT) {
67010Sstevel@tonic-gate uint32_t np = client->io_alloc.NumPorts1 +
67020Sstevel@tonic-gate client->io_alloc.NumPorts2;
67030Sstevel@tonic-gate uint32_t limit, do_bit = 0;
67040Sstevel@tonic-gate int lm;
67050Sstevel@tonic-gate
67060Sstevel@tonic-gate limit = (IONUMPORTS_FROBNITZ(np) - 1);
67070Sstevel@tonic-gate
67080Sstevel@tonic-gate for (lm = 7; lm >= 0; lm--) {
67090Sstevel@tonic-gate if (limit & (1 << lm))
67100Sstevel@tonic-gate do_bit = 1;
67110Sstevel@tonic-gate if (do_bit)
67120Sstevel@tonic-gate limit |= (1 << lm);
67130Sstevel@tonic-gate } /* for */
67140Sstevel@tonic-gate
67150Sstevel@tonic-gate csx_Put8(cis_handle, crt->iolimit_p, limit);
67160Sstevel@tonic-gate } /* CONFIG_IOLIMIT_REG_PRESENT */
67170Sstevel@tonic-gate } /* REQ_IO_DONE */
67180Sstevel@tonic-gate
67190Sstevel@tonic-gate /*
67200Sstevel@tonic-gate * Mark the socket as being in IO mode.
67210Sstevel@tonic-gate */
67220Sstevel@tonic-gate if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)
67230Sstevel@tonic-gate sp->flags |= SOCKET_IS_IO;
67240Sstevel@tonic-gate
67250Sstevel@tonic-gate mutex_exit(&sp->lock);
67260Sstevel@tonic-gate
67270Sstevel@tonic-gate /*
67280Sstevel@tonic-gate * Enable the interrupt if needed
67290Sstevel@tonic-gate */
67300Sstevel@tonic-gate if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67310Sstevel@tonic-gate set_socket.IREQRouting |= IRQ_ENABLE;
67320Sstevel@tonic-gate
67330Sstevel@tonic-gate /*
67340Sstevel@tonic-gate * Now that we know if the PRR is present and if it is, which
67350Sstevel@tonic-gate * bits in the PRR are valid, we can construct the correct
67360Sstevel@tonic-gate * socket event mask.
67370Sstevel@tonic-gate */
67380Sstevel@tonic-gate set_socket.SCIntMask = cs_merge_event_masks(sp, client);
67390Sstevel@tonic-gate
67400Sstevel@tonic-gate /*
67410Sstevel@tonic-gate * Configuration Option Register - we handle this specially since
67420Sstevel@tonic-gate * we don't allow the client to manipulate the RESET or
67430Sstevel@tonic-gate * INTERRUPT bits (although a client can manipulate these
67440Sstevel@tonic-gate * bits via an AccessConfigurationRegister call - explain
67450Sstevel@tonic-gate * THAT logic to me).
67460Sstevel@tonic-gate * XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
67470Sstevel@tonic-gate * XXX - we always enable the function on a multi-function card
67480Sstevel@tonic-gate */
67490Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) {
67500Sstevel@tonic-gate crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ;
67510Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT)
67520Sstevel@tonic-gate crt->cor |= COR_ENABLE_BASE_LIMIT;
67530Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
67540Sstevel@tonic-gate crt->cor |= COR_ENABLE_FUNCTION;
67550Sstevel@tonic-gate crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
67560Sstevel@tonic-gate if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67570Sstevel@tonic-gate crt->cor |= COR_ENABLE_IREQ_ROUTING;
67580Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */
67590Sstevel@tonic-gate
67600Sstevel@tonic-gate #ifdef CS_DEBUG
67610Sstevel@tonic-gate if (cs_debug > 0)
67620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration "
67630Sstevel@tonic-gate "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
67640Sstevel@tonic-gate "present=x%x cis_handle=%p cor_p=x%x\n",
67650Sstevel@tonic-gate crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags,
67660Sstevel@tonic-gate client->present, cis_handle, crt->cor_p);
67670Sstevel@tonic-gate #endif
67680Sstevel@tonic-gate
67690Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor);
67700Sstevel@tonic-gate } /* CONFIG_OPTION_REG_PRESENT */
67710Sstevel@tonic-gate
67720Sstevel@tonic-gate if (cs_rc1_delay)
67730Sstevel@tonic-gate drv_usecwait(cs_rc1_delay * 1000);
67740Sstevel@tonic-gate
67750Sstevel@tonic-gate /*
67760Sstevel@tonic-gate * Set the socket to the parameters that the client requested.
67770Sstevel@tonic-gate */
67780Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
67790Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) {
67800Sstevel@tonic-gate crt->cor = 0; /* XXX is 0 the right thing here? */
67810Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor);
67820Sstevel@tonic-gate }
67830Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO;
67840Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
67850Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
67860Sstevel@tonic-gate return (CS_BAD_SOCKET);
67870Sstevel@tonic-gate }
67880Sstevel@tonic-gate
67890Sstevel@tonic-gate if (cs_rc2_delay)
67900Sstevel@tonic-gate drv_usecwait(cs_rc2_delay * 1000);
67910Sstevel@tonic-gate
67920Sstevel@tonic-gate /*
67930Sstevel@tonic-gate * Mark this client as having done a successful RequestConfiguration
67940Sstevel@tonic-gate * call.
67950Sstevel@tonic-gate */
67960Sstevel@tonic-gate client->flags |= REQ_CONFIGURATION_DONE;
67970Sstevel@tonic-gate
67980Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
67990Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68000Sstevel@tonic-gate
68010Sstevel@tonic-gate return (CS_SUCCESS);
68020Sstevel@tonic-gate }
68030Sstevel@tonic-gate
68040Sstevel@tonic-gate /*
68050Sstevel@tonic-gate * cs_release_configuration - releases configuration previously set via the
68060Sstevel@tonic-gate * RequestConfiguration call; this is ReleaseConfiguration
68070Sstevel@tonic-gate *
68080Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully released
68090Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
68100Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error
68110Sstevel@tonic-gate * CS_BAD_HANDLE - a RequestConfiguration has not been done
68120Sstevel@tonic-gate */
68130Sstevel@tonic-gate /*ARGSUSED*/
68140Sstevel@tonic-gate static int
68150Sstevel@tonic-gate cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg)
68160Sstevel@tonic-gate {
68170Sstevel@tonic-gate cs_socket_t *sp;
68180Sstevel@tonic-gate client_t *client;
68190Sstevel@tonic-gate volatile config_regs_t *crt;
68200Sstevel@tonic-gate set_socket_t set_socket;
68210Sstevel@tonic-gate get_socket_t get_socket;
68220Sstevel@tonic-gate acc_handle_t cis_handle;
68230Sstevel@tonic-gate int error;
68240Sstevel@tonic-gate uint32_t newoffset;
68250Sstevel@tonic-gate int client_lock_acquired;
68260Sstevel@tonic-gate
68270Sstevel@tonic-gate /*
68280Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
68290Sstevel@tonic-gate * is, we don't support SS using this call.
68300Sstevel@tonic-gate */
68310Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
68320Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
68330Sstevel@tonic-gate
68340Sstevel@tonic-gate /*
68350Sstevel@tonic-gate * Get a pointer to this client's socket structure.
68360Sstevel@tonic-gate */
68370Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
68380Sstevel@tonic-gate return (CS_BAD_SOCKET);
68390Sstevel@tonic-gate
68400Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
68410Sstevel@tonic-gate
68420Sstevel@tonic-gate /*
68430Sstevel@tonic-gate * Make sure that this is a valid client handle.
68440Sstevel@tonic-gate */
68450Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
68460Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68470Sstevel@tonic-gate return (error);
68480Sstevel@tonic-gate }
68490Sstevel@tonic-gate
68500Sstevel@tonic-gate /*
68510Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow
68520Sstevel@tonic-gate * this call.
68530Sstevel@tonic-gate */
68540Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) {
68550Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68560Sstevel@tonic-gate return (CS_BAD_HANDLE);
68570Sstevel@tonic-gate }
68580Sstevel@tonic-gate
68590Sstevel@tonic-gate #ifdef CS_DEBUG
68600Sstevel@tonic-gate if (cs_debug > 0)
68610Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_configuration: "
68620Sstevel@tonic-gate "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
68630Sstevel@tonic-gate sp->cis_flags, CW_MULTI_FUNCTION_CIS);
68640Sstevel@tonic-gate
68650Sstevel@tonic-gate #endif
68660Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
68670Sstevel@tonic-gate
68680Sstevel@tonic-gate /*
68690Sstevel@tonic-gate * Set the card back to a memory-only interface byte writing a zero
68700Sstevel@tonic-gate * to the COR. Note that we don't update our soft copy of the
68710Sstevel@tonic-gate * COR state since the PCMCIA spec only requires us to maintain
68720Sstevel@tonic-gate * the last value that was written to that register during a
68730Sstevel@tonic-gate * call to RequestConfiguration.
68740Sstevel@tonic-gate */
68750Sstevel@tonic-gate crt = &client->config_regs;
68760Sstevel@tonic-gate
68770Sstevel@tonic-gate newoffset = client->config_regs_offset;
68780Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
68790Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) {
68800Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
68810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init "
68830Sstevel@tonic-gate "CIS window\n", sp->socket_num);
68840Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
68850Sstevel@tonic-gate }
68860Sstevel@tonic-gate
68870Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
68880Sstevel@tonic-gate /*
68890Sstevel@tonic-gate * For the Multifunction cards do not reset the socket
68900Sstevel@tonic-gate * to a memory only interface but do clear the
68910Sstevel@tonic-gate * Configuration Option Register and mark this client
68920Sstevel@tonic-gate * as not having a configuration by clearing the
68930Sstevel@tonic-gate * REQ_CONFIGURATION_DONE flag.
68940Sstevel@tonic-gate */
68950Sstevel@tonic-gate client->flags &= ~REQ_CONFIGURATION_DONE;
68960Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, 0);
68970Sstevel@tonic-gate
68980Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
68990Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69000Sstevel@tonic-gate return (CS_SUCCESS);
69010Sstevel@tonic-gate }
69020Sstevel@tonic-gate
69030Sstevel@tonic-gate /*
69040Sstevel@tonic-gate * Set the socket back to a memory-only interface; don't change
69050Sstevel@tonic-gate * any other parameter of the socket.
69060Sstevel@tonic-gate */
69070Sstevel@tonic-gate get_socket.socket = sp->socket_num;
69080Sstevel@tonic-gate
69090Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
69100Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
69110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69120Sstevel@tonic-gate return (CS_BAD_SOCKET);
69130Sstevel@tonic-gate }
69140Sstevel@tonic-gate
69150Sstevel@tonic-gate mutex_enter(&sp->lock);
69160Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO;
69170Sstevel@tonic-gate set_socket.SCIntMask = cs_merge_event_masks(sp, client);
69180Sstevel@tonic-gate mutex_exit(&sp->lock);
69190Sstevel@tonic-gate
69200Sstevel@tonic-gate set_socket.socket = sp->socket_num;
69210Sstevel@tonic-gate set_socket.IREQRouting = 0;
69220Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
69230Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */
69240Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
69250Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
69260Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
69270Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
69280Sstevel@tonic-gate
69290Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT)
69300Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, 0);
69310Sstevel@tonic-gate
69320Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
69330Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
69340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69350Sstevel@tonic-gate return (CS_BAD_SOCKET);
69360Sstevel@tonic-gate }
69370Sstevel@tonic-gate
69380Sstevel@tonic-gate /*
69390Sstevel@tonic-gate * Mark this client as not having a configuration.
69400Sstevel@tonic-gate */
69410Sstevel@tonic-gate client->flags &= ~REQ_CONFIGURATION_DONE;
69420Sstevel@tonic-gate
69430Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
69440Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69450Sstevel@tonic-gate
69460Sstevel@tonic-gate return (CS_SUCCESS);
69470Sstevel@tonic-gate }
69480Sstevel@tonic-gate
69490Sstevel@tonic-gate /*
69500Sstevel@tonic-gate * cs_modify_configuration - modifies a configuration established by
69510Sstevel@tonic-gate * RequestConfiguration; this is ModifyConfiguration
69520Sstevel@tonic-gate *
69530Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully modified
69540Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error
69550Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
69560Sstevel@tonic-gate * CS_BAD_HANDLE - a RequestConfiguration has not been done
69570Sstevel@tonic-gate * CS_NO_CARD - if no card in socket
69580Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
69590Sstevel@tonic-gate * are set
69600Sstevel@tonic-gate * CS_BAD_VCC - if Vcc value is not supported by socket
69610Sstevel@tonic-gate * CS_BAD_VPP1 - if Vpp1 value is not supported by socket
69620Sstevel@tonic-gate * CS_BAD_VPP2 - if Vpp2 value is not supported by socket
69630Sstevel@tonic-gate */
69640Sstevel@tonic-gate static int
69650Sstevel@tonic-gate cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
69660Sstevel@tonic-gate {
69670Sstevel@tonic-gate cs_socket_t *sp;
69680Sstevel@tonic-gate client_t *client;
69690Sstevel@tonic-gate set_socket_t set_socket;
69700Sstevel@tonic-gate get_socket_t get_socket;
69710Sstevel@tonic-gate int error;
69720Sstevel@tonic-gate int client_lock_acquired;
69730Sstevel@tonic-gate
69740Sstevel@tonic-gate /*
69750Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
69760Sstevel@tonic-gate * is, we don't support SS using this call.
69770Sstevel@tonic-gate */
69780Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
69790Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
69800Sstevel@tonic-gate
69810Sstevel@tonic-gate /*
69820Sstevel@tonic-gate * Get a pointer to this client's socket structure.
69830Sstevel@tonic-gate */
69840Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
69850Sstevel@tonic-gate return (CS_BAD_SOCKET);
69860Sstevel@tonic-gate
69870Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
69880Sstevel@tonic-gate
69890Sstevel@tonic-gate /*
69900Sstevel@tonic-gate * Make sure that this is a valid client handle.
69910Sstevel@tonic-gate */
69920Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
69930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69940Sstevel@tonic-gate return (error);
69950Sstevel@tonic-gate }
69960Sstevel@tonic-gate
69970Sstevel@tonic-gate /*
69980Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow
69990Sstevel@tonic-gate * this call.
70000Sstevel@tonic-gate */
70010Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) {
70020Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70030Sstevel@tonic-gate return (CS_BAD_HANDLE);
70040Sstevel@tonic-gate }
70050Sstevel@tonic-gate
70060Sstevel@tonic-gate /*
70070Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
70080Sstevel@tonic-gate * for this client, then return an error.
70090Sstevel@tonic-gate */
70100Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
70110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70120Sstevel@tonic-gate return (CS_NO_CARD);
70130Sstevel@tonic-gate }
70140Sstevel@tonic-gate
70150Sstevel@tonic-gate /*
70160Sstevel@tonic-gate * Get the current socket parameters so that we can modify them.
70170Sstevel@tonic-gate */
70180Sstevel@tonic-gate get_socket.socket = sp->socket_num;
70190Sstevel@tonic-gate
70200Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
70210Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70220Sstevel@tonic-gate return (CS_BAD_SOCKET);
70230Sstevel@tonic-gate }
70240Sstevel@tonic-gate
70250Sstevel@tonic-gate #ifdef CS_DEBUG
70260Sstevel@tonic-gate if (cs_debug > 0)
70270Sstevel@tonic-gate cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
70280Sstevel@tonic-gate "client->irq_alloc.irq 0x%x "
70290Sstevel@tonic-gate "get_socket.IRQRouting 0x%x\n",
70300Sstevel@tonic-gate sp->socket_num, (int)client->irq_alloc.irq,
70310Sstevel@tonic-gate get_socket.IRQRouting);
70320Sstevel@tonic-gate #endif
70330Sstevel@tonic-gate
70340Sstevel@tonic-gate set_socket.socket = sp->socket_num;
70350Sstevel@tonic-gate set_socket.SCIntMask = get_socket.SCIntMask;
70360Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd;
70370Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */
70380Sstevel@tonic-gate set_socket.IFType = get_socket.IFType;
70390Sstevel@tonic-gate
70400Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting;
70410Sstevel@tonic-gate
70420Sstevel@tonic-gate /*
70430Sstevel@tonic-gate * Modify the IRQ routing if the client wants it modified.
70440Sstevel@tonic-gate */
70450Sstevel@tonic-gate if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
70460Sstevel@tonic-gate set_socket.IREQRouting &= ~IRQ_ENABLE;
70470Sstevel@tonic-gate
70480Sstevel@tonic-gate if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
70490Sstevel@tonic-gate (client->present & CONFIG_OPTION_REG_PRESENT)) {
70500Sstevel@tonic-gate config_regs_t *crt = &client->config_regs;
70510Sstevel@tonic-gate acc_handle_t cis_handle;
70520Sstevel@tonic-gate uint32_t newoffset = client->config_regs_offset;
70530Sstevel@tonic-gate
70540Sstevel@tonic-gate /*
70550Sstevel@tonic-gate * Get a pointer to a window that contains the configuration
70560Sstevel@tonic-gate * registers.
70570Sstevel@tonic-gate */
70580Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
70590Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) {
70600Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70610Sstevel@tonic-gate cmn_err(CE_CONT,
70620Sstevel@tonic-gate "cs_modify_configuration: socket %d can't init "
70630Sstevel@tonic-gate "CIS window\n", sp->socket_num);
70640Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
70650Sstevel@tonic-gate } /* cs_init_cis_window */
70660Sstevel@tonic-gate
70670Sstevel@tonic-gate crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
70680Sstevel@tonic-gate
70690Sstevel@tonic-gate if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70700Sstevel@tonic-gate crt->cor |= COR_ENABLE_IREQ_ROUTING;
70710Sstevel@tonic-gate
70720Sstevel@tonic-gate #ifdef CS_DEBUG
70730Sstevel@tonic-gate if (cs_debug > 0)
70740Sstevel@tonic-gate cmn_err(CE_CONT, "cs_modify_configuration:"
70750Sstevel@tonic-gate " cor_p=0x%x cor=0x%x\n",
70760Sstevel@tonic-gate crt->cor_p, crt->cor);
70770Sstevel@tonic-gate #endif
70780Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor);
70790Sstevel@tonic-gate
70800Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */
70810Sstevel@tonic-gate
70820Sstevel@tonic-gate if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70830Sstevel@tonic-gate set_socket.IREQRouting |= IRQ_ENABLE;
70840Sstevel@tonic-gate
70850Sstevel@tonic-gate } /* CONF_IRQ_CHANGE_VALID */
70860Sstevel@tonic-gate
70870Sstevel@tonic-gate /*
70880Sstevel@tonic-gate * Modify the voltage levels that the client specifies.
70890Sstevel@tonic-gate */
70900Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel;
70910Sstevel@tonic-gate
70920Sstevel@tonic-gate if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
70930Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
70940Sstevel@tonic-gate &set_socket.Vpp1Level) != CS_SUCCESS) {
70950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70960Sstevel@tonic-gate return (CS_BAD_VPP);
70970Sstevel@tonic-gate }
70980Sstevel@tonic-gate } else {
70990Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level;
71000Sstevel@tonic-gate }
71010Sstevel@tonic-gate
71020Sstevel@tonic-gate if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
71030Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
71040Sstevel@tonic-gate &set_socket.Vpp2Level) != CS_SUCCESS) {
71050Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71060Sstevel@tonic-gate return (CS_BAD_VPP);
71070Sstevel@tonic-gate }
71080Sstevel@tonic-gate } else {
71090Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level;
71100Sstevel@tonic-gate }
71110Sstevel@tonic-gate
71120Sstevel@tonic-gate /*
71130Sstevel@tonic-gate * Setup the modified socket configuration.
71140Sstevel@tonic-gate */
71150Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
71160Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71170Sstevel@tonic-gate return (CS_BAD_SOCKET);
71180Sstevel@tonic-gate }
71190Sstevel@tonic-gate
71200Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71210Sstevel@tonic-gate return (CS_SUCCESS);
71220Sstevel@tonic-gate }
71230Sstevel@tonic-gate
71240Sstevel@tonic-gate /*
71250Sstevel@tonic-gate * cs_access_configuration_register - provides a client access to the card's
71260Sstevel@tonic-gate * configuration registers; this is AccessConfigurationRegister
71270Sstevel@tonic-gate *
71280Sstevel@tonic-gate * returns: CS_SUCCESS - if register accessed successfully
71290Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
71300Sstevel@tonic-gate * CS_BAD_ARGS - if arguments are out of range
71310Sstevel@tonic-gate * CS_NO_CARD - if no card in socket
71320Sstevel@tonic-gate * CS_BAD_BASE - if no config registers base address
71330Sstevel@tonic-gate * CS_UNSUPPORTED_MODE - if no RequestConfiguration has
71340Sstevel@tonic-gate * been done yet
71350Sstevel@tonic-gate */
71360Sstevel@tonic-gate static int
71370Sstevel@tonic-gate cs_access_configuration_register(client_handle_t client_handle,
71380Sstevel@tonic-gate access_config_reg_t *acr)
71390Sstevel@tonic-gate {
71400Sstevel@tonic-gate cs_socket_t *sp;
71410Sstevel@tonic-gate client_t *client;
71420Sstevel@tonic-gate acc_handle_t cis_handle;
71430Sstevel@tonic-gate int error;
71440Sstevel@tonic-gate uint32_t newoffset;
71450Sstevel@tonic-gate int client_lock_acquired;
71460Sstevel@tonic-gate
71470Sstevel@tonic-gate /*
71480Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
71490Sstevel@tonic-gate * is, we don't support SS using this call.
71500Sstevel@tonic-gate */
71510Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
71520Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
71530Sstevel@tonic-gate
71540Sstevel@tonic-gate /*
71550Sstevel@tonic-gate * Make sure that the specifed offset is in range.
71560Sstevel@tonic-gate */
71570Sstevel@tonic-gate if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
71580Sstevel@tonic-gate return (CS_BAD_ARGS);
71590Sstevel@tonic-gate
71600Sstevel@tonic-gate /*
71610Sstevel@tonic-gate * Get a pointer to this client's socket structure.
71620Sstevel@tonic-gate */
71630Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
71640Sstevel@tonic-gate return (CS_BAD_SOCKET);
71650Sstevel@tonic-gate
71660Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
71670Sstevel@tonic-gate
71680Sstevel@tonic-gate /*
71690Sstevel@tonic-gate * Make sure that this is a valid client handle.
71700Sstevel@tonic-gate */
71710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
71720Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71730Sstevel@tonic-gate return (error);
71740Sstevel@tonic-gate }
71750Sstevel@tonic-gate
71760Sstevel@tonic-gate /*
71770Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
71780Sstevel@tonic-gate * for this client, then return an error.
71790Sstevel@tonic-gate */
71800Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
71810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71820Sstevel@tonic-gate return (CS_NO_CARD);
71830Sstevel@tonic-gate }
71840Sstevel@tonic-gate
71850Sstevel@tonic-gate /*
71860Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow
71870Sstevel@tonic-gate * this call.
71880Sstevel@tonic-gate */
71890Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) {
71900Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71910Sstevel@tonic-gate return (CS_UNSUPPORTED_MODE);
71920Sstevel@tonic-gate }
71930Sstevel@tonic-gate
71940Sstevel@tonic-gate mutex_enter(&sp->cis_lock);
71950Sstevel@tonic-gate
71960Sstevel@tonic-gate /*
71970Sstevel@tonic-gate * Get a pointer to the CIS window
71980Sstevel@tonic-gate */
71990Sstevel@tonic-gate newoffset = client->config_regs_offset + acr->Offset;
72000Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle,
72010Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) {
72020Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
72030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72040Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
72050Sstevel@tonic-gate sp->socket_num);
72060Sstevel@tonic-gate return (CS_GENERAL_FAILURE);
72070Sstevel@tonic-gate }
72080Sstevel@tonic-gate
72090Sstevel@tonic-gate /*
72100Sstevel@tonic-gate * Create the address for the config register that the client
72110Sstevel@tonic-gate * wants to access.
72120Sstevel@tonic-gate */
72130Sstevel@tonic-gate mutex_enter(&sp->lock);
72140Sstevel@tonic-gate
72150Sstevel@tonic-gate #ifdef CS_DEBUG
72160Sstevel@tonic-gate if (cs_debug > 1) {
72170Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
72180Sstevel@tonic-gate "Offset 0x%x newoffset 0x%x\n",
72190Sstevel@tonic-gate (int)client->config_regs_offset,
72200Sstevel@tonic-gate (int)acr->Offset, newoffset);
72210Sstevel@tonic-gate }
72220Sstevel@tonic-gate #endif
72230Sstevel@tonic-gate
72240Sstevel@tonic-gate /*
72250Sstevel@tonic-gate * Determine what the client wants us to do. The client is
72260Sstevel@tonic-gate * allowed to specify any valid offset, even if it would
72270Sstevel@tonic-gate * cause an unimplemented configuration register to be
72280Sstevel@tonic-gate * accessed.
72290Sstevel@tonic-gate */
72300Sstevel@tonic-gate error = CS_SUCCESS;
72310Sstevel@tonic-gate switch (acr->Action) {
72320Sstevel@tonic-gate case CONFIG_REG_READ:
72330Sstevel@tonic-gate acr->Value = csx_Get8(cis_handle, newoffset);
72340Sstevel@tonic-gate break;
72350Sstevel@tonic-gate case CONFIG_REG_WRITE:
72360Sstevel@tonic-gate csx_Put8(cis_handle, newoffset, acr->Value);
72370Sstevel@tonic-gate break;
72380Sstevel@tonic-gate default:
72390Sstevel@tonic-gate error = CS_BAD_ARGS;
72400Sstevel@tonic-gate break;
72410Sstevel@tonic-gate } /* switch */
72420Sstevel@tonic-gate
72430Sstevel@tonic-gate mutex_exit(&sp->lock);
72440Sstevel@tonic-gate mutex_exit(&sp->cis_lock);
72450Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72460Sstevel@tonic-gate
72470Sstevel@tonic-gate return (error);
72480Sstevel@tonic-gate }
72490Sstevel@tonic-gate
72500Sstevel@tonic-gate /*
72510Sstevel@tonic-gate * ==== RESET and general info functions ====
72520Sstevel@tonic-gate */
72530Sstevel@tonic-gate
72540Sstevel@tonic-gate /*
72550Sstevel@tonic-gate * cs_reset_function - RESET the requested function on the card; this
72560Sstevel@tonic-gate * is ResetFunction
72570Sstevel@tonic-gate *
72580Sstevel@tonic-gate * Note: We don't support this functionality yet, and the standard
72590Sstevel@tonic-gate * says it's OK to reutrn CS_IN_USE if we can't do this
72600Sstevel@tonic-gate * operation.
72610Sstevel@tonic-gate */
72620Sstevel@tonic-gate /*ARGSUSED*/
72630Sstevel@tonic-gate static int
72640Sstevel@tonic-gate cs_reset_function(client_handle_t ch, reset_function_t *rf)
72650Sstevel@tonic-gate {
72660Sstevel@tonic-gate return (CS_IN_USE);
72670Sstevel@tonic-gate }
72680Sstevel@tonic-gate
72690Sstevel@tonic-gate /*
72700Sstevel@tonic-gate * cs_get_configuration_info - return configuration info for the passed
72710Sstevel@tonic-gate * socket and function number to the caller;
72720Sstevel@tonic-gate * this is GetConfigurationInfo
72730Sstevel@tonic-gate */
72740Sstevel@tonic-gate /*ARGSUSED*/
72750Sstevel@tonic-gate static int
72760Sstevel@tonic-gate cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
72770Sstevel@tonic-gate {
72780Sstevel@tonic-gate cs_socket_t *sp;
72790Sstevel@tonic-gate uint32_t fn;
72800Sstevel@tonic-gate client_t *client;
72810Sstevel@tonic-gate int client_lock_acquired;
72820Sstevel@tonic-gate
72830Sstevel@tonic-gate /*
72840Sstevel@tonic-gate * Get a pointer to this client's socket structure.
72850Sstevel@tonic-gate */
72860Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
72870Sstevel@tonic-gate return (CS_BAD_SOCKET);
72880Sstevel@tonic-gate
72890Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
72900Sstevel@tonic-gate mutex_enter(&sp->lock);
72910Sstevel@tonic-gate
72920Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
72930Sstevel@tonic-gate
72940Sstevel@tonic-gate client = sp->client_list;
72950Sstevel@tonic-gate while (client) {
72960Sstevel@tonic-gate
72970Sstevel@tonic-gate if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
72980Sstevel@tonic-gate
72990Sstevel@tonic-gate /*
73000Sstevel@tonic-gate * If there's no card in the socket or the card in the
73010Sstevel@tonic-gate * socket is not for this client, then return
73020Sstevel@tonic-gate * an error.
73030Sstevel@tonic-gate */
73040Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
73050Sstevel@tonic-gate mutex_exit(&sp->lock);
73060Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73070Sstevel@tonic-gate return (CS_NO_CARD);
73080Sstevel@tonic-gate }
73090Sstevel@tonic-gate
73100Sstevel@tonic-gate mutex_exit(&sp->lock);
73110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73120Sstevel@tonic-gate return (CS_SUCCESS);
73130Sstevel@tonic-gate
73140Sstevel@tonic-gate } /* GET_CLIENT_FUNCTION == fn */
73150Sstevel@tonic-gate
73160Sstevel@tonic-gate client = client->next;
73170Sstevel@tonic-gate } /* while (client) */
73180Sstevel@tonic-gate
73190Sstevel@tonic-gate mutex_exit(&sp->lock);
73200Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73210Sstevel@tonic-gate
73220Sstevel@tonic-gate return (CS_BAD_SOCKET);
73230Sstevel@tonic-gate }
73240Sstevel@tonic-gate
73250Sstevel@tonic-gate /*
73260Sstevel@tonic-gate * cs_get_cardservices_info - return info about Card Services to the
73270Sstevel@tonic-gate * caller; this is GetCardServicesInfo
73280Sstevel@tonic-gate */
73290Sstevel@tonic-gate /*ARGSUSED*/
73300Sstevel@tonic-gate static int
73310Sstevel@tonic-gate cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
73320Sstevel@tonic-gate {
73330Sstevel@tonic-gate gcsi->Signature[0] = 'C';
73340Sstevel@tonic-gate gcsi->Signature[1] = 'S';
73350Sstevel@tonic-gate gcsi->NumSockets = cs_globals.num_sockets;
73360Sstevel@tonic-gate gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
73370Sstevel@tonic-gate gcsi->CSLevel = CS_VERSION;
73380Sstevel@tonic-gate gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
73390Sstevel@tonic-gate (void) strncpy(gcsi->VendorString,
73400Sstevel@tonic-gate CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
73410Sstevel@tonic-gate CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
73420Sstevel@tonic-gate
73430Sstevel@tonic-gate return (CS_SUCCESS);
73440Sstevel@tonic-gate }
73450Sstevel@tonic-gate
73460Sstevel@tonic-gate /*
73470Sstevel@tonic-gate * cs_get_physical_adapter_info - returns information about the requested
73480Sstevel@tonic-gate * physical adapter; this is
73490Sstevel@tonic-gate * GetPhysicalAdapterInfo
73500Sstevel@tonic-gate *
73510Sstevel@tonic-gate * calling: client_handle_t:
73520Sstevel@tonic-gate * NULL - use map_log_socket_t->LogSocket member
73530Sstevel@tonic-gate * to specify logical socket number
73540Sstevel@tonic-gate * !NULL - extract logical socket number from
73550Sstevel@tonic-gate * client_handle_t
73560Sstevel@tonic-gate *
73570Sstevel@tonic-gate * returns: CS_SUCCESS
73580Sstevel@tonic-gate * CS_BAD_SOCKET - if client_handle_t is NULL and invalid
73590Sstevel@tonic-gate * socket number is specified in
73600Sstevel@tonic-gate * map_log_socket_t->LogSocket
73610Sstevel@tonic-gate * CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
73620Sstevel@tonic-gate * client handle is specified
73630Sstevel@tonic-gate */
73640Sstevel@tonic-gate static int
73650Sstevel@tonic-gate cs_get_physical_adapter_info(client_handle_t ch,
73660Sstevel@tonic-gate get_physical_adapter_info_t *gpai)
73670Sstevel@tonic-gate {
73680Sstevel@tonic-gate cs_socket_t *sp;
73690Sstevel@tonic-gate int client_lock_acquired;
73700Sstevel@tonic-gate
73710Sstevel@tonic-gate if (ch == NULL)
73720Sstevel@tonic-gate gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
73730Sstevel@tonic-gate else
73740Sstevel@tonic-gate gpai->PhySocket = GET_CLIENT_SOCKET(ch);
73750Sstevel@tonic-gate
73760Sstevel@tonic-gate /*
73770Sstevel@tonic-gate * Determine if the passed socket number is valid or not.
73780Sstevel@tonic-gate */
73790Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
73800Sstevel@tonic-gate return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
73810Sstevel@tonic-gate
73820Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
73830Sstevel@tonic-gate
73840Sstevel@tonic-gate /*
73850Sstevel@tonic-gate * If we were passed a client handle, determine if it's valid or not.
73860Sstevel@tonic-gate */
73870Sstevel@tonic-gate if (ch != NULL) {
73880Sstevel@tonic-gate if (cs_find_client(ch, NULL) == NULL) {
73890Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73900Sstevel@tonic-gate return (CS_BAD_HANDLE);
73910Sstevel@tonic-gate } /* cs_find_client */
73920Sstevel@tonic-gate } /* ch != NULL */
73930Sstevel@tonic-gate
73940Sstevel@tonic-gate gpai->flags = sp->adapter.flags;
73950Sstevel@tonic-gate (void) strcpy(gpai->name, sp->adapter.name);
73960Sstevel@tonic-gate gpai->major = sp->adapter.major;
73970Sstevel@tonic-gate gpai->minor = sp->adapter.minor;
73980Sstevel@tonic-gate gpai->instance = sp->adapter.instance;
73990Sstevel@tonic-gate gpai->number = sp->adapter.number;
74000Sstevel@tonic-gate gpai->num_sockets = sp->adapter.num_sockets;
74010Sstevel@tonic-gate gpai->first_socket = sp->adapter.first_socket;
74020Sstevel@tonic-gate
74030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74040Sstevel@tonic-gate
74050Sstevel@tonic-gate return (CS_SUCCESS);
74060Sstevel@tonic-gate }
74070Sstevel@tonic-gate
74080Sstevel@tonic-gate /*
74090Sstevel@tonic-gate * ==== general functions ====
74100Sstevel@tonic-gate */
74110Sstevel@tonic-gate
74120Sstevel@tonic-gate /*
74130Sstevel@tonic-gate * cs_map_log_socket - returns the physical socket number associated with
74140Sstevel@tonic-gate * either the passed client handle or the passed
74150Sstevel@tonic-gate * logical socket number; this is MapLogSocket
74160Sstevel@tonic-gate *
74170Sstevel@tonic-gate * calling: client_handle_t:
74180Sstevel@tonic-gate * NULL - use map_log_socket_t->LogSocket member
74190Sstevel@tonic-gate * to specify logical socket number
74200Sstevel@tonic-gate * !NULL - extract logical socket number from
74210Sstevel@tonic-gate * client_handle_t
74220Sstevel@tonic-gate *
74230Sstevel@tonic-gate * returns: CS_SUCCESS
74240Sstevel@tonic-gate * CS_BAD_SOCKET - if client_handle_t is NULL and invalid
74250Sstevel@tonic-gate * socket number is specified in
74260Sstevel@tonic-gate * map_log_socket_t->LogSocket
74270Sstevel@tonic-gate * CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
74280Sstevel@tonic-gate * client handle is specified
74290Sstevel@tonic-gate *
74300Sstevel@tonic-gate * Note: We provide this function since the instance number of a client
74310Sstevel@tonic-gate * driver doesn't necessary correspond to the physical
74320Sstevel@tonic-gate * socket number
74330Sstevel@tonic-gate */
74340Sstevel@tonic-gate static int
74350Sstevel@tonic-gate cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
74360Sstevel@tonic-gate {
74370Sstevel@tonic-gate cs_socket_t *sp;
74380Sstevel@tonic-gate int client_lock_acquired;
74390Sstevel@tonic-gate
74400Sstevel@tonic-gate if (ch == NULL)
74410Sstevel@tonic-gate mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
74420Sstevel@tonic-gate else
74430Sstevel@tonic-gate mls->PhySocket = GET_CLIENT_SOCKET(ch);
74440Sstevel@tonic-gate
74450Sstevel@tonic-gate /*
74460Sstevel@tonic-gate * Determine if the passed socket number is valid or not.
74470Sstevel@tonic-gate */
74480Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
74490Sstevel@tonic-gate return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
74500Sstevel@tonic-gate
74510Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
74520Sstevel@tonic-gate
74530Sstevel@tonic-gate /*
74540Sstevel@tonic-gate * If we were passed a client handle, determine if it's valid or not.
74550Sstevel@tonic-gate */
74560Sstevel@tonic-gate if (ch != NULL) {
74570Sstevel@tonic-gate if (cs_find_client(ch, NULL) == NULL) {
74580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74590Sstevel@tonic-gate return (CS_BAD_HANDLE);
74600Sstevel@tonic-gate } /* cs_find_client */
74610Sstevel@tonic-gate } /* ch != NULL */
74620Sstevel@tonic-gate
74630Sstevel@tonic-gate mls->PhyAdapter = sp->adapter.number;
74640Sstevel@tonic-gate
74650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74660Sstevel@tonic-gate
74670Sstevel@tonic-gate return (CS_SUCCESS);
74680Sstevel@tonic-gate }
74690Sstevel@tonic-gate
74700Sstevel@tonic-gate /*
74710Sstevel@tonic-gate * cs_convert_speed - convers nS to devspeed and devspeed to nS
74720Sstevel@tonic-gate *
74730Sstevel@tonic-gate * The actual function is is in the CIS parser module; this
74740Sstevel@tonic-gate * is only a wrapper.
74750Sstevel@tonic-gate */
74760Sstevel@tonic-gate static int
74770Sstevel@tonic-gate cs_convert_speed(convert_speed_t *cs)
74780Sstevel@tonic-gate {
74790Sstevel@tonic-gate return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
74800Sstevel@tonic-gate }
74810Sstevel@tonic-gate
74820Sstevel@tonic-gate /*
74830Sstevel@tonic-gate * cs_convert_size - converts a devsize value to a size in bytes value
74840Sstevel@tonic-gate * or a size in bytes value to a devsize value
74850Sstevel@tonic-gate *
74860Sstevel@tonic-gate * The actual function is is in the CIS parser module; this
74870Sstevel@tonic-gate * is only a wrapper.
74880Sstevel@tonic-gate */
74890Sstevel@tonic-gate static int
74900Sstevel@tonic-gate cs_convert_size(convert_size_t *cs)
74910Sstevel@tonic-gate {
74920Sstevel@tonic-gate return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
74930Sstevel@tonic-gate }
74940Sstevel@tonic-gate
74950Sstevel@tonic-gate /*
74960Sstevel@tonic-gate * cs_convert_powerlevel - converts a power level in tenths of a volt
74970Sstevel@tonic-gate * to a power table entry for the specified socket
74980Sstevel@tonic-gate *
74990Sstevel@tonic-gate * returns: CS_SUCCESS - if volts converted to a valid power level
75000Sstevel@tonic-gate * CS_BAD_ADAPTER - if SS_InquireAdapter fails
75010Sstevel@tonic-gate * CS_BAD_ARGS - if volts are not supported on this socket
75020Sstevel@tonic-gate * and adapter
75030Sstevel@tonic-gate */
75040Sstevel@tonic-gate static int
75050Sstevel@tonic-gate cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
75060Sstevel@tonic-gate {
75070Sstevel@tonic-gate inquire_adapter_t inquire_adapter;
75080Sstevel@tonic-gate int i;
75090Sstevel@tonic-gate
75100Sstevel@tonic-gate #ifdef lint
75110Sstevel@tonic-gate if (sn == 0)
75120Sstevel@tonic-gate panic("lint panic");
75130Sstevel@tonic-gate #endif
75140Sstevel@tonic-gate
75150Sstevel@tonic-gate *pl = 0;
75160Sstevel@tonic-gate
75170Sstevel@tonic-gate if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
75180Sstevel@tonic-gate return (CS_BAD_ADAPTER);
75190Sstevel@tonic-gate
75200Sstevel@tonic-gate for (i = 0; (i < inquire_adapter.NumPower); i++) {
75210Sstevel@tonic-gate if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
75220Sstevel@tonic-gate (inquire_adapter.power_entry[i].PowerLevel == volts)) {
75230Sstevel@tonic-gate *pl = i;
75240Sstevel@tonic-gate return (CS_SUCCESS);
75250Sstevel@tonic-gate }
75260Sstevel@tonic-gate }
75270Sstevel@tonic-gate
75280Sstevel@tonic-gate return (CS_BAD_ARGS);
75290Sstevel@tonic-gate }
75300Sstevel@tonic-gate
75310Sstevel@tonic-gate /*
75320Sstevel@tonic-gate * cs_event2text - returns text string(s) associated with the event; this
75330Sstevel@tonic-gate * function supports the Event2Text CS call.
75340Sstevel@tonic-gate *
75350Sstevel@tonic-gate * calling: event2text_t * - pointer to event2text struct
75360Sstevel@tonic-gate * int event_source - specifies event type in event2text_t:
75370Sstevel@tonic-gate * 0 - SS event
75380Sstevel@tonic-gate * 1 - CS event
75390Sstevel@tonic-gate *
75400Sstevel@tonic-gate * returns: CS_SUCCESS
75410Sstevel@tonic-gate */
75420Sstevel@tonic-gate static int
75430Sstevel@tonic-gate cs_event2text(event2text_t *e2t, int event_source)
75440Sstevel@tonic-gate {
75450Sstevel@tonic-gate event_t event;
75460Sstevel@tonic-gate char *sepchar = "|";
75470Sstevel@tonic-gate
75480Sstevel@tonic-gate /*
75490Sstevel@tonic-gate * If event_source is 0, this is a SS event
75500Sstevel@tonic-gate */
75510Sstevel@tonic-gate if (!event_source) {
75520Sstevel@tonic-gate for (event = 0; event < MAX_SS_EVENTS; event++) {
75530Sstevel@tonic-gate if (cs_ss_event_text[event].ss_event == e2t->event) {
75540Sstevel@tonic-gate (void) strcpy(e2t->text, cs_ss_event_text[event].text);
75550Sstevel@tonic-gate return (CS_SUCCESS);
75560Sstevel@tonic-gate }
75570Sstevel@tonic-gate }
75580Sstevel@tonic-gate (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
75590Sstevel@tonic-gate return (CS_SUCCESS);
75600Sstevel@tonic-gate } else {
75610Sstevel@tonic-gate /*
75620Sstevel@tonic-gate * This is a CS event
75630Sstevel@tonic-gate */
75640Sstevel@tonic-gate e2t->text[0] = '\0';
75650Sstevel@tonic-gate for (event = 0; event < MAX_CS_EVENTS; event++) {
75660Sstevel@tonic-gate if (cs_ss_event_text[event].cs_event & e2t->event) {
75670Sstevel@tonic-gate (void) strcat(e2t->text, cs_ss_event_text[event].text);
75680Sstevel@tonic-gate (void) strcat(e2t->text, sepchar);
75690Sstevel@tonic-gate } /* if (cs_ss_event_text) */
75700Sstevel@tonic-gate } /* for (event) */
75710Sstevel@tonic-gate if (e2t->text[0])
75720Sstevel@tonic-gate e2t->text[strlen(e2t->text)-1] = NULL;
75730Sstevel@tonic-gate } /* if (!event_source) */
75740Sstevel@tonic-gate
75750Sstevel@tonic-gate return (CS_SUCCESS);
75760Sstevel@tonic-gate }
75770Sstevel@tonic-gate
75780Sstevel@tonic-gate /*
75790Sstevel@tonic-gate * cs_error2text - returns a pointer to a text string containing the name
75800Sstevel@tonic-gate * of the passed Card Services function or return code
75810Sstevel@tonic-gate *
75820Sstevel@tonic-gate * This function supports the Error2Text CS call.
75830Sstevel@tonic-gate */
75840Sstevel@tonic-gate static char *
75850Sstevel@tonic-gate cs_error2text(int function, int type)
75860Sstevel@tonic-gate {
75870Sstevel@tonic-gate cs_csfunc2text_strings_t *cfs;
75880Sstevel@tonic-gate int end_marker;
75890Sstevel@tonic-gate
75900Sstevel@tonic-gate if (type == CSFUN2TEXT_FUNCTION) {
75910Sstevel@tonic-gate cfs = cs_csfunc2text_funcstrings;
75920Sstevel@tonic-gate end_marker = CSFuncListEnd;
75930Sstevel@tonic-gate } else {
75940Sstevel@tonic-gate cfs = cs_csfunc2text_returnstrings;
75950Sstevel@tonic-gate end_marker = CS_ERRORLIST_END;
75960Sstevel@tonic-gate }
75970Sstevel@tonic-gate
75980Sstevel@tonic-gate while (cfs->item != end_marker) {
75990Sstevel@tonic-gate if (cfs->item == function)
76000Sstevel@tonic-gate return (cfs->text);
76010Sstevel@tonic-gate cfs++;
76020Sstevel@tonic-gate }
76030Sstevel@tonic-gate
76040Sstevel@tonic-gate return (cfs->text);
76050Sstevel@tonic-gate }
76060Sstevel@tonic-gate
76070Sstevel@tonic-gate /*
76080Sstevel@tonic-gate * cs_make_device_node - creates/removes device nodes on a client's behalf;
76090Sstevel@tonic-gate * this is MakeDeviceNode and RemoveDeviceNode
76100Sstevel@tonic-gate *
76110Sstevel@tonic-gate * returns: CS_SUCCESS - if all device nodes successfully created/removed
76120Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
76130Sstevel@tonic-gate * is REMOVAL_ALL_DEVICES
76140Sstevel@tonic-gate * CS_BAD_ARGS - if an invalid Action code is specified
76150Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
76160Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if can't create/remove device node
76170Sstevel@tonic-gate */
76180Sstevel@tonic-gate static int
76190Sstevel@tonic-gate cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
76200Sstevel@tonic-gate {
76210Sstevel@tonic-gate cs_socket_t *sp;
76220Sstevel@tonic-gate client_t *client;
76230Sstevel@tonic-gate ss_make_device_node_t ss_make_device_node;
76240Sstevel@tonic-gate int error, i;
76250Sstevel@tonic-gate int client_lock_acquired;
76260Sstevel@tonic-gate
76270Sstevel@tonic-gate /*
76280Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it
76290Sstevel@tonic-gate * is, we don't support SS using this call.
76300Sstevel@tonic-gate */
76310Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle))
76320Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION);
76330Sstevel@tonic-gate
76340Sstevel@tonic-gate /*
76350Sstevel@tonic-gate * Get a pointer to this client's socket structure.
76360Sstevel@tonic-gate */
76370Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
76380Sstevel@tonic-gate return (CS_BAD_SOCKET);
76390Sstevel@tonic-gate
76400Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
76410Sstevel@tonic-gate
76420Sstevel@tonic-gate /*
76430Sstevel@tonic-gate * Make sure that this is a valid client handle.
76440Sstevel@tonic-gate */
76450Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) {
76460Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76470Sstevel@tonic-gate return (error);
76480Sstevel@tonic-gate }
76490Sstevel@tonic-gate
76500Sstevel@tonic-gate #ifdef XXX
76510Sstevel@tonic-gate /*
76520Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not
76530Sstevel@tonic-gate * for this client, then return an error.
76540Sstevel@tonic-gate */
76550Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) {
76560Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76570Sstevel@tonic-gate return (CS_NO_CARD);
76580Sstevel@tonic-gate }
76590Sstevel@tonic-gate #endif
76600Sstevel@tonic-gate
76610Sstevel@tonic-gate /*
76620Sstevel@tonic-gate * Setup the client's dip, since we use it later on.
76630Sstevel@tonic-gate */
76640Sstevel@tonic-gate ss_make_device_node.dip = client->dip;
76650Sstevel@tonic-gate
76660Sstevel@tonic-gate /*
76670Sstevel@tonic-gate * Make sure that we're being given a valid Action. Set the default
76680Sstevel@tonic-gate * error code as well.
76690Sstevel@tonic-gate */
76700Sstevel@tonic-gate error = CS_BAD_ARGS; /* for default case */
76710Sstevel@tonic-gate switch (mdn->Action) {
76720Sstevel@tonic-gate case CREATE_DEVICE_NODE:
76730Sstevel@tonic-gate case REMOVE_DEVICE_NODE:
76740Sstevel@tonic-gate break;
76750Sstevel@tonic-gate case REMOVAL_ALL_DEVICE_NODES:
76760Sstevel@tonic-gate if (mdn->NumDevNodes) {
76770Sstevel@tonic-gate error = CS_BAD_ATTRIBUTE;
76780Sstevel@tonic-gate } else {
76790Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
76800Sstevel@tonic-gate ss_make_device_node.name = NULL;
76810Sstevel@tonic-gate SocketServices(CSInitDev, &ss_make_device_node);
76820Sstevel@tonic-gate error = CS_SUCCESS;
76830Sstevel@tonic-gate }
76840Sstevel@tonic-gate /* fall-through case */
76850Sstevel@tonic-gate default:
76860Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76870Sstevel@tonic-gate return (error);
76880Sstevel@tonic-gate /* NOTREACHED */
76890Sstevel@tonic-gate } /* switch */
76900Sstevel@tonic-gate
76910Sstevel@tonic-gate /*
76920Sstevel@tonic-gate * Loop through the device node descriptions and create or destroy
76930Sstevel@tonic-gate * the device node.
76940Sstevel@tonic-gate */
76950Sstevel@tonic-gate for (i = 0; i < mdn->NumDevNodes; i++) {
76960Sstevel@tonic-gate devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
76970Sstevel@tonic-gate
76980Sstevel@tonic-gate ss_make_device_node.name = devnode_desc->name;
76990Sstevel@tonic-gate ss_make_device_node.spec_type = devnode_desc->spec_type;
77000Sstevel@tonic-gate ss_make_device_node.minor_num = devnode_desc->minor_num;
77010Sstevel@tonic-gate ss_make_device_node.node_type = devnode_desc->node_type;
77020Sstevel@tonic-gate
77030Sstevel@tonic-gate /*
77040Sstevel@tonic-gate * Set the appropriate flag for the action that we want
77050Sstevel@tonic-gate * SS to perform. Note that if we ever OR-in the flag
77060Sstevel@tonic-gate * here, we need to be sure to clear the flags member
77070Sstevel@tonic-gate * since we sometimes OR-in other flags below.
77080Sstevel@tonic-gate */
77090Sstevel@tonic-gate if (mdn->Action == CREATE_DEVICE_NODE) {
77100Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
77110Sstevel@tonic-gate } else {
77120Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
77130Sstevel@tonic-gate }
77140Sstevel@tonic-gate
77150Sstevel@tonic-gate /*
77160Sstevel@tonic-gate * If this is not the last device to process, then we need
77170Sstevel@tonic-gate * to tell SS that more device process requests are on
77180Sstevel@tonic-gate * their way after this one.
77190Sstevel@tonic-gate */
77200Sstevel@tonic-gate if (i < (mdn->NumDevNodes - 1))
77210Sstevel@tonic-gate ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
77220Sstevel@tonic-gate
77230Sstevel@tonic-gate if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
77240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77250Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE);
77260Sstevel@tonic-gate } /* CSInitDev */
77270Sstevel@tonic-gate } /* for (mdn->NumDevNodes) */
77280Sstevel@tonic-gate
77290Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77300Sstevel@tonic-gate return (CS_SUCCESS);
77310Sstevel@tonic-gate }
77320Sstevel@tonic-gate
77330Sstevel@tonic-gate /*
77340Sstevel@tonic-gate * cs_remove_device_node - removes device nodes
77350Sstevel@tonic-gate *
77360Sstevel@tonic-gate * (see cs_make_device_node for a description of the calling
77370Sstevel@tonic-gate * and return parameters)
77380Sstevel@tonic-gate */
77390Sstevel@tonic-gate static int
77400Sstevel@tonic-gate cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
77410Sstevel@tonic-gate {
77420Sstevel@tonic-gate
77430Sstevel@tonic-gate /*
77440Sstevel@tonic-gate * XXX - Note the assumption here that the make_device_node_t and
77450Sstevel@tonic-gate * remove_device_node_t structures are identical.
77460Sstevel@tonic-gate */
77470Sstevel@tonic-gate return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
77480Sstevel@tonic-gate }
77490Sstevel@tonic-gate
77500Sstevel@tonic-gate /*
77510Sstevel@tonic-gate * cs_ddi_info - this function is used by clients that need to support
77520Sstevel@tonic-gate * the xxx_getinfo function; this is CS_DDI_Info
77530Sstevel@tonic-gate */
77540Sstevel@tonic-gate static int
77550Sstevel@tonic-gate cs_ddi_info(cs_ddi_info_t *cdi)
77560Sstevel@tonic-gate {
77570Sstevel@tonic-gate cs_socket_t *sp;
77580Sstevel@tonic-gate client_t *client;
77590Sstevel@tonic-gate int client_lock_acquired;
77600Sstevel@tonic-gate
77610Sstevel@tonic-gate if (cdi->driver_name == NULL)
77620Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
77630Sstevel@tonic-gate
77640Sstevel@tonic-gate #ifdef CS_DEBUG
77650Sstevel@tonic-gate if (cs_debug > 0) {
77660Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
77670Sstevel@tonic-gate (int)cdi->Socket, cdi->driver_name);
77680Sstevel@tonic-gate }
77690Sstevel@tonic-gate #endif
77700Sstevel@tonic-gate
77710Sstevel@tonic-gate /*
77720Sstevel@tonic-gate * Check to see if the socket number is in range - the system
77730Sstevel@tonic-gate * framework may cause a client driver to call us with
77740Sstevel@tonic-gate * a socket number that used to be present but isn't
77750Sstevel@tonic-gate * anymore. This is not a bug, and it's OK to return
77760Sstevel@tonic-gate * an error if the socket number is out of range.
77770Sstevel@tonic-gate */
77780Sstevel@tonic-gate if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
77790Sstevel@tonic-gate
77800Sstevel@tonic-gate #ifdef CS_DEBUG
77810Sstevel@tonic-gate if (cs_debug > 0) {
77820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
77830Sstevel@tonic-gate "SOCKET IS OUT OF RANGE\n",
77840Sstevel@tonic-gate (int)cdi->Socket,
77850Sstevel@tonic-gate cdi->driver_name);
77860Sstevel@tonic-gate }
77870Sstevel@tonic-gate #endif
77880Sstevel@tonic-gate
77890Sstevel@tonic-gate return (CS_BAD_SOCKET);
77900Sstevel@tonic-gate } /* if (!CHECK_SOCKET_NUM) */
77910Sstevel@tonic-gate
77920Sstevel@tonic-gate /*
77930Sstevel@tonic-gate * Get a pointer to this client's socket structure.
77940Sstevel@tonic-gate */
77950Sstevel@tonic-gate if ((sp = cs_get_sp(cdi->Socket)) == NULL)
77960Sstevel@tonic-gate return (CS_BAD_SOCKET);
77970Sstevel@tonic-gate
77980Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
77990Sstevel@tonic-gate
78000Sstevel@tonic-gate client = sp->client_list;
78010Sstevel@tonic-gate while (client) {
78020Sstevel@tonic-gate
78030Sstevel@tonic-gate #ifdef CS_DEBUG
78040Sstevel@tonic-gate if (cs_debug > 0) {
78050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
78060Sstevel@tonic-gate "handle 0x%x\n",
78070Sstevel@tonic-gate (int)cdi->Socket,
78080Sstevel@tonic-gate client->driver_name,
78090Sstevel@tonic-gate (int)client->client_handle);
78100Sstevel@tonic-gate }
78110Sstevel@tonic-gate #endif
78120Sstevel@tonic-gate
78130Sstevel@tonic-gate if (client->driver_name != NULL) {
78140Sstevel@tonic-gate if (!(strcmp(client->driver_name, cdi->driver_name))) {
78150Sstevel@tonic-gate cdi->dip = client->dip;
78160Sstevel@tonic-gate cdi->instance = client->instance;
78170Sstevel@tonic-gate
78180Sstevel@tonic-gate #ifdef CS_DEBUG
78190Sstevel@tonic-gate if (cs_debug > 0) {
78200Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
78210Sstevel@tonic-gate "instance %d handle 0x%x\n",
78220Sstevel@tonic-gate client->driver_name, client->instance,
78230Sstevel@tonic-gate (int)client->client_handle);
78240Sstevel@tonic-gate }
78250Sstevel@tonic-gate #endif
78260Sstevel@tonic-gate
78270Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78280Sstevel@tonic-gate return (CS_SUCCESS);
78290Sstevel@tonic-gate } /* strcmp */
78300Sstevel@tonic-gate } /* driver_name != NULL */
78310Sstevel@tonic-gate client = client->next;
78320Sstevel@tonic-gate } /* while (client) */
78330Sstevel@tonic-gate
78340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78350Sstevel@tonic-gate return (CS_BAD_SOCKET);
78360Sstevel@tonic-gate }
78370Sstevel@tonic-gate
78380Sstevel@tonic-gate /*
78390Sstevel@tonic-gate * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
78400Sstevel@tonic-gate */
78410Sstevel@tonic-gate static int
78420Sstevel@tonic-gate cs_sys_ctl(cs_sys_ctl_t *csc)
78430Sstevel@tonic-gate {
78440Sstevel@tonic-gate cs_socket_t *sp;
78450Sstevel@tonic-gate client_t *cp;
78460Sstevel@tonic-gate int sn, ret = CS_UNSUPPORTED_MODE;
78470Sstevel@tonic-gate
78480Sstevel@tonic-gate switch (csc->Action) {
78490Sstevel@tonic-gate case CS_SYS_CTL_SEND_EVENT:
78500Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78510Sstevel@tonic-gate sn = CS_GET_SOCKET_NUMBER(csc->Socket);
78520Sstevel@tonic-gate else
78530Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(csc->client_handle);
78540Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
78550Sstevel@tonic-gate return (CS_BAD_SOCKET);
78560Sstevel@tonic-gate mutex_enter(&sp->client_lock);
78570Sstevel@tonic-gate mutex_enter(&sp->lock);
78580Sstevel@tonic-gate csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
78590Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78600Sstevel@tonic-gate sp->events |= csc->Events;
78610Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
78620Sstevel@tonic-gate if ((cp = cs_find_client(csc->client_handle, &ret)) ==
78630Sstevel@tonic-gate NULL) {
78640Sstevel@tonic-gate mutex_exit(&sp->lock);
78650Sstevel@tonic-gate mutex_exit(&sp->client_lock);
78660Sstevel@tonic-gate return (ret);
78670Sstevel@tonic-gate } /* cs_find_client */
78680Sstevel@tonic-gate /*
78690Sstevel@tonic-gate * Setup the events that we want to send to the client.
78700Sstevel@tonic-gate */
78710Sstevel@tonic-gate cp->events |= (csc->Events &
78720Sstevel@tonic-gate (cp->event_mask | cp->global_mask));
78730Sstevel@tonic-gate } /* CS_SYS_CTL_EVENT_CLIENT */
78740Sstevel@tonic-gate
78750Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
78760Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_SYNC;
78770Sstevel@tonic-gate mutex_exit(&sp->lock);
78780Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
78790Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock);
78800Sstevel@tonic-gate } else {
78810Sstevel@tonic-gate mutex_exit(&sp->lock);
78820Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
78830Sstevel@tonic-gate } /* CS_SYS_CTL_WAIT_SYNC */
78840Sstevel@tonic-gate mutex_exit(&sp->client_lock);
78850Sstevel@tonic-gate ret = CS_SUCCESS;
78860Sstevel@tonic-gate break;
78870Sstevel@tonic-gate default:
78880Sstevel@tonic-gate break;
78890Sstevel@tonic-gate } /* switch */
78900Sstevel@tonic-gate
78910Sstevel@tonic-gate return (ret);
78920Sstevel@tonic-gate }
78930Sstevel@tonic-gate
78940Sstevel@tonic-gate /*
78950Sstevel@tonic-gate * cs_get_sp - returns pointer to per-socket structure for passed
78960Sstevel@tonic-gate * socket number
78970Sstevel@tonic-gate *
78980Sstevel@tonic-gate * return: (cs_socket_t *) - pointer to socket structure
78990Sstevel@tonic-gate * NULL - invalid socket number passed in
79000Sstevel@tonic-gate */
79010Sstevel@tonic-gate static cs_socket_t *
79020Sstevel@tonic-gate cs_get_sp(uint32_t sn)
79030Sstevel@tonic-gate {
79040Sstevel@tonic-gate cs_socket_t *sp = cs_globals.sp;
79050Sstevel@tonic-gate
79060Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79070Sstevel@tonic-gate return (NULL);
79080Sstevel@tonic-gate
79090Sstevel@tonic-gate if ((sp = cs_find_sp(sn)) == NULL)
79100Sstevel@tonic-gate return (NULL);
79110Sstevel@tonic-gate
79120Sstevel@tonic-gate if (sp->flags & SOCKET_IS_VALID)
79130Sstevel@tonic-gate return (sp);
79140Sstevel@tonic-gate
79150Sstevel@tonic-gate return (NULL);
79160Sstevel@tonic-gate }
79170Sstevel@tonic-gate
79180Sstevel@tonic-gate /*
79190Sstevel@tonic-gate * cs_find_sp - searches socket list and returns pointer to passed socket
79200Sstevel@tonic-gate * number
79210Sstevel@tonic-gate *
79220Sstevel@tonic-gate * return: (cs_socket_t *) - pointer to socket structure if found
79230Sstevel@tonic-gate * NULL - socket not found
79240Sstevel@tonic-gate */
79250Sstevel@tonic-gate static cs_socket_t *
79260Sstevel@tonic-gate cs_find_sp(uint32_t sn)
79270Sstevel@tonic-gate {
79280Sstevel@tonic-gate cs_socket_t *sp = cs_globals.sp;
79290Sstevel@tonic-gate
79300Sstevel@tonic-gate while (sp) {
79310Sstevel@tonic-gate if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
79320Sstevel@tonic-gate return (sp);
79330Sstevel@tonic-gate sp = sp->next;
79340Sstevel@tonic-gate } /* while */
79350Sstevel@tonic-gate
79360Sstevel@tonic-gate return (NULL);
79370Sstevel@tonic-gate }
79380Sstevel@tonic-gate
79390Sstevel@tonic-gate /*
79400Sstevel@tonic-gate * cs_add_socket - add a socket
79410Sstevel@tonic-gate *
79420Sstevel@tonic-gate * call: sn - socket number to add
79430Sstevel@tonic-gate *
79440Sstevel@tonic-gate * return: CS_SUCCESS - operation sucessful
79450Sstevel@tonic-gate * CS_BAD_SOCKET - unable to add socket
79460Sstevel@tonic-gate * CS_BAD_WINDOW - unable to get CIS window for socket
79470Sstevel@tonic-gate *
79480Sstevel@tonic-gate * We get called here once for each socket that the framework wants to
79490Sstevel@tonic-gate * add. When we are called, the framework guarentees that until we
79500Sstevel@tonic-gate * complete this routine, no other adapter instances will be allowed
79510Sstevel@tonic-gate * to attach and thus no other PCE_ADD_SOCKET events will occur.
79520Sstevel@tonic-gate * It is safe to call SS_InquireAdapter to get the number of
79530Sstevel@tonic-gate * windows that the framework currently knows about.
79540Sstevel@tonic-gate */
79550Sstevel@tonic-gate static uint32_t
79560Sstevel@tonic-gate cs_add_socket(uint32_t sn)
79570Sstevel@tonic-gate {
79580Sstevel@tonic-gate cs_socket_t *sp;
79590Sstevel@tonic-gate sservice_t sservice;
79600Sstevel@tonic-gate get_cookies_and_dip_t *gcad;
79610Sstevel@tonic-gate win_req_t win_req;
79620Sstevel@tonic-gate convert_speed_t convert_speed;
79630Sstevel@tonic-gate set_socket_t set_socket;
79640Sstevel@tonic-gate cs_window_t *cw;
79650Sstevel@tonic-gate inquire_adapter_t inquire_adapter;
79660Sstevel@tonic-gate inquire_window_t inquire_window;
79670Sstevel@tonic-gate int ret, added_windows;
79680Sstevel@tonic-gate
79690Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79700Sstevel@tonic-gate return (CS_BAD_SOCKET);
79710Sstevel@tonic-gate
79720Sstevel@tonic-gate /*
79730Sstevel@tonic-gate * See if this socket has already been added - if it has, we
79740Sstevel@tonic-gate * fail this. If we can't find the socket, then allocate
79750Sstevel@tonic-gate * a new socket structure. If we do find the socket, then
79760Sstevel@tonic-gate * check to see if it's already added; if it is, then
79770Sstevel@tonic-gate * this is an error and return CS_BAD_SOCKET; if not,
79780Sstevel@tonic-gate * then traverse the socket structure list and add this
79790Sstevel@tonic-gate * next socket strcture to the end of the list.
79800Sstevel@tonic-gate * XXX What about locking this list while we update it? Is
79810Sstevel@tonic-gate * that necessary since we're using the SOCKET_IS_VALID
79820Sstevel@tonic-gate * flag and since we never delete a socket from the
79830Sstevel@tonic-gate * list once it's been added?
79840Sstevel@tonic-gate */
79850Sstevel@tonic-gate if ((sp = cs_find_sp(sn)) == NULL) {
79860Sstevel@tonic-gate cs_socket_t *spp = cs_globals.sp;
79870Sstevel@tonic-gate
79880Sstevel@tonic-gate sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
79890Sstevel@tonic-gate
79900Sstevel@tonic-gate if (cs_globals.sp == NULL)
79910Sstevel@tonic-gate cs_globals.sp = sp;
79920Sstevel@tonic-gate else
79930Sstevel@tonic-gate while (spp) {
79940Sstevel@tonic-gate if (spp->next == NULL) {
79950Sstevel@tonic-gate spp->next = sp;
79960Sstevel@tonic-gate break;
79970Sstevel@tonic-gate } /* if */
79980Sstevel@tonic-gate spp = spp->next;
79990Sstevel@tonic-gate } /* while */
80000Sstevel@tonic-gate
80010Sstevel@tonic-gate } else {
80020Sstevel@tonic-gate if (sp->flags & SOCKET_IS_VALID)
80030Sstevel@tonic-gate return (CS_BAD_SOCKET);
80040Sstevel@tonic-gate } /* cs_find_sp */
80050Sstevel@tonic-gate
80060Sstevel@tonic-gate /*
80070Sstevel@tonic-gate * Setup the socket number
80080Sstevel@tonic-gate */
80090Sstevel@tonic-gate sp->socket_num = sn;
80100Sstevel@tonic-gate
80110Sstevel@tonic-gate /*
80120Sstevel@tonic-gate * Find out how many windows the framework knows about
80130Sstevel@tonic-gate * so far. If this number of windows is greater
80140Sstevel@tonic-gate * than our current window count, bump up our
80150Sstevel@tonic-gate * current window count.
80160Sstevel@tonic-gate * XXX Note that there is a BIG assumption here and that
80170Sstevel@tonic-gate * is that once the framework tells us that it has
80180Sstevel@tonic-gate * a window (as reflected in the NumWindows
80190Sstevel@tonic-gate * value) it can NEVER remove that window.
80200Sstevel@tonic-gate * When we really get the drop socket and drop
80210Sstevel@tonic-gate * window mechanism working correctly, we'll have
80220Sstevel@tonic-gate * to revisit this.
80230Sstevel@tonic-gate */
80240Sstevel@tonic-gate SocketServices(SS_InquireAdapter, &inquire_adapter);
80250Sstevel@tonic-gate
80260Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock);
80270Sstevel@tonic-gate added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
80280Sstevel@tonic-gate if (added_windows > 0) {
80290Sstevel@tonic-gate if (cs_add_windows(added_windows,
80300Sstevel@tonic-gate cs_globals.num_windows) != CS_SUCCESS) {
80310Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
80320Sstevel@tonic-gate return (CS_BAD_WINDOW);
80330Sstevel@tonic-gate } /* cs_add_windows */
80340Sstevel@tonic-gate
80350Sstevel@tonic-gate cs_globals.num_windows = inquire_adapter.NumWindows;
80360Sstevel@tonic-gate
80370Sstevel@tonic-gate } /* if (added_windows) */
80380Sstevel@tonic-gate
80390Sstevel@tonic-gate /*
80400Sstevel@tonic-gate * Find a window that we can use for this socket's CIS window.
80410Sstevel@tonic-gate */
80420Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80430Sstevel@tonic-gate
80440Sstevel@tonic-gate convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
80450Sstevel@tonic-gate convert_speed.nS = CIS_DEFAULT_SPEED;
80460Sstevel@tonic-gate (void) cs_convert_speed(&convert_speed);
80470Sstevel@tonic-gate
80480Sstevel@tonic-gate win_req.win_params.AccessSpeed = convert_speed.devspeed;
80490Sstevel@tonic-gate win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
80500Sstevel@tonic-gate win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
80510Sstevel@tonic-gate win_req.Base.base = 0;
80520Sstevel@tonic-gate win_req.Size = 0;
80530Sstevel@tonic-gate
80540Sstevel@tonic-gate if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
80550Sstevel@tonic-gate &sp->cis_win_num)) != CS_SUCCESS) {
80560Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
80570Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80580Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
80590Sstevel@tonic-gate "window - error 0x%x\n",
80600Sstevel@tonic-gate sp->socket_num, ret);
80610Sstevel@tonic-gate return (CS_BAD_WINDOW);
80620Sstevel@tonic-gate } /* cs_find_mem_window */
80630Sstevel@tonic-gate
80640Sstevel@tonic-gate if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
80650Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
80660Sstevel@tonic-gate return (CS_BAD_WINDOW);
80670Sstevel@tonic-gate }
80680Sstevel@tonic-gate
80690Sstevel@tonic-gate inquire_window.window = sp->cis_win_num;
80700Sstevel@tonic-gate SocketServices(SS_InquireWindow, &inquire_window);
80710Sstevel@tonic-gate
80720Sstevel@tonic-gate /*
80730Sstevel@tonic-gate * If the CIS window is a variable sized window, then use
80740Sstevel@tonic-gate * the size that cs_find_mem_window returned to us,
80750Sstevel@tonic-gate * since this will be the minimum size that we can
80760Sstevel@tonic-gate * set this window to. If the CIS window is a fixed
80770Sstevel@tonic-gate * sized window, then use the system pagesize as the
80780Sstevel@tonic-gate * CIS window size.
80790Sstevel@tonic-gate */
80800Sstevel@tonic-gate if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
80810Sstevel@tonic-gate sp->cis_win_size = win_req.Size;
80820Sstevel@tonic-gate } else {
80830Sstevel@tonic-gate sp->cis_win_size = PAGESIZE;
80840Sstevel@tonic-gate }
80850Sstevel@tonic-gate
80860Sstevel@tonic-gate cw->state |= (CW_CIS | CW_ALLOCATED);
80870Sstevel@tonic-gate cw->socket_num = sp->socket_num;
80880Sstevel@tonic-gate
80890Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock);
80900Sstevel@tonic-gate
80910Sstevel@tonic-gate #if defined(CS_DEBUG)
80920Sstevel@tonic-gate if (cs_debug > 1) {
80930Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
80940Sstevel@tonic-gate "size 0x%x\n", (int)sp->socket_num,
80950Sstevel@tonic-gate (int)sp->cis_win_num,
80960Sstevel@tonic-gate (int)sp->cis_win_size);
80970Sstevel@tonic-gate }
80980Sstevel@tonic-gate #endif
80990Sstevel@tonic-gate
81000Sstevel@tonic-gate /*
81010Sstevel@tonic-gate * Get the adapter information associated with this socket so
81020Sstevel@tonic-gate * that we can initialize the mutexes, condition variables,
81030Sstevel@tonic-gate * soft interrupt handler and per-socket adapter info.
81040Sstevel@tonic-gate */
81050Sstevel@tonic-gate gcad = &sservice.get_cookies;
81060Sstevel@tonic-gate gcad->socket = sp->socket_num;
81070Sstevel@tonic-gate if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
81080Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
81090Sstevel@tonic-gate "failure\n", sp->socket_num);
81100Sstevel@tonic-gate return (CS_BAD_SOCKET);
81110Sstevel@tonic-gate } /* CSGetCookiesAndDip */
81120Sstevel@tonic-gate
81130Sstevel@tonic-gate /*
81140Sstevel@tonic-gate * Save the iblock and idev cookies for RegisterClient
81150Sstevel@tonic-gate */
81160Sstevel@tonic-gate sp->iblk = gcad->iblock;
81170Sstevel@tonic-gate sp->idev = gcad->idevice;
81180Sstevel@tonic-gate
81190Sstevel@tonic-gate /*
81200Sstevel@tonic-gate * Setup the per-socket adapter info
81210Sstevel@tonic-gate */
81220Sstevel@tonic-gate sp->adapter.flags = 0;
81230Sstevel@tonic-gate (void) strcpy(sp->adapter.name, gcad->adapter_info.name);
81240Sstevel@tonic-gate sp->adapter.major = gcad->adapter_info.major;
81250Sstevel@tonic-gate sp->adapter.minor = gcad->adapter_info.minor;
81260Sstevel@tonic-gate sp->adapter.instance = ddi_get_instance(gcad->dip);
81270Sstevel@tonic-gate sp->adapter.number = gcad->adapter_info.number;
81280Sstevel@tonic-gate sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
81290Sstevel@tonic-gate sp->adapter.first_socket = gcad->adapter_info.first_socket;
81300Sstevel@tonic-gate
81310Sstevel@tonic-gate /* Setup for cs_event and cs_event_thread */
81320Sstevel@tonic-gate mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
81330Sstevel@tonic-gate mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
81340Sstevel@tonic-gate mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
81350Sstevel@tonic-gate
81360Sstevel@tonic-gate /* Setup for Socket Services work thread */
81370Sstevel@tonic-gate mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
81380Sstevel@tonic-gate
81390Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_MUTEX;
81400Sstevel@tonic-gate
81410Sstevel@tonic-gate /* Setup for cs_event_thread */
81420Sstevel@tonic-gate cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
81430Sstevel@tonic-gate cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
81440Sstevel@tonic-gate cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
81450Sstevel@tonic-gate
81460Sstevel@tonic-gate /* Setup for Socket Services work thread */
81470Sstevel@tonic-gate cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
81480Sstevel@tonic-gate cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
81490Sstevel@tonic-gate
81500Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_CV;
81510Sstevel@tonic-gate
81520Sstevel@tonic-gate /*
81530Sstevel@tonic-gate * If we haven't installed it yet, then install the soft interrupt
81540Sstevel@tonic-gate * handler and save away the softint id.
81550Sstevel@tonic-gate */
81560Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
81570Sstevel@tonic-gate if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
81580Sstevel@tonic-gate &sp->softint_id,
81590Sstevel@tonic-gate NULL, NULL,
81600Sstevel@tonic-gate cs_socket_event_softintr,
81610Sstevel@tonic-gate (caddr_t)NULL) != DDI_SUCCESS) {
81620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
81630Sstevel@tonic-gate "softintr\n", sp->socket_num);
81640Sstevel@tonic-gate return (CS_BAD_SOCKET);
81650Sstevel@tonic-gate } /* ddi_add_softintr */
81660Sstevel@tonic-gate
81670Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
81680Sstevel@tonic-gate cs_globals.softint_id = sp->softint_id;
81690Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
81700Sstevel@tonic-gate /* XXX this timer is hokey at best... */
81710Sstevel@tonic-gate cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
81720Sstevel@tonic-gate NULL, SOFTINT_TIMEOUT_TIME);
81730Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
81740Sstevel@tonic-gate } else {
81750Sstevel@tonic-gate /*
81760Sstevel@tonic-gate * We've already added the soft interrupt handler, so just
81770Sstevel@tonic-gate * store away the softint id.
81780Sstevel@tonic-gate */
81790Sstevel@tonic-gate sp->softint_id = cs_globals.softint_id;
81800Sstevel@tonic-gate } /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
81810Sstevel@tonic-gate
81820Sstevel@tonic-gate /*
81830Sstevel@tonic-gate * While this next flag doesn't really describe a per-socket
81840Sstevel@tonic-gate * resource, we still set it for each socket. When the soft
81850Sstevel@tonic-gate * interrupt handler finally gets removed in cs_deinit, this
81860Sstevel@tonic-gate * flag will get cleared.
81870Sstevel@tonic-gate */
81880Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
81890Sstevel@tonic-gate
81900Sstevel@tonic-gate /*
81910Sstevel@tonic-gate * Socket Services defaults all sockets to power off and
81920Sstevel@tonic-gate * clears all event masks. We want to receive at least
81930Sstevel@tonic-gate * card insertion events, so enable them. Turn off power
81940Sstevel@tonic-gate * to the socket as well. We will turn it on again when
81950Sstevel@tonic-gate * we get a card insertion event.
81960Sstevel@tonic-gate */
81970Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION;
81980Sstevel@tonic-gate set_socket.socket = sp->socket_num;
81990Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD;
82000Sstevel@tonic-gate set_socket.IREQRouting = 0;
82010Sstevel@tonic-gate set_socket.IFType = IF_MEMORY;
82020Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */
82030Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */
82040Sstevel@tonic-gate
82050Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
82060Sstevel@tonic-gate &set_socket.VccLevel);
82070Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
82080Sstevel@tonic-gate &set_socket.Vpp1Level);
82090Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
82100Sstevel@tonic-gate &set_socket.Vpp2Level);
82110Sstevel@tonic-gate
82120Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
82130Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
82140Sstevel@tonic-gate "failure %d\n", sp->socket_num, ret);
82150Sstevel@tonic-gate return (CS_BAD_SOCKET);
82160Sstevel@tonic-gate } /* SS_SetSocket */
82170Sstevel@tonic-gate
82180Sstevel@tonic-gate /*
82190Sstevel@tonic-gate * The various socket-specific variables are now set up, so
82200Sstevel@tonic-gate * increment the global socket count and also mark the
82210Sstevel@tonic-gate * socket as available. We need to set this before we
82220Sstevel@tonic-gate * start any of the per-socket threads so that the threads
82230Sstevel@tonic-gate * can get a valid socket pointer when they start.
82240Sstevel@tonic-gate */
82250Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock);
82260Sstevel@tonic-gate cs_globals.num_sockets++;
82270Sstevel@tonic-gate cs_globals.max_socket_num =
82280Sstevel@tonic-gate max(cs_globals.max_socket_num, sp->socket_num + 1);
82290Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock);
82300Sstevel@tonic-gate sp->flags = SOCKET_IS_VALID;
82310Sstevel@tonic-gate
82320Sstevel@tonic-gate /*
82330Sstevel@tonic-gate * Create the per-socket event handler thread.
82340Sstevel@tonic-gate */
82350Sstevel@tonic-gate sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
82360Sstevel@tonic-gate (uintptr_t)sn);
82370Sstevel@tonic-gate
82380Sstevel@tonic-gate mutex_enter(&sp->lock);
82390Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_THREAD;
82400Sstevel@tonic-gate mutex_exit(&sp->lock);
82410Sstevel@tonic-gate
82420Sstevel@tonic-gate /*
82430Sstevel@tonic-gate * Create the per-socket Socket Services work thread.
82440Sstevel@tonic-gate */
82450Sstevel@tonic-gate sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
82460Sstevel@tonic-gate (uintptr_t)sn);
82470Sstevel@tonic-gate
82480Sstevel@tonic-gate mutex_enter(&sp->lock);
82490Sstevel@tonic-gate sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
82500Sstevel@tonic-gate SOCKET_INIT_STATE_READY);
82510Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION;
82520Sstevel@tonic-gate mutex_exit(&sp->lock);
82530Sstevel@tonic-gate
82540Sstevel@tonic-gate return (CS_SUCCESS);
82550Sstevel@tonic-gate }
82560Sstevel@tonic-gate
82570Sstevel@tonic-gate /*
82580Sstevel@tonic-gate * cs_drop_socket - drop a socket
82590Sstevel@tonic-gate *
82600Sstevel@tonic-gate * call: sn - socket number to drop
82610Sstevel@tonic-gate *
82620Sstevel@tonic-gate * return: CS_SUCCESS - operation sucessful
82630Sstevel@tonic-gate * CS_BAD_SOCKET - unable to drop socket
82640Sstevel@tonic-gate */
82650Sstevel@tonic-gate /*ARGSUSED*/
82660Sstevel@tonic-gate static uint32_t
82670Sstevel@tonic-gate cs_drop_socket(uint32_t sn)
82680Sstevel@tonic-gate {
82690Sstevel@tonic-gate #ifdef XXX
82700Sstevel@tonic-gate cs_socket_t *sp;
82710Sstevel@tonic-gate
82720Sstevel@tonic-gate /*
82730Sstevel@tonic-gate * Tell the socket event thread to exit and then wait for it
82740Sstevel@tonic-gate * to do so.
82750Sstevel@tonic-gate */
82760Sstevel@tonic-gate mutex_enter(&sp->client_lock);
82770Sstevel@tonic-gate sp->thread_state |= SOCKET_THREAD_EXIT;
82780Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
82790Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock);
82800Sstevel@tonic-gate mutex_exit(&sp->client_lock);
82810Sstevel@tonic-gate
82820Sstevel@tonic-gate /*
82830Sstevel@tonic-gate * Tell the socket SS thread to exit and then wait for it
82840Sstevel@tonic-gate * to do so.
82850Sstevel@tonic-gate */
82860Sstevel@tonic-gate
82870Sstevel@tonic-gate /*
82880Sstevel@tonic-gate * Mark the socket as dropped.
82890Sstevel@tonic-gate */
82900Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_VALID;
82910Sstevel@tonic-gate
82920Sstevel@tonic-gate #endif /* XXX */
82930Sstevel@tonic-gate
82940Sstevel@tonic-gate /* XXX for now don't allow dropping sockets XXX */
82950Sstevel@tonic-gate return (CS_BAD_SOCKET);
82960Sstevel@tonic-gate }
82970Sstevel@tonic-gate
82980Sstevel@tonic-gate /*
82990Sstevel@tonic-gate * cs_get_socket - returns the socket and function numbers and a pointer
83000Sstevel@tonic-gate * to the socket structure
83010Sstevel@tonic-gate *
83020Sstevel@tonic-gate * calling: client_handle_t client_handle - client handle to extract
83030Sstevel@tonic-gate * socket number from
83040Sstevel@tonic-gate * uint32_t *socket - pointer to socket number to use if
83050Sstevel@tonic-gate * client_handle is for the SS client;
83060Sstevel@tonic-gate * this value will be filled in on
83070Sstevel@tonic-gate * return with the correct socket
83080Sstevel@tonic-gate * and function numbers if we
83090Sstevel@tonic-gate * return CS_SUCCESS
83100Sstevel@tonic-gate * uint32_t *function - pointer to return function number into
83110Sstevel@tonic-gate * if not NULL
83120Sstevel@tonic-gate * cs_socket_t **sp - pointer to a pointer where a pointer
83130Sstevel@tonic-gate * to the socket struct will be
83140Sstevel@tonic-gate * placed if this is non-NULL
83150Sstevel@tonic-gate * client_t **clp - pointer to a pointer where a pointer
83160Sstevel@tonic-gate * to the client struct will be
83170Sstevel@tonic-gate * placed if this is non-NULL
83180Sstevel@tonic-gate *
83190Sstevel@tonic-gate * The socket and function numbers are derived as follows:
83200Sstevel@tonic-gate *
83210Sstevel@tonic-gate * Client Type Socket Number Function Number
83220Sstevel@tonic-gate * PC card client From client_handle From client_handle
83230Sstevel@tonic-gate * Socket Services client From *socket From *socket
83240Sstevel@tonic-gate * CSI client From client_handle From *socket
83250Sstevel@tonic-gate */
83260Sstevel@tonic-gate static uint32_t
83270Sstevel@tonic-gate cs_get_socket(client_handle_t client_handle, uint32_t *socket,
83280Sstevel@tonic-gate uint32_t *function, cs_socket_t **csp, client_t **clp)
83290Sstevel@tonic-gate {
83300Sstevel@tonic-gate cs_socket_t *sp;
83310Sstevel@tonic-gate client_t *client;
83320Sstevel@tonic-gate uint32_t sn, fn;
83330Sstevel@tonic-gate int ret;
83340Sstevel@tonic-gate
83350Sstevel@tonic-gate sn = *socket;
83360Sstevel@tonic-gate
83370Sstevel@tonic-gate /*
83380Sstevel@tonic-gate * If this is the Socket Services client, then return the
83390Sstevel@tonic-gate * socket and function numbers specified in the passed
83400Sstevel@tonic-gate * socket number parameter, otherwise extract the socket
83410Sstevel@tonic-gate * and function numbers from the client handle.
83420Sstevel@tonic-gate */
83430Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) {
83440Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(sn);
83450Sstevel@tonic-gate sn = CS_GET_SOCKET_NUMBER(sn);
83460Sstevel@tonic-gate } else {
83470Sstevel@tonic-gate fn = GET_CLIENT_FUNCTION(client_handle);
83480Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(client_handle);
83490Sstevel@tonic-gate }
83500Sstevel@tonic-gate
83510Sstevel@tonic-gate /*
83520Sstevel@tonic-gate * Check to be sure that the socket number is in range
83530Sstevel@tonic-gate */
83540Sstevel@tonic-gate if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
83550Sstevel@tonic-gate return (CS_BAD_SOCKET);
83560Sstevel@tonic-gate
83570Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
83580Sstevel@tonic-gate return (CS_BAD_SOCKET);
83590Sstevel@tonic-gate
83600Sstevel@tonic-gate /*
83610Sstevel@tonic-gate * If we were given a pointer, then fill it in with a pointer
83620Sstevel@tonic-gate * to this socket.
83630Sstevel@tonic-gate */
83640Sstevel@tonic-gate if (csp)
83650Sstevel@tonic-gate *csp = sp;
83660Sstevel@tonic-gate
83670Sstevel@tonic-gate /*
83680Sstevel@tonic-gate * Search for the client; if it's not found, return an error.
83690Sstevel@tonic-gate */
83700Sstevel@tonic-gate mutex_enter(&sp->lock);
83710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &ret))) {
83720Sstevel@tonic-gate mutex_exit(&sp->lock);
83730Sstevel@tonic-gate return (ret);
83740Sstevel@tonic-gate }
83750Sstevel@tonic-gate
83760Sstevel@tonic-gate /*
83770Sstevel@tonic-gate * If we're a CIS client, then extract the function number
83780Sstevel@tonic-gate * from the socket number.
83790Sstevel@tonic-gate */
83800Sstevel@tonic-gate if (client->flags & CLIENT_CSI_CLIENT)
83810Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(*socket);
83820Sstevel@tonic-gate
83830Sstevel@tonic-gate mutex_exit(&sp->lock);
83840Sstevel@tonic-gate
83850Sstevel@tonic-gate /*
83860Sstevel@tonic-gate * Return the found client pointer if the caller wants it.
83870Sstevel@tonic-gate */
83880Sstevel@tonic-gate if (clp)
83890Sstevel@tonic-gate *clp = client;
83900Sstevel@tonic-gate
83910Sstevel@tonic-gate /*
83920Sstevel@tonic-gate * Return a socket number that is made up of the socket number
83930Sstevel@tonic-gate * and the function number.
83940Sstevel@tonic-gate */
83950Sstevel@tonic-gate *socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
83960Sstevel@tonic-gate
83970Sstevel@tonic-gate /*
83980Sstevel@tonic-gate * Return the function number if the caller wants it.
83990Sstevel@tonic-gate */
84000Sstevel@tonic-gate if (function)
84010Sstevel@tonic-gate *function = fn;
84020Sstevel@tonic-gate
84030Sstevel@tonic-gate return (CS_SUCCESS);
84040Sstevel@tonic-gate }
84050Sstevel@tonic-gate
84060Sstevel@tonic-gate /*
84070Sstevel@tonic-gate * cs_get_wp - returns pointer to passed window number
84080Sstevel@tonic-gate *
84090Sstevel@tonic-gate * return: (cs_window_t *) - pointer to window structure
84100Sstevel@tonic-gate * NULL - if invalid window number passed in
84110Sstevel@tonic-gate */
84120Sstevel@tonic-gate static cs_window_t *
84130Sstevel@tonic-gate cs_get_wp(uint32_t wn)
84140Sstevel@tonic-gate {
84150Sstevel@tonic-gate cs_window_t *cw;
84160Sstevel@tonic-gate
84170Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
84180Sstevel@tonic-gate return (NULL);
84190Sstevel@tonic-gate
84200Sstevel@tonic-gate if ((cw = cs_find_wp(wn)) == NULL)
84210Sstevel@tonic-gate return (NULL);
84220Sstevel@tonic-gate
84230Sstevel@tonic-gate if (cw->state & CW_WINDOW_VALID)
84240Sstevel@tonic-gate return (cw);
84250Sstevel@tonic-gate
84260Sstevel@tonic-gate #ifdef CS_DEBUG
84270Sstevel@tonic-gate if (cs_debug > 0) {
84280Sstevel@tonic-gate cmn_err(CE_CONT, "cs_get_wp(): wn=%d cw=%p\n",
84290Sstevel@tonic-gate (int)wn, (void *)cw);
84300Sstevel@tonic-gate }
84310Sstevel@tonic-gate #endif
84320Sstevel@tonic-gate
84330Sstevel@tonic-gate return (NULL);
84340Sstevel@tonic-gate }
84350Sstevel@tonic-gate
84360Sstevel@tonic-gate /*
84370Sstevel@tonic-gate * cs_find_wp - searches window list and returns pointer to passed window
84380Sstevel@tonic-gate * number
84390Sstevel@tonic-gate *
84400Sstevel@tonic-gate * return: (cs_window_t *) - pointer to window structure
84410Sstevel@tonic-gate * NULL - window not found
84420Sstevel@tonic-gate */
84430Sstevel@tonic-gate static cs_window_t *
84440Sstevel@tonic-gate cs_find_wp(uint32_t wn)
84450Sstevel@tonic-gate {
84460Sstevel@tonic-gate cs_window_t *cw = cs_globals.cw;
84470Sstevel@tonic-gate
84480Sstevel@tonic-gate while (cw) {
84490Sstevel@tonic-gate if (cw->window_num == wn)
84500Sstevel@tonic-gate return (cw);
84510Sstevel@tonic-gate cw = cw->next;
84520Sstevel@tonic-gate } /* while */
84530Sstevel@tonic-gate
84540Sstevel@tonic-gate #ifdef CS_DEBUG
84550Sstevel@tonic-gate if (cs_debug > 0) {
84560Sstevel@tonic-gate cmn_err(CE_CONT, "cs_find_wp(): wn=%d window_num=%d cw=%p\n",
84570Sstevel@tonic-gate (int)wn, (int)cw->window_num, (void *)cw);
84580Sstevel@tonic-gate }
84590Sstevel@tonic-gate #endif
84600Sstevel@tonic-gate
84610Sstevel@tonic-gate return (NULL);
84620Sstevel@tonic-gate }
84630Sstevel@tonic-gate
84640Sstevel@tonic-gate /*
84650Sstevel@tonic-gate * cs_add_windows - adds number of windows specified in "aw" to
84660Sstevel@tonic-gate * the global window list; start the window
84670Sstevel@tonic-gate * numbering at "bn"
84680Sstevel@tonic-gate *
84690Sstevel@tonic-gate * return: CS_SUCCESS - if windows added sucessfully
84700Sstevel@tonic-gate * CS_BAD_WINDOW - if unable to add windows
84710Sstevel@tonic-gate *
84720Sstevel@tonic-gate * Note: The window list must be protected by a lock by the caller.
84730Sstevel@tonic-gate */
84740Sstevel@tonic-gate static int
84750Sstevel@tonic-gate cs_add_windows(int aw, uint32_t bn)
84760Sstevel@tonic-gate {
84770Sstevel@tonic-gate cs_window_t *cwp = cs_globals.cw;
84780Sstevel@tonic-gate cs_window_t *cw, *cwpp;
84790Sstevel@tonic-gate
84800Sstevel@tonic-gate if (aw <= 0)
84810Sstevel@tonic-gate return (CS_BAD_WINDOW);
84820Sstevel@tonic-gate
84830Sstevel@tonic-gate while (cwp) {
84840Sstevel@tonic-gate cwpp = cwp;
84850Sstevel@tonic-gate cwp = cwp->next;
84860Sstevel@tonic-gate }
84870Sstevel@tonic-gate
84880Sstevel@tonic-gate while (aw--) {
84890Sstevel@tonic-gate cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
84900Sstevel@tonic-gate
84910Sstevel@tonic-gate if (cs_globals.cw == NULL) {
84920Sstevel@tonic-gate cs_globals.cw = cw;
84930Sstevel@tonic-gate cwpp = cs_globals.cw;
84940Sstevel@tonic-gate } else {
84950Sstevel@tonic-gate cwpp->next = cw;
84960Sstevel@tonic-gate cwpp = cwpp->next;
84970Sstevel@tonic-gate }
84980Sstevel@tonic-gate
84990Sstevel@tonic-gate cwpp->window_num = bn++;
85000Sstevel@tonic-gate cwpp->state = CW_WINDOW_VALID;
85010Sstevel@tonic-gate
85020Sstevel@tonic-gate } /* while (aw) */
85030Sstevel@tonic-gate
85040Sstevel@tonic-gate return (CS_SUCCESS);
85050Sstevel@tonic-gate }
85060Sstevel@tonic-gate
85070Sstevel@tonic-gate /*
85080Sstevel@tonic-gate * cs_ss_init - initialize CS items that need to wait until we receive
85090Sstevel@tonic-gate * a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
85100Sstevel@tonic-gate *
85110Sstevel@tonic-gate * return: CS_SUCESS - if sucessfully initialized
85120Sstevel@tonic-gate * (various) if error initializing
85130Sstevel@tonic-gate *
85140Sstevel@tonic-gate * At this point, we expect that Socket Services has setup the
85150Sstevel@tonic-gate * following global variables for us:
85160Sstevel@tonic-gate *
85170Sstevel@tonic-gate * cs_socket_services - Socket Services entry point
85180Sstevel@tonic-gate * cis_parser - CIS parser entry point
85190Sstevel@tonic-gate */
85200Sstevel@tonic-gate static uint32_t
85210Sstevel@tonic-gate cs_ss_init()
85220Sstevel@tonic-gate {
85230Sstevel@tonic-gate cs_register_cardservices_t rcs;
85240Sstevel@tonic-gate csregister_t csr;
85250Sstevel@tonic-gate uint32_t ret;
85260Sstevel@tonic-gate
85270Sstevel@tonic-gate /*
85280Sstevel@tonic-gate * Fill out the parameters for CISP_CIS_SETUP
85290Sstevel@tonic-gate */
85300Sstevel@tonic-gate csr.cs_magic = PCCS_MAGIC;
85310Sstevel@tonic-gate csr.cs_version = PCCS_VERSION;
85320Sstevel@tonic-gate csr.cs_card_services = CardServices;
85330Sstevel@tonic-gate csr.cs_event = NULL;
85340Sstevel@tonic-gate
85350Sstevel@tonic-gate /*
85360Sstevel@tonic-gate * Call into the CIS module and tell it what the private
85370Sstevel@tonic-gate * Card Services entry point is. The CIS module will
85380Sstevel@tonic-gate * call us back at CardServices(CISRegister, ...)
85390Sstevel@tonic-gate * with the address of various CIS-specific global
85400Sstevel@tonic-gate * data structures.
85410Sstevel@tonic-gate */
85420Sstevel@tonic-gate CIS_PARSER(CISP_CIS_SETUP, &csr);
85430Sstevel@tonic-gate
85440Sstevel@tonic-gate /*
85450Sstevel@tonic-gate * Register with the Card Services kernel stubs module
85460Sstevel@tonic-gate */
85470Sstevel@tonic-gate rcs.magic = CS_STUBS_MAGIC;
85480Sstevel@tonic-gate rcs.function = CS_ENTRY_REGISTER;
85490Sstevel@tonic-gate rcs.cardservices = CardServices;
85500Sstevel@tonic-gate
85510Sstevel@tonic-gate if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
85520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_init: can't register with "
85530Sstevel@tonic-gate "cs_stubs, retcode = 0x%x\n", ret);
85540Sstevel@tonic-gate return (ret);
85550Sstevel@tonic-gate } /* csx_register_cardservices */
85560Sstevel@tonic-gate
85570Sstevel@tonic-gate return (CS_SUCCESS);
85580Sstevel@tonic-gate }
85590Sstevel@tonic-gate
85600Sstevel@tonic-gate /*
85610Sstevel@tonic-gate * cs_create_cis - reads CIS on card in socket and creates CIS lists
85620Sstevel@tonic-gate *
85630Sstevel@tonic-gate * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
85640Sstevel@tonic-gate * function.
85650Sstevel@tonic-gate *
85660Sstevel@tonic-gate * This function returns:
85670Sstevel@tonic-gate *
85680Sstevel@tonic-gate * CS_SUCCESS - if the CIS lists were created sucessfully
85690Sstevel@tonic-gate * CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
85700Sstevel@tonic-gate * not be setup
85710Sstevel@tonic-gate * CS_BAD_CIS - if error creating CIS chains
85720Sstevel@tonic-gate * CS_BAD_OFFSET - if the CIS parser tried to read past the
85730Sstevel@tonic-gate * boundries of the allocated CIS window
85740Sstevel@tonic-gate */
85750Sstevel@tonic-gate static int
85760Sstevel@tonic-gate cs_create_cis(cs_socket_t *sp)
85770Sstevel@tonic-gate {
85780Sstevel@tonic-gate uint32_t ret;
85790Sstevel@tonic-gate
85800Sstevel@tonic-gate ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
85810Sstevel@tonic-gate cis_cistpl_std_callout, sp);
85820Sstevel@tonic-gate
85830Sstevel@tonic-gate #ifdef CS_DEBUG
85840Sstevel@tonic-gate if (ret == CS_NO_CIS) {
85850Sstevel@tonic-gate if (cs_debug > 0)
85860Sstevel@tonic-gate cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
85870Sstevel@tonic-gate sp->socket_num);
85880Sstevel@tonic-gate } else if (ret != CS_SUCCESS) {
85890Sstevel@tonic-gate if (cs_debug > 0)
85900Sstevel@tonic-gate cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
85910Sstevel@tonic-gate sp->socket_num, ret);
85920Sstevel@tonic-gate return (ret);
85930Sstevel@tonic-gate }
85940Sstevel@tonic-gate #else
85950Sstevel@tonic-gate if (ret != CS_NO_CIS)
85960Sstevel@tonic-gate if (ret != CS_SUCCESS)
85970Sstevel@tonic-gate return (ret);
85980Sstevel@tonic-gate #endif
85990Sstevel@tonic-gate
86000Sstevel@tonic-gate /*
86010Sstevel@tonic-gate * If this card didn't have any CIS at all, there's not much
86020Sstevel@tonic-gate * else for us to do.
86030Sstevel@tonic-gate */
86040Sstevel@tonic-gate if (!(sp->cis_flags & CW_VALID_CIS))
86050Sstevel@tonic-gate return (CS_SUCCESS);
86060Sstevel@tonic-gate
86070Sstevel@tonic-gate /*
86080Sstevel@tonic-gate * If this is a single-function card, we need to move the CIS list
86090Sstevel@tonic-gate * that is currently on CS_GLOBAL_CIS to the function zero
86100Sstevel@tonic-gate * CIS list.
86110Sstevel@tonic-gate */
86120Sstevel@tonic-gate if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
86130Sstevel@tonic-gate bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
86140Sstevel@tonic-gate (caddr_t)&sp->cis[0], sizeof (cis_info_t));
86150Sstevel@tonic-gate bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
86160Sstevel@tonic-gate } /* !CW_MULTI_FUNCTION_CIS */
86170Sstevel@tonic-gate
86180Sstevel@tonic-gate return (CS_SUCCESS);
86190Sstevel@tonic-gate }
86200Sstevel@tonic-gate
86210Sstevel@tonic-gate /*
86220Sstevel@tonic-gate * cs_destroy_cis - destroys CIS list for socket
86230Sstevel@tonic-gate */
86240Sstevel@tonic-gate static int
86250Sstevel@tonic-gate cs_destroy_cis(cs_socket_t *sp)
86260Sstevel@tonic-gate {
86270Sstevel@tonic-gate CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
86280Sstevel@tonic-gate
86290Sstevel@tonic-gate return (CS_SUCCESS);
86300Sstevel@tonic-gate }
86310Sstevel@tonic-gate
86320Sstevel@tonic-gate /*
86330Sstevel@tonic-gate * cs_get_client_info - This function is GetClientInfo.
86340Sstevel@tonic-gate *
86350Sstevel@tonic-gate * calling: client_handle_t - client handle to get client info on
86360Sstevel@tonic-gate * client_info_t * - pointer to a client_info_t structure
86370Sstevel@tonic-gate * to return client information in
86380Sstevel@tonic-gate *
86390Sstevel@tonic-gate * returns: CS_SUCCESS - if client info retreived from client
86400Sstevel@tonic-gate * CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
86410Sstevel@tonic-gate * handle passed in
86420Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if client does not handle the
86430Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO event
86440Sstevel@tonic-gate * or if invalid client info
86450Sstevel@tonic-gate * retreived from client
86460Sstevel@tonic-gate */
86470Sstevel@tonic-gate static int
86480Sstevel@tonic-gate cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
86490Sstevel@tonic-gate {
86500Sstevel@tonic-gate cs_socket_t *sp;
86510Sstevel@tonic-gate client_t *client;
86520Sstevel@tonic-gate client_info_t *cinfo;
86530Sstevel@tonic-gate int ret = CS_SUCCESS;
86540Sstevel@tonic-gate
86550Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) {
86560Sstevel@tonic-gate ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
86570Sstevel@tonic-gate CS_CLIENT_INFO_VALID);
86580Sstevel@tonic-gate return (CS_SUCCESS);
86590Sstevel@tonic-gate } /* CLIENT_HANDLE_IS_SS */
86600Sstevel@tonic-gate
86610Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
86620Sstevel@tonic-gate return (CS_BAD_SOCKET);
86630Sstevel@tonic-gate
86640Sstevel@tonic-gate mutex_enter(&sp->client_lock);
86650Sstevel@tonic-gate mutex_enter(&sp->lock);
86660Sstevel@tonic-gate
86670Sstevel@tonic-gate if ((client = cs_find_client(client_handle, &ret)) == NULL) {
86680Sstevel@tonic-gate mutex_exit(&sp->lock);
86690Sstevel@tonic-gate mutex_exit(&sp->client_lock);
86700Sstevel@tonic-gate return (ret);
86710Sstevel@tonic-gate } /* cs_find_client */
86720Sstevel@tonic-gate
86730Sstevel@tonic-gate /*
86740Sstevel@tonic-gate * If this client is not handling CS_EVENT_CLIENT_INFO events,
86750Sstevel@tonic-gate * then don't bother to even wake up the event thread.
86760Sstevel@tonic-gate */
86770Sstevel@tonic-gate if (!((client->event_mask | client->global_mask) &
86780Sstevel@tonic-gate CS_EVENT_CLIENT_INFO)) {
86790Sstevel@tonic-gate mutex_exit(&sp->lock);
86800Sstevel@tonic-gate mutex_exit(&sp->client_lock);
86810Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
86820Sstevel@tonic-gate } /* !CS_EVENT_CLIENT_INFO */
86830Sstevel@tonic-gate
86840Sstevel@tonic-gate cinfo = &client->event_callback_args.client_info;
86850Sstevel@tonic-gate
86860Sstevel@tonic-gate bzero((caddr_t)cinfo, sizeof (client_info_t));
86870Sstevel@tonic-gate cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
86880Sstevel@tonic-gate
86890Sstevel@tonic-gate client->events |= CS_EVENT_CLIENT_INFO;
86900Sstevel@tonic-gate
86910Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_SYNC;
86920Sstevel@tonic-gate mutex_exit(&sp->lock);
86930Sstevel@tonic-gate cv_broadcast(&sp->thread_cv);
86940Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock);
86950Sstevel@tonic-gate
86960Sstevel@tonic-gate if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
86970Sstevel@tonic-gate bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
86980Sstevel@tonic-gate ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
86990Sstevel@tonic-gate CS_CLIENT_INFO_SUBSVC_MASK);
87000Sstevel@tonic-gate ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
87010Sstevel@tonic-gate INFO_CARD_FLAGS_MASK |
87020Sstevel@tonic-gate CS_CLIENT_INFO_CLIENT_ACTIVE);
87030Sstevel@tonic-gate ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
87040Sstevel@tonic-gate INFO_CARD_FLAGS_MASK));
87050Sstevel@tonic-gate (void) strcpy(ci->DriverName, client->driver_name);
87060Sstevel@tonic-gate if (cs_card_for_client(client))
87070Sstevel@tonic-gate ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
87080Sstevel@tonic-gate } else {
87090Sstevel@tonic-gate ret = CS_NO_MORE_ITEMS;
87100Sstevel@tonic-gate } /* CS_CLIENT_INFO_VALID */
87110Sstevel@tonic-gate
87120Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87130Sstevel@tonic-gate
87140Sstevel@tonic-gate return (ret);
87150Sstevel@tonic-gate }
87160Sstevel@tonic-gate
87170Sstevel@tonic-gate /*
87180Sstevel@tonic-gate * cs_get_firstnext_client - This function is GetFirstClient and
87190Sstevel@tonic-gate * GetNextClient
87200Sstevel@tonic-gate *
87210Sstevel@tonic-gate * calling: get_firstnext_client_t * - pointer to a get_firstnext_client_t
87220Sstevel@tonic-gate * structure to return client handle and
87230Sstevel@tonic-gate * attributes in
87240Sstevel@tonic-gate * flags - one of the following:
87250Sstevel@tonic-gate * CS_GET_FIRST_FLAG - get first client handle
87260Sstevel@tonic-gate * CS_GET_NEXT_FLAG - get next client handle
87270Sstevel@tonic-gate *
87280Sstevel@tonic-gate * returns: CS_SUCCESS - if client info retreived from client
87290Sstevel@tonic-gate * CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
87300Sstevel@tonic-gate * handle passed in
87310Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if client does not handle the
87320Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO event
87330Sstevel@tonic-gate * or if invalid client info
87340Sstevel@tonic-gate * retreived from client
87350Sstevel@tonic-gate */
87360Sstevel@tonic-gate static int
87370Sstevel@tonic-gate cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
87380Sstevel@tonic-gate {
87390Sstevel@tonic-gate cs_socket_t *sp;
87400Sstevel@tonic-gate client_t *client;
87410Sstevel@tonic-gate uint32_t sn = 0;
87420Sstevel@tonic-gate int ret = CS_SUCCESS;
87430Sstevel@tonic-gate
87440Sstevel@tonic-gate switch (flags) {
87450Sstevel@tonic-gate case CS_GET_FIRST_FLAG:
87460Sstevel@tonic-gate if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87470Sstevel@tonic-gate while (sn < cs_globals.max_socket_num) {
87480Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) {
87490Sstevel@tonic-gate mutex_enter(&sp->client_lock);
87500Sstevel@tonic-gate if ((client = sp->client_list) != NULL)
87510Sstevel@tonic-gate break;
87520Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87530Sstevel@tonic-gate } /* if */
87540Sstevel@tonic-gate sn++;
87550Sstevel@tonic-gate } /* while */
87560Sstevel@tonic-gate
87570Sstevel@tonic-gate if (sn == cs_globals.max_socket_num)
87580Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
87590Sstevel@tonic-gate } else if (fnc->Attributes &
87600Sstevel@tonic-gate CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
87610Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
87620Sstevel@tonic-gate NULL)
87630Sstevel@tonic-gate return (CS_BAD_SOCKET);
87640Sstevel@tonic-gate mutex_enter(&sp->client_lock);
87650Sstevel@tonic-gate if ((client = sp->client_list) == NULL) {
87660Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87670Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
87680Sstevel@tonic-gate }
87690Sstevel@tonic-gate } else {
87700Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
87710Sstevel@tonic-gate }
87720Sstevel@tonic-gate
87730Sstevel@tonic-gate fnc->client_handle = client->client_handle;
87740Sstevel@tonic-gate fnc->num_clients = sp->num_clients;
87750Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87760Sstevel@tonic-gate break;
87770Sstevel@tonic-gate case CS_GET_NEXT_FLAG:
87780Sstevel@tonic-gate if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87790Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(fnc->client_handle);
87800Sstevel@tonic-gate
87810Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL)
87820Sstevel@tonic-gate return (CS_BAD_SOCKET);
87830Sstevel@tonic-gate
87840Sstevel@tonic-gate mutex_enter(&sp->client_lock);
87850Sstevel@tonic-gate if ((client = cs_find_client(fnc->client_handle,
87860Sstevel@tonic-gate &ret)) == NULL) {
87870Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87880Sstevel@tonic-gate return (ret);
87890Sstevel@tonic-gate }
87900Sstevel@tonic-gate if ((client = client->next) == NULL) {
87910Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87920Sstevel@tonic-gate sn++;
87930Sstevel@tonic-gate while (sn < cs_globals.max_socket_num) {
87940Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) {
87950Sstevel@tonic-gate mutex_enter(&sp->client_lock);
87960Sstevel@tonic-gate if ((client = sp->client_list) != NULL)
87970Sstevel@tonic-gate break;
87980Sstevel@tonic-gate mutex_exit(&sp->client_lock);
87990Sstevel@tonic-gate } /* if */
88000Sstevel@tonic-gate sn++;
88010Sstevel@tonic-gate } /* while */
88020Sstevel@tonic-gate
88030Sstevel@tonic-gate if (sn == cs_globals.max_socket_num)
88040Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
88050Sstevel@tonic-gate } /* client = client->next */
88060Sstevel@tonic-gate
88070Sstevel@tonic-gate } else if (fnc->Attributes &
88080Sstevel@tonic-gate CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
88090Sstevel@tonic-gate sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
88100Sstevel@tonic-gate if (sp == NULL)
88110Sstevel@tonic-gate return (CS_BAD_SOCKET);
88120Sstevel@tonic-gate mutex_enter(&sp->client_lock);
88130Sstevel@tonic-gate if ((client = cs_find_client(fnc->client_handle,
88140Sstevel@tonic-gate &ret)) == NULL) {
88150Sstevel@tonic-gate mutex_exit(&sp->client_lock);
88160Sstevel@tonic-gate return (ret);
88170Sstevel@tonic-gate }
88180Sstevel@tonic-gate if ((client = client->next) == NULL) {
88190Sstevel@tonic-gate mutex_exit(&sp->client_lock);
88200Sstevel@tonic-gate return (CS_NO_MORE_ITEMS);
88210Sstevel@tonic-gate }
88220Sstevel@tonic-gate } else {
88230Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE);
88240Sstevel@tonic-gate }
88250Sstevel@tonic-gate
88260Sstevel@tonic-gate fnc->client_handle = client->client_handle;
88270Sstevel@tonic-gate fnc->num_clients = sp->num_clients;
88280Sstevel@tonic-gate mutex_exit(&sp->client_lock);
88290Sstevel@tonic-gate break;
88300Sstevel@tonic-gate default:
88310Sstevel@tonic-gate ret = CS_BAD_ATTRIBUTE;
88320Sstevel@tonic-gate break;
88330Sstevel@tonic-gate
88340Sstevel@tonic-gate } /* switch */
88350Sstevel@tonic-gate
88360Sstevel@tonic-gate return (ret);
88370Sstevel@tonic-gate }
88380Sstevel@tonic-gate
88390Sstevel@tonic-gate /*
88400Sstevel@tonic-gate * cs_set_acc_attributes - converts Card Services endianness and
88410Sstevel@tonic-gate * data ordering values to values
88420Sstevel@tonic-gate * that Socket Services understands
88430Sstevel@tonic-gate *
88440Sstevel@tonic-gate * calling: *sw - pointer to a set_window_t to set attributes in
88450Sstevel@tonic-gate * Attributes - CS attributes
88460Sstevel@tonic-gate */
88470Sstevel@tonic-gate static void
88480Sstevel@tonic-gate cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
88490Sstevel@tonic-gate {
88500Sstevel@tonic-gate sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
88510Sstevel@tonic-gate
88520Sstevel@tonic-gate switch (Attributes & WIN_ACC_ENDIAN_MASK) {
88530Sstevel@tonic-gate case WIN_ACC_LITTLE_ENDIAN:
88540Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
88550Sstevel@tonic-gate break;
88560Sstevel@tonic-gate case WIN_ACC_BIG_ENDIAN:
88570Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
88580Sstevel@tonic-gate break;
88590Sstevel@tonic-gate case WIN_ACC_NEVER_SWAP:
88600Sstevel@tonic-gate default:
88610Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
88620Sstevel@tonic-gate break;
88630Sstevel@tonic-gate } /* switch */
88640Sstevel@tonic-gate
88650Sstevel@tonic-gate switch (Attributes & WIN_ACC_ORDER_MASK) {
88660Sstevel@tonic-gate case WIN_ACC_UNORDERED_OK:
88670Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
88680Sstevel@tonic-gate break;
88690Sstevel@tonic-gate case WIN_ACC_MERGING_OK:
88700Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
88710Sstevel@tonic-gate break;
88720Sstevel@tonic-gate case WIN_ACC_LOADCACHING_OK:
88730Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
88740Sstevel@tonic-gate break;
88750Sstevel@tonic-gate case WIN_ACC_STORECACHING_OK:
88760Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
88770Sstevel@tonic-gate break;
88780Sstevel@tonic-gate case WIN_ACC_STRICT_ORDER:
88790Sstevel@tonic-gate default:
88800Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
88810Sstevel@tonic-gate break;
88820Sstevel@tonic-gate } /* switch */
88830Sstevel@tonic-gate }
8884