Channels ▼
RSS

Embedded Systems

Writing PCMCIA Software

Source Code Accompanies This Article. Download It Now.


JUN94: Writing PCMCIA Software

Programming for portable systems

Troy runs Entertainment Software Partners and can be reached via the Internet at troymiles@delphi.com.


The Personal Computer Memory Card International Association (PCMCIA) 1.0 specification defined a standard for adding 68-pin memory cards to a computer system. PCMCIA 2.0 added support for I/O devices such as modems, pagers, LAN cards, and hard disks. Unlike their ISA and MCA cousins, system- and CPU-independent PCMCIA cards don't have jumpers or dip switches. Instead, they're configured via software and can be inserted and extracted with the system powered.

Nearly all portable DOS machines now include PCMCIA slots. Additionally, both the IBM DOS and OS/2 operating systems include PCMCIA support (and it's rumored that forthcoming versions of Microsoft MS-DOS and Windows will, too). This article examines what's involved in writing PCMCIA software for DOS-based systems.

PCMCIA Hardware Architecture

The first layer of PCMCIA hardware is the socket, a receptacle for a PCMCIA card. There's no limit to the number of sockets a system can have, although one, two, and four are the most common. Two or more sockets are usually joined to an adapter, which is hooked into the system bus. Unlike hard disks or modems, there are no standard I/O addresses used by adapters. Nor are there any standard mappings for the registers on the adapters. All of this is left to the system designer. The adapter allows the card's memory and I/O resources to be mapped into the system under software control. For example, a modem card can be made to appear at any available COM port by executing the appropriate code. PCMCIA cards are about the size of a credit card. Type I cards are the thinnest and are mainly used for memory cards. Type IIs are thicker and used mostly for modems and LANs. Type IIIs are the thickest and are used by rotating hard drives.

PCMCIA cards have both common and attribute on-board memory. Common memory stores data and is usually present only in memory cards. Attribute memory, present on all 2.0-compliant cards, is where information about the card is kept. The card information structure (CIS), beginning at address 0 in attribute memory, consists of a linked list of data blocks called "tuples" which hold information about the type of card and the information the software needs to configure it.

PCMCIA Software Architecture

PCMCIA software consists of socket and card services. Socket services, the lowest layer (similar to BIOS), is written specifically to support a single type of PCMCIA adapter. It is intended to be small and needs minimal RAM, allowing it to be ROMable. Card services, on the other hand, is more like DOS. It never deals directly with the hardware, using socket services, instead. Card services is the API most important to programmers. While it is possible to bypass card services and go directly to socket services, doing so could be dangerous. Card and socket services are tightly synchronized. If this synchronization is lost, a system crash or hardware damage can result. If you make direct calls to socket services, you'd better know what you're doing.

Card Services API

There are 54 card-services functions, divided into five types: client services, resource management, bulk memory, client utilities, and advanced client services. Client-service functions get information from card services. Resource-management functions allocate and free system resources. (This is how PCMCIA card resources are made visible to the rest of the system.) Bulk-memory services are for accessing common memory, and client utilities parse tuple information. Advanced client-service functions get even lower level information from card services.

All of the functions are called with a similar argument. In C, a card-services call has the form: results=CardServices(function, handle, pointer, arglength, argpointer); in which function is a byte that indicates the card-services function number, handle is a word used to send or receive a client handle, and pointer is a far pointer to code or data (for most functions, pointer is NULL). arglength holds the size of the buffer that argpointer points to. argpointer is a far pointer to an argument packet which sends/receives information from card services. If a card-services call is successful, results will be 0; otherwise it holds an error number. Some functions return additional error information in the argument packet.

Since a bad PCMCIA program can damage the hardware, card services does a lot of checking on parameters passed to it. If any of the values are determined to be bad, the function call will fail before any action is taken. It is critical to always check the values card services returns because, unlike normal DOS programming, PCMCIA is dynamic. Hardware can be added and removed from the system at any time. You should never make assumptions about the state of the system.

The Cardinfo Program

The Cardinfo program presented in Listing One (page 152) returns information about cards plugged into the first or second socket of the system. It is written mostly in C, although two functions are written in inline assembly. I've tested Cardinfo on Toshiba, IBM, AST, and Compuadd notebooks, using both Phoenix and SystemSoft PCMCIA software.

The most important function in this program is CardServices, which encapsulates the call to card services with a C-callable function. Under DOS, card services is called via interrupt 0x1A, function 0xAF. The value in AL holds the number of the desired card-services function. Other registers hold the other arguments. Putting this call into a C function and its argument packet in a structure is easier to manage than manipulating bytes in assembly.

GET_CARDSERVICES_INFO is the first call every PCMCIA program should make, since nothing will work without card services. If card services is installed, the return value will be SUCCESS (or 0) and the signature word of the argument packet will be set to CS. Both values must be checked, since other functions use interrupt 0x1A, and any of those can accidentally zero the AX register which holds the return value.

Besides confirming card-services installation, GET_CARDSERVICES_INFO returns the number of PCMCIA sockets, the vendor revision number, and the version of card services. All this information is displayed before the program enters its main loop. In the 2.0 version of card services, sockets were numbered beginning with 1. In version 2.01 and later, socket numbering begins with 0. Cardinfo always begins its numbering with 1. It determines what the base socket is by checking the PCMCIA version.

Since PCMCIA is a dynamic environment, card services provides a callback mechanism for notifying you of card events as they occur. To use the callback, a call is made to REGISTER_CLIENT. The argument packet first contains the attribute which tells card services what kind of client your program is. This allows card services to set your priority level, since there may be more than one client in the system. Priority is given first to I/O clients, then to memory-technology drivers, and finally to memory clients. The Cardinfo program case assumes a memory client which will get notification after all other clients. The next piece of information is the event mask, which tells card services what kind of events you are interested in. We are only interested in detecting changed events, indicated by setting bit 7. The last piece of information is the version of card services the program was written to be compliant with. Since it's compliant with both version 2.0 and 2.01, the program returns the version number it gave us to card services.

If the request for a callback is granted, card services returns with SUCCESS, and ClientHandle will hold the client handle, which is used later to free the callback. Callbacks are a limited system resource, so not all requests will be granted. Be sure to check the value that is returned.

If the callback request is granted, the program enters the information-display loop. The first pass through the loop will force an update by initially setting fCardEvent to True. Afterwards, fCardEvent will be True only after an event occurs.

Card services makes getting informa-tion from a card simple. A call to GET_STATUS will return the state of a socket. If a card is in the socket, the CARD_DETECT_FLAG of the CardState word will be set. The version 1.0 information tuple (CISTPL_VERS_1) contains the manufacturer and product-name strings. The GET_FIRST_TUPLE and GET_TUPLE_DATA card services calls returns these strings in the GetLevel1Info function. The strings themselves will be in a buffer with NULLs separating them and a double NULL marking the end of the buffer.

A call to GetDeviceType is made to determine the type of card. It makes calls to GET_FIRST_TUPLE and GET_TUPLE_DATA also, except the desired tuple is CISTPL_DEVICE. Only memory types are defined. If it is an I/O card, the device type will be DTYPE_NULL or DTYPE_FUNCSPEC. Memory devices also return their size in bytes. If the memory type is DTYPE_SRAM, the state of the device's battery is contained in wState.

The information-display loop continues to wait for card events until the user presses a key. At that point, the callback is free, and the program returns to DOS. If the callback isn't free, card services will call it after the next card event and crash the system.

Conclusion

There are many ways to enhance Cardinfo. For instance, you could have it tell the user what kind of I/O card is being used by comparing the I/O addresses used by the card with those of known PC devices.

Finally, keep in mind that the PCMCIA specification is an open standard. If you'd like more information on it, contact the Personal Computer Memory Card International Association, 1030G E. Duane Ave., Sunnyvale, CA 94086 (408-720-0107).

[LISTING ONE]



//*** CARDINFO.C -- by Troy-Anthony Miles -- A PCMCIA Information Utility ***

#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "cardinfo.h"

#define  MAX_VENDOR_STRING  (80-10)
#define  MAX_SOCKET         2

BYTE  buffer[256], heap[256];
WORD  ClientHandle=0,  fCardEvent=TRUE, bEventType=0;
WORD  wPCMCIAVersion, wVendorVersion, wSockets, wBaseSocket;

DWORD  SizeCodes[] = {
  0x200,    //* 512 bytes
  0x800,    //* 2k
  0x2000,   //* 8k
  0x8000,   //* 32k
  0x20000,  //* 128k
  0x80000,  //* 512k
  0x200000  //* 2m
};
char *OldCard =  "Information Unavailable";
char *strLines[] = {"    product:", "     line 3:", "     line 4:"};
char *strDevices[] = {"ROM","OTPROM","EPROM","EEPROM","FLASH","SRAM","DRAM"};
WORD      CardServices(WORD, WORD, DWORD, WORD, void far *);
WORD      GetLevel1Info(WORD socket, char *buffer);
WORD      GetDeviceType(WORD socket, DWORD *size, char *buffer);
WORD      SetCallbackHandler(void);
void far  Callback(void);
char      *CreateMemoryString(DWORD value);
void      FilterString(char *string);
void      SetCursorPos(WORD x, WORD y);
void      ClearScreen(void);
//*******************************************************************
void  main()
{
  STATUS_INFO *statInfo = (STATUS_INFO *)heap;
  CS_INFO     *csInfo = (CS_INFO *)heap;
  DWORD       dwSize;
  WORD        wState, wStatus, wType;
  ClearScreen();
  SetCursorPos(0, 0);
  puts("CardInfo - A PCMCIA Information Utility");
  //* See if CS is installed and get basic information
  csInfo->Signature = 0;
  wStatus = CardServices(GET_CARDSERVICES_INFO,0,0L,sizeof(CS_INFO),csInfo);
  if(wStatus != SUCCESS || csInfo->Signature != SIGNATURE)
  {
    puts("ERROR: Card Services not installed.");
    return;
  }
  SetCursorPos(0, 2);
  wSockets       = csInfo->Count;
  wVendorVersion = csInfo->Revision;
  wPCMCIAVersion = csInfo->CSLevel;
  //* after v2.0 socket numbering began at 0, before it was 1
  wBaseSocket = (wPCMCIAVersion > 0x200)? 0: 1;
  //* Display the basic information
  printf("PCMCIA version: %X.%02X, Vendor version: %X.%02X, Sockets: %d",
          HIBYTE(wPCMCIAVersion), LOBYTE(wPCMCIAVersion),
          HIBYTE(wVendorVersion), LOBYTE(wVendorVersion), wSockets);
  //* Try to get a callback handle, exit if can't get one
  if(SetCallbackHandler())
  {
    puts("ERROR: Unable to allocate a callback handle.");
    return;
  }
  //* Display the Vendor Information string
  SetCursorPos(0, 3);
  if(csInfo->VStrLen)
  {
    FilterString(csInfo->VendorString);
    printf("Vendor: [%s]", csInfo->VendorString);
  }
  //* This is the information display loop
  do
  {
    //* Wait until a card event occurs
    if(fCardEvent)
    {
      WORD  ndx, wCurrSocket;
      fCardEvent = FALSE;
      //* Display the event
      SetCursorPos(0, 4);
      printf("Last Card Event: 0x%02X", bEventType);
      //* Display info for each socket
      for(wCurrSocket=wBaseSocket, ndx=1;
          ndx <= wSockets && ndx <= MAX_SOCKET;
          wCurrSocket++, ndx++)
      {
        int  iYLine;
        //* Erase the socket information
        for(iYLine=0; iYLine < D_LINES; iYLine++)
        {
          SetCursorPos(0, (ndx-1)*D_LINES + D_Y + iYLine);
          printf("                                                          ");
        }
        //* Get the socket state information
        statInfo->Socket = wCurrSocket;
        CardServices(GET_STATUS, 0, 0L, sizeof(STATUS_INFO), statInfo);
        wState = statInfo->CardState;
        //* Is there a card in the socket?
        if(wState & CARD_DETECT_FLAG)
        {
          WORD  wOffset, wNumLines, wCurrLine;
          //* Display level 1 information
          wNumLines = GetLevel1Info(wCurrSocket, buffer) - 1;
          SetCursorPos(0, (ndx-1)*D_LINES + D_Y);
          printf("   Socket %d: %s",  ndx, buffer);
          //* Loop through and display each line of level 1 info
          for(wOffset=0, wCurrLine=1; wCurrLine < 4; wCurrLine++)
          {
            SetCursorPos(D_X, (ndx-1)*D_LINES + D_Y + wCurrLine);
            printf("%s", strLines[wCurrLine-1]);
            wOffset = strlen(&buffer[wOffset]) + wOffset + 1;
            if(wNumLines)
            {
              printf(" %s", &buffer[wOffset]);
              wNumLines--;
            }
            else
              printf(" %s", "UNDEFINED");
          }
          //* Display type information
          wType = GetDeviceType(wCurrSocket, &dwSize, buffer);
          SetCursorPos(D_X, (ndx-1)*D_LINES + D_Y2 + 0);
          printf("Device Type: %s", buffer);
          //* Only memory cards have size information
          if(wType && wType != DTYPE_FUNCSPEC)
          {
            SetCursorPos(D_X, (ndx-1)*D_LINES + D_Y2 + 1);
            printf("       Size: %s", CreateMemoryString(dwSize));
            printf(", Write Protect: %s",(wState & WRITE_PROTECT)?"ON": "OFF");
            //* Only an SRAM will have a battery
            if(wType == DTYPE_SRAM)
            {
              printf(", Battery: ");
              if(wState & BATTERY_DEAD_FLAG)
                printf("Dead");
              else if(wState & BATTERY_LOW_FLAG)
                printf("Low");
              else
                printf("Okay");
            }
          }
        }
        else
        {
          SetCursorPos(0, (ndx-1)*D_LINES + D_Y);
          printf("   Socket %d: Empty",  ndx);
        }
      }
    }
  }while(!_kbhit());
  //* Flush the keyboard buffer
  while(_kbhit())
    _getch();
  //* Deallocate the callback else CS will crash later
  if(ClientHandle)
    if(CardServices(DEREGISTER_CLIENT, ClientHandle, 0L, 0, 0L))
      puts("ERROR: Unable to free the callback handle.");
  SetCursorPos(0, 23);
}
//*****  Call CS via its interrupt *****
WORD  CardServices(WORD  Function, WORD  Handle, DWORD Pointer,
                                  WORD  ArgLength, void  far *ArgPointer)
{
  WORD  wStatus, wHandle;
  DWORD  pointer;
  _asm
  {
    push  es
    push  di
    push  si
    mov   bx, WORD PTR ArgPointer
    mov   ax, WORD PTR ArgPointer+2
    mov   es, ax
    mov   dx, Handle
    mov   si, WORD PTR Pointer
    mov   di, WORD PTR Pointer+2
    mov   cx, ArgLength
    mov   al, BYTE PTR Function
    mov   ah, CARD_SUBFUNCTION
    int   CARD_INTERRUPT
    mov   wStatus, ax
    mov   wHandle, dx
    mov   WORD PTR pointer, si
    mov   WORD PTR pointer+2, di
    pop   si
    pop   di
    pop   es
  }
  if(Handle && Function == REGISTER_CLIENT)
    *((WORD *)Handle) = wHandle;
  return(wStatus);
}
//*** Receives Card Services callback when a card event occurs sets the flag
//* ENTRY:    AL          - holds the event type
//* EXIT:    AX          - is set to zero to indicate no errors
void far  Callback()
{
  _asm
  {
      push  ds
      mov   bx, SEG fCardEvent        ;get the data segment
      mov   ds, bx
      inc   fCardEvent                ;set the event flag
      mov   BYTE PTR bEventType, al   ;save the event type
      xor   ax, ax
      pop   ds
      clc
  }
}
//*** Get Level one information (manufacturer, product name, etc) from card.
//* ENTRY: socket  - the socket to retrieve the information from
//*        buffer  - a pointer to a buffer which will recieve the info
//*               it should be at least 256 bytes which is the max tuple length
//*  EXIT:   buffer - hold the info strings, separated by '\0'
//*  RETURN: the number of strings in buffer
WORD  GetLevel1Info(WORD socket, char *buffer)
{
  WORD            len, ndx1, ndx2, wStatus1, wStatus2, strCount;
  TUPLE_INFO      *pTup;
  TUPLE_DATA_INFO *pTupData;
  strCount = 0;
  //* We want the level 1 info tuple. Find it with GET_FIRST_TUPLE
  //* Then retrieve its data with GET_TUPLE_DATA
  pTup              = (TUPLE_INFO *)heap;
  pTupData          = (TUPLE_DATA_INFO *)heap;
  pTup->Socket      = socket;
  pTup->Attributes  = 0;
  pTup->DesiredTuple= CISTPL_VERS_1;
  pTup->Reserved    = 0;
  wStatus1 = CardServices(GET_FIRST_TUPLE, 0, 0L, sizeof(TUPLE_INFO), pTup);
  wStatus2 = CardServices(GET_TUPLE_DATA, 0, 0L, sizeof(TUPLE_DATA_INFO),
                                                                    pTupData);
  //* If data was retrieved successfully, sort it out
  if(wStatus1 == SUCCESS && wStatus2 == SUCCESS)
  {
    ndx1 = 2;
    ndx2 = 0;
    while(pTupData->TupleData[ndx1] != 0xFF && strCount < 4)
    {
      strCount++;
      strcpy(&buffer[ndx2], &pTupData->TupleData[ndx1]);
      len = strlen(&pTupData->TupleData[ndx1]) + 1;
      ndx2 += len;
      ndx1 += len;
    }
  }
  //* If an error occurred, Information Unavailable
  else
  {
    strCount++;
    strcpy(buffer, OldCard);
  }
  return(strCount);
}
//*** Retrieves information from the Device Information tuple. If the
//* card is memory, its size is also returned
//* ENTRY: socket  - the socket to retrieve the information from
//*        dwSize  - a pointer to a DWORD which will receive the device's size
//*        buffer  - a pointer to a buffer which will receive the info
//*             it should be at least 256 bytes which is the max tuple length
//*  EXIT: buffer   - hold the type string
//*  RETURN: the device type
WORD  GetDeviceType(WORD  socket, DWORD *dwSize, char  *buffer)
{
  WORD            wStatus1, wStatus2, wType;
  TUPLE_INFO      *pTup;
  TUPLE_DATA_INFO *pTupData;
  *dwSize = 0;
  //* We want the device tuple. Find it with GET_FIRST_TUPLE
  //* Then retrieve its data with GET_TUPLE_DATA
  pTup              = (TUPLE_INFO*)heap;
  pTupData          = (TUPLE_DATA_INFO*)heap;
  pTup->Socket      = socket;
  pTup->Attributes  = 0;
  pTup->DesiredTuple= CISTPL_DEVICE;
  pTup->Reserved    = 0;
  wStatus1 = CardServices(GET_FIRST_TUPLE, 0, 0L, sizeof(TUPLE_INFO), pTup);
  wStatus2 = CardServices(GET_TUPLE_DATA, 0, 0L, sizeof(TUPLE_DATA_INFO),
                                                                   pTupData);
  //* If data was retrieved successfully, sort it out
  if(wStatus1 == SUCCESS && wStatus2 == SUCCESS)
  {
    wType = (WORD)((pTupData->TupleData[0] & 0xF0) >> 4);
    if(wType != DTYPE_NULL)
    {
      if(wType >= DTYPE_ROM && wType <= DTYPE_DRAM)
      {
        strcpy(buffer, strDevices[wType - 1]);
        strcat(buffer, " Memory");
        if(pTupData->TupleData[1] != 0xFF)
        {
          WORD  wSizeCode, wUnits;
          wSizeCode = (WORD)(pTupData->TupleData[1] & 0x07);
          wUnits    = (WORD)(((pTupData->TupleData[1] & 0xF8) >> 3) + 1);
          *dwSize   = (DWORD)(wUnits * SizeCodes[wSizeCode]);
        }
      }
      else if(wType == DTYPE_FUNCSPEC)
      {
        strcpy(buffer, "FUNCTION SPECIFIC");
      }
    }
    else
    {
      strcpy(buffer, "Input/Output");
    }
  }
  else
  {
    strcpy(buffer, OldCard);
    wType = 0;
  }
  return(wType);
}
//*** Sets the callback handler to our callback function.  If status
//* is !0, an error occurred.
//* ENTRY: none
//* EXIT:  none
WORD  SetCallbackHandler(void)
{
  WORD                 wStatus;
  REGISTER_CLIENT_INFO pRC;
  //* We are memory client device driver. We only want card detect events
  //* We want the version, CS it told us it was
  pRC.Attributes = 0x0001;
  pRC.EventMask  = 0x0080;
  pRC.Version    = wPCMCIAVersion;
  wStatus = CardServices(REGISTER_CLIENT, (WORD)&ClientHandle,
             (DWORD)(void far *)Callback, sizeof(REGISTER_CLIENT_INFO), &pRC);
  if(wStatus)
    ClientHandle = 0;
  return(wStatus);
}
//*** Converts a DWORD byte value into an ASCII string containing the
//*    value in normalized byte form
//* ENTRY: value    - holds the byte value to be converted
//* EXIT:
//* RETURN: a pointer to the size string. This string will be overwritten
//*    the next time this function is called
char *CreateMemoryString(DWORD value)
{
  static char line[40];
  if(value < 0x400L)
    sprintf(line, "%ld bytes", value);
  else if(value < 0x100000L)
    sprintf(line, "%ld KB", value / 0x400L);
  else
    sprintf(line, "%ld MB", value / 0x100000L);
  return(line);
}
//*** This function limits a string to MAX_VENDOR_STRING characters and
//*    changes any non-printable characters to '.'
//*  ENTRY: szString    - the string to be filtered
//*  EXIT:  szString    - the string filtered string
void  FilterString(char *szString)
{
  int  ndx;
  for(ndx=0; ndx < MAX_VENDOR_STRING && *szString; ndx++, szString++)
  {
    if(!isprint(*szString))
      *szString = '.';
  }
  *szString = '\0';
}
//*** Set the cursor position using BIOS ***
void SetCursorPos(WORD x, WORD y)
{
  _asm
  {
    mov    ax, 0200h
    mov    bh, 00
    mov    dl, BYTE PTR x
    mov    dh, BYTE PTR y
    int    10h
  }
}
//*** Clear the screen using BIOS ***
void ClearScreen()
{
  _asm
  {
    mov     ax, 0600h
    mov     bx, 0700h
    xor     cx, cx
    mov     dx, (25-1)*100h+(80-1)
    int     10h                          ;Scroll up using BIOS
  }
}
//*** CARDINFO.H -- by Troy-Anthony Miles ***
//* GENERAL DEFINITIONS
typedef unsigned char           BYTE;
typedef unsigned short int      WORD;
typedef unsigned long           DWORD;

#define LOBYTE(w)               ((BYTE)(w))
#define HIBYTE(w)               ((BYTE)(((WORD)(w) >> 8) & 0xFF))
#define LOWORD(l)               ((WORD)(DWORD)(l))
#define HIWORD(l)               ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))
#define  FALSE                  0
#define  TRUE                   1
#define CARD_INTERRUPT          0x1A
#define CARD_SUBFUNCTION        0xAF
#define SIGNATURE               'SC'

//* POSITIONS
#define D_LINES                 7
#define D_Y                     6
#define D_Y2                    (D_Y + 4)
#define D_X                     0

//*  FUNCTION CODES
#define GET_CARDSERVICES_INFO   0x0B
#define REGISTER_CLIENT         0x10
#define DEREGISTER_CLIENT       0x02
#define GET_STATUS              0x0C
#define RESET_CARD              0x11
#define SET_EVENT_MASK          0x31
#define GET_EVENT_MASK          0x2E

#define REQUEST_IO              0x1F
#define RELEASE_IO              0x1B
#define REQUEST_IRQ             0x20
#define RELEASE_IRQ             0x1C
#define REQUEST_WINDOW          0x21
#define RELEASE_WINDOW          0x1D
#define MODIFY_WINDOW           0x17
#define MAP_MEM_PAGE            0x14
#define REQUEST_SOCKET_MASK     0x22
#define RELEASE_SOCKET_MASK     0x2F
#define REQUEST_CONFIGURATION   0x30
#define GET_CONFIGURATION_INFO  0x04
#define MODIFY_CONFIGURATION    0x27
#define RELEASE_CONFIGURATION   0x1E

#define OPEN_MEMORY             0x18
#define READ_MEMORY             0x19
#define WRITE_MEMORY            0x24
#define COPY_MEMORY             0x01
#define REGISTER_ERASE_QUEUE    0x0F
#define CHECK_ERASE_QUEUE       0x26
#define DEREGISTER_ERASE_QUEUE  0x25
#define CLOSE_MEMORY            0x00

#define GET_FIRST_TUPLE         0x07
#define GET_NEXT_TUPLE          0x0A
#define GET_TUPLE_DATA          0x0D
#define GET_FIRST_REGION        0x06
#define GET_NEXT_REGION         0x09
#define GET_FIRST_PARTITION     0x05
#define GET_NEXT_PARTITION      0x08

#define RETURN_SS_ENTRY         0x23
#define MAP_LOG_SOCKET          0x12
#define MAP_PHY_SOCKET          0x15
#define MAP_LOG_WINDOW          0x13
#define MAP_PHY_WINDOW          0x16
#define REGISTER_MTD            0x1A
#define REGISTER_TIMER          0x28
#define SET_REGION              0x29
#define VALIDATE_CIS            0x2B
#define REQUEST_EXCLUSIVE       0x2C
#define RELEASE_EXCLUSIVE       0x2D
#define GET_FIRST_CLIENT        0x0E
#define GET_NEXT_CLIENT         0x2A
#define GET_CLIENT_INFO         0x03
#define ADD_SOCKET_SERVICES     0x32
#define REPLACE_SOCKET_SERVICES 0x33
#define VENDOR_SPECIFIC         0x34
#define ADJUST_RESOURCE_INFO    0x35

//* FLAGS
#define WRITE_PROTECT           0x01
#define BATTERY_DEAD_FLAG       0x10
#define BATTERY_LOW_FLAG        0x20
#define CARD_DETECT_FLAG        0x80

//* RETURN CODES
#define SUCCESS                 0x00
#define BAD_ADAPTER             0x01
#define BAD_ATTRIBUTE           0x02
#define BAD_BASE                0x03
#define BAD_EDC                 0x04
#define BAD_IRQ                 0x06
#define BAD_OFFSET              0x07
#define BAD_PAGE                0x08
#define READ_FAILURE            0x09
#define BAD_SIZE                0x0A
#define BAD_SOCKET              0x0B
#define BAD_TYPE                0x0D
#define BAD_VCC                 0x0E
#define BAD_VPP                 0x0F
#define BAD_WINDOW              0x11
#define WRITE_FAILURE           0x12
#define NO_CARD                 0x14
#define UNSUPPORTED_FUNCTION    0x15
#define UNSUPPORTED_MODE        0x16
#define BAD_SPEED               0x17
#define BUSY                    0x18
#define GENERAL_FAILURE         0x19
#define WRITE_PROTECTED         0x1A
#define BAD_ARGS_LENGTH         0x1B
#define BAD_ARGS                0x1C
#define CONFIGURATION_LOCKED    0x1D
#define IN_USE                  0x1E
#define NO_MORE_ITEMS           0x1F
#define OUT_OF_RESOURCE         0x20
#define BAD_HANDLE              0x21

//*  TUPLES
#define CISTPL_NULL             0x00
#define CISTPL_DEVICE           0x01
#define CISTPL_CHECKSUM         0x10
#define CISTPL_LONGLINK_A       0x11
#define CISTPL_LONGLINK_C       0x12
#define CISTPL_LINKTARGET       0x13
#define CISTPL_NO_LINK          0x14
#define CISTPL_VERS_1           0x15
#define CISTPL_ALTSTR           0x16
#define CISTPL_DEVICE_A         0x17
#define CISTPL_JEDEC_C          0x18
#define CISTPL_JEDEC_A          0x19
#define CISTPL_CONFIG           0x1A
#define CISTPL_CFTABLE_ENTRY    0x1B
#define CISTPL_DEVICE_OC        0x1C
#define CISTPL_DEVICE_OA        0x1D
#define CISTPL_VERS_2           0x40
#define CISTPL_FORMAT           0x41
#define CISTPL_GEOMETRY         0x42
#define CISTPL_BYTEORDER        0x43
#define CISTPL_DATE             0x44
#define CISTPL_BATTERY          0x45
#define CISTPL_ORG              0x46
#define CISTPL_END              0xFF

//*  DEVICE TYPES
#define  DTYPE_NULL             0x0
#define  DTYPE_ROM              0x1
#define  DTYPE_OTPROM           0x2
#define  DTYPE_EPROM            0x3
#define  DTYPE_EEPROM           0x4
#define  DTYPE_FLASH            0x5
#define  DTYPE_SRAM             0x6
#define  DTYPE_DRAM             0x7
#define  DTYPE_FUNCSPEC         0xD
#define  DTYPE_EXTEND           0xE

//*  EVENTS
#define PM_RESUME               0x0B
#define PM_SUSPEND              0x0C
#define BATTERY_DEAD            0x01
#define BATTERY_LOW             0x02
#define CARD_INSERTION          0x40
#define CARD_LOCK               0x03
#define CARD_READY              0x04
#define CARD_REMOVAL            0x05
#define CARD_RESET              0x11
#define CARD_UNLOCK             0x06
#define EJECTION_COMPLETE       0x07
#define EJECTION_REQUEST        0x08
#define ERASE_COMPLETE          0x81
#define EXCLUSIVE_COMPLETE      0x0D
#define EXCLUSIVE_REQUEST       0x0E
#define INSERTION_COMPLETE      0x09
#define INSERTION_REQUEST       0x0A
#define REGISTRATION_COMPLETE   0x82
#define RESET_COMPLETE          0x80
#define RESET_PHYSICAL          0x0F
#define RESET_REQUEST           0x10
#define MTD_REQUEST             0x12
#define CLIENT_INFO             0x14
#define TIMER_EXPIRED           0x15
#define SS_UPDATED              0x16

//*  STRUCTURES
typedef struct {
  WORD  InfoLen;
  WORD  Signature;
  WORD  Count;
  WORD  Revision;
  WORD  CSLevel;
  WORD  VStrOff;
  WORD  VStrLen;
  BYTE  VendorString[80];
}CS_INFO;

typedef struct{
  WORD  Socket;
  WORD  CardState;
  WORD  SocketState;
}STATUS_INFO;

typedef struct {
  WORD  Socket;
  WORD  Attributes;
  BYTE  DesiredTuple;
  BYTE  Reserved;
  WORD  Flags;
  DWORD LinkOffset;
  DWORD CISOffset;
  BYTE  TupleCode;
  BYTE  TupleLink;
}TUPLE_INFO;

typedef struct {
  WORD  Socket;
  WORD  Attributes;
  BYTE  DesiredTuple;
  BYTE  TupleOffset;
  WORD  Flags;
  DWORD LinkOffset;
  DWORD CISOffset;
  WORD  TupleDataMax;
  WORD  TupleDataLen;
  BYTE  TupleData[];
}TUPLE_DATA_INFO;

typedef struct {
  WORD  Attributes;
  WORD  EventMask;
  BYTE  ClientData[8];
  WORD  Version;
}REGISTER_CLIENT_INFO;

//# END

Copyright © 1994, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.