7 Driver Services interface

Contents of this section

Driver Services provides a link between Card Services client drivers and user mode utilities like the cardmgr daemon. It is a sort of Card Services ``super-client''. Driver Services uses the 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.

7.1 Interface to other client drivers

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 dev_info_t, defined in cs_types.h. Each device instance is described by a dev_link_t structure.

The dev_link_t structure

The dev_link_t data structure is given by:

#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;

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

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

DEV_PRESENT

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.

DEV_CONFIG

Indicates that the card is configured for use.

DEV_CONFIG_PENDING

Indicates that configuration is in progress.

DEV_SUSPEND

Indicates that the card is suspended.

DEV_BUSY

Indicates that an IO operation is in progress. This bit may be used as an interlock to prevent access conflicts.

DEV_STALE_CONFIG

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.

DEV_STALE_LINK

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.

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

The 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 DEV_PRESENT bit in the device state, then scheduling the shutdown processing to run at a later time.

The handle, io, irq, conf, and win fields comprise all the normal PCMCIA data structures needed to configure an ordinary PCMCIA IO card.

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

register_pcmcia_driver

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

unregister_pcmcia_driver

int unregister_pcmcia_driver(dev_info_t *dev_info);

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

7.2 Interface to user mode PCMCIA utilities

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 /proc/devices 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 ioctl calls. A read/write connection can issue all ioctl calls, and can also receive Card Services event notifications.

Card Services event notifications

Driver Services implements read() and 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 read(). If no events have been received, the call will block until the next event. A select() call can be used to monitor several sockets for new events.

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

ioctl descriptions

Most Driver Services ioctl operations directly map to Card Services functions. An ioctl call has the form:

int ioctl(int fd, int cmd, ds_ioctl_arg_t *arg);
The ds_ioctl_arg_t structure is given by:
typedef union ds_ioctl_arg_t {
        servinfo_t      servinfo;
        adjust_t        adjust;
        config_info_t   config;
        tuple_t         tuple;
        tuple_parse_t   tuple_parse;
        client_req_t    client_req;
        status_t        status;
        conf_reg_t      conf_reg;
        cisinfo_t       cisinfo;
        region_info_t   region;
        bind_info_t     bind_info;
        mtd_info_t      mtd_info;
} ds_ioctl_arg_t;

The following ioctl commands execute the corresponding Card Services function:

DS_GET_CARD_SERVICES_INFO

Calls CardServices(GetCardServicesInfo, ..., &arg->servinfo).

DS_ADJUST_RESOURCE_INFO

Calls CardServices(AdjustResourceInfo, ..., &arg->adjust).

DS_GET_CONFIGURATION_INFO

Calls CardServices(GetConfigurationInfo, ..., &arg->config).

DS_GET_FIRST_TUPLE

Calls CardServices(GetFirstTuple, ..., &arg->tuple).

DS_GET_NEXT_TUPLE

Calls CardServices(GetNextTuple, ..., &arg->tuple).

DS_GET_TUPLE_DATA

Calls CardServices(GetTupleData, ..., &arg->tuple_parse.tuple). The tuple data is returned in arg->tuple_parse.data.

DS_PARSE_TUPLE

Calls CardServices(ParseTuple, ..., &arg->tuple_parse.tuple, &arg->tuple_parse.parse).

DS_RESET_CARD

Calls CardServices(ResetCard, ...).

DS_GET_STATUS

Calls CardServices(GetStatus, ..., &arg->status).

DS_ACCESS_CONFIGURATION_REGISTER

Calls CardServices(AccessConfigurationRegister, ..., &arg->conf_reg).

DS_VALIDATE_CIS

Calls CardServices(ValidateCIS, ..., &arg->cisinfo).

DS_SUSPEND_CARD

Calls CardServices(SuspendCard, ...).

DS_RESUME_CARD

Calls CardServices(ResumeCard, ...).

DS_EJECT_CARD

Calls CardServices(EjectCard, ...).

DS_INSERT_CARD

Calls CardServices(InsertCard, ...).

DS_GET_FIRST_REGION

Calls CardServices(GetFirstRegion, ..., &arg->region).

DS_GET_NEXT_REGION

Calls CardServices(GetNextRegion, ..., &arg->region).

The following ioctl commands invoke special Driver Services functions. They act on bind_info_t structures:

typedef struct bind_info_t {
        dev_info_t              dev_info;
        u_char                  function;
        struct dev_info_t       *instance;
        char                    name[8];
        u_char                  major, minor;
        void                    *next;
} bind_info_t;
DS_BIND_REQUEST

This call connects a socket to a client driver. The specified device ID dev_info is looked up in the list of registered drivers. If this is a multifunction card, the function field identifies which card function is being bound. If found, the driver is bound to this socket and function using the BindDevice call. Then, Driver Services calls the client driver's attach() entry point to create a device instance. The new dev_link_t pointer is returned in instance.

DS_GET_DEVICE_INFO

This call retrieves the dev_name, major, and minor entries from the dev_link_t structure pointed to by instance.

DS_UNBIND_REQUEST

This call calls the detach() function for the specified driver and instance, shutting down this device.

Finally, the DS_BIND_MTD request takes an argument of type mtd_info_t:

typedef struct mtd_info_t {
        dev_info_t      dev_info;
        u_long          Attributes;
        u_long          CardOffset;
} mtd_info_t;

This call associates an MTD identified by dev_info with a memory region described by Attributes and CardOffset, which have the same meanings as in the Card Services BindMTD call.

Next Chapter, Previous Chapter

Table of contents of this chapter, General table of contents

Top of the document, Beginning of this Chapter