Each release of the Linux Card Services package comes with a well-commented
``dummy'' client driver that should be used as a starting point for
writing a new driver. Look for it in clients/dummy_cs.c.
This is not just a piece of sample code: it is written to function as
a sort of generic card enabler. If bound to an IO card, it will read
the card's CIS and configure the card appropriately, assuming that the
card's CIS is complete and accurate.

All loadable modules must supply init_module() and
cleanup_module() functions, which are invoked by the module
support code when the module is installed and removed. A client
driver's init function should register the driver with Driver
Services, via the register_pccard_driver() call. The cleanup
function should use unregister_pccard_driver() to unregister with
Driver Services. Depending on the driver, the cleanup function may
also need to free any device structures that still exist at shutdown
time.

The *_attach() entry point is responsible for creating an
``instance'' of the driver, setting up any data structures needed to
manage one card. The *_attach() function should allocate
and initialize a dev_link_t structure, and call
RegisterClient to establish a link with Card Services. It
returns a pointer to the new dev_link_t structure, or NULL
if the new instance could not be created.

The *_detach() entry point deletes a driver instance created by a
previous call to *_attach. It also breaks the link with Card
Services, using DeregisterClient.

The *_attach() entry point is called by Driver Services when a
card has been successfully identified and mapped to a matching driver
by a DS_BIND_REQUEST ioctl(). The *_detach() entry point is
called in response to a DS_UNBIND_REQUEST ioctl() call.

The *_config() function is called to prepare a card for IO. Most
drivers read some configuration details from the card itsef, but most
have at least some built-in knowledge of how the device should be set
up. For example, the serial card driver reads a card's
CFTABLE_ENTRY tuples to determine appropriate IO port base
addresses and corresponding configuration indices, but the driver
ignores the interrupt information in the CIS. The *_config
function will parse relevant parts of a card's CIS, then make calls to
RequestIO, RequestIRQ, and/or RequestWindow, then call
RequestConfiguration.

When a card is successfully configured, the *_config() routine
should fill in the dev_name, major, and minor fields in
the dev_link_t structure. These fields will be returned to user
programs by Driver Services in response to a DS_GET_DEVICE_INFO
ioctl().

The *_release() function should release any resource allocated by
a previous call to *_config(), and blank out the device's
dev_name field.

The *_config() and *_release functions are normally called
in response to card status change events or from timer interrupts.
Thus, they cannot sleep, and should not call other kernel functions
that might block.

A configured socket should only be released when all associated
devices are closed. Releasing a socket allows its system resources to
be allocated for use by another device. If the released resources are
reallocated while IO to the original device is still in progress, the
original driver may interfere with use of the new device.

A driver instance should only be freed after its corresponding socket
configuration has been released. Card Services requires that a client
explicitly release any allocated resources before a call to
DeregisterClient will succeed.

All loadable modules have a ``use count'' that is used by the system
to determine when it is safe to unload a module. The convention in
client drivers is to increment the use count when a device is opened,
and to decrement the count when a device is closed. So, a driver can
be unloaded whenever all associated devices are closed. in
particular, a driver can be unloaded even if it is still bound to a
socket, and the module cleanup code needs to be able to appropriately
free any such resources that are still allocated. This should always
be safe, because if the driver has a use count of zero, all devices
are closed, which means all active sockets can be released, and all
device instances can be detached.

If a driver's *_release() function is called while a device is
still open, it should set the DEV_STALE_CONFIG flag in the device
state, to signal that the device should be released when the driver's
close() function is called. If *_detach() is called for a
configured device, the DEV_STALE_LINK flag should be set to
signal that the instance should be detached when the *_release()
function is called.

Many of the current client drivers use existing Linux driver
code to perform device IO operations. The Card Services client module
handles card configuration and responds to card status change events,
but delegates device IO to a compatible driver for a conventional ISA
bus card. In some cases, a conventional driver can be used without
modification. However, to fully support PC Card features like hot
swapping and power management, there needs to be some communication
between the PC Card client code and the device IO code.

Most Linux drivers expect to probe for devices at boot time, and are
not designed to handle adding and removing devices. One side-effect of
the move towards driver modularization is that it is usually easier to
adapt a modularized driver to handle removable devices.

It is important that a device driver be able to recover from having a
device disappear at an inappropriate time. At best, the driver should
check for device presence before attempting any IO operation or before
handling an IO interrupt. Loops that check device status should have
timeouts so they will eventually exit if a device never responds.

The dummy_cs driver may be useful for loading legacy drivers for
compatible PC Card devices. After binding dummy_cs to a card, the
legacy driver module may be able to detect and communicate with the
device as if it were not a PC Card. This arrangement will generally not
support clean hot swapping or power management functions, however it
may be useful as a basis for later developing a more full-featured
client driver.