PCMCIA(9)
πΈ PCMCIA πΈ
Kernel Developer's Manual, section 9 β support for PCMCIA PC-Card devices π
okay bestie, this one is a whole saga, so buckle up β¨
π 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 π
like, all of them. every single one. this page is the whole friend group π
β¨ SYNOPSIS β¨
#include <sys/bus.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
#include <dev/pcmcia/pcmciadevs.h>
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 π¦
okay so the machine-independent PCMCIA subsystem is the one providing support for PC-Card devices defined by the Personal Computer Memory Card International Association (PCMCIA). iconic of them. and the PCMCIA bus supports insertion and removal of cards while a system is powered-on (ie, dynamic reconfiguration) β yes bestie, you can just yank it out while it's running, that's the whole vibe π«Ά
the socket must be powered-off when a card is not present, though. no cap. 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. it's giving project manager energy, honestly.
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. and additionally, devices can perform multiple functions (such as ethernet and modem) and these functions are identified by a function ID. multitasking icon π
lowkey important: PCMCIA devices do not support DMA. however memory on the device can be mapped into the address space of the host. okay so that's the trade-off, noted π
π 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 β like, don't peek inside, just trust it π
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. (yes, basically the memory twin of the one above, they're matching β¨)
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. setting the stage, main character energy β¨
pcmcia_function_enable(pf)
provide power to the socket containing the device specified by device function pf. turning it on, we love to see it π₯
pcmcia_function_disable(pf)
remove power from the socket containing the device specified by device function pf. the lights are off, everybody go home π
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. book the venue, bestie π
pcmcia_io_free(pf, pcihp)
release I/O space with handle pcihp for device function pf. venue closed, thank you for coming π«Ά
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. slay, you got a window π¦
pcmcia_io_unmap(pf, window)
unmap the I/O window window for device function pf. bye window, it was fun π
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. yes, memory space, we're doing the memory side now π§
pcmcia_mem_free(pf, pcmhp)
release memory space with handle pcmhp for device function pf. giving it back, very demure πΈ
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. two outputs, one call, efficiency queen π
pcmcia_mem_unmap(pf, window)
unmap the memory window window for device function pf. memory window: closed π
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. so like, check for NULL, bestie, don't just trust it π
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(). we're breaking up with the interrupt handler, respectfully π
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. the n is literally the number argument, iykyk π
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. yes bestie, 0 means found it, invert your brain accordingly π
π to be continuedβ¦
πΈ AUTOCONFIGURATION πΈ
okay so here's the whole meet-cute between a driver and a device π During autoconfiguration, a PCMCIA driver gets handed a pointer to struct pcmcia_attach_args β that's the little profile card describing the device attached to the PCMCIA bus. Drivers do the matching thing using the manufacturer and product members, iykyk. β¨
Then comes the driver attach step, where drivers use the pcmcia function pf. Bestie, this is the part where you actually do stuff:
- the driver should walk through the list of config entries, hunting for a useful configuration π
- that config entry gets passed to
pcmcia_function_init()to initialise the machine-independent interface - I/O and memory resources should be initialised with
pcmcia_io_alloc()andpcmcia_mem_alloc(), using the resources specified in the config entry - those resources can then be mapped into processor bus space with
pcmcia_io_map()andpcmcia_mem_map()respectively - once allocation succeeds (slay π
), power can be applied to the device with
pcmcia_function_enable()so you can do the device-specific interrogation - and finally, power should be removed from the device with
pcmcia_function_disable()
Since PCMCIA devices support dynamic configuration, drivers should lowkey make use of the pmf(9) framework β power can be applied through this interface, and your interrupt handler should be established through it too. No cap, it's the moment. π«Ά
π DMA SUPPORT π
PCMCIA devices do not support DMA. That's it. That's the whole section. periodt.
π CODE REFERENCES π
The PCMCIA subsystem itself lives in the file sys/dev/pcmcia/pcmcia.c β main character energy fr fr.
The database of known devices exists within the file sys/dev/pcmcia/pcmciadevs_data.h, and it's generated automatically from the file sys/dev/pcmcia/pcmciadevs. New manufacturer and product identifiers should be added to this file (yes, that's your job, bestie πΈ). You can regenerate the database using the Makefile sys/dev/pcmcia/Makefile.pcmciadevs. Iconic build system behaviour, honestly.
π¦ SEE ALSO π¦
Also the absolute classic: Personal Computer Memory Card International Association (PCMCIA), PC Card 95 Standard, 1995. History textbook material π
β¨ HISTORY β¨
The machine-independent PCMCIA subsystem appeared in NetBSD 1.3. She's been serving looks since the 90s, we stan a veteran. π
π§ okay bestie that's the whole page!! go forth and write your PCMCIA driver, you're gonna eat π
this was the Debian version, dated April 15, 2010 β page PCMCIA(9), mwah π
π¦ where this page comes from
- nixpkgs unstable: netbsd-source 11.0
- Copyright (c) 2001 The NetBSD Foundation, Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms