<!doctype linuxdoc system>

<article>
<title>Linux PCMCIA Programmers Guide
<author>David Hinds, <tt/dhinds@allegro.stanford.edu/
<date>v1.10, 1995/02/08 17:51:54
<abstract>
This document describes how to write kernel device drivers for the
Linux PCMCIA Card Services interface.  It also describes how to write
user-mode utilities for communicating with Card Services.  The latest
version of this document can always be found at
<tt/cb-iris.stanford.edu/ in <tt>/pub/pcmcia/doc</tt>.
</abstract>

<toc>

<!-- ================================================================= -->

<sect>Introduction
<p>
The Linux kernel PCMCIA system has three main components.  At the
lowest level are the socket drivers.  Next is the Card Services
module.  Drivers for specific cards are layered on top of Card
Services.  One special Card Services client, called Driver Services,
provides a link betweek user level PCMCIA utility programs and the
kernel PCMCIA facilities.

The socket driver layer is loosely based on the Socket Services API.
There are two socket driver modules.  The <tt/tcic/ module supports
the Databook TCIC-2 family of PCMCIA controllers.  The <tt/i82365/
module supports the Intel i82365sl family and various Intel-compatible
controllers, including Cirrus, VLSI, and Vadem chips.

Card Services is the largest single component of the PCMCIA package.
It provides an API somewhat similar to DOS Card Services, adapted to a
Unix environment.  The Linux implementation was based in part on the
Solaris PCMCIA interface specification.  It is implemented in the
<tt/pcmcia_core/ module.

The Driver Services layer implements a user mode pseudo-device for
accessing some Card Services functions from PCMCIA utility programs.
It is responsible for keeping track of all PCMCIA client drivers, and
for matching up drivers with physical sockets.  It is implemented in
the <tt/ds/ module.

This document describes the kernel interface to the Card Services and
Driver Services modules, and the user interface to Driver Services.
It is intended for use by PCMCIA device driver developers.  The Linux
PCMCIA-HOWTO describes how to install and use Linux PCMCIA support.
It is available from <tt/cb-iris.stanford.edu/ in
<tt>/pub/pcmcia</tt>.

<!-- ================================================================= -->

<sect1>Copyright notice and disclaimer
<p>
Copyright (c) 1995 David A. Hinds

This document may be reproduced or distributed in any form without my
prior permission.  Parts of this document may be distributed, provided
that this copyright message and a pointer to the complete document are
included.  Specifically, it may be included in commercial
distributions without my prior consent.  However, I would like to be
informed of such usage.

This document may be translated into any language, provided this
copyright statement is left intact.

This document is provided ``as is'', with no explicit or implied
warranties.  Use the information in this document at your own risk.

<!-- ================================================================= -->

<sect>Card Services subfunction descriptions

<p>
Card Services calls have the general form:

<tscreen><verb>
#include "cs_types.h"
#include "cs.h"

int CardServices(int subfunc, void *arg1, void *arg2, ...);
</verb></tscreen>

Some Card Services functions require additional <tt/#include/
statements.  The particular subfunction determines the number of
expected arguments.  A return code of <tt/CS_SUCCESS/ indicates that a
call succeeded.  Other return codes indicate errors.

<!-- ================================================================= -->

<sect1>Client management functions
<p>
Device drivers that use Card Services functions are called
``clients''.  A device driver should use the <tt/RegisterClient/ call
to get a client handle before using other services.  Most Card
Services functions will take this client handle as an argument.
Before unloading, drivers should also unregister with
<tt/DeregisterClient/.

<!-- ================================================================= -->

<sect2>RegisterClient
<p>
<tscreen><verb>
int CardServices(RegisterClient, client_handle_t *client, client_reg_t *reg);
</verb></tscreen>
The <tt/client_reg_t/ data structure is given by:
<tscreen><verb>
typedef struct client_reg_t {
	dev_info_t		*dev_info;
	u_long			Attributes;
	u_long			EventMask;
	int			(*event_handler)(event_t event, int priority,
						 event_callback_args_t *args);
	event_callback_args_t	event_callback_args;
	u_long			Version;
} client_reg_t;
</verb></tscreen>

<tt/RegisterClient/ establishes a link between a client driver and
Card Services, and connects the client with an appropriate socket.
The <tt/dev_info/ parameter is used by Card Services to match the
client with a socket, following a call to <tt/BindDevice/.  If
successful, a client handle will be returned in <tt/client/.

<tt/EventMask/ specifies what events this client should be notified
of.  The <tt/event_handler/ entry point will be called by Card
Services when an event in <tt/EventMask/ is processed.  The
<tt/event_handler_args/ structure is a template for the structure that
will be passed to the event handler.  The <tt/Version/ parameter
identifies the Card Services version level that this driver expects;
it is currently ignored.

A driver should be prepared to handle Card Services events when it
calls <tt/RegisterClient/.  This call will always generate a
<tt/CS_REGISTRATION_COMPLETE/ event, and may also generate an
artificial <tt/CS_CARD_INSERTION/ event if the socket is currently
occupied.

Return codes:
<descrip>
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
An appropriate socket could not be found for this driver.
</descrip>

<!-- ================================================================= -->

<sect2>DeregisterClient
<p>
<tscreen><verb>
int CardServices(DeregisterClient, client_handle_t client);
</verb></tscreen>

<tt/DeregisterClient/ severs the connection between a client and Card
Services.  It should be called after the client has freed any
resources it has allocated.  Once a connection is broken, it cannot be
reestablished until after another call to <tt/BindDevice/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_IN_USE/</tag>
The client still has allocated resources, such as IO port windows or
an interrupt, or the socket configuration is locked.
</descrip>

<!-- ================================================================= -->

<sect2>SetEventMask
<p>
<tscreen><verb>
int CardServices(SetEventMask, client_handle_t client, eventmask_t *mask);
</verb></tscreen>
The <tt/eventmask_t/ structure is given by:
<tscreen><verb>
typedef struct eventmask_t {
	u_long		Attributes;
	u_long		EventMask;
} eventmask_t;
</verb></tscreen>

<tt/SetEventMask/ updates the mask that determines which events this
client will be notified of.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
</descrip>

<!-- ================================================================= -->

<sect2>BindDevice
<p>
<tscreen><verb>
int CardServices(BindDevice, bind_req_t *req);
</verb></tscreen>
The <tt/bind_req/ structure is given by:
<tscreen><verb>
typedef struct bind_req_t {
	socket_t	Socket;
	dev_info_t	*dev_info;
} bind_req_t;
</verb></tscreen>

<tt/BindDevice/ associates a device driver with a particular socket.
It is normally called by Driver Services after a newly inserted card
has been identified.  Once a driver has been bound to a socket, it
will be eligible to register as a client of that socket.  Note that
this call does not take a client handle as an argument.  This is the
only Card Services call that takes a socket number as an argument.

Return codes:
<descrip>
<tag><tt/CS_BAD_SOCKET/</tag>
The specified socket number is invalid.
</descrip>

<!-- ================================================================= -->

<sect1>Socket state control
<p>

These functions are more or less concerned with getting and setting
the current operating state of a socket.  <tt/GetStatus/ returns the
current socket state.  <tt/ResetCard/ is used to send a hard reset
signal to a socket.  <tt/SuspendCard/ and <tt/ResumeCard/ can be used
to power down and power up a socket without releasing the drivers
currently bound to that socket.  <tt/EjectCard/ and <tt/InsertCard/
essentially mimic real card ejection and insertion events.

<!-- ================================================================= -->

<sect2>GetStatus
<p>
<tscreen><verb>
int CardServices(GetStatus, client_handle_t client, status_t *status);
</verb></tscreen>
The <tt/status_t/ data structure is given by:
<tscreen><verb>
typedef struct status_t {
	u_long		CardState;
	u_long		SocketState;
} status_t;
</verb></tscreen>

<tt/GetStatus/ returns the current status of a client's socket.  The
following flags are defined in <tt/CardState/:

<descrip>
<tag><tt/CS_EVENT_CARD_DETECT/</tag>
Specifies that the socket is occupied.
<tag><tt/CS_EVENT_WRITE_PROTECT/</tag>
Specifies that the card is currently write protected.
<tag><tt/CS_EVENT_BATTERY_LOW/</tag>
Specifies that the card battery is low.
<tag><tt/CS_EVENT_BATTERY_DEAD/</tag>
Specifies that the card battery is dead.
<tag><tt/CS_EVENT_READY_CHANGE/</tag>
Specifies that the card is ready.
<tag><tt/CS_EVENT_PM_SUSPEND/</tag>
Specifies that the socket is suspended.
</descrip>

<tt/SocketState/ is currently unused, but in theory, it should latch
changes in the state of the fields in <tt/CardState/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
</descrip>

<!-- ================================================================= -->

<sect2>ResetCard
<p>
<tscreen><verb>
int CardServices(ResetCard, client_handle_t client);
</verb></tscreen>

<tt/ResetCard/ requests that a client's socket be reset.  When this
call is made, Card Services sends all clients a
<tt/CS_EVENT_RESET_REQUEST/ event.  If any client rejects the request,
Card Services sends the initiating client a
<tt/CS_EVENT_RESET_COMPLETE/ event with <tt/event_callback_args.info/
set to the return code of the client that rejected the request.

If all clients agree to the request, Card Services sends a
<tt/CS_EVENT_RESET_PHYSICAL/ event, then resets the socket.  When the
socket signals that it is ready, a <tt/CS_EVENT_CARD_RESET/ event is
generated.  Finally, a <tt/CS_EVENT_RESET_COMPLETE/ event is sent to the
initiating client, with <tt/event_callback_args.info/ set to zero.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
This socket is currently being reset.
</descrip>

<!-- ================================================================= -->

<sect2>SuspendCard
<p>
<tscreen><verb>
int CardServices(SuspendCard, client_handle_t client);
</verb></tscreen>

Card Services sends all clients <tt/CS_EVENT_PM_SUSPEND/ events, then
shuts down and turns off power to the socket.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
This socket is already suspended.
</descrip>

<!-- ================================================================= -->

<sect2>ResumeCard
<p>
<tscreen><verb>
int CardServices(ResumeCard, client_handle_t client);
</verb></tscreen>

After restoring power to the socket, Card Services will notify all
clients with <tt/CS_EVENT_PM_RESUME/ events.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
This socket is not currently suspended.
</descrip>

<!-- ================================================================= -->

<sect2>EjectCard
<p>
<tscreen><verb>
int CardServices(EjectCard, client_handle_t client);
</verb></tscreen>

Card Services sends eject events to all clients, then shuts down and
turns off power to the socket.  All clients except for Driver Services
will be unlinked from the socket.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
</descrip>

<!-- ================================================================= -->

<sect2>InsertCard
<p>
<tscreen><verb>
int CardServices(InsertCard, client_handle_t client);
</verb></tscreen>

Card Services sends insertion events to all clients of this socket
(normally, only Driver Services).

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
The socket has already been configured.
</descrip>

<!-- ================================================================= -->

<sect1>IO card configuration calls
<p>

The normal order of events is for a driver to reserve IO ports and an
interrupt line with calls to <tt/RequestIO/ and <tt/RequestIRQ/, then
to call <tt/RequestConfiguration/ to actually configure the socket.
If any of these calls fails, a driver should be sure to release any
resources it successfully reserved.

<!-- ================================================================= -->

<sect2>RequestIO
<p>
<tscreen><verb>
int CardServices(RequestIO, client_handle_t client, io_req_t *req);
</verb></tscreen>
The <tt/io_req_t/ data structure is given by:
<tscreen><verb>
typedef struct io_req_t {
	ioaddr_t	BasePort1;
	ioaddr_t	NumPorts1;
	u_long		Attributes1;
	ioaddr_t	BasePort2;
	ioaddr_t	NumPorts2;
	u_long		Attributes2;
	u_long		IOAddrLines;
} io_req_t;
</verb></tscreen>

<tt/RequestIO/ reserves IO port windows for a card.  If <tt/BasePort1/
is non-zero, it specifies the IO port address of the window to be
reserved; if it is zero, Card Services will find an available window
and set <tt/BasePort1/ to this address.  If <tt/NumPorts2/ is
non-zero, a second IO port window will also be reserved.
<tt/IOAddrLines/ specifies the number of address lines that are
actually decoded by the PCMCIA card; this is not currently used.

The following flags can be specified in <tt/Attributes1/ and
<tt/Attributes2/:
<descrip>
<tag><tt/IO_DATA_PATH_WIDTH/</tag>
This field may either be <tt/IO_DATA_PATH_WIDTH_16/ for 16-bit access, or
<tt/IO_DATA_PATH_WIDTH_8/ for 8-bit access, or
<tt/IO_DATA_PATH_WIDTH_AUTO/ to dynamically size the bus based on the
access size.
</descrip>

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
This socket's IO windows have already been reserved.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This socket's configuration has been locked by a call to
<tt/RequestConfiguration/.
<tag><tt/CS_BAD_ATTRIBUTE/</tag>
An unsupported attribute flag was specified.
</descrip>

<!-- ================================================================= -->

<sect2>ReleaseIO
<p>
<tscreen><verb>
int CardServices(ReleaseIO, client_handle_t client, io_req_t *req);
</verb></tscreen>

<tt/ReleaseIO/ un-reserves IO port windows allocated by a previous
call to <tt/RequestIO/.  The <tt/req/ parameter should be the same one
passed to <tt/RequestIO/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This socket's configuration has been locked by a call to
<tt/RequestConfiguration/.  The configuration should be released
before calling ReleaseIO.
<tag><tt/CS_BAD_ARGS/</tag>
The parameters in <tt/req/ do not match the parameters passed to
<tt/RequestIO/.
</descrip>

<!-- ================================================================= -->

<sect2>RequestIRQ
<p>
<tscreen><verb>
int CardServices(RequestIRQ, client_handle_t client, irq_req_t *req);
</verb></tscreen>
The <tt/irq_req_t/ structure is given by:
<tscreen><verb>
typedef struct irq_req_t {
	u_long		Attributes;
	u_long		AssignedIRQ;
	u_long		IRQInfo1, IRQInfo2;
} irq_req_t;
</verb></tscreen>

<tt/RequestIRQ/ reserves an interrupt line for use by a PCMCIA card.
The <tt/IRQInfo1/ and <tt/IRQInfo2/ fields correspond to the interrupt
description bytes in a <tt/CFTABLE_ENTRY/ tuple.  If <tt/IRQ_INFO2_VALID/
is set in <tt/IRQInfo1/, then <tt/IRQInfo2/ is a bit-mapped mask of
allowed interrupt values.  Each bit corresponds to one interrupt line:
bit 0 = irq 0, bit 1 = irq 1, etc.  So, a mask of 0x1100 would mean
that interrupts 12 and 8 could be used.  If <tt/IRQ_INFO2_VALID/ is
not set, <tt/IRQInfo1/ is just the desired interrupt number.  If the
call is successful, the reserved interrupt is returned in
<tt/AssignedIRQ/.

The following flags can be specified in <tt/Attributes/:
<descrip>
<tag><tt/IRQ_FORCED_PULSE/</tag>
Specifies that the interrupt should be configured for pulsed mode,
rather than the default level mode.
<tag><tt/IRQ_TYPE_TIME/</tag>
Specifies that this interrupt can be time-shared with other Card
Services drivers.  Only one driver should enable the interrupt at any
time.
<tag><tt/IRQ_FIRST_SHARED/</tag>
In conjunction with <tt/IRQ_TYPE_TIME/, this should be set by the
first driver requesting a shared interrupt.
</descrip>

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_IN_USE/</tag>
An interrupt has already been reserved for this socket, or the
requested interrupt is unavailable.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This socket's configuration has been locked by a call to
<tt/RequestConfiguration/.
<tag><tt/CS_BAD_ATTRIBUTE/</tag>
An unsupported attribute flag was specified.
</descrip>

<!-- ================================================================= -->

<sect2>ReleaseIRQ
<p>
<tscreen><verb>
int CardServices(ReleaseIRQ, client_handle_t client, irq_req_t *req);
</verb></tscreen>

<tt/ReleaseIRQ/ un-reserves an interrupt assigned by an earlier call to
<tt/RequestIRQ/.  The <tt/req/ structure should be the same structure
that was passed to <tt/RequestIRQ/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This socket's configuration has been locked by a call to
<tt/RequestConfiguration/.  The configuration should be released
before calling ReleaseIRQ.
<tag><tt/CS_BAD_IRQ/</tag>
The parameters in <tt/req/ do not match the parameters passed to
<tt/RequestIRQ/.
</descrip>

<!-- ================================================================= -->

<sect2>RequestConfiguration
<p>
<tscreen><verb>
int CardServices(RequestConfiguration, client_handle_t client, config_req_t *req);
</verb></tscreen>
The <tt/config_req_t/ structure is given by:
<tscreen><verb>
typedef struct config_req_t {
	u_long		Attributes;
	u_long		Vcc, Vpp1, Vpp2;
	u_long		IntType;
	caddr_t		ConfigBase;
	u_char		Status, Pin, Copy;
	u_char		ConfigIndex;
	u_long		Present;
} config_req_t;
</verb></tscreen>

<tt/RequestConfiguration/ is responsible for actually configuring a
socket.  This includes setting voltages, setting CIS configuration
registers, setting up IO port windows, and setting up interrupts.

<tt/IntType/ specifies the type of interface to use for this card.  It
may either be <tt/INT_MEMORY/ or <tt/INT_MEMORY_AND_IO/.  Voltages are
specified in units of 1/10 volt.

The following flags can be specified in <tt/Attributes/.  DMA and
speaker control are not supported on all systems.
<descrip>
<tag><tt/CONF_ENABLE_IRQ/</tag>
Enable the IO interrupt reserved by a previous call to
<tt/RequestIRQ/.
<tag><tt/CONF_ENABLE_DMA/</tag>
Enable DMA accesses for this socket.
<tag><tt/CONF_ENABLE_SPKR/</tag>
Enable speaker output from this socket.
</descrip>

The <tt/Present/ parameter is a bit map specifying which CIS
configuration registers are implemented by this card.  <tt/ConfigBase/
gives the offset of the configuration registers in attribute memory.
The following registers can be specified:
<descrip>
<tag><tt/PRESENT_OPTION/</tag>
Specifies that the Configuration Option Register is present.  The COR
register will be set using the <tt/ConfigIndex/ parameter.
<tag><tt/PRESENT_STATUS/</tag>
Specifies that the Card Configuration and Status Register is present.
The CCSR will be initialized with the <tt/Status/ parameter.
<tag><tt/PRESENT_PIN_REPLACE/</tag>
Specifies that the Pin Replacement Register is present.  The PRR will
be initialized with the <tt/Pin/ parameter.
<tag><tt/PRESENT_COPY/</tag>
Specifies that the Socket and Copy Register is present.  The SCR will
be initialized with the <tt/Copy/ parameter.
</descrip>

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
Card Services was unable to allocate a memory window to access the
card's configuration registers.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This socket's configuration has already been locked by another call to
<tt/RequestConfiguration/.
<tag><tt/CS_BAD_VCC/</tag>
The requested Vcc voltage is not supported.
<tag><tt/CS_BAD_VPP/</tag>
The requested Vpp1/Vpp2 voltage is not supported.
</descrip>

<!-- ================================================================= -->

<sect2>ModifyConfiguration
<p>
<tscreen><verb>
int CardServices(ModifyConfiguration, client_handle_t client, modconf_t *mod);
</verb></tscreen>
The <tt/modconf_t/ structure is given by:
<tscreen><verb>
typedef struct modconf_t {
	u_long		Attributes;
	u_long		Vcc, Vpp1, Vpp2;
} modconf_t;
</verb></tscreen>

<tt/ModifyConfiguration/ modifies some attributes of a socket that has
been configured by a call to <tt/RequestConfiguration/.

The following flags can be specified in <tt/Attributes/:
<descrip>
<tag><tt/CONF_IRQ_CHANGE_VALID/</tag>
Indicates that the CONF_ENABLE_IRQ setting should be updated.
<tag><tt/CONF_ENABLE_IRQ/</tag>
Specifies that IO interrupts should be enabled for this socket.
<tag><tt/CONF_VCC_CHANGE_VALID/</tag>
Indicates that Vcc should be updated.
<tag><tt/CONF_VPP1_CHANGE_VALID/</tag>
Indicates that Vpp1 should be updated.
<tag><tt/CONF_VPP2_CHANGE_VALID/</tag>
Indicates that Vpp2 should be updated.
</descrip>

Currently, Vpp1 and Vpp2 must always have the same value.  So, the two
values must always be changed at the same time.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This actually means that this socket has <bf/not/ been locked.
<tag><tt/CS_BAD_VCC/</tag>
The requested Vcc voltage is not supported.
<tag><tt/CS_BAD_VPP/</tag>
The requested Vpp1/Vpp2 voltage is not supported.
</descrip>

<!-- ================================================================= -->

<sect2>ReleaseConfiguration
<p>
<tscreen><verb>
int CardServices(ReleaseConfiguration, client_handle_t client, config_req_t *req);
</verb></tscreen>

<tt/ReleaseConfiguration/ un-configures a socket previously set up by
a call to <tt/RequestConfiguration/.  The <tt/req/ parameter should be
the same one used to configure the socket.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The window handle is invalid, or the socket is not configured.
</descrip>

<!-- ================================================================= -->

<sect2>GetConfigurationInfo
<p>
<tscreen><verb>
int CardServices(GetConfigurationInfo, client_handle_t client, config_t *config);
</verb></tscreen>
The <tt/config_t/ structure is given by:
<tscreen><verb>
typedef struct config_t {
	u_long		Attributes;
	u_long		Vcc, Vpp1, Vpp2;
	u_long		IntType;
	caddr_t		ConfigBase;
	u_char		Status, Pin, Copy, Option;
	u_long		Present;
	u_long		AssignedIRQ;
	u_long		IRQAttributes;
	ioaddr_t	BasePort1;
	ioaddr_t	NumPorts1;
	u_long		Attributes1;
	ioaddr_t	BasePort2;
	ioaddr_t	NumPorts2;
	u_long		Attributes2;
	u_long		IOAddrLines;
} config_t;
</verb></tscreen>

<tt/GetConfigurationInfo/ returns the current socket configuration as
it was set up by <tt/RequestIO/, <tt/RequestIRQ/, and
<tt/RequestConfiguration/.  It can only be applied to a fully
configured socket.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The window handle is invalid, or the socket is not configured.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This actually means that the configuration has <bf/not/ been locked.
</descrip>

<!-- ================================================================= -->

<sect1>Card Information Structure (CIS) calls
<p>
The definition of the Card Information Structure (CIS) is the darkest
chapter of the PCMCIA standard.  All version 2 PCMCIA cards should
have a CIS, which describes the card and how it should be configured.
The CIS is a linked list of ``tuples'' in the card's attribute memory
space.  Each tuple consists of an identification code, a length byte,
and a series of data bytes.  The layout of the data bytes for some
tuple types is absurdly complicated, in an apparent effort to use
every last bit.

The <tt/ValidateCIS/ call checks to see if a card has a reasonable
CIS.  The <tt/GetFirstTuple/ and <tt/GetNextTuple/ calls are used to
step through CIS tuple lists.  <tt/GetTupleData/ extracts data bytes
from a tuple.  And <tt/ParseTuple/ interprets a limited number of
particularly important tuple types.

<!-- ================================================================= -->

<sect2>GetFirstTuple, GetNextTuple
<p>
<tscreen><verb>
#include "cistpl.h"

int CardServices(GetFirstTuple, client_handle_t client, tuple_t *tuple);
int CardServices(GetNextTuple, client_handle_t client, tuple_t *tuple);
</verb></tscreen>
The <tt/tuple_t/ data structure is given by:
<tscreen><verb>
typedef struct tuple_t {
	u_long		Attributes;
	cis_data_t	DesiredTuple;
	u_long		Flags;
	cisdata_t	TupleCode;
	u_long		TupleLink;
	cisdata_t	TupleOffset;
	cisdata_t	TupleDataMax;
	cisdata_t	TupleDataLen;
	cisdata_t	*TupleData;
} tuple_t;
</verb></tscreen>

<tt/GetFirstTuple/ searches a card's CIS for the first tuple code
matching <tt/DesiredTuple/.  The special code <tt/RETURN_FIRST_TUPLE/
will match the first tuple of any kind.  If successful, <tt/TupleCode/
is set to the code of the first matching tuple found, and
<tt/TupleLink/ is the address of this tuple in attribute memory.

<tt/GetNextTuple/ is like <tt/GetFirstTuple/, except that given a
<tt/tuple_t/ structure returned by a previous call to
<tt/GetFirstTuple/ or <tt/GetNextTuple/, it will return
the next tuple matching <tt/DesiredTuple/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
Card Services was unable to set up a memory window to map the card's
CIS.
<tag><tt/CS_NO_MORE_ITEMS/</tag>
There were no tuples matching <tt/DesiredTuple/.
</descrip>

<!-- ================================================================= -->

<sect2>GetTupleData
<p>
<tscreen><verb>
#include "cistpl.h"

int CardServices(GetTupleData, client_handle_t client, tuple_t *tuple);
</verb></tscreen>

<tt/GetTupleData/ extracts a series of data bytes from the specified
tuple, which must have been returned by a previous call to
<tt/GetFirstTuple/ or <tt/GetNextTuple/.  A maximum of
<tt/TupleDataMax/ bytes will be copied into the <tt/TupleData/ buffer,
starting at an offset of <tt/TupleOffset/ bytes.  The number of bytes
copied is returned in <tt/TupleDataLen/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
Card Services was unable to set up a memory window to map the card's
CIS.
<tag><tt/CS_NO_MORE_ITEMS/</tag>
The tuple does not contain any more data.  <tt/TuppleOffset/ is
greater than or equal to the length of the tuple.
</descrip>

<!-- ================================================================= -->

<sect2>ParseTuple
<p>
<tscreen><verb>
#include "cistpl.h"

int CardServices(ParseTuple, client_handle_t client, tuple_t *tuple, cisparse_t *parse)
</verb></tscreen>
The <tt/cisparse_t/ data structure is given by:
<tscreen><verb>
typedef union cisparse_t {
	cistpl_device_t		device;
	cistpl_vers_1_t		version_1;
	cistpl_config_t		config;
	cistpl_cftable_entry_t	cftable_entry;
} cisparse_t;
</verb></tscreen>

<tt/ParseTuple/ interprets tuple data returned by a previous call to
<tt/GetTupleData/.  The structure returned depends on the type of the
parsed tuple.  See the <tt/cistpl.h/ file for these structure
definitions; they are quite complex.  Currently, <tt/ParseTuple/ can
parse <tt/DEVICE/, <tt/VERS_1/, <tt/CONFIG/, and <tt/CFTABLE_ENTRY/
tuples.

Return codes:
<descrip>
<tag><tt/CS_BAD_TUPLE/</tag>
An error was encounted during parsing of this tuple.  The tuple may be
incomplete, or may be formatted incorrectly.
<tag><tt/CS_UNSUPPORTED_FUNCTION/</tag>
<tt/ParseTuple/ cannot parse the specified tuple type.
</descrip>

<!-- ================================================================= -->

<sect2>ValidateCIS
<p>
<tscreen><verb>
int CardServices(ValidateCIS, client_handle_t client, cisinfo_t *cisinfo)
</verb></tscreen>
The <tt/cisinfo_t/ structure is given by:
<tscreen><verb>
typedef struct cisinfo_t {
	u_long		Chains;
} cisinfo_t;
</verb></tscreen>

<tt/ValidateCIS/ attempts to verify that a card has a reasonable Card
Information Structure.  It returns the number of tuples found in
<tt/Chains/.  If the CIS appears to be uninterpretable, <tt/Chains/
will be set to 0.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
Card Services was unable to set up a memory window to map the card's
CIS.
</descrip>

<!-- ================================================================= -->

<sect1>Memory window control

<p>
PCMCIA cards have two memory spaces: attribute memory, and common
memory.  Attribute memory is commonly used for holding descriptive
information (i.e., the CIS) and configuration registers.  Common
memory may contain device buffers in the case of IO cards, or the
actual bulk storage of a memory card.  Each socket can have up to four
active memory windows, mapping portions of PCMCIA memory into the host
system address space.  A PCMCIA device can address at most 16MB of
both common and attribute memory.  Windows should typically be aligned
to at least 4K boundaries in both the host and card address spaces.

A memory window is initialized by a call to <tt/RequestWindow/.  Some
window attributes can be modified using <tt/ModifyWindow/.  The
segment of card memory mapped to the window can be modified using
<tt/MapMemPage/.  And windows are released with <tt/ReleaseWindow/.
Unlike almost all other Card Services subfunctions, the memory window
functions normally act on <tt/window_handle_t/ handles, rather than
<tt/client_handle_t/ handles.

<!-- ================================================================= -->

<sect2>RequestWindow
<p>
<tscreen><verb>
int CardServices(RequestWindow, client_handle_t *handle, win_req_t *req);
</verb></tscreen>
The <tt/win_req_t/ structure is given by:
<tscreen><verb>
typedef struct win_req_t {
	u_long		Attributes;
	caddr_t		Base;
	u_long		Size;
	u_long		AccessSpeed;
} win_req_t;
</verb></tscreen>

<tt/RequestWindow/ maps a window of card memory into system memory.
On entry, the <tt/handle/ parameter should point to a valid client
handle.  On return, this will be replaced by a <tt/window_handle_t/
handle that should be used in subsequent calls to <tt/ModifyWindow/,
<tt/MapMemPage/, and <tt/ReleaseWindow/.

The following flags can be specified in <tt/Attributes/:
<descrip>
<tag><tt/WIN_MEMORY_TYPE/</tag>
This field can be either <tt/WIN_MEMORY_TYPE_CM/ for common memory, or
<tt/WIN_MEMORY_TYPE_AM/ for attribute memory.
<tag><tt/WIN_DATA_WIDTH/</tag>
Either <tt/WIN_DATA_WIDTH_16/ for 16-bit accesses, or
<tt/WIN_DATA_WIDTH_8/ for 8-bit access.
<tag><tt/WIN_ENABLE/</tag>
If this is set, the window is turned on.
</descrip>

<tt/Base/ specifies the base address of the window in system memory.
If <tt/NULL/, Card Services will set <tt/Base/ to the first available
window address.  <tt/Size/ specifies the window size in bytes.
<tt/AccessSpeed/ specifies the memory access speed, in nanoseconds.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_NO_CARD/</tag>
The socket assigned to this client is currently vacant.
<tag><tt/CS_BAD_ATTRIBUTE/</tag>
An unsupported window attribute was requested.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
The maximum number of memory windows for this socket are already being
used.
<tag><tt/CS_IN_USE/</tag>
<tt/RequestWindow/ was unable to find a free window of system memory.
</descrip>

<!-- ================================================================= -->

<sect2>ModifyWindow
<p>
<tscreen><verb>
int CardServices(ModifyWindow, window_handle_t, modwin_t *);
</verb></tscreen>
The <tt/modwin_t/ structure is given by:
<tscreen><verb>
typedef struct modwin_t {
	u_long		Attributes;
	u_long		AccessSpeed;
} modwin_t;
</verb></tscreen>

<tt/ModifyWindow/ modifies the attributes of a window handle returned
by a previous call to <tt/RequestWindow/.  The following attributes
can be changed:
<descrip>
<tag><tt/WIN_MEMORY_TYPE/</tag>
This field can be either <tt/WIN_MEMORY_TYPE_CM/ for common memory, or
<tt/WIN_MEMORY_TYPE_AM/ for attribute memory.
<tag><tt/WIN_DATA_WIDTH/</tag>
Either <tt/WIN_DATA_WIDTH_16/ for 16-bit accesses, or
<tt/WIN_DATA_WIDTH_8/ for 8-bit access.
<tag><tt/WIN_ENABLE/</tag>
If this is set, the window is turned on.
</descrip>

<tt/AccessSpeed/ gives the new memory access speed, in nanoseconds.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The window handle is invalid.
</descrip>

<!-- ================================================================= -->

<sect2>MapMemPage
<p>
<tscreen><verb>
int CardServices(MapMemPage, window_handle_t, memreq_t *)
</verb></tscreen>
The <tt/memreq_t/ structure is given by:
<tscreen><verb>
typedef struct memreq_t {
	u_long		CardOffset;
	page_t		Page;
} memreq_t;
</verb></tscreen>

<tt/MapMemPage/ sets the address of card memory that is mapped to the
base of a memory window to <tt/CardOffset/.  The window should have
been created by a call to <tt/RequestWindow/.  The <tt/Page/ parameter
is not implemented in this version and should be set to 0.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The window handle is invalid.
<tag><tt/CS_BAD_PAGE/</tag>
The <tt/Page/ value was non-zero.
</descrip>

<!-- ================================================================= -->

<sect2>ReleaseWindow
<p>
<tscreen><verb>
int CardServices(ReleaseWindow, window_handle_t handle)
</verb></tscreen>

<tt/ReleaseWindow/ releases a memory window previously allocated with
<tt/RequestWindow/.

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The window handle is invalid.
</descrip>

<!-- ================================================================= -->

<sect1> Miscellaneous calls

<!-- ================================================================= -->

<sect2>GetCardServicesInfo
<p>
<tscreen><verb>
int CardServices(GetCardServicesInfo, servinfo_t *info)
</verb></tscreen>
The <tt/servinfo_t/ structure is given by:
<tscreen><verb>
typedef struct servinfo_t {
	char		Signature[2];
	u_long		Count;
	u_long		Revision;
	u_long		CSLevel;
	char		*VendorString;
} servinfo_t;
</verb></tscreen>

<tt/GetCardServicesInfo/ returns revision information about this
version of Card Services.  <tt/Signature/ is set to ``CS''.
<tt/Count/ is set to the number of sockets currently configured.
<tt/Revision/ is set to the revision level of the Card Services
package, and <tt/CSLevel/ is set to the level of compliance with the
PCMCIA standard.  These are encoded as BCD numbers.  <tt/VendorString/
is set to point to an RCS identification string.

This call always succeeds.

<!-- ================================================================= -->

<sect2>AccessConfigurationRegister
<p>
<tscreen><verb>
#include "cisreg.h"

int CardServices(AccessConfigurationRegister, conf_reg_t *reg);
</verb></tscreen>
The <tt/conf_reg_t/ structure is given by:
<tscreen><verb>
typedef struct conf_reg_t {
	u_long		Action;
	off_t		Offset;
	u_long		Value;
} conf_reg_t;
</verb></tscreen>

The <tt/Action/ parameter can be one of the following:
<descrip>
<tag><tt/CS_READ/</tag>
Read the specified configuration register and return <tt/Value/.
<tag><tt/CS_WRITE/</tag>
Write <tt/Value/ to the specified configuration register.
</descrip>

<tt/AccessConfigurationRegister/ either reads or writes the one-byte
CIS configuration register at offset <tt/Offset/ from the start of the
config register area.  It can only be used for a socket that has been
configured with <tt/RequestConfiguration/.

The following values for <tt/Offset/ are defined in <tt/cistpl.h/:

<descrip>
<tag><tt/CISREG_COR/</tag>
The Configuration Option Register.
<tag><tt/CISREG_CCSR/</tag>
The Card Configuration and Status Register.
<tag><tt/CISREG_PRR/</tag>
The Pin Replacement Register.
<tag><tt/CISREG_SCR/</tag>
The Socket and Copy Register.
</descrip>

Return codes:
<descrip>
<tag><tt/CS_BAD_HANDLE/</tag>
The client handle is invalid.
<tag><tt/CS_BAD_ARGS/</tag>
The specified <tt/Action/ is not supported.
<tag><tt/CS_CONFIGURATION_LOCKED/</tag>
This actually means that the configuration has <bf/not/ been locked.
<tag><tt/CS_OUT_OF_RESOURCE/</tag>
Card Services was unable to allocate a memory window to access the
card's configuration registers.
</descrip>

<!-- ================================================================= -->

<sect2>AdjustResourceInfo
<p>
<tscreen><verb>
int CardServices(AdjustResourceInfo, client_handle_t handle, adjust_t *adj);
</verb></tscreen>
The <tt/adjust_t/ structure is given by:
<tscreen><verb>
typedef struct adjust_t {
	u_long		Action;
	u_long		Resource;
	u_long		Attributes;
	union {
		struct memory {
			caddr_t		Base;
			u_long		Size;
		} memory;
		struct io {
			ioaddr_t	BasePort;
			ioaddr_t	NumPorts;
			u_long		IOAddrLines;
		} io;
		struct irq {
			u_long		IRQ;
		} irq;
	} resource;
} adjust_t;
</verb></tscreen>

<tt/AdjustResourceInfo/ is used to tell Card Services what resources
may or may not be allocated by PCMCIA devices.  The normal Linux
resource management systems (the *_region calls for IO ports,
interrupt allocation) are respected by Card Services, but this call
gives the user another level of control.

The <tt/Action/ parameter can have the following values:
<descrip>
<tag><tt/ADD_MANAGED_RESOURCE/</tag>
Place the specified resource under Card Services control, so that it
may be allocated by PCMCIA devices.
<tag><tt/REMOVE_MANAGED_RESOURCE/</tag>
Remove the specified resource from Card Services control.
</descrip>

At initialization time, Card Services assumes that it can use all
available interrupts, but IO ports and memory regions must be
explicitly enabled with <tt/ADD_MANAGED_RESOURCE/.

The <tt/Resource/ parameter can have the following values:
<descrip>
<tag><tt/RES_MEMORY_RANGE/</tag>
Specifies a memory range resource, described by <tt/adj->resource.memory/.
<tag><tt/RES_IO_RANGE/</tag>
Specifies an IO port resource, described by <tt/adj->resource.io/.
<tag><tt/RES_IRQ/</tag>
Specifies an interrupt resource, described by <tt/adj->resource.irq/.
</descrip>

The following flags may be specified in <tt/Attributes/:
<descrip>
<tag><tt/RES_RESERVED/</tag>
Indicates that the resource should be reserved for PCMCIA devices that
specifically request it.  The resource will not be allocated for a
device that asks Card Services for any available location.  This is
not implemented yet.
</descrip>

Return codes:
<descrip>
<tag><tt/CS_UNSUPPORTED_FUNCTION/</tag>
The specified <tt/Action/ or <tt/Resource/ is not supported.
<tag><tt/CS_BAD_BASE/</tag>
The specified IO address is out of range.
<tag><tt/CS_BAD_SIZE/</tag>
The specified memory or IO window size is out of range.
<tag><tt/CS_IN_USE/</tag>
The specified interrupt is currently allocated by a Card Services
client.
</descrip>

<!-- ================================================================= -->

<sect2>ReportError
<p>
<tscreen><verb>
int CardServices(ReportError, char *prefix, int func, int ret);
</verb></tscreen>

<tt/ReportError/ generates a kernel error message given a Card
Services function code and its return code, with an optional prefix
string.  For example:

<tscreen><verb>
CardServices(ReportError, "serial_cs", RequestIO, CS_BAD_HANDLE);
</verb></tscreen>
would generate the following message:
<tscreen><verb>
serial_cs: RequestIO: Bad handle
</verb></tscreen>

This call always succeeds.

<!-- ================================================================= -->

<sect> Card Information Structure Definitions
<p>

<!-- ================================================================= -->

<sect1>CISTPL_DEVICE
<p>

The <tt/cistpl_device_t/ structure is given by:
<tscreen><verb>
typedef struct cistpl_device_t {
	u_char		type;
	u_char		wp;
	u_char		speed;
	u_long		size;
} cistpl_device_t;
</verb></tscreen>

<!-- ================================================================= -->

<sect1>CISTPL_VERS_1
<p>

The <tt/cistpl_vers_1_t/ structure is given by:
<tscreen><verb>
typedef struct cistpl_vers_1_t {
	u_char		major;
	u_char		minor;
	int		ns;
	char		pi[CISTPL_VERS_1_MAX_PROD_STRINGS][CISTPL_VERS_1_STRLEN];
} cistpl_vers_1_t;
</verb></tscreen>

<!-- ================================================================= -->

<sect1>CISTPL_CONFIG
<p>

The <tt/cistpl_config_t/ structure is given by:
<tscreen><verb>
typedef struct cistpl_config_t {
	u_char		last_idx;
	u_long		base;
	u_long		rmask[4];
} cistpl_config_t;
</verb></tscreen>

<!-- ================================================================= -->

<sect1>CISTPL_CFTABLE_ENTRY
<p>

The <tt/cistpl_cftable_entry_t/ structure is given by:
<tscreen><verb>
typedef struct cistpl_cftable_entry_t {
	u_char		index;
	u_char		Default;
	u_char		interface;
	u_char		features;
	cistpl_power_t	power[4];
	cistpl_timing_t	timing;
	cistpl_io_t	io;
	cistpl_irq_t	irq;
	cistpl_mem_t	mem;
} cistpl_cftable_entry_t;
</verb></tscreen>

<!-- ================================================================= -->

<sect> Card Services Event Handling
<p>
Card Services events have several sources:

<itemize>
<item>Card status changes reported by the low-level socket drivers.
<item>Artificial events generated by Card Services itself.
<item>Advanced Power Management (APM) events.
<item>Events generated by other Card Services clients.
</itemize>

Socket driver events may be either interrupt-driven or polled.

<!-- ================================================================= -->

<sect1> Event handler operations
<p>
When Card Services recognizes that an event has occurred, it checks
the event mask of each client to determine which clients should
receive an event notification.  When a client registers with Card
Services, it specifies  an event handler callback function.  This
handler should have the form:

<tscreen><verb>
int (*event_handler)(event_t event, int priority, event_callback_args_t *args);
</verb></tscreen>

The <tt/priority/ parameter is set to either <tt/CS_EVENT_PRI_LOW/ for
ordinary events, or <tt/CS_EVENT_PRI_HIGH/ for events that require an
immediate response.  The only high priority event is
<tt/CS_EVENT_CARD_REMOVAL/.  A client event handler should process
this event as efficiently as possible so that Card Services can
quickly notify other clients.

The <tt/event_callback_args_t/ structure is given by:
<tscreen><verb>
typedef struct event_callback_args_t {
	client_handle_t		client_handle;
	void			*info;
	void			*mtdrequest;
	void			*buffer;
	void			*misc;
	void			*client_data;
} event_callback_args_t;
</verb></tscreen>

The <tt/client_handle/ member is set to the handle of the client whose
socket was responsible for the event.  This is useful if a driver is
bound to several sockets.  The <tt/info/ field is currently only used
to return an exit status from a call to <tt/ResetCard/.  The
<tt/client_data/ field may be used by a driver to point to a local
data structure associated with this device.  The remaining
fields are currently unused.

<sect1> Event descriptions
<p>

<descrip>
<tag><tt/CS_EVENT_CARD_INSERTION/</tag>
This event signals that a card has been inserted.  If a driver is
bound to an already occupied socket, Card Services will send the
driver an artificial insertion event.
<tag><tt/CS_EVENT_CARD_REMOVAL/</tag>
This event signals that a card has been removed.  This event should be
handled with minimum delay so that Card Services can notify all
clients as quickly as possible.
<tag><tt/CS_EVENT_BATTERY_LOW/</tag>
This event signals a change of state of the ``battery low'' signal.
<tag><tt/CS_EVENT_BATTERY_DEAD/</tag>
This event signals a change of state of the ``battery dead'' signal.
<tag><tt/CS_EVENT_READY_CHANGE/</tag>
This event signals a change of state of the ``ready'' signal.
<tag><tt/CS_EVENT_WRITE_PROTECT/</tag>
This event signals a change of state of the ``write protect'' signal.
<tag><tt/CS_EVENT_REGISTRATION_COMPLETE/</tag>
This event is sent to a driver after a successful call to
<tt/RegisterClient/.
<tag><tt/CS_EVENT_RESET_REQUEST/</tag>
This event is sent when a client calls <tt/ResetCard/.  An event
handler can veto the reset operation by returning failure.
<tag><tt/CS_EVENT_RESET_PHYSICAL/</tag>
This is sent to all clients just before a reset signal is sent to a
card.
<tag><tt/CS_EVENT_CARD_RESET/</tag>
This event signals that a reset operation is finished.  The success or
failure of the reset can be determined using <tt/GetStatus/.
<tag><tt/CS_EVENT_RESET_COMPLETE/</tag>
This event is sent to a client that has called <tt/ResetCard/ to
signal the end of reset processing.
<tag><tt/CS_EVENT_PM_SUSPEND/</tag>
This event signals that Card Services has received either a user
initiated or APM suspend request.  An event handler can veto the
suspend by returning failure.
<tag><tt/CS_EVENT_PM_RESUME/</tag>
This signals that the system is back on line after a suspend/resume
cycle.
</descrip>

<!-- ================================================================= -->

<sect> Driver Services interface
<p>
Driver Services provides a link between Card Services client drivers
and user mode utilities like the <tt/cardmgr/ daemon.  It is a sort of
Card Services ``super-client''.  Driver Services uses the
<tt/BindDevice/ function to link other client drivers with their
corresponding PCMCIA cards.  Unlike other clients, Driver Services
remains permanently bound to all sockets as cards are inserted and
removed.

<!-- ================================================================= -->

<sect1> Interface to other client drivers
<p>
Driver Services keeps track of all client drivers that are installed
and ready to attach to a socket.  Client drivers need to have entry
points for creating and deleting device ``instances'', where one
device instance is everything needed to manage one PCMCIA card.

Each client driver is identified by a unique 16-character tag that has
the special type <tt/dev_info_t/, defined in <tt/cs_types.h/.  Each
device instance is described by a <tt/dev_link_t/ structure.

<sect2> The <tt/dev_link_t/ structure
<p>
The <tt/dev_link_t/ data structure is given by:
<tscreen><verb>
#include "ds.h"

typedef struct dev_link_t {
	char			dev_name[8];
	u_char			major, minor;
	u_long			state;
	u_long			open;
	struct wait_queue	*pending
	struct timer_list	release
	client_handle_t		handle;
	io_req_t		io;
	irq_req_t		irq;
	config_req_t		conf;
	window_handle_t		win;
	void			*priv;
	struct dev_link_t	*next;
} dev_link_t;
</verb></tscreen>

The <tt/dev_name/ field should be filled in by the driver with a
device file name for accessing this device, if appropriate.  For
example, the <tt/serial_cs/ driver uses names like ``<tt/cua1/''.  The
<tt/major/ and <tt/minor/ fields give major and minor device numbers
for accessing this device.  Driver Services relays these fields to
user mode programs via the <tt/DS_GET_DEVICE_INFO/ ioctl.

The <tt/state/ field should be used to keep track of the current
device state.  The following flags are defined:

<descrip>
<tag><tt/DEV_PRESENT/</tag>
Indicates that the card is present.  This bit should be set and
cleared by the driver's event handler in response to card insertion
and removal events.
<tag><tt/DEV_CONFIG/</tag>
Indicates that the card is configured for use.
<tag><tt/DEV_CONFIG_PENDING/</tag>
Indicates that configuration is in progress.
<tag><tt/DEV_SUSPEND/</tag>
Indicates that the card is suspended.
<tag><tt/DEV_BUSY/</tag>
Indicates that an IO operation is in progress.  This bit may be used
as an interlock to prevent access conflicts.
<tag><tt/DEV_STALE_CONFIG/</tag>
For some drivers, when a running card is ejected, the socket should
not be unconfigured until any devices corresponding to this card are
closed.  This flag indicates that the socket should be unconfigured
when the device is closed.
<tag><tt/DEV_STALE_LINK/</tag>
A driver instance should not be deleted until all its PCMCIA resources
are released.  This flag indicates that this driver instance should be
freed as soon as the socket is unconfigured.
</descrip>

The <tt/open/ field is a usage count for this device.  The device
should only be freed when the open count is zero.  The <tt/pending/
field can be used to manage a queue of processes waiting to use the
device.

The <tt/release/ field is used to schedule device shutdown processing
when a card is ejected.  A card removal event needs to be handled at
high priority, so a driver's event handler will typically deal with an
eject by resetting the <tt/DEV_PRESENT/ bit in the device state, then
scheduling the shutdown processing to run at a later time.

The <tt/handle/, <tt/io/, <tt/irq/, <tt/conf/, and <tt/win/ fields
comprise all the normal PCMCIA data structures needed to configure one 
PCMCIA IO card.

The <tt/priv/ field can be used for any sort of private data structure
needed to manage the device.  The <tt/next/ field can be used to build
linked lists of <tt/dev_link_t/ structures, for drivers that can
handle multiple instances.

<!-- ================================================================= -->

<sect2> register_pcmcia_driver
<p>
<tscreen><verb>
int register_pcmcia_driver(dev_info_t *dev_info,
			   dev_link_t *(*attach)(void),
			   void (*detach)(dev_link_t *));
</verb></tscreen>
<tt/register_pcmcia_driver/ informs Driver Services that a client
driver is present and ready to be bound to sockets.  When Driver
Services receives a <tt/DS_BIND_REQUEST/ ioctl that matches this
driver's <tt/dev_info/ string, it will call the driver's <tt/attach()/
entry point.  When it gets a <tt/DS_UNBIND_REQUEST/ ioctl, it will
call <tt/detach()/.

<!-- ================================================================= -->

<sect2> unregister_pcmcia_driver
<p>
<tscreen><verb>
int unregister_pcmcia_driver(dev_info_t *dev_info);
</verb></tscreen>

This informs Driver Services that it should no longer bind sockets to
the specified client driver.

<!-- ================================================================= -->

<sect1> Interface to user mode PCMCIA utilities
<p>
Driver Services creates a pseudo-device for communicating with user
mode PCMCIA utilities.  The major number of the device is chosen
dynamically, and PCMCIA utilities should read <tt>/proc/devices</tt> 
to determine it.  Minor device numbers correspond to socket numbers,
starting with 0.

Only one process is allowed to open a socket for read/write access.
Other processes can open the socket in read-only mode.  A read-only
connection to Driver Services can perform a subset of <tt/ioctl/
calls.  A read/write connection can issue all <tt/ioctl/ calls, and
can also receive Card Services event notifications.

<!-- ================================================================= -->

<sect2> Card Services event notifications
<p>
Driver Services implements <tt/read()/ and <tt/select()/ functions for
event notification.  Reading from a pcmcia device returns an unsigned
long value containing all the events received by Driver Services since
the previous <tt/read()/.  If no events have been received, the call
will block until the next event.  A <tt/select()/ call can be used to
monitor several sockets for new events.

The following events are monitored by Driver Services:
<tt/CS_EVENT_CARD_INSERTION/, <tt/CS_EVENT_CARD_REMOVAL/,
<tt/CS_EVENT_RESET_PHYSICAL/, <tt/CS_EVENT_CARD_RESET/, and
<tt/CS_EVENT_RESET_COMPLETE/.

<!-- ================================================================= -->

<sect2> <tt/ioctl/ descriptions
<p>
Most Driver Services <tt/ioctl/ operations directly map to Card
Services functions.  An ioctl call has the form:

<tscreen><verb>
int ioctl(int fd, int cmd, ds_ioctl_arg_t *arg);
</verb></tscreen>
The ds_ioctl_arg_t structure is given by:
<tscreen><verb>
typedef union ds_ioctl_arg_t {
	servinfo_t	servinfo;
	adjust_t	adjust;
	config_t	config;
	tuple_t		tuple;
	tuple_parse_t	tuple_parse;
	client_req_t	client_req;
	status_t	status;
	conf_reg_t	conf_reg;
	bind_info_t	bind_info;
	cisinfo_t	cisinfo;
} ds_ioctl_arg_t;
</verb></tscreen>

The following <tt/ioctl/ commands execute the corresponding Card
Services function:
<descrip>
<tag><tt/DS_GET_CARD_SERVICES_INFO/</tag>
Calls <tt/CardServices(GetCardServicesInfo, ..., &amp;arg->servinfo)/.
<tag><tt/DS_ADJUST_RESOURCE_INFO/</tag>
Calls <tt/CardServices(AdjustResourceInfo, ..., &amp;arg->adjust)/.
<tag><tt/DS_GET_CONFIGURATION_INFO/</tag>
Calls <tt/CardServices(GetConfigurationInfo, ..., &amp;arg->config)/.
<tag><tt/DS_GET_FIRST_TUPLE/</tag>
Calls <tt/CardServices(GetFirstTuple, ..., &amp;arg->tuple)/.
<tag><tt/DS_GET_NEXT_TUPLE/</tag>
Calls <tt/CardServices(GetNextTuple, ..., &amp;arg->tuple)/.
<tag><tt/DS_GET_TUPLE_DATA/</tag>
Calls <tt/CardServices(GetNextTuple, ..., &amp;arg->tuple_parse.tuple)/.
The tuple data is returned in <tt/arg->tuple_parse.data/.
<tag><tt/DS_PARSE_TUPLE/</tag>
Calls <tt/CardServices(ParseTuple, ..., &amp;arg->tuple_parse.tuple, &amp;arg->tuple_parse.parse)/.
<tag><tt/DS_RESET_CARD/</tag>
Calls <tt/CardServices(ResetCard, ...)/.
<tag><tt/DS_GET_STATUS/</tag>
Calls <tt/CardServices(GetStatus, ..., &amp;arg->status)/.
<tag><tt/DS_ACCESS_CONFIGURATION_REGISTER/</tag>
Calls <tt/CardServices(AccessConfigurationRegister, ..., &amp;arg->conf_reg)/.
<tag><tt/DS_VALIDATE_CIS/</tag>
Calls <tt/CardServices(ValidateCIS, ..., &amp;arg->cisinfo)/.
<tag><tt/DS_SUSPEND_CARD/</tag>
Calls <tt/CardServices(SuspendCard, ...)/.
<tag><tt/DS_RESUME_CARD/</tag>
Calls <tt/CardServices(ResumeCard, ...)/.
<tag><tt/DS_EJECT_CARD/</tag>
Calls <tt/CardServices(EjectCard, ...)/.
<tag><tt/DS_INSERT_CARD/</tag>
Calls <tt/CardServices(InsertCard, ...)/.
</descrip>

The following <tt/ioctl/ commands invoke special Driver Services
functions.  They act on <tt/bind_info_t/ structures:
<tscreen><verb>
typedef struct bind_info_t {
	dev_info_t		dev_info;
	struct dev_info_t	*instance;
	char			name[8];
	u_char			major, minor;
	void			*next;
} bind_info_t;
</verb></tscreen>
<descrip>
<tag><tt/DS_BIND_REQUEST/</tag>
This call connects a socket to a client driver.  The specified device
ID <tt/dev_info/ is looked up in the list of registered drivers.  If
found, the driver is bound to this socket using the <tt/BindDevice/
call.  Then, Driver Services calls the client driver's <tt/attach()/
entry point to create a device instance.  The new <tt/dev_link_t/
pointer is returned in <tt/instance/.
<tag><tt/DS_GET_DEVICE_INFO/</tag>
This call retrieves the <tt/dev_name/, <tt/major/, and <tt/minor/
entries from the <tt/dev_link_t/ structure pointed to by
<tt/instance/.
<tag><tt/DS_UNBIND_REQUEST/</tag>
This call calls the <tt/detach()/ function for the specified driver
and instance, shutting down this device.
</descrip>

<!-- ================================================================= -->

<sect>Where to Go for More Information
<p>
The <em/Linux Kernel Hackers' Guide/, written by Michael Johnson, is a
good source of general information about writing Linux device drivers.
It is available from the usual Linux FTP sites.

The genuine PCMCIA standard is only available for a steep price from
the PCMCIA association itself.  The new PC Card Standard is supposed
to cost &dollar;399, but you may still be able to get old copies of
the 2.1 standard at a deep discount.

<tscreen><verb>
Personal Computer Memory Card International Association
1030 East Duane Avenue, Suite G
Sunnyvale, CA 94086 USA
(408) 720-0107, (408) 720-9416 FAX, (408) 720-9388 BBS
</verb></tscreen>

One alternative is the <em/PCMCIA Developer's Guide/, written by Michael
Mori, available from Sycard Technology for &dollar;89.95:

<tscreen><verb>
Sycard Technology
1180-F Miraloma Way
Sunnyvale, CA 94086 USA
(408) 749-0130, (408) 749-1323 FAX
</verb></tscreen>

Programming information for various PCMCIA controllers is available
from the corresponding chip vendors:

<tscreen><verb>
Intel Corporation
(800) 628-8686

Cirrus Logic
(510) 623-8300

Vadem
(408) 943-9301

Databook Inc.
(716) 889-4204
</verb></tscreen>

<!-- ================================================================= -->

</article>
