TOC PREV NEXT INDEX

Writing Device Drivers for LynxOS


Writing PC Card Client Drivers

The LynxOS PC Card package architecture is based upon the PCMCIA/JEIDA PC Card Architecture specification. The following figure illustrates the card package architecture.

PC Card Architecture

Socket Services provides a standardized interface to manipulate PC Cards, sockets and adapters. A host system may have more than one PC Card adapter present. Each adapter has its own Socket Services instance.

Each instance of Socket Services registers with Card Services and notifies it about status changes in PC Cards or sockets.

By making all accesses to adapters, sockets, and PC Cards through the Socket Services interface, higher-level software is unaffected by different implementations of the hardware. Only the hardware-specific Socket Services code needs to modified to accommodate a new hardware implementation.

Card Services coordinates access to PC Cards, sockets and system resources among multiple clients. There is only one instance of Card Services in the system. Card Services makes all access to the hardware level through the Socket Services interface. All Socket Services status change reporting is routed to Card Services. Card Services then notifies the appropriate clients. Card Services preserves for its clients an abstract, hardware-independent view of a card and its resources.

Client Device Drivers refers to all users of Card Services. In the LynxOS PC Card architecture, users of Card Services are device drivers. They use a standardized API to access Card Services.

Card Services Overview

Card Services Initialization

Card Services is implemented as a device driver. There is only one instance of Card Services present in the system. At installation time, Card Services initializes its resource databases and prepares to handle registration requests from both Socket Services and client device drivers. The Card Services driver must be installed prior to any other PC Card-related driver.

Logical Sockets

The Card Services interface uses logical socket numbers to identify the socket a service is intended to access. The first physical socket on the first physical adapter is logical socket 0. The last logical socket is the total number of sockets less one.

Card Services Groups

The services defined by the card services interface can be divided into six functional groups. These are:

Client Services

The following services are used for client initialization and registration.

Client Utilities

The following services are used to perform common tasks required by all clients.

Resource Management Services

The following services provide basic access to available system resources. These services combine knowledge of the current status of system resources with the underlying Socket Services adapter control services.

Advanced Client Services

The following are advanced client services.

Bulk Memory Services

The following services provide various memory operations for memory clients that require isolation from the details of underlying memory technology hardware.

Special Services

The following are services providing miscellaneous operations for client drivers.

Card Services Calling Conventions

The Card Services interface consists of the CardServices() function. CardServices() provides the API for all card services.

Header Files

All prototypes and constants needed to access card services from client device drivers are located in the following header files:

Card Services Header Files
File
Description
/sys/dheaders/pcmcia_cs.h
Contains definitions common for all services.
/sys/dheaders/pcmcia_cs_tuple.h
Contains definitions required by the tuple parsing services.

Synopsis

The prototype for CardServices() is:

int CardServices( int Service, void * Handle, void *  Pointer,
int rgLength, void * ArgPointer );

The CardServices() parameters are defined as follows:

Service
Specifies the service code. Services details are documented in "Card Services Reference".
Handle
Is the client handle returned by the RegisterClient service. It is not used by any other service. The RegisterClient service places a new client handle in the location pointed to by this argument.
Pointer
Is a service-dependent value.
ArgLength
Is the size of the structure pointed to by ArgPointer.
ArgPointer
Is a pointer to service-dependent data.

After invocation, a service returns a completion code, unique for a particular service, as defined "Card Services Reference".

Client Structure

A client device driver is a device driver that uses the API defined by CardServices().

The following tasks are common for client device drivers:

These steps are described below and are illustrated by a sample client device driver acting as a PC Card enabler.

Detecting the Presence of Card Services

The presence of card services is detected using the GetCardServicesInfo service. For example:

int code;
pcmcia_cs_information_t cs_info;

/* Get Card Services information. */
code = CardServices( GetCardServicesInfo, ( void * )0, ( void * )0,
sizeof( cs_info ), &cs_info );
if ( code != PCMCIA_CS_SUCCESS )
{
return (char *)SYSERR;
}

/* Detect the presence of Card Services. */
if ( cs_info.signature[0] != 'C' || cs_info.signature[1] != 'S' )
{
return (char *)SYSERR;
}

Client Registration

Following initialization, a client registers itself with card services to specify the event notification it is to receive. The RegisterClient service is used to register a new client. At registration time, the client specifies its type, thus defining its priority for event notification. I/O clients are notified of events first, memory technology drivers are notified next, and memory clients are notified last. Also, the client provides the event mask that defines the events to be notified of. For example:

pcmcia_cs_register_t reg;
int code;

/* I/O type client, create artificial insertion event
* for all card inserted at the registration time.
*/
reg.attributes = PCMCIA_CS_ATTR_IO | PCMCIA_CS_ATTR_INSERT;

/* Receive notification of PCMCIA_CS_EVENT_REMOVAL and
* PCMCIA_CS_EVENT_INSERTION events.
*/
reg.event_mask = PCMCIA_CS_EVENT_REMOVAL | PCMCIA_CS_EVENT_INSERTION;

/* No client specific data is needed.
*/
reg.client_data = ( void * )0;

/* Now register. NULL in the Handle param will prevent Card Services
* from returning a client handle.
*/
code = CardServices( RegisterClient, ( void * )0, ex_callback,
sizeof( reg ), &reg );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;}

Client Callback

Card services notifies clients of events through a single callback routine that is specified at client registration. A client receives notification of an event along with various event-specific data.

The prototype for callback() is:

int callback( int event, int socket, void * handle, void * buffer,
pcmcia_cs_mtd_request_t * mtd_request, void * client_param );

where:

event
Is the event code. Events are listed and described in the table, "Events."
socket
Is the logical socket with which the event is associated. socket is meaningful only for status change events.
handle
Is the client handle.
buffer, mtd_request
These arguments are used by memory technology drivers (not supported).
client_param
Is client-specific data provided at registration.

Events

The following events are supported:

Events  
Event
Syntax/Description
PCMCIA_CS_EVENT_REG_COMPLETE
callback(PCMCIA_CS_EVENT_REG_COMPLETE,
         0, handle, NULL, NULL, param);
This is the first and mandatory event each client receives as soon as registration is complete. This event arrives before RegisterClient service completion to ensure determinism of control flow.
PCMCIA_CS_EVENT_INSERTION
callback(PCMCIA_CS_EVENT_INSERTION,
         socket, handle, NULL, NULL,
         param );
This event occurs when card services detects an operational PC Card in the logical socket socket. The callback receives an artificial PCMCIA_CS_EVENT_INSERTION event for all sockets that contain a PC Card if the client has registered with the PCMCIA_CS_ATTR_INSERTION attribute. The artificial insertion event arrives before RegisterClient service completion to ensure determinism of control flow.
PCMCIA_CS_EVENT_REMOVAL
callback( PCMCIA_CS_EVENT_REMOVE,
         socket, handle, NULL, NULL,
         param );
This event occurs when card services detects removal of a PC Card from the logical socket socket.

PC Card Identification

When a client receives the PCMCIA_CS_EVENT_INSERTION event, it must first identify the just inserted PC Card. PC Card identification can be accomplished by using the card and manufacturer identification numbers present in the mandatory MANFID tuple. This tuple is parsed automatically by card services on card insertion and is provided to client in the data returned by the GetConfigurationInfo service. For example:

pcmcia_cs_config_info_t config_info;
int code;

/* A part of callback code.
* Use the socket number from callback arguments.
*/
config_info.socket = socket;
code = CardServices( GetConfigurationInfo, handle, (void *)0,
sizeof( config_info ), &config_info );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}

if ( config_info.manuf_code == 0x101 &&
config_info.manuf_info == 0x589 )
{
/* This is a 3COM 3c589x PC Card.
*/
}

An alternate method to identify the PC card is to use the client utilities services to find some other tuples that contain card identification information, and parse them using the ParseTuple service. For example:

pcmcia_cs_tuple_t tuple;
pcmcia_cs_tuple_data_t tuple_data;
int code;

/* Find mandatory Version1 tuple.
*/
tuple.socket = socket;
tuple.code = PCMCIA_CS_TUPLE_VERS_1;
code = CardServices( GetFirstTuple, handle, (void *)0,
sizeof( tuple ), &tuple );
if ( code == PCMCIA_CS_SUCCESS )
{
code = CardServices( ParseTuple, handle, &tuple,
sizeof( tuple_data ), &tuple_data );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}
kkprintf( "CARD DETECTED: v%d.%d\n",
            tuple_data.vers_1.major, tuple_data.vers_1.minor );
  kkprintf( " %s\n", tuple_data.vers_1.manf_name );
  kkprintf( " %s\n", tuple_data.vers_1.prod_name );
  kkprintf( " %s\n", tuple_data.vers_1.lot_info );
  kkprintf( " %s\n", tuple_data.vers_1.prog_info );
}

PC Card Configuration

To configure a PC Card, the client must first reserve appropriate system resources (I/O range and optional IRQ) using the RequestIO and RequestIRQ services. Reservation is necessary to prevent possible configuration conflicts with other client device drivers. For example:

pcmcia_cs_request_io_t io;
pcmcia_cs_request_irq_t irq;
int code;

/* Request I/O range 0x200-0x210.
*/
io.socket = socket;
io.base_port1 = 0x200;
io.num_ports1 = 0x10;
io.attributes1 = 0;
io.base_port2 = 0;
io.num_ports2 = 0;
io.attributes2 = 0;

code = CardServices( RequestIO, handle, ( void * )0,
sizeof( io ), &io );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}

/* Request IRQ 14.
*/
irq.socket = socket;
irq.assigned_irq = 32 + 14;
code = CardServices( RequestIRQ, handle, ( void * )0,
sizeof(irq), &irq );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}

Actual configuration of a PC Card is performed by the RequestConfiguration service. It applies the specified voltage to the card and reserves the I/O address ranges and IRQ for corresponding socket. For example:

pcmcia_cs_request_config_t config;
int code;

/* Apply the voltage and configure the card
*/
config.socket = socket;
config.vcc = 50;
config.vpp = 50;
config.int_type = PCMCIA_CS_INTERFACE_IO;
config.option = 1 + 0x40;
config.present = PCMCIA_CS_PRESENT_OPTION;
code = CardServices( RequestConfiguration, handle, ( void * )0,
       sizeof( config ), &config );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}

Client Deregistration

To deregister a client, the DeregisterClient service is used. The client handle obtained using the RegisterClient service is passed to CardServices(). For example:

int code;

code = CardServices( DeregisterClient, handle, ( void * )0, 0, ( void * )0 );
if ( code != PCMCIA_CS_SUCCESS )
{
return SYSERR;
}

Sample Client Drivers

PC Card Enabler

An enabler is a client device driver that detects insertion of a certain PC Card and configures it. The enabler allows standard device drivers to work with the PC Card as a conventional ISA device. The simplest enabler is a character device driver that has only install and uninstall entry point functions. At installation, the enabler detects the presence of card services and registers with it, requesting to receive card insertion events. Upon receiving a card insertion event, the enabler identifies the PC Card. If a supported card is inserted, the enabler configures it.

As soon as the PC Card configuration is complete, an appropriate dynamic device driver can be installed. The PC Card is controlled as if it were an ISA device.

If both enabler and driver are linked statically into the kernel, the enabler is installed before the driver. The card must be inserted prior to system boot and the driver should work without any changes.

Note: Note that you must ensure that the driver is configured to use the same IRQ and I/O ports range as used by the enabler to configure the card.

A sample driver layout is illustrated below:

install
· Detects card services presence.
· Registers I/O type client with attributes shown in the following example:
/* I/O type client, create artificial insertion event
 * for all card inserted at the registration time.
 */
reg.attributes = PCMCIA_CS_ATTR_IO | PCMCIA_CS_ATTR_INSERT;
reg.event_mask = PCMCIA_CS_EVENT_INSERTION;
uninstall
· Deregisters the client.
callback
· Upon receipt of PCMCIA_CS_EVENT_INSERTION event, identifies and configure the card.

Addition to Existing ISA Device Driver

It is possible to add the enabler code to an existing device driver of a conventional ISA card. This approach allows you to create a hot swap-capable device driver for the PC Card device. The driver can be statically or dynamically linked into the kernel.

A driver with an embedded enabler should return success at installation, whether it finds the card or not. However, it should be modified to reject any user accesses to the device until the enabler detects and configures the PC Card. As soon as the PC Card configuration is complete, the driver should perform the initialization procedure, which would have been otherwise performed at installation of the conventional device driver. Upon a request to remove the card, the driver should attempt to shut down the device.

A sample driver layout is illustrated below:

install
· Detect card services presence.
· Register I/O type client with attributes shown in the following example:
/* I/O type client, create artificial insertion event
 * for all card inserted at the registration time.
 */
reg.attributes = PCMCIA_CS_ATTR_IO | PCMCIA_CS_ATTR_INSERT;
reg.event_mask = PCMCIA_CS_EVENT_INSERTION |
                  PCMCIA_CS_EVENT_REMOVAL
· Do not perform any device initialization, to ensure proper operation if the card is not present in the socket.
· Set up a flag ensuring that any user access to the device is rejected. The flag can be either a global variable or contained in the statics structure of the driver.
uninstall
· Deregister the client.
callback
· Upon PCMCIA_CS_EVENT_INSERTION event, identify and configure the card. Perform device initialization, then de-assert the access rejection flag. Upon PCMCIA_CS_EVENT_REMOVAL event, safely shut down the device, terminate the device driver operation, and set the access rejection flag again.
open, read,...
· If the access rejection flag is set, return ENXIO. Operate as usual otherwise.

Card Services Reference

This section provides a description of the services supported by Card Services. Card Services uses the CardServices() API for access to all services. CardServices() is defined as follows:

int CardServices( int Service, void * Handle, void *  Pointer,
int rgLength, void * ArgPointer );

where:

Service
Specifies the service code.
Handle
Is the client handle returned by the RegisterClient service. It is not used by any other service. The RegisterClient service places a new client handle in the location pointed to by this argument.
Pointer
Is a service-dependent value.
ArgLength
Is the size of the structure pointed to by ArgPointer.
ArgPointer
Is a pointer to service-dependent data.

AccessConfigReg

AccessConfigReg allows a client to read or write a PC Card Configuration Register. ArgPointer must be a pointer to a pcmcia_cs_access_reg_t structure.

The pcmcia_cs_access_reg_t structure is defined as follows:

typedef struct pcmcia_cs_access_reg_s
{
int socket; /* logical socket */
int action; /* action to be performed */
int offset; /* offset to status register      */
unsigned char value; /* value to read or write */
}
pcmcia_cs_access_reg_t;

where:

socket
Is a logical socket.
action
Is the code of the action to be executed. action can be set to either PCMCIA_CS_ACCESS_READ or PCMCIA_CS_ACCESS_WRITE.
If action is set to PCMCIA_CS_ACCESS_WRITE, value is written to the PC Card Configuration Register.
If action is set to PCMCIA_CS_ACCESS_READ, value is set to the current value of the PC Card Configuration Register.
offset
This is the byte offset to the status register. This is relative to the PC Card configuration register base.
value
Contains the value to read or write.

EXAMPLE
pcmcia_cs_access_reg_t access_reg;

/* get the value of Configuration Option Register */

access_reg.socket = 0;
access_reg.action = PCMCIA_CS_ACCESS_READ;
access_reg.offset = 0;
res = CardServices( AccessConfigReg, NULL, NULL, sizeof( access_reg ),
      &access_reg );
if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Configuration Option Register: 0x%x\n", access_reg.value );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_NO_CARD
No PC Card in the socket.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_ARGS
Specified arguments are invalid.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.

DeregisterClient

The DeregisterClient service removes a client from the list of registered clients maintained by card services. The client handle is passed in the Handle parameter.

EXAMPLE
res = CardServices( DeregisterClient, NULL, NULL, 0, NULL );
name.code = res;
CardServices( ErrorName, NULL, NULL, 0, &name );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "I am not a client anymore\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_BAD_HANDLE
Client handle is invalid.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.

ErrorName

ErrorName service returns a character string corresponding to a specified error code returned previously by Card Services. ArgPointer must be a pointer to a pcmcia_cs_name_t structure.

The pcmcia_cs_name_t structure is defined as follows:

typedef struct pcmcia_cs_name_s
{
int code;
char * name;
}
pcmcia_cs_name_t;

where:

code
Is the error code.
name
Is a pointer to the string that contains the error name.

EXAMPLE
pcmcia_cs_name_t;

res = CardServices ( DeregisterClient, NULL, NULL, 0, NULL );
name.code = res;
CardServices( ErrorName, NULL, NULL, 0, &name );

/* should print PCMCIA_CS_BAD_HANDLE */
cprintf( "code 0x%x, name %s\n", name.code, name.name );
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.

GetCardServicesInfo

GetCardServicesInfo service returns the number of installed logical sockets and information about Card Services that includes the vendor revision number and release compliance code. ArgPointer must be a pointer to a pcmcia_cs_information_t structure.

The pcmcia_cs_information_t structure is defined as follows:

typedef struct pcmcia_cs_information_s
{
char signature[2]; /* "CS" */
int count; /* number of sockets */
int revision; /* BCD value of CS revision */
short cs_level; /* BCD value of CD release */
char * vendor_string; /* vendor string */
}
pcmcia_cs_information_t;

where:

signature[]
Contains `CS' if card services is installed.
count
Is the number of logical sockets.
revision
Is the binary coded decimal (BCD) value of the CardServices() revision.
cs_level
Is the BCD value of the CardServices() release.
vendor_string
Is a vendor-specific string.

EXAMPLE
pcmcia_cs_information_t info;

res = CardServices( GetCardServicesInfo, NULL, NULL, sizeof( info ), &info );

if ( res == PCMCIA_CS_SUCCESS )
{
if ( info.signature[0] == 'C' &&
info.signature[1] == 'S' )
{
cprintf( "Card Services detected!\n" );
}
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.

GetConfigurationInfo

GetConfigurationInfo service returns information about the specified socket and PC Card installed in the socket. ArgPointer must be a pointer to a pcmcia_cs_config_info_t structure.

The pcmcia_cs_config_info_t structure is defined as follows:

typedef struct pcmcia_cs_config_info_s
{
int socket; /* logical socket */
int attributes; /* bit-mapped attributes */
int vcc; /* Vcc settings */
int vpp; /* Vpp settings */
int int_type; /* interface type */
unsigned config_base; /* base address of config register */
unsigned manuf_code; /* from Manufacturer ID tuple */
unsigned manuf_info; /* from Manufacturer ID tuple */
unsigned base_port1; /* base address for a range */
int num_ports1; /* number of contiguous ports */
int attributes1; /* bit-mapped port attributes */
unsigned base_port2; /* base address for a range */
int num_ports2; /* number of contiguous ports */
int attributes2; /* bit-mapped port attributes */
int assigned_irq;/* irq assigned to PC Card */
unsigned char status; /* Card Status register settings */
unsigned char pin; /* Card Pin register settings */
unsigned char copy; /* Card Copy register settings */
unsigned char option; /* Card Option register settings */
int present; /* Card Configuration registers present */
}
pcmcia_cs_config_info_t;

where:

socket
Is the logical socket.
attributes
Is the bit mapped socket attributes. attributes is a bitwise combination of the constants:
· PCMCIA_CS_SATTR_ON - The socket contains a PC Card.
· PCMCIA_CS_SATTR_CONFIGURED - The PC Card installed in the socket has been configured using the RequestConfiguration service.
vcc
Is the voltage applied to the Vcc pin of a PC Card. The voltage is expressed in tenths of a volt.
vpp
Is the voltage applied to the Vpp pins of a PC Card. The voltage is expressed in tenths of a volt.
int_type
Interface type. Must be set to:
· PCMCIA_CS_INTERFACE_NONE - For the simplest interface, featuring only card detection
· PCMCIA_CS_INTERFACE_MEM - For a memory only interface
· PCMCIA_CS_INTERFACE_IO - For a memory and I/O interface
config_base
Is the card base address of the configuration registers area.
manuf_code
Is the manufacturer number from the MANFID tuple.
manuf_info
Is the product identification number from the MANFID tuple.
base_port1
Is the base port number for I/O window 1.
num_ports1
Is the number of contiguous ports in I/O window 1.
attributes1
If set to PCMCIA_CS_IO_ATTR_8BIT, the I/O window has an 8 bit width.
base_port2
Is the base port number for I/O window 2.
num_ports2
Is the number of contiguous ports in I/O window 2.
attributes2
If set to PCMCIA_CS_IO_ATTR_8BIT, the I/O window has an 8 bit width.
assigned_irq
Is the IRQ assigned to the PC Card.
status
Is the card status register settings, if present.
pin
Is the card pin register settings, if present.
copy
Is the card socket/copy register settings, if present.
option
Is the card option register settings, if present.
present
Specifies if the card configuration registers are present. A bitwise combination of the following constants:
· PCMCIA_CS_PRESENT_STATUS - Status register is present.
· PCMCIA_CS_PRESENT_PIN - Pin register is present.
· PCMCIA_CS_PRESENT_COPY - Copy register is present.
· PCMCIA_CS_PRESENT_OPTION - Option register is present.

EXAMPLE
pcmcia_cs_config_info_t info;

info.socket = 0;
res = CardServices( GetConfigurationInfo, NULL, NULL, sizeof( info ),
      &info );
if ( res == PCMCIA_CS_SUCCESS )
{
if ( info.attributes & PCMCIA_CS_SATTR_ON )
{
  cprintf( "Socket #0 contains a PC Card!\n" );
}
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.

GetFirstTuple

The GetFirstTuple service returns the first tuple of the specified type in the CIS for the specified socket. ArgPointer must be a pointer to a pcmcia_cs_tuple_t structure.

The pcmcia_cs_tuple_t structure is defined as follows:

typedef struct pcmcia_cs_tuple_s
{
int socket; /* Socket id */
int code; /* Requested tuple code */
pcmcia_cs_tuple_internal_t internal; /* Internal state */
}
pcmcia_cs_tuple_t;

where:

socket
Is the logical socket.
code
Is the tuple code. See table below.
internal
Is the Card Services CIS state information. This field is used internally by Card Services.

The following predefined constants can be used to specify a tuple code:

PCMCIA_CS_TUPLE_DEVICE
(0x01)
PCMCIA_CS_TUPLE_INDIRECT
(0x03)
PCMCIA_CS_TUPLE_CONFIG_CB
(0x04)
PCMCIA_CS_TUPLE_CFTABLE_ENTRY_CB
(0x05)
PCMCIA_CS_TUPLE_LONGLINK_MFC
(0x06)
PCMCIA_CS_TUPLE_BAR
(0x07)
PCMCIA_CS_TUPLE_CHECKSUM
(0x10)
PCMCIA_CS_TUPLE_VERS_1
(0x15)
PCMCIA_CS_TUPLE_ALTSTR
(0x16)
PCMCIA_CS_TUPLE_DEVICE_A
(0x17)
PCMCIA_CS_TUPLE_JEDEC_C
(0x18)
PCMCIA_CS_TUPLE_JEDEC_A
(0x19)
PCMCIA_CS_TUPLE_CONFIG
(0x1A)
PCMCIA_CS_TUPLE_CFTABLE_ENTRY
(0x1B)
PCMCIA_CS_TUPLE_DEVICE_OC
(0x1C)
PCMCIA_CS_TUPLE_DEVICE_OA
(0x1D)
PCMCIA_CS_TUPLE_DEVICEGEO
(0x1E)
PCMCIA_CS_TUPLE_DEVICEGEO_A
(0x1F)
PCMCIA_CS_TUPLE_MANFID
(0x20)
PCMCIA_CS_TUPLE_FUNCID
(0x21)
PCMCIA_CS_TUPLE_FUNCE
(0x22)
PCMCIA_CS_TUPLE_SWIL
(0x23)
PCMCIA_CS_TUPLE_VERS_2
(0x40)
PCMCIA_CS_TUPLE_FORMAT
(0x41)
PCMCIA_CS_TUPLE_GEOMETRY
(0x42)
PCMCIA_CS_TUPLE_BYTEORDER
(0x43)
PCMCIA_CS_TUPLE_DATE
(0x44)
PCMCIA_CS_TUPLE_BATTERY
(0x45)
PCMCIA_CS_TUPLE_ORG
(0x46)
PCMCIA_CS_TUPLE_FORMAT_A
(0x47)
PCMCIA_CS_TUPLE_SPCL
(0x90)

EXAMPLE
pcmcia_cs_tuple_t tuple;

tuple.socket = 0;
tuple.code = PCMCIA_CS_TUPLE_VERS_1;
res = CardServices( GetFirstTuple, NULL, NULL, sizeof( tuple ), &tuple );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Vers1 tuple found\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_NO_CARD
No PC Card in socket.
PCMCIA_CS_NO_MORE_ITEMS
No tuples with specified code.

GetNextTuple

The GetNextTuple service returns the next tuple of the specified type in the CIS for the specified socket. ArgPointer must be a pointer to the pcmcia_cs_tuple_t structure returned by a GetFirstTuple or a previous GetNextTuple request.

EXAMPLE
pcmcia_cs_tuple_t tuple;

tuple.socket = 0;
tuple.code = PCMCIA_CS_TUPLE_VERS_1;
res = CardServices( GetFirstTuple, NULL, NULL, sizeof( tuple ), &tuple );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Vers1 tuple found\n" );
}

res = CardServices( GetNextTuple, NULL, NULL, sizeof( tuple ), &tuple );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Another Vers1 tuple found\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_NO_CARD
No PC Card in socket.
PCMCIA_CS_NO_MORE_ITEMS
No tuples with specified code.

ParseTuple

The ParseTuple service parses a tuple. Pointer must be a pointer to the pcmcia_cs_tuple_t structure returned by a GetFirstTuple or GetNextTuple request. The ParseTuple service fills a pcmcia_cs_tuple_data_t structure pointed to by the ArgPointer parameter. The pcmcia_cs_tuple_data_t structure is defined as follows:

typedef union pcmcia_cs_tuple_data_u
{
pcmcia_cs_tuple_device_t device;
pcmcia_cs_tuple_bar_t bar;
pcmcia_cs_tuple_checksum_t checksum;
pcmcia_cs_tuple_vers_1_t vers_1;
pcmcia_cs_tuple_altstr_t altstr;
pcmcia_cs_tuple_jedec_t jedec;
pcmcia_cs_tuple_config_t config;
pcmcia_cs_tuple_cftable_entry_t entry;
pcmcia_cs_tuple_device_o_t device_o;
pcmcia_cs_tuple_devicegeo_t devicegeo;
pcmcia_cs_tuple_manfid_t manfid;
pcmcia_cs_tuple_funcid_t funcid;
pcmcia_cs_tuple_funce_t funce;
pcmcia_cs_tuple_swil_t swil;
pcmcia_cs_tuple_vers_2_t vers_2;
pcmcia_cs_tuple_format_t format;
pcmcia_cs_tuple_geometry_t geo;
pcmcia_cs_tuple_byteorder_t order;
pcmcia_cs_tuple_date_t date;
pcmcia_cs_tuple_battery_t battery;
pcmcia_cs_tuple_org_t org;
pcmcia_cs_tuple_spcl_t spcl;}
pcmcia_cs_tuple_data_t;

Supported Tuple Codes

This section lists the supported tuple codes and field sets that support each. For detailed information about each field semantics, refer to the PCMIA\JEIDA Metaformat Specification.

PCMCIA_CS_TUPLE_DEVICE
PCMCIA_CS_TUPLE_DEVICE_A

typedef struct pcmcia_cs_tuple_device_s
{
int ndev; /* Number of device structs */
struct
{
u_char type; /* Type of device */
u_char wps; /* Write protect switch */
u_char units; /* Number of mem units */
u_long unit_size; /* Mem unit's size */
u_long speed; /* Card's speed */
u_long size; /* Full size of mem */
}
dev[MAX_DEVICES];
}
pcmcia_cs_tuple_device_t;
PCMCIA_CS_TUPLE_BAR
typedef struct pcmcia_cs_tuple_bar_s
{
struct
{
u_int below : 1; /* Below 1 Mb bit */
u_int cache : 2; /* Prefetchable/Cacheable */
u_int addr_spc : 1; /* Address space bit */
u_int indicator : 3; /* Address space indicator */
}
attr; /* Attributes */
u_long size; /* Base Address Register size */
}
pcmcia_cs_tuple_bar_t;
PCMCIA_CS_TUPLE_CHECKSUM
typedef struct pcmcia_cs_tuple_checksum_s
{
u_short address; /* Checksumed address */
u_short length; /* Length of checksumed space */
u_char checksum; /* Checksum */
}
pcmcia_cs_tuple_checksum_t;
PCMCIA_CS_TUPLE_VERS_1
typedef struct pcmcia_cs_tuple_vers_1_s
{
u_char major; /* Major version */
u_char minor; /* Minor version */
char manf_name[MAX_STRING_LEN]; /* Manufacturer name */
char prod_name[MAX_STRING_LEN]; /* Product name */
char lot_info[MAX_STRING_LEN]; /* Lot number */
char prog_info[MAX_STRING_LEN]; /* Programming conditions */
}
pcmcia_cs_tuple_vers_1_t;
PCMCIA_CS_TUPLE_ALTSTR
typedef struct pcmcia_cs_tuple_altstr_s
{
char escape[MAX_ESCAPE_SEQ_LEN]; /* Alternative string */
/* escape sequence */
char altstrings[MAX_ALTSTRINGS][MAX_STRING_LEN];
/* Strings in alternative */
/* language (corresponding to */
/* vers_1 or vers_2 tuples) */
}
pcmcia_cs_tuple_altstr_t;
PCMCIA_CS_TUPLE_JEDEC
PCMCIA_CS_TUPLE_JEDEC_A
typedef struct pcmcia_cs_tuple_jedec_s
{
int ndev; /* Number of device structs */
/* (corresponding to last */
/* device tuple) */
struct
{
u_char manf; /* Manufacturer number */
u_char units; /* Number of mem units */
u_long unit_size; /* Mem unit's size */
u_long size; /* Full size of used mem */
}
dev[MAX_DEVICES];
}
pcmcia_cs_tuple_jedec_t;
PCMCIA_CS_TUPLE_CONFIG
typedef struct pcmcia_cs_tuple_config_s
{
struct
{
u_int mask_size : 4; /* Size of Configuration */
/* Registers presence mask */
/* field in bytes (minus 1) */
u_int addr_size : 2; /* Size of Configuration */
/* Registers base address */
/* field in bytes (minus 1) */
}
sizes;
u_char index; /* Last index */
u_long base; /* Base address */
u_char mask[16]; /* Conf. Reg. presence masks */
u_char subtuple[MAX_DATA_SIZE];
/* Optional additional data */
u_char size; /* Size of subtuple data */
}
pcmcia_cs_tuple_config_t;
PCMCIA_CS_TUPLE_CFTABLE_ENTRY
typedef struct pcmcia_cs_tuple_power_s
{
struct
{
u_int pdown : 1; /* Power down bit */
u_int peak : 1; /* Peak current bit */
u_int avg : 1; /* Average current bit */
u_int stat : 1; /* Static current bit */
u_int max_v : 1; /* Maximum voltage bit */
u_int min_v : 1; /* Minimum voltage bit */
u_int nom_v : 1; /* Nominal voltage bit */
}
select;
struct
{
u_long value; /* Value corresponding to */
/* field in select structure */
u_char flags; /* Flags corresponding to */
/* field in select structure */
}
values[7];
}
pcmcia_cs_tuple_power_t;

typedef struct pcmcia_cs_tuple_timing_s
{
u_long wait; /* Max Wait time */
u_long ready; /* Max Ready time */
u_long reserved; /* reserved */
u_char waitscale; /* Wait scale */
u_char rdyscale; /* Ready scale */
u_char rsvscale; /* Reserved scale */
struct
{
u_int wait : 1; /* Wait bit */
u_int ready : 1; /* Ready bit */
u_int reserved : 1; /* Reserved bit */
}
select;
}
pcmcia_cs_tuple_timing_t;

typedef struct pcmcia_cs_tuple_iospace_s
{
struct
{
u_int range : 1; /* Range bit */
u_int bus8_16 : 2; /* Bus width info */
u_int ioaddrlines : 5; /* Total number of address */
/* lines */
}
iospace_desc;
struct
{
u_int len_size : 2; /* Size of length field */
u_int addr_size : 2; /* Size of address field */
u_int num_fields : 4; /* Total number of range */
/* fields (minus 1) */
}
range_desc;
struct
{
u_long base; /* Start of the next I/O */
/* Block */
u_long length; /* Length of the next I/O */
/* Block */
}
range[16];
}
pcmcia_cs_tuple_iospace_t;

typedef struct pcmcia_cs_tuple_irq_s
{
struct
{
u_int share : 1; /* Share bit */
u_int pulse : 1; /* Pulse bit */
u_int level : 1; /* Level bit */
u_int mask : 1; /* Mask bit */
u_int vend : 1; /* Vendor specific signal */
u_int berr : 1; /* Bus error signal */
u_int iock : 1; /* I/O check signal */
u_int nmi : 1; /* Non-maskable interrupt */
u_int irqn : 4; /* One of possible lines */
}
irq_desc;
u_short irq_mask; /* IRQ lines mask */
}
pcmcia_cs_tuple_irq_t;

typedef struct pcmcia_cs_tuple_mem_s
{
struct
{
u_int host_addr : 1; /* Host address bit */
u_int caddr_size : 2; /* Size of card address */
u_int len_size : 2; /* Size of length */
u_int windows : 3; /* The number of window */
/* descriptors (minus 1) */
}
mem_desc;
struct
{
u_long length; /* The length of the window */
/* in units of 256 bytes */
u_long card_addr; /* The address to be accessed */
/* on the card corresponding */
/* to the host address */
u_long host_addr; /* The physical address in */
/* the host-address space */
/* where the block of memory */
/* must be placed */
}
window[8];
}
pcmcia_cs_tuple_mem_t;

typedef struct pcmcia_cs_tuple_misc_s
{
u_int pdown : 1; /* Power down bit */
u_int read_only : 1; /* Read only bit */
u_int audio : 1; /* Audio bit */
u_int max_twins : 3; /* Max Twin cards (minus 1) */
u_int dma_width : 1; /* The DMA data transfer */
/* width */
u_int dma_req : 2; /* DMA request signal */
}
pcmcia_cs_tuple_misc_t;

typedef struct pcmcia_cs_tuple_cftable_entry_s
{
struct
{
u_int interface : 1; /* Interface bit */
u_int dflt : 1; /* Default bit */
u_int entry_num : 6; /* Value is to be written to */
/* the Card Configuration */
/* Register to enable the */
/* configuration described in */
/* the tuple */
}
index;
struct
{
u_int wait_req : 1; /* WAIT# Signal support */
/* required for Memory Cycles */
u_int rdy_active : 1; /* READY Status Active */
u_int wp_active : 1; /* Write Protect Status is */
/* active */
u_int bvd_active : 1; /* BVD1 and BVD2 signals are */
/* active */
u_int type : 4; /* Interface type */
}
interface;
struct
{
u_int misc : 1; /* Miscell. structure bit */
u_int memspace : 2; /* Memspace structure */
/* descriptor */
u_int irq : 1; /* IRQ structure bit */
u_int iospace : 1; /* IO space structure bit */
u_int timing : 1; /* Timing structure bit */
u_int power : 2; /* Number of power structures */
}
select;
pcmcia_cs_tuple_power_t power[3];
/* Power structures */
pcmcia_cs_tuple_timing_t timing;
/* Timing structure */
pcmcia_cs_tuple_iospace_t iospace;
/* IO space structure */
pcmcia_cs_tuple_irq_t irq;
/* IRQ structure */
pcmcia_cs_tuple_mem_t mem;
/* Memspace structure */
pcmcia_cs_tuple_misc_t misc;
/* Miscellaneous structure */
u_char subtuple[MAX_DATA_SIZE];
/* Optional additional data */
u_char size;
/* Size of subtuple data */
}
pcmcia_cs_tuple_cftable_entry_t;
PCMCIA_CS_TUPLE_DEVICE_OC
PCMCIA_CS_TUPLE_DEVICE_OA
typedef struct pcmcia_cs_tuple_device_o_s
{
int ndev; /* Number of device structs */
struct
{
u_int vcc_used : 2; /* Vcc voltage */
u_int mwait : 1; /* MWait bit */
}
info;
struct
{
u_char type; /* Type of device */
u_char wps; /* Write protect switch */
u_char units; /* Number of mem units */
u_long unit_size; /* Mem unit's size */
u_long speed; /* Card's speed */
u_long size; /* Full size of mem */
}
dev[MAX_DEVICES];
}
pcmcia_cs_tuple_device_o_t;
PCMCIA_CS_TUPLE_DEVICEGEO
PCMCIA_CS_TUPLE_DEVICEGEO_A
typedef struct pcmcia_cs_tuple_devicegeo_s
{
int ndev; /* Number of device structs */
struct
{
u_char bus; /* Card interface width */
/* (2^(bus - 1)) */
u_char erase; /* Minimum erase block */
/* size (2^(erase - 1)) */
u_char read; /* Minimum read block */
/* size (2^(read - 1)) */
u_char write; /* Minimum write block */
/* size (2^(write - 1)) */
u_char partition; /* Minimal partition size */
/* (2^(partition - 1)) */
u_char hwil; /* Hardware interleave */
/* (2^(hwil - 1)) */
}
dev[MAX_DEVICES];
}
pcmcia_cs_tuple_devicegeo_t;
PCMCIA_CS_TUPLE_MANFID
typedef struct pcmcia_cs_tuple_manfid_s
{
u_short code; /* Manufacture code */
u_short card; /* Card info */
}
pcmcia_cs_tuple_manfid_t;
PCMCIA_CS_TUPLE_FUNCID
typedef struct pcmcia_cs_tuple_funcid_s
{
u_int func : 8; /* Type of card */
u_int rom : 1; /* ROM bit */
u_int post : 1; /* POST bit */
}
pcmcia_cs_tuple_funcid_t;
PCMCIA_CS_TUPLE_FUNCE
typedef struct pcmcia_cs_tuple_funce_s
{
u_char type; /* Type of extended data */
u_char data[MAX_DATA_SIZE]; /* Function information */
u_char size; /* Size of extended data */
}
pcmcia_cs_tuple_funce_t;
PCMCIA_CS_TUPLE_SWIL
typedef struct pcmcia_cs_tuple_swil_s
{
u_char interleave; /* Interleave factor */
}
pcmcia_cs_tuple_swil_t;
PCMCIA_CS_TUPLE_VERS_2
typedef struct pcmcia_cs_tuple_vers_2_s
{
u_char version; /* Structure version */
u_char comply; /* Level of compliance */
u_short first_addr; /* Byte address of first */
/* data byte in card */
u_char rsv1; /* Reserved */
u_char rsv2; /* Reserved */
u_char vendor1; /* Vendor specific */
u_char vendor2; /* Vendor specific */
u_char copies; /* Number of copies of CIS */
/* present on the device */
u_char soft_vend[MAX_STRING_LEN];
/* Vendor of software that */
/* formatted the card */
u_char card_info[MAX_STRING_LEN];
/* Informational message */
/* about the card */
pcmcia_cs_tuple_vers_2_t;
PCMCIA_CS_TUPLE_FORMAT
PCMCIA_CS_TUPLE_FORMAT_A
typedef struct pcmcia_cs_tuple_format_s
{
u_char type; /* Format type code */
struct
{
u_int type : 3; /* Error code type */
u_int length : 4; /* Error code length */
}
err_code; /* Error detection method and */
/* length of error detection */
/* code */
u_long offset; /* Byte address of the first */
/* data byte in partition */
u_long size; /* Number of data bytes in */
/* this partition */
union
{
struct
{
u_short block_size; /* Block size */
u_long blocks; /* Number of data blocks */
u_long err_loc; /* Location of the error */
/* detection code */
u_char bar; /* Base Address Register */
/* Indicator */
}
disk; /* Disk like regions */
struct
{
u_char flags; /* Various flags */
u_char reserved; /* Reserved */
u_long addr; /* Physical address at which */
/* this memory partition */
/* should be mapped */
u_long err_loc; /* Location of the error */
/* detection code */
u_char bar; /* Base Address Register */
/* Indicator */
}
memory; /* Memory like regions */
}
info; /* Additional information, */
/* interpreted based on value */
/* of 'type' field */
}
pcmcia_cs_tuple_format_t;
PCMCIA_CS_TUPLE_GEOMETRY
typedef struct pcmcia_cs_tuple_geometry_s
{
u_char sectors; /* Sectors per track */
u_char tracks; /* Tracks per cylinder */
u_char cylinders; /* Total number of cylinders */
}
pcmcia_cs_tuple_geometry_t;
PCMCIA_CS_TUPLE_BYTEORDER
typedef struct pcmcia_cs_tuple_byteorder_s
{
u_char byteorder; /* Byte order code */
u_char bytemap; /* Byte mapping code */
}
pcmcia_cs_tuple_byteorder_t;
PCMCIA_CS_TUPLE_DATE
typedef struct pcmcia_cs_tuple_date_s
{
struct
{
u_char seconds; /* Seconds */
u_char minutes; /* Minutes */
u_char hours; /* Hours */
}
time; /* The time at which the card */
/* was initialized */
struct
{
u_char day; /* Day */
u_char month; /* Month */
u_char year; /* Year */
}
day; /* The date the card was */
/* initialized */
}
pcmcia_cs_tuple_date_t;
PCMCIA_CS_TUPLE_BATTERY
typedef struct pcmcia_cs_tuple_battery_s
{
struct
{
u_char seconds; /* Seconds */
u_char minutes; /* Minutes */
u_char hours; /* Hours */
}
rday; /* The date on which the */
/* battery was last replaced */
struct
{
u_char seconds; /* Seconds */
u_char minutes; /* Minutes */
u_char hours; /* Hours */
}
xday; /* The date on which the */
/* battery should be replaced */
}
pcmcia_cs_tuple_battery_t;
PCMCIA_CS_TUPLE_ORG
typedef struct pcmcia_cs_tuple_org_s
{
u_char type; /* Data organization code */
u_char fs_info[MAX_STRING_LEN];
/* Text description of this */
/* organization */
}
pcmcia_cs_tuple_org_t;
PCMCIA_CS_TUPLE_SPCL
typedef struct pcmcia_cs_tuple_spcl_s
{
u_long id; /* PCMCIA or JEIDA assigned */
/* value */
u_char seq; /* Tuple number in sequence */
u_char data[MAX_DATA_SIZE];
/* The data component */
u_char size; /* Size of data */
}
pcmcia_cs_tuple_spcl_t;

EXAMPLE

pcmcia_cs_tuple_data_t tuple_data;

tuple.socket = 0;
tuple.code = PCMCIA_CS_TUPLE_VERS_1;
res = CardServices( GetFirstTuple, handle, (void *)0, sizeof( tuple ), &tuple );
if ( res == PCMCIA_CS_SUCCESS )
{
res = CardServices( ParseTuple, handle, &tuple, sizeof( tuple_data ),
&tuple_data );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "CARD DETECTED: v%d.%d\n", tuple_data.vers_1.major,
tuple_data.vers_1.minor );
cprintf( " %s\n", tuple_data.vers_1.manf_name );
cprintf( " %s\n", tuple_data.vers_1.prod_name );
cprintf( " %s\n", tuple_data.vers_1.lot_info );
cprintf( " %s\n", tuple_data.vers_1.prog_info );
}
}

RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.

RegisterClient

The RegisterClient service registers a client with Card Services. ArgPointer must be a pointer to a pcmcia_cs_register_t structure. The client callback handler entry point is passed in Pointer. If the Handle argument is not NULL, the service places the new client handle into the location pointed by Handle.

The pcmcia_cs_register_t structure is defined as follows:

typedef struct pcmcia_cs_register_s
{
int attributes; /* bit-mapped client attributes */
int event_mask; /* notification events */
void * client_data; /* user-specific client */
}
pcmcia_cs_register_t;

where:

attributes
Are bit mapped client attributes. Bit mapped client attributes are bitwise combinations of the followings constants:
· PCMCIA_CS_ATTR_MEM - Memory client device driver
· PCMCIA_CS_ATTR_MTD - Memory technology driver
· PCMCIA_CS_ATTR_IO - I/O client device driver
· PCMCIA_CS_ATTR_INSERT - If specified, the client receives an artificial PCMCIA_CS_EVENT_INSERTION event for every socket that contains a PC Card.
event_mask
Are events of which to notify the client - A bitwise combination of event codes.
client_data
Is user-specific data.

EXAMPLE
pcmcia_cs_register_t reg;

reg.attributes = PCMCIA_CS_ATTR_IO | PCMCIA_CS_ATTR_INSERT;
reg.event_mask = PCMCIA_CS_EVENT_INSERTION;
reg.client_data = NULL;
res = CardServices( RegisterClient, NULL, callback, sizeof( reg ), &reg );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Registration complete\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_ATTRIBUTE
Incorrect client type.

ReleaseConfiguration

ReleaseConfiguration service returns a PC Card and its socket to a simple interface and configuration zero. ArgPointer must be a pointer to a pcmcia_cs_release_config_t structure.

The pcmcia_cs_release_config_t structure is defined as follows:

typedef struct pcmcia_cs_release_config_s
{
int socket; /* logical socket */
}
pcmcia_cs_release_config_t;

where:

socket Is a logical socket.
EXAMPLE
pcmcia_cs_release_config_t release;

release.socket = 0;
res = CardServices( ReleaseConfiguration, NULL, NULL, sizeof( release ),
&release );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Configuration released\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.

ReleaseIO

The ReleaseIO service releases the I/O addresses requested with the RequestIO service. Only the Card Services resource database is modified by a call to this service. No changes are made in the socket adapter. ArgPointer must be a pointer to a pcmcia_cs_release_io_t structure.

The pcmcia_cs_release_io_t structure is defined as follows:

typedef struct pcmcia_cs_release_io_s
{
int socket; /* logical socket */
}
pcmcia_cs_release_io_t;

where:

socket Is a logical socket.
EXAMPLE
pcmcia_cs_release_io_t release;

release.socket = 0;
res = CardServices( ReleaseIO, NULL, NULL, sizeof( release ),
&release );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "IO released\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.

ReleaseIRQ

The ReleaseIRQ service releases a previously allocated interrupt line. Only the Card Services resource database is modified by a call to this service. No changes are made in the socket adapter. The ArgPointer must be a pointer to a pcmcia_cs_release_irq_t structure.

The pcmcia_cs_release_irq_t structure is defined as follows:

typedef struct pcmcia_cs_release_irq_s
{
int socket; /* logical socket */
}
pcmcia_cs_release_irq_t;

where:

socket Is a logical socket.
EXAMPLE
pcmcia_cs_release_irq_t release;

release.socket = 0;
res = CardServices( ReleaseIRQ, NULL, NULL, sizeof( release ),
&release );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "IRQ released\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.

RequestConfiguration

RequestConfiguration service configures the PC Card and socket. ArgPointer must be a pointer to a pcmcia_cs_request_config_t structure.

The pcmcia_cs_request_config_t structure is defined as follows:

typedef struct pcmcia_cs_request_config_s
{
int socket; /* logical socket */
int vcc; /* Vcc settings */
int vpp; /* Vpp settings */
int int_type; /* interface type */
unsigned char status; /* Card Status register settings */
unsigned char pin; /* Card Pin register settings */
unsigned char copy; /* Card Copy register settings */
unsigned char option; /* Card Option register settings */
int present; /* Card Configuration registers present */
}
pcmcia_cs_request_config_t;

where:

socket
Is a logical socket.
vcc
Is the Vcc setting. The voltage is expressed in tenths of a volt.
vpp
Is the Vpp setting. The voltage is expressed in tenths of a volt.
int_type
Is the interface type. Must be set to:
· PCMCIA_CS_INTERFACE_NONE - Is for the simplest interface, featuring only card detection.
· PCMCIA_CS_INTERFACE_MEM - Is for memory only interface.
· PCMCIA_CS_INTERFACE_IO - Is for memory and I/O interface.
status
Is the Card Status register settings, if present.
pin
Is the Card Pin register settings, if present.
copy
Is the Card Socket/Copy register settings, if present.
option
Is the Card Option register settings, if present.
present
Specifies Card Configuration registers present. present is a bitwise combination of the following constants:
· PCMCIA_CS_PRESENT_STATUS - The status register is present.
· PCMCIA_CS_PRESENT_PIN - The pin register is present.
· PCMCIA_CS_PRESENT_COPY - The copy register is present.
· PCMCIA_CS_PRESENT_OPTION - The option register is present.
Only those registers that are specified using this field are set.

EXAMPLE
pcmcia_cs_request_config_t req;

req.socket = 0;
req.vcc = 50;
req.vpp = 50;
req.int_type = PCMCIA_CS_INTERFACE_MEM;
req.present = 0;
res = CardServices( RequestConfiguration, NULL, NULL, sizeof( req ), &req );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "Configuration succeeded\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_CONFIGURATION_LOCKED
The RequestConfiguration service has already been called for this socket but a matching ReleaseConfiguration has not.
PCMCIA_CS_NO_CARD
No PC Card in socket.

RequestIO

The RequestIO service reserves the specified I/O range for later assignment using the RequestConfiguration service. ArgPointer must be a pointer to a pcmcia_cs_request_io_t structure.

The pcmcia_cs_request_io_t structure is defined as follows:

typedef struct pcmcia_cs_request_io_s
{
int socket; /* logical socket */
unsigned base_port1; /* base port address for range */
int num_ports1; /* number of contiguous ports */
int attributes1; /* bit-mapped port attributes */
unsigned base_port2; /* base port address for range */
int num_ports2; /* number of contiguous ports */
int attributes2; /* bit-mapped port attributes */
}
pcmcia_cs_request_io_t;

where

socket
Is a logical socket.
base_port1
Is the base port number for I/O window 1.
num_ports1
Is the number of contiguous ports in I/O window 1.
attributes1
If set to PCMCIA_CS_IO_ATTR_8BIT, the I/O window has an 8 bit width.
base_port2
Is the base port number for I/O window 2.
num_ports2
Is the number of contiguous ports in I/O window 2.
attributes2
If set to PCMCIA_CS_IO_ATTR_8BIT, the I/O window has an 8 bit width.

EXAMPLE
pcmcia_cs_request_io_t req;

req.socket = 0;
req.base_port1 = 0x3f0;
req.num_ports1 = 32;
req.attributes1 = 0;
req.base_port2 = 0x1f0;
req.num_ports2 = 4;
req.attributes1 = 0;
res = CardServices( RequestIO, NULL, NULL, sizeof( req ), &req );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "I/O range request successful\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_CONFIGURATION_LOCKED
The RequestConfiguration service has already been called for this socket but a matching ReleaseConfiguration has not.
PCMCIA_CS_OUT_OF_RESOURCE
Requested I/O window is already in use.

RequestIRQ

The RequestIRQ service reserves the specified IRQ line for later assignment using the RequestConfiguration service. The ArgPointer must be a pointer to a pcmcia_cs_request_irq_t structure.

The pcmcia_cs_request_irq_t structure is defined as follows:

typedef struct pcmcia_cs_request_irq_s
{
int socket; /* logical socket */
int assigned_irq; /* irq assigned to PC Card */
}
pcmcia_cs_request_irq_t;

where:

socket
Is a logical socket.
assigned_irq
Is the IRQ line.

EXAMPLE
pcmcia_cs_request_irq_t req;

req.socket = 0;
req.assigned_irq = 14;
res = CardServices( RequestIRQ, NULL, NULL, sizeof( req ), &req );

if ( res == PCMCIA_CS_SUCCESS )
{
cprintf( "IRQ request successful\n" );
}
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.
PCMCIA_CS_BAD_ARG_LENGTH
ArgLength is invalid.
PCMCIA_CS_BAD_SOCKET
Specified socket is invalid.
PCMCIA_CS_CONFIGURATION_LOCKED
The RequestConfiguration service has already been called for this socket but a matching ReleaseConfiguration has not.
PCMCIA_CS_OUT_OF_RESOURCE
Requested I/O window is already in use.

ServiceName

ServiceName service returns a character string corresponding to a specified request code. ArgPointer must be a pointer to a pcmcia_cs_name_t structure.

The pcmcia_cs_name_t structure is defined as follows:

typedef struct pcmcia_cs_name_s
{
int code;
char * name;
}
pcmcia_cs_name_t;

where

code
Is the request code.
name
Is a pointer to a string containing the request name.

EXAMPLE
pcmcia_cs_name_t name;
name.code = GetConfigurationInfo;
CardServices( ServiceName, NULL, NULL, 0, &name );

/* should print GetConfigurationInfo */
cprintf( "code 0x%x, name %s\n", name.code, name.name );
RETURN CODES

PCMCIA_CS_SUCCESS
Request succeeded.
PCMCIA_CS_UNSUPPORTED_SERVICE
Service is not supported.

PC Card Support

PC Card Support is a facility that enables the use of PC Card (PCMCIA) devices in the LynxOS environment. Features supported by the PC Card subsystem include:

Installing and Removing PC Card Support

.PC Card Support can be installed and removed after initial installation of LynxOS.

To install PC Card Support enter the following commands:

cd /sys/lynx.os
make install.pcmcia

To remove PC Card Support enter the following commands:

cd /sys/lynx.os
make uninstall.pcmcia

PC Card Support Architecture

The LynxOS PC Card subsystem is based upon the PCMCIA/JEIDA PC Card architecture specification. It has three main layers (see figure below). At the lowest level is Socket Services. The next level is Card Services. Layered on the top of Card Services are client device drivers. All these components are kernel entities. User mode applications interact with PC Card devices and the PC Card subsystem using interfaces defined by client device drivers.

PC Card Support Architecture

Socket Services

Socket Services provides a standardized interface to manipulate PC Cards, sockets and adapters.

Host systems may have more than one PC Card adapter present. Each adapter has its own Socket Services. All instances of Socket Services are intended to support a single instance of Card Services. A socket service registers with Card Services and notifies it of status changes on PC Cards or in sockets.

By making all accesses to adapters, sockets, and PC Cards through the socket services interface, higher-level software is unaffected by different implementations of the hardware. Only hardware-specific socket services implementations must be modified to accommodate any different hardware implementations.

LynxOS PC Card Support implements socket services as an ordinary device driver. Refer to "Writing PC Card Socket Services" for a detailed discussion of interfaces defined by Socket Services and for information on how to develop a new socket service.

Card Services

Above the Socket Services layer is the Card Services layer. Card Services coordinates accesses to PC Cards, sockets, and system resources among multiple clients. There is only one instance of Card Services in the system.

Card Services makes all accesses to the hardware level through the Socket Services interface. All Socket Services status change reporting is routed to Card Services. Card Services then notifies the appropriate clients. Card Services preserves for its clients an abstract, hardware-independent view of a card and associated system resources.

LynxOS PC Card Support implements the Card Services as an ordinary device driver. Refer to "Writing PC Card Socket Services"" for a detailed discussion of interfaces defined by Card Services.

Client Device Drivers

Client Device Drivers refers to all users of Card Services. In a LynxOS PC Card subsystem, users of Card Services are devices drivers that use the standardized API CardServices() to manipulate PC Cards, sockets, and adapters.

PC Card Enabler

LynxOS PC Card support includes a special client device driver called the PC Card Enabler. This driver responds to runtime insertion and removal events and provides the following services to the rest of the system:

Refer to pcmcia_enabler(4) man page for a detailed description of the PC Card Enabler.

PC Card Utilities

LynxOS PC Card support includes the following utilities:

For a complete discussion of each utility, refer to an appropriate man page.

Using a PC Card

When a supported PC Card is inserted before system boot, it is automatically configured by the PC Card Enabler. It can then be accessed as an ISA device using the existing device driver.

Supported Cards

The following PC Cards are supported by the PC Card Enabler and work with the specified standard LynxOS driver:

Supported PC Cards
PC Card
Driver for x86
Driver for MPC860
3Com 3C589x EtherLinkIII Ethernet adapter
if_3c5x9
if_3c5x9
Adaptec SlimSCSI SCSI adapter
sim1522
sim1522_8xx
EigerStar ATA Hard Disk
ide
ide

Hot Swapping

Hot swapping is used to refer to the ability of PC Cards to be inserted and removed when power is applied to the machine and OS is running, and the ability of the system to automatically detect and react to configuration changes.

When a card is being inserted on a running system, it is handled by the PC Card Enabler exactly the same way as a card inserted to a socket prior to boot. If the card is supported, it is configured as specified in the PC Card Enabler configuration tables.

There are two ways to automatically install an appropriate device driver in response to card insertion.

One way is to use the PC Card Enabler static driver installation feature. It allows for an automatic call to the device driver install entry point function of a static driver that failed to install a major device at the boot time due to the absence of a device. Because the PC Card Enabler calls the install entry point after the PC Card device has been inserted and configured on the I/O bus, the driver can successfully create an appropriate major device and return success, thus making the PC Card device available for the device driver operations.

Information about statically linked device drivers supported by the PC Card subsystem is located in the configuration file /sys/devices/pcmcia_enabler_info.c. Please refer to pcmcia_enabler(4) man page for a detailed description of the PC Card Enabler facility.

The second way is to use pcmcia_d daemon program. This daemon program responds to card insertion events, and acts according to the configuration data in the configuration files. The key responsibility of pcmcia_d is to dynamically install an appropriate device driver, create a device node, and invoke an optional script configuring the PC Card for operation in the system. For instance, the script can mount an inserted PC Card disk as a LynxOS file system. Please refer to pcmcia_d(1) man page for a detailed description of the pcmcia_d daemon.

It is possible to remove a PC Card from a running system. Prior to removal, call the pcmcia_shu utility to prepare the socket for card removal. pcmcia_shu is responsible for ensuring that no device driver is accessing the device being removed. pcmcia_shu interacts with the PC Card Enabler and pcmcia_d to handle the removal request. An attempt to deinstall the driver is made. In addition, if the driver has been deinstalled by the pcmcia_d daemon, the daemon calls an optional user script that removes the device special node.

Request to remove a PC Card device may fail, for example, if the PC Card disk being removed is mounted as a file system. Appropriate steps must be taken to ensure that the PC Card removed is not used by any application. Removing a card without a successful card shutdown may cause a system crash.

Adding Support for a New PC Card

You can add support for a new PC Card by adding support to the PC Card Enabler configuration tables or by developing of a new client device driver.

Adding Support to PC Card Enabler

To add support for a new card, add a new entry to the PC Card Enabler configuration table. The required information includes the manufacturer and product identification numbers from the card MANFID tuple, Configuration Table Entry index, and the configuration to which the entry corresponds.

You can use the pcmcia_info utility to find out various information about the PC Card. For instance, if the PC Card device is inserted into the first PCMCIA socket, pcmcia_info creates a display similar to one shown below:

lynx1# pcmcia_info 0
Card in socket #0 : [ 0x0106 0x0000 ]

Current configuration:
I/O range 1: 0x1f0 0x8
I/O range 2: 0x3f6 0x1
IRQ: 46

+-------+------------+------------+-------+
| Index | Range1 | Range2 | Width |
+-------+------------+------------+-------+
| 0x01 | N * 0x10 | n/a | 16 |
| 0x02 | 0x1f0 0x08 | 0x3f6 0x01 | 16 |
| *0x03 | 0x170 0x08 | 0x376 0x01 | 16 |
+-------+------------+------------+-------+

The first line indicates that there is a PC Card device found in the PCMCIA socket, and its manufacturer and product identification numbers are 0x0106 and 0x0000 respectively.

The table shows correspondence between a Configuration Table Entry and I/O ranges used by the particular configuration. Choose an entry with the configuration most appropriate for the host system.

To add a new entry to the PC Card Enabler configuration table, use the information obtained using pcmcia_info to define an entry corresponding to the new PC Card device. A detailed description of the PC Card Enabler configuration table format is available in pcmcia_enabler(4) man page.

Next configure the existing LynxOS driver capable of controlling the ISA device. Configure the driver to ensure that it uses I/O ranges and IRQ line identical to those specified in the PC Card Enabler configuration table.

Create New Device Driver

A new device driver should be a regular device driver using the Card Services API to detect, identify, and configure the PC Card prior to any normal mode accesses to the device. Refer to "Writing PC Card Socket Services" for a detailed specification of the Card Services API.

Adding Support for a New PCMCIA Adapter

Adding support for a new PCMCIA adapter involves development of a new Socket Services device driver. No changes to other components of the PC Card Support software are necessary. Refer to "Writing PC Card Socket Services" for a detailed specification of the Socket Services API and information on how to develop a new Socket Services driver.

Supported PCMCIA Adapters

The following PCMCIA adapters are supported by the LynxOS PC Card subsystem:

Supported PCMCIA Adapters  
PCMCIA Adapter
Architecture
Embedded RPXL823 PCMCIA Interface
RPXL823
i82365 compatible ISA/PCI PCMCIA Adapter
x86 adapters

Troubleshooting

This section provides troubleshooting tips that support the EtherLinkIII PC Card on the x86 platform.

  1. Check that Socket Services information structure contains the correct information about the PCMCIA adapter(s) installed in your system:

Open the /sys/devices/pcmcia_ss_pci_info.c file. Find the description of your adapter(s) in the sspci_known_adapters array. The current revision of the driver has only two entries - one for the O2Micro OZ6860 adapter, another for all other i82365-compatible adapters. All adapters other than OZ6860 are configured in the ISA legacy mode. If you are having problems with your adapter, try to increase the verbosity level by setting the SSPCI_FLAG_VERBOSE flag in the attributes field of the adapter entry. Additional debug information may help to understand the problem. Note that the debug output is sent to COM2. Another field that you might want to change in the Socket Services information file is the interrupt delivery mode. Refer to the next troubleshooting tip for details. Note the possible ISA locations table. You can add ISA port address to the sspci_isa_locations array, if you know that your adapter uses an alternate ISA port.
Modify the file as necessary and rebuild the Socket Services device and the kernel.
  1. Check the IRQ numbers and I/O addresses in the Enabler table and in the EtherLinkIII device information file are the same and are not in use by some other device:

Open /sys/devices/pcmcia_enabler_info.c. Find the following entry in the pcmcia_enabler_card_table_cfg structure:
{
  0x101, 0x589,       /* 3COM 3c589x cards */

  #ifdef __x86__
    0x110, 0x10, 16,
  #else
    0x220, 0x10, 16,  /* 0x220-0x230 */
  #endif

  0x0, 0x0, 0x0,      /* unused */
  0x1 | 0x40,         /* config index 1 */
                      /* level mode intrs */
  #ifdef __x86__
    10
  #else
    9                 /* IRQ 9 */
  #endif

},
The first two fields identify the card. The third field is the base I/O address of the card. The last field is the IRQ number assigned to the card. Note that 32 is not added to the IRQ number.
Open /sys/devices/if_3c589x_pcmcia_info.c. Observe the following structure:
struct if_3c5x9_info if_3c589x_pcmcia_info = {
0x110,
32 + 10,
0, /* (EISA only) slot number, ISA set to zero */
0, /* TP = 0, AUI = 1, BNC = 3 */
3 /* bus type, ISA = 1, EISA = 2, PCMCIA = 3 */
};
The first field of the structure is the base I/O address of the device. The second field is the IRQ number. Note that here, 32 is added to the IRQ number. The assigned IRQ number must be the same in both files, and not in use by any other device. The I/O address must also be the same in both files. The I/O range used by the EtherLinkIII card must not overlap with I/O ranges used by other devices.
Unfortunately, there is no simple way to determine the IRQ numbers and I/O ranges are already in use. The device information files for all configured devices have to be examined. As a starting point, try the following configurations:
- For a laptop computer: I/O address = 0x110, IRQ = 10.
- For a desktop computer: I/O address = 0x220, IRQ = 9,12,15.
It is also possible that different values have to be used. Note that the I/O range must start at the 16 byte boundary. For example, 0x220 and 0x230 are valid, while 0x223 and 0x228 are not.
If no IRQ and base address combination works for the card, try to enable the PC Card I/O interrupts emulation mode in the Socket Services driver. To enable emulation, modify /sys/devices/pcmcia_ss_pci_info.c.
Find in the supported adapters table the entry containing information about the PCMCIA adapter, and add the SSPCI_FLAG_EMU flag to the attributes field.
To change the configuration edit the appropriate files, rebuild the device information files and the kernel. For example:
# cd /sys/devices
# vi pcmcia_enabler_info.c
Make necessary corrections.
# vi if_3c589x_pcmcia_info.c
Make necessary corrections.
# make install
# cd /sys/lynx.os
# make install
# cd /dev
# mknod -a /etc/nodetab
  1. Shut down the host computer. Remove all PC Cards from the PCMCIA sockets. Insert the EtherLinkIII PC Card into PCMCIA socket #0. Boot.

If the system hangs, go to troubleshooting tip 2 and change the values of IRQ number, I/O address, or both. Start with IRQ number the I/O address. IRQ 9,10,11,12,15 are good examples.
  1. Execute:

# ls -1 /dev/pcmcia* /dev/el_pc
The following lines should be present in the output:
/dev/el_pc
/dev/pcmcia_enabler

If any of the above nodes is not present, check CONFIG.TBL and make sure that all listed devices are installed. Rebuild the kernel if necessary. Rebuild the contents of /dev directory from /etc/nodetab using the following commands:
# cd /dev
# mknod -a /etc/nodetab
  1. Execute:

# devices | grep -i "pcmcia \| CardBus/i82365"
The output should be similar to the following:

devices Command Output
35    char   36     0     db27d6d8       0     pcmcia CS
36    char   37     0     0              0     CardBus/i82365
SS
37    char   38     0     db280178       0     PCMCIA Enabler


Possible mismatches are explained below:
- Some of the devices are not present. Check CONFIG.TBL and make sure that all listed devices are installed. Rebuild the kernel if necessary.
- All devices are present, but "PCI CardBus SS" is not installed ((no dev) value in device start address column). Make sure that a PCMCIA adapter is present in the system and that it is i82365-compatible. This package does not support other types of PCMCIA adapters. If you are using an adapter other than OZ6860, make sure that the appropriate ISA port is listed in the possible ISA locations table in the Socket Services information file. Also ensure that the device configuration files are listed in CONFIG.TBL and are in proper order. Rebuild the kernel if necessary.
- All devices are present, but "pcmcia CS" or "PCMCIA Enabler" is not installed ((no dev) value in device start address column). Make sure that device configuration files are listed in CONFIG.TBL and are in proper order. Rebuild the kernel if necessary.
  1. Execute:

# pcmcia_info
You should see a table of the following format:
+----------+---------+------------+--------+--------+
| Socket # | Present | Configured | Code | Card |
+----------+---------+------------+--------+--------+
| 0*| Yes | Yes | 0x0101 | 0x0589 |
| 1 | No | No | n/a | n/a |
+----------+---------+------------+--------+--------+
Possible mismatches are explained below:
- Message "failed to open file /dev/pcmcia_enabler". Rebuild the contents of /dev from /etc/nodetab using the commands:
# cd /dev
# mknod -a /etc/nodetab
- The table shown by the pcmcia_info utility is empty. Make sure that a PCMCIA adapter is present in the system and that it is i82365-compatible. This package does not support other types of PCMCIA adapters. If you are using an adapter other than OZ6860, make sure that the appropriate ISA port is listed in the possible ISA locations table in the Socket Services information file.
- The card is not marked as present. Check that the card is properly installed in the socket.
- The card is not marked as configured. There is no description for this card in Card Enabler's information table. Check that Code and Card values provided by pcmcia_info match the values for the 3C589C card in the Card Enabler information file. These values should be equal to 0x0101 and 0x0589 respectively. If pcmcia_info gives different values, the wrong card is inserted. Also try different IRQ and I/O address settings (see Step 2).
  1. Execute:

# pcmcia_info 0

This command gives more information about a PC Card in socket #0.

The sample output is given below:

Card in socket #0 : [ 0x0101 0x0589 ]

Current configuration:
I/O range 1: 0x110 0x10
I/O range 2: n/a
IRQ: 9

+-------+------------+------------+-------+
| Index | Range1 | Range2 | Width |
+-------+------------+------------+-------+
| *0x01 | N * 0x10 | n/a | 16 |
+-------+------------+------------+-------+

Note the Current configuration section of the output. The values of I/O range 1 and IRQ should match the corresponding values in if_3c589x_pcmcia_info.c. If this is not so, correct if_3c589x_pcmcia_info.c or the card descriptions table in the Card Enabler information file as described in Step 2.

  1. Execute:

# devices | grep el_pc
The output should be similar to the following:
38 char 39 0 db2802b8 0 el_pc
If there is no el_pc device listed, check that the line I:3c589x_pcmcia.cfg is present in CONFIG.TBL file.
If el_pc device is present but not installed ((no dev) value in the device start address column), check that IRQ value and I/O base address are the same in the output of pcmcia_info 0 command and in the if_3c589x_pcmcia_info.c file.
Also make sure that the line I:3c589x_pcmcia.cfg has been placed in CONFIG.TBL after the three lines describing the PCMCIA devices (I:pcmcia_cs.cfg, I:pcmcia_ss_pci.cfg, I:pcmcia_enabler.cfg).
Try different IRQ and I/O address settings (see Step 2).

Writing PC Card Socket Services

Socket Services is defined as a device driver that interfaces to the Card Services module and implements hardware-specific details of programming a specific PCMCIA adapter. The interface between Card Services and Socket Services is defined by a set of driver entry points and data structures, described in the following sections.

Socket Services Overview

Socket Services is the lower layer in the PC Card Support subsystem. Socket Services provides a unified software interface to the PCMCIA sockets hardware. It masks the hardware implementation details, providing an abstraction layer that allows for development of higher-level software without explicit knowledge of the underlying hardware interfaces.

Socket Services handles the hardware as a number of objects of different types. A PCMCIA adapter is the hardware that connects a host system bus to PC Card sockets. A host system may have more than one adapter. There is one instance of Socket Services for each adapter present in the system. Socket Services reports the number of sockets and windows implemented by the adapter it services. An adapter has one or more sockets. Sockets are receptacles for PC Cards and the source of status change events. A range in the PC Card memory or I/O address space can be mapped into the host system space through a window. Most adapters provide a limited number of windows and each window has different mapping capabilities. Socket Services reports the characteristics of each window to the higher-level PC Card Support layers.

Socket Services Groups

The Socket Services interface can be divided into three functional groups of services.

Adapter Services

Socket Services controls the adapter using the following SS_GetInfo service.

Socket Services

Socket Services controls sockets using the following services:

Window Services

Socket Services controls windows using the following services:

Socket Services Structure

LynxOS PC Card Support implements a Socket Services as an ordinary device driver. A Socket Services registers with Card Services at installation. As soon as the registration is complete, the Socket Services resources are available to Card Services and its clients. Socket Services drivers should be installed after Card Services, but before any client device drivers.

Header Files

All prototypes and constants needed to implement the Socket Services interface are defined in the following header files:

Socket Services Header Files  
Header File
Description
/sys/dheaders/pcmcia_ss.h
Contains definitions of the Socket Services interface.
/sys/dheaders/pcmcia_cs_ss.h
Contains prototypes for the Socket Services callback, registration entry point, and event notification entry point.

Registration

To register with Card Services, a Socket Services calls the pcmcia_cs_register_ss function, passing all necessary registration data as the parameters. The registration data consists of a callback entry point and user specific data to be passed to the callback:

id = pcmcia_cs_register_ss( callback, statics_ptr );

pcmcia_cs_register_ss returns a Socket Services identification number. The Socket Services identification number is passed back to Card Services when Socket Services notifies it of a status change event. If registration fails, pcmcia_cs_register_ss returns -1.

Event Notification

Socket Services intercepts status changes and reports them to Card Services. Status change detection can be interrupt-driven or polled, depending on the hardware features of the PCMCIA adapter. If the adapter supports interrupt-driven delivery of status change events, Socket Services should install an interrupt handler and process status change interrupts within the handler. If the adapter does not implement an interrupt for the status change events, Socket Services should use a polling based technique to detect status changes in the PCMCIA sockets.

Socket Services reports a status change event to Card Services by calling the pcmcia_cs_event entry point. Socket status, socket number, and Socket Services identification number obtained at registration time must be passed as the parameters. For example:

pcmcia_cs_event( status, socket, id );

Socket Services Callback

Card Services invokes a Socket Services through the callback interface. The callback entry point is provided by Socket Services at the registration time.

The callback routine has the following syntax:

int callback( void * stat, int service, int Number, void * ArgPointer );

where:

stat
Is the user-specific data registered through pcmcia_cs_register_ss.
service
Specifies the service code.
Number
Identifies an object on which to manipulate. Must be either a window or socket number, depending on the service.
ArgPointer
Is service-specific data.

Each service must return one of the following constants:

PCMCIA_SS_SUCCESS
Request succeeded.
PCMCIA_SS_UNSUPPORTED
Service or feature is not supported.
PCMICA_SS_BAD_VOLTAGE
Voltage specified for the SS_SetSocket request cannot be applied.

Socket Services Reference

SS_GetInfo

The SS_GetInfo service returns information about the PCMCIA adapter and the Socket Services. ArgPointer must be a pointer to a pcmcia_ss_information_t structure.

The pcmcia_ss_information_t structure is defined as follows:

typedef struct pcmcia_ss_information_s
{
int revision; /* version */
int sockets_num; /* number of sockets */
int windows_num; /* number of windows */
char * name; /* HBA name */
char * vendor; /* vendor */
}
pcmcia_ss_information_t;

where:

revision
Is the binary coded decimal (BCD) value of the SS version number.
sockets_num
Specifies the number of sockets.
windows_num
Specifies the number of windows.
name
Is the PCMCIA adapter name.
vendor
Is the vendor-specific string.

SS_InquireSocket

The SS_InquireSocket service returns the read-only information about the specified socket. Number must be set to the socket number. ArgPointer must be a pointer to a pcmcia_ss_inquire_socket_t structure.

The pcmcia_ss_inquire_socket_t structure is defined as follows:

typedef struct pcmcia_ss_inquire_socket_s
{
int status;
}
pcmcia_ss_inquire_socket_t;

where:

status
Is the bit mapped socket status. A bitwise combination of the following constants:
· PCMCIA_SS_STATUS_DETECT - PC Card is present in the socket.
· PCMCIA_SS_STATUS_CHANGE - Status change event in I/O PC Card
· PCMCIA_SS_STATUS_BATTERY_DEAD - Battery dead event in memory PC Card
· PCMCIA_SS_STATUS_BATTERY_LOW - Battery low event in memory PC Card
· PCMCIA_SS_STATUS_READY - Ready event in I/O PC Card

SS_SetSocket

The SS_SetSocket service configures the specified socket. Number must be set to the socket number. ArgPointer must be a pointer to a pcmcia_ss_socket_t structure.

The pcmcia_ss_socket_t structure is defined as follows:

typedef struct pcmcia_ss_socket_s
{
int interface; /* interface type */
int irq; /* assigned IRQ */
int vcc; /* voltage applied to Vcc pin */
int vpp; /* voltage applied to Vpp pins */
}
pcmcia_ss_socket_t;

where:

interface
Is the interface type. This field must be set to one of the following constants:
· PCMCIA_SS_INTERFACE_NONE - Simplest interface, featuring only card detection
· PCMCIA_SS_INTERFACE_MEM - Memory only interface
· PCMCIA_SS_INTERFACE_IO - Memory and I/O interface.
irq
Specifies the IRQ line. A value of 0 means no steering. This field is meaningful only if interface is set to PCMCIA_SS_INTERFACE_IO.
vcc
Is the voltage applied to the Vcc pin. The voltage is defined in tenths of a volt.
vpp
Is the voltage applied to the Vpp pins. The voltage is defined in tenths of a volt.

SS_GetSocket

The SS_GetSocket service returns the configuration of the specified socket. Number must be set to the socket number. ArgPointer must be a pointer to a pcmcia_ss_socket_t structure.

SS_InquireWindow

The SS_InquireWindow service returns the read-only information about the specified window. Number must be set to the window number. ArgPointer must be a pointer to a pcmcia_ss_inquire_window_t structure.

The pcmcia_ss_inquire_window_t structure is defined as follows:

typedef struct pcmcia_ss_inquire_window_s
{
int type; /* supported window types */
int socket; /* bit pattern */

/* io window characteristics */
pcmcia_ss_io_win_chars_t io_chars;

/* memory window characteristics */
pcmcia_ss_memory_win_chars_t memory_chars;
}
pcmcia_ss_inquire_window_t;

where:

type
Specifies the type of the window. Must be a bitwise combination of the following constants:
· PCMCIA_SS_WINDOW_COMMON - memory window
· PCMCIA_SS_WINDOW_ATTR - attribute window
· PCMCIA_SS_WINDOW_IO - I/O window
socket
Specifies sockets to which this window can be assigned. Each bit corresponds to a single socket. The least significant bit corresponds to the socket 0.
io_chars
Specifies window characteristics when used as an I/O window. Currently unused.
memory_chars
Specifies window characteristics when used as a common window. Currently unused.

SS_SetWindow

The SS_SetWindow service configures the specified window. Number must be set to the window number. ArgPointer must be a pointer to a pcmcia_ss_window_t structure.

The pcmcia_ss_window_t structure is defined as follows:

typedef struct pcmcia_ss_window_s
{
int socket; /* socket index */
int type; /* window type (IO/ATTR/COMMON) */
unsigned base; /* card base */
int size; /* in bytes */
int data_width; /* 8 or 16 */
int access_speed; /* access speed for common type */
unsigned offset; /* window offset */
int valid; /* validity flag */
}
pcmcia_ss_window_t;

where:

socket
Is the socket number.
type
Specifies the window type. Must be set to one of the following constants:
· PCMCIA_SS_WINDOW_COMMON - memory window
· PCMCIA_SS_WINDOW_ATTR - attribute window
· PCMCIA_SS_WINDOW_IO - I/O window.
base
Specifies the host base address of the window.
size
Is the number of bytes in the window.
data_width
Is the data width in bits. Must be set to 8 or 16.
access_speed
Specifies the window access speed in nanoseconds. This field is used only if the type field is set to PCMCIA_SS_WINDOW_COMMON.
offset
Is the offset to the window.
valid
Is the window validity flag. If set to zero, the window is disabled.

SS_GetWindow

The SS_GetWindow service gets the configuration of the specified window. Number must be set to the window number. ArgPointer must be a pointer to a pcmcia_ss_window_t structure.



LynuxWorks, Inc.
855 Branham Lane East
San Jose, CA 95138
http://www.lynuxworks.com
1.800.255.5969
TOC PREV NEXT INDEX