This patch is vs. 2.3.3. Documentation is included.
Comments ?
- Werner (rushing off to the airport)
---------------------------------- cut here -----------------------------------
--- linux.orig/Documentation/Configure.help Tue May 18 03:19:17 1999
+++ linux/Documentation/Configure.help Tue May 18 03:31:41 1999
@@ -1598,6 +1598,16 @@
Documentation/mca.txt (and especially the web page given there)
before attempting to build an MCA bus kernel.
+Kernel-based PCMCIA support
+CONFIG_KERNEL_PCMCIA
+ Enable limited support for PCMCIA/CompactFlash devices directly in
+ the kernel. This should be used only during early development of
+ ports to PDAs, embedded systems, etc. See Documentation/PCMCIA.txt
+ for details. If unsure, say N.
+
+ See http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html for
+ regular PCMCIA support under Linux.
+
SGI Visual Workstation support
CONFIG_VISWS
The SGI Visual Workstation series is an IA32-based workstation
--- /dev/null Tue May 5 22:32:27 1998
+++ linux/Documentation/PCMCIA.txt Tue May 18 03:31:41 1999
@@ -0,0 +1,36 @@
+Kernel based PCMCIA/CompactFlash access
+---------------------------------------
+
+On many portable and embedded platforms, the only persistent mass-storage
+is in a PCMCIA or CompactFlash slot. This can greatly complicate porting
+Linux to such a device, because PCMCIA support under Linux lives largely
+in user space and requires modules. This means that a fairly complete
+user-space (cross-)development environment, with recent libraries, etc.,
+is necessary to implement PCMCIA support. It also means that a large
+portion of the system has to be operational before work on PCMCIA support
+can begin.
+
+An alternative to using persistent storage is to use initrd. This has the
+disadvantages that the entire file system has to fit into RAM, and also
+that the initrd image has to be downloaded at least after each change.
+
+The kernel based PCMCIA/CF support (in drivers/pcmcia) solves this
+problem by giving the kernel direct access to the PCMCIA bus, and
+allowing the use of the most common storage devices, i.e. the ones which
+are accessed exactly like an IDE hard disk. The main component is a
+parser for the CIS (Card Information Structure), which describes the type
+and operation modes of a PCMCIA or CompactFlash card. In addition to
+this, only a few interface functions and the IDE driver are needed to
+build fully functional disk access into the kernel.
+
+All this is intentionally kept very simple: there is no support for hot-
+plugging, not all of the CIS is decoded, support for variable voltage is
+cumbersome, only one device can be detected, etc. Such advanced features
+are better implemented in the user-space PCMCIA support, instead of
+duplicating functionality in the kernel.
+
+In order to make kernel-based PCMCIA support available, you need to add
+
+bool 'Simple kernel-based PCMCIA Support' CONFIG_KERNEL_PCMCIA
+
+to a suitable architecture-specific config.in file.
--- linux.orig/Makefile Sat May 15 01:04:47 1999
+++ linux/Makefile Tue May 18 03:31:41 1999
@@ -186,6 +186,10 @@
DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a
endif
+ifeq ($(CONFIG_KERNEL_PCMCIA),y)
+DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.a
+endif
+
include arch/$(ARCH)/Makefile
.S.s:
--- linux.orig/drivers/Makefile Mon May 10 19:18:34 1999
+++ linux/drivers/Makefile Tue May 18 03:31:41 1999
@@ -10,7 +10,7 @@
SUB_DIRS := block char net misc sound
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \
- macintosh video dio zorro fc4 usb
+ macintosh video dio zorro fc4 usb pcmcia
ifdef CONFIG_DIO
SUB_DIRS += dio
@@ -99,6 +99,11 @@
ifeq ($(CONFIG_FC4),m)
MOD_SUB_DIRS += fc4
endif
+endif
+
+ifeq ($(CONFIG_KERNEL_PCMCIA),y)
+SUB_DIRS += pcmcia
+ALL_SUB_DIRS += pcmcia
endif
# When MOD_LIST_NAME is set, make will try to add $(MOD_SUB_DIRS).o to
--- linux.orig/drivers/block/genhd.c Tue May 18 03:19:17 1999
+++ linux/drivers/block/genhd.c Tue May 18 03:31:41 1999
@@ -59,6 +59,7 @@
extern int chr_dev_init(void);
extern int blk_dev_init(void);
extern int scsi_dev_init(void);
+extern void pcmcia_init(void);
extern int net_dev_init(void);
#ifdef CONFIG_PPC
@@ -1340,6 +1341,9 @@
#endif
#ifdef CONFIG_SCSI
scsi_dev_init();
+#endif
+#ifdef CONFIG_KERNEL_PCMCIA
+ pcmcia_init();
#endif
#ifdef CONFIG_INET
net_dev_init();
--- /dev/null Tue May 5 22:32:27 1998
+++ linux/drivers/pcmcia/Makefile Tue May 18 09:39:56 1999
@@ -0,0 +1,28 @@
+#
+# Makefile for the kernel-based PCMCIA/CF drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS :=
+
+L_TARGET := pcmcia.a
+M_OBJS :=
+L_OBJS := cis.o
+LX_OBJS :=
+
+ifeq ($(CONFIG_ARCH_PSION),y)
+ L_OBJS += psion.o
+endif
+ifeq ($(CONFIG_ARCH_GEOFOX),y)
+ L_OBJS += geofox.o
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null Tue May 5 22:32:27 1998
+++ linux/drivers/pcmcia/cis.c Tue May 18 09:38:18 1999
@@ -0,0 +1,447 @@
+/*
+ * cis.c - Simplistic CIS scanner and PCMCIA device finder (disks only)
+ *
+ * Hacked 1998,1999 by Werner Almesberger
+ */
+
+/*
+ * In the DOS world, this would be part of a "point enabler". The point is to
+ * avoid having a complete PCMCIA stack with tons of drivers if you already
+ * know exactly what you'll find. Too bad if you're wrong.
+ *
+ * Anyway, this has a lot less overhead than the normal Linux way of using
+ * PCMCIA, i.e. cardmgr+modules, requiring libc, probably insmod, etc., so
+ * it's more useful while we're still struggling with trivial problems.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pcmcia.h>
+
+
+/*
+ * The following code reads the CIS, determines if the card is in fact an ATA
+ * disk drive, and selects a suitable configuration. A configuration is
+ * accepted if:
+ * - it uses the Vcc available for the PCMCIA/CF slot
+ * - it doesn't need Vpp
+ * - it allows 8 and 16 bit bus accesses
+ * - it defines a fixed IO port range (so we don't have to select one)
+ */
+
+
+#define MAX_CIS_SIZE 0x200
+#define MAX_IO_AREAS 2
+
+struct power {
+ unsigned long v_max,v_min,v_nom;
+ unsigned long i_pdwn,i_peak,i_avg,i_static;
+};
+
+struct cfg_data {
+ struct power vcc,vpp1,vpp2;
+ int bus;
+ unsigned long io_base[MAX_IO_AREAS];
+ unsigned long io_size[MAX_IO_AREAS];
+};
+
+static u8 selected __initdata = 0;
+static struct cfg_data selected_cfg __initdata = { { 0, }, },
+ curr_cfg __initdata = { { 0, }, }, dfl_cfg __initdata = { { 0, }, };
+
+static unsigned long curr __initdata = 0, next __initdata = 0;
+static int got_version __initdata = 0, got_function __initdata = 0,
+ got_ata __initdata = 0, got_config __initdata = 0;
+static unsigned long fcr_base __initdata = 0;
+ /* FCR base address in attrib mem */
+static unsigned long fcr_mask __initdata = 0;
+ /* Registers available in FCR */
+static int verbose __initdata = 0;
+
+#define CISTPL_VERS_1 0x15
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_END 0xff
+
+
+static int __init next_cis_tupel(u8 *res)
+{
+ *res = cis_read(next);
+ if (*res == CISTPL_END) return 0;
+ curr = next+4;
+ if (curr >= MAX_CIS_SIZE) return -1;
+ next = curr+cis_read(curr-2)*2;
+ if (next >= MAX_CIS_SIZE) return -1;
+ return 0;
+}
+
+
+static int __init next_cis_byte(u8 *res)
+{
+ if (curr == next) return -1;
+ *res = cis_read(curr);
+ curr += 2;
+ return 0;
+}
+
+
+static int __init skip_cis_bytes(int bytes)
+{
+ if (curr+bytes*2 > next) return -1;
+ curr += bytes*2;
+ return 0;
+}
+
+
+static int __init get_value(int mult,unsigned long *res)
+{
+ static unsigned long xlat[] = __initlocaldata {
+ 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90 };
+ u8 v;
+ int i;
+
+ if (next_cis_byte(&v)) return -1;
+ mult /= 10; /* because xlat is scaled *10 */
+ for (i = 0; i < (v & 7); i++) mult *= 10;
+ *res = xlat[(v >> 3) & 15]*mult;
+ mult /= 10;
+ while (v & 0x80) {
+ if (next_cis_byte(&v)) return -1;
+ if ((v & 0x7f) > 99) {
+ printk(KERN_WARNING " Don't grok power ext 0x%02x\n",
+ v & 0x7f);
+ return 0;
+ }
+ *res += (v & 0x7f)*mult;
+ mult /= 100;
+ }
+ return 0;
+}
+
+
+static int __init parse_power(struct power *power)
+{
+ u8 mask;
+
+ if (next_cis_byte(&mask)) return -1; /* TPCE_PD */
+ if ((mask & 0x01) && get_value(10,&power->v_nom)) return -1;
+ if ((mask & 0x02) && get_value(10,&power->v_min)) return -1;
+ if ((mask & 0x04) && get_value(10,&power->v_max)) return -1;
+ if ((mask & 0x08) && get_value(100,&power->i_static)) return -1;
+ if ((mask & 0x10) && get_value(100,&power->i_avg)) return -1;
+ if ((mask & 0x20) && get_value(100,&power->i_peak)) return -1;
+ if ((mask & 0x40) && get_value(100,&power->i_pdwn)) return -1;
+ return 0;
+}
+
+
+static int __init parse_entry(u8 fs)
+{
+ curr_cfg = dfl_cfg;
+ if ((fs & 3) && parse_power(&curr_cfg.vcc)) return -1;
+ if ((fs & 3) > 1 && parse_power(&curr_cfg.vpp1)) return -1;
+ if ((fs & 3) > 2 && parse_power(&curr_cfg.vpp2)) return -1;
+ if (fs & 4) {
+ u8 td;
+
+ if (next_cis_byte(&td)) return -1; /* TPCE_TD */
+ if ((td & 3) != 3)
+ if (skip_cis_bytes(1)) return -1;
+ if (((td >> 2) & 7) != 7)
+ if (skip_cis_bytes(1)) return -1;
+ }
+ if (fs & 8) {
+ u8 io;
+ u8 sizes;
+ int areas,i,j;
+
+ if (next_cis_byte(&io)) return -1; /* TPCE_IO */
+ for (i = 0; i < MAX_IO_AREAS; i++)
+ curr_cfg.io_base[i] = curr_cfg.io_size[i] = 0;
+ if ((io >> 5) & 3) curr_cfg.bus = (io >> 5) & 3;
+ else {
+ printk(KERN_WARNING " Unrecognized IO bus size (0)\n");
+ return 0;
+ }
+ if (!(io & 0x80)) return 0;
+ if (next_cis_byte(&sizes)) return -1;
+ areas = (sizes & 15)+1;
+ if (areas > MAX_IO_AREAS) areas = MAX_IO_AREAS;
+ for (i = 0; i < areas; i++) {
+ for (j = 0; j < ((sizes >> 4) & 3); j++) {
+ u8 v;
+
+ if (next_cis_byte(&v)) return -1;
+ curr_cfg.io_base[i] |= v << (j*8);
+ }
+ for (j = 0; j < (sizes >> 6); j++) {
+ u8 v;
+
+ if (next_cis_byte(&v)) return -1;
+ curr_cfg.io_size[i] |= v << (j*8);
+ }
+ /*if (!curr_cfg.io_size)
+ curr_cfg.io_size[i] = 1 << (io & 0x1f);*/
+ }
+ }
+ return 0;
+}
+
+
+static void __init print_pow_prm(unsigned long value,const char *suffix,
+ const char *unit)
+{
+ char s[2];
+
+ while (*suffix && !(value % 1000)) {
+ value /= 1000;
+ suffix++;
+ }
+ if (*suffix && value > 1000) {
+ s[0] = suffix[1];
+ printk("%ld.",value/1000);
+ if (value % 10) printk("%03ld",value % 1000);
+ else if (value % 100) printk("%02ld",(value % 1000)/10);
+ else printk("%ld",(value % 1000)/100);
+ }
+ else {
+ s[0] = suffix[0];
+ printk("%ld",value);
+ }
+ s[1] = 0;
+ printk("%s%s",s,unit);
+}
+
+
+static void __init print_power(const char *name,struct power power)
+{
+ if (!power.v_nom && !power.v_min && !power.v_max) return;
+ printk(KERN_INFO " %s: ",name);
+ print_pow_prm(power.v_nom,"um","V");
+ printk(" (");
+ print_pow_prm(power.v_min,"um","V");
+ printk("-");
+ print_pow_prm(power.v_max,"um","V");
+ printk(")");
+ if (!power.i_pdwn && !power.i_peak && !power.i_avg && !power.i_static) {
+ printk("\n");
+ return;
+ }
+ printk(" current ");
+ if (power.i_avg) {
+ print_pow_prm(power.i_avg,"num","A");
+ printk(" (");
+ }
+ if (power.i_pdwn) {
+ print_pow_prm(power.i_pdwn,"num","A");
+ printk(",");
+ }
+ print_pow_prm(power.i_static,"num","A");
+ printk("-");
+ if (power.i_peak) print_pow_prm(power.i_peak,"num","A");
+ if (power.i_avg) printk(")");
+ printk("\n");
+}
+
+
+static void __init print_entry(void)
+{
+ static const char *bsz[] __initlocaldata = { "???","8","16","8/16" };
+ int i;
+
+ print_power("Vcc",curr_cfg.vcc);
+ print_power("Vpp1",curr_cfg.vpp1);
+ print_power("Vpp2",curr_cfg.vpp2);
+ if (!curr_cfg.bus && !curr_cfg.io_base[0] && !curr_cfg.io_size[0])
+ return;
+ printk(KERN_INFO " IO");
+ for (i = 0; i < MAX_IO_AREAS; i++)
+ if (curr_cfg.io_base[i] || curr_cfg.io_size[i])
+ printk(" 0x%lx-0x%lx",curr_cfg.io_base[i],
+ curr_cfg.io_base[i]+curr_cfg.io_size[i]);
+ if (curr_cfg.bus) printk(" bus %s bit",bsz[curr_cfg.bus]);
+ printk("\n");
+}
+
+
+static int __init accept_cfg(int millivolts)
+{
+ unsigned long mv;
+
+ if (!curr_cfg.vcc.v_nom) return 0;
+ if (curr_cfg.vpp1.v_nom || curr_cfg.vpp2.v_nom) return 0;
+ if (!curr_cfg.bus || !curr_cfg.io_base[0] || !curr_cfg.io_size[0] ||
+ !curr_cfg.io_base[1] || !curr_cfg.io_size[1])
+ return 0;
+ if (curr_cfg.bus != 3) return 0;
+ /* don't know what accesses the IDE driver will attempt, so we
+ require 8 and 16 bit */
+ mv = curr_cfg.vcc.v_nom/1000; /* convert to mV */
+ /*
+ * Allow 10% tolerance.
+ */
+ if (millivolts < mv-mv/10 || millivolts> mv+mv/10) return 0;
+ return 1;
+}
+
+
+static int __init parse_tupel(u8 tupel,int millivolts)
+{
+ u8 v,v2;
+ int first,i;
+
+ switch (tupel) {
+ case CISTPL_VERS_1:
+ got_version = 1;
+ if (skip_cis_bytes(2)) return -1;
+ /* TPLLV1_MAJOR, TPLLV1_MINOR */
+ printk(KERN_INFO "PCMCIA device:");
+ first = 1; /* TPLLV1_INFO */
+ while (1) {
+ if (next_cis_byte(&v)) return -1;
+ if (v == 0xff) break;
+ printk("%s %c",first ? "" : ";",v);
+ first = 0;
+ while (1) {
+ if (next_cis_byte(&v)) return -1;
+ if (!v || v == 0xff) break;
+ printk("%c",v);
+ }
+ }
+ printk("\n");
+ break;
+ case CISTPL_CONFIG:
+ got_config = 1;
+ if (next_cis_byte(&v)) return -1; /* TPCC_SZ */
+ if (skip_cis_bytes(1)) return -1; /* TPCC_LAST */
+ fcr_base = 0; /* TPCC_RADR */
+ for (i = 0; i <= (v & 3); i++) {
+ if (next_cis_byte(&v2)) return -1;
+ fcr_base |= v2 << (8*i);
+ }
+ fcr_mask = 0; /* TPCC_RMSK */
+ for (i = 0; i <= ((v >> 2) & 15); i++) {
+ if (next_cis_byte(&v2)) return -1;
+ fcr_mask |= v2 << (8*i);
+ }
+ break;
+ case CISTPL_CFTABLE_ENTRY:
+ if (next_cis_byte(&v)) return -1; /* TPCE_INDX */
+ if (v & 0x80)
+ if (skip_cis_bytes(1)) return -1; /* TPCE_IF */
+ if (next_cis_byte(&v2)) return -1; /* TPCE_FS */
+ if (parse_entry(v2)) return -1;
+ if (v & 0x40) dfl_cfg = curr_cfg;
+ if (!selected && accept_cfg(millivolts)) {
+ selected = v & 0x3f;
+ selected_cfg = curr_cfg;
+ print_entry();
+ }
+ break;
+ case CISTPL_FUNCID:
+ if (next_cis_byte(&v)) return -1; /* TPFID_FUNCTION */
+ if (v == 0x04) got_function = 1;
+ else printk(KERN_WARNING " Unrecognized device "
+ "function 0x%02x\n",v);
+ break;
+ case CISTPL_FUNCE:
+ if (!got_function) break;
+ if (next_cis_byte(&v)) return -1; /* TPLFE_TYPE */
+ switch (v) {
+ case 1:
+ if (next_cis_byte(&v)) return -1;
+ /* TPLFE_DATA */
+ if (v == 1) break;
+ printk(KERN_WARNING " Unrecognized "
+ "interface 0x%02x\n",v);
+ return 0;
+ case 2:
+ if (next_cis_byte(&v)) return -1;
+ /* TPLFE_DATA */
+ if (v & 3) {
+ printk(KERN_WARNING " Device "
+ "needs Vpp (not "
+ "supported)\n");
+ return 0;
+ }
+ break;
+ default:
+ printk(KERN_WARNING " Unrecognized "
+ "TPLFE_TYPE 0x%02x\n",v);
+ return 0;
+ }
+ got_ata = 1;
+ break;
+ default:
+ if (verbose)
+ printk(KERN_DEBUG " (Ignoring tupel "
+ "0x%02x)\n",tupel);
+ }
+ return 0;
+}
+
+
+int __init parse_cis(int millivolts,unsigned long *fcr,u8 *cfg,
+ unsigned long *io_base0,unsigned long *io_base1)
+{
+ u8 tupel;
+
+ curr = next = 0;
+ got_version = got_function = got_ata = got_config = 0;
+ while (1) {
+ if (next_cis_tupel(&tupel)) return -1;
+ if (tupel == CISTPL_END) break;
+ if (parse_tupel(tupel,millivolts)) return -1;
+ }
+ if (!got_version || !got_function || !got_ata || !got_config ||
+ !selected) {
+ printk(KERN_INFO "Device skipped (reason:%s%s%s%s%s)\n",
+ got_version ? "" : " Bad version",
+ got_function ? "" : " No function",
+ got_ata ? "" : " Not ATA",
+ got_config ? "" : " No configuration",
+ selected ? "" : " Not selected");
+ return 0;
+ }
+ printk(KERN_INFO "Device selected. FCR at 0x%lx, mask 0x%lx. "
+ "Configuration index 0x%02x\n",fcr_base,fcr_mask,selected);
+ *fcr = fcr_base;
+ *cfg = selected;
+ *io_base0 = selected_cfg.io_base[0];
+ *io_base1 = selected_cfg.io_base[1];
+ return 1;
+}
+
+
+/*
+ * If we didn't find any suitable device (or if we simply failed to understand
+ * the CIS), we dump the raw CIS contents now.
+ */
+
+
+void __init dump_cis(void)
+{
+ unsigned long p;
+
+ printk("CIS dump follows:\n");
+ p = 0;
+ while (cis_read(p) != 0xff) {
+ int i;
+
+ if (p >= MAX_CIS_SIZE) {
+ printk("TOO MUCH !\n");
+ return;
+ }
+ printk(" %02x:",cis_read(p));
+ p += 2;
+ for (i = cis_read(p); i; i--) {
+ p += 2;
+ printk(" %02x",cis_read(p));
+ }
+ printk("\n");
+ p += 2;
+ }
+}
--- /dev/null Tue May 5 22:32:27 1998
+++ linux/drivers/pcmcia/skeleton.c Tue May 18 09:39:23 1999
@@ -0,0 +1,57 @@
+/*
+ * skeleton.c - Skeleton for system-specific PCMCIA functions
+ *
+ * Hacked 1999 by Werner Almesberger
+ */
+
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pcmcia.h>
+
+
+u8 __init cis_read(unsigned long offset)
+{
+ /*
+ * From psion.c:
+
+ return *(u8 *) PCMCIA_ATTR8(offset);
+
+ */
+ return 0; /* dummy */
+}
+
+
+void __init pcmcia_init(void)
+{
+ unsigned long fcr,io0,io1;
+ u8 cfg;
+ int res;
+
+ /* Power up PCMCIA slot, enable drivers, check if card present */
+ /* Obtain available voltage, or - if fixed - just use that constant
+ (e.g. 3.3 V) */
+ res = parse_cis(3300,&fcr,&cfg,&io0,&io1);
+ if (res < 0) {
+ printk(KERN_WARNING
+ "CompactFlash/PCMCIA card absent or invalid.\n");
+ return;
+ }
+ if (!res) {
+ dump_cis();
+ return;
+ }
+ /* Write 0 to CCSR (which is at address "fcr"+2) to clear pending
+ interrupts */
+ /* Write "cfg" into COR (which is at address "fcr") */
+ /* Route interrupts, enable PCMCIA IO space, etc. */
+ /*
+ * Register IDE driver:
+
+ if (ide_register(io0,io1,IRQ_...) < 0)
+ printk("pcmcia_init: ide_register failed\n");
+
+ */
+}
--- /dev/null Tue May 5 22:32:27 1998
+++ linux/include/linux/pcmcia.h Tue May 18 03:31:41 1999
@@ -0,0 +1,44 @@
+#ifndef _LINUX_PCMCIA_H_
+#define _LINUX_PCMCIA_H_
+
+/*
+ * PCMCIA device finder functions
+ *
+ * Written 1999 by Werner Almesberger
+ */
+
+#include <linux/types.h>
+
+
+/*
+ * Find a disk device. "millivolts" is the available Vcc. Returns the base
+ * address of the configuration registers in *fcr, the index of the selected
+ * configuration in *cfg, and the base addresses of the two IO ranges in
+ * *io_base0 and *io_base1. (Unused IO ranges are returned as 0.) The return
+ * value is positive if a suitable device has been found, zero if not, and
+ * negative if the CIS was absent or unparseable.
+ */
+
+int parse_cis(int millivolts,unsigned long *fcr,u8 *cfg,
+ unsigned long *io_base0,unsigned long *io_base1);
+
+/*
+ * Dump the CIS content using printk.
+ */
+
+void dump_cis(void);
+
+/*
+ * Read a byte from the CIS at the specified offset. This function needs to be
+ * provided by the architecture-specific interface.
+ */
+
+u8 cis_read(unsigned long offset);
+
+/*
+ * Enable the PCMCIA bus, call parse_cis, and activate device
+ */
+
+void pcmcia_init(void);
+
+#endif
-- _________________________________________________________________________ / Werner Almesberger, DI-ICA,EPFL,CH werner.almesberger@lrc.di.epfl.ch / /_IN_R_131__Tel_+41_21_693_6621__Fax_+41_21_693_6610_____________________/- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/