November 2, 2005 PCMCIA 9

### NAME

PCMCIA pcmcia_function_init, pcmcia_function_enable, pcmcia_function_disable, pcmcia_io_alloc, pcmcia_io_free, pcmcia_io_map, pcmcia_io_unmap, pcmcia_mem_alloc, pcmcia_mem_free, pcmcia_mem_map, pcmcia_mem_unmap, pcmcia_intr_establish, pcmcia_intr_disestablish, pcmcia_cis_read_1, pcmcia_cis_read_2, pcmcia_cis_read_3, pcmcia_cis_read_4, pcmcia_cis_read_n, pcmcia_scan_cis - support for PCMCIA PC-Card devices

### SYNOPSIS

```void` pcmcia_function_init(```struct pcmcia_function *pf``, struct pcmcia_config_entry *cfe`)
```int` pcmcia_function_enable(```struct pcmcia_function *pf`)
```void` pcmcia_function_disable(```struct pcmcia_function *pf`)
```int` pcmcia_io_alloc(```struct pcmcia_function *pf``, bus_addr_t start``, bus_size_t size``, bus_size_t align``, struct pcmcia_io_handle *pciop`)
```void` pcmcia_io_free(```struct pcmcia_function *pf``, struct pcmcia_io_handle *pcihp`)
```int` pcmcia_io_map(```struct pcmcia_function *pf``, int width``, struct pcmcia_io_handle *pcihp``, int *windowp`)
```void` pcmcia_io_unmap(```struct pcmcia_function *pf``, int window`)
```int` pcmcia_mem_alloc(```struct pcmcia_function *pf``, bus_size_t size``, struct pcmcia_mem_handle *pcmhp`)
```void` pcmcia_mem_free(```struct pcmcia_function *pf``, struct pcmcia_mem_handle *pcmhp`)
```int` pcmcia_mem_map(```struct pcmcia_function *pf``, int width``, bus_addr_t card_addr``, bus_size_t size``, struct pcmcia_mem_handle *pcmhp``, bus_size_t *offsetp``, int *windowp`)
```void` pcmcia_mem_unmap(```struct pcmcia_function *pf``, int window`)
```void``*` pcmcia_intr_establish(```struct pcmcia_function *pf``, int level``, int (*handler)(void *)``, void *arg`)
```void` pcmcia_intr_disestablish(```struct pcmcia_function *pf``, void *ih`)
```uint8_t` pcmcia_cis_read_1(```struct pcmcia_tuple *tuple``, int index`)
```uint16_t` pcmcia_cis_read_2(```struct pcmcia_tuple *tuple``, int index`)
```uint32_t` pcmcia_cis_read_3(```struct pcmcia_tuple *tuple``, int index`)
```uint32_t` pcmcia_cis_read_4(```struct pcmcia_tuple *tuple``, int index`)
```uint32_t` pcmcia_cis_read_n(```struct pcmcia_tuple *tuple``, int number``, int index`)
```int` pcmcia_scan_cis(```struct device *dev``, int (*func)(struct pcmcia_tuple *, void *)``, void *arg`)

### DESCRIPTION

The machine-independent PCMCIA subsystem provides support for PC-Card devices defined by the Personal Computer Memory Card International Assocation (PCMCIA). The PCMCIA bus supports insertion and removal of cards while a system is powered-on (ie, dynamic reconfiguration). The socket must be powered-off when a card is not present. To the user, this appears as though the socket is "hot" during insertion and removal events.

A PCMCIA controller interfaces the PCMCIA bus with the ISA or PCI busses on the host system. The controller is responsible for detecting and enabling devices and for allocating and mapping resources such as memory and interrupts to devices on the PCMCIA bus.

Each device has a table called the Card Information Structure (CIS) which contains configuration information. The tuples in the CIS are used by the controller to uniquely identify the device. Additional information may be present in the CIS, such as the ethernet MAC address, that can be accessed and used within a device driver.

Devices on the PCMCIA bus are uniquely identified by a 32-bit manufacturer ID and a 32-bit product ID. Additionally, devices can perform multiple functions (such as ethernet and modem) and these functions are identified by a function ID.

PCMCIA devices do not support DMA, however memory on the device can be mapped into the address space of the host.

### DATA TYPES

Drivers attached to the PCMCIA bus will make use of the following data types:

```struct` `pcmcia_card`
  Devices (cards) have their identity recorded in this structure. It contains the following members: `

              char            *cis1_info[4];
              int32_t         manufacturer;
              int32_t         product;
              uint16_t       error;
              SIMPLEQ_HEAD(, pcmcia_function) pf_head;

  `

```struct` `pcmcia_function`
  Identifies the function of the devices. A device can have multiple functions. Consider it an opaque type for identifying a particular function of a device.

struct pcmcia_config_entry
  Contains information about the resources requested by the device. It contains the following members: `

              int             number;
              uint32_t       flags;
              int             iftype;
              int             num_iospace;
              u_long          iomask;
              struct {
                      u_long  length;
                      u_long  start;
              } iospace[4];
              uint16_t       irqmask;
              int             num_memspace;
              struct {
                      u_long  length;
                      u_long  cardaddr;
                      u_long  hostaddr;
              }               memspace[2];
              int             maxtwins;
              SIMPLEQ_ENTRY(pcmcia_config_entry) cfe_list;

  `

```struct` `pcmcia_tuple`
  A handle for identifying an entry in the CIS.

```struct` `pcmcia_io_handle`
  A handle for mapping and allocating I/O address spaces. It contains the tag and handle for accessing the bus-space.

```struct` `pcmcia_mem_handle`
  A handle for mapping and allocating memory address spaces. It contains the tag and handle for accessing the bus-space.

```struct` `pcmcia_attach_args`
  A structure used to inform the driver of the device properties. It contains the following members: `

              int32_t                 manufacturer;
              int32_t                 product;
              struct pcmcia_card      *card;
              struct pcmcia_function  *pf;

  `

### FUNCTIONS

pcmcia_function_init(```pf``, cfe`)
  Initialise the machine-independent PCMCIA state with the config entry ```cfe`.

pcmcia_function_enable(```pf`)
  Provide power to the socket containing the device specified by device function ```pf`.

pcmcia_function_disable(```pf`)
  Remove power from the socket containing the device specified by device function ```pf`.

pcmcia_io_alloc(```pf``, start``, size``, align``, pciop`)
  Request I/O space for device function ```pf` at address ```start` of size ```size`. Alignment is specified by ```align`. A handle for the I/O space is returned in ```pciop`.

pcmcia_io_free(```pf``, pcihp`)
  Release I/O space with handle ```pcihp` for device function ```pf`.

pcmcia_io_map(```pf``, width``, pcihp``, windowp`)
  Map device I/O for device function ```pf` to the I/O space with handle ```pcihp`. The width of data access is specified by ```width`. Valid values for the width are:

  PCMCIA_WIDTH_AUTO
    Use the largest I/O width reported by the device.

  PCMCIA_WIDTH_IO8
    Force 8-bit I/O width.

  PCMCIA_WIDTH_IO16
    Force 16-bit I/O width.
  A handle for the mapped I/O window is returned in ```windowp`.

pcmcia_io_unmap(```pf``, window`)
  Unmap the I/O window ```window` for device function ```pf`.

pcmcia_mem_alloc(```pf``, size``, pcmhp`)
  Request memory space for device function ```pf` of size ```size`. A handle for the memory space is returned in ```pcmhp`.

pcmcia_mem_free(```pf``, pcmhp`)
  Release memory space with handle ```pcmhp` for device function ```pf`.

pcmcia_mem_map(```pf``, width``, card_addr``, size``, pcmhp``, offsetp``, windowp`)
  Map device memory for device function ```pf` to the memory space with handle ```pcmhp`. The address of the device memory starts at ```card_addr` and is size ```size`. The width of data access is specified by ```width`. Valid values for the width are:

  PCMCIA_WIDTH_MEM8
    Force 8-bit memory width.

  PCMCIA_WIDTH_MEM16
    Force 16-bit memory width.
  A handle for the mapped memory window is returned in ```windowp` and a bus-space offset into the memory window is returned in ```offsetp`.

pcmcia_mem_unmap(```pf``, window`)
  Unmap the memory window ```window` for device function ```pf`.

pcmcia_intr_establish(```pf``, level``, handler``, arg`)
  Establish an interrupt handler for device function ```pf`. The priority of the interrupt is specified by ```level`. When the interrupt occurs the function ```handler` is called with argument ```arg`. The return value is a handle for the interrupt handler. pcmcia_intr_establish(``) returns an opaque handle to an event descriptor if it succeeds, and returns NULL on failure.

pcmcia_intr_disestablish(```pf``, ih`)
  Dis-establish the interrupt handler for device function ```pf` with handle ```ih`. The handle was returned from pcmcia_intr_establish(``).

pcmcia_cis_read_1(```tuple``, index`)
  Read one byte from tuple ```tuple` at index ```index` in the CIS.

pcmcia_cis_read_2(```tuple``, index`)
  Read two bytes from tuple ```tuple` at index ```index` in the CIS.

pcmcia_cis_read_3(```tuple``, index`)
  Read three bytes from tuple ```tuple` at index ```index` in the CIS.

pcmcia_cis_read_4(```tuple``, index`)
  Read four bytes from tuple ```tuple` at index ```index` in the CIS.

pcmcia_cis_read_n(```tuple``, number``, index`)
  Read ```n` bytes from tuple ```tuple` at index ```index` in the CIS.

pcmcia_scan_cis(```dev``, func``, arg`)
  Scan the CIS for device ```dev`. For each tuple in the CIS, function ```func` is called with the tuple and the argument ```arg`. ```func` should return 0 if the tuple it was called with is the one it was looking for, or 1 otherwise.

### AUTOCONFIGURATION

During autoconfiguration, a PCMCIA driver will receive a pointer to ```struct` `pcmcia_attach_args` describing the device attached to the PCMCIA bus. Drivers match the device using the manufacturer and product members.

During the driver attach step, drivers will use the pcmcia function pf. The driver should traverse the list of config entries searching for a useful configuration. This config entry is passed to pcmcia_function_init(``) to initialise the machine-independent interface. I/O and memory resources should be initialised using pcmcia_io_alloc(``) and pcmcia_mem_alloc(``) using the specified resources in the config entry. These resources can then be mapped into processor bus space using pcmcia_io_map(``) and pcmcia_mem_map(``) respectively. Upon successful allocation of resources, power can be applied to the device with pcmcia_function_enable(``) so that device-specific interrogation can be performed. Finally, power should be removed from the device using pcmcia_function_disable(``).

Since PCMCIA devices support dynamic configuration, drivers should make use of powerhook_establish(```9`). Power can be applied and the interrupt handler should be established through this interface.

### DMA SUPPORT

PCMCIA devices do not support DMA.

### CODE REFERENCES

This section describes places within the NetBSD source tree where actual code implementing or using the machine-independent PCMCIA subsystem can be found. All pathnames are relative to ```/usr/src`.

The PCMCIA subsystem itself is implemented within the file ```sys/dev/pcmcia/pcmcia.c`. The database of known devices exists within the file ```sys/dev/pcmcia/pcmciadevs_data.h` and is generated automatically from the file ```sys/dev/pcmcia/pcmciadevs`. New manufacturer and product identifiers should be added to this file. The database can be regenerated using the Makefile ```sys/dev/pcmcia/Makefile.pcmciadevs`.

### SEE ALSO

pcic(4), pcmcia(4), tcic(4), autoconf(9), bus_dma(9), bus_space(9), driver(9)

### HISTORY

The machine-independent PCMCIA subsystem appeared in NetBSD1.3.