/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PCMCIA Card Services
* The PCMCIA Card Services is a loadable module which
* presents the Card Services interface to client device
* drivers.
*
* Card Services uses Socket Services-like calls into the
* PCMCIA nexus driver to manipulate socket and adapter
* resources.
*
* Note that a bunch of comments are not indented correctly with the
* code that they are commenting on. This is because cstyle is
* is inflexible concerning 4-column indenting.
*/
#if defined(DEBUG)
#define CS_DEBUG
#endif
#include <sys/autoconf.h>
#include <sys/sservice.h>
/*
* The cs_strings header file is where all of the major strings that
* Card Services uses are located.
*/
/*
* Function declarations
*
* The main Card Services entry point
*/
int CardServices(int function, ...);
/*
* functions and globals used by Socket Services
*
* WAS: void *(*cis_parser)(int, ...) = NULL;
*/
/*
* event handling functions
*/
static void cs_event_thread(uint32_t);
static int cs_card_removal(cs_socket_t *);
static void cs_ss_thread(uint32_t);
void cs_ready_timeout(void *);
static int cs_card_for_client(client_t *);
static int cs_event2text(event2text_t *, int);
get_ss_status_t *, int);
void cs_event_softintr_timeout(void *);
static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
/*
* SS<->CS communication and internal socket and window handling functions
*/
static int cs_add_windows(int, uint32_t);
static uint32_t cs_ss_init();
/*
* CIS handling functions
*/
static int cs_create_cis(cs_socket_t *);
static int cs_destroy_cis(cs_socket_t *);
/*
* client handling functions
*/
unsigned cs_create_next_client_minor(unsigned, unsigned);
static int cs_destroy_client_handle(client_handle_t);
static int cs_deregister_client(client_handle_t);
static int cs_deregister_mtd(client_handle_t);
static void cs_clear_superclient_lock(int);
static int cs_add_client_to_socket(unsigned, client_handle_t *,
client_reg_t *, int);
/*
* window handling functions
*/
static int cs_release_window(window_handle_t);
int);
/*
* IO, IRQ and configuration handling functions
*/
static int cs_access_configuration_register(client_handle_t,
/*
* RESET and general info functions
*/
static int cs_get_configuration_info(client_handle_t *,
static int cs_get_cardservices_info(client_handle_t,
static int cs_get_physical_adapter_info(client_handle_t,
/*
* general functions
*/
cs_socket_t **, client_t **);
static int cs_convert_speed(convert_speed_t *);
static int cs_convert_size(convert_size_t *);
static char *cs_error2text(int, int);
static int cs_ddi_info(cs_ddi_info_t *);
uint32_t);
static int cs_sys_ctl(cs_sys_ctl_t *);
/*
* global variables
*/
#ifdef CS_DEBUG
int cs_debug = 0;
#endif
/*
* cs_init - Initialize CS internal structures, databases, and state,
* and register with SS
*
* XXX - Need to make sure that if we fail at any point that we free
* any resources that we allocated, as well as kill any
* threads that may have been started.
*/
int
cs_init()
{
/*
* Initialize the CS global structure
*/
/*
* Set up the global Socket Services client, since we're going to
* need it once we register with SS.
*/
/*
* Setup the client type structure - this is used in the socket event
* thread to sequence the delivery of events to all clients on
* the socket.
*/
ct = &client_types[0];
return (CS_SUCCESS);
}
/*
* cs_deinit - Deinitialize CS
*
* This function cleans up any allocated resources, stops any running threads,
* destroys any mutexes and condition variables, and finally frees up the
* global socket and window structure arrays.
*/
int
{
#if defined(CS_DEBUG)
if (cs_debug > 1)
#endif
/*
* Deregister with the Card Services kernel stubs module
*/
(void) csx_register_cardservices(&rcs);
/*
* Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
* from registering.
*/
/*
* Go through each socket and make sure that there are no clients
* on any of the sockets. If there are, we can't deinit until
* all the clients for every socket are gone.
*/
have_sockets++;
if (sp->client_list) {
"socket %d has registered clients\n", sn);
have_clients++;
}
}
}
/*
* We don't allow unload if there are any clients registered
* or if there are still sockets that are active.
*/
if ((have_clients > 0) || (have_sockets > 0))
return (BAD_FUNCTION);
#ifdef XXX
/*
* If one or more sockets have been added, we need to deallocate
* the resources associated with those sockets.
*/
/*
* First, tell Socket Services that we're leaving, so that we
* don't get any more event callbacks.
*/
/*
* Wait for the soft int timer to tell us it's done
*/
/*
* Remove the soft interrupt handler.
*/
}
return (CS_SUCCESS);
/*
* Go through each socket and free any resource allocated to that
* socket, as well as any mutexs and condition variables.
*/
/*
*/
(void) cs_destroy_cis(sp);
/*
* Tell the event handler thread that we want it to exit, then
* wait around until it tells us that it has exited.
*/
}
/*
* Tell the SS work thread that we want it to exit, then
* wait around until it tells us that it has exited.
*/
}
/*
* Free the mutexii and condition variables that we used.
*/
}
}
#ifdef USE_IOMMAP_WINDOW
/*
* Free the memory-mapped IO structure if we allocated one.
*/
if (sp->io_mmap_window)
#endif /* USE_IOMMAP_WINDOW */
/*
* Return the socket to memory-only mode and turn off the
* socket power.
*/
sp->event_mask = 0;
set_socket.SCIntMask = 0;
set_socket.IREQRouting = 0;
/*
* If we fail this call, there's not much we can do, so
* just continue with the resource deallocation.
*/
if ((ret =
"cs_deinit: socket %d SS_SetSocket failure %d\n",
}
} /* cs_get_sp */
} /* for (sn) */
#endif /* XXX */
/*
* Destroy the global mutexii.
*/
#ifdef XXX
/*
* Free the global "super-client" structure
*/
if (cs_globals.sclient_list)
#endif /* XXX */
return (CS_SUCCESS);
}
/*
* ==== drip, drip, drip - the Card Services waterfall :-) ====
*/
/*
* CardServices - general Card Services entry point for CS clients
* and Socket Services; the address of this
* function is handed to SS via the CSRegister
* SS call
*/
int
{
#ifdef CS_DEBUG
if (cs_debug > 127) {
function);
}
#endif
/*
* Here's the Card Services waterfall
*/
switch (function) {
/*
* We got here as a result of the CIS module calling us
* in response to cs_ss_init() calling the CIS module
* at CIS_PARSER(CISP_CIS_SETUP, ...)
*/
case CISRegister: {
"CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
(long)cisr->cis_version,
(long)cisr->cis_parser,
(long)cisr->cistpl_std_callout);
} else {
/*
* Replace the CIS Parser entry point if
* necessary.
*/
}
}
break;
case CISUnregister: /* XXX - should we do some more checking */
/* XXX - need to protect this by a mutex */
cis_parser = NULL;
break;
case InitCISWindow:
break;
case RegisterClient:
break;
case DeregisterClient:
break;
case GetStatus:
break;
case ResetFunction:
break;
case SetEventMask:
break;
case GetEventMask:
break;
case RequestIO:
break;
case ReleaseIO:
break;
case RequestIRQ:
break;
case ReleaseIRQ:
break;
case RequestWindow:
break;
case ReleaseWindow:
break;
case ModifyWindow:
break;
case MapMemPage:
break;
case RequestSocketMask:
break;
case ReleaseSocketMask:
break;
case RequestConfiguration:
break;
case GetPhysicalAdapterInfo:
break;
case GetCardServicesInfo:
break;
case GetConfigurationInfo:
break;
case ModifyConfiguration:
break;
break;
case ReleaseConfiguration:
break;
case OpenMemory:
break;
case ReadMemory:
break;
case WriteMemory:
break;
case CopyMemory:
break;
case RegisterEraseQueue:
break;
case CheckEraseQueue:
break;
case DeregisterEraseQueue:
break;
case CloseMemory:
break;
case GetFirstRegion:
break;
case GetNextRegion:
break;
case GetFirstPartition:
break;
case GetNextPartition:
break;
case ReturnSSEntry:
break;
case MapLogSocket:
break;
case MapPhySocket:
break;
case MapLogWindow:
break;
case MapPhyWindow:
break;
case RegisterMTD:
break;
case RegisterTimer:
break;
case SetRegion:
break;
case RequestExclusive:
break;
case ReleaseExclusive:
break;
case GetFirstClient:
break;
case GetNextClient:
break;
case GetClientInfo:
break;
case AddSocketServices:
break;
case ReplaceSocketServices:
break;
case VendorSpecific:
break;
case AdjustResourceInfo:
break;
case ValidateCIS:
break;
case GetFirstTuple:
break;
case GetNextTuple:
break;
case GetTupleData:
break;
case ParseTuple:
break;
case MakeDeviceNode:
break;
case RemoveDeviceNode:
break;
case ConvertSpeed:
break;
case ConvertSize:
break;
case Event2Text:
break;
case Error2Text: {
}
break;
case CS_DDI_Info:
break;
case CS_Sys_Ctl:
break;
default:
break;
} /* switch(function) */
#ifdef CS_DEBUG
if (cs_debug > 127) {
retcode);
}
#endif
return (retcode);
}
/*
* ==== tuple and CIS handling section ====
*/
/*
* cs_parse_tuple - This function supports the CS ParseTuple function call.
*
* returns: CS_SUCCESS - if tuple parsed sucessfully
* CS_NO_CARD - if no card in socket
* CS_BAD_ARGS - if passed CIS list pointer is NULL
* CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
* CS_BAD_CIS - if generic parser error
*
* See notes for the cs_get_firstnext_tuple function.
*/
static int
{
int ret;
return (ret);
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
/*
* Sanity check to be sure that we've got a non-NULL CIS list
* pointer.
*/
return (CS_BAD_ARGS);
/*
* Check to see if there is a valid CIS for this function.
* There is an implicit assumption here that if this
* is a multi-function CIS and the specified function
* number is not CS_GLOBAL_CIS that in order for there
* to be a valid function-specific CIS, there also must
* be a valid global CIS. This means that we don't need
* to know whether this tuple came from the global CIS
* or from the function-specific CIS.
*/
if (ret == CISTPLF_UNKNOWN)
return (CS_UNKNOWN_TUPLE);
if (ret != CISTPLF_NOERROR)
return (CS_BAD_CIS);
ret = CS_SUCCESS;
} else {
} /* if (CW_VALID_CIS) */
return (ret);
}
/*
* this is to support the GetFirstTuple and
* GetNextTuple function call
*
* flags - one of:
* CS_GET_FIRST_FLAG causes function to support GetFirstTuple
* CS_GET_NEXT_FLAG causes function to support GetNextTuple
*
* tuple_t->Attributes flags:
* TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
* TUPLE_RETURN_IGNORED_TUPLES - return tuples with
* CISTPLF_IGNORE_TUPLE set in the
* cistpl_t->flags member.
*
* Notes for regular PC card driver callers:
*
* On a single-function card, the caller will get back all the tuples in
* the CIS.
*
* On a multi-function card, the caller will get the tuples from the
* global CIS followed by the tuples in the function-specific CIS. The
* caller will not get any tuples from a function-specific CIS that
* does not belong to the caller's function.
*
* Notes for Socket Services, the "super-client" or CSI driver callers:
*
* On a single-function card, the operation is the same as for regular
* PC card driver callers with the addition that if the function number
* is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
*
* On a multi-function card, the operation is the same as for regular
* PC card driver callers with the addition that if the function number
* is set to CS_GLOBAL_CIS the caller will only get tuples from the
* global CIS. If a particular function nubmer does not exist, this
* function will return CS_NO_CIS for that function.
*
* General notes:
*
* On both a single-function card and a multi-function card, if the tuple
* comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
* set in the tuple_t->flags member.
*
* On a multi-function card, if the tuple comes from the function-specific
* CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
* member.
*
* For other flags that are set in the tuple_t->flags member, see the
* comments for the cis_list_lcreate function in the cis.c file.
*
* The CIS parser may not include all the tuples that are in the CIS in
* the private CIS list that it creates and maintains. See the CIS
* parser documentation for a list of tuples that the parser does not
* include in the list.
*
* If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
* parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
* be returned to the caller. Instead, the next tuple that matches
* the calling criteria will be returned (or NULL if no other tuples
* match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
* the flags paramter, tuples in the CIS list that match the calling
* criteria will be returned.
*
* XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
* the tuple_t->Attributes member is not set, then we don't return
* any of the link tuples. This function ignores this flag and always
* returns link tuples.
*
* Return codes:
* CS_SUCCESS - if tuple sucessfully found and returned
* CS_NO_CARD - if no card inserted
* CS_NO_MORE_ITEMS - if tuple not found or no more tuples
* to return
*
* See notes for cs_get_socket for a description of valid client, socket
* and function number combinations.
*/
static int
{
int ret;
return (ret);
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
/*
* If there's no CIS on this card or no CIS for the specified
* function, then we can't do much.
*/
return (CS_NO_CIS);
}
/*
* This will set the CIS_GET_LTUPLE_IGNORE flag if the
* TUPLE_RETURN_IGNORED_TUPLES flag is set. The
* assumption here is that the CIS_GET_LTUPLE_IGNORE
* flag and the TUPLE_RETURN_IGNORED_TUPLES flag
* shares the same bit position. If this ever changes,
* we'll ahve to re-work this section of code.
*/
/*
* Are we GetFirstTuple or GetNextTuple?
*/
/*
* Initialize the tuple structure; we need this information when
* we have to process a GetNextTuple or ParseTuple call.
* If this card has a multi-function CIS, then we always start out
* delivering tuples from the global CIS chain. If this card does
* not have a multi-function CIS, then the function 0 CIS chain
* will contain the complete CIS list.
* If this is a multi-function card, then use the GET_FIRST_LTUPLE
* macro to return the first tuple in the CIS list - we do this
* since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
* set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
* Note that we don't have to cross over into the fucntion-specific
* CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
* always have at least a CISTPL_LONGLINK_MFC tuple in the global
* CIS chain - the test for NULL is just a sanity check.
*/
return (CS_NO_MORE_ITEMS);
} /* GET_FIRST_LTUPLE */
} else {
} /* CW_MULTI_FUNCTION_CIS */
} else {
/*
* Check to be sure that we have a non-NULL tuple list pointer.
* This is necessary in the case where the caller calls us
* with get next tuple requests but we don't have any more
* tuples to give back.
*/
return (CS_NO_MORE_ITEMS);
}
/*
* Point to the next tuple in the list. If we're searching for
* a particular tuple, FIND_LTUPLE_FWD will find it.
*
* If there are no more tuples in the chain that we're looking
* at, then if we're looking at the global portion of a
* multi-function CIS, switch to the function-specific list
* and start looking there.
*/
(fn != CS_GLOBAL_CIS)) {
} /* CISTPLF_GLOBAL_CIS */
} /* CW_MULTI_FUNCTION_CIS */
} /* GET_NEXT_TUPLE */
/*
* If there are no more tuples in the chain, then return.
*/
return (CS_NO_MORE_ITEMS);
}
} /* CS_GET_FIRST_FLAG */
/*
* Check if we want to get the first of a particular type of tuple
* or just the first tuple in the chain.
* If there are no more tuples of the type we're searching for in
* the chain that we're looking at, then if we're looking at
* the global portion of a multi-function CIS, switch to the
* function-specific list and start looking there.
*/
(fn != CS_GLOBAL_CIS)) {
} /* CISTPLF_GLOBAL_CIS */
} /* CW_MULTI_FUNCTION_CIS */
} /* FIND_LTUPLE_FWD */
/*
* If there are no more tuples in the chain, then return.
*/
return (CS_NO_MORE_ITEMS);
}
} /* !RETURN_FIRST_TUPLE */
/*
* We've got a tuple, now fill out the rest of the tuple_t
* structure. Callers can use the flags member to
* determine whether or not the tuple data was copied
* to the linked list or if it's still on the card.
*/
return (CS_SUCCESS);
}
/*
* cs_get_tuple_data - get the data portion of a tuple; this is to
* support the GetTupleData function call.
*
* Note that if the data body of a tuple was not read from the CIS,
* then this function will return CS_NO_MORE_ITEMS.
*
* For flags that are set in the tuple_t->flags member, see the
* comments for the cis_list_lcreate function in the cis.c file.
* These flags are copied into the tuple_t->flags member by the
* cs_get_firstnext_tuple function call.
*
* See notes for the cs_get_firstnext_tuple function.
*/
static int
{
return (ret);
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
/*
* Check to be sure that we have a non-NULL pointer to
* a CIS list.
*/
return (CS_NO_MORE_ITEMS);
}
/*
* Since the tuple data buffer that the caller calls us with
* is preallocated in the tuple_t structure, we ignore any
* TupleDataMax value that the caller has setup and use the
* actual size of the tuple data buffer in the structure.
*/
/*
* Make sure the requested offset is not past the end of the
* tuple data body nor past the end of the user-supplied
* buffer.
*/
(int)tuple->TupleDataMax)) {
return (CS_NO_MORE_ITEMS);
}
(int)tuple->TupleOffset,
(int)tuple->TupleDataLen -
return (CS_BAD_ARGS);
}
/*
* The tuple data destination is always the tuple_t->TupleData
* buffer in the tuple_t structure no matter where we read the
* tuple data from.
*/
/*
* Do we have a copy of the tuple data? If not, we have to
* get a pointer to the CIS and read the tuple data from the
* card itself.
*/
case CISTPLF_LM_SPACE:
(unsigned)tuple->TupleOffset);
while (nbytes--)
break;
case CISTPLF_AM_SPACE:
case CISTPLF_CM_SPACE:
/*
* Setup the proper space flags as well as setup the
* address offset to point to the start of the tuple
* data area; we need to do the latter since the
* cis_store_cis_addr function in cis.c sets up the
* tuple->CISOffset->offset offset to point to the
* start of the tuple.
*/
} else {
}
flags) != CS_SUCCESS) {
"can't init CIS window\n",
sp->socket_num);
return (CS_GENERAL_FAILURE);
} /* cs_init_cis_window */
while (nbytes--) {
newoffset++;
} /* while */
break;
default:
return (CS_GENERAL_FAILURE);
} /* switch */
ret = CS_SUCCESS;
} else {
} /* if (CW_VALID_CIS) */
return (ret);
}
/*
* cs_validate_cis - validates the CIS on a card in the given socket; this
* is to support the ValidateCIS function call.
*
* Notes for regular PC card driver callers:
*
* Regular PC card drivers calling ValidateCIS will get the meaning of
* the structure members as specified in the standard.
*
* Notes for Socket Services, the "super-client" or CSI driver callers:
*
* with: Function Number = CS_GLOBAL_CIS
*
* For a single-function card, CS_NO_CIS will be returned and the
* cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
*
* For a multi-function card, cisinfo_t->Chains will contain a count of
* the number of CIS chains in the global portion of the CIS, and
* cisinfo_t->Tuples will contain a count of the number of tuples in
* the global portion of the CIS.
*
* with: 0 <= Function Number < CIS_MAX_FUNCTIONS
*
* For a single-function card, if the function number is equal to 0 and
* has a CIS, cisinfo_t->Chains will contain a count of the number of
* CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
* the number of tuples in the CIS. If the card does not have a CIS, or
* if the function number is not equal to 0, CS_NO_CIS will be returned
* and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
* to 0.
*
* For a multi-function card, cisinfo_t->Chains will contain a count of
* the number of CIS chains in the global and function-specific
* portions of the CIS, and cisinfo_t->Tuples will contain a count of
* the number of tuples in the global and function-specific portions of
* the CIS. If the function does not exist or has no CIS, CS_NO_CIS
* will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
* members will be set to 0.
*
* General notes:
*
* If the card does not have a CIS, or if the function does not exist
* or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
* and cisinfo_t->Tuples members will be set to 0.
*
* Most of the work of validating the CIS has already been done by the
* CIS parser module, so we don't have to do much here except for
* setup by the CIS parser.
*
* See notes for the cs_get_firstnext_tuple function.
*/
static int
{
int ret;
return (ret);
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
if ((fn != CS_GLOBAL_CIS) &&
} /* !CS_GLOBAL_CIS */
ret = CS_SUCCESS;
} else {
}
return (ret);
}
/*
* cs_init_cis_window - initializes the CIS window for the passed socket
*
* calling: *sp - pointer to the per-socket structure
* *offset - offset from start of AM or CM space
* *hp - pointer to acc_handle_t to store modified
* window access handle in
* flags - one of:
* CISTPLF_AM_SPACE - set window to AM space
* CISTPLF_CM_SPACE - set window to CM space
*
* returns: CS_SUCCESS if CIS window was set up
* *offset - contains adjusted offset to use to access
* requested space
* CS_BAD_WINDOW if CIS window could not be setup
* CS_GENERAL_FAILURE if socket has a CIS window number
* but the window flags are wrong
*
* Note: This function will check to be sure that there is a valid
* CIS window allocated to this socket.
* If there is an error in setting up the window hardware, the
* CIS window information for this socket is cleared.
* This function is also used by routines that need to get
* a pointer to the base of AM space to access the card's
* configuration registers.
* The passed offset is the un-window-size-aligned offset.
*/
int
{
/*
* Check to be sure that we have a valid CIS window
*/
if (!SOCKET_HAS_CIS_WINDOW(sp)) {
"cs_init_cis_window: socket %d has no CIS window\n",
sp->socket_num);
return (CS_BAD_WINDOW);
}
/*
* Check to be sure that this window is allocated for CIS use
*/
return (CS_BAD_WINDOW);
"cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
return (CS_BAD_WINDOW);
}
/*
* Get the characteristics of this window - we use this to
* determine whether we need to re-map the window or
* just move the window offset on the card.
*/
/*
* We've got a window, now set up the hardware. If we've got
* a variable sized window, then all we need to do is to
* get a valid mapping to the base of the window using
* the current window size; if we've got a fixed-size
* window, then we need to get a mapping to the window
* starting at offset zero of the window.
*/
sp->cis_win_size);
} else {
}
/*
* Return a normalized base offset; this takes care of the case
* where the required offset is greater than the window size.
* BugID 1236404
* code was:
* *offset = *offset & (set_page.offset - 1);
*/
#ifdef CS_DEBUG
if (cs_debug > 1)
"offset 0x%x\n",
(int)sw.WindowSize,
if (cs_debug > 1)
(int)*offset,
(flags & CISTPLF_AM_SPACE)?
"CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
#endif
/*
* The PCMCIA SS spec specifies this be expressed in
* a device speed format per 5.2.7.1.3 but
* our implementation of SS_SetWindow uses
* actual nanoseconds.
*/
/*
* Set up the window - if this fails, then just set the
* CIS window number back to it's initialized value so
* that we'll fail when we break out of the loop.
*/
return (CS_BAD_WINDOW);
} else {
if (flags & CISTPLF_AM_SPACE)
return (CS_BAD_WINDOW);
} /* if (SS_SetPage) */
} /* if (SS_SetWindow) */
/*
* Get the window information for the CIS window for this socket.
*/
return (CS_BAD_WINDOW);
return (CS_SUCCESS);
}
/*
* ==== client registration/deregistration section ====
*/
/*
* cs_register_client - This supports the RegisterClient call.
*
* Upon successful registration, the client_handle_t * handle argument will
* contain the new client handle and we return CS_SUCCESS.
*/
static int
{
int super_client = 0;
/*
* See if we're not supposed to register any new clients.
*/
return (CS_OUT_OF_RESOURCE);
/*
* Do a version check - if the client expects a later version of
* Card Services than what we are, return CS_BAD_VERSION.
* XXX - How do we specify just a PARTICULAR version of CS??
*/
return (CS_BAD_VERSION);
/*
* Check to be sure that the client has given us a valid set of
* client type flags. We also use this opportunity to see
* if the registering client is Socket Services or is a
* "super-client" or a CSI client.
*
* Note that SS can not set any flag in the Attributes field other
* than the INFO_SOCKET_SERVICES flag.
*
* Valid combinations of cr->Attributes and cr->EventMask flags:
*
* for Socket Services:
* cr->Attributes:
* set:
* INFO_SOCKET_SERVICES
* clear:
* {all other flags}
* cr->EventMask:
* don't care:
* {all flags}
*
* for regular clients:
* cr->Attributes:
* only one of:
* INFO_IO_CLIENT
* INFO_MTD_CLIENT
* INFO_MEM_CLIENT
* don't care:
* INFO_CARD_SHARE
* INFO_CARD_EXCL
* cr->EventMask:
* clear:
* CS_EVENT_ALL_CLIENTS
* don't care:
* {all other flags}
*
* for CSI clients:
* cr->Attributes:
* set:
* INFO_IO_CLIENT
* INFO_CSI_CLIENT
* clear:
* INFO_MTD_CLIENT
* INFO_MEM_CLIENT
* don't care:
* INFO_CARD_SHARE
* INFO_CARD_EXCL
* cr->EventMask:
* don't care:
* {all flags}
*
* for "super-clients":
* cr->Attributes:
* set:
* INFO_IO_CLIENT
* INFO_MTD_CLIENT
* INFO_SOCKET_SERVICES
* INFO_CARD_SHARE
* clear:
* INFO_MEM_CLIENT
* INFO_CARD_EXCL
* cr->EventMask:
* don't care:
* {all flags}
*/
/*
* Check first to see if this is Socket Services registering; if
* so, we don't do anything but return the client handle that is
* in the global SS client.
*/
case INFO_SOCKET_SERVICES:
return (CS_SUCCESS);
/* NOTREACHED */
/* CSI clients */
case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
break;
/* regular clients */
case INFO_IO_CLIENT:
case INFO_MTD_CLIENT:
case INFO_MEM_CLIENT:
return (CS_BAD_ATTRIBUTE);
break;
/* "super-client" clients */
return (CS_BAD_ATTRIBUTE);
/*
* We only allow one "super-client" per system.
*/
return (CS_NO_MORE_ITEMS);
}
break;
default:
return (CS_BAD_ATTRIBUTE);
} /* switch (cr->Attributes) */
/*
* Now, actually create the client node on the socket; this will
* also return the new client handle if there were no errors
* creating the client node.
* The DIP2SOCKET_NUM macro will return the socket and function
* number using the encoding specified in the cs_priv.h file.
*/
if (super_client != CLIENT_SUPER_CLIENT) {
else
} /* CLIENT_SUPER_CLIENT */
/*
* This registering client is a "super-client", so we create one
* client node for each socket in the system. We use the
* client_reg_t.priv structure member to point to a struct
* that the "super-client" client knows about. The client
* handle pointer is not used in this case.
* We return CS_SUCCESS if at least one client node could be
* created. The client must check the error codes in the
* error code array to determine which clients could not
* be created on which sockets.
* We return CS_BAD_HANDLE if no client nodes could be created.
*/
scr->num_clients = 0;
scr->num_clients++;
}
}
/*
* If we couldn't create any client nodes at all, then
* return an error.
*/
if (!scr->num_clients) {
/*
* XXX - The global superclient lock now gets
* cleared in cs_deregister_client
*/
/* cs_clear_superclient_lock(super_client); */
return (CS_BAD_HANDLE);
}
return (CS_SUCCESS);
}
/*
* cs_add_client_to_socket - this function creates the client node on the
* requested socket.
*
* Note that if we return an error, there is no state that can be cleaned
* up. The only way that we can return an error with allocated resources
* would be if one of the client handle functions had an internal error.
* Since we wouldn't get a valid client handle in this case anyway, there
* would be no way to find out what was allocated and what wasn't.
*/
static int
{
int client_lock_acquired;
return (CS_BAD_ARGS);
return (CS_BAD_SOCKET);
/*
* Run through all of the registered clients and compare the passed
* dip to the dip of each client to make sure that this client
* is not trying to register more than once. If they are, then
* display a message and return an error.
* XXX - we should really check all the sockets in case the client
* manipulates the instance number in the dip.
* XXX - if we check each socket, we ned to also check for the
* "super-client" since it will use the same dip for all
* of it's client nodes.
*/
while (client) {
"function 0x%x\n"
"\tclient already registered with "
"handle 0x%x\n",
(int)CS_GET_SOCKET_NUMBER(sn),
(int)CS_GET_FUNCTION_NUMBER(sn),
(int)client->client_handle);
return (CS_BAD_HANDLE);
}
} /* while (client) */
/*
* Create a unique client handle then make sure that we can find it.
* This has the side effect of getting us a pointer to the
* client structure as well.
* Create a client list entry - cs_create_client_handle will use this
* as the new client node.
* We do it here so that we can grab the sp->lock mutex for the
* duration of our manipulation of the client list.
* If this function fails, then it will not have added the newly
* allocated client node to the client list on this socket,
* so we have to free the node that we allocated.
*/
return (CS_OUT_OF_RESOURCE);
}
/*
* Make sure that this is a valid client handle. We should never
* fail this since we just got a valid client handle.
* If this fails, then we have an internal error so don't bother
* trying to clean up the allocated client handle since the
* whole system is probably hosed anyway and will shortly
* esplode.
* It doesn't make sense to call cs_deregister_client at this point
* to clean up this broken client since the deregistration
* code will also call cs_find_client and most likely fail.
*/
"invalid client handle created handle 0x%x\n",
(int)CS_GET_SOCKET_NUMBER(sn),
(int)CS_GET_FUNCTION_NUMBER(sn),
(int)*ch);
return (error);
}
/*
* Save the DDI information.
*/
KM_SLEEP);
/*
* Copy over the interesting items that the client gave us.
*/
sizeof (event_callback_args_t));
/*
* Set the client handle since the client needs a client handle
* when they call us for their event handler.
*/
/*
* Initialize the IO window numbers; if an IO window number is equal
* to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
*/
/*
* Give the client the iblock and idevice cookies to use in
* the client's event handler high priority mutex.
*/
/*
* Set up the global event mask information; we copy this directly
* from the client; since we are the only source of events,
* any bogus bits that the client puts in here won't matter
* because we'll never look at them.
*/
/*
* If this client registered as a CSI client, set the appropriate
* flag in the client's flags area.
*/
/*
* If this client registered as a "super-client" set the appropriate
* flag in the client's flags area.
*/
if (super_client == CLIENT_SUPER_CLIENT)
/*
* Save other misc information that this client gave us - it is
* used in the GetClientInfo function.
*/
/*
* Determine if we should give artificial card insertion events and
* a registration complete event. Since we don't differentiate
* between sharable and exclusive use cards when giving clients
* flags as follows:
*
* If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
* the client will receive artificial card insertion
* events (if the client's card is currently in the
* socket) and a registration complete event.
*
* If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
* set, the client will not receive an artificial card
* insertion event nor a registration complete event
* due to the client's call to register client.
*
* The client's event mask is not affected by the setting
* of these two bits.
*/
/*
* Check to see if the card for this client is currently in
* the socket. If it is, then set CLIENT_CARD_INSERTED
* since clients that are calling GetStatus at attach
* time will typically check to see if their card is
* currently installed.
* If this is the CSI client, we also need to check to see
* if there is any card inserted in the socket, since
* the cs_card_for_client function will always return
* TRUE for a CSI client.
* XXX What about super-clients?
*/
return (CS_BAD_SOCKET);
} /* SS_GetStatus */
cie = 0;
} /* CLIENT_CSI_CLIENT */
} /* cs_card_for_client */
sp->num_clients++;
return (CS_SUCCESS);
}
/*
* cs_deregister_client - This supports the DeregisterClient call.
*/
static int
{
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* Make sure that any resources allocated by this client are
* not still allocated, and that if this is an MTD that
* no MTD operations are still in progress.
*/
REQ_IRQ_DONE)) {
return (CS_BUSY);
}
return (CS_IN_USE);
}
/*
* Any previously allocated resources are not allocated anymore, and
* no MTD operations are in progress, so if this is an MTD client
* then do any MTD-specific client deregistration, and then
* nuke this client.
* We expect cs_deregister_mtd to never fail.
*/
(void) cs_deregister_mtd(client_handle);
/*
* If this was the "super-client" deregistering, then this
* will clear the global "super-client" lock.
* XXX - move this outside the per-socket code.
*/
return (error);
}
/*
* cs_create_next_client_minor - returns the next available client minor
* number or 0 if none available
*
* Note that cs_find_client will always return a valid pointer to the
* global Socket Services client which has a client minor number
* of 0; this means that this function can never return a 0 as the
* next valid available client minor number.
*/
unsigned
{
do {
next_minor), NULL)) {
return (next_minor);
}
next_minor++;
} while (max_client_handles--);
return (0);
}
/*
* cs_find_client - finds the client pointer associated with the client handle
* or NULL if client not found
*
* returns: (client_t *)NULL - if client not found or an error occured
* If the error argument is not NULL,
* it is set to:
* CS_BAD_SOCKET - socket number in client_handle_t is
* invalid
* CS_BAD_HANDLE - client not found
* If no error, the error argument is not modified.
* (client_t *) - pointer to client_t structure
*
* Note that each socket always has a pseudo client with a client minor number
* of 0; this client minor number is used for Socket Services access to
* Card Services functions. The client pointer returned for client minor
* number 0 is the global Socket Services client pointer.
*/
static client_t *
{
/*
* If we are being asked to see if a client with a minor number
* of 0 exists, always return a pointer to the global Socket
* Services client, since this client always exists, and is
* only for use by Socket Services. There is no socket
* associated with this special client handle.
*/
return (&cs_socket_services_client);
/*
* Check to be sure that the socket number is in range
*/
cs_globals.max_socket_num))) {
if (error)
*error = CS_BAD_SOCKET;
return (NULL);
}
if (error)
*error = CS_BAD_SOCKET;
return (NULL);
}
while (clp) {
return (clp);
}
if (error)
*error = CS_BAD_HANDLE;
return (NULL);
}
/*
* cs_destroy_client_handle - destroys client handle and client structure of
* passed client handle
*
* returns: CS_SUCCESS - if client handle sucessfully destroyed
* CS_BAD_HANDLE - if client handle is invalid or if trying
* to destroy global SS client
* {other errors} - other errors from cs_find_client()
*/
static int
{
/*
* See if we were passed a valid client handle or if we're being asked
* to destroy the Socket Services client
*/
return (error);
return (CS_BAD_SOCKET);
/*
* Recycle this client's minor number. This will most likely
* be the next client minor number we use, but it is also
* a hint to cs_create_client_handle, and that function
* may actually create a new client handle using a minor
* number different that this number.
*/
/*
* See if we're the first or not in the client list; if we're
* not first, then just adjust the client behind us to
* point to the client ahead of us; this could be NULL
* if we're the last client in the list.
*/
} else {
/*
* We are first, so adjust the client list head pointer
* in the socket to point to the client structure that
* follows us; this could turn out to be NULL if we're
* the only client on this socket.
*/
}
/*
* If we're not the last client in the list, point the next
* client to the client behind us; this could turn out
* to be NULL if we're the first client on this socket.
*/
sp->num_clients--;
/*
* Free this client's memory.
*/
return (CS_SUCCESS);
}
/*
* cs_create_client_handle - create a new client handle for the passed
* socket and function number
*
* returns: 0 - if can't create client for some reason
* client_handle_t - new client handle
*/
static client_handle_t
{
unsigned next_minor;
return (0);
/*
* Get the next available minor number that we can use. We use the
* next_cl_minor number as a hint to cs_create_next_client_minor
* and in most cases this will be the minor number we get back.
* If for some reason we can't get a minor number, return an error.
* The only way we could get an error would be if there are
* already the maximum number of clients for this socket. Since
* the maximum number of clients per socket is pretty large,
* this error is unlikely to occur.
*/
if (!(next_minor =
return (0);
/*
* Got a new client minor number, now create a new client handle.
*/
/*
* If this client handle exists, then we have an internal
* error; this should never happen, BTW. This is really
* a double-check on the cs_create_next_client_minor
* function, which also calls cs_find_client.
*/
"cs_create_client_handle: duplicate client handle 0x%x\n",
(int)client_handle);
return (0);
}
/*
* If we don't have any clients on this socket yet, create
* a new client and hang it on the socket client list.
*/
if (!sp->client_list) {
} else {
/*
* There are other clients on this socket, so look for
* the last client and add our new client after it.
*/
}
} /* if (!sp->client_list) */
/*
* Assign the new client handle to this new client structure.
*/
/*
* Create the next available client minor number for this socket
* and save it away.
*/
sp->next_cl_minor =
return (client_handle);
}
/*
* cs_clear_superclient_lock - clears the global "super-client" lock
*
* Note: this function uses the cs_globals.global_lock so observe proper
* nexting of locks!!
*/
static void
{
/*
* If this was a "super-client" registering then we need
* to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
* so that other "super-clients" can register.
*/
if (super_client == CLIENT_SUPER_CLIENT) {
}
}
/*
* ==== event handling section ====
*/
/*
* cs_event - CS event hi-priority callback handler
*
* This function gets called by SS and is passed the event type in
* the "event" argument, and the socket number in the "sn"
* argument. The "sn" argument is a valid logical socket
* number for all events except the PCE_SS_READY event.
*
* The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
* are never called at high priority. These events return
* the following return codes:
*
* CS_SUCCESS - operation sucessful
* CS_BAD_SOCKET - unable to complete operation
* CS_UNSUPPORTED_FUNCTION - bad subfunction of
* PCE_SS_INIT_STATE
*
* The caller MUST look at these return codes!
*
* This function is called at high-priority interrupt time for standard
* Card Services events, and the only standard Card Services
* event that it handles directly is the CS_EVENT_CARD_REMOVAL
* event, which gets shuttled right into the client's event
* handler. All other events are just queued up and the socket
* event thread is woken up via the soft interrupt handler.
* Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
* code is responsible for setting this event in a client's
* event field.
*
*/
/*ARGSUSED*/
{
/*
* Handle special SS<->CS events
*/
switch (event) {
case PCE_SS_INIT_STATE:
switch (sn) {
case PCE_SS_STATE_INIT:
break;
case PCE_SS_STATE_DEINIT:
break;
default:
"directive: 0x%x\n", sn);
break;
} /* switch (sn) */
return (ret);
case PCE_ADD_SOCKET:
return (cs_add_socket(sn));
case PCE_DROP_SOCKET:
return (cs_drop_socket(sn));
} /* switch (event) */
return (CS_BAD_SOCKET);
/*
* Check to see if CS wants to unload - we do this since it's possible
* to disable certain sockets. Do NOT acquire any locks yet.
*/
if (event == PCE_CARD_INSERT)
"remove card\n", sn);
return (CS_SUCCESS);
}
#ifdef CS_DEBUG
if (cs_debug > 1) {
(void) cs_event2text(&event2text, 0);
}
#endif
/*
* Convert SS events to CS events; handle the PRR if necessary.
*/
/*
* We want to maintain the required event dispatching order as
* specified in the PCMCIA spec, so we cycle through all
* clients on this socket to make sure that they are
* notified in the correct order of any high-priority
* events.
*/
ct = &client_types[0];
while (ct) {
/*
* Point to the head of the client list for this socket, and go
* through each client to set up the client events as well as
* call the client's event handler directly if we have a high
* priority event that we need to tell the client about.
*/
while (client) {
}
}
while (client) {
#ifdef CS_DEBUG
if (cs_debug > 1) {
"events 0x%x flags 0x%x\n",
}
#endif
/*
* Handle the suspend and card removal events
* specially here so that the client can receive
* these events at high-priority.
*/
} /* if (CLIENT_CARD_INSERTED) */
} /* if (CS_EVENT_PM_SUSPEND) */
/*
* Check to see if the client wants low priority
* removal events as well.
*/
}
} /* if (CLIENT_CARD_INSERTED) */
} /* if (CS_EVENT_CARD_REMOVAL) */
} /* if (ct->type) */
} else {
}
} /* while (client) */
} /* while (ct) */
/*
* Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
* handler will wakeup this socket's event thread.
*/
/*
* Fire off a soft interrupt that will cause the socket thread
* to be woken up and any remaining events to be sent to
* the clients on this socket.
*/
return (CS_SUCCESS);
}
/*
* cs_card_insertion - handle card insertion and card ready events
*
* We read the CIS, if present, and store it away, then tell SS that
* we have read the CIS and it's ready to be parsed. Since card
* insertion and card ready events are pretty closely intertwined,
* we handle both here. For card ready events that are not the
* result of a card insertion event, we expect that the caller has
* already done the appropriate processing and that we will not be
* called unless we received a card ready event right after a card
* insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
* sp->thread_state was set or if we get a CARD_READY event right
* after a CARD_INSERTION event.
*
* calling: sp - pointer to socket structure
* event - event to handle, one of:
* CS_EVENT_CARD_INSERTION
* CS_EVENT_CARD_READY
* CS_EVENT_SS_UPDATED
*/
static int
{
int ret;
/*
* Since we're only called while waiting for the card insertion
* and card ready sequence to occur, we may have a pending
* card ready timer that hasn't gone off yet if we got a
* real card ready event.
*/
#ifdef CS_DEBUG
if (cs_debug > 1) {
}
#endif
/*
* Handle card insertion processing
*/
if (event & CS_EVENT_CARD_INSERTION) {
/*
* Check to be sure that we have a valid CIS window
*/
if (!SOCKET_HAS_CIS_WINDOW(sp)) {
"cs_card_insertion: socket %d has no "
"CIS window\n",
sp->socket_num);
return (CS_GENERAL_FAILURE);
}
/*
* Apply power to the socket, enable card detect and card ready
* events, then reset the socket.
*/
set_socket.IREQRouting = 0;
"cs_card_insertion: socket %d SS_SetSocket failure %d\n",
return (ret);
}
/*
* Clear the ready and ready_timeout events since they are now
* bogus since we're about to reset the socket.
* XXX - should these be cleared right after the RESET??
*/
/*
* We are required by the PCMCIA spec to wait some number of
* milliseconds after reset before we access the card, so
* we set up a timer here that will wake us up and allow us
* to continue with our card initialization.
*/
#ifdef CS_DEBUG
if (cs_debug > 2) {
"for %d mS sp->events 0x%x\n",
}
#endif
/*
* If we have a pending CS_EVENT_CARD_REMOVAL event it
* means that we likely got CD line bounce on the
* insertion, so terminate this processing.
*/
#ifdef CS_DEBUG
if (cs_debug > 0) {
"CS_EVENT_CARD_REMOVAL event "
"terminating insertion "
"processing\n",
sp->socket_num);
}
#endif
return (CS_SUCCESS);
} /* if (CS_EVENT_CARD_REMOVAL) */
/*
* If we got a card ready event after the reset, then don't
* bother setting up a card ready timer, since we'll blast
* right on through to the card ready processing.
* Get the current card status to see if it's ready; if it
* is, we probably won't get a card ready event.
*/
"cs_card_insertion: socket %d SS_GetStatus failure %d\n",
return (ret);
}
#ifdef CS_DEBUG
if (cs_debug > 1) {
}
#endif
} else {
#ifdef CS_DEBUG
if (cs_debug > 1) {
}
#endif
} /* if (CS_EVENT_CARD_READY) */
} /* if (CS_EVENT_CARD_INSERTION) */
/*
* Handle card ready processing. This is only card ready processing
* for card ready events in conjunction with a card insertion.
*/
if (event == CS_EVENT_CARD_READY) {
/*
* The only events that we want to see now are card removal
* events.
*/
"cs_card_insertion: socket %d SS_GetSocket failed\n",
sp->socket_num);
return (CS_BAD_SOCKET);
}
/* XXX (is ~0 correct here?) to reset latched values */
set_socket.State = (unsigned)~0;
"cs_card_insertion: socket %d SS_SetSocket failed\n",
sp->socket_num);
return (CS_BAD_SOCKET);
}
/*
* Grab the cis_lock mutex to protect the CIS-to-be and
* the CIS window, then fire off the CIS parser to
* create a local copy of the card's CIS.
*/
return (ret);
}
/*
* If we have a pending CS_EVENT_CARD_REMOVAL event it
* means that we likely got CD line bounce on the
* insertion, so destroy the CIS and terminate this
* processing. We'll get called back to handle the
* insertion again later.
*/
(void) cs_destroy_cis(sp);
} else {
/*
* Schedule the call to the Socket Services work thread.
*/
} /* if (CS_EVENT_CARD_REMOVAL) */
} /* if (CS_EVENT_CARD_READY) */
/*
* Socket Services has parsed the CIS and has done any other
* work to get the client driver loaded and attached if
* necessary, so setup the per-client state.
*/
if (event == CS_EVENT_SS_UPDATED) {
/*
* Now that we and SS are done handling the card insertion
* semantics, go through each client on this socket and set
* the CS_EVENT_CARD_INSERTION event in each client's event
* field. We do this here instead of in cs_event so that
* when a client gets a CS_EVENT_CARD_INSERTION event, the
* card insertion and ready processing has already been done
* and SocketServices has had a chance to create a dip for
* the card in this socket.
*/
while (client) {
} /* while (client) */
} /* if (CS_EVENT_SS_UPDATED) */
return (CS_SUCCESS);
}
/*
* cs_card_removal - handle card removal events
*
* Destroy the CIS.
*
* calling: sp - pointer to socket structure
*
*/
static int
{
int ret;
#ifdef CS_DEBUG
if (cs_debug > 0) {
}
#endif
/*
* Remove any pending card ready timer
*/
/*
* Clear various flags so that everyone else knows that there's
* nothing on this socket anymore. Note that we clear the
* SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
* ss_to_cs_events event mapping function.
*/
/*
* Turn off socket power and set the socket back to memory mode.
* Disable all socket events except for CARD_INSERTION events.
*/
set_socket.IREQRouting = 0;
"cs_card_removal: socket %d SS_SetSocket failure %d\n",
return (ret);
}
#ifdef CS_DEBUG
if (cs_debug > 2) {
"calling cs_destroy_cis\n",
sp->socket_num);
}
#endif
/*
* Destroy the CIS and tell Socket Services that we're done
* handling the card removal event.
*/
(void) cs_destroy_cis(sp);
#ifdef CS_DEBUG
if (cs_debug > 2) {
}
#endif
return (CS_SUCCESS);
}
/*
* ss_to_cs_events - convert Socket Services events to Card Services event
* masks; this function will not read the PRR if the
* socket is in IO mode; this happens in cs_event_thread
*
* This function returns a bit mask of events.
*
* Note that we do some simple hysterious on card insertion and card removal
* events to prevent spurious insertion and removal events from being
* propogated down the chain.
*/
static event_t
{
switch (event) {
case PCE_CARD_STATUS_CHANGE:
break;
case PCE_CARD_REMOVAL:
/*
* If we're processing a removal event, it makes
* no sense to keep any insertion or ready events,
* so nuke them here. This will not clear any
* insertion events in the per-client event field.
*/
/*
* We also don't need to wait for READY anymore since
* it probably won't show up, or if it does, it will
* be a bogus READY event as the card is sliding out
* of the socket. Since we never do a cv_wait on the
* card ready timer, it's OK for that timer to either
* never go off (via an UNTIMEOUT in cs_card_removal)
* or to go off but not do a cv_broadcast (since the
* SOCKET_WAIT_FOR_READY flag is cleared here).
*/
}
break;
case PCE_CARD_INSERT:
}
break;
case PCE_CARD_READY:
break;
case PCE_CARD_BATTERY_WARN:
break;
case PCE_CARD_BATTERY_DEAD:
break;
case PCE_CARD_WRITE_PROTECT:
break;
case PCE_PM_RESUME:
break;
case PCE_PM_SUSPEND:
break;
default:
(int)event);
break;
} /* switch(event) */
return (revent);
}
/*
*
* Note that we really only expect one of the two events to be asserted when
* we are called. XXX - Perhaps this might be a problem later on??
*
* There is also the problem of cv_broadcast dropping the interrupt
* priority, even though we have our high-priority mutex held. If
* we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
* we get a high-priority interrupt during this time, the system will
* deadlock or panic. Thanks to Andy Banta for finding this out in
* the SPC/S (stc.c) driver.
*
* This callback routine can not grab the sp->client_lock mutex or deadlock
* will result.
*/
void
{
#ifdef CS_DEBUG
if (cs_debug > 1) {
sp->socket_num);
}
#endif
}
#ifdef CS_DEBUG
if (cs_debug > 1) {
}
#endif
}
if (cvp)
}
/*
* cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
*/
/* ARGSUSED */
void
{
/*
* If we're trying to unload this module, then don't do
* anything but exit.
* We acquire the cs_globals.global_lock mutex here so that
* we can correctly synchronize with cs_deinit when it
* is telling us to shut down. XXX - is this bogus??
*/
(void) cs_socket_event_softintr(NULL);
} else {
}
}
/*
* cs_socket_event_softintr - This function just does a cv_broadcast on behalf
* of the high-priority interrupt handler.
*
* Note: There is no calling argument.
*/
/*ARGSUSED*/
{
/*
* If the module is on it's way out, then don't bother
* to do anything else except return.
*/
/*
* Note that we return DDI_INTR_UNCLAIMED here
* since we don't want to be constantly
* called back.
*/
return (ret);
} else {
}
/*
* Go through each socket and dispatch the appropriate events.
* We have to funnel everything through this one routine because
* we can't do a cv_broadcast from a high level interrupt handler
* and we also can't have more than one soft interrupt handler
* on a single dip and using the same handler address.
*/
/*
* If we're being asked to unload CS, then don't bother
* waking up the socket event thread handler.
*/
} /* if (SOCKET_NEEDS_THREAD) */
} /* if (SOCKET_INIT_STATE_READY) */
} /* cs_get_sp */
} /* for (sn) */
return (ret);
}
/*
* cs_event_thread - This is the per-socket event thread.
*/
static void
{
return;
#ifdef CS_DEBUG
if (cs_debug > 1) {
sp->socket_num);
}
#endif
callb_generic_cpr, "cs_event_thread");
for (;;) {
/*
* Check to see if there are any special thread operations that
* we are being asked to perform.
*/
#ifdef CS_DEBUG
if (cs_debug > 1) {
"SOCKET_THREAD_EXIT\n",
sp->socket_num);
}
#endif
return;
} /* if (SOCKET_THREAD_EXIT) */
#ifdef CS_DEBUG
if (cs_debug > 1) {
sp->socket_num,
}
#endif
/*
* Handle CS_EVENT_CARD_INSERTION events
*/
/*
* If we have a pending CS_EVENT_CARD_REMOVAL event it
* means that we likely got CD line bounce on the
* insertion, so terminate this processing.
*/
}
#ifdef CS_DEBUG
else if (cs_debug > 0) {
"CS_EVENT_CARD_REMOVAL event "
"terminating "
"CS_EVENT_CARD_INSERTION "
}
#endif
} /* if (CS_EVENT_CARD_INSERTION) */
/*
* Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
*/
} /* if (SOCKET_WAIT_FOR_READY) */
} /* if (CS_EVENT_CARD_READY) */
/*
* Handle CS_EVENT_SS_UPDATED events
*/
} /* if (CS_EVENT_SS_UPDATED) */
/*
* Handle CS_EVENT_STATUS_CHANGE events
*/
/*
* Go through each client and add any events that we saw to
* the client's event list if the client has that event
* enabled in their event mask.
* Remove any events that may be pending for this client if
* the client's event mask says that the client doesn't
* want to see those events anymore. This handles the
* case where the client had an event enabled in it's
* event mask when the event came in but between that
* time and the time we're called here the client
* disabled that event.
*/
while (client) {
/*
* Read the PRR (if it exists) and check for any events.
* The PRR will only be read if the socket is in IO
* mode, if there is a card in the socket, and if there
* is a PRR.
* We don't have to clear revent before we call the
* cs_read_event_status function since it will
* clear it before adding any current events.
*/
(client->event_mask |
client->global_mask));
} /* CLIENT_CARD_INSERTED */
} /* while (client) */
} /* if (CS_EVENT_STATUS_CHANGE) */
/*
* We want to maintain the required event dispatching order as
* specified in the PCMCIA spec, so we cycle through all
* clients on this socket to make sure that they are
* notified in the correct order.
*/
ct = &client_types[0];
while (ct) {
/*
* Point to the head of the client list for this socket, and go
* through each client to set up the client events as well
* as call the client's event handler directly if we have
* a high priority event that we need to tell the client
* about.
*/
while (client) {
}
}
while (client) {
/*
* Clients always receive registration complete
* events, even if there is no card of
* their type currently in the socket.
*/
break;
/*
* The client only gets a card insertion event
* if there is currently a card in the
* socket that the client can control.
* The nexus determines this. We also
* prevent the client from receiving
* multiple CS_EVENT_CARD_INSERTION
* events without receiving intervening
* CS_EVENT_CARD_REMOVAL events.
*/
case CS_EVENT_CARD_INSERTION:
if (cs_card_for_client(client)) {
int send_insertion;
if (!(send_insertion &
} /* if (!CLIENT_SENT_INSERTION) */
}
break;
/*
* The CS_EVENT_CARD_REMOVAL_LOWP is a low
* priority CS_EVENT_CARD_REMOVAL event.
*/
break;
/*
* The hardware card removal events are handed
* to the client in cs_event at high
* priority interrupt time; this card
* removal event is a software-generated
* event.
*/
case CS_EVENT_CARD_REMOVAL:
}
break;
/*
* Write protect events require the info field
* of the client's event callback args to
* be zero if the card is not write
* protected and one if it is.
*/
case CS_EVENT_WRITE_PROTECT:
NULL,
&gs, 0);
(void *)
} else {
(void *)
}
} /* CLIENT_CARD_INSERTED */
break;
case CS_EVENT_CLIENT_INFO:
break;
case 0:
break;
default:
}
break;
} /* switch */
bit++;
} /* while (client->events) */
} /* if (ct->type) */
} else {
}
} /* while (client) */
} /* while (ct) */
/*
* Handle CS_EVENT_CARD_REMOVAL events
*/
(void) cs_card_removal(sp);
} /* if (CS_EVENT_CARD_REMOVAL) */
/*
* If someone is waiting for us to complete, signal them now.
*/
} /* SOCKET_WAIT_SYNC */
} /* for (;;) */
}
/*
* cs_card_for_client - checks to see if a card that the client can control
* is currently inserted in the socket. Socket Services
* has to tell us if this is the case.
*/
static int
{
/*
* If the client has set the CS_EVENT_ALL_CLIENTS it means that they
* want to get all events for all clients, irrespective of
* whether or not there is a card in the socket. Such clients
* have to be very careful if they touch the card hardware in
* any way to prevent causing problems for other clients on the
* same socket. This flag will typically only be set by the
* "super-client" or CSI types of clients that wish to get
* information on other clients or cards in the system.
* Note that the CS_EVENT_ALL_CLIENTS must be set in either the
* client's global event mask or client event mask.
* The client must also have registered as a "super-client" or as a
* CSI client for this socket.
*/
return (1);
/*
* Look for the PCM_DEV_ACTIVE property on this client's dip; if
* it's found, it means that this client can control the card
* that is currently in the socket. This is a boolean
* property managed by Socket Services.
*/
PCM_DEV_ACTIVE, NULL)) {
#ifdef CS_DEBUG
if (cs_debug > 1) {
"driver [%s] says %s found\n",
(int)client->client_handle,
}
#endif
return (1);
}
return (0);
}
/*
* cs_ss_thread - This is the Socket Services work thread. We fire off
* any calls to Socket Services here that we want
* to run on a thread that is seperate from the
* per-socket event thread.
*/
static void
{
return;
/*
* Tell CPR that we've started a new thread.
*/
callb_generic_cpr, "cs_ss_thread");
for (;;) {
/*
* Check to see if there are any special thread operations
* that we are being asked to perform.
*/
#ifdef CS_DEBUG
if (cs_debug > 1) {
"SOCKET_THREAD_EXIT\n",
sp->socket_num);
}
#endif
return;
} /* if (SOCKET_THREAD_EXIT) */
#ifdef CS_DEBUG
if (cs_debug > 1) {
"ss_thread_state = 0x%x\n",
(int)sp->socket_num,
(int)sp->ss_thread_state);
}
#endif
/*
* Call SocketServices(CSCISInit) to have SS parse the
*/
"card NOT inserted\n",
sp->socket_num);
}
#ifdef CS_DEBUG
if (cs_debug > 1) {
}
#endif
/*
* Tell SS that we have a complete CIS and that it can now
* be parsed.
* Note that in some cases the client driver may block in
* their attach routine, causing this call to block until
* the client completes their attach.
*/
/*
* Set the CS_EVENT_SS_UPDATED event for this socket so that the
* event thread can continue any card insertion processing
* that it has to do.
*/
/*
* Wake up this socket's event thread so that clients can
* continue any card insertion or attach processing
* that they need to do.
*/
} /* if ST_CSCISInit */
} /* for (;;) */
}
/*
* cs_request_socket_mask - set the client's event mask as well as causes
* any events pending from RegisterClient to
* be scheduled to be sent to the client
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If this client has already done a RequestSocketMask without
* a corresponding ReleaseSocketMask, then return an error.
*/
return (CS_IN_USE);
}
/*
* Set up the event mask information; we copy this directly from
* the client; since we are the only source of events, any
* bogus bits that the client puts in here won't matter
* because we'll never look at them.
*/
/*
* If RegisterClient left us some events to process, set these
* events up here.
*/
if (client->pending_events) {
client->pending_events = 0;
#ifdef CS_DEBUG
if (cs_debug > 1) {
"driver_name = [%s] events = 0x%x\n",
(int)client->client_handle,
}
#endif
}
/*
* Merge all the clients' event masks and set the socket
* to generate the appropriate events.
*/
/*
* Wakeup the event thread if there are any client events to process.
*/
#ifdef CS_DEBUG
if (cs_debug > 1) {
"client_handle = 0x%x "
"driver_name = [%s] events = 0x%x\n",
(int)client->client_handle,
}
#endif
}
return (CS_SUCCESS);
}
/*
* cs_release_socket_mask - clear the client's event mask
*
* Once this function returns, the client is guaranteed
* not to get any more event callbacks.
*/
/*ARGSUSED*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If this client has already done a RequestSocketMask without
* a corresponding ReleaseSocketMask, then return an error.
*/
return (CS_BAD_SOCKET);
}
/*
* Clear both the client event mask and the global event mask.
* We clear both since the semantics of this function are
* that once it returns, the client will not be called at
* it's event handler for any events until RequestSocketMask
* is called again.
*/
client->event_mask = 0;
client->global_mask = 0;
/*
* Merge all the clients' event masks and set the socket
* to generate the appropriate events.
*/
return (CS_SUCCESS);
}
/*
* cs_get_event_mask - return the event mask for this client
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
#ifdef XXX
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
* XXX - how can a client get their event masks if their card
* goes away?
*/
return (CS_NO_CARD);
}
#endif
/*
* We are only allowed to get the client event mask if a
* RequestSocketMask has been called previously. We
* are allowed to get the global event mask at any
* time.
* The global event mask is initially set by the client
* in the call to RegisterClient. The client event
* mask is set by the client in calls to SetEventMask
* and RequestSocketMask and gotten in calls to
* GetEventMask.
*/
return (CS_BAD_SOCKET);
}
} else {
}
return (CS_SUCCESS);
}
/*
* cs_set_event_mask - set the event mask for this client
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
#ifdef XXX
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
#endif
/*
* We are only allowed to set the client event mask if a
* RequestSocketMask has been called previously. We
* are allowed to set the global event mask at any
* time.
* The global event mask is initially set by the client
* in the call to RegisterClient. The client event
* mask is set by the client in calls to SetEventMask
* and RequestSocketMask and gotten in calls to
* GetEventMask.
*/
return (CS_BAD_SOCKET);
}
} else {
}
/*
* Merge all the clients' event masks and set the socket
* to generate the appropriate events.
*/
return (CS_SUCCESS);
}
/*
* cs_read_event_status - handles PRR events and returns card status
*
* calling: *sp - socket struct point
* *client - client to check events on
* *revent - pointer to event mask to update; if NULL, will
* not be updated, if non-NULL, will be updated
* with CS-format events; it is NOT necessary
* to clear this value before calling this
* function
* *gs - pointer to a get_ss_status_t used for the SS GetStatus
* call; it is not necessary to initialize any
* members in this structure; set to NULL if
* not used
* flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
* card present will not be done
*
* returns: CS_SUCCESS
* CS_NO_CARD - if no card is in the socket and the flags arg
* is not set to CS_RES_IGNORE_NO_CARD
* CS_BAD_SOCKET - if the SS_GetStatus function returned an
* error
*
* Note that if the client that configured this socket has told us that
* the READY pin in the PRR isn't valid and the socket is in IO
* mode, we always return that the card is READY.
*
* Note that if gs is not NULL, the current card state will be returned
* in the gs->CardState member; this will always reflect the
* current card state and the state will come from both the
* SS_GetStatus call and the PRR, whichever is appropriate for
* the mode that the socket is currently in.
*/
static int
{
/*
* SOCKET_IS_IO will only be set if a RequestConfiguration
* has been done by at least one client on this socket.
* If there isn't a card in the socket or the caller wants to ignore
* whether the card is in the socket or not, get the current
* card status.
*/
(flags & CS_RES_IGNORE_NO_CARD)) {
/*
* Get a handle to the CIS window
*/
CISTPLF_AM_SPACE) != CS_SUCCESS) {
"can't init CIS window\n",
sp->socket_num);
return (CS_GENERAL_FAILURE);
} /* cs_init_cis_window */
#ifdef CS_DEBUG
if (cs_debug > 1) {
"prrd 0x%x client->pin 0x%x\n",
(int)prrd,
((prrd & PRR_WP_STATUS)?
"PRR_WP_STATUS ":""),
((prrd & PRR_READY_STATUS)?
"PRR_READY_STATUS ":""),
((prrd & PRR_BVD2_STATUS)?
"PRR_BVD2_STATUS ":""),
((prrd & PRR_BVD1_STATUS)?
"PRR_BVD1_STATUS ":""),
((prrd & PRR_WP_EVENT)?
"PRR_WP_EVENT ":""),
((prrd & PRR_READY_EVENT)?
"PRR_READY_EVENT ":""),
((prrd & PRR_BVD2_EVENT)?
"PRR_BVD2_EVENT ":""),
((prrd & PRR_BVD1_EVENT)?
"PRR_BVD1_EVENT ":""));
}
#endif
/*
* The caller wants the event changes sent back and
* the PRR event change bits cleared.
*/
if (revent) {
/*
* Bug ID: 1193636 - Card Services sends bogus
* events on CS_EVENT_STATUS_CHANGE events
* Clear this before we OR-in any values.
*/
*revent = 0;
#ifdef CS_DEBUG
if (cs_debug > 1) {
((prrd & PRR_WP_STATUS)?
"PRR_WP_STATUS ":""),
((prrd & PRR_READY_STATUS)?
"PRR_READY_STATUS ":""),
((prrd & PRR_BVD2_STATUS)?
"PRR_BVD2_STATUS ":""),
((prrd & PRR_BVD1_STATUS)?
"PRR_BVD1_STATUS ":""),
((prrd & PRR_WP_EVENT)?
"PRR_WP_EVENT ":""),
((prrd & PRR_READY_EVENT)?
"PRR_READY_EVENT ":""),
((prrd & PRR_BVD2_EVENT)?
"PRR_BVD2_EVENT ":""),
((prrd & PRR_BVD1_EVENT)?
"PRR_BVD1_EVENT ":""));
}
#endif
if (prrd)
prrd);
/*
* We now have to reenable the status change interrupts
* if there are any valid bits in the PRR. Since
* the BVD1 signal becomes the STATUS_CHANGE
* signal when the socket is in IO mode, we just
* have to set the SBM_BVD1 enable bit in the
* event mask.
*/
} /* if (client->pin) */
} /* if (revent) */
} /* if (CONFIG_PINREPL_REG_PRESENT) */
} /* if (SOCKET_IS_IO) */
/*
* The caller wants the current card state; we just read
* it and return a copy of it but do not clear any of
* the event changed bits (if we're reading the PRR).
*/
if (gs) {
return (CS_BAD_SOCKET);
/*
* If the socket is in IO mode, then clear the
* gs->CardState bits that are now in the PRR
*/
SBM_BVD2 | SBM_RDYBSY);
/*
* Convert PRR status to SS_GetStatus status
*/
if (prrd & PRR_WP_STATUS)
if (prrd & PRR_BVD2_STATUS)
if (prrd & PRR_BVD1_STATUS)
/*
* If the client has indicated that there is no
* PRR or that the READY bit in the PRR isn't
* valid, then we simulate the READY bit by
* always returning READY.
*/
(PRR_READY_STATUS | PRR_READY_EVENT)) ==
(PRR_READY_STATUS | PRR_READY_EVENT))) ||
(prrd & PRR_READY_STATUS))
#ifdef CS_DEBUG
if (cs_debug > 1) {
"client->pin 0x%x "
"gs->CardState 0x%x\n",
}
#endif
} /* if (SOCKET_IS_IO) */
} /* if (gs) */
return (CS_SUCCESS);
} /* if (SOCKET_CARD_INSERTED) */
return (CS_NO_CARD);
}
/*
* cs_get_status - gets live card status and latched card status changes
* supports the GetStatus CS call
*
* returns: CS_SUCCESS
* CS_BAD_HANDLE if the passed client handle is invalid
*
* Note: This function resets the latched status values maintained
* by Socket Services
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't do anything except for return success.
*/
return (CS_SUCCESS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* Get the current card status as well as the latched card
* state. Set the CS_RES_IGNORE_NO_CARD so that even
* if there is no card in the socket we'll still get
* a valid status.
* Note that it is not necessary to initialize any values
* in the get_ss_status structure.
*/
CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
return (error);
}
/*
* Assign the "live" card state to the "real" card state. If there's
* no card in the socket or the card in the socket is not
* for this client, then we lie and tell the caller that the
* card is not inserted.
*/
return (CS_BAD_SOCKET);
/* XXX (is ~0 correct here?) reset latched values */
set_socket.State = (unsigned)~0;
return (CS_BAD_SOCKET);
return (CS_SUCCESS);
}
/*
* cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
*/
static event_t
{
/*
* XXX - we need to handle PM_CHANGE and RESET here as well
*/
if (event_mask & CS_EVENT_WRITE_PROTECT)
if (event_mask & CS_EVENT_BATTERY_DEAD)
if (event_mask & CS_EVENT_BATTERY_LOW)
if (event_mask & CS_EVENT_CARD_READY)
sbm_event |= SBM_RDYBSY;
if (event_mask & CS_EVENT_CARD_LOCK)
sbm_event |= SBM_LOCKED;
sbm_event |= SBM_INSERT;
return (sbm_event);
}
/*
* cs_sbm2cse - converts SBM_xxx state to CS event bits
*
* This function should never set any of the following bits:
*
* CS_EVENT_MTD_REQUEST
* CS_EVENT_CLIENT_INFO
* CS_EVENT_TIMER_EXPIRED
* CS_EVENT_CARD_REMOVAL
* CS_EVENT_CARD_REMOVAL_LOWP
* CS_EVENT_ALL_CLIENTS
* CS_EVENT_READY_TIMEOUT
*
* These bits are defined in the CS_STATUS_XXX series and are
* used by GetStatus.
*/
static uint32_t
{
/*
* XXX - we need to handle PM_CHANGE and RESET here as well
*/
if (state & SBM_RDYBSY)
if (state & SBM_LOCKED)
if (state & SBM_INSERT)
return (rstate);
}
/*
* cs_merge_event_masks - merge the CS global socket event mask with the
* passed client's event masks
*/
static unsigned
{
unsigned SCIntMask;
/*
* We always want to see card detect and status change events.
*/
sp->event_mask;
} else {
/*
* If the socket is in IO mode and there is a PRR present,
* then we may need to enable PCE_CARD_STATUS_CHANGE
* events.
*/
if (event_mask & CS_EVENT_WRITE_PROTECT)
if (event_mask & CS_EVENT_CARD_READY)
if (event_mask & CS_EVENT_BATTERY_LOW)
if (event_mask & CS_EVENT_BATTERY_DEAD)
} /* if (CONFIG_PINREPL_REG_PRESENT) */
} /* if (!SOCKET_IS_IO) */
return (SCIntMask);
}
/*
* cs_set_socket_event_mask - set the event mask for the socket
*/
static int
{
return (CS_BAD_SOCKET);
/* XXX (is ~0 correct here?) reset latched values */
set_socket.State = (unsigned)~0;
return (CS_BAD_SOCKET);
return (CS_SUCCESS);
}
/*
* ==== MTD handling section ====
*/
static int
{
(int)client_handle);
return (CS_SUCCESS);
}
/*
* ==== memory window handling section ====
*/
/*
* cs_request_window - searches through window list for the socket to find a
* memory window that matches the requested criteria;
* this is RequestWindow
*
* calling: cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
*
* On sucessful return, the window_handle_t * pointed to will
* contain a valid window handle for this window.
*
* returns: CS_SUCCESS - if window found
* CS_OUT_OF_RESOURCE - if no windows match requirements
* CS_BAD_HANDLE - client handle is invalid
* CS_BAD_SIZE - if requested size can not be met
* CS_BAD_WINDOW - if an internal error occured
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_NO_CARD - if no card is in socket
* CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
* flags are set
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Make sure that none of the unsupported flags are set.
*/
/* CS internal */
/* IO window flags */
/* CardBus flags */
return (CS_BAD_ATTRIBUTE);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* See if we can find a window that matches the caller's criteria.
* If we can't, then thre's not much more that we can do except
* for return an error.
*/
CS_SUCCESS) {
return (error);
}
/*
* We got a window, now synthesize a new window handle for this
* client and get a pointer to the global window structs
* and assign this window to this client.
* We don't have to check for errors from cs_create_window_handle
* since that function always returns a valid window handle
* if it is given a valid window number.
*/
return (CS_BAD_WINDOW);
}
mw.Attributes = (
rw->Attributes |
CS_SUCCESS) {
return (error);
}
/*
* Get any required card offset and pass it back to the client.
* This is not defined in the current PCMCIA spec. It is
* an aid to clients that want to use it to generate an
* optimum card offset.
*/
else
/*
* Increment the client's memory window count; this is how we know
* when a client has any allocated memory windows.
*/
client->memwin_count++;
return (CS_SUCCESS);
}
/*
* cs_release_window - deallocates the window associated with the passed
* window handle; this is ReleaseWindow
*
* returns: CS_SUCCESS if window handle is valid and window was
* sucessfully deallocated
* CS_BAD_HANDLE if window handle is invalid or if window
* handle is valid but window is not allocated
*/
static int
{
int error;
int client_lock_acquired;
return (CS_BAD_HANDLE);
}
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
}
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* Mark this window as not in use anymore.
*/
/*
* Decrement the client's memory window count; this is how we know
* when a client has any allocated memory windows.
*/
if (!(--(client->memwin_count)))
return (CS_SUCCESS);
}
/*
* cs_modify_window - modifies a window's characteristics; this is ModifyWindow
*/
static int
{
int error;
int client_lock_acquired;
/*
* Do some sanity checking - make sure that we can find a pointer
* to the window structure, and if we can, get the client that
* has allocated that window.
*/
return (CS_BAD_HANDLE);
}
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
return (error);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
mw->Attributes &= (
return (error);
}
return (CS_SUCCESS);
}
/*
* cs_modify_mem_window - modifies a window's characteristics; used internally
* by Card Services
*
* If *wr is NULL, it means that we're being called by ModifyWindow
* If *wr is non-NULL, it means that we are being called by RequestWindow
* and so we can't use SS_GetWindow.
*/
static int
{
/*
* If the win_req_t struct pointer is NULL, it means that
* we're being called by ModifyWindow, so get the
* current window characteristics.
*/
if (!wr) {
return (CS_BAD_WINDOW);
} else {
}
/*
* If we're being called by RequestWindow, we must always have
* WIN_ACCESS_SPEED_VALID set since get_window_t is not
* defined.
*/
return (CS_BAD_SPEED);
} else {
}
if (!wr) {
return (CS_BAD_WINDOW);
} else {
}
} else {
}
else
}
return (CS_BAD_WINDOW);
else
return (CS_BAD_OFFSET);
/*
* Return the current base address of this window
*/
if (wr) {
return (CS_BAD_WINDOW);
}
return (CS_SUCCESS);
}
/*
* cs_map_mem_page - sets the card offset of the mapped window
*/
static int
{
int error;
int client_lock_acquired;
/*
* We don't support paged windows, so never allow a page number
* of other than 0
*/
return (CS_BAD_PAGE);
/*
* Do some sanity checking - make sure that we can find a pointer
* to the window structure, and if we can, get the client that
* has allocated that window.
*/
return (CS_BAD_HANDLE);
}
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
return (error);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
else
return (CS_BAD_OFFSET);
}
return (CS_BAD_OFFSET);
}
return (CS_SUCCESS);
}
/*
* cs_find_window - finds the window associated with the passed window
* handle; if the window handle is invalid or no
* windows match the passed window handle, NULL
* is returned. Note that the window must be
* allocated for this function to return a valid
* window pointer.
*
* returns: cs_window_t * pointer to the found window
* NULL if window handle invalid or window not allocated
*/
{
return ((cs_window_t *)NULL);
return (NULL);
return (cw);
return ((cs_window_t *)NULL);
}
/*
* cs_create_window_handle - creates a unique window handle based on the
* passed window number.
*/
static window_handle_t
{
}
/*
* cs_find_mem_window - tries to find a memory window matching the caller's
* criteria
*
* We return the first window that matches the requested criteria.
*
* returns: CS_SUCCESS - if memory window found
* CS_OUT_OF_RESOURCE - if no windows match requirements
* CS_BAD_SIZE - if requested size can not be met
* CS_BAD_WINDOW - if an internal error occured
*/
/* BEGIN CSTYLED */
static int
{
iw = &inquire_window;
/*
* If we can't get a pointer to this window, we should contine
* with scanning the next window, since this window might have
* been dropped.
*/
return (CS_BAD_WINDOW);
CS_SUCCESS) {
error = CS_BAD_SIZE;
window_num = wn;
goto found_window;
} else {
if (!(MemWndCaps & WC_SIZE)) {
window_num = wn;
goto found_window;
}
} else { /* WC_SIZE */
if (!ReqGran) {
} else {
if (MemWndCaps & WC_POW2) {
window_num = wn;
goto found_window;
}
} /* for (tws) */
} else {
window_num = wn;
goto found_window;
}
} /* for (tws) */
} /* if (!WC_POW2) */
} /* if (Size >= MinSize) */
} /* if (!ReqGran) */
} /* if (WC_SIZE) */
} /* if (rw->Size) */
} /* if (cs_space_and_map_ok) */
} /* if (cs_valid_window_speed) */
} /* if (WINDOW_FOR_SOCKET) */
} /* if (cs_get_wp) */
} /* for (wn) */
/*
* If we got here and the window_num wasn't set by any window
* matches in the above code, it means that we didn't
* find a window matching the caller's criteria.
* If the error is CS_BAD_TYPE, it means that the last reason
* that we couldn't match a window was because the caller's
* requested speed was out of range of the last window that
* we checked. We convert this error code to CS_OUT_OF_RESOURCE
* to conform to the RequestWindow section of the PCMCIA
* Card Services spec.
*/
if (window_num == PCMCIA_MAX_WINDOWS) {
if (error == CS_BAD_TYPE)
return (error);
}
if (MemWndCaps & WC_CALIGN)
else
return (CS_SUCCESS);
}
/* END CSTYLED */
/*
* cs_memwin_space_and_map_ok - checks to see if the passed window mapping
* capabilities and window speeds are in the
* range of the passed window.
*
* returns: 0 - if the capabilities are out of range
* 1 - if the capabilities are in range
*/
static int
{
#ifdef CS_DEBUG
if (cs_debug > 240)
printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
"WndCaps 0x%x MemWndCaps 0x%x\n",
(int)rw->Attributes,
#endif
return (0);
}
return (0);
} else {
return (0);
}
return (0);
}
return (0);
}
return (1);
}
/*
* cs_valid_window_speed - checks to see if requested window speed
* is in range of passed window
*
* The inquire_window_t struct gives us speeds in nS, and we
* get speeds in the AccessSpeed variable as a devspeed code.
*
* returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
* CS_BAD_TYPE - if AccessSpeed is not in range of valid
* speed for this window
* CS_SUCCESS - if window speed is in range
*/
static int
{
cs = &convert_speed;
return (CS_BAD_SPEED);
return (CS_BAD_TYPE);
return (CS_SUCCESS);
}
/*
* ==== IO window handling section ====
*/
/*
* cs_request_io - provides IO resources for clients; this is RequestIO
*
* calling: cs_request_io(client_handle_t, io_req_t *)
*
* returns: CS_SUCCESS - if IO resources available for client
* CS_OUT_OF_RESOURCE - if no windows match requirements
* CS_BAD_HANDLE - client handle is invalid
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_NO_CARD - if no card is in socket
* CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
* flags are set
* CS_BAD_BASE - if either or both base port addresses
* are invalid or out of range
* CS_CONFIGURATION_LOCKED - a RequestConfiguration has
* already been done
* CS_IN_USE - IO ports already in use or function has
* already been called
* CS_BAD_WINDOW - if failure while trying to set window
* characteristics
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* If the client has only requested one IO range, then make sure
* that the Attributes2 filed is clear.
*/
ior->Attributes2 = 0;
/*
* Make sure that none of the unsupported or reserved flags are set.
*/
return (CS_BAD_ATTRIBUTE);
/*
* Make sure that we have a port count for the first region.
*/
return (CS_BAD_BASE);
/*
* If we're being asked for multiple IO ranges, then both base port
* members must be non-zero.
*/
return (CS_BAD_BASE);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has already been done, we don't allow
* this call.
*/
return (CS_CONFIGURATION_LOCKED);
}
/*
* If RequestIO has already been done, we don't allow this call.
*/
return (CS_IN_USE);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* If we're only being asked for one IO range, then set BasePort2 to
* zero, since we use it later on.
*/
/*
* See if we can allow Card Services to select the base address
* value for this card; if the client has specified a non-zero
* base IO address but the card doesn't decode enough IO
* address lines to uniquely use that address, then we have
* the flexibility to choose an alternative base address.
* Note that if the client specifies that the card decodes zero
* IO address lines, then we have to use the NumPortsX
* values to figure out how many address lines the card
* actually decodes, and we have to round the NumPortsX
* values up to the closest power of two.
*/
if (ior->IOAddrLines) {
ior->IOAddrLines);
ior->IOAddrLines);
} else {
}
#ifdef USE_IOMMAP_WINDOW
/*
* Here is where the code diverges, depending on the type of IO windows
* that this socket supports. If this socket supportes memory
* mapped IO windows, as determined by cs_init allocating an
* io_mmap_window_t structure on the socket structure, then we
* use one IO window for all the clients on this socket. We can
* do this safely since a memory mapped IO window implies that
* only this socket shares the complete IO space of the card.
* See the next major block of code for a description of what we do
* if a socket doesn't support memory mapped IO windows.
*/
if (sp->io_mmap_window) {
/*
* If we haven't allocated an IO window yet, do it now.
* Try to allocate the IO window that cs_init found for us;
* if that fails, then call cs_find_io_win to find a window.
*/
WC_8BIT |
WC_16BIT);
} /* cs_find_io_win */
} /* if (!WINDOW_AVAILABLE_FOR_IO) */
WS_EXACT_MAPIN | WS_IO);
/* XXX - what to d here? XXX */
return (CS_BAD_WINDOW);
}
/*
* Check the caller's port requirements to be sure that they
* fit within our found IO window.
*/
return (CS_BAD_BASE);
}
return (CS_BAD_WINDOW)
}
} /* if (!imw->count) */
/*
* All common access handles for this type of adapter are
* duped. We never give the original back to the caller.
*/
/* XXX need to set endianess and data ordering flags */
/* XXX need to set endianess and data ordering flags */
}
/*
* We don't really use these two values if we've got a memory
* mapped IO window since the assigned window number is stored
* in imw->number.
*/
/*
* This socket supports only IO port IO windows.
*/
} else {
#else /* USE_IOMMAP_WINDOW */
{
#endif /* USE_IOMMAP_WINDOW */
return (error);
} /* if (cs_allocate_io_win(1)) */
/*
* Setup the window hardware; if this fails, then we need to
* deallocate the previously allocated window.
*/
ior->Attributes1)) !=
CS_SUCCESS) {
(
return (error);
} /* if (cs_setup_io_win(1)) */
/*
* See if the client wants two IO ranges.
*/
/*
* If we fail to allocate this window, then we must deallocate
* the previous IO window that is already allocated.
*/
CS_SUCCESS) {
(void) cs_setup_io_win(socket_num,
(
return (error);
} /* if (cs_allocate_io_win(2)) */
/*
* Setup the window hardware; if this fails, then we need to
* deallocate the previously allocated window.
*/
ior->Attributes2)) !=
CS_SUCCESS) {
(void) cs_setup_io_win(socket_num,
(
(void) cs_setup_io_win(socket_num,
(
return (error);
} /* if (cs_setup_io_win(2)) */
} else {
} /* if (ior->NumPorts2) */
} /* if (sp->io_mmap_window) */
/*
* Save a copy of the client's port information so that we
* can use it in the RequestConfiguration call. We set
* the IO window number(s) allocated in the respective
* section of code, above.
*/
/*
* Mark this client as having done a successful RequestIO call.
*/
return (CS_SUCCESS);
}
/*
* cs_release_io - releases IO resources allocated by RequestIO; this is
* ReleaseIO
*
* calling: cs_release_io(client_handle_t, io_req_t *)
*
* returns: CS_SUCCESS - if IO resources sucessfully deallocated
* CS_BAD_HANDLE - client handle is invalid
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
* done without a ReleaseConfiguration
* CS_IN_USE - no RequestIO has been done
*/
static int
{
int error;
int client_lock_acquired;
#ifdef lint
#endif
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has already been done, we don't allow
* this call.
*/
return (CS_CONFIGURATION_LOCKED);
}
/*
* If RequestIO has not been done, we don't allow this call.
*/
return (CS_IN_USE);
}
#ifdef XXX
/*
* Check the passed IO allocation with the stored allocation; if
* they don't match, then return an error.
*/
return (CS_BAD_ARGS);
}
#endif
#ifdef USE_IOMMAP_WINDOW
/*
* The code diverges here depending on if this socket supports
* memory mapped IO windows or not. See comments in the
* cs_request_io function for a description of what's
* going on here.
*/
if (sp->io_mmap_window) {
/*
* We should never see this; if we do, it's an internal
* consistency error.
*/
sp->socket_num);
return (CS_GENERAL_FAILURE);
}
/*
* All common access handles for this type of adapter are
* duped. We never give the original back to the caller,
* so it's OK to unconditionally free the handle here.
*/
/*
* If the IO window referance count is zero, then deallocate
* and disable this window.
*/
(
} /* if (imw->count) */
} else {
#endif /* USE_IOMMAP_WINDOW */
(
(
#ifdef USE_IOMMAP_WINDOW
} /* if (sp->io_mmap_window) */
#endif /* USE_IOMMAP_WINDOW */
/*
* Mark the client as not having any IO resources allocated.
*/
return (CS_SUCCESS);
}
/*
* cs_find_io_win - finds an IO window that matches the parameters specified
* in the flags argument
*
* calling: sn - socket number to look for IO window on
* *iwc - other window characteristics to match
* *assigned_window - pointer to where we return the assigned
* window number if we found a window or
* undefined otherwise
* *size - if non-NULL, the found window size will be stored here
*
* returns: CS_SUCCESS - if IO window found
* CS_OUT_OF_RESOURCE - if no windows match requirements
*/
static int
{
unsigned wn;
iw = &inquire_window;
*assigned_window = wn;
if (size)
return (CS_SUCCESS);
} /* if (WINDOW_FOR_SOCKET) */
} /* cs_get_wp */
} /* for (wn) */
return (CS_OUT_OF_RESOURCE);
}
/*
* cs_allocate_io_win - finds and allocates an IO window
*
* calling: sn - socket number to look for window on
* Attributes - window attributes in io_req_t.Attributes format
* *assigned_window - pointer to return assigned window number
*
* returns: CS_SUCCESS - IO window found and allocated
* CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
* window that matches the passed criteria
*
* Note: This fucntion will find and allocate an IO window. The caller is
* responsible for deallocating the window.
*/
static int
{
CS_SUCCESS) {
return (CS_OUT_OF_RESOURCE);
return (CS_SUCCESS);
}
return (CS_OUT_OF_RESOURCE);
}
/*
* cs_setup_io_win - setup and destroy an IO window
*
* calling: sn - socket number
* wn - window number
* XXX Base - pointer to XXX
* *NumPorts - pointer to number of allocated ports to return
* IOAddrLines - number of IO address lines decoded by this card
* Attributes - either io_req_t attributes, or a combination of
* the following flags:
* IO_DEALLOCATE_WINDOW - deallocate the window
* IO_DISABLE_WINDOW - disable the window
* When either of these two flags are set, *Base
* and NumPorts should be NULL.
*
* returns: CS_SUCCESS - if no failure
* CS_BAD_WINDOW - if error while trying to configure window
*
* Note: We use the IOAddrLines value to determine what base address to pass
* to Socket Services.
*/
static int
{
if (Attributes & IO_DEALLOCATE_WINDOW) {
return (CS_BAD_WINDOW);
} /* IO_DEALLOCATE_WINDOW */
if (Attributes & IO_DISABLE_WINDOW) {
set_window.base = 0;
} /* IO_DISABLE_WINDOW */
return (CS_SUCCESS);
} /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
/*
* See if we can allow Socket Services to select the base address
* value for this card; if the client has specified a non-zero
* base IO address but the card doesn't decode enough IO
* address lines to uniquely use that address, then we have
* the flexibility to choose an alternative base address.
* XXX - Is this really correct in all cases?
*/
if (!IOAddrLines)
else
return (CS_BAD_WINDOW);
return (CS_SUCCESS);
}
/*
* ==== IRQ handling functions ====
*/
/*
* cs_request_irq - add's client's IRQ handler; supports RequestIRQ
*
* calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
* flag set, and all other flags clear, or
* CS_BAD_ATTRIBUTE will be returned
*
* returns: CS_SUCCESS - if IRQ resources available for client
* CS_BAD_IRQ - if IRQ can not be allocated
* CS_BAD_HANDLE - client handle is invalid
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_NO_CARD - if no card is in socket
* CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
* flags are set
* CS_CONFIGURATION_LOCKED - a RequestConfiguration has
* already been done
* CS_IN_USE - IRQ ports already in use or function has
* already been called
*
* Note: We only allow level-mode interrupts.
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Make sure that none of the unsupported or reserved flags are set.
*/
IRQ_FORCED_PULSE)) ||
return (CS_BAD_ATTRIBUTE);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has already been done, we don't allow
* this call.
*/
return (CS_CONFIGURATION_LOCKED);
}
/*
* If RequestIRQ has already been done, we don't allow this call.
*/
return (CS_IN_USE);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* Set up the parameters and ask Socket Services to give us an IRQ
* for this client. We don't really do much, since the IRQ
* resources are managed by SS and the kernel. We also don't
* care which IRQ level we are given.
*/
&set_irq_handler)) != SUCCESS) {
return (CS_BAD_IRQ);
}
/*
* Save the allocated IRQ information for this client.
*/
#ifdef CS_DEBUG
if (cs_debug > 0)
"set_irq_handler.irq 0x%x\n",
sp->socket_num,
(int)irqr->Attributes,
#endif
/*
* Mark this client as having done a successful RequestIRQ call.
*/
return (CS_SUCCESS);
}
/*
* cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
* ReleaseIRQ
*
* calling: cs_release_irq(client_handle_t, irq_req_t *)
*
* returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
* CS_BAD_IRQ - if IRQ can not be deallocated
* CS_BAD_HANDLE - client handle is invalid
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
* done without a ReleaseConfiguration
* CS_IN_USE - no RequestIRQ has been done
*/
static int
{
int error;
int client_lock_acquired;
#ifdef lint
#endif
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has already been done, we don't allow
* this call.
*/
return (CS_CONFIGURATION_LOCKED);
}
/*
* If RequestIRQ has not been done, we don't allow this call.
*/
return (CS_IN_USE);
}
/*
* Tell Socket Services that we want to deregister this client's
* IRQ handler.
*/
/*
* At this point, we should never fail this SS call; if we do, it
* means that there is an internal consistancy error in either
* Card Services or Socket Services.
*/
SUCCESS) {
return (CS_BAD_IRQ);
}
/*
* Mark the client as not having any IRQ resources allocated.
*/
return (CS_SUCCESS);
}
/*
* ==== configuration handling functions ====
*/
/*
* cs_request_configuration - sets up socket and card configuration on behalf
* of the client; this is RequestConfiguration
*
* returns: CS_SUCCESS - if configuration sucessfully set
* CS_BAD_SOCKET - if Socket Services returns an error
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
* are set
* CS_BAD_TYPE - if the socket doesn't support a mem and IO
* interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
* CS_CONFIGURATION_LOCKED - a RequestConfiguration has
* already been done
* CS_BAD_VCC - if Vcc value is not supported by socket
* CS_BAD_VPP1 - if Vpp1 value is not supported by socket
* CS_BAD_VPP2 - if Vpp2 value is not supported by socket
*
* Bug ID: 1193637 - Card Services RequestConfiguration does not conform
* to PCMCIA standard
* We allow clients to do a RequestConfiguration even if they haven't
* done a RequestIO or RequestIRQ.
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
#ifdef XXX
/*
* If the client specifies Vcc = 0 and any non-zero value for
* either of the Vpp members, that's an illegal condition.
*/
return (CS_BAD_VCC);
#endif
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* If the client is asking for a memory and IO interface on this
* socket, then check the socket capabilities to be sure that
* this socket supports this configuration.
*/
return (CS_BAD_SOCKET);
return (CS_BAD_TYPE);
} /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has already been done, we don't allow
* this call.
*/
return (CS_CONFIGURATION_LOCKED);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* At this point, most of the client's calling parameters have been
* validated, so we can go ahead and configure the socket and
* the card.
*/
/*
* Configure the socket with the interface type and voltages requested
* by the client.
*/
return (CS_BAD_SOCKET);
}
#ifdef CS_DEBUG
if (cs_debug > 0)
"client->irq_alloc.irq 0x%x "
"get_socket.IRQRouting 0x%x\n",
sp->socket_num,
#endif
return (CS_BAD_VCC);
}
return (CS_BAD_VPP);
}
return (CS_BAD_VPP);
}
else {
/*
* protect the CIS if the socket is in MEMORY mode and the
* will fail to be written. Go ahead and set the socket,
* even though the event mask isn't complete yet, so we can
* configure the adapter. Afterwards, set the socket again
* to make sure the event mask is correct.
*/
return (CS_BAD_SOCKET);
}
}
if (cs_rc2_delay)
/*
* Get a pointer to a window that contains the configuration
* registers.
*/
CISTPLF_AM_SPACE) != CS_SUCCESS) {
return (CS_GENERAL_FAILURE);
}
/*
* Setup the config register pointers.
* Note that these pointers are not the complete virtual address;
* the complete address is constructed each time the registers
* are accessed.
*/
/* Configuration Option Register */
/* Configuration and Status Register */
/* Pin Replacement Register */
/* Socket and Copy Register */
/* Extended Status Register */
/* IO Base 0 Register */
/* IO Base 1 Register */
/* IO Base 2 Register */
/* IO Base 3 Register */
/* IO Limit Register */
/*
* Setup the bits in the PRR mask that are valid; this is easy, just
* copy the Pin value that the client gave us. Note that for
* this to work, the client must set both of the XXX_STATUS
* and the XXX_EVENT bits in the Pin member.
*/
#ifdef CS_DEBUG
if (cs_debug > 128)
"client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
"ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
#endif
/*
* If the socket isn't in IO mode, WP is asserted, and we're going to
* write any of the config registers, issue a warning.
*/
"write CIS config regs with WP set\n");
}
/*
* Write any configuration registers that the client tells us are
* present to the card; save a copy of what we wrote so that we
* can return them if the client calls GetConfigurationInfo.
* The order in which we write the configuration registers is
* register first (if it exists), and then we can write the
* registers in any arbitrary order.
*/
/* Socket and Copy Register */
}
/* Pin Replacement Register */
}
/* Configuration and Status Register */
/* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
}
/* Extended Status Register */
}
/*
* If any IO base and limit registers exist, and this client
* has done a RequestIO, setup the IO Base and IO Limit
* registers.
*/
do {
} while (present);
} /* CONFIG_IOBASE0_REG_PRESENT */
int lm;
do_bit = 1;
if (do_bit)
} /* for */
} /* CONFIG_IOLIMIT_REG_PRESENT */
} /* REQ_IO_DONE */
/*
* Mark the socket as being in IO mode.
*/
/*
* Enable the interrupt if needed
*/
/*
* Now that we know if the PRR is present and if it is, which
* bits in the PRR are valid, we can construct the correct
* socket event mask.
*/
/*
* Configuration Option Register - we handle this specially since
* we don't allow the client to manipulate the RESET or
* INTERRUPT bits (although a client can manipulate these
* bits via an AccessConfigurationRegister call - explain
* THAT logic to me).
* XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
* XXX - we always enable the function on a multi-function card
*/
} /* CW_MULTI_FUNCTION_CIS */
#ifdef CS_DEBUG
if (cs_debug > 0)
"cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
"present=x%x cis_handle=%p cor_p=x%x\n",
#endif
} /* CONFIG_OPTION_REG_PRESENT */
if (cs_rc1_delay)
/*
* Set the socket to the parameters that the client requested.
*/
}
return (CS_BAD_SOCKET);
}
if (cs_rc2_delay)
/*
* Mark this client as having done a successful RequestConfiguration
* call.
*/
return (CS_SUCCESS);
}
/*
* cs_release_configuration - releases configuration previously set via the
* RequestConfiguration call; this is ReleaseConfiguration
*
* returns: CS_SUCCESS - if configuration sucessfully released
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_BAD_SOCKET - if Socket Services returns an error
* CS_BAD_HANDLE - a RequestConfiguration has not been done
*/
/*ARGSUSED*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has not been done, we don't allow
* this call.
*/
return (CS_BAD_HANDLE);
}
#ifdef CS_DEBUG
if (cs_debug > 0)
"flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
#endif
/*
* Set the card back to a memory-only interface byte writing a zero
* to the COR. Note that we don't update our soft copy of the
* COR state since the PCMCIA spec only requires us to maintain
* the last value that was written to that register during a
* call to RequestConfiguration.
*/
CISTPLF_AM_SPACE) != CS_SUCCESS) {
return (CS_GENERAL_FAILURE);
}
/*
* For the Multifunction cards do not reset the socket
* to a memory only interface but do clear the
* Configuration Option Register and mark this client
* as not having a configuration by clearing the
* REQ_CONFIGURATION_DONE flag.
*/
return (CS_SUCCESS);
}
/*
* Set the socket back to a memory-only interface; don't change
* any other parameter of the socket.
*/
return (CS_BAD_SOCKET);
}
set_socket.IREQRouting = 0;
return (CS_BAD_SOCKET);
}
/*
* Mark this client as not having a configuration.
*/
return (CS_SUCCESS);
}
/*
* cs_modify_configuration - modifies a configuration established by
* RequestConfiguration; this is ModifyConfiguration
*
* returns: CS_SUCCESS - if configuration sucessfully modified
* CS_BAD_SOCKET - if Socket Services returns an error
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_BAD_HANDLE - a RequestConfiguration has not been done
* CS_NO_CARD - if no card in socket
* CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
* are set
* CS_BAD_VCC - if Vcc value is not supported by socket
* CS_BAD_VPP1 - if Vpp1 value is not supported by socket
* CS_BAD_VPP2 - if Vpp2 value is not supported by socket
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If RequestConfiguration has not been done, we don't allow
* this call.
*/
return (CS_BAD_HANDLE);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* Get the current socket parameters so that we can modify them.
*/
return (CS_BAD_SOCKET);
}
#ifdef CS_DEBUG
if (cs_debug > 0)
"client->irq_alloc.irq 0x%x "
"get_socket.IRQRouting 0x%x\n",
#endif
/*
* Modify the IRQ routing if the client wants it modified.
*/
/*
* Get a pointer to a window that contains the configuration
* registers.
*/
CISTPLF_AM_SPACE) != CS_SUCCESS) {
"cs_modify_configuration: socket %d can't init "
return (CS_GENERAL_FAILURE);
} /* cs_init_cis_window */
#ifdef CS_DEBUG
if (cs_debug > 0)
" cor_p=0x%x cor=0x%x\n",
#endif
} /* CW_MULTI_FUNCTION_CIS */
} /* CONF_IRQ_CHANGE_VALID */
/*
* Modify the voltage levels that the client specifies.
*/
return (CS_BAD_VPP);
}
} else {
}
return (CS_BAD_VPP);
}
} else {
}
/*
* Setup the modified socket configuration.
*/
return (CS_BAD_SOCKET);
}
return (CS_SUCCESS);
}
/*
* cs_access_configuration_register - provides a client access to the card's
* configuration registers; this is AccessConfigurationRegister
*
* returns: CS_SUCCESS - if register accessed successfully
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
* CS_BAD_ARGS - if arguments are out of range
* CS_NO_CARD - if no card in socket
* CS_BAD_BASE - if no config registers base address
* CS_UNSUPPORTED_MODE - if no RequestConfiguration has
* been done yet
*/
static int
{
int error;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Make sure that the specifed offset is in range.
*/
return (CS_BAD_ARGS);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
/*
* If RequestConfiguration has not been done, we don't allow
* this call.
*/
return (CS_UNSUPPORTED_MODE);
}
/*
* Get a pointer to the CIS window
*/
CISTPLF_AM_SPACE) != CS_SUCCESS) {
sp->socket_num);
return (CS_GENERAL_FAILURE);
}
/*
* Create the address for the config register that the client
* wants to access.
*/
#ifdef CS_DEBUG
if (cs_debug > 1) {
"Offset 0x%x newoffset 0x%x\n",
(int)client->config_regs_offset,
}
#endif
/*
* Determine what the client wants us to do. The client is
* allowed to specify any valid offset, even if it would
* cause an unimplemented configuration register to be
* accessed.
*/
error = CS_SUCCESS;
case CONFIG_REG_READ:
break;
case CONFIG_REG_WRITE:
break;
default:
error = CS_BAD_ARGS;
break;
} /* switch */
return (error);
}
/*
* ==== RESET and general info functions ====
*/
/*
* cs_reset_function - RESET the requested function on the card; this
* is ResetFunction
*
* Note: We don't support this functionality yet, and the standard
* says it's OK to reutrn CS_IN_USE if we can't do this
* operation.
*/
/*ARGSUSED*/
static int
{
return (CS_IN_USE);
}
/*
* cs_get_configuration_info - return configuration info for the passed
* socket and function number to the caller;
* this is GetConfigurationInfo
*/
/*ARGSUSED*/
static int
{
int client_lock_acquired;
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
while (client) {
/*
* If there's no card in the socket or the card in the
* socket is not for this client, then return
* an error.
*/
return (CS_NO_CARD);
}
return (CS_SUCCESS);
} /* GET_CLIENT_FUNCTION == fn */
} /* while (client) */
return (CS_BAD_SOCKET);
}
/*
* cs_get_cardservices_info - return info about Card Services to the
* caller; this is GetCardServicesInfo
*/
/*ARGSUSED*/
static int
{
return (CS_SUCCESS);
}
/*
* cs_get_physical_adapter_info - returns information about the requested
* physical adapter; this is
* GetPhysicalAdapterInfo
*
* calling: client_handle_t:
* NULL - use map_log_socket_t->LogSocket member
* to specify logical socket number
* !NULL - extract logical socket number from
* client_handle_t
*
* returns: CS_SUCCESS
* CS_BAD_SOCKET - if client_handle_t is NULL and invalid
* socket number is specified in
* map_log_socket_t->LogSocket
* CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
* client handle is specified
*/
static int
{
int client_lock_acquired;
else
/*
* Determine if the passed socket number is valid or not.
*/
/*
* If we were passed a client handle, determine if it's valid or not.
*/
return (CS_BAD_HANDLE);
} /* cs_find_client */
} /* ch != NULL */
return (CS_SUCCESS);
}
/*
* ==== general functions ====
*/
/*
* cs_map_log_socket - returns the physical socket number associated with
* either the passed client handle or the passed
* logical socket number; this is MapLogSocket
*
* calling: client_handle_t:
* NULL - use map_log_socket_t->LogSocket member
* to specify logical socket number
* !NULL - extract logical socket number from
* client_handle_t
*
* returns: CS_SUCCESS
* CS_BAD_SOCKET - if client_handle_t is NULL and invalid
* socket number is specified in
* map_log_socket_t->LogSocket
* CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
* client handle is specified
*
* Note: We provide this function since the instance number of a client
* driver doesn't necessary correspond to the physical
* socket number
*/
static int
{
int client_lock_acquired;
else
/*
* Determine if the passed socket number is valid or not.
*/
/*
* If we were passed a client handle, determine if it's valid or not.
*/
return (CS_BAD_HANDLE);
} /* cs_find_client */
} /* ch != NULL */
return (CS_SUCCESS);
}
/*
* cs_convert_speed - convers nS to devspeed and devspeed to nS
*
* The actual function is is in the CIS parser module; this
* is only a wrapper.
*/
static int
{
}
/*
* cs_convert_size - converts a devsize value to a size in bytes value
* or a size in bytes value to a devsize value
*
* The actual function is is in the CIS parser module; this
* is only a wrapper.
*/
static int
{
}
/*
* cs_convert_powerlevel - converts a power level in tenths of a volt
* to a power table entry for the specified socket
*
* returns: CS_SUCCESS - if volts converted to a valid power level
* CS_BAD_ADAPTER - if SS_InquireAdapter fails
* CS_BAD_ARGS - if volts are not supported on this socket
* and adapter
*/
static int
{
int i;
#ifdef lint
if (sn == 0)
panic("lint panic");
#endif
*pl = 0;
return (CS_BAD_ADAPTER);
for (i = 0; (i < inquire_adapter.NumPower); i++) {
*pl = i;
return (CS_SUCCESS);
}
}
return (CS_BAD_ARGS);
}
/*
* cs_event2text - returns text string(s) associated with the event; this
* function supports the Event2Text CS call.
*
* calling: event2text_t * - pointer to event2text struct
* int event_source - specifies event type in event2text_t:
* 0 - SS event
* 1 - CS event
*
* returns: CS_SUCCESS
*/
static int
{
/*
* If event_source is 0, this is a SS event
*/
if (!event_source) {
return (CS_SUCCESS);
}
}
return (CS_SUCCESS);
} else {
/*
* This is a CS event
*/
} /* if (cs_ss_event_text) */
} /* for (event) */
} /* if (!event_source) */
return (CS_SUCCESS);
}
/*
* cs_error2text - returns a pointer to a text string containing the name
* of the passed Card Services function or return code
*
* This function supports the Error2Text CS call.
*/
static char *
{
int end_marker;
if (type == CSFUN2TEXT_FUNCTION) {
} else {
}
cfs++;
}
}
/*
* this is MakeDeviceNode and RemoveDeviceNode
*
* CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
* is REMOVAL_ALL_DEVICES
* CS_BAD_ARGS - if an invalid Action code is specified
* CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
*/
static int
{
int error, i;
int client_lock_acquired;
/*
* Check to see if this is the Socket Services client handle; if it
* is, we don't support SS using this call.
*/
return (CS_UNSUPPORTED_FUNCTION);
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
/*
* Make sure that this is a valid client handle.
*/
return (error);
}
#ifdef XXX
/*
* If there's no card in the socket or the card in the socket is not
* for this client, then return an error.
*/
return (CS_NO_CARD);
}
#endif
/*
* Setup the client's dip, since we use it later on.
*/
/*
* Make sure that we're being given a valid Action. Set the default
* error code as well.
*/
case CREATE_DEVICE_NODE:
case REMOVE_DEVICE_NODE:
break;
case REMOVAL_ALL_DEVICE_NODES:
if (mdn->NumDevNodes) {
} else {
error = CS_SUCCESS;
}
/* fall-through case */
default:
return (error);
/* NOTREACHED */
} /* switch */
/*
* Loop through the device node descriptions and create or destroy
* the device node.
*/
for (i = 0; i < mdn->NumDevNodes; i++) {
/*
* Set the appropriate flag for the action that we want
* SS to perform. Note that if we ever OR-in the flag
* here, we need to be sure to clear the flags member
* since we sometimes OR-in other flags below.
*/
} else {
}
/*
* If this is not the last device to process, then we need
* to tell SS that more device process requests are on
* their way after this one.
*/
return (CS_OUT_OF_RESOURCE);
} /* CSInitDev */
} /* for (mdn->NumDevNodes) */
return (CS_SUCCESS);
}
/*
* cs_remove_device_node - removes device nodes
*
* (see cs_make_device_node for a description of the calling
* and return parameters)
*/
static int
{
/*
* XXX - Note the assumption here that the make_device_node_t and
* remove_device_node_t structures are identical.
*/
}
/*
* cs_ddi_info - this function is used by clients that need to support
* the xxx_getinfo function; this is CS_DDI_Info
*/
static int
{
int client_lock_acquired;
return (CS_BAD_ATTRIBUTE);
#ifdef CS_DEBUG
if (cs_debug > 0) {
}
#endif
/*
* Check to see if the socket number is in range - the system
* framework may cause a client driver to call us with
* a socket number that used to be present but isn't
* anymore. This is not a bug, and it's OK to return
* an error if the socket number is out of range.
*/
#ifdef CS_DEBUG
if (cs_debug > 0) {
"SOCKET IS OUT OF RANGE\n",
cdi->driver_name);
}
#endif
return (CS_BAD_SOCKET);
} /* if (!CHECK_SOCKET_NUM) */
/*
* Get a pointer to this client's socket structure.
*/
return (CS_BAD_SOCKET);
while (client) {
#ifdef CS_DEBUG
if (cs_debug > 0) {
"handle 0x%x\n",
(int)client->client_handle);
}
#endif
#ifdef CS_DEBUG
if (cs_debug > 0) {
"instance %d handle 0x%x\n",
(int)client->client_handle);
}
#endif
return (CS_SUCCESS);
} /* strcmp */
} /* driver_name != NULL */
} /* while (client) */
return (CS_BAD_SOCKET);
}
/*
* cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
*/
static int
{
case CS_SYS_CTL_SEND_EVENT:
else
return (CS_BAD_SOCKET);
NULL) {
return (ret);
} /* cs_find_client */
/*
* Setup the events that we want to send to the client.
*/
} /* CS_SYS_CTL_EVENT_CLIENT */
} else {
} /* CS_SYS_CTL_WAIT_SYNC */
ret = CS_SUCCESS;
break;
default:
break;
} /* switch */
return (ret);
}
/*
* cs_get_sp - returns pointer to per-socket structure for passed
* socket number
*
* return: (cs_socket_t *) - pointer to socket structure
* NULL - invalid socket number passed in
*/
static cs_socket_t *
{
return (NULL);
return (NULL);
return (sp);
return (NULL);
}
/*
* cs_find_sp - searches socket list and returns pointer to passed socket
* number
*
* return: (cs_socket_t *) - pointer to socket structure if found
* NULL - socket not found
*/
static cs_socket_t *
{
while (sp) {
return (sp);
} /* while */
return (NULL);
}
/*
* cs_add_socket - add a socket
*
* call: sn - socket number to add
*
* return: CS_SUCCESS - operation sucessful
* CS_BAD_SOCKET - unable to add socket
* CS_BAD_WINDOW - unable to get CIS window for socket
*
* We get called here once for each socket that the framework wants to
* add. When we are called, the framework guarentees that until we
* complete this routine, no other adapter instances will be allowed
* to attach and thus no other PCE_ADD_SOCKET events will occur.
* It is safe to call SS_InquireAdapter to get the number of
* windows that the framework currently knows about.
*/
static uint32_t
{
return (CS_BAD_SOCKET);
/*
* See if this socket has already been added - if it has, we
* fail this. If we can't find the socket, then allocate
* a new socket structure. If we do find the socket, then
* check to see if it's already added; if it is, then
* this is an error and return CS_BAD_SOCKET; if not,
* then traverse the socket structure list and add this
* next socket strcture to the end of the list.
* XXX What about locking this list while we update it? Is
* that necessary since we're using the SOCKET_IS_VALID
* flag and since we never delete a socket from the
* list once it's been added?
*/
else
while (spp) {
break;
} /* if */
} /* while */
} else {
return (CS_BAD_SOCKET);
} /* cs_find_sp */
/*
* Setup the socket number
*/
/*
* Find out how many windows the framework knows about
* so far. If this number of windows is greater
* than our current window count, bump up our
* current window count.
* XXX Note that there is a BIG assumption here and that
* is that once the framework tells us that it has
* a window (as reflected in the NumWindows
* value) it can NEVER remove that window.
* When we really get the drop socket and drop
* window mechanism working correctly, we'll have
* to revisit this.
*/
if (added_windows > 0) {
return (CS_BAD_WINDOW);
} /* cs_add_windows */
} /* if (added_windows) */
/*
* Find a window that we can use for this socket's CIS window.
*/
(void) cs_convert_speed(&convert_speed);
"window - error 0x%x\n",
return (CS_BAD_WINDOW);
} /* cs_find_mem_window */
return (CS_BAD_WINDOW);
}
/*
* If the CIS window is a variable sized window, then use
* the size that cs_find_mem_window returned to us,
* since this will be the minimum size that we can
* set this window to. If the CIS window is a fixed
* sized window, then use the system pagesize as the
* CIS window size.
*/
} else {
}
#if defined(CS_DEBUG)
if (cs_debug > 1) {
(int)sp->cis_win_num,
(int)sp->cis_win_size);
}
#endif
/*
* Get the adapter information associated with this socket so
* that we can initialize the mutexes, condition variables,
* soft interrupt handler and per-socket adapter info.
*/
return (CS_BAD_SOCKET);
} /* CSGetCookiesAndDip */
/*
* Save the iblock and idev cookies for RegisterClient
*/
/*
* Setup the per-socket adapter info
*/
/* Setup for cs_event and cs_event_thread */
/* Setup for Socket Services work thread */
/* Setup for cs_event_thread */
/* Setup for Socket Services work thread */
/*
* If we haven't installed it yet, then install the soft interrupt
* handler and save away the softint id.
*/
&sp->softint_id,
return (CS_BAD_SOCKET);
} /* ddi_add_softintr */
/* XXX this timer is hokey at best... */
} else {
/*
* We've already added the soft interrupt handler, so just
* store away the softint id.
*/
} /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
/*
* While this next flag doesn't really describe a per-socket
* resource, we still set it for each socket. When the soft
* interrupt handler finally gets removed in cs_deinit, this
* flag will get cleared.
*/
/*
* Socket Services defaults all sockets to power off and
* clears all event masks. We want to receive at least
* card insertion events, so enable them. Turn off power
* to the socket as well. We will turn it on again when
* we get a card insertion event.
*/
set_socket.IREQRouting = 0;
return (CS_BAD_SOCKET);
} /* SS_SetSocket */
/*
* The various socket-specific variables are now set up, so
* increment the global socket count and also mark the
* socket as available. We need to set this before we
* start any of the per-socket threads so that the threads
* can get a valid socket pointer when they start.
*/
/*
* Create the per-socket event handler thread.
*/
/*
* Create the per-socket Socket Services work thread.
*/
return (CS_SUCCESS);
}
/*
* cs_drop_socket - drop a socket
*
* call: sn - socket number to drop
*
* return: CS_SUCCESS - operation sucessful
* CS_BAD_SOCKET - unable to drop socket
*/
/*ARGSUSED*/
static uint32_t
{
#ifdef XXX
/*
* Tell the socket event thread to exit and then wait for it
* to do so.
*/
/*
* Tell the socket SS thread to exit and then wait for it
* to do so.
*/
/*
* Mark the socket as dropped.
*/
#endif /* XXX */
/* XXX for now don't allow dropping sockets XXX */
return (CS_BAD_SOCKET);
}
/*
* cs_get_socket - returns the socket and function numbers and a pointer
* to the socket structure
*
* calling: client_handle_t client_handle - client handle to extract
* socket number from
* uint32_t *socket - pointer to socket number to use if
* client_handle is for the SS client;
* this value will be filled in on
* return with the correct socket
* and function numbers if we
* return CS_SUCCESS
* uint32_t *function - pointer to return function number into
* if not NULL
* cs_socket_t **sp - pointer to a pointer where a pointer
* to the socket struct will be
* placed if this is non-NULL
* client_t **clp - pointer to a pointer where a pointer
* to the client struct will be
* placed if this is non-NULL
*
* The socket and function numbers are derived as follows:
*
* Client Type Socket Number Function Number
* PC card client From client_handle From client_handle
* Socket Services client From *socket From *socket
* CSI client From client_handle From *socket
*/
static uint32_t
{
int ret;
/*
* If this is the Socket Services client, then return the
* socket and function numbers specified in the passed
* socket number parameter, otherwise extract the socket
* and function numbers from the client handle.
*/
if (CLIENT_HANDLE_IS_SS(client_handle)) {
} else {
}
/*
* Check to be sure that the socket number is in range
*/
return (CS_BAD_SOCKET);
return (CS_BAD_SOCKET);
/*
* If we were given a pointer, then fill it in with a pointer
* to this socket.
*/
if (csp)
/*
* Search for the client; if it's not found, return an error.
*/
return (ret);
}
/*
* If we're a CIS client, then extract the function number
* from the socket number.
*/
/*
* Return the found client pointer if the caller wants it.
*/
if (clp)
/*
* Return a socket number that is made up of the socket number
* and the function number.
*/
/*
* Return the function number if the caller wants it.
*/
if (function)
return (CS_SUCCESS);
}
/*
* cs_get_wp - returns pointer to passed window number
*
* return: (cs_window_t *) - pointer to window structure
* NULL - if invalid window number passed in
*/
static cs_window_t *
{
return (NULL);
return (NULL);
return (cw);
#ifdef CS_DEBUG
if (cs_debug > 0) {
}
#endif
return (NULL);
}
/*
* cs_find_wp - searches window list and returns pointer to passed window
* number
*
* return: (cs_window_t *) - pointer to window structure
* NULL - window not found
*/
static cs_window_t *
{
while (cw) {
return (cw);
} /* while */
#ifdef CS_DEBUG
if (cs_debug > 0) {
}
#endif
return (NULL);
}
/*
* cs_add_windows - adds number of windows specified in "aw" to
* the global window list; start the window
* numbering at "bn"
*
* return: CS_SUCCESS - if windows added sucessfully
* CS_BAD_WINDOW - if unable to add windows
*
* Note: The window list must be protected by a lock by the caller.
*/
static int
{
if (aw <= 0)
return (CS_BAD_WINDOW);
while (cwp) {
}
while (aw--) {
} else {
}
} /* while (aw) */
return (CS_SUCCESS);
}
/*
* cs_ss_init - initialize CS items that need to wait until we receive
* a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
*
* return: CS_SUCESS - if sucessfully initialized
* (various) if error initializing
*
* At this point, we expect that Socket Services has setup the
* following global variables for us:
*
* cs_socket_services - Socket Services entry point
* cis_parser - CIS parser entry point
*/
static uint32_t
{
/*
* Fill out the parameters for CISP_CIS_SETUP
*/
/*
* Call into the CIS module and tell it what the private
* Card Services entry point is. The CIS module will
* call us back at CardServices(CISRegister, ...)
* with the address of various CIS-specific global
* data structures.
*/
/*
* Register with the Card Services kernel stubs module
*/
"cs_stubs, retcode = 0x%x\n", ret);
return (ret);
} /* csx_register_cardservices */
return (CS_SUCCESS);
}
/*
* cs_create_cis - reads CIS on card in socket and creates CIS lists
*
* Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
* function.
*
* This function returns:
*
* CS_SUCCESS - if the CIS lists were created sucessfully
* CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
* not be setup
* CS_BAD_CIS - if error creating CIS chains
* CS_BAD_OFFSET - if the CIS parser tried to read past the
* boundries of the allocated CIS window
*/
static int
{
#ifdef CS_DEBUG
if (cs_debug > 0)
sp->socket_num);
} else if (ret != CS_SUCCESS) {
if (cs_debug > 0)
return (ret);
}
#else
if (ret != CS_SUCCESS)
return (ret);
#endif
/*
* If this card didn't have any CIS at all, there's not much
* else for us to do.
*/
return (CS_SUCCESS);
/*
* If this is a single-function card, we need to move the CIS list
* that is currently on CS_GLOBAL_CIS to the function zero
* CIS list.
*/
} /* !CW_MULTI_FUNCTION_CIS */
return (CS_SUCCESS);
}
/*
* cs_destroy_cis - destroys CIS list for socket
*/
static int
{
return (CS_SUCCESS);
}
/*
* cs_get_client_info - This function is GetClientInfo.
*
* calling: client_handle_t - client handle to get client info on
* client_info_t * - pointer to a client_info_t structure
* to return client information in
*
* returns: CS_SUCCESS - if client info retreived from client
* CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
* handle passed in
* CS_NO_MORE_ITEMS - if client does not handle the
* CS_EVENT_CLIENT_INFO event
* or if invalid client info
* retreived from client
*/
static int
{
if (CLIENT_HANDLE_IS_SS(client_handle)) {
return (CS_SUCCESS);
} /* CLIENT_HANDLE_IS_SS */
return (CS_BAD_SOCKET);
return (ret);
} /* cs_find_client */
/*
* If this client is not handling CS_EVENT_CLIENT_INFO events,
* then don't bother to even wake up the event thread.
*/
return (CS_NO_MORE_ITEMS);
} /* !CS_EVENT_CLIENT_INFO */
if (cs_card_for_client(client))
} else {
} /* CS_CLIENT_INFO_VALID */
return (ret);
}
/*
* cs_get_firstnext_client - This function is GetFirstClient and
* GetNextClient
*
* calling: get_firstnext_client_t * - pointer to a get_firstnext_client_t
* structure to return client handle and
* attributes in
* flags - one of the following:
* CS_GET_FIRST_FLAG - get first client handle
* CS_GET_NEXT_FLAG - get next client handle
*
* returns: CS_SUCCESS - if client info retreived from client
* CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
* handle passed in
* CS_NO_MORE_ITEMS - if client does not handle the
* CS_EVENT_CLIENT_INFO event
* or if invalid client info
* retreived from client
*/
static int
{
switch (flags) {
case CS_GET_FIRST_FLAG:
break;
} /* if */
sn++;
} /* while */
return (CS_NO_MORE_ITEMS);
} else if (fnc->Attributes &
NULL)
return (CS_BAD_SOCKET);
return (CS_NO_MORE_ITEMS);
}
} else {
return (CS_BAD_ATTRIBUTE);
}
break;
case CS_GET_NEXT_FLAG:
return (CS_BAD_SOCKET);
return (ret);
}
sn++;
break;
} /* if */
sn++;
} /* while */
return (CS_NO_MORE_ITEMS);
} /* client = client->next */
} else if (fnc->Attributes &
return (CS_BAD_SOCKET);
return (ret);
}
return (CS_NO_MORE_ITEMS);
}
} else {
return (CS_BAD_ATTRIBUTE);
}
break;
default:
break;
} /* switch */
return (ret);
}
/*
* cs_set_acc_attributes - converts Card Services endianness and
* data ordering values to values
* that Socket Services understands
*
* calling: *sw - pointer to a set_window_t to set attributes in
* Attributes - CS attributes
*/
static void
{
switch (Attributes & WIN_ACC_ENDIAN_MASK) {
case WIN_ACC_LITTLE_ENDIAN:
break;
case WIN_ACC_BIG_ENDIAN:
break;
case WIN_ACC_NEVER_SWAP:
default:
break;
} /* switch */
switch (Attributes & WIN_ACC_ORDER_MASK) {
case WIN_ACC_UNORDERED_OK:
break;
case WIN_ACC_MERGING_OK:
break;
case WIN_ACC_LOADCACHING_OK:
break;
case WIN_ACC_STORECACHING_OK:
break;
case WIN_ACC_STRICT_ORDER:
default:
break;
} /* switch */
}