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.
The *_event()
entry point is called from Card Services to notify
a driver of card status change events.
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.