[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/Kconfig b/src/kernel/linux/v4.14/drivers/pcmcia/Kconfig
new file mode 100644
index 0000000..d3c378b
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/Kconfig
@@ -0,0 +1,297 @@
+#
+# PCCARD (PCMCIA/CardBus) bus subsystem configuration
+#
+
+menuconfig PCCARD
+	tristate "PCCard (PCMCIA/CardBus) support"
+	---help---
+	  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+	  computer.  These are credit-card size devices such as network cards,
+	  modems or hard drives often used with laptops computers.  There are
+	  actually two varieties of these cards: 16 bit PCMCIA and 32 bit
+	  CardBus cards.
+
+	  To compile this driver as modules, choose M here: the
+	  module will be called pcmcia_core.
+
+if PCCARD
+
+config PCMCIA
+	tristate "16-bit PCMCIA support"
+	select CRC32
+	default y
+	---help---
+	   This option enables support for 16-bit PCMCIA cards. Most older
+	   PC-cards are such 16-bit PCMCIA cards, so unless you know you're
+	   only using 32-bit CardBus cards, say Y or M here.
+
+	   To use 16-bit PCMCIA cards, you will need supporting software in
+	   most cases. (see the file <file:Documentation/Changes> for
+	   location and details).
+
+	   To compile this driver as modules, choose M here: the
+	   module will be called pcmcia.
+
+	   If unsure, say Y.
+
+config PCMCIA_LOAD_CIS
+	bool "Load CIS updates from userspace"
+	depends on PCMCIA
+	select FW_LOADER
+	default y
+	help
+	  Some PCMCIA cards require an updated Card Information Structure (CIS)
+	  to be loaded from userspace to work correctly. If you say Y here,
+	  and your userspace is arranged correctly, this will be loaded
+	  automatically using the in-kernel firmware loader and the hotplug
+	  subsystem, instead of relying on cardmgr from pcmcia-cs to do so.
+
+	  If unsure, say Y.
+
+config CARDBUS
+	bool "32-bit CardBus support"
+	depends on PCI
+	default y
+	---help---
+	  CardBus is a bus mastering architecture for PC-cards, which allows
+	  for 32 bit PC-cards (the original PCMCIA standard specifies only
+	  a 16 bit wide bus). Many newer PC-cards are actually CardBus cards.
+
+	  To use 32 bit PC-cards, you also need a CardBus compatible host
+	  bridge. Virtually all modern PCMCIA bridges do this, and most of
+	  them are "yenta-compatible", so say Y or M there, too.
+
+	  If unsure, say Y.
+
+comment "PC-card bridges"
+
+config YENTA
+	tristate "CardBus yenta-compatible bridge support"
+	depends on PCI
+	select CARDBUS if !EXPERT
+	select PCCARD_NONSTATIC if PCMCIA != n
+	---help---
+	  This option enables support for CardBus host bridges.  Virtually
+	  all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
+	  the hardware inside your computer that PCMCIA cards are plugged
+	  into.
+
+	  To compile this driver as modules, choose M here: the
+	  module will be called yenta_socket.
+
+	  If unsure, say Y.
+
+config YENTA_O2
+	default y
+	bool "Special initialization for O2Micro bridges" if EXPERT
+	depends on YENTA
+
+config YENTA_RICOH
+	default y
+	bool "Special initialization for Ricoh bridges" if EXPERT
+	depends on YENTA
+
+config YENTA_TI
+	default y
+	bool "Special initialization for TI and EnE bridges" if EXPERT
+	depends on YENTA
+
+config YENTA_ENE_TUNE
+	default y
+	bool "Auto-tune EnE bridges for CB cards" if EXPERT
+	depends on YENTA_TI && CARDBUS
+
+config YENTA_TOSHIBA
+	default y
+	bool "Special initialization for Toshiba ToPIC bridges" if EXPERT
+	depends on YENTA
+
+config PD6729
+	tristate "Cirrus PD6729 compatible bridge support"
+	depends on PCMCIA && PCI
+	select PCCARD_NONSTATIC
+	help
+	  This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
+	  device, found in some older laptops and PCMCIA card readers.
+
+config I82092
+	tristate "i82092 compatible bridge support"
+	depends on PCMCIA && PCI
+	select PCCARD_NONSTATIC
+	help
+	  This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
+	  found in some older laptops and more commonly in evaluation boards for the
+	  chip.
+
+config I82365
+	tristate "i82365 compatible bridge support"
+	depends on PCMCIA && ISA
+	select PCCARD_NONSTATIC
+	help
+	  Say Y here to include support for ISA-bus PCMCIA host bridges that
+	  are register compatible with the Intel i82365.  These are found on
+	  older laptops and ISA-bus card readers for desktop systems.  A
+	  "bridge" is the hardware inside your computer that PCMCIA cards are
+	  plugged into. If unsure, say N.
+
+config TCIC
+	tristate "Databook TCIC host bridge support"
+	depends on PCMCIA && ISA
+	select PCCARD_NONSTATIC
+	help
+	  Say Y here to include support for the Databook TCIC family of PCMCIA
+	  host bridges. These are only found on a handful of old systems.
+	  "Bridge" is the name used for the hardware inside your computer that
+	  PCMCIA cards are plugged into. If unsure, say N.
+
+config PCMCIA_ALCHEMY_DEVBOARD
+	tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
+	depends on MIPS_ALCHEMY && PCMCIA
+	help
+	  Enable this driver of you want PCMCIA support on your Alchemy
+	  Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300
+	  board.  NOT suitable for the PB1000!
+
+	  This driver is also available as a module called db1xxx_ss.ko
+
+config PCMCIA_XXS1500
+	tristate "MyCable XXS1500 PCMCIA socket support"
+	depends on PCMCIA && MIPS_XXS1500
+	help
+	  Support for the PCMCIA/CF socket interface on MyCable XXS1500
+	  systems.
+
+	  This driver is also available as a module called xxs1500_ss.ko
+
+config PCMCIA_BCM63XX
+	tristate "bcm63xx pcmcia support"
+	depends on BCM63XX && PCMCIA
+
+config PCMCIA_SOC_COMMON
+	tristate
+
+config PCMCIA_SA11XX_BASE
+	tristate
+
+config PCMCIA_SA1100
+	tristate "SA1100 support"
+	depends on ARM && ARCH_SA1100 && PCMCIA
+	select PCMCIA_SOC_COMMON
+	select PCMCIA_SA11XX_BASE
+	help
+	  Say Y here to include support for SA11x0-based PCMCIA or CF
+	  sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
+	  Xscale(R) embedded machines.
+
+	  This driver is also available as a module called sa1100_cs.
+
+config PCMCIA_SA1111
+	tristate "SA1111 support"
+	depends on ARM && SA1111 && PCMCIA
+	select PCMCIA_SOC_COMMON
+	select PCMCIA_SA11XX_BASE if ARCH_SA1100
+	select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
+	help
+	  Say Y  here to include support for SA1111-based PCMCIA or CF
+	  sockets, found on the Jornada 720, Graphicsmaster and other
+	  StrongARM(R)/Xscale(R) embedded machines.
+
+	  This driver is also available as a module called sa1111_cs.
+
+config PCMCIA_PXA2XX
+	tristate "PXA2xx support"
+	depends on ARM && ARCH_PXA && PCMCIA
+	depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
+		    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
+		    || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
+		    || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
+		    || MACH_COLIBRI320 || MACH_H4700)
+	select PCMCIA_SOC_COMMON
+	help
+	  Say Y here to include support for the PXA2xx PCMCIA controller
+
+config PCMCIA_DEBUG
+	bool "Enable debugging"
+	depends on (PCMCIA_SA1111 || PCMCIA_SA1100 || PCMCIA_PXA2XX)
+	help
+	  Say Y here to enable debugging for the SoC PCMCIA layer.
+	  You will need to choose the debugging level either via the
+	  kernel command line, or module options depending whether
+	  you build the drivers as modules.
+
+	  The kernel command line options are:
+	    sa11xx_core.pc_debug=N
+	    pxa2xx_core.pc_debug=N
+
+	  The module option is called pc_debug=N
+
+	  In all the above examples, N is the debugging verbosity
+	  level.
+
+config PCMCIA_PROBE
+	bool
+	default y if ISA && !ARCH_SA1100 && !PARISC
+
+config M32R_PCC
+	bool "M32R PCMCIA I/F"
+	depends on M32R && CHIP_M32700 && PCMCIA
+	help
+	  Say Y here to use the M32R PCMCIA controller.
+
+config M32R_CFC
+	bool "M32R CF I/F Controller"
+	depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT)
+	help
+	  Say Y here to use the M32R CompactFlash controller.
+
+config M32R_CFC_NUM
+	int "M32R CF I/F number"
+	depends on M32R_CFC
+	default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT
+	help
+	  Set the number of M32R CF slots.
+
+config PCMCIA_VRC4171
+	tristate "NEC VRC4171 Card Controllers support"
+	depends on CPU_VR41XX && ISA && PCMCIA
+
+config PCMCIA_VRC4173
+	tristate "NEC VRC4173 CARDU support"
+	depends on CPU_VR41XX && PCI && PCMCIA
+
+config OMAP_CF
+	tristate "OMAP CompactFlash Controller"
+	depends on PCMCIA && ARCH_OMAP16XX
+	help
+	  Say Y here to support the CompactFlash controller on OMAP.
+	  Note that this doesn't support "True IDE" mode.
+
+config BFIN_CFPCMCIA
+	tristate "Blackfin CompactFlash PCMCIA Driver"
+	depends on PCMCIA && BLACKFIN
+	help
+	  Say Y here to support the CompactFlash PCMCIA driver for Blackfin.
+
+
+config AT91_CF
+	tristate "AT91 CompactFlash Controller"
+	depends on PCI
+	depends on PCMCIA && ARCH_AT91
+	help
+	  Say Y here to support the CompactFlash controller on AT91 chips.
+	  Or choose M to compile the driver as a module named "at91_cf".
+
+config ELECTRA_CF
+	tristate "Electra CompactFlash Controller"
+	depends on PCMCIA && PPC_PASEMI
+	help
+	  Say Y here to support the CompactFlash controller on the
+	  PA Semi Electra eval board.
+
+config PCCARD_NONSTATIC
+	bool
+
+config PCCARD_IODYN
+	bool
+
+endif	# PCCARD
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/Makefile b/src/kernel/linux/v4.14/drivers/pcmcia/Makefile
new file mode 100644
index 0000000..e7dae16
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/Makefile
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
+#
+
+pcmcia_core-y					+= cs.o socket_sysfs.o
+pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
+obj-$(CONFIG_PCCARD)				+= pcmcia_core.o
+
+pcmcia-y					+= ds.o pcmcia_resource.o cistpl.o pcmcia_cis.o
+obj-$(CONFIG_PCMCIA)				+= pcmcia.o
+
+pcmcia_rsrc-y					+= rsrc_mgr.o
+pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)		+= rsrc_nonstatic.o
+pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)		+= rsrc_iodyn.o
+obj-$(CONFIG_PCCARD)				+= pcmcia_rsrc.o
+
+
+# socket drivers
+
+obj-$(CONFIG_YENTA) 				+= yenta_socket.o
+
+obj-$(CONFIG_PD6729)				+= pd6729.o
+obj-$(CONFIG_I82365)				+= i82365.o
+obj-$(CONFIG_I82092)				+= i82092.o
+obj-$(CONFIG_TCIC)				+= tcic.o
+obj-$(CONFIG_PCMCIA_SOC_COMMON)			+= soc_common.o
+obj-$(CONFIG_PCMCIA_SA11XX_BASE)		+= sa11xx_base.o
+obj-$(CONFIG_PCMCIA_SA1100)			+= sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)			+= sa1111_cs.o
+obj-$(CONFIG_M32R_PCC)				+= m32r_pcc.o
+obj-$(CONFIG_M32R_CFC)				+= m32r_cfc.o
+obj-$(CONFIG_PCMCIA_BCM63XX)			+= bcm63xx_pcmcia.o
+obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc4171_card.o
+obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
+obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
+obj-$(CONFIG_BFIN_CFPCMCIA)			+= bfin_cf_pcmcia.o
+obj-$(CONFIG_AT91_CF)				+= at91_cf.o
+obj-$(CONFIG_ELECTRA_CF)			+= electra_cf.o
+obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)		+= db1xxx_ss.o
+
+sa1111_cs-y					+= sa1111_generic.o
+sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1111_neponset.o
+sa1111_cs-$(CONFIG_SA1100_BADGE4)		+= sa1111_badge4.o
+sa1111_cs-$(CONFIG_SA1100_JORNADA720)		+= sa1111_jornada720.o
+sa1111_cs-$(CONFIG_ARCH_LUBBOCK)		+= sa1111_lubbock.o
+
+sa1100_cs-y					+= sa1100_generic.o
+sa1100_cs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
+sa1100_cs-$(CONFIG_SA1100_CERF)			+= sa1100_cerf.o
+sa1100_cs-$(CONFIG_SA1100_COLLIE)		+= pxa2xx_sharpsl.o
+sa1100_cs-$(CONFIG_SA1100_H3100)		+= sa1100_h3600.o
+sa1100_cs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-$(CONFIG_SA1100_NANOENGINE)		+= sa1100_nanoengine.o
+sa1100_cs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
+sa1100_cs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
+
+pxa2xx_cm_x2xx_cs-y				+= pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
+pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)		+= pxa2xx_mainstone.o
+pxa2xx-obj-$(CONFIG_PXA_SHARPSL)		+= pxa2xx_sharpsl.o
+pxa2xx-obj-$(CONFIG_MACH_ARMCORE)		+= pxa2xx_cm_x2xx_cs.o
+pxa2xx-obj-$(CONFIG_ARCOM_PCMCIA)		+= pxa2xx_viper.o
+pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)		+= pxa2xx_trizeps4.o
+pxa2xx-obj-$(CONFIG_MACH_PALMTX)		+= pxa2xx_palmtx.o
+pxa2xx-obj-$(CONFIG_MACH_PALMTC)		+= pxa2xx_palmtc.o
+pxa2xx-obj-$(CONFIG_MACH_PALMLD)		+= pxa2xx_palmld.o
+pxa2xx-obj-$(CONFIG_MACH_E740)			+= pxa2xx_e740.o
+pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+= pxa2xx_stargate2.o
+pxa2xx-obj-$(CONFIG_MACH_VPAC270)		+= pxa2xx_vpac270.o
+pxa2xx-obj-$(CONFIG_MACH_BALLOON3)		+= pxa2xx_balloon3.o
+pxa2xx-obj-$(CONFIG_MACH_COLIBRI)		+= pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_COLIBRI320)		+= pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_H4700)			+= pxa2xx_hx4700.o
+
+obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_base.o $(pxa2xx-obj-y)
+
+obj-$(CONFIG_PCMCIA_XXS1500)			+= xxs1500_ss.o
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/at91_cf.c b/src/kernel/linux/v4.14/drivers/pcmcia/at91_cf.c
new file mode 100644
index 0000000..87147bc
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/at91_cf.c
@@ -0,0 +1,421 @@
+/*
+ * at91_cf.c -- AT91 CompactFlash controller driver
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/atmel.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-mc.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+
+#include <pcmcia/ss.h>
+
+/*
+ * A0..A10 work in each range; A23 indicates I/O space;  A25 is CFRNW;
+ * some other bit in {A24,A22..A11} is nREG to flag memory access
+ * (vs attributes).  So more than 2KB/region would just be waste.
+ * Note: These are offsets from the physical base address.
+ */
+#define	CF_ATTR_PHYS	(0)
+#define	CF_IO_PHYS	(1 << 23)
+#define	CF_MEM_PHYS	(0x017ff800)
+
+struct regmap *mc;
+
+/*--------------------------------------------------------------------------*/
+
+struct at91_cf_socket {
+	struct pcmcia_socket	socket;
+
+	unsigned		present:1;
+
+	struct platform_device	*pdev;
+	struct at91_cf_data	*board;
+
+	unsigned long		phys_baseaddr;
+};
+
+static inline int at91_cf_present(struct at91_cf_socket *cf)
+{
+	return !gpio_get_value(cf->board->det_pin);
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int at91_cf_ss_init(struct pcmcia_socket *s)
+{
+	return 0;
+}
+
+static irqreturn_t at91_cf_irq(int irq, void *_cf)
+{
+	struct at91_cf_socket *cf = _cf;
+
+	if (irq == gpio_to_irq(cf->board->det_pin)) {
+		unsigned present = at91_cf_present(cf);
+
+		/* kick pccard as needed */
+		if (present != cf->present) {
+			cf->present = present;
+			dev_dbg(&cf->pdev->dev, "card %s\n",
+					present ? "present" : "gone");
+			pcmcia_parse_events(&cf->socket, SS_DETECT);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+	struct at91_cf_socket	*cf;
+
+	if (!sp)
+		return -EINVAL;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+
+	/* NOTE: CF is always 3VCARD */
+	if (at91_cf_present(cf)) {
+		int rdy	= gpio_is_valid(cf->board->irq_pin);	/* RDY/nIRQ */
+		int vcc	= gpio_is_valid(cf->board->vcc_pin);
+
+		*sp = SS_DETECT | SS_3VCARD;
+		if (!rdy || gpio_get_value(cf->board->irq_pin))
+			*sp |= SS_READY;
+		if (!vcc || gpio_get_value(cf->board->vcc_pin))
+			*sp |= SS_POWERON;
+	} else
+		*sp = 0;
+
+	return 0;
+}
+
+static int
+at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+	struct at91_cf_socket	*cf;
+
+	cf = container_of(sock, struct at91_cf_socket, socket);
+
+	/* switch Vcc if needed and possible */
+	if (gpio_is_valid(cf->board->vcc_pin)) {
+		switch (s->Vcc) {
+		case 0:
+			gpio_set_value(cf->board->vcc_pin, 0);
+			break;
+		case 33:
+			gpio_set_value(cf->board->vcc_pin, 1);
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* toggle reset if needed */
+	gpio_set_value(cf->board->rst_pin, s->flags & SS_RESET);
+
+	dev_dbg(&cf->pdev->dev, "Vcc %d, io_irq %d, flags %04x csc %04x\n",
+				s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+	return 0;
+}
+
+static int at91_cf_ss_suspend(struct pcmcia_socket *s)
+{
+	return at91_cf_set_socket(s, &dead_socket);
+}
+
+/* we already mapped the I/O region */
+static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	struct at91_cf_socket	*cf;
+	u32			csr;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+	io->flags &= (MAP_ACTIVE | MAP_16BIT | MAP_AUTOSZ);
+
+	/*
+	 * Use 16 bit accesses unless/until we need 8-bit i/o space.
+	 *
+	 * NOTE: this CF controller ignores IOIS16, so we can't really do
+	 * MAP_AUTOSZ.  The 16bit mode allows single byte access on either
+	 * D0-D7 (even addr) or D8-D15 (odd), so it's close enough for many
+	 * purposes (and handles ide-cs).
+	 *
+	 * The 8bit mode is needed for odd byte access on D0-D7.  It seems
+	 * some cards only like that way to get at the odd byte, despite
+	 * CF 3.0 spec table 35 also giving the D8-D15 option.
+	 */
+	if (!(io->flags & (MAP_16BIT | MAP_AUTOSZ))) {
+		csr = AT91_MC_SMC_DBW_8;
+		dev_dbg(&cf->pdev->dev, "8bit i/o bus\n");
+	} else {
+		csr = AT91_MC_SMC_DBW_16;
+		dev_dbg(&cf->pdev->dev, "16bit i/o bus\n");
+	}
+	regmap_update_bits(mc, AT91_MC_SMC_CSR(cf->board->chipselect),
+			   AT91_MC_SMC_DBW, csr);
+
+	io->start = cf->socket.io_offset;
+	io->stop = io->start + SZ_2K - 1;
+
+	return 0;
+}
+
+/* pcmcia layer maps/unmaps mem regions */
+static int
+at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+	struct at91_cf_socket	*cf;
+
+	if (map->card_start)
+		return -EINVAL;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+
+	map->flags &= (MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT);
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = cf->phys_baseaddr + CF_ATTR_PHYS;
+	else
+		map->static_start = cf->phys_baseaddr + CF_MEM_PHYS;
+
+	return 0;
+}
+
+static struct pccard_operations at91_cf_ops = {
+	.init			= at91_cf_ss_init,
+	.suspend		= at91_cf_ss_suspend,
+	.get_status		= at91_cf_get_status,
+	.set_socket		= at91_cf_set_socket,
+	.set_io_map		= at91_cf_set_io_map,
+	.set_mem_map		= at91_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_cf_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-cf" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_cf_dt_ids);
+
+static int at91_cf_dt_init(struct platform_device *pdev)
+{
+	struct at91_cf_data *board;
+
+	board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
+	if (!board)
+		return -ENOMEM;
+
+	board->irq_pin = of_get_gpio(pdev->dev.of_node, 0);
+	board->det_pin = of_get_gpio(pdev->dev.of_node, 1);
+	board->vcc_pin = of_get_gpio(pdev->dev.of_node, 2);
+	board->rst_pin = of_get_gpio(pdev->dev.of_node, 3);
+
+	pdev->dev.platform_data = board;
+
+	mc = syscon_regmap_lookup_by_compatible("atmel,at91rm9200-sdramc");
+	if (IS_ERR(mc))
+		return PTR_ERR(mc);
+
+	return 0;
+}
+#else
+static int at91_cf_dt_init(struct platform_device *pdev)
+{
+	return -ENODEV;
+}
+#endif
+
+static int at91_cf_probe(struct platform_device *pdev)
+{
+	struct at91_cf_socket	*cf;
+	struct at91_cf_data	*board = pdev->dev.platform_data;
+	struct resource		*io;
+	int			status;
+
+	if (!board) {
+		status = at91_cf_dt_init(pdev);
+		if (status)
+			return status;
+
+		board = pdev->dev.platform_data;
+	}
+
+	if (!gpio_is_valid(board->det_pin) || !gpio_is_valid(board->rst_pin))
+		return -ENODEV;
+
+	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!io)
+		return -ENODEV;
+
+	cf = devm_kzalloc(&pdev->dev, sizeof(*cf), GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+
+	cf->board = board;
+	cf->pdev = pdev;
+	cf->phys_baseaddr = io->start;
+	platform_set_drvdata(pdev, cf);
+
+	/* must be a GPIO; ergo must trigger on both edges */
+	status = devm_gpio_request(&pdev->dev, board->det_pin, "cf_det");
+	if (status < 0)
+		return status;
+
+	status = devm_request_irq(&pdev->dev, gpio_to_irq(board->det_pin),
+					at91_cf_irq, 0, "at91_cf detect", cf);
+	if (status < 0)
+		return status;
+
+	device_init_wakeup(&pdev->dev, 1);
+
+	status = devm_gpio_request(&pdev->dev, board->rst_pin, "cf_rst");
+	if (status < 0)
+		goto fail0a;
+
+	if (gpio_is_valid(board->vcc_pin)) {
+		status = devm_gpio_request(&pdev->dev, board->vcc_pin, "cf_vcc");
+		if (status < 0)
+			goto fail0a;
+	}
+
+	/*
+	 * The card driver will request this irq later as needed.
+	 * but it causes lots of "irqNN: nobody cared" messages
+	 * unless we report that we handle everything (sigh).
+	 * (Note:  DK board doesn't wire the IRQ pin...)
+	 */
+	if (gpio_is_valid(board->irq_pin)) {
+		status = devm_gpio_request(&pdev->dev, board->irq_pin, "cf_irq");
+		if (status < 0)
+			goto fail0a;
+
+		status = devm_request_irq(&pdev->dev, gpio_to_irq(board->irq_pin),
+					at91_cf_irq, IRQF_SHARED, "at91_cf", cf);
+		if (status < 0)
+			goto fail0a;
+		cf->socket.pci_irq = gpio_to_irq(board->irq_pin);
+	} else
+		cf->socket.pci_irq = nr_irqs + 1;
+
+	/*
+	 * pcmcia layer only remaps "real" memory not iospace
+	 * io_offset is set to 0x10000 to avoid the check in static_find_io().
+	 * */
+	cf->socket.io_offset = 0x10000;
+	status = pci_ioremap_io(0x10000, cf->phys_baseaddr + CF_IO_PHYS);
+	if (status)
+		goto fail0a;
+
+	/* reserve chip-select regions */
+	if (!devm_request_mem_region(&pdev->dev, io->start, resource_size(io), "at91_cf")) {
+		status = -ENXIO;
+		goto fail0a;
+	}
+
+	dev_info(&pdev->dev, "irqs det #%d, io #%d\n",
+		gpio_to_irq(board->det_pin), gpio_to_irq(board->irq_pin));
+
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.dev.parent = &pdev->dev;
+	cf->socket.ops = &at91_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+				| SS_CAP_MEM_ALIGN;
+	cf->socket.map_size = SZ_2K;
+	cf->socket.io[0].res = io;
+
+	status = pcmcia_register_socket(&cf->socket);
+	if (status < 0)
+		goto fail0a;
+
+	return 0;
+
+fail0a:
+	device_init_wakeup(&pdev->dev, 0);
+	return status;
+}
+
+static int at91_cf_remove(struct platform_device *pdev)
+{
+	struct at91_cf_socket	*cf = platform_get_drvdata(pdev);
+
+	pcmcia_unregister_socket(&cf->socket);
+	device_init_wakeup(&pdev->dev, 0);
+
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	struct at91_cf_socket	*cf = platform_get_drvdata(pdev);
+	struct at91_cf_data	*board = cf->board;
+
+	if (device_may_wakeup(&pdev->dev)) {
+		enable_irq_wake(gpio_to_irq(board->det_pin));
+		if (gpio_is_valid(board->irq_pin))
+			enable_irq_wake(gpio_to_irq(board->irq_pin));
+	}
+	return 0;
+}
+
+static int at91_cf_resume(struct platform_device *pdev)
+{
+	struct at91_cf_socket	*cf = platform_get_drvdata(pdev);
+	struct at91_cf_data	*board = cf->board;
+
+	if (device_may_wakeup(&pdev->dev)) {
+		disable_irq_wake(gpio_to_irq(board->det_pin));
+		if (gpio_is_valid(board->irq_pin))
+			disable_irq_wake(gpio_to_irq(board->irq_pin));
+	}
+
+	return 0;
+}
+
+#else
+#define	at91_cf_suspend		NULL
+#define	at91_cf_resume		NULL
+#endif
+
+static struct platform_driver at91_cf_driver = {
+	.driver = {
+		.name		= "at91_cf",
+		.of_match_table = of_match_ptr(at91_cf_dt_ids),
+	},
+	.probe		= at91_cf_probe,
+	.remove		= at91_cf_remove,
+	.suspend	= at91_cf_suspend,
+	.resume		= at91_cf_resume,
+};
+
+module_platform_driver(at91_cf_driver);
+
+MODULE_DESCRIPTION("AT91 Compact Flash Driver");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_cf");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.c b/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.c
new file mode 100644
index 0000000..0802e0b
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.c
@@ -0,0 +1,537 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+#include "bcm63xx_pcmcia.h"
+
+#define PFX	"bcm63xx_pcmcia: "
+
+#ifdef CONFIG_CARDBUS
+/* if cardbus is used, platform device needs reference to actual pci
+ * device */
+static struct pci_dev *bcm63xx_cb_dev;
+#endif
+
+/*
+ * read/write helper for pcmcia regs
+ */
+static inline u32 pcmcia_readl(struct bcm63xx_pcmcia_socket *skt, u32 off)
+{
+	return bcm_readl(skt->base + off);
+}
+
+static inline void pcmcia_writel(struct bcm63xx_pcmcia_socket *skt,
+				 u32 val, u32 off)
+{
+	bcm_writel(val, skt->base + off);
+}
+
+/*
+ * This callback should (re-)initialise the socket, turn on status
+ * interrupts and PCMCIA bus, and wait for power to stabilise so that
+ * the card status signals report correctly.
+ *
+ * Hardware cannot do that.
+ */
+static int bcm63xx_pcmcia_sock_init(struct pcmcia_socket *sock)
+{
+	return 0;
+}
+
+/*
+ * This callback should remove power on the socket, disable IRQs from
+ * the card, turn off status interrupts, and disable the PCMCIA bus.
+ *
+ * Hardware cannot do that.
+ */
+static int bcm63xx_pcmcia_suspend(struct pcmcia_socket *sock)
+{
+	return 0;
+}
+
+/*
+ * Implements the set_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetSocket in Card Services). We more or
+ * less punt all of this work and let the kernel handle the details
+ * of power configuration, reset, &c. We also record the value of
+ * `state' in order to regurgitate it to the PCMCIA core later.
+ */
+static int bcm63xx_pcmcia_set_socket(struct pcmcia_socket *sock,
+				     socket_state_t *state)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+	unsigned long flags;
+	u32 val;
+
+	skt = sock->driver_data;
+
+	spin_lock_irqsave(&skt->lock, flags);
+
+	/* note: hardware cannot control socket power, so we will
+	 * always report SS_POWERON */
+
+	/* apply socket reset */
+	val = pcmcia_readl(skt, PCMCIA_C1_REG);
+	if (state->flags & SS_RESET)
+		val |= PCMCIA_C1_RESET_MASK;
+	else
+		val &= ~PCMCIA_C1_RESET_MASK;
+
+	/* reverse reset logic for cardbus card */
+	if (skt->card_detected && (skt->card_type & CARD_CARDBUS))
+		val ^= PCMCIA_C1_RESET_MASK;
+
+	pcmcia_writel(skt, val, PCMCIA_C1_REG);
+
+	/* keep requested state for event reporting */
+	skt->requested_state = *state;
+
+	spin_unlock_irqrestore(&skt->lock, flags);
+
+	return 0;
+}
+
+/*
+ * identity cardtype from VS[12] input, CD[12] input while only VS2 is
+ * floating, and CD[12] input while only VS1 is floating
+ */
+enum {
+	IN_VS1 = (1 << 0),
+	IN_VS2 = (1 << 1),
+	IN_CD1_VS2H = (1 << 2),
+	IN_CD2_VS2H = (1 << 3),
+	IN_CD1_VS1H = (1 << 4),
+	IN_CD2_VS1H = (1 << 5),
+};
+
+static const u8 vscd_to_cardtype[] = {
+
+	/* VS1 float, VS2 float */
+	[IN_VS1 | IN_VS2] = (CARD_PCCARD | CARD_5V),
+
+	/* VS1 grounded, VS2 float */
+	[IN_VS2] = (CARD_PCCARD | CARD_5V | CARD_3V),
+
+	/* VS1 grounded, VS2 grounded */
+	[0] = (CARD_PCCARD | CARD_5V | CARD_3V | CARD_XV),
+
+	/* VS1 tied to CD1, VS2 float */
+	[IN_VS1 | IN_VS2 | IN_CD1_VS1H] = (CARD_CARDBUS | CARD_3V),
+
+	/* VS1 grounded, VS2 tied to CD2 */
+	[IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V | CARD_XV),
+
+	/* VS1 tied to CD2, VS2 grounded */
+	[IN_VS1 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_3V | CARD_XV | CARD_YV),
+
+	/* VS1 float, VS2 grounded */
+	[IN_VS1] = (CARD_PCCARD | CARD_XV),
+
+	/* VS1 float, VS2 tied to CD2 */
+	[IN_VS1 | IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V),
+
+	/* VS1 float, VS2 tied to CD1 */
+	[IN_VS1 | IN_VS2 | IN_CD1_VS2H] = (CARD_CARDBUS | CARD_XV | CARD_YV),
+
+	/* VS1 tied to CD2, VS2 float */
+	[IN_VS1 | IN_VS2 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_YV),
+
+	/* VS2 grounded, VS1 is tied to CD1, CD2 is grounded */
+	[IN_VS1 | IN_CD1_VS1H] = 0, /* ignore cardbay */
+};
+
+/*
+ * poll hardware to check card insertion status
+ */
+static unsigned int __get_socket_status(struct bcm63xx_pcmcia_socket *skt)
+{
+	unsigned int stat;
+	u32 val;
+
+	stat = 0;
+
+	/* check CD for card presence */
+	val = pcmcia_readl(skt, PCMCIA_C1_REG);
+
+	if (!(val & PCMCIA_C1_CD1_MASK) && !(val & PCMCIA_C1_CD2_MASK))
+		stat |= SS_DETECT;
+
+	/* if new insertion, detect cardtype */
+	if ((stat & SS_DETECT) && !skt->card_detected) {
+		unsigned int stat = 0;
+
+		/* float VS1, float VS2 */
+		val |= PCMCIA_C1_VS1OE_MASK;
+		val |= PCMCIA_C1_VS2OE_MASK;
+		pcmcia_writel(skt, val, PCMCIA_C1_REG);
+
+		/* wait for output to stabilize and read VS[12] */
+		udelay(10);
+		val = pcmcia_readl(skt, PCMCIA_C1_REG);
+		stat |= (val & PCMCIA_C1_VS1_MASK) ? IN_VS1 : 0;
+		stat |= (val & PCMCIA_C1_VS2_MASK) ? IN_VS2 : 0;
+
+		/* drive VS1 low, float VS2 */
+		val &= ~PCMCIA_C1_VS1OE_MASK;
+		val |= PCMCIA_C1_VS2OE_MASK;
+		pcmcia_writel(skt, val, PCMCIA_C1_REG);
+
+		/* wait for output to stabilize and read CD[12] */
+		udelay(10);
+		val = pcmcia_readl(skt, PCMCIA_C1_REG);
+		stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS2H : 0;
+		stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS2H : 0;
+
+		/* float VS1, drive VS2 low */
+		val |= PCMCIA_C1_VS1OE_MASK;
+		val &= ~PCMCIA_C1_VS2OE_MASK;
+		pcmcia_writel(skt, val, PCMCIA_C1_REG);
+
+		/* wait for output to stabilize and read CD[12] */
+		udelay(10);
+		val = pcmcia_readl(skt, PCMCIA_C1_REG);
+		stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS1H : 0;
+		stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS1H : 0;
+
+		/* guess cardtype from all this */
+		skt->card_type = vscd_to_cardtype[stat];
+		if (!skt->card_type)
+			dev_err(&skt->socket.dev, "unsupported card type\n");
+
+		/* drive both VS pin to 0 again */
+		val &= ~(PCMCIA_C1_VS1OE_MASK | PCMCIA_C1_VS2OE_MASK);
+
+		/* enable correct logic */
+		val &= ~(PCMCIA_C1_EN_PCMCIA_MASK | PCMCIA_C1_EN_CARDBUS_MASK);
+		if (skt->card_type & CARD_PCCARD)
+			val |= PCMCIA_C1_EN_PCMCIA_MASK;
+		else
+			val |= PCMCIA_C1_EN_CARDBUS_MASK;
+
+		pcmcia_writel(skt, val, PCMCIA_C1_REG);
+	}
+	skt->card_detected = (stat & SS_DETECT) ? 1 : 0;
+
+	/* report card type/voltage */
+	if (skt->card_type & CARD_CARDBUS)
+		stat |= SS_CARDBUS;
+	if (skt->card_type & CARD_3V)
+		stat |= SS_3VCARD;
+	if (skt->card_type & CARD_XV)
+		stat |= SS_XVCARD;
+	stat |= SS_POWERON;
+
+	if (gpio_get_value(skt->pd->ready_gpio))
+		stat |= SS_READY;
+
+	return stat;
+}
+
+/*
+ * core request to get current socket status
+ */
+static int bcm63xx_pcmcia_get_status(struct pcmcia_socket *sock,
+				     unsigned int *status)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+
+	skt = sock->driver_data;
+
+	spin_lock_bh(&skt->lock);
+	*status = __get_socket_status(skt);
+	spin_unlock_bh(&skt->lock);
+
+	return 0;
+}
+
+/*
+ * socket polling timer callback
+ */
+static void bcm63xx_pcmcia_poll(unsigned long data)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+	unsigned int stat, events;
+
+	skt = (struct bcm63xx_pcmcia_socket *)data;
+
+	spin_lock_bh(&skt->lock);
+
+	stat = __get_socket_status(skt);
+
+	/* keep only changed bits, and mask with required one from the
+	 * core */
+	events = (stat ^ skt->old_status) & skt->requested_state.csc_mask;
+	skt->old_status = stat;
+	spin_unlock_bh(&skt->lock);
+
+	if (events)
+		pcmcia_parse_events(&skt->socket, events);
+
+	mod_timer(&skt->timer,
+		  jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
+}
+
+static int bcm63xx_pcmcia_set_io_map(struct pcmcia_socket *sock,
+				     struct pccard_io_map *map)
+{
+	/* this doesn't seem to be called by pcmcia layer if static
+	 * mapping is used */
+	return 0;
+}
+
+static int bcm63xx_pcmcia_set_mem_map(struct pcmcia_socket *sock,
+				      struct pccard_mem_map *map)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+	struct resource *res;
+
+	skt = sock->driver_data;
+	if (map->flags & MAP_ATTRIB)
+		res = skt->attr_res;
+	else
+		res = skt->common_res;
+
+	map->static_start = res->start + map->card_start;
+	return 0;
+}
+
+static struct pccard_operations bcm63xx_pcmcia_operations = {
+	.init			= bcm63xx_pcmcia_sock_init,
+	.suspend		= bcm63xx_pcmcia_suspend,
+	.get_status		= bcm63xx_pcmcia_get_status,
+	.set_socket		= bcm63xx_pcmcia_set_socket,
+	.set_io_map		= bcm63xx_pcmcia_set_io_map,
+	.set_mem_map		= bcm63xx_pcmcia_set_mem_map,
+};
+
+/*
+ * register pcmcia socket to core
+ */
+static int bcm63xx_drv_pcmcia_probe(struct platform_device *pdev)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+	struct pcmcia_socket *sock;
+	struct resource *res, *irq_res;
+	unsigned int regmem_size = 0, iomem_size = 0;
+	u32 val;
+	int ret;
+
+	skt = kzalloc(sizeof(*skt), GFP_KERNEL);
+	if (!skt)
+		return -ENOMEM;
+	spin_lock_init(&skt->lock);
+	sock = &skt->socket;
+	sock->driver_data = skt;
+
+	/* make sure we have all resources we need */
+	skt->common_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	skt->attr_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	skt->pd = pdev->dev.platform_data;
+	if (!skt->common_res || !skt->attr_res || !irq_res || !skt->pd) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* remap pcmcia registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regmem_size = resource_size(res);
+	if (!request_mem_region(res->start, regmem_size, "bcm63xx_pcmcia")) {
+		ret = -EINVAL;
+		goto err;
+	}
+	skt->reg_res = res;
+
+	skt->base = ioremap(res->start, regmem_size);
+	if (!skt->base) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* remap io registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	iomem_size = resource_size(res);
+	skt->io_base = ioremap(res->start, iomem_size);
+	if (!skt->io_base) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* resources are static */
+	sock->resource_ops = &pccard_static_ops;
+	sock->ops = &bcm63xx_pcmcia_operations;
+	sock->owner = THIS_MODULE;
+	sock->dev.parent = &pdev->dev;
+	sock->features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->io_offset = (unsigned long)skt->io_base;
+	sock->pci_irq = irq_res->start;
+
+#ifdef CONFIG_CARDBUS
+	sock->cb_dev = bcm63xx_cb_dev;
+	if (bcm63xx_cb_dev)
+		sock->features |= SS_CAP_CARDBUS;
+#endif
+
+	/* assume common & attribute memory have the same size */
+	sock->map_size = resource_size(skt->common_res);
+
+	/* initialize polling timer */
+	setup_timer(&skt->timer, bcm63xx_pcmcia_poll, (unsigned long)skt);
+
+	/* initialize  pcmcia  control register,  drive  VS[12] to  0,
+	 * leave CB IDSEL to the old  value since it is set by the PCI
+	 * layer */
+	val = pcmcia_readl(skt, PCMCIA_C1_REG);
+	val &= PCMCIA_C1_CBIDSEL_MASK;
+	val |= PCMCIA_C1_EN_PCMCIA_GPIO_MASK;
+	pcmcia_writel(skt, val, PCMCIA_C1_REG);
+
+	/*
+	 * Hardware has only one set of timings registers, not one for
+	 * each memory access type, so we configure them for the
+	 * slowest one: attribute memory.
+	 */
+	val = PCMCIA_C2_DATA16_MASK;
+	val |= 10 << PCMCIA_C2_RWCOUNT_SHIFT;
+	val |= 6 << PCMCIA_C2_INACTIVE_SHIFT;
+	val |= 3 << PCMCIA_C2_SETUP_SHIFT;
+	val |= 3 << PCMCIA_C2_HOLD_SHIFT;
+	pcmcia_writel(skt, val, PCMCIA_C2_REG);
+
+	ret = pcmcia_register_socket(sock);
+	if (ret)
+		goto err;
+
+	/* start polling socket */
+	mod_timer(&skt->timer,
+		  jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
+
+	platform_set_drvdata(pdev, skt);
+	return 0;
+
+err:
+	if (skt->io_base)
+		iounmap(skt->io_base);
+	if (skt->base)
+		iounmap(skt->base);
+	if (skt->reg_res)
+		release_mem_region(skt->reg_res->start, regmem_size);
+	kfree(skt);
+	return ret;
+}
+
+static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
+{
+	struct bcm63xx_pcmcia_socket *skt;
+	struct resource *res;
+
+	skt = platform_get_drvdata(pdev);
+	del_timer_sync(&skt->timer);
+	iounmap(skt->base);
+	iounmap(skt->io_base);
+	res = skt->reg_res;
+	release_mem_region(res->start, resource_size(res));
+	kfree(skt);
+	return 0;
+}
+
+struct platform_driver bcm63xx_pcmcia_driver = {
+	.probe	= bcm63xx_drv_pcmcia_probe,
+	.remove	= bcm63xx_drv_pcmcia_remove,
+	.driver	= {
+		.name	= "bcm63xx_pcmcia",
+		.owner  = THIS_MODULE,
+	},
+};
+
+#ifdef CONFIG_CARDBUS
+static int bcm63xx_cb_probe(struct pci_dev *dev,
+				      const struct pci_device_id *id)
+{
+	/* keep pci device */
+	bcm63xx_cb_dev = dev;
+	return platform_driver_register(&bcm63xx_pcmcia_driver);
+}
+
+static void bcm63xx_cb_exit(struct pci_dev *dev)
+{
+	platform_driver_unregister(&bcm63xx_pcmcia_driver);
+	bcm63xx_cb_dev = NULL;
+}
+
+static const struct pci_device_id bcm63xx_cb_table[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_BROADCOM,
+		.device		= BCM6348_CPU_ID,
+		.subvendor	= PCI_VENDOR_ID_BROADCOM,
+		.subdevice	= PCI_ANY_ID,
+		.class		= PCI_CLASS_BRIDGE_CARDBUS << 8,
+		.class_mask	= ~0,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_BROADCOM,
+		.device		= BCM6358_CPU_ID,
+		.subvendor	= PCI_VENDOR_ID_BROADCOM,
+		.subdevice	= PCI_ANY_ID,
+		.class		= PCI_CLASS_BRIDGE_CARDBUS << 8,
+		.class_mask	= ~0,
+	},
+
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, bcm63xx_cb_table);
+
+static struct pci_driver bcm63xx_cardbus_driver = {
+	.name		= "bcm63xx_cardbus",
+	.id_table	= bcm63xx_cb_table,
+	.probe		= bcm63xx_cb_probe,
+	.remove		= bcm63xx_cb_exit,
+};
+#endif
+
+/*
+ * if cardbus support is enabled, register our platform device after
+ * our fake cardbus bridge has been registered
+ */
+static int __init bcm63xx_pcmcia_init(void)
+{
+#ifdef CONFIG_CARDBUS
+	return pci_register_driver(&bcm63xx_cardbus_driver);
+#else
+	return platform_driver_register(&bcm63xx_pcmcia_driver);
+#endif
+}
+
+static void __exit bcm63xx_pcmcia_exit(void)
+{
+#ifdef CONFIG_CARDBUS
+	return pci_unregister_driver(&bcm63xx_cardbus_driver);
+#else
+	platform_driver_unregister(&bcm63xx_pcmcia_driver);
+#endif
+}
+
+module_init(bcm63xx_pcmcia_init);
+module_exit(bcm63xx_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm63xx Socket Controller");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.h b/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.h
new file mode 100644
index 0000000..2122c59
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/bcm63xx_pcmcia.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef BCM63XX_PCMCIA_H_
+#define BCM63XX_PCMCIA_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <pcmcia/ss.h>
+#include <bcm63xx_dev_pcmcia.h>
+
+/* socket polling rate in ms */
+#define BCM63XX_PCMCIA_POLL_RATE	500
+
+enum {
+	CARD_CARDBUS = (1 << 0),
+	CARD_PCCARD = (1 << 1),
+	CARD_5V = (1 << 2),
+	CARD_3V = (1 << 3),
+	CARD_XV = (1 << 4),
+	CARD_YV = (1 << 5),
+};
+
+struct bcm63xx_pcmcia_socket {
+	struct pcmcia_socket socket;
+
+	/* platform specific data */
+	struct bcm63xx_pcmcia_platform_data *pd;
+
+	/* all regs access are protected by this spinlock */
+	spinlock_t lock;
+
+	/* pcmcia registers resource */
+	struct resource *reg_res;
+
+	/* base remapped address of registers */
+	void __iomem *base;
+
+	/* whether a card is detected at the moment */
+	int card_detected;
+
+	/* type of detected card (mask of above enum) */
+	u8 card_type;
+
+	/* keep last socket status to implement event reporting */
+	unsigned int old_status;
+
+	/* backup of requested socket state */
+	socket_state_t requested_state;
+
+	/* timer used for socket status polling */
+	struct timer_list timer;
+
+	/* attribute/common memory resources */
+	struct resource *attr_res;
+	struct resource *common_res;
+	struct resource *io_res;
+
+	/* base address of io memory */
+	void __iomem *io_base;
+};
+
+#endif /* BCM63XX_PCMCIA_H_ */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/bfin_cf_pcmcia.c b/src/kernel/linux/v4.14/drivers/pcmcia/bfin_cf_pcmcia.c
new file mode 100644
index 0000000..8b0923f
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/bfin_cf_pcmcia.c
@@ -0,0 +1,316 @@
+/*
+ * file: drivers/pcmcia/bfin_cf.c
+ *
+ * based on: drivers/pcmcia/omap_cf.c
+ * omap_cf.c -- OMAP 16xx CompactFlash controller driver
+ *
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc.
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see the
+ * gnu general public license for more details.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cisreg.h>
+
+#define	SZ_1K	0x00000400
+#define	SZ_8K	0x00002000
+#define	SZ_2K	(2 * SZ_1K)
+
+#define	POLL_INTERVAL	(2 * HZ)
+
+#define	CF_ATASEL_ENA 	0x20311802	/* Inverts RESET */
+#define	CF_ATASEL_DIS 	0x20311800
+
+#define bfin_cf_present(pfx) (gpio_get_value(pfx))
+
+/*--------------------------------------------------------------------------*/
+
+static const char driver_name[] = "bfin_cf_pcmcia";
+
+struct bfin_cf_socket {
+	struct pcmcia_socket socket;
+
+	struct timer_list timer;
+	unsigned present:1;
+	unsigned active:1;
+
+	struct platform_device *pdev;
+	unsigned long phys_cf_io;
+	unsigned long phys_cf_attr;
+	u_int irq;
+	u_short cd_pfx;
+};
+
+/*--------------------------------------------------------------------------*/
+static int bfin_cf_reset(void)
+{
+	outw(0, CF_ATASEL_ENA);
+	mdelay(200);
+	outw(0, CF_ATASEL_DIS);
+
+	return 0;
+}
+
+static int bfin_cf_ss_init(struct pcmcia_socket *s)
+{
+	return 0;
+}
+
+/* the timer is primarily to kick this socket's pccardd */
+static void bfin_cf_timer(unsigned long _cf)
+{
+	struct bfin_cf_socket *cf = (void *)_cf;
+	unsigned short present = bfin_cf_present(cf->cd_pfx);
+
+	if (present != cf->present) {
+		cf->present = present;
+		dev_dbg(&cf->pdev->dev, ": card %s\n",
+			 present ? "present" : "gone");
+		pcmcia_parse_events(&cf->socket, SS_DETECT);
+	}
+
+	if (cf->active)
+		mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+}
+
+static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+	struct bfin_cf_socket *cf;
+
+	if (!sp)
+		return -EINVAL;
+
+	cf = container_of(s, struct bfin_cf_socket, socket);
+
+	if (bfin_cf_present(cf->cd_pfx)) {
+		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+		s->pcmcia_irq = 0;
+		s->pci_irq = cf->irq;
+
+	} else
+		*sp = 0;
+	return 0;
+}
+
+static int
+bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+
+	struct bfin_cf_socket *cf;
+	cf = container_of(sock, struct bfin_cf_socket, socket);
+
+	switch (s->Vcc) {
+	case 0:
+	case 33:
+		break;
+	case 50:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (s->flags & SS_RESET) {
+		disable_irq(cf->irq);
+		bfin_cf_reset();
+		enable_irq(cf->irq);
+	}
+
+	dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
+		 s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+	return 0;
+}
+
+static int bfin_cf_ss_suspend(struct pcmcia_socket *s)
+{
+	return bfin_cf_set_socket(s, &dead_socket);
+}
+
+/* regions are 2K each:  mem, attrib, io (and reserved-for-ide) */
+
+static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	struct bfin_cf_socket *cf;
+
+	cf = container_of(s, struct bfin_cf_socket, socket);
+	io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
+	io->start = cf->phys_cf_io;
+	io->stop = io->start + SZ_2K - 1;
+	return 0;
+}
+
+static int
+bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+	struct bfin_cf_socket *cf;
+
+	if (map->card_start)
+		return -EINVAL;
+	cf = container_of(s, struct bfin_cf_socket, socket);
+	map->static_start = cf->phys_cf_io;
+	map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = cf->phys_cf_attr;
+
+	return 0;
+}
+
+static struct pccard_operations bfin_cf_ops = {
+	.init = bfin_cf_ss_init,
+	.suspend = bfin_cf_ss_suspend,
+	.get_status = bfin_cf_get_status,
+	.set_socket = bfin_cf_set_socket,
+	.set_io_map = bfin_cf_set_io_map,
+	.set_mem_map = bfin_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int bfin_cf_probe(struct platform_device *pdev)
+{
+	struct bfin_cf_socket *cf;
+	struct resource *io_mem, *attr_mem;
+	int irq;
+	unsigned short cd_pfx;
+	int status = 0;
+
+	dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return -EINVAL;
+
+	cd_pfx = platform_get_irq(pdev, 1);	/*Card Detect GPIO PIN */
+
+	if (gpio_request(cd_pfx, "pcmcia: CD")) {
+		dev_err(&pdev->dev,
+		       "Failed ro request Card Detect GPIO_%d\n",
+		       cd_pfx);
+		return -EBUSY;
+	}
+	gpio_direction_input(cd_pfx);
+
+	cf = kzalloc(sizeof *cf, GFP_KERNEL);
+	if (!cf) {
+		gpio_free(cd_pfx);
+		return -ENOMEM;
+	}
+
+	cf->cd_pfx = cd_pfx;
+
+	setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
+
+	cf->pdev = pdev;
+	platform_set_drvdata(pdev, cf);
+
+	cf->irq = irq;
+	cf->socket.pci_irq = irq;
+
+	irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
+
+	io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+	if (!io_mem || !attr_mem)
+		goto fail0;
+
+	cf->phys_cf_io = io_mem->start;
+	cf->phys_cf_attr = attr_mem->start;
+
+	/* pcmcia layer only remaps "real" memory */
+	cf->socket.io_offset = (unsigned long)
+	    ioremap(cf->phys_cf_io, SZ_2K);
+
+	if (!cf->socket.io_offset)
+		goto fail0;
+
+	dev_err(&pdev->dev, ": on irq %d\n", irq);
+
+	dev_dbg(&pdev->dev, ": %s\n",
+		 bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)");
+
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.dev.parent = &pdev->dev;
+	cf->socket.ops = &bfin_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+	    | SS_CAP_MEM_ALIGN;
+	cf->socket.map_size = SZ_2K;
+
+	status = pcmcia_register_socket(&cf->socket);
+	if (status < 0)
+		goto fail2;
+
+	cf->active = 1;
+	mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+	return 0;
+
+fail2:
+	iounmap((void __iomem *)cf->socket.io_offset);
+	release_mem_region(cf->phys_cf_io, SZ_8K);
+
+fail0:
+	gpio_free(cf->cd_pfx);
+	kfree(cf);
+	platform_set_drvdata(pdev, NULL);
+
+	return status;
+}
+
+static int bfin_cf_remove(struct platform_device *pdev)
+{
+	struct bfin_cf_socket *cf = platform_get_drvdata(pdev);
+
+	gpio_free(cf->cd_pfx);
+	cf->active = 0;
+	pcmcia_unregister_socket(&cf->socket);
+	del_timer_sync(&cf->timer);
+	iounmap((void __iomem *)cf->socket.io_offset);
+	release_mem_region(cf->phys_cf_io, SZ_8K);
+	platform_set_drvdata(pdev, NULL);
+	kfree(cf);
+	return 0;
+}
+
+static struct platform_driver bfin_cf_driver = {
+	.driver = {
+		   .name = driver_name,
+		   },
+	.probe = bfin_cf_probe,
+	.remove = bfin_cf_remove,
+};
+
+module_platform_driver(bfin_cf_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/cardbus.c b/src/kernel/linux/v4.14/drivers/pcmcia/cardbus.c
new file mode 100644
index 0000000..4fe4cc4
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/cardbus.c
@@ -0,0 +1,126 @@
+/*
+ * cardbus.c -- 16-bit PCMCIA core support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+/*
+ * Cardbus handling has been re-written to be more of a PCI bridge thing,
+ * and the PCI code basically does all the resource handling.
+ *
+ *		Linus, Jan 2000
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+
+
+static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		u8 irq_pin;
+
+		/*
+		 * Since there is only one interrupt available to
+		 * CardBus devices, all devices downstream of this
+		 * device must be using this IRQ.
+		 */
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
+		if (irq_pin) {
+			dev->irq = irq;
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		}
+
+		/*
+		 * Some controllers transfer very slowly with 0 CLS.
+		 * Configure it.  This may fail as CLS configuration
+		 * is mandatory only for MWI.
+		 */
+		pci_set_cacheline_size(dev);
+
+		if (dev->subordinate)
+			cardbus_config_irq_and_cls(dev->subordinate, irq);
+	}
+}
+
+/**
+ * cb_alloc() - add CardBus device
+ * @s:		the pcmcia_socket where the CardBus device is located
+ *
+ * cb_alloc() allocates the kernel data structures for a Cardbus device
+ * and handles the lowest level PCI device setup issues.
+ */
+int __ref cb_alloc(struct pcmcia_socket *s)
+{
+	struct pci_bus *bus = s->cb_dev->subordinate;
+	struct pci_dev *dev;
+	unsigned int max, pass;
+
+	pci_lock_rescan_remove();
+
+	s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
+	pci_fixup_cardbus(bus);
+
+	max = bus->busn_res.start;
+	for (pass = 0; pass < 2; pass++)
+		list_for_each_entry(dev, &bus->devices, bus_list)
+			if (pci_is_bridge(dev))
+				max = pci_scan_bridge(bus, dev, max, pass);
+
+	/*
+	 * Size all resources below the CardBus controller.
+	 */
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	cardbus_config_irq_and_cls(bus, s->pci_irq);
+
+	/* socket specific tune function */
+	if (s->tune_bridge)
+		s->tune_bridge(s, bus);
+
+	pci_bus_add_devices(bus);
+
+	pci_unlock_rescan_remove();
+	return 0;
+}
+
+/**
+ * cb_free() - remove CardBus device
+ * @s:		the pcmcia_socket where the CardBus device was located
+ *
+ * cb_free() handles the lowest level PCI device cleanup.
+ */
+void cb_free(struct pcmcia_socket *s)
+{
+	struct pci_dev *bridge, *dev, *tmp;
+	struct pci_bus *bus;
+
+	bridge = s->cb_dev;
+	if (!bridge)
+		return;
+
+	bus = bridge->subordinate;
+	if (!bus)
+		return;
+
+	pci_lock_rescan_remove();
+
+	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list)
+		pci_stop_and_remove_bus_device(dev);
+
+	pci_unlock_rescan_remove();
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/cirrus.h b/src/kernel/linux/v4.14/drivers/pcmcia/cirrus.h
new file mode 100644
index 0000000..446a457
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/cirrus.h
@@ -0,0 +1,147 @@
+/*
+ * cirrus.h 1.4 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#define PD67_MISC_CTL_1		0x16	/* Misc control 1 */
+#define PD67_FIFO_CTL		0x17	/* FIFO control */
+#define PD67_MISC_CTL_2		0x1E	/* Misc control 2 */
+#define PD67_CHIP_INFO		0x1f	/* Chip information */
+#define PD67_ATA_CTL		0x026	/* 6730: ATA control */
+#define PD67_EXT_INDEX		0x2e	/* Extension index */
+#define PD67_EXT_DATA		0x2f	/* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0		0x01	/* Data mask 0 */
+#define PD67_DATA_MASK1		0x02	/* Data mask 1 */
+#define PD67_DMA_CTL		0x03	/* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1		0x03	/* Extension control 1 */
+#define PD67_MEM_PAGE(n)	((n)+5)	/* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA	0x0a
+#define PD67_MISC_CTL_3		0x25
+#define PD67_SMB_PWR_CTL	0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w)		(0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n)	(0x3a + 3*(n))
+#define PD67_TIME_CMD(n)	(0x3b + 3*(n))
+#define PD67_TIME_RECOV(n)	(0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET		0x01	/* 5v detect */
+#define PD67_MC1_MEDIA_ENA	0x01	/* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V		0x02	/* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT	0x04
+#define PD67_MC1_PULSE_IRQ	0x08
+#define PD67_MC1_SPKR_ENA	0x10
+#define PD67_MC1_INPACK_ENA	0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY		0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS	0x01
+#define PD67_MC2_DYNAMIC_MODE	0x02
+#define PD67_MC2_SUSPEND	0x04
+#define PD67_MC2_5V_CORE	0x08
+#define PD67_MC2_LED_ENA	0x10	/* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI	0x10	/* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7	0x20	/* Floppy change bit */
+#define PD67_MC2_DMA_MODE	0x40
+#define PD67_MC2_IRQ15_RI	0x80	/* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS		0x20	/* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID	0xc0
+#define PD67_INFO_REV		0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE		0xc0
+#define PD67_TIME_SCALE_1	0x00
+#define PD67_TIME_SCALE_16	0x40
+#define PD67_TIME_SCALE_256	0x80
+#define PD67_TIME_SCALE_4096	0xc0
+#define PD67_TIME_MULT		0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE		0xc0
+#define PD67_DMA_OFF		0x00
+#define PD67_DMA_DREQ_INPACK	0x40
+#define PD67_DMA_DREQ_WP	0x80
+#define PD67_DMA_DREQ_BVD2	0xc0
+#define PD67_DMA_PULLUP		0x20	/* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK	0x01
+#define PD67_EC1_AUTO_PWR_CLEAR	0x02
+#define PD67_EC1_LED_ENA	0x04
+#define PD67_EC1_INV_CARD_IRQ	0x08
+#define PD67_EC1_INV_MGMT_IRQ	0x10
+#define PD67_EC1_PULLUP_CTL	0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK	0x03
+#define PD67_MC3_IRQ_PCPCI	0x00
+#define PD67_MC3_IRQ_EXTERN	0x01
+#define PD67_MC3_IRQ_PCIWAY	0x02
+#define PD67_MC3_IRQ_PCI	0x03
+#define PD67_MC3_PWR_MASK	0x0c
+#define PD67_MC3_PWR_SERIAL	0x00
+#define PD67_MC3_PWR_TI2202	0x08
+#define PD67_MC3_PWR_SMB	0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2			0x0b
+#define PD68_PCI_SPACE			0x22
+#define PD68_PCCARD_SPACE		0x23
+#define PD68_WINDOW_TYPE		0x24
+#define PD68_EXT_CSC			0x2e
+#define PD68_MISC_CTL_4			0x2f
+#define PD68_MISC_CTL_5			0x30
+#define PD68_MISC_CTL_6			0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP		0x10
+#define PD68_MC3_MM_EXPAND		0x40
+#define PD68_MC3_MM_ARM			0x80
+
+/* Bridge Control Register */
+#define  PD6832_BCR_MGMT_IRQ_ENA	0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER		0x004c	/* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/cistpl.c b/src/kernel/linux/v4.14/drivers/pcmcia/cistpl.c
new file mode 100644
index 0000000..55ef7d1
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/cistpl.c
@@ -0,0 +1,1607 @@
+/*
+ * cistpl.c -- 16-bit PCMCIA Card Information Structure parser
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+static const u_char mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+    (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+    (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v)		(exponent[(v)&7])
+
+/* Upper limit on reasonable # of tuples */
+#define MAX_TUPLES		200
+
+/* Bits in IRQInfo1 field */
+#define IRQ_INFO2_VALID		0x10
+
+/* 16-bit CIS? */
+static int cis_width;
+module_param(cis_width, int, 0444);
+
+void release_cis_mem(struct pcmcia_socket *s)
+{
+	mutex_lock(&s->ops_mutex);
+	if (s->cis_mem.flags & MAP_ACTIVE) {
+		s->cis_mem.flags &= ~MAP_ACTIVE;
+		s->ops->set_mem_map(s, &s->cis_mem);
+		if (s->cis_mem.res) {
+			release_resource(s->cis_mem.res);
+			kfree(s->cis_mem.res);
+			s->cis_mem.res = NULL;
+		}
+		iounmap(s->cis_virt);
+		s->cis_virt = NULL;
+	}
+	mutex_unlock(&s->ops_mutex);
+}
+
+/**
+ * set_cis_map() - map the card memory at "card_offset" into virtual space.
+ *
+ * If flags & MAP_ATTRIB, map the attribute space, otherwise
+ * map the memory space.
+ *
+ * Must be called with ops_mutex held.
+ */
+static void __iomem *set_cis_map(struct pcmcia_socket *s,
+				unsigned int card_offset, unsigned int flags)
+{
+	pccard_mem_map *mem = &s->cis_mem;
+	int ret;
+
+	if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
+		mem->res = pcmcia_find_mem_region(0, s->map_size,
+						s->map_size, 0, s);
+		if (mem->res == NULL) {
+			dev_notice(&s->dev, "cs: unable to map card memory!\n");
+			return NULL;
+		}
+		s->cis_virt = NULL;
+	}
+
+	if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
+		s->cis_virt = ioremap(mem->res->start, s->map_size);
+
+	mem->card_start = card_offset;
+	mem->flags = flags;
+
+	ret = s->ops->set_mem_map(s, mem);
+	if (ret) {
+		iounmap(s->cis_virt);
+		s->cis_virt = NULL;
+		return NULL;
+	}
+
+	if (s->features & SS_CAP_STATIC_MAP) {
+		if (s->cis_virt)
+			iounmap(s->cis_virt);
+		s->cis_virt = ioremap(mem->static_start, s->map_size);
+	}
+
+	return s->cis_virt;
+}
+
+
+/* Bits in attr field */
+#define IS_ATTR		1
+#define IS_INDIRECT	8
+
+/**
+ * pcmcia_read_cis_mem() - low-level function to read CIS memory
+ *
+ * must be called with ops_mutex held
+ */
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+		 u_int len, void *ptr)
+{
+	void __iomem *sys, *end;
+	unsigned char *buf = ptr;
+
+	dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+
+	if (attr & IS_INDIRECT) {
+		/* Indirect accesses use a bunch of special registers at fixed
+		   locations in common memory */
+		u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+		if (attr & IS_ATTR) {
+			addr *= 2;
+			flags = ICTRL0_AUTOINC;
+		}
+
+		sys = set_cis_map(s, 0, MAP_ACTIVE |
+				((cis_width) ? MAP_16BIT : 0));
+		if (!sys) {
+			dev_dbg(&s->dev, "could not map memory\n");
+			memset(ptr, 0xff, len);
+			return -1;
+		}
+
+		writeb(flags, sys+CISREG_ICTRL0);
+		writeb(addr & 0xff, sys+CISREG_IADDR0);
+		writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+		writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+		writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
+		for ( ; len > 0; len--, buf++)
+			*buf = readb(sys+CISREG_IDATA0);
+	} else {
+		u_int inc = 1, card_offset, flags;
+
+		if (addr > CISTPL_MAX_CIS_SIZE) {
+			dev_dbg(&s->dev,
+				"attempt to read CIS mem at addr %#x", addr);
+			memset(ptr, 0xff, len);
+			return -1;
+		}
+
+		flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+		if (attr) {
+			flags |= MAP_ATTRIB;
+			inc++;
+			addr *= 2;
+		}
+
+		card_offset = addr & ~(s->map_size-1);
+		while (len) {
+			sys = set_cis_map(s, card_offset, flags);
+			if (!sys) {
+				dev_dbg(&s->dev, "could not map memory\n");
+				memset(ptr, 0xff, len);
+				return -1;
+			}
+			end = sys + s->map_size;
+			sys = sys + (addr & (s->map_size-1));
+			for ( ; len > 0; len--, buf++, sys += inc) {
+				if (sys == end)
+					break;
+				*buf = readb(sys);
+			}
+			card_offset += s->map_size;
+			addr = 0;
+		}
+	}
+	dev_dbg(&s->dev, "  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+		*(u_char *)(ptr+0), *(u_char *)(ptr+1),
+		*(u_char *)(ptr+2), *(u_char *)(ptr+3));
+	return 0;
+}
+
+
+/**
+ * pcmcia_write_cis_mem() - low-level function to write CIS memory
+ *
+ * Probably only useful for writing one-byte registers. Must be called
+ * with ops_mutex held.
+ */
+int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+		   u_int len, void *ptr)
+{
+	void __iomem *sys, *end;
+	unsigned char *buf = ptr;
+
+	dev_dbg(&s->dev,
+		"pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+
+	if (attr & IS_INDIRECT) {
+		/* Indirect accesses use a bunch of special registers at fixed
+		   locations in common memory */
+		u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+		if (attr & IS_ATTR) {
+			addr *= 2;
+			flags = ICTRL0_AUTOINC;
+		}
+
+		sys = set_cis_map(s, 0, MAP_ACTIVE |
+				((cis_width) ? MAP_16BIT : 0));
+		if (!sys) {
+			dev_dbg(&s->dev, "could not map memory\n");
+			return -EINVAL;
+		}
+
+		writeb(flags, sys+CISREG_ICTRL0);
+		writeb(addr & 0xff, sys+CISREG_IADDR0);
+		writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+		writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+		writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
+		for ( ; len > 0; len--, buf++)
+			writeb(*buf, sys+CISREG_IDATA0);
+	} else {
+		u_int inc = 1, card_offset, flags;
+
+		flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+		if (attr & IS_ATTR) {
+			flags |= MAP_ATTRIB;
+			inc++;
+			addr *= 2;
+		}
+
+		card_offset = addr & ~(s->map_size-1);
+		while (len) {
+			sys = set_cis_map(s, card_offset, flags);
+			if (!sys) {
+				dev_dbg(&s->dev, "could not map memory\n");
+				return -EINVAL;
+			}
+
+			end = sys + s->map_size;
+			sys = sys + (addr & (s->map_size-1));
+			for ( ; len > 0; len--, buf++, sys += inc) {
+				if (sys == end)
+					break;
+				writeb(*buf, sys);
+			}
+			card_offset += s->map_size;
+			addr = 0;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * read_cis_cache() - read CIS memory or its associated cache
+ *
+ * This is a wrapper around read_cis_mem, with the same interface,
+ * but which caches information, for cards whose CIS may not be
+ * readable all the time.
+ */
+static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
+			size_t len, void *ptr)
+{
+	struct cis_cache_entry *cis;
+	int ret = 0;
+
+	if (s->state & SOCKET_CARDBUS)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	if (s->fake_cis) {
+		if (s->fake_cis_len >= addr+len)
+			memcpy(ptr, s->fake_cis+addr, len);
+		else {
+			memset(ptr, 0xff, len);
+			ret = -EINVAL;
+		}
+		mutex_unlock(&s->ops_mutex);
+		return ret;
+	}
+
+	list_for_each_entry(cis, &s->cis_cache, node) {
+		if (cis->addr == addr && cis->len == len && cis->attr == attr) {
+			memcpy(ptr, cis->cache, len);
+			mutex_unlock(&s->ops_mutex);
+			return 0;
+		}
+	}
+
+	ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
+
+	if (ret == 0) {
+		/* Copy data into the cache */
+		cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL);
+		if (cis) {
+			cis->addr = addr;
+			cis->len = len;
+			cis->attr = attr;
+			memcpy(cis->cache, ptr, len);
+			list_add(&cis->node, &s->cis_cache);
+		}
+	}
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+}
+
+static void
+remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
+{
+	struct cis_cache_entry *cis;
+
+	mutex_lock(&s->ops_mutex);
+	list_for_each_entry(cis, &s->cis_cache, node)
+		if (cis->addr == addr && cis->len == len && cis->attr == attr) {
+			list_del(&cis->node);
+			kfree(cis);
+			break;
+		}
+	mutex_unlock(&s->ops_mutex);
+}
+
+/**
+ * destroy_cis_cache() - destroy the CIS cache
+ * @s:		pcmcia_socket for which CIS cache shall be destroyed
+ *
+ * This destroys the CIS cache but keeps any fake CIS alive. Must be
+ * called with ops_mutex held.
+ */
+void destroy_cis_cache(struct pcmcia_socket *s)
+{
+	struct list_head *l, *n;
+	struct cis_cache_entry *cis;
+
+	list_for_each_safe(l, n, &s->cis_cache) {
+		cis = list_entry(l, struct cis_cache_entry, node);
+		list_del(&cis->node);
+		kfree(cis);
+	}
+}
+
+/**
+ * verify_cis_cache() - does the CIS match what is in the CIS cache?
+ */
+int verify_cis_cache(struct pcmcia_socket *s)
+{
+	struct cis_cache_entry *cis;
+	char *buf;
+	int ret;
+
+	if (s->state & SOCKET_CARDBUS)
+		return -EINVAL;
+
+	buf = kmalloc(256, GFP_KERNEL);
+	if (buf == NULL) {
+		dev_warn(&s->dev, "no memory for verifying CIS\n");
+		return -ENOMEM;
+	}
+	mutex_lock(&s->ops_mutex);
+	list_for_each_entry(cis, &s->cis_cache, node) {
+		int len = cis->len;
+
+		if (len > 256)
+			len = 256;
+
+		ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
+		if (ret || memcmp(buf, cis->cache, len) != 0) {
+			kfree(buf);
+			mutex_unlock(&s->ops_mutex);
+			return -1;
+		}
+	}
+	kfree(buf);
+	mutex_unlock(&s->ops_mutex);
+	return 0;
+}
+
+/**
+ * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS
+ *
+ * For really bad cards, we provide a facility for uploading a
+ * replacement CIS.
+ */
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+		       const u8 *data, const size_t len)
+{
+	if (len > CISTPL_MAX_CIS_SIZE) {
+		dev_warn(&s->dev, "replacement CIS too big\n");
+		return -EINVAL;
+	}
+	mutex_lock(&s->ops_mutex);
+	kfree(s->fake_cis);
+	s->fake_cis = kmalloc(len, GFP_KERNEL);
+	if (s->fake_cis == NULL) {
+		dev_warn(&s->dev, "no memory to replace CIS\n");
+		mutex_unlock(&s->ops_mutex);
+		return -ENOMEM;
+	}
+	s->fake_cis_len = len;
+	memcpy(s->fake_cis, data, len);
+	dev_info(&s->dev, "Using replacement CIS\n");
+	mutex_unlock(&s->ops_mutex);
+	return 0;
+}
+
+/* The high-level CIS tuple services */
+
+struct tuple_flags {
+	u_int		link_space:4;
+	u_int		has_link:1;
+	u_int		mfc_fn:3;
+	u_int		space:4;
+};
+
+#define LINK_SPACE(f)	(((struct tuple_flags *)(&(f)))->link_space)
+#define HAS_LINK(f)	(((struct tuple_flags *)(&(f)))->has_link)
+#define MFC_FN(f)	(((struct tuple_flags *)(&(f)))->mfc_fn)
+#define SPACE(f)	(((struct tuple_flags *)(&(f)))->space)
+
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+			tuple_t *tuple)
+{
+	if (!s)
+		return -EINVAL;
+
+	if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
+		return -ENODEV;
+	tuple->TupleLink = tuple->Flags = 0;
+
+	/* Assume presence of a LONGLINK_C to address 0 */
+	tuple->CISOffset = tuple->LinkOffset = 0;
+	SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+
+	if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+		cisdata_t req = tuple->DesiredTuple;
+		tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+		if (pccard_get_next_tuple(s, function, tuple) == 0) {
+			tuple->DesiredTuple = CISTPL_LINKTARGET;
+			if (pccard_get_next_tuple(s, function, tuple) != 0)
+				return -ENOSPC;
+		} else
+			tuple->CISOffset = tuple->TupleLink = 0;
+		tuple->DesiredTuple = req;
+	}
+	return pccard_get_next_tuple(s, function, tuple);
+}
+
+static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
+{
+	u_char link[5];
+	u_int ofs;
+	int ret;
+
+	if (MFC_FN(tuple->Flags)) {
+		/* Get indirect link from the MFC tuple */
+		ret = read_cis_cache(s, LINK_SPACE(tuple->Flags),
+				tuple->LinkOffset, 5, link);
+		if (ret)
+			return -1;
+		ofs = get_unaligned_le32(link + 1);
+		SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+		/* Move to the next indirect link */
+		tuple->LinkOffset += 5;
+		MFC_FN(tuple->Flags)--;
+	} else if (HAS_LINK(tuple->Flags)) {
+		ofs = tuple->LinkOffset;
+		SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+		HAS_LINK(tuple->Flags) = 0;
+	} else
+		return -1;
+
+	if (SPACE(tuple->Flags)) {
+		/* This is ugly, but a common CIS error is to code the long
+		   link offset incorrectly, so we check the right spot... */
+		ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+		if (ret)
+			return -1;
+		if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+			(strncmp(link+2, "CIS", 3) == 0))
+			return ofs;
+		remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
+		/* Then, we try the wrong spot... */
+		ofs = ofs >> 1;
+	}
+	ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+	if (ret)
+		return -1;
+	if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+		(strncmp(link+2, "CIS", 3) == 0))
+		return ofs;
+	remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
+	return -1;
+}
+
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+			tuple_t *tuple)
+{
+	u_char link[2], tmp;
+	int ofs, i, attr;
+	int ret;
+
+	if (!s)
+		return -EINVAL;
+	if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
+		return -ENODEV;
+
+	link[1] = tuple->TupleLink;
+	ofs = tuple->CISOffset + tuple->TupleLink;
+	attr = SPACE(tuple->Flags);
+
+	for (i = 0; i < MAX_TUPLES; i++) {
+		if (link[1] == 0xff)
+			link[0] = CISTPL_END;
+		else {
+			ret = read_cis_cache(s, attr, ofs, 2, link);
+			if (ret)
+				return -1;
+			if (link[0] == CISTPL_NULL) {
+				ofs++;
+				continue;
+			}
+		}
+
+		/* End of chain?  Follow long link if possible */
+		if (link[0] == CISTPL_END) {
+			ofs = follow_link(s, tuple);
+			if (ofs < 0)
+				return -ENOSPC;
+			attr = SPACE(tuple->Flags);
+			ret = read_cis_cache(s, attr, ofs, 2, link);
+			if (ret)
+				return -1;
+		}
+
+		/* Is this a link tuple?  Make a note of it */
+		if ((link[0] == CISTPL_LONGLINK_A) ||
+			(link[0] == CISTPL_LONGLINK_C) ||
+			(link[0] == CISTPL_LONGLINK_MFC) ||
+			(link[0] == CISTPL_LINKTARGET) ||
+			(link[0] == CISTPL_INDIRECT) ||
+			(link[0] == CISTPL_NO_LINK)) {
+			switch (link[0]) {
+			case CISTPL_LONGLINK_A:
+				HAS_LINK(tuple->Flags) = 1;
+				LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
+				ret = read_cis_cache(s, attr, ofs+2, 4,
+						&tuple->LinkOffset);
+				if (ret)
+					return -1;
+				break;
+			case CISTPL_LONGLINK_C:
+				HAS_LINK(tuple->Flags) = 1;
+				LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
+				ret = read_cis_cache(s, attr, ofs+2, 4,
+						&tuple->LinkOffset);
+				if (ret)
+					return -1;
+				break;
+			case CISTPL_INDIRECT:
+				HAS_LINK(tuple->Flags) = 1;
+				LINK_SPACE(tuple->Flags) = IS_ATTR |
+					IS_INDIRECT;
+				tuple->LinkOffset = 0;
+				break;
+			case CISTPL_LONGLINK_MFC:
+				tuple->LinkOffset = ofs + 3;
+				LINK_SPACE(tuple->Flags) = attr;
+				if (function == BIND_FN_ALL) {
+					/* Follow all the MFC links */
+					ret = read_cis_cache(s, attr, ofs+2,
+							1, &tmp);
+					if (ret)
+						return -1;
+					MFC_FN(tuple->Flags) = tmp;
+				} else {
+					/* Follow exactly one of the links */
+					MFC_FN(tuple->Flags) = 1;
+					tuple->LinkOffset += function * 5;
+				}
+				break;
+			case CISTPL_NO_LINK:
+				HAS_LINK(tuple->Flags) = 0;
+				break;
+			}
+			if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+				(tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+				break;
+		} else
+			if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+				break;
+
+		if (link[0] == tuple->DesiredTuple)
+			break;
+		ofs += link[1] + 2;
+	}
+	if (i == MAX_TUPLES) {
+		dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
+		return -ENOSPC;
+	}
+
+	tuple->TupleCode = link[0];
+	tuple->TupleLink = link[1];
+	tuple->CISOffset = ofs + 2;
+	return 0;
+}
+
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
+{
+	u_int len;
+	int ret;
+
+	if (!s)
+		return -EINVAL;
+
+	if (tuple->TupleLink < tuple->TupleOffset)
+		return -ENOSPC;
+	len = tuple->TupleLink - tuple->TupleOffset;
+	tuple->TupleDataLen = tuple->TupleLink;
+	if (len == 0)
+		return 0;
+	ret = read_cis_cache(s, SPACE(tuple->Flags),
+			tuple->CISOffset + tuple->TupleOffset,
+			min(len, (u_int) tuple->TupleDataMax),
+			tuple->TupleData);
+	if (ret)
+		return -1;
+	return 0;
+}
+
+
+/* Parsing routines for individual tuples */
+
+static int parse_device(tuple_t *tuple, cistpl_device_t *device)
+{
+	int i;
+	u_char scale;
+	u_char *p, *q;
+
+	p = (u_char *)tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	device->ndev = 0;
+	for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+
+		if (*p == 0xff)
+			break;
+		device->dev[i].type = (*p >> 4);
+		device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+		switch (*p & 0x07) {
+		case 0:
+			device->dev[i].speed = 0;
+			break;
+		case 1:
+			device->dev[i].speed = 250;
+			break;
+		case 2:
+			device->dev[i].speed = 200;
+			break;
+		case 3:
+			device->dev[i].speed = 150;
+			break;
+		case 4:
+			device->dev[i].speed = 100;
+			break;
+		case 7:
+			if (++p == q)
+				return -EINVAL;
+			device->dev[i].speed = SPEED_CVT(*p);
+			while (*p & 0x80)
+				if (++p == q)
+					return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (++p == q)
+			return -EINVAL;
+		if (*p == 0xff)
+			break;
+		scale = *p & 7;
+		if (scale == 7)
+			return -EINVAL;
+		device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+		device->ndev++;
+		if (++p == q)
+			break;
+	}
+
+	return 0;
+}
+
+
+static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
+{
+	u_char *p;
+	if (tuple->TupleDataLen < 5)
+		return -EINVAL;
+	p = (u_char *) tuple->TupleData;
+	csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
+	csum->len = get_unaligned_le16(p + 2);
+	csum->sum = *(p + 4);
+	return 0;
+}
+
+
+static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
+{
+	if (tuple->TupleDataLen < 4)
+		return -EINVAL;
+	link->addr = get_unaligned_le32(tuple->TupleData);
+	return 0;
+}
+
+
+static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link)
+{
+	u_char *p;
+	int i;
+
+	p = (u_char *)tuple->TupleData;
+
+	link->nfn = *p; p++;
+	if (tuple->TupleDataLen <= link->nfn*5)
+		return -EINVAL;
+	for (i = 0; i < link->nfn; i++) {
+		link->fn[i].space = *p; p++;
+		link->fn[i].addr = get_unaligned_le32(p);
+		p += 4;
+	}
+	return 0;
+}
+
+
+static int parse_strings(u_char *p, u_char *q, int max,
+			 char *s, u_char *ofs, u_char *found)
+{
+	int i, j, ns;
+
+	if (p == q)
+		return -EINVAL;
+	ns = 0; j = 0;
+	for (i = 0; i < max; i++) {
+		if (*p == 0xff)
+			break;
+		ofs[i] = j;
+		ns++;
+		for (;;) {
+			s[j++] = (*p == 0xff) ? '\0' : *p;
+			if ((*p == '\0') || (*p == 0xff))
+				break;
+			if (++p == q)
+				return -EINVAL;
+		}
+		if ((*p == 0xff) || (++p == q))
+			break;
+	}
+	if (found) {
+		*found = ns;
+		return 0;
+	}
+
+	return (ns == max) ? 0 : -EINVAL;
+}
+
+
+static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
+{
+	u_char *p, *q;
+
+	p = (u_char *)tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	vers_1->major = *p; p++;
+	vers_1->minor = *p; p++;
+	if (p >= q)
+		return -EINVAL;
+
+	return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+			vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+
+static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
+{
+	u_char *p, *q;
+
+	p = (u_char *)tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+			altstr->str, altstr->ofs, &altstr->ns);
+}
+
+
+static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
+{
+	u_char *p, *q;
+	int nid;
+
+	p = (u_char *)tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+		if (p > q-2)
+			break;
+		jedec->id[nid].mfr = p[0];
+		jedec->id[nid].info = p[1];
+		p += 2;
+	}
+	jedec->nid = nid;
+	return 0;
+}
+
+
+static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
+{
+	if (tuple->TupleDataLen < 4)
+		return -EINVAL;
+	m->manf = get_unaligned_le16(tuple->TupleData);
+	m->card = get_unaligned_le16(tuple->TupleData + 2);
+	return 0;
+}
+
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+	u_char *p;
+	if (tuple->TupleDataLen < 2)
+		return -EINVAL;
+	p = (u_char *)tuple->TupleData;
+	f->func = p[0];
+	f->sysinit = p[1];
+	return 0;
+}
+
+
+static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
+{
+	u_char *p;
+	int i;
+	if (tuple->TupleDataLen < 1)
+		return -EINVAL;
+	p = (u_char *)tuple->TupleData;
+	f->type = p[0];
+	for (i = 1; i < tuple->TupleDataLen; i++)
+		f->data[i-1] = p[i];
+	return 0;
+}
+
+
+static int parse_config(tuple_t *tuple, cistpl_config_t *config)
+{
+	int rasz, rmsz, i;
+	u_char *p;
+
+	p = (u_char *)tuple->TupleData;
+	rasz = *p & 0x03;
+	rmsz = (*p & 0x3c) >> 2;
+	if (tuple->TupleDataLen < rasz+rmsz+4)
+		return -EINVAL;
+	config->last_idx = *(++p);
+	p++;
+	config->base = 0;
+	for (i = 0; i <= rasz; i++)
+		config->base += p[i] << (8*i);
+	p += rasz+1;
+	for (i = 0; i < 4; i++)
+		config->rmask[i] = 0;
+	for (i = 0; i <= rmsz; i++)
+		config->rmask[i>>2] += p[i] << (8*(i%4));
+	config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+	return 0;
+}
+
+/* The following routines are all used to parse the nightmarish
+ * config table entries.
+ */
+
+static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr)
+{
+	int i;
+	u_int scale;
+
+	if (p == q)
+		return NULL;
+	pwr->present = *p;
+	pwr->flags = 0;
+	p++;
+	for (i = 0; i < 7; i++)
+		if (pwr->present & (1<<i)) {
+			if (p == q)
+				return NULL;
+			pwr->param[i] = POWER_CVT(*p);
+			scale = POWER_SCALE(*p);
+			while (*p & 0x80) {
+				if (++p == q)
+					return NULL;
+				if ((*p & 0x7f) < 100)
+					pwr->param[i] +=
+						(*p & 0x7f) * scale / 100;
+				else if (*p == 0x7d)
+					pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+				else if (*p == 0x7e)
+					pwr->param[i] = 0;
+				else if (*p == 0x7f)
+					pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+				else
+					return NULL;
+			}
+			p++;
+		}
+	return p;
+}
+
+
+static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing)
+{
+	u_char scale;
+
+	if (p == q)
+		return NULL;
+	scale = *p;
+	if ((scale & 3) != 3) {
+		if (++p == q)
+			return NULL;
+		timing->wait = SPEED_CVT(*p);
+		timing->waitscale = exponent[scale & 3];
+	} else
+		timing->wait = 0;
+	scale >>= 2;
+	if ((scale & 7) != 7) {
+		if (++p == q)
+			return NULL;
+		timing->ready = SPEED_CVT(*p);
+		timing->rdyscale = exponent[scale & 7];
+	} else
+		timing->ready = 0;
+	scale >>= 3;
+	if (scale != 7) {
+		if (++p == q)
+			return NULL;
+		timing->reserved = SPEED_CVT(*p);
+		timing->rsvscale = exponent[scale];
+	} else
+		timing->reserved = 0;
+	p++;
+	return p;
+}
+
+
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
+{
+	int i, j, bsz, lsz;
+
+	if (p == q)
+		return NULL;
+	io->flags = *p;
+
+	if (!(*p & 0x80)) {
+		io->nwin = 1;
+		io->win[0].base = 0;
+		io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+		return p+1;
+	}
+
+	if (++p == q)
+		return NULL;
+	io->nwin = (*p & 0x0f) + 1;
+	bsz = (*p & 0x30) >> 4;
+	if (bsz == 3)
+		bsz++;
+	lsz = (*p & 0xc0) >> 6;
+	if (lsz == 3)
+		lsz++;
+	p++;
+
+	for (i = 0; i < io->nwin; i++) {
+		io->win[i].base = 0;
+		io->win[i].len = 1;
+		for (j = 0; j < bsz; j++, p++) {
+			if (p == q)
+				return NULL;
+			io->win[i].base += *p << (j*8);
+		}
+		for (j = 0; j < lsz; j++, p++) {
+			if (p == q)
+				return NULL;
+			io->win[i].len += *p << (j*8);
+		}
+	}
+	return p;
+}
+
+
+static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
+{
+	int i, j, asz, lsz, has_ha;
+	u_int len, ca, ha;
+
+	if (p == q)
+		return NULL;
+
+	mem->nwin = (*p & 0x07) + 1;
+	lsz = (*p & 0x18) >> 3;
+	asz = (*p & 0x60) >> 5;
+	has_ha = (*p & 0x80);
+	if (++p == q)
+		return NULL;
+
+	for (i = 0; i < mem->nwin; i++) {
+		len = ca = ha = 0;
+		for (j = 0; j < lsz; j++, p++) {
+			if (p == q)
+				return NULL;
+			len += *p << (j*8);
+		}
+		for (j = 0; j < asz; j++, p++) {
+			if (p == q)
+				return NULL;
+			ca += *p << (j*8);
+		}
+		if (has_ha)
+			for (j = 0; j < asz; j++, p++) {
+				if (p == q)
+					return NULL;
+				ha += *p << (j*8);
+			}
+		mem->win[i].len = len << 8;
+		mem->win[i].card_addr = ca << 8;
+		mem->win[i].host_addr = ha << 8;
+	}
+	return p;
+}
+
+
+static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
+{
+	if (p == q)
+		return NULL;
+	irq->IRQInfo1 = *p; p++;
+	if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+		if (p+2 > q)
+			return NULL;
+		irq->IRQInfo2 = (p[1]<<8) + p[0];
+		p += 2;
+	}
+	return p;
+}
+
+
+static int parse_cftable_entry(tuple_t *tuple,
+			       cistpl_cftable_entry_t *entry)
+{
+	u_char *p, *q, features;
+
+	p = tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+	entry->index = *p & 0x3f;
+	entry->flags = 0;
+	if (*p & 0x40)
+		entry->flags |= CISTPL_CFTABLE_DEFAULT;
+	if (*p & 0x80) {
+		if (++p == q)
+			return -EINVAL;
+		if (*p & 0x10)
+			entry->flags |= CISTPL_CFTABLE_BVDS;
+		if (*p & 0x20)
+			entry->flags |= CISTPL_CFTABLE_WP;
+		if (*p & 0x40)
+			entry->flags |= CISTPL_CFTABLE_RDYBSY;
+		if (*p & 0x80)
+			entry->flags |= CISTPL_CFTABLE_MWAIT;
+		entry->interface = *p & 0x0f;
+	} else
+		entry->interface = 0;
+
+	/* Process optional features */
+	if (++p == q)
+		return -EINVAL;
+	features = *p; p++;
+
+	/* Power options */
+	if ((features & 3) > 0) {
+		p = parse_power(p, q, &entry->vcc);
+		if (p == NULL)
+			return -EINVAL;
+	} else
+		entry->vcc.present = 0;
+	if ((features & 3) > 1) {
+		p = parse_power(p, q, &entry->vpp1);
+		if (p == NULL)
+			return -EINVAL;
+	} else
+		entry->vpp1.present = 0;
+	if ((features & 3) > 2) {
+		p = parse_power(p, q, &entry->vpp2);
+		if (p == NULL)
+			return -EINVAL;
+	} else
+		entry->vpp2.present = 0;
+
+	/* Timing options */
+	if (features & 0x04) {
+		p = parse_timing(p, q, &entry->timing);
+		if (p == NULL)
+			return -EINVAL;
+	} else {
+		entry->timing.wait = 0;
+		entry->timing.ready = 0;
+		entry->timing.reserved = 0;
+	}
+
+	/* I/O window options */
+	if (features & 0x08) {
+		p = parse_io(p, q, &entry->io);
+		if (p == NULL)
+			return -EINVAL;
+	} else
+		entry->io.nwin = 0;
+
+	/* Interrupt options */
+	if (features & 0x10) {
+		p = parse_irq(p, q, &entry->irq);
+		if (p == NULL)
+			return -EINVAL;
+	} else
+		entry->irq.IRQInfo1 = 0;
+
+	switch (features & 0x60) {
+	case 0x00:
+		entry->mem.nwin = 0;
+		break;
+	case 0x20:
+		entry->mem.nwin = 1;
+		entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+		entry->mem.win[0].card_addr = 0;
+		entry->mem.win[0].host_addr = 0;
+		p += 2;
+		if (p > q)
+			return -EINVAL;
+		break;
+	case 0x40:
+		entry->mem.nwin = 1;
+		entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+		entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
+		entry->mem.win[0].host_addr = 0;
+		p += 4;
+		if (p > q)
+			return -EINVAL;
+		break;
+	case 0x60:
+		p = parse_mem(p, q, &entry->mem);
+		if (p == NULL)
+			return -EINVAL;
+		break;
+	}
+
+	/* Misc features */
+	if (features & 0x80) {
+		if (p == q)
+			return -EINVAL;
+		entry->flags |= (*p << 8);
+		while (*p & 0x80)
+			if (++p == q)
+				return -EINVAL;
+		p++;
+	}
+
+	entry->subtuples = q-p;
+
+	return 0;
+}
+
+
+static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
+{
+	u_char *p, *q;
+	int n;
+
+	p = (u_char *)tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+		if (p > q-6)
+			break;
+		geo->geo[n].buswidth = p[0];
+		geo->geo[n].erase_block = 1 << (p[1]-1);
+		geo->geo[n].read_block  = 1 << (p[2]-1);
+		geo->geo[n].write_block = 1 << (p[3]-1);
+		geo->geo[n].partition   = 1 << (p[4]-1);
+		geo->geo[n].interleave  = 1 << (p[5]-1);
+		p += 6;
+	}
+	geo->ngeo = n;
+	return 0;
+}
+
+
+static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
+{
+	u_char *p, *q;
+
+	if (tuple->TupleDataLen < 10)
+		return -EINVAL;
+
+	p = tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+
+	v2->vers = p[0];
+	v2->comply = p[1];
+	v2->dindex = get_unaligned_le16(p + 2);
+	v2->vspec8 = p[6];
+	v2->vspec9 = p[7];
+	v2->nhdr = p[8];
+	p += 9;
+	return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+
+static int parse_org(tuple_t *tuple, cistpl_org_t *org)
+{
+	u_char *p, *q;
+	int i;
+
+	p = tuple->TupleData;
+	q = p + tuple->TupleDataLen;
+	if (p == q)
+		return -EINVAL;
+	org->data_org = *p;
+	if (++p == q)
+		return -EINVAL;
+	for (i = 0; i < 30; i++) {
+		org->desc[i] = *p;
+		if (*p == '\0')
+			break;
+		if (++p == q)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
+{
+	u_char *p;
+
+	if (tuple->TupleDataLen < 10)
+		return -EINVAL;
+
+	p = tuple->TupleData;
+
+	fmt->type = p[0];
+	fmt->edc = p[1];
+	fmt->offset = get_unaligned_le32(p + 2);
+	fmt->length = get_unaligned_le32(p + 6);
+
+	return 0;
+}
+
+
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
+{
+	int ret = 0;
+
+	if (tuple->TupleDataLen > tuple->TupleDataMax)
+		return -EINVAL;
+	switch (tuple->TupleCode) {
+	case CISTPL_DEVICE:
+	case CISTPL_DEVICE_A:
+		ret = parse_device(tuple, &parse->device);
+		break;
+	case CISTPL_CHECKSUM:
+		ret = parse_checksum(tuple, &parse->checksum);
+		break;
+	case CISTPL_LONGLINK_A:
+	case CISTPL_LONGLINK_C:
+		ret = parse_longlink(tuple, &parse->longlink);
+		break;
+	case CISTPL_LONGLINK_MFC:
+		ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+		break;
+	case CISTPL_VERS_1:
+		ret = parse_vers_1(tuple, &parse->version_1);
+		break;
+	case CISTPL_ALTSTR:
+		ret = parse_altstr(tuple, &parse->altstr);
+		break;
+	case CISTPL_JEDEC_A:
+	case CISTPL_JEDEC_C:
+		ret = parse_jedec(tuple, &parse->jedec);
+		break;
+	case CISTPL_MANFID:
+		ret = parse_manfid(tuple, &parse->manfid);
+		break;
+	case CISTPL_FUNCID:
+		ret = parse_funcid(tuple, &parse->funcid);
+		break;
+	case CISTPL_FUNCE:
+		ret = parse_funce(tuple, &parse->funce);
+		break;
+	case CISTPL_CONFIG:
+		ret = parse_config(tuple, &parse->config);
+		break;
+	case CISTPL_CFTABLE_ENTRY:
+		ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+		break;
+	case CISTPL_DEVICE_GEO:
+	case CISTPL_DEVICE_GEO_A:
+		ret = parse_device_geo(tuple, &parse->device_geo);
+		break;
+	case CISTPL_VERS_2:
+		ret = parse_vers_2(tuple, &parse->vers_2);
+		break;
+	case CISTPL_ORG:
+		ret = parse_org(tuple, &parse->org);
+		break;
+	case CISTPL_FORMAT:
+	case CISTPL_FORMAT_A:
+		ret = parse_format(tuple, &parse->format);
+		break;
+	case CISTPL_NO_LINK:
+	case CISTPL_LINKTARGET:
+		ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret)
+		pr_debug("parse_tuple failed %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_parse_tuple);
+
+
+/**
+ * pccard_validate_cis() - check whether card has a sensible CIS
+ * @s:		the struct pcmcia_socket we are to check
+ * @info:	returns the number of tuples in the (valid) CIS, or 0
+ *
+ * This tries to determine if a card has a sensible CIS.  In @info, it
+ * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The
+ * checks include making sure several critical tuples are present and
+ * valid; seeing if the total number of tuples is reasonable; and
+ * looking for tuples that use reserved codes.
+ *
+ * The function returns 0 on success.
+ */
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
+{
+	tuple_t *tuple;
+	cisparse_t *p;
+	unsigned int count = 0;
+	int ret, reserved, dev_ok = 0, ident_ok = 0;
+
+	if (!s)
+		return -EINVAL;
+
+	if (s->functions || !(s->state & SOCKET_PRESENT)) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* We do not want to validate the CIS cache... */
+	mutex_lock(&s->ops_mutex);
+	destroy_cis_cache(s);
+	mutex_unlock(&s->ops_mutex);
+
+	tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
+	if (tuple == NULL) {
+		dev_warn(&s->dev, "no memory to validate CIS\n");
+		return -ENOMEM;
+	}
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p == NULL) {
+		kfree(tuple);
+		dev_warn(&s->dev, "no memory to validate CIS\n");
+		return -ENOMEM;
+	}
+
+	count = reserved = 0;
+	tuple->DesiredTuple = RETURN_FIRST_TUPLE;
+	tuple->Attributes = TUPLE_RETURN_COMMON;
+	ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
+	if (ret != 0)
+		goto done;
+
+	/* First tuple should be DEVICE; we should really have either that
+	   or a CFTABLE_ENTRY of some sort */
+	if ((tuple->TupleCode == CISTPL_DEVICE) ||
+	    (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) ||
+	    (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p)))
+		dev_ok++;
+
+	/* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
+	   tuple, for card identification.  Certain old D-Link and Linksys
+	   cards have only a broken VERS_2 tuple; hence the bogus test. */
+	if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
+	    (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
+	    (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
+		ident_ok++;
+
+	if (!dev_ok && !ident_ok)
+		goto done;
+
+	for (count = 1; count < MAX_TUPLES; count++) {
+		ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
+		if (ret != 0)
+			break;
+		if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
+		    ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
+		    ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
+			reserved++;
+	}
+	if ((count == MAX_TUPLES) || (reserved > 5) ||
+		((!dev_ok || !ident_ok) && (count > 10)))
+		count = 0;
+
+	ret = 0;
+
+done:
+	/* invalidate CIS cache on failure */
+	if (!dev_ok || !ident_ok || !count) {
+		mutex_lock(&s->ops_mutex);
+		destroy_cis_cache(s);
+		mutex_unlock(&s->ops_mutex);
+		/* We differentiate between dev_ok, ident_ok and count
+		   failures to allow for an override for anonymous cards
+		   in ds.c */
+		if (!dev_ok || !ident_ok)
+			ret = -EIO;
+		else
+			ret = -EFAULT;
+	}
+
+	if (info)
+		*info = count;
+	kfree(tuple);
+	kfree(p);
+	return ret;
+}
+
+
+#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
+
+static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
+				  loff_t off, size_t count)
+{
+	tuple_t tuple;
+	int status, i;
+	loff_t pointer = 0;
+	ssize_t ret = 0;
+	u_char *tuplebuffer;
+	u_char *tempbuffer;
+
+	tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
+	if (!tuplebuffer)
+		return -ENOMEM;
+
+	tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
+	if (!tempbuffer) {
+		ret = -ENOMEM;
+		goto free_tuple;
+	}
+
+	memset(&tuple, 0, sizeof(tuple_t));
+
+	tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+	tuple.TupleOffset = 0;
+
+	status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
+	while (!status) {
+		tuple.TupleData = tuplebuffer;
+		tuple.TupleDataMax = 255;
+		memset(tuplebuffer, 0, sizeof(u_char) * 255);
+
+		status = pccard_get_tuple_data(s, &tuple);
+		if (status)
+			break;
+
+		if (off < (pointer + 2 + tuple.TupleDataLen)) {
+			tempbuffer[0] = tuple.TupleCode & 0xff;
+			tempbuffer[1] = tuple.TupleLink & 0xff;
+			for (i = 0; i < tuple.TupleDataLen; i++)
+				tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
+
+			for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
+				if (((i + pointer) >= off) &&
+				    (i + pointer) < (off + count)) {
+					buf[ret] = tempbuffer[i];
+					ret++;
+				}
+			}
+		}
+
+		pointer += 2 + tuple.TupleDataLen;
+
+		if (pointer >= (off + count))
+			break;
+
+		if (tuple.TupleCode == CISTPL_END)
+			break;
+		status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
+	}
+
+	kfree(tempbuffer);
+ free_tuple:
+	kfree(tuplebuffer);
+
+	return ret;
+}
+
+
+static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t off, size_t count)
+{
+	unsigned int size = 0x200;
+
+	if (off >= size)
+		count = 0;
+	else {
+		struct pcmcia_socket *s;
+		unsigned int chains = 1;
+
+		if (off + count > size)
+			count = size - off;
+
+		s = to_socket(container_of(kobj, struct device, kobj));
+
+		if (!(s->state & SOCKET_PRESENT))
+			return -ENODEV;
+		if (!s->functions && pccard_validate_cis(s, &chains))
+			return -EIO;
+		if (!chains)
+			return -ENODATA;
+
+		count = pccard_extract_cis(s, buf, off, count);
+	}
+
+	return count;
+}
+
+
+static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct pcmcia_socket *s;
+	int error;
+
+	s = to_socket(container_of(kobj, struct device, kobj));
+
+	if (off)
+		return -EINVAL;
+
+	if (count >= CISTPL_MAX_CIS_SIZE)
+		return -EINVAL;
+
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+
+	error = pcmcia_replace_cis(s, buf, count);
+	if (error)
+		return -EIO;
+
+	pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+
+	return count;
+}
+
+
+struct bin_attribute pccard_cis_attr = {
+	.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
+	.size = 0x200,
+	.read = pccard_show_cis,
+	.write = pccard_store_cis,
+};
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/cs.c b/src/kernel/linux/v4.14/drivers/pcmcia/cs.c
new file mode 100644
index 0000000..8c8caec
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/cs.c
@@ -0,0 +1,923 @@
+/*
+ * cs.c -- Kernel Card Services - core services
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <asm/irq.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include "cs_internal.h"
+
+
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Linux Kernel Card Services");
+MODULE_LICENSE("GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
+
+INT_MODULE_PARM(setup_delay,	10);		/* centiseconds */
+INT_MODULE_PARM(resume_delay,	20);		/* centiseconds */
+INT_MODULE_PARM(shutdown_delay,	3);		/* centiseconds */
+INT_MODULE_PARM(vcc_settle,	40);		/* centiseconds */
+INT_MODULE_PARM(reset_time,	10);		/* usecs */
+INT_MODULE_PARM(unreset_delay,	10);		/* centiseconds */
+INT_MODULE_PARM(unreset_check,	10);		/* centiseconds */
+INT_MODULE_PARM(unreset_limit,	30);		/* unreset_check's */
+
+/* Access speed for attribute memory windows */
+INT_MODULE_PARM(cis_speed,	300);		/* ns */
+
+
+socket_state_t dead_socket = {
+	.csc_mask	= SS_DETECT,
+};
+EXPORT_SYMBOL(dead_socket);
+
+
+/* List of all sockets, protected by a rwsem */
+LIST_HEAD(pcmcia_socket_list);
+EXPORT_SYMBOL(pcmcia_socket_list);
+
+DECLARE_RWSEM(pcmcia_socket_list_rwsem);
+EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
+
+
+struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)
+{
+	struct device *dev = get_device(&skt->dev);
+	if (!dev)
+		return NULL;
+	return dev_get_drvdata(dev);
+}
+EXPORT_SYMBOL(pcmcia_get_socket);
+
+
+void pcmcia_put_socket(struct pcmcia_socket *skt)
+{
+	put_device(&skt->dev);
+}
+EXPORT_SYMBOL(pcmcia_put_socket);
+
+
+static void pcmcia_release_socket(struct device *dev)
+{
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
+
+	complete(&socket->socket_released);
+}
+
+static int pccardd(void *__skt);
+
+/**
+ * pcmcia_register_socket - add a new pcmcia socket device
+ * @socket: the &socket to register
+ */
+int pcmcia_register_socket(struct pcmcia_socket *socket)
+{
+	struct task_struct *tsk;
+	int ret;
+
+	if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
+		return -EINVAL;
+
+	dev_dbg(&socket->dev, "pcmcia_register_socket(0x%p)\n", socket->ops);
+
+	/* try to obtain a socket number [yes, it gets ugly if we
+	 * register more than 2^sizeof(unsigned int) pcmcia
+	 * sockets... but the socket number is deprecated
+	 * anyways, so I don't care] */
+	down_write(&pcmcia_socket_list_rwsem);
+	if (list_empty(&pcmcia_socket_list))
+		socket->sock = 0;
+	else {
+		unsigned int found, i = 1;
+		struct pcmcia_socket *tmp;
+		do {
+			found = 1;
+			list_for_each_entry(tmp, &pcmcia_socket_list, socket_list) {
+				if (tmp->sock == i)
+					found = 0;
+			}
+			i++;
+		} while (!found);
+		socket->sock = i - 1;
+	}
+	list_add_tail(&socket->socket_list, &pcmcia_socket_list);
+	up_write(&pcmcia_socket_list_rwsem);
+
+#ifndef CONFIG_CARDBUS
+	/*
+	 * If we do not support Cardbus, ensure that
+	 * the Cardbus socket capability is disabled.
+	 */
+	socket->features &= ~SS_CAP_CARDBUS;
+#endif
+
+	/* set proper values in socket->dev */
+	dev_set_drvdata(&socket->dev, socket);
+	socket->dev.class = &pcmcia_socket_class;
+	dev_set_name(&socket->dev, "pcmcia_socket%u", socket->sock);
+
+	/* base address = 0, map = 0 */
+	socket->cis_mem.flags = 0;
+	socket->cis_mem.speed = cis_speed;
+
+	INIT_LIST_HEAD(&socket->cis_cache);
+
+	init_completion(&socket->socket_released);
+	init_completion(&socket->thread_done);
+	mutex_init(&socket->skt_mutex);
+	mutex_init(&socket->ops_mutex);
+	spin_lock_init(&socket->thread_lock);
+
+	if (socket->resource_ops->init) {
+		mutex_lock(&socket->ops_mutex);
+		ret = socket->resource_ops->init(socket);
+		mutex_unlock(&socket->ops_mutex);
+		if (ret)
+			goto err;
+	}
+
+	tsk = kthread_run(pccardd, socket, "pccardd");
+	if (IS_ERR(tsk)) {
+		ret = PTR_ERR(tsk);
+		goto err;
+	}
+
+	wait_for_completion(&socket->thread_done);
+	if (!socket->thread) {
+		dev_warn(&socket->dev,
+			 "PCMCIA: warning: socket thread did not start\n");
+		return -EIO;
+	}
+
+	pcmcia_parse_events(socket, SS_DETECT);
+
+	/*
+	 * Let's try to get the PCMCIA module for 16-bit PCMCIA support.
+	 * If it fails, it doesn't matter -- we still have 32-bit CardBus
+	 * support to offer, so this is not a failure mode.
+	 */
+	request_module_nowait("pcmcia");
+
+	return 0;
+
+ err:
+	down_write(&pcmcia_socket_list_rwsem);
+	list_del(&socket->socket_list);
+	up_write(&pcmcia_socket_list_rwsem);
+	return ret;
+} /* pcmcia_register_socket */
+EXPORT_SYMBOL(pcmcia_register_socket);
+
+
+/**
+ * pcmcia_unregister_socket - remove a pcmcia socket device
+ * @socket: the &socket to unregister
+ */
+void pcmcia_unregister_socket(struct pcmcia_socket *socket)
+{
+	if (!socket)
+		return;
+
+	dev_dbg(&socket->dev, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
+
+	if (socket->thread)
+		kthread_stop(socket->thread);
+
+	/* remove from our own list */
+	down_write(&pcmcia_socket_list_rwsem);
+	list_del(&socket->socket_list);
+	up_write(&pcmcia_socket_list_rwsem);
+
+	/* wait for sysfs to drop all references */
+	if (socket->resource_ops->exit) {
+		mutex_lock(&socket->ops_mutex);
+		socket->resource_ops->exit(socket);
+		mutex_unlock(&socket->ops_mutex);
+	}
+	wait_for_completion(&socket->socket_released);
+} /* pcmcia_unregister_socket */
+EXPORT_SYMBOL(pcmcia_unregister_socket);
+
+
+struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr)
+{
+	struct pcmcia_socket *s;
+
+	down_read(&pcmcia_socket_list_rwsem);
+	list_for_each_entry(s, &pcmcia_socket_list, socket_list)
+		if (s->sock == nr) {
+			up_read(&pcmcia_socket_list_rwsem);
+			return s;
+		}
+	up_read(&pcmcia_socket_list_rwsem);
+
+	return NULL;
+
+}
+EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
+
+static int socket_reset(struct pcmcia_socket *skt)
+{
+	int status, i;
+
+	dev_dbg(&skt->dev, "reset\n");
+
+	skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+	skt->ops->set_socket(skt, &skt->socket);
+	udelay((long)reset_time);
+
+	skt->socket.flags &= ~SS_RESET;
+	skt->ops->set_socket(skt, &skt->socket);
+
+	msleep(unreset_delay * 10);
+	for (i = 0; i < unreset_limit; i++) {
+		skt->ops->get_status(skt, &status);
+
+		if (!(status & SS_DETECT))
+			return -ENODEV;
+
+		if (status & SS_READY)
+			return 0;
+
+		msleep(unreset_check * 10);
+	}
+
+	dev_err(&skt->dev, "time out after reset\n");
+	return -ETIMEDOUT;
+}
+
+/*
+ * socket_setup() and socket_shutdown() are called by the main event handler
+ * when card insertion and removal events are received.
+ * socket_setup() turns on socket power and resets the socket, in two stages.
+ * socket_shutdown() unconfigures a socket and turns off socket power.
+ */
+static void socket_shutdown(struct pcmcia_socket *s)
+{
+	int status;
+
+	dev_dbg(&s->dev, "shutdown\n");
+
+	if (s->callback)
+		s->callback->remove(s);
+
+	mutex_lock(&s->ops_mutex);
+	s->state &= SOCKET_INUSE | SOCKET_PRESENT;
+	msleep(shutdown_delay * 10);
+	s->state &= SOCKET_INUSE;
+
+	/* Blank out the socket state */
+	s->socket = dead_socket;
+	s->ops->init(s);
+	s->ops->set_socket(s, &s->socket);
+	s->lock_count = 0;
+	kfree(s->fake_cis);
+	s->fake_cis = NULL;
+	s->functions = 0;
+
+	/* From here on we can be sure that only we (that is, the
+	 * pccardd thread) accesses this socket, and all (16-bit)
+	 * PCMCIA interactions are gone. Therefore, release
+	 * ops_mutex so that we don't get a sysfs-related lockdep
+	 * warning.
+	 */
+	mutex_unlock(&s->ops_mutex);
+
+#ifdef CONFIG_CARDBUS
+	cb_free(s);
+#endif
+
+	/* give socket some time to power down */
+	msleep(100);
+
+	s->ops->get_status(s, &status);
+	if (status & SS_POWERON) {
+		dev_err(&s->dev,
+			"*** DANGER *** unable to remove socket power\n");
+	}
+
+	s->state &= ~SOCKET_INUSE;
+}
+
+static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
+{
+	int status, i;
+
+	dev_dbg(&skt->dev, "setup\n");
+
+	skt->ops->get_status(skt, &status);
+	if (!(status & SS_DETECT))
+		return -ENODEV;
+
+	msleep(initial_delay * 10);
+
+	for (i = 0; i < 100; i++) {
+		skt->ops->get_status(skt, &status);
+		if (!(status & SS_DETECT))
+			return -ENODEV;
+
+		if (!(status & SS_PENDING))
+			break;
+
+		msleep(100);
+	}
+
+	if (status & SS_PENDING) {
+		dev_err(&skt->dev, "voltage interrogation timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	if (status & SS_CARDBUS) {
+		if (!(skt->features & SS_CAP_CARDBUS)) {
+			dev_err(&skt->dev, "cardbus cards are not supported\n");
+			return -EINVAL;
+		}
+		skt->state |= SOCKET_CARDBUS;
+	} else
+		skt->state &= ~SOCKET_CARDBUS;
+
+	/*
+	 * Decode the card voltage requirements, and apply power to the card.
+	 */
+	if (status & SS_3VCARD)
+		skt->socket.Vcc = skt->socket.Vpp = 33;
+	else if (!(status & SS_XVCARD))
+		skt->socket.Vcc = skt->socket.Vpp = 50;
+	else {
+		dev_err(&skt->dev, "unsupported voltage key\n");
+		return -EIO;
+	}
+
+	if (skt->power_hook)
+		skt->power_hook(skt, HOOK_POWER_PRE);
+
+	skt->socket.flags = 0;
+	skt->ops->set_socket(skt, &skt->socket);
+
+	/*
+	 * Wait "vcc_settle" for the supply to stabilise.
+	 */
+	msleep(vcc_settle * 10);
+
+	skt->ops->get_status(skt, &status);
+	if (!(status & SS_POWERON)) {
+		dev_err(&skt->dev, "unable to apply power\n");
+		return -EIO;
+	}
+
+	status = socket_reset(skt);
+
+	if (skt->power_hook)
+		skt->power_hook(skt, HOOK_POWER_POST);
+
+	return status;
+}
+
+/*
+ * Handle card insertion.  Setup the socket, reset the card,
+ * and then tell the rest of PCMCIA that a card is present.
+ */
+static int socket_insert(struct pcmcia_socket *skt)
+{
+	int ret;
+
+	dev_dbg(&skt->dev, "insert\n");
+
+	mutex_lock(&skt->ops_mutex);
+	if (skt->state & SOCKET_INUSE) {
+		mutex_unlock(&skt->ops_mutex);
+		return -EINVAL;
+	}
+	skt->state |= SOCKET_INUSE;
+
+	ret = socket_setup(skt, setup_delay);
+	if (ret == 0) {
+		skt->state |= SOCKET_PRESENT;
+
+		dev_notice(&skt->dev, "pccard: %s card inserted into slot %d\n",
+			   (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
+			   skt->sock);
+
+#ifdef CONFIG_CARDBUS
+		if (skt->state & SOCKET_CARDBUS) {
+			cb_alloc(skt);
+			skt->state |= SOCKET_CARDBUS_CONFIG;
+		}
+#endif
+		dev_dbg(&skt->dev, "insert done\n");
+		mutex_unlock(&skt->ops_mutex);
+
+		if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+			skt->callback->add(skt);
+	} else {
+		mutex_unlock(&skt->ops_mutex);
+		socket_shutdown(skt);
+	}
+
+	return ret;
+}
+
+static int socket_suspend(struct pcmcia_socket *skt)
+{
+	if ((skt->state & SOCKET_SUSPEND) && !(skt->state & SOCKET_IN_RESUME))
+		return -EBUSY;
+
+	mutex_lock(&skt->ops_mutex);
+	/* store state on first suspend, but not after spurious wakeups */
+	if (!(skt->state & SOCKET_IN_RESUME))
+		skt->suspended_state = skt->state;
+
+	skt->socket = dead_socket;
+	skt->ops->set_socket(skt, &skt->socket);
+	if (skt->ops->suspend)
+		skt->ops->suspend(skt);
+	skt->state |= SOCKET_SUSPEND;
+	skt->state &= ~SOCKET_IN_RESUME;
+	mutex_unlock(&skt->ops_mutex);
+	return 0;
+}
+
+static int socket_early_resume(struct pcmcia_socket *skt)
+{
+	mutex_lock(&skt->ops_mutex);
+	skt->socket = dead_socket;
+	skt->ops->init(skt);
+	skt->ops->set_socket(skt, &skt->socket);
+	if (skt->state & SOCKET_PRESENT)
+		skt->resume_status = socket_setup(skt, resume_delay);
+	skt->state |= SOCKET_IN_RESUME;
+	mutex_unlock(&skt->ops_mutex);
+	return 0;
+}
+
+static int socket_late_resume(struct pcmcia_socket *skt)
+{
+	int ret = 0;
+
+	mutex_lock(&skt->ops_mutex);
+	skt->state &= ~(SOCKET_SUSPEND | SOCKET_IN_RESUME);
+	mutex_unlock(&skt->ops_mutex);
+
+	if (!(skt->state & SOCKET_PRESENT)) {
+		ret = socket_insert(skt);
+		if (ret == -ENODEV)
+			ret = 0;
+		return ret;
+	}
+
+	if (skt->resume_status) {
+		socket_shutdown(skt);
+		return 0;
+	}
+
+	if (skt->suspended_state != skt->state) {
+		dev_dbg(&skt->dev,
+			"suspend state 0x%x != resume state 0x%x\n",
+			skt->suspended_state, skt->state);
+
+		socket_shutdown(skt);
+		return socket_insert(skt);
+	}
+
+	if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+		ret = skt->callback->early_resume(skt);
+	return ret;
+}
+
+/*
+ * Finalize the resume. In case of a cardbus socket, we have
+ * to rebind the devices as we can't be certain that it has been
+ * replaced, or not.
+ */
+static int socket_complete_resume(struct pcmcia_socket *skt)
+{
+	int ret = 0;
+#ifdef CONFIG_CARDBUS
+	if (skt->state & SOCKET_CARDBUS) {
+		/* We can't be sure the CardBus card is the same
+		 * as the one previously inserted. Therefore, remove
+		 * and re-add... */
+		cb_free(skt);
+		ret = cb_alloc(skt);
+		if (ret)
+			cb_free(skt);
+	}
+#endif
+	return ret;
+}
+
+/*
+ * Resume a socket.  If a card is present, verify its CIS against
+ * our cached copy.  If they are different, the card has been
+ * replaced, and we need to tell the drivers.
+ */
+static int socket_resume(struct pcmcia_socket *skt)
+{
+	int err;
+	if (!(skt->state & SOCKET_SUSPEND))
+		return -EBUSY;
+
+	socket_early_resume(skt);
+	err = socket_late_resume(skt);
+	if (!err)
+		err = socket_complete_resume(skt);
+	return err;
+}
+
+static void socket_remove(struct pcmcia_socket *skt)
+{
+	dev_notice(&skt->dev, "pccard: card ejected from slot %d\n", skt->sock);
+	socket_shutdown(skt);
+}
+
+/*
+ * Process a socket card detect status change.
+ *
+ * If we don't have a card already present, delay the detect event for
+ * about 20ms (to be on the safe side) before reading the socket status.
+ *
+ * Some i82365-based systems send multiple SS_DETECT events during card
+ * insertion, and the "card present" status bit seems to bounce.  This
+ * will probably be true with GPIO-based card detection systems after
+ * the product has aged.
+ */
+static void socket_detect_change(struct pcmcia_socket *skt)
+{
+	if (!(skt->state & SOCKET_SUSPEND)) {
+		int status;
+
+		if (!(skt->state & SOCKET_PRESENT))
+			msleep(20);
+
+		skt->ops->get_status(skt, &status);
+		if ((skt->state & SOCKET_PRESENT) &&
+		     !(status & SS_DETECT))
+			socket_remove(skt);
+		if (!(skt->state & SOCKET_PRESENT) &&
+		    (status & SS_DETECT))
+			socket_insert(skt);
+	}
+}
+
+static int pccardd(void *__skt)
+{
+	struct pcmcia_socket *skt = __skt;
+	int ret;
+
+	skt->thread = current;
+	skt->socket = dead_socket;
+	skt->ops->init(skt);
+	skt->ops->set_socket(skt, &skt->socket);
+
+	/* register with the device core */
+	ret = device_register(&skt->dev);
+	if (ret) {
+		dev_warn(&skt->dev, "PCMCIA: unable to register socket\n");
+		skt->thread = NULL;
+		complete(&skt->thread_done);
+		return 0;
+	}
+	ret = pccard_sysfs_add_socket(&skt->dev);
+	if (ret)
+		dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
+
+	complete(&skt->thread_done);
+
+	/* wait for userspace to catch up */
+	msleep(250);
+
+	set_freezable();
+	for (;;) {
+		unsigned long flags;
+		unsigned int events;
+		unsigned int sysfs_events;
+
+		spin_lock_irqsave(&skt->thread_lock, flags);
+		events = skt->thread_events;
+		skt->thread_events = 0;
+		sysfs_events = skt->sysfs_events;
+		skt->sysfs_events = 0;
+		spin_unlock_irqrestore(&skt->thread_lock, flags);
+
+		mutex_lock(&skt->skt_mutex);
+		if (events & SS_DETECT)
+			socket_detect_change(skt);
+
+		if (sysfs_events) {
+			if (sysfs_events & PCMCIA_UEVENT_EJECT)
+				socket_remove(skt);
+			if (sysfs_events & PCMCIA_UEVENT_INSERT)
+				socket_insert(skt);
+			if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
+				!(skt->state & SOCKET_CARDBUS)) {
+				if (skt->callback)
+					ret = skt->callback->suspend(skt);
+				else
+					ret = 0;
+				if (!ret) {
+					socket_suspend(skt);
+					msleep(100);
+				}
+			}
+			if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
+				!(skt->state & SOCKET_CARDBUS)) {
+				ret = socket_resume(skt);
+				if (!ret && skt->callback)
+					skt->callback->resume(skt);
+			}
+			if ((sysfs_events & PCMCIA_UEVENT_REQUERY) &&
+				!(skt->state & SOCKET_CARDBUS)) {
+				if (!ret && skt->callback)
+					skt->callback->requery(skt);
+			}
+		}
+		mutex_unlock(&skt->skt_mutex);
+
+		if (events || sysfs_events)
+			continue;
+
+		if (kthread_should_stop())
+			break;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		schedule();
+
+		/* make sure we are running */
+		__set_current_state(TASK_RUNNING);
+
+		try_to_freeze();
+	}
+
+	/* shut down socket, if a device is still present */
+	if (skt->state & SOCKET_PRESENT) {
+		mutex_lock(&skt->skt_mutex);
+		socket_remove(skt);
+		mutex_unlock(&skt->skt_mutex);
+	}
+
+	/* remove from the device core */
+	pccard_sysfs_remove_socket(&skt->dev);
+	device_unregister(&skt->dev);
+
+	return 0;
+}
+
+/*
+ * Yenta (at least) probes interrupts before registering the socket and
+ * starting the handler thread.
+ */
+void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
+{
+	unsigned long flags;
+	dev_dbg(&s->dev, "parse_events: events %08x\n", events);
+	if (s->thread) {
+		spin_lock_irqsave(&s->thread_lock, flags);
+		s->thread_events |= events;
+		spin_unlock_irqrestore(&s->thread_lock, flags);
+
+		wake_up_process(s->thread);
+	}
+} /* pcmcia_parse_events */
+EXPORT_SYMBOL(pcmcia_parse_events);
+
+/**
+ * pcmcia_parse_uevents() - tell pccardd to issue manual commands
+ * @s:		the PCMCIA socket we wan't to command
+ * @events:	events to pass to pccardd
+ *
+ * userspace-issued insert, eject, suspend and resume commands must be
+ * handled by pccardd to avoid any sysfs-related deadlocks. Valid events
+ * are PCMCIA_UEVENT_EJECT (for eject), PCMCIA_UEVENT__INSERT (for insert),
+ * PCMCIA_UEVENT_RESUME (for resume), PCMCIA_UEVENT_SUSPEND (for suspend)
+ * and PCMCIA_UEVENT_REQUERY (for re-querying the PCMCIA card).
+ */
+void pcmcia_parse_uevents(struct pcmcia_socket *s, u_int events)
+{
+	unsigned long flags;
+	dev_dbg(&s->dev, "parse_uevents: events %08x\n", events);
+	if (s->thread) {
+		spin_lock_irqsave(&s->thread_lock, flags);
+		s->sysfs_events |= events;
+		spin_unlock_irqrestore(&s->thread_lock, flags);
+
+		wake_up_process(s->thread);
+	}
+}
+EXPORT_SYMBOL(pcmcia_parse_uevents);
+
+
+/* register pcmcia_callback */
+int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
+{
+	int ret = 0;
+
+	/* s->skt_mutex also protects s->callback */
+	mutex_lock(&s->skt_mutex);
+
+	if (c) {
+		/* registration */
+		if (s->callback) {
+			ret = -EBUSY;
+			goto err;
+		}
+
+		s->callback = c;
+
+		if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT)
+			s->callback->add(s);
+	} else
+		s->callback = NULL;
+ err:
+	mutex_unlock(&s->skt_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(pccard_register_pcmcia);
+
+
+/* I'm not sure which "reset" function this is supposed to use,
+ * but for now, it uses the low-level interface's reset, not the
+ * CIS register.
+ */
+
+int pcmcia_reset_card(struct pcmcia_socket *skt)
+{
+	int ret;
+
+	dev_dbg(&skt->dev, "resetting socket\n");
+
+	mutex_lock(&skt->skt_mutex);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			dev_dbg(&skt->dev, "can't reset, not present\n");
+			ret = -ENODEV;
+			break;
+		}
+		if (skt->state & SOCKET_SUSPEND) {
+			dev_dbg(&skt->dev, "can't reset, suspended\n");
+			ret = -EBUSY;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			dev_dbg(&skt->dev, "can't reset, is cardbus\n");
+			ret = -EPERM;
+			break;
+		}
+
+		if (skt->callback)
+			skt->callback->suspend(skt);
+		mutex_lock(&skt->ops_mutex);
+		ret = socket_reset(skt);
+		mutex_unlock(&skt->ops_mutex);
+		if ((ret == 0) && (skt->callback))
+			skt->callback->resume(skt);
+
+		ret = 0;
+	} while (0);
+	mutex_unlock(&skt->skt_mutex);
+
+	return ret;
+} /* reset_card */
+EXPORT_SYMBOL(pcmcia_reset_card);
+
+
+static int pcmcia_socket_uevent(struct device *dev,
+				struct kobj_uevent_env *env)
+{
+	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+
+	if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
+		return -ENOMEM;
+
+	return 0;
+}
+
+
+static struct completion pcmcia_unload;
+
+static void pcmcia_release_socket_class(struct class *data)
+{
+	complete(&pcmcia_unload);
+}
+
+
+#ifdef CONFIG_PM
+
+static int __pcmcia_pm_op(struct device *dev,
+			  int (*callback) (struct pcmcia_socket *skt))
+{
+	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+	int ret;
+
+	mutex_lock(&s->skt_mutex);
+	ret = callback(s);
+	mutex_unlock(&s->skt_mutex);
+
+	return ret;
+}
+
+static int pcmcia_socket_dev_suspend_noirq(struct device *dev)
+{
+	return __pcmcia_pm_op(dev, socket_suspend);
+}
+
+static int pcmcia_socket_dev_resume_noirq(struct device *dev)
+{
+	return __pcmcia_pm_op(dev, socket_early_resume);
+}
+
+static int __used pcmcia_socket_dev_resume(struct device *dev)
+{
+	return __pcmcia_pm_op(dev, socket_late_resume);
+}
+
+static void __used pcmcia_socket_dev_complete(struct device *dev)
+{
+	WARN(__pcmcia_pm_op(dev, socket_complete_resume),
+		"failed to complete resume");
+}
+
+static const struct dev_pm_ops pcmcia_socket_pm_ops = {
+	/* dev_resume may be called with IRQs enabled */
+	SET_SYSTEM_SLEEP_PM_OPS(NULL,
+				pcmcia_socket_dev_resume)
+
+	/* late suspend must be called with IRQs disabled */
+	.suspend_noirq = pcmcia_socket_dev_suspend_noirq,
+	.freeze_noirq = pcmcia_socket_dev_suspend_noirq,
+	.poweroff_noirq = pcmcia_socket_dev_suspend_noirq,
+
+	/* early resume must be called with IRQs disabled */
+	.resume_noirq = pcmcia_socket_dev_resume_noirq,
+	.thaw_noirq = pcmcia_socket_dev_resume_noirq,
+	.restore_noirq = pcmcia_socket_dev_resume_noirq,
+	.complete = pcmcia_socket_dev_complete,
+};
+
+#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define PCMCIA_SOCKET_CLASS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
+struct class pcmcia_socket_class = {
+	.name = "pcmcia_socket",
+	.dev_uevent = pcmcia_socket_uevent,
+	.dev_release = pcmcia_release_socket,
+	.class_release = pcmcia_release_socket_class,
+	.pm = PCMCIA_SOCKET_CLASS_PM_OPS,
+};
+EXPORT_SYMBOL(pcmcia_socket_class);
+
+
+static int __init init_pcmcia_cs(void)
+{
+	init_completion(&pcmcia_unload);
+	return class_register(&pcmcia_socket_class);
+}
+
+static void __exit exit_pcmcia_cs(void)
+{
+	class_unregister(&pcmcia_socket_class);
+	wait_for_completion(&pcmcia_unload);
+}
+
+subsys_initcall(init_pcmcia_cs);
+module_exit(exit_pcmcia_cs);
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/cs_internal.h b/src/kernel/linux/v4.14/drivers/pcmcia/cs_internal.h
new file mode 100644
index 0000000..384629c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/cs_internal.h
@@ -0,0 +1,185 @@
+/*
+ * cs_internal.h -- definitions internal to the PCMCIA core modules
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ * (C) 2003 - 2010	Dominik Brodowski
+ *
+ *
+ * This file contains definitions _only_ needed by the PCMCIA core modules.
+ * It must not be included by PCMCIA socket drivers or by PCMCIA device
+ * drivers.
+ */
+
+#ifndef _LINUX_CS_INTERNAL_H
+#define _LINUX_CS_INTERNAL_H
+
+#include <linux/kref.h>
+
+/* Flags in client state */
+#define CLIENT_WIN_REQ(i)	(0x1<<(i))
+
+/* Flag to access all functions */
+#define BIND_FN_ALL	0xff
+
+/* Each card function gets one of these guys */
+typedef struct config_t {
+	struct kref	ref;
+	unsigned int	state;
+
+	struct resource io[MAX_IO_WIN]; /* io ports */
+	struct resource mem[MAX_WIN];   /* mem areas */
+} config_t;
+
+
+struct cis_cache_entry {
+	struct list_head	node;
+	unsigned int		addr;
+	unsigned int		len;
+	unsigned int		attr;
+	unsigned char		cache[0];
+};
+
+struct pccard_resource_ops {
+	int	(*validate_mem)		(struct pcmcia_socket *s);
+	int	(*find_io)		(struct pcmcia_socket *s,
+					 unsigned int attr,
+					 unsigned int *base,
+					 unsigned int num,
+					 unsigned int align,
+					 struct resource **parent);
+	struct resource* (*find_mem)	(unsigned long base, unsigned long num,
+					 unsigned long align, int low,
+					 struct pcmcia_socket *s);
+	int	(*init)			(struct pcmcia_socket *s);
+	void	(*exit)			(struct pcmcia_socket *s);
+};
+
+/* Flags in config state */
+#define CONFIG_LOCKED		0x01
+#define CONFIG_IRQ_REQ		0x02
+#define CONFIG_IO_REQ		0x04
+
+/* Flags in socket state */
+#define SOCKET_PRESENT		0x0008
+#define SOCKET_INUSE		0x0010
+#define SOCKET_IN_RESUME	0x0040
+#define SOCKET_SUSPEND		0x0080
+#define SOCKET_WIN_REQ(i)	(0x0100<<(i))
+#define SOCKET_CARDBUS		0x8000
+#define SOCKET_CARDBUS_CONFIG	0x10000
+
+
+/*
+ * Stuff internal to module "pcmcia_rsrc":
+ */
+extern int static_init(struct pcmcia_socket *s);
+extern struct resource *pcmcia_make_resource(resource_size_t start,
+					resource_size_t end,
+					unsigned long flags, const char *name);
+
+/*
+ * Stuff internal to module "pcmcia_core":
+ */
+
+/* socket_sysfs.c */
+extern int pccard_sysfs_add_socket(struct device *dev);
+extern void pccard_sysfs_remove_socket(struct device *dev);
+
+/* cardbus.c */
+int cb_alloc(struct pcmcia_socket *s);
+void cb_free(struct pcmcia_socket *s);
+
+
+
+/*
+ * Stuff exported by module "pcmcia_core" to module "pcmcia"
+ */
+
+struct pcmcia_callback{
+	struct module	*owner;
+	int		(*add) (struct pcmcia_socket *s);
+	int		(*remove) (struct pcmcia_socket *s);
+	void		(*requery) (struct pcmcia_socket *s);
+	int		(*validate) (struct pcmcia_socket *s, unsigned int *i);
+	int		(*suspend) (struct pcmcia_socket *s);
+	int		(*early_resume) (struct pcmcia_socket *s);
+	int		(*resume) (struct pcmcia_socket *s);
+};
+
+/* cs.c */
+extern struct rw_semaphore pcmcia_socket_list_rwsem;
+extern struct list_head pcmcia_socket_list;
+extern struct class pcmcia_socket_class;
+
+int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
+struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr);
+
+void pcmcia_parse_uevents(struct pcmcia_socket *socket, unsigned int events);
+#define PCMCIA_UEVENT_EJECT	0x0001
+#define PCMCIA_UEVENT_INSERT	0x0002
+#define PCMCIA_UEVENT_SUSPEND	0x0004
+#define PCMCIA_UEVENT_RESUME	0x0008
+#define PCMCIA_UEVENT_REQUERY	0x0010
+
+struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt);
+void pcmcia_put_socket(struct pcmcia_socket *skt);
+
+/*
+ * Stuff internal to module "pcmcia".
+ */
+/* ds.c */
+extern struct bus_type pcmcia_bus_type;
+
+struct pcmcia_device;
+
+/* pcmcia_resource.c */
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+extern int pcmcia_validate_mem(struct pcmcia_socket *s);
+extern struct resource *pcmcia_find_mem_region(u_long base,
+					       u_long num,
+					       u_long align,
+					       int low,
+					       struct pcmcia_socket *s);
+
+void pcmcia_cleanup_irq(struct pcmcia_socket *s);
+int pcmcia_setup_irq(struct pcmcia_device *p_dev);
+
+/* cistpl.c */
+extern struct bin_attribute pccard_cis_attr;
+
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
+			u_int addr, u_int len, void *ptr);
+int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
+			u_int addr, u_int len, void *ptr);
+void release_cis_mem(struct pcmcia_socket *s);
+void destroy_cis_cache(struct pcmcia_socket *s);
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
+		      cisdata_t code, void *parse);
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+		       const u8 *data, const size_t len);
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *count);
+int verify_cis_cache(struct pcmcia_socket *s);
+
+int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
+		      cisdata_t code, cisparse_t *parse, void *priv_data,
+		      int (*loop_tuple) (tuple_t *tuple,
+					 cisparse_t *parse,
+					 void *priv_data));
+
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+			tuple_t *tuple);
+
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+			tuple_t *tuple);
+
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
+
+#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/db1xxx_ss.c b/src/kernel/linux/v4.14/drivers/pcmcia/db1xxx_ss.c
new file mode 100644
index 0000000..19e1782
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/db1xxx_ss.c
@@ -0,0 +1,598 @@
+/*
+ * PCMCIA socket code for the Alchemy Db1xxx/Pb1xxx boards.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+/* This is a fairly generic PCMCIA socket driver suitable for the
+ * following Alchemy Development boards:
+ *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200, Db1300
+ *
+ * The Db1000 is used as a reference:  Per-socket card-, carddetect- and
+ *  statuschange IRQs connected to SoC GPIOs, control and status register
+ *  bits arranged in per-socket groups in an external PLD.  All boards
+ *  listed here use this layout, including bit positions and meanings.
+ *  Of course there are exceptions in later boards:
+ *
+ *	- Pb1100/Pb1500:  single socket only; voltage key bits VS are
+ *			  at STATUS[5:4] (instead of STATUS[1:0]).
+ *	- Au1200-based:	  additional card-eject irqs, irqs not gpios!
+ *	- Db1300:	  Db1200-like, no pwr ctrl, single socket (#1).
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#define MEM_MAP_SIZE	0x400000
+#define IO_MAP_SIZE	0x1000
+
+struct db1x_pcmcia_sock {
+	struct pcmcia_socket	socket;
+	int		nr;		/* socket number */
+	void		*virt_io;
+
+	phys_addr_t	phys_io;
+	phys_addr_t	phys_attr;
+	phys_addr_t	phys_mem;
+
+	/* previous flags for set_socket() */
+	unsigned int old_flags;
+
+	/* interrupt sources: linux irq numbers! */
+	int	insert_irq;	/* default carddetect irq */
+	int	stschg_irq;	/* card-status-change irq */
+	int	card_irq;	/* card irq */
+	int	eject_irq;	/* db1200/pb1200 have these */
+	int	insert_gpio;	/* db1000 carddetect gpio */
+
+#define BOARD_TYPE_DEFAULT	0	/* most boards */
+#define BOARD_TYPE_DB1200	1	/* IRQs aren't gpios */
+#define BOARD_TYPE_PB1100	2	/* VS bits slightly different */
+#define BOARD_TYPE_DB1300	3	/* no power control */
+	int	board_type;
+};
+
+#define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
+
+static int db1300_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	return bcsr_read(BCSR_SIGSTAT) & (1 << 8);
+}
+
+/* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
+static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	unsigned short sigstat;
+
+	sigstat = bcsr_read(BCSR_SIGSTAT);
+	return sigstat & 1 << (8 + 2 * sock->nr);
+}
+
+/* carddetect gpio: low-active */
+static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	return !gpio_get_value(sock->insert_gpio);
+}
+
+static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	switch (sock->board_type) {
+	case BOARD_TYPE_DB1200:
+		return db1200_card_inserted(sock);
+	case BOARD_TYPE_DB1300:
+		return db1300_card_inserted(sock);
+	default:
+		return db1000_card_inserted(sock);
+	}
+}
+
+/* STSCHG tends to bounce heavily when cards are inserted/ejected.
+ * To avoid this, the interrupt is normally disabled and only enabled
+ * after reset to a card has been de-asserted.
+ */
+static inline void set_stschg(struct db1x_pcmcia_sock *sock, int en)
+{
+	if (sock->stschg_irq != -1) {
+		if (en)
+			enable_irq(sock->stschg_irq);
+		else
+			disable_irq(sock->stschg_irq);
+	}
+}
+
+static irqreturn_t db1000_pcmcia_cdirq(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_STSCHG);
+
+	return IRQ_HANDLED;
+}
+
+/* Db/Pb1200 have separate per-socket insertion and ejection
+ * interrupts which stay asserted as long as the card is
+ * inserted/missing.  The one which caused us to be called
+ * needs to be disabled and the other one enabled.
+ */
+static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
+{
+	disable_irq_nosync(irq);
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t db1200_pcmcia_cdirq_fn(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	/* Wait a bit for the signals to stop bouncing. */
+	msleep(100);
+	if (irq == sock->insert_irq)
+		enable_irq(sock->eject_irq);
+	else
+		enable_irq(sock->insert_irq);
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
+{
+	int ret;
+
+	if (sock->stschg_irq != -1) {
+		ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
+				  0, "pcmcia_stschg", sock);
+		if (ret)
+			return ret;
+	}
+
+	/* Db/Pb1200 have separate per-socket insertion and ejection
+	 * interrupts, which should show edge behaviour but don't.
+	 * So interrupts are disabled until both insertion and
+	 * ejection handler have been registered and the currently
+	 * active one disabled.
+	 */
+	if ((sock->board_type == BOARD_TYPE_DB1200) ||
+	    (sock->board_type == BOARD_TYPE_DB1300)) {
+		ret = request_threaded_irq(sock->insert_irq, db1200_pcmcia_cdirq,
+			db1200_pcmcia_cdirq_fn, 0, "pcmcia_insert", sock);
+		if (ret)
+			goto out1;
+
+		ret = request_threaded_irq(sock->eject_irq, db1200_pcmcia_cdirq,
+			db1200_pcmcia_cdirq_fn, 0, "pcmcia_eject", sock);
+		if (ret) {
+			free_irq(sock->insert_irq, sock);
+			goto out1;
+		}
+
+		/* enable the currently silent one */
+		if (db1x_card_inserted(sock))
+			enable_irq(sock->eject_irq);
+		else
+			enable_irq(sock->insert_irq);
+	} else {
+		/* all other (older) Db1x00 boards use a GPIO to show
+		 * card detection status:  use both-edge triggers.
+		 */
+		irq_set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH);
+		ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq,
+				  0, "pcmcia_carddetect", sock);
+
+		if (ret)
+			goto out1;
+	}
+
+	return 0;	/* all done */
+
+out1:
+	if (sock->stschg_irq != -1)
+		free_irq(sock->stschg_irq, sock);
+
+	return ret;
+}
+
+static void db1x_pcmcia_free_irqs(struct db1x_pcmcia_sock *sock)
+{
+	if (sock->stschg_irq != -1)
+		free_irq(sock->stschg_irq, sock);
+
+	free_irq(sock->insert_irq, sock);
+	if (sock->eject_irq != -1)
+		free_irq(sock->eject_irq, sock);
+}
+
+/*
+ * configure a PCMCIA socket on the Db1x00 series of boards (and
+ * compatibles).
+ *
+ * 2 external registers are involved:
+ *   pcmcia_status (offset 0x04): bits [0:1/2:3]: read card voltage id
+ *   pcmcia_control(offset 0x10):
+ *	bits[0:1] set vcc for card
+ *	bits[2:3] set vpp for card
+ *	bit 4:	enable data buffers
+ *	bit 7:	reset# for card
+ *	add 8 for second socket.
+ */
+static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
+				 struct socket_state_t *state)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+	unsigned short cr_clr, cr_set;
+	unsigned int changed;
+	int v, p, ret;
+
+	/* card voltage setup */
+	cr_clr = (0xf << (sock->nr * 8)); /* clear voltage settings */
+	cr_set = 0;
+	v = p = ret = 0;
+
+	switch (state->Vcc) {
+	case 50:
+		++v;
+	case 33:
+		++v;
+	case 0:
+		break;
+	default:
+		printk(KERN_INFO "pcmcia%d unsupported Vcc %d\n",
+			sock->nr, state->Vcc);
+	}
+
+	switch (state->Vpp) {
+	case 12:
+		++p;
+	case 33:
+	case 50:
+		++p;
+	case 0:
+		break;
+	default:
+		printk(KERN_INFO "pcmcia%d unsupported Vpp %d\n",
+			sock->nr, state->Vpp);
+	}
+
+	/* sanity check: Vpp must be 0, 12, or Vcc */
+	if (((state->Vcc == 33) && (state->Vpp == 50)) ||
+	    ((state->Vcc == 50) && (state->Vpp == 33))) {
+		printk(KERN_INFO "pcmcia%d bad Vcc/Vpp combo (%d %d)\n",
+			sock->nr, state->Vcc, state->Vpp);
+		v = p = 0;
+		ret = -EINVAL;
+	}
+
+	/* create new voltage code */
+	if (sock->board_type != BOARD_TYPE_DB1300)
+		cr_set |= ((v << 2) | p) << (sock->nr * 8);
+
+	changed = state->flags ^ sock->old_flags;
+
+	if (changed & SS_RESET) {
+		if (state->flags & SS_RESET) {
+			set_stschg(sock, 0);
+			/* assert reset, disable io buffers */
+			cr_clr |= (1 << (7 + (sock->nr * 8)));
+			cr_clr |= (1 << (4 + (sock->nr * 8)));
+		} else {
+			/* de-assert reset, enable io buffers */
+			cr_set |= 1 << (7 + (sock->nr * 8));
+			cr_set |= 1 << (4 + (sock->nr * 8));
+		}
+	}
+
+	/* update PCMCIA configuration */
+	bcsr_mod(BCSR_PCMCIA, cr_clr, cr_set);
+
+	sock->old_flags = state->flags;
+
+	/* reset was taken away: give card time to initialize properly */
+	if ((changed & SS_RESET) && !(state->flags & SS_RESET)) {
+		msleep(500);
+		set_stschg(sock, 1);
+	}
+
+	return ret;
+}
+
+/* VCC bits at [3:2]/[11:10] */
+#define GET_VCC(cr, socknr)		\
+	((((cr) >> 2) >> ((socknr) * 8)) & 3)
+
+/* VS bits at [0:1]/[3:2] */
+#define GET_VS(sr, socknr)		\
+	(((sr) >> (2 * (socknr))) & 3)
+
+/* reset bits at [7]/[15] */
+#define GET_RESET(cr, socknr)		\
+	((cr) & (1 << (7 + (8 * (socknr)))))
+
+static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
+				  unsigned int *value)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+	unsigned short cr, sr;
+	unsigned int status;
+
+	status = db1x_card_inserted(sock) ? SS_DETECT : 0;
+
+	cr = bcsr_read(BCSR_PCMCIA);
+	sr = bcsr_read(BCSR_STATUS);
+
+	/* PB1100/PB1500: voltage key bits are at [5:4] */
+	if (sock->board_type == BOARD_TYPE_PB1100)
+		sr >>= 4;
+
+	/* determine card type */
+	switch (GET_VS(sr, sock->nr)) {
+	case 0:
+	case 2:
+		status |= SS_3VCARD;	/* 3V card */
+	case 3:
+		break;			/* 5V card: set nothing */
+	default:
+		status |= SS_XVCARD;	/* treated as unsupported in core */
+	}
+
+	/* if Vcc is not zero, we have applied power to a card */
+	status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
+
+	/* DB1300: power always on, but don't tell when no card present */
+	if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT))
+		status = SS_POWERON | SS_3VCARD | SS_DETECT;
+
+	/* reset de-asserted? then we're ready */
+	status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
+
+	*value = status;
+
+	return 0;
+}
+
+static int db1x_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int db1x_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+				    struct pccard_io_map *map)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+	map->start = (u32)sock->virt_io;
+	map->stop = map->start + IO_MAP_SIZE;
+
+	return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+				     struct pccard_mem_map *map)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = sock->phys_attr + map->card_start;
+	else
+		map->static_start = sock->phys_mem + map->card_start;
+
+	return 0;
+}
+
+static struct pccard_operations db1x_pcmcia_operations = {
+	.init			= db1x_pcmcia_sock_init,
+	.suspend		= db1x_pcmcia_sock_suspend,
+	.get_status		= db1x_pcmcia_get_status,
+	.set_socket		= db1x_pcmcia_configure,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static int db1x_pcmcia_socket_probe(struct platform_device *pdev)
+{
+	struct db1x_pcmcia_sock *sock;
+	struct resource *r;
+	int ret, bid;
+
+	sock = kzalloc(sizeof(struct db1x_pcmcia_sock), GFP_KERNEL);
+	if (!sock)
+		return -ENOMEM;
+
+	sock->nr = pdev->id;
+
+	bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+	switch (bid) {
+	case BCSR_WHOAMI_PB1500:
+	case BCSR_WHOAMI_PB1500R2:
+	case BCSR_WHOAMI_PB1100:
+		sock->board_type = BOARD_TYPE_PB1100;
+		break;
+	case BCSR_WHOAMI_DB1000 ... BCSR_WHOAMI_PB1550_SDR:
+		sock->board_type = BOARD_TYPE_DEFAULT;
+		break;
+	case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
+		sock->board_type = BOARD_TYPE_DB1200;
+		break;
+	case BCSR_WHOAMI_DB1300:
+		sock->board_type = BOARD_TYPE_DB1300;
+		break;
+	default:
+		printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
+		ret = -ENODEV;
+		goto out0;
+	};
+
+	/*
+	 * gather resources necessary and optional nice-to-haves to
+	 * operate a socket:
+	 * This includes IRQs for Carddetection/ejection, the card
+	 *  itself and optional status change detection.
+	 * Also, the memory areas covered by a socket.  For these
+	 *  we require the real 36bit addresses (see the au1000.h
+	 *  header for more information).
+	 */
+
+	/* card: irq assigned to the card itself. */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
+	sock->card_irq = r ? r->start : 0;
+
+	/* insert: irq which triggers on card insertion/ejection
+	 * BIG FAT NOTE: on DB1000/1100/1500/1550 we pass a GPIO here!
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
+	sock->insert_irq = r ? r->start : -1;
+	if (sock->board_type == BOARD_TYPE_DEFAULT) {
+		sock->insert_gpio = r ? r->start : -1;
+		sock->insert_irq = r ? gpio_to_irq(r->start) : -1;
+	}
+
+	/* stschg: irq which trigger on card status change (optional) */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
+	sock->stschg_irq = r ? r->start : -1;
+
+	/* eject: irq which triggers on ejection (DB1200/PB1200 only) */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eject");
+	sock->eject_irq = r ? r->start : -1;
+
+	ret = -ENODEV;
+
+	/* 36bit PCMCIA Attribute area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_attr = r->start;
+
+	/* 36bit PCMCIA Memory area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_mem = r->start;
+
+	/* 36bit PCMCIA IO area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_io = r->start;
+
+	/*
+	 * PCMCIA client drivers use the inb/outb macros to access
+	 * the IO registers.  Since mips_io_port_base is added
+	 * to the access address of the mips implementation of
+	 * inb/outb, we need to subtract it here because we want
+	 * to access the I/O or MEM address directly, without
+	 * going through this "mips_io_port_base" mechanism.
+	 */
+	sock->virt_io = (void *)(ioremap(sock->phys_io, IO_MAP_SIZE) -
+				 mips_io_port_base);
+
+	if (!sock->virt_io) {
+		printk(KERN_ERR "pcmcia%d: cannot remap IO area\n",
+			sock->nr);
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	sock->socket.ops	= &db1x_pcmcia_operations;
+	sock->socket.owner	= THIS_MODULE;
+	sock->socket.pci_irq	= sock->card_irq;
+	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->socket.map_size	= MEM_MAP_SIZE;
+	sock->socket.io_offset	= (unsigned long)sock->virt_io;
+	sock->socket.dev.parent	= &pdev->dev;
+	sock->socket.resource_ops = &pccard_static_ops;
+
+	platform_set_drvdata(pdev, sock);
+
+	ret = db1x_pcmcia_setup_irqs(sock);
+	if (ret) {
+		printk(KERN_ERR "pcmcia%d cannot setup interrupts\n",
+			sock->nr);
+		goto out1;
+	}
+
+	set_stschg(sock, 0);
+
+	ret = pcmcia_register_socket(&sock->socket);
+	if (ret) {
+		printk(KERN_ERR "pcmcia%d failed to register\n", sock->nr);
+		goto out2;
+	}
+
+	printk(KERN_INFO "Alchemy Db/Pb1xxx pcmcia%d @ io/attr/mem %09llx"
+		"(%p) %09llx %09llx  card/insert/stschg/eject irqs @ %d "
+		"%d %d %d\n", sock->nr, sock->phys_io, sock->virt_io,
+		sock->phys_attr, sock->phys_mem, sock->card_irq,
+		sock->insert_irq, sock->stschg_irq, sock->eject_irq);
+
+	return 0;
+
+out2:
+	db1x_pcmcia_free_irqs(sock);
+out1:
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+	kfree(sock);
+	return ret;
+}
+
+static int db1x_pcmcia_socket_remove(struct platform_device *pdev)
+{
+	struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+	db1x_pcmcia_free_irqs(sock);
+	pcmcia_unregister_socket(&sock->socket);
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+	kfree(sock);
+
+	return 0;
+}
+
+static struct platform_driver db1x_pcmcia_socket_driver = {
+	.driver	= {
+		.name	= "db1xxx_pcmcia",
+	},
+	.probe		= db1x_pcmcia_socket_probe,
+	.remove		= db1x_pcmcia_socket_remove,
+};
+
+module_platform_driver(db1x_pcmcia_socket_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/ds.c b/src/kernel/linux/v4.14/drivers/pcmcia/ds.c
new file mode 100644
index 0000000..a9258f6
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/ds.c
@@ -0,0 +1,1460 @@
+/*
+ * ds.c -- 16-bit PCMCIA core support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ * (C) 2003 - 2010	Dominik Brodowski
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
+#include <linux/kref.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
+
+#include "cs_internal.h"
+
+/*====================================================================*/
+
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA Driver Services");
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+
+static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
+{
+	const struct pcmcia_device_id *did = p_drv->id_table;
+	unsigned int i;
+	u32 hash;
+
+	if (!p_drv->probe || !p_drv->remove)
+		printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
+		       "function\n", p_drv->name);
+
+	while (did && did->match_flags) {
+		for (i = 0; i < 4; i++) {
+			if (!did->prod_id[i])
+				continue;
+
+			hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
+			if (hash == did->prod_id_hash[i])
+				continue;
+
+			printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
+			       "product string \"%s\": is 0x%x, should "
+			       "be 0x%x\n", p_drv->name, did->prod_id[i],
+			       did->prod_id_hash[i], hash);
+			printk(KERN_DEBUG "pcmcia: see "
+				"Documentation/pcmcia/devicetable.txt for "
+				"details\n");
+		}
+		did++;
+	}
+
+	return;
+}
+
+
+/*======================================================================*/
+
+
+struct pcmcia_dynid {
+	struct list_head		node;
+	struct pcmcia_device_id		id;
+};
+
+/**
+ * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic PCMCIA device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t
+new_id_store(struct device_driver *driver, const char *buf, size_t count)
+{
+	struct pcmcia_dynid *dynid;
+	struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
+	__u16 match_flags, manf_id, card_id;
+	__u8 func_id, function, device_no;
+	__u32 prod_id_hash[4] = {0, 0, 0, 0};
+	int fields = 0;
+	int retval = 0;
+
+	fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
+			&match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
+			&prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
+	if (fields < 6)
+		return -EINVAL;
+
+	dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
+	if (!dynid)
+		return -ENOMEM;
+
+	dynid->id.match_flags = match_flags;
+	dynid->id.manf_id = manf_id;
+	dynid->id.card_id = card_id;
+	dynid->id.func_id = func_id;
+	dynid->id.function = function;
+	dynid->id.device_no = device_no;
+	memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
+
+	mutex_lock(&pdrv->dynids.lock);
+	list_add_tail(&dynid->node, &pdrv->dynids.list);
+	mutex_unlock(&pdrv->dynids.lock);
+
+	retval = driver_attach(&pdrv->drv);
+
+	if (retval)
+		return retval;
+	return count;
+}
+static DRIVER_ATTR_WO(new_id);
+
+static void
+pcmcia_free_dynids(struct pcmcia_driver *drv)
+{
+	struct pcmcia_dynid *dynid, *n;
+
+	mutex_lock(&drv->dynids.lock);
+	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	mutex_unlock(&drv->dynids.lock);
+}
+
+static int
+pcmcia_create_newid_file(struct pcmcia_driver *drv)
+{
+	int error = 0;
+	if (drv->probe != NULL)
+		error = driver_create_file(&drv->drv, &driver_attr_new_id);
+	return error;
+}
+
+static void
+pcmcia_remove_newid_file(struct pcmcia_driver *drv)
+{
+	driver_remove_file(&drv->drv, &driver_attr_new_id);
+}
+
+/**
+ * pcmcia_register_driver - register a PCMCIA driver with the bus core
+ * @driver: the &driver being registered
+ *
+ * Registers a PCMCIA driver with the PCMCIA bus core.
+ */
+int pcmcia_register_driver(struct pcmcia_driver *driver)
+{
+	int error;
+
+	if (!driver)
+		return -EINVAL;
+
+	pcmcia_check_driver(driver);
+
+	/* initialize common fields */
+	driver->drv.bus = &pcmcia_bus_type;
+	driver->drv.owner = driver->owner;
+	driver->drv.name = driver->name;
+	mutex_init(&driver->dynids.lock);
+	INIT_LIST_HEAD(&driver->dynids.list);
+
+	pr_debug("registering driver %s\n", driver->name);
+
+	error = driver_register(&driver->drv);
+	if (error < 0)
+		return error;
+
+	error = pcmcia_create_newid_file(driver);
+	if (error)
+		driver_unregister(&driver->drv);
+
+	return error;
+}
+EXPORT_SYMBOL(pcmcia_register_driver);
+
+/**
+ * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core
+ * @driver: the &driver being unregistered
+ */
+void pcmcia_unregister_driver(struct pcmcia_driver *driver)
+{
+	pr_debug("unregistering driver %s\n", driver->name);
+	pcmcia_remove_newid_file(driver);
+	driver_unregister(&driver->drv);
+	pcmcia_free_dynids(driver);
+}
+EXPORT_SYMBOL(pcmcia_unregister_driver);
+
+
+/* pcmcia_device handling */
+
+static struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
+{
+	struct device *tmp_dev;
+	tmp_dev = get_device(&p_dev->dev);
+	if (!tmp_dev)
+		return NULL;
+	return to_pcmcia_dev(tmp_dev);
+}
+
+static void pcmcia_put_dev(struct pcmcia_device *p_dev)
+{
+	if (p_dev)
+		put_device(&p_dev->dev);
+}
+
+static void pcmcia_release_function(struct kref *ref)
+{
+	struct config_t *c = container_of(ref, struct config_t, ref);
+	pr_debug("releasing config_t\n");
+	kfree(c);
+}
+
+static void pcmcia_release_dev(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	int i;
+	dev_dbg(dev, "releasing device\n");
+	pcmcia_put_socket(p_dev->socket);
+	for (i = 0; i < 4; i++)
+		kfree(p_dev->prod_id[i]);
+	kfree(p_dev->devname);
+	kref_put(&p_dev->function_config->ref, pcmcia_release_function);
+	kfree(p_dev);
+}
+
+
+static int pcmcia_device_probe(struct device *dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_driver *p_drv;
+	struct pcmcia_socket *s;
+	cistpl_config_t cis_config;
+	int ret = 0;
+
+	dev = get_device(dev);
+	if (!dev)
+		return -ENODEV;
+
+	p_dev = to_pcmcia_dev(dev);
+	p_drv = to_pcmcia_drv(dev->driver);
+	s = p_dev->socket;
+
+	dev_dbg(dev, "trying to bind to %s\n", p_drv->name);
+
+	if ((!p_drv->probe) || (!p_dev->function_config) ||
+	    (!try_module_get(p_drv->owner))) {
+		ret = -EINVAL;
+		goto put_dev;
+	}
+
+	/* set up some more device information */
+	ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
+				&cis_config);
+	if (!ret) {
+		p_dev->config_base = cis_config.base;
+		p_dev->config_regs = cis_config.rmask[0];
+		dev_dbg(dev, "base %x, regs %x", p_dev->config_base,
+			p_dev->config_regs);
+	} else {
+		dev_info(dev,
+			 "pcmcia: could not parse base and rmask0 of CIS\n");
+		p_dev->config_base = 0;
+		p_dev->config_regs = 0;
+	}
+
+	ret = p_drv->probe(p_dev);
+	if (ret) {
+		dev_dbg(dev, "binding to %s failed with %d\n",
+			   p_drv->name, ret);
+		goto put_module;
+	}
+	dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name,
+		p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq);
+	dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR",
+		p_dev->resource[0], p_dev->resource[1], p_dev->resource[2],
+		p_dev->resource[3], p_dev->resource[4]);
+
+	mutex_lock(&s->ops_mutex);
+	if ((s->pcmcia_pfc) &&
+	    (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
+		pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+	mutex_unlock(&s->ops_mutex);
+
+put_module:
+	if (ret)
+		module_put(p_drv->owner);
+put_dev:
+	if (ret)
+		put_device(dev);
+	return ret;
+}
+
+
+/*
+ * Removes a PCMCIA card from the device tree and socket list.
+ */
+static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
+{
+	struct pcmcia_device	*p_dev;
+	struct pcmcia_device	*tmp;
+
+	dev_dbg(leftover ? &leftover->dev : &s->dev,
+		   "pcmcia_card_remove(%d) %s\n", s->sock,
+		   leftover ? leftover->devname : "");
+
+	mutex_lock(&s->ops_mutex);
+	if (!leftover)
+		s->device_count = 0;
+	else
+		s->device_count = 1;
+	mutex_unlock(&s->ops_mutex);
+
+	/* unregister all pcmcia_devices registered with this socket, except leftover */
+	list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
+		if (p_dev == leftover)
+			continue;
+
+		mutex_lock(&s->ops_mutex);
+		list_del(&p_dev->socket_device_list);
+		mutex_unlock(&s->ops_mutex);
+
+		dev_dbg(&p_dev->dev, "unregistering device\n");
+		device_unregister(&p_dev->dev);
+	}
+
+	return;
+}
+
+static int pcmcia_device_remove(struct device *dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_driver *p_drv;
+	int i;
+
+	p_dev = to_pcmcia_dev(dev);
+	p_drv = to_pcmcia_drv(dev->driver);
+
+	dev_dbg(dev, "removing device\n");
+
+	/* If we're removing the primary module driving a
+	 * pseudo multi-function card, we need to unbind
+	 * all devices
+	 */
+	if ((p_dev->socket->pcmcia_pfc) &&
+	    (p_dev->socket->device_count > 0) &&
+	    (p_dev->device_no == 0))
+		pcmcia_card_remove(p_dev->socket, p_dev);
+
+	/* detach the "instance" */
+	if (!p_drv)
+		return 0;
+
+	if (p_drv->remove)
+		p_drv->remove(p_dev);
+
+	/* check for proper unloading */
+	if (p_dev->_irq || p_dev->_io || p_dev->_locked)
+		dev_info(dev,
+			 "pcmcia: driver %s did not release config properly\n",
+			 p_drv->name);
+
+	for (i = 0; i < MAX_WIN; i++)
+		if (p_dev->_win & CLIENT_WIN_REQ(i))
+			dev_info(dev,
+				 "pcmcia: driver %s did not release window properly\n",
+				 p_drv->name);
+
+	/* references from pcmcia_probe_device */
+	pcmcia_put_dev(p_dev);
+	module_put(p_drv->owner);
+
+	return 0;
+}
+
+
+/*
+ * pcmcia_device_query -- determine information about a pcmcia device
+ */
+static int pcmcia_device_query(struct pcmcia_device *p_dev)
+{
+	cistpl_manfid_t manf_id;
+	cistpl_funcid_t func_id;
+	cistpl_vers_1_t	*vers1;
+	unsigned int i;
+
+	vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);
+	if (!vers1)
+		return -ENOMEM;
+
+	if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
+			       CISTPL_MANFID, &manf_id)) {
+		mutex_lock(&p_dev->socket->ops_mutex);
+		p_dev->manf_id = manf_id.manf;
+		p_dev->card_id = manf_id.card;
+		p_dev->has_manf_id = 1;
+		p_dev->has_card_id = 1;
+		mutex_unlock(&p_dev->socket->ops_mutex);
+	}
+
+	if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+			       CISTPL_FUNCID, &func_id)) {
+		mutex_lock(&p_dev->socket->ops_mutex);
+		p_dev->func_id = func_id.func;
+		p_dev->has_func_id = 1;
+		mutex_unlock(&p_dev->socket->ops_mutex);
+	} else {
+		/* rule of thumb: cards with no FUNCID, but with
+		 * common memory device geometry information, are
+		 * probably memory cards (from pcmcia-cs) */
+		cistpl_device_geo_t *devgeo;
+
+		devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);
+		if (!devgeo) {
+			kfree(vers1);
+			return -ENOMEM;
+		}
+		if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+				      CISTPL_DEVICE_GEO, devgeo)) {
+			dev_dbg(&p_dev->dev,
+				   "mem device geometry probably means "
+				   "FUNCID_MEMORY\n");
+			mutex_lock(&p_dev->socket->ops_mutex);
+			p_dev->func_id = CISTPL_FUNCID_MEMORY;
+			p_dev->has_func_id = 1;
+			mutex_unlock(&p_dev->socket->ops_mutex);
+		}
+		kfree(devgeo);
+	}
+
+	if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
+			       vers1)) {
+		mutex_lock(&p_dev->socket->ops_mutex);
+		for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
+			char *tmp;
+			unsigned int length;
+			char *new;
+
+			tmp = vers1->str + vers1->ofs[i];
+
+			length = strlen(tmp) + 1;
+			if ((length < 2) || (length > 255))
+				continue;
+
+			new = kstrdup(tmp, GFP_KERNEL);
+			if (!new)
+				continue;
+
+			tmp = p_dev->prod_id[i];
+			p_dev->prod_id[i] = new;
+			kfree(tmp);
+		}
+		mutex_unlock(&p_dev->socket->ops_mutex);
+	}
+
+	kfree(vers1);
+	return 0;
+}
+
+
+static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
+					       unsigned int function)
+{
+	struct pcmcia_device *p_dev, *tmp_dev;
+	int i;
+
+	s = pcmcia_get_socket(s);
+	if (!s)
+		return NULL;
+
+	pr_debug("adding device to %d, function %d\n", s->sock, function);
+
+	p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+	if (!p_dev)
+		goto err_put;
+
+	mutex_lock(&s->ops_mutex);
+	p_dev->device_no = (s->device_count++);
+	mutex_unlock(&s->ops_mutex);
+
+	/* max of 2 PFC devices */
+	if ((p_dev->device_no >= 2) && (function == 0))
+		goto err_free;
+
+	/* max of 4 devices overall */
+	if (p_dev->device_no >= 4)
+		goto err_free;
+
+	p_dev->socket = s;
+	p_dev->func   = function;
+
+	p_dev->dev.bus = &pcmcia_bus_type;
+	p_dev->dev.parent = s->dev.parent;
+	p_dev->dev.release = pcmcia_release_dev;
+	/* by default don't allow DMA */
+	p_dev->dma_mask = DMA_MASK_NONE;
+	p_dev->dev.dma_mask = &p_dev->dma_mask;
+	dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
+	if (!dev_name(&p_dev->dev))
+		goto err_free;
+	p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
+	if (!p_dev->devname)
+		goto err_free;
+	dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
+
+	mutex_lock(&s->ops_mutex);
+
+	/*
+	 * p_dev->function_config must be the same for all card functions.
+	 * Note that this is serialized by ops_mutex, so that only one
+	 * such struct will be created.
+	 */
+	list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
+		if (p_dev->func == tmp_dev->func) {
+			p_dev->function_config = tmp_dev->function_config;
+			p_dev->irq = tmp_dev->irq;
+			kref_get(&p_dev->function_config->ref);
+		}
+
+	/* Add to the list in pcmcia_bus_socket */
+	list_add(&p_dev->socket_device_list, &s->devices_list);
+
+	if (pcmcia_setup_irq(p_dev))
+		dev_warn(&p_dev->dev,
+			"IRQ setup failed -- device might not work\n");
+
+	if (!p_dev->function_config) {
+		config_t *c;
+		dev_dbg(&p_dev->dev, "creating config_t\n");
+		c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
+		if (!c) {
+			mutex_unlock(&s->ops_mutex);
+			goto err_unreg;
+		}
+		p_dev->function_config = c;
+		kref_init(&c->ref);
+		for (i = 0; i < MAX_IO_WIN; i++) {
+			c->io[i].name = p_dev->devname;
+			c->io[i].flags = IORESOURCE_IO;
+		}
+		for (i = 0; i < MAX_WIN; i++) {
+			c->mem[i].name = p_dev->devname;
+			c->mem[i].flags = IORESOURCE_MEM;
+		}
+	}
+	for (i = 0; i < MAX_IO_WIN; i++)
+		p_dev->resource[i] = &p_dev->function_config->io[i];
+	for (; i < (MAX_IO_WIN + MAX_WIN); i++)
+		p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
+
+	mutex_unlock(&s->ops_mutex);
+
+	dev_notice(&p_dev->dev, "pcmcia: registering new device %s (IRQ: %d)\n",
+		   p_dev->devname, p_dev->irq);
+
+	pcmcia_device_query(p_dev);
+
+	if (device_register(&p_dev->dev))
+		goto err_unreg;
+
+	return p_dev;
+
+ err_unreg:
+	mutex_lock(&s->ops_mutex);
+	list_del(&p_dev->socket_device_list);
+	mutex_unlock(&s->ops_mutex);
+
+ err_free:
+	mutex_lock(&s->ops_mutex);
+	s->device_count--;
+	mutex_unlock(&s->ops_mutex);
+
+	for (i = 0; i < 4; i++)
+		kfree(p_dev->prod_id[i]);
+	kfree(p_dev->devname);
+	kfree(p_dev);
+ err_put:
+	pcmcia_put_socket(s);
+
+	return NULL;
+}
+
+
+static int pcmcia_card_add(struct pcmcia_socket *s)
+{
+	cistpl_longlink_mfc_t mfc;
+	unsigned int no_funcs, i, no_chains;
+	int ret = -EAGAIN;
+
+	mutex_lock(&s->ops_mutex);
+	if (!(s->resource_setup_done)) {
+		dev_dbg(&s->dev,
+			   "no resources available, delaying card_add\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EAGAIN; /* try again, but later... */
+	}
+
+	if (pcmcia_validate_mem(s)) {
+		dev_dbg(&s->dev, "validating mem resources failed, "
+		       "delaying card_add\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EAGAIN; /* try again, but later... */
+	}
+	mutex_unlock(&s->ops_mutex);
+
+	ret = pccard_validate_cis(s, &no_chains);
+	if (ret || !no_chains) {
+#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
+		/* Set up as an anonymous card. If we don't have anonymous
+		   memory support then just error the card as there is no
+		   point trying to second guess.
+
+		   Note: some cards have just a device entry, it may be
+		   worth extending support to cover these in future */
+		if (ret == -EIO) {
+			dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
+			pcmcia_replace_cis(s, "\xFF", 1);
+			no_chains = 1;
+			ret = 0;
+		} else
+#endif
+		{
+			dev_dbg(&s->dev, "invalid CIS or invalid resources\n");
+			return -ENODEV;
+		}
+	}
+
+	if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
+		no_funcs = mfc.nfn;
+	else
+		no_funcs = 1;
+	s->functions = no_funcs;
+
+	for (i = 0; i < no_funcs; i++)
+		pcmcia_device_add(s, i);
+
+	return ret;
+}
+
+
+static int pcmcia_requery_callback(struct device *dev, void *_data)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	if (!p_dev->dev.driver) {
+		dev_dbg(dev, "update device information\n");
+		pcmcia_device_query(p_dev);
+	}
+
+	return 0;
+}
+
+
+static void pcmcia_requery(struct pcmcia_socket *s)
+{
+	int has_pfc;
+
+	if (!(s->state & SOCKET_PRESENT))
+		return;
+
+	if (s->functions == 0) {
+		pcmcia_card_add(s);
+		return;
+	}
+
+	/* some device information might have changed because of a CIS
+	 * update or because we can finally read it correctly... so
+	 * determine it again, overwriting old values if necessary. */
+	bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
+
+	/* if the CIS changed, we need to check whether the number of
+	 * functions changed. */
+	if (s->fake_cis) {
+		int old_funcs, new_funcs;
+		cistpl_longlink_mfc_t mfc;
+
+		/* does this cis override add or remove functions? */
+		old_funcs = s->functions;
+
+		if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
+					&mfc))
+			new_funcs = mfc.nfn;
+		else
+			new_funcs = 1;
+		if (old_funcs != new_funcs) {
+			/* we need to re-start */
+			pcmcia_card_remove(s, NULL);
+			s->functions = 0;
+			pcmcia_card_add(s);
+		}
+	}
+
+	/* If the PCMCIA device consists of two pseudo devices,
+	 * call pcmcia_device_add() -- which will fail if both
+	 * devices are already registered. */
+	mutex_lock(&s->ops_mutex);
+	has_pfc = s->pcmcia_pfc;
+	mutex_unlock(&s->ops_mutex);
+	if (has_pfc)
+		pcmcia_device_add(s, 0);
+
+	/* we re-scan all devices, not just the ones connected to this
+	 * socket. This does not matter, though. */
+	if (bus_rescan_devices(&pcmcia_bus_type))
+		dev_warn(&s->dev, "rescanning the bus failed\n");
+}
+
+
+#ifdef CONFIG_PCMCIA_LOAD_CIS
+
+/**
+ * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+ * @dev: the pcmcia device which needs a CIS override
+ * @filename: requested filename in /lib/firmware/
+ *
+ * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+ * the one provided by the card is broken. The firmware files reside in
+ * /lib/firmware/ in userspace.
+ */
+static int pcmcia_load_firmware(struct pcmcia_device *dev, char *filename)
+{
+	struct pcmcia_socket *s = dev->socket;
+	const struct firmware *fw;
+	int ret = -ENOMEM;
+	cistpl_longlink_mfc_t mfc;
+	int old_funcs, new_funcs = 1;
+
+	if (!filename)
+		return -EINVAL;
+
+	dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename);
+
+	if (request_firmware(&fw, filename, &dev->dev) == 0) {
+		if (fw->size >= CISTPL_MAX_CIS_SIZE) {
+			ret = -EINVAL;
+			dev_err(&dev->dev, "pcmcia: CIS override is too big\n");
+			goto release;
+		}
+
+		if (!pcmcia_replace_cis(s, fw->data, fw->size))
+			ret = 0;
+		else {
+			dev_err(&dev->dev, "pcmcia: CIS override failed\n");
+			goto release;
+		}
+
+		/* we need to re-start if the number of functions changed */
+		old_funcs = s->functions;
+		if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
+					&mfc))
+			new_funcs = mfc.nfn;
+
+		if (old_funcs != new_funcs)
+			ret = -EBUSY;
+
+		/* update information */
+		pcmcia_device_query(dev);
+
+		/* requery (as number of functions might have changed) */
+		pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+	}
+ release:
+	release_firmware(fw);
+
+	return ret;
+}
+
+#else /* !CONFIG_PCMCIA_LOAD_CIS */
+
+static inline int pcmcia_load_firmware(struct pcmcia_device *dev,
+				       char *filename)
+{
+	return -ENODEV;
+}
+
+#endif
+
+
+static inline int pcmcia_devmatch(struct pcmcia_device *dev,
+				  const struct pcmcia_device_id *did)
+{
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
+		if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
+		if ((!dev->has_card_id) || (dev->card_id != did->card_id))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
+		if (dev->func != did->function)
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
+		if (!dev->prod_id[0])
+			return 0;
+		if (strcmp(did->prod_id[0], dev->prod_id[0]))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
+		if (!dev->prod_id[1])
+			return 0;
+		if (strcmp(did->prod_id[1], dev->prod_id[1]))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
+		if (!dev->prod_id[2])
+			return 0;
+		if (strcmp(did->prod_id[2], dev->prod_id[2]))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
+		if (!dev->prod_id[3])
+			return 0;
+		if (strcmp(did->prod_id[3], dev->prod_id[3]))
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
+		dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
+		mutex_lock(&dev->socket->ops_mutex);
+		dev->socket->pcmcia_pfc = 1;
+		mutex_unlock(&dev->socket->ops_mutex);
+		if (dev->device_no != did->device_no)
+			return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
+		int ret;
+
+		if ((!dev->has_func_id) || (dev->func_id != did->func_id))
+			return 0;
+
+		/* if this is a pseudo-multi-function device,
+		 * we need explicit matches */
+		if (dev->socket->pcmcia_pfc)
+			return 0;
+		if (dev->device_no)
+			return 0;
+
+		/* also, FUNC_ID matching needs to be activated by userspace
+		 * after it has re-checked that there is no possible module
+		 * with a prod_id/manf_id/card_id match.
+		 */
+		mutex_lock(&dev->socket->ops_mutex);
+		ret = dev->allow_func_id_match;
+		mutex_unlock(&dev->socket->ops_mutex);
+
+		if (!ret) {
+			dev_dbg(&dev->dev,
+				"skipping FUNC_ID match until userspace ACK\n");
+			return 0;
+		}
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
+		dev_dbg(&dev->dev, "device needs a fake CIS\n");
+		if (!dev->socket->fake_cis)
+			if (pcmcia_load_firmware(dev, did->cisfile))
+				return 0;
+	}
+
+	if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
+		int i;
+		for (i = 0; i < 4; i++)
+			if (dev->prod_id[i])
+				return 0;
+		if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
+	const struct pcmcia_device_id *did = p_drv->id_table;
+	struct pcmcia_dynid *dynid;
+
+	/* match dynamic devices first */
+	mutex_lock(&p_drv->dynids.lock);
+	list_for_each_entry(dynid, &p_drv->dynids.list, node) {
+		dev_dbg(dev, "trying to match to %s\n", drv->name);
+		if (pcmcia_devmatch(p_dev, &dynid->id)) {
+			dev_dbg(dev, "matched to %s\n", drv->name);
+			mutex_unlock(&p_drv->dynids.lock);
+			return 1;
+		}
+	}
+	mutex_unlock(&p_drv->dynids.lock);
+
+	while (did && did->match_flags) {
+		dev_dbg(dev, "trying to match to %s\n", drv->name);
+		if (pcmcia_devmatch(p_dev, did)) {
+			dev_dbg(dev, "matched to %s\n", drv->name);
+			return 1;
+		}
+		did++;
+	}
+
+	return 0;
+}
+
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct pcmcia_device *p_dev;
+	int i;
+	u32 hash[4] = { 0, 0, 0, 0};
+
+	if (!dev)
+		return -ENODEV;
+
+	p_dev = to_pcmcia_dev(dev);
+
+	/* calculate hashes */
+	for (i = 0; i < 4; i++) {
+		if (!p_dev->prod_id[i])
+			continue;
+		hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
+	}
+
+	if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+			   "pa%08Xpb%08Xpc%08Xpd%08X",
+			   p_dev->has_manf_id ? p_dev->manf_id : 0,
+			   p_dev->has_card_id ? p_dev->card_id : 0,
+			   p_dev->has_func_id ? p_dev->func_id : 0,
+			   p_dev->func,
+			   p_dev->device_no,
+			   hash[0],
+			   hash[1],
+			   hash[2],
+			   hash[3]))
+		return -ENOMEM;
+
+	return 0;
+}
+
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+	int rc;
+
+	device_lock(dev);
+	rc = pcmcia_dev_suspend(dev);
+	device_unlock(dev);
+	return rc;
+}
+
+static int runtime_resume(struct device *dev)
+{
+	int rc;
+
+	device_lock(dev);
+	rc = pcmcia_dev_resume(dev);
+	device_unlock(dev);
+	return rc;
+}
+
+/************************ per-device sysfs output ***************************/
+
+#define pcmcia_device_attr(field, test, format)				\
+static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf)		\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
+}									\
+static DEVICE_ATTR_RO(field);
+
+#define pcmcia_device_stringattr(name, field)					\
+static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf)		\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
+}									\
+static DEVICE_ATTR_RO(name);
+
+pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
+pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
+pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
+pcmcia_device_stringattr(prod_id1, prod_id[0]);
+pcmcia_device_stringattr(prod_id2, prod_id[1]);
+pcmcia_device_stringattr(prod_id3, prod_id[2]);
+pcmcia_device_stringattr(prod_id4, prod_id[3]);
+
+static ssize_t function_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
+}
+static DEVICE_ATTR_RO(function);
+
+static ssize_t resources_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	char *str = buf;
+	int i;
+
+	for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
+		str += sprintf(str, "%pr\n", p_dev->resource[i]);
+
+	return str - buf;
+}
+static DEVICE_ATTR_RO(resources);
+
+static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+	if (p_dev->suspended)
+		return sprintf(buf, "off\n");
+	else
+		return sprintf(buf, "on\n");
+}
+
+static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	int ret = 0;
+
+	if (!count)
+		return -EINVAL;
+
+	if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
+		ret = runtime_suspend(dev);
+	else if (p_dev->suspended && !strncmp(buf, "on", 2))
+		ret = runtime_resume(dev);
+
+	return ret ? ret : count;
+}
+static DEVICE_ATTR_RW(pm_state);
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	int i;
+	u32 hash[4] = { 0, 0, 0, 0};
+
+	/* calculate hashes */
+	for (i = 0; i < 4; i++) {
+		if (!p_dev->prod_id[i])
+			continue;
+		hash[i] = crc32(0, p_dev->prod_id[i],
+				strlen(p_dev->prod_id[i]));
+	}
+	return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+				"pa%08Xpb%08Xpc%08Xpd%08X\n",
+				p_dev->has_manf_id ? p_dev->manf_id : 0,
+				p_dev->has_card_id ? p_dev->card_id : 0,
+				p_dev->has_func_id ? p_dev->func_id : 0,
+				p_dev->func, p_dev->device_no,
+				hash[0], hash[1], hash[2], hash[3]);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static ssize_t allow_func_id_match_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	mutex_lock(&p_dev->socket->ops_mutex);
+	p_dev->allow_func_id_match = 1;
+	mutex_unlock(&p_dev->socket->ops_mutex);
+	pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
+
+	return count;
+}
+static DEVICE_ATTR_WO(allow_func_id_match);
+
+static struct attribute *pcmcia_dev_attrs[] = {
+	&dev_attr_resources.attr,
+	&dev_attr_pm_state.attr,
+	&dev_attr_function.attr,
+	&dev_attr_func_id.attr,
+	&dev_attr_manf_id.attr,
+	&dev_attr_card_id.attr,
+	&dev_attr_prod_id1.attr,
+	&dev_attr_prod_id2.attr,
+	&dev_attr_prod_id3.attr,
+	&dev_attr_prod_id4.attr,
+	&dev_attr_modalias.attr,
+	&dev_attr_allow_func_id_match.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(pcmcia_dev);
+
+/* PM support, also needed for reset */
+
+static int pcmcia_dev_suspend(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv = NULL;
+	int ret = 0;
+
+	mutex_lock(&p_dev->socket->ops_mutex);
+	if (p_dev->suspended) {
+		mutex_unlock(&p_dev->socket->ops_mutex);
+		return 0;
+	}
+	p_dev->suspended = 1;
+	mutex_unlock(&p_dev->socket->ops_mutex);
+
+	dev_dbg(dev, "suspending\n");
+
+	if (dev->driver)
+		p_drv = to_pcmcia_drv(dev->driver);
+
+	if (!p_drv)
+		goto out;
+
+	if (p_drv->suspend) {
+		ret = p_drv->suspend(p_dev);
+		if (ret) {
+			dev_err(dev,
+				"pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
+				p_dev->devname, p_drv->name, ret);
+			mutex_lock(&p_dev->socket->ops_mutex);
+			p_dev->suspended = 0;
+			mutex_unlock(&p_dev->socket->ops_mutex);
+			goto out;
+		}
+	}
+
+	if (p_dev->device_no == p_dev->func) {
+		dev_dbg(dev, "releasing configuration\n");
+		pcmcia_release_configuration(p_dev);
+	}
+
+ out:
+	return ret;
+}
+
+
+static int pcmcia_dev_resume(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv = NULL;
+	int ret = 0;
+
+	mutex_lock(&p_dev->socket->ops_mutex);
+	if (!p_dev->suspended) {
+		mutex_unlock(&p_dev->socket->ops_mutex);
+		return 0;
+	}
+	p_dev->suspended = 0;
+	mutex_unlock(&p_dev->socket->ops_mutex);
+
+	dev_dbg(dev, "resuming\n");
+
+	if (dev->driver)
+		p_drv = to_pcmcia_drv(dev->driver);
+
+	if (!p_drv)
+		goto out;
+
+	if (p_dev->device_no == p_dev->func) {
+		dev_dbg(dev, "requesting configuration\n");
+		ret = pcmcia_enable_device(p_dev);
+		if (ret)
+			goto out;
+	}
+
+	if (p_drv->resume)
+		ret = p_drv->resume(p_dev);
+
+ out:
+	return ret;
+}
+
+
+static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
+{
+	struct pcmcia_socket *skt = _data;
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+	if (p_dev->socket != skt || p_dev->suspended)
+		return 0;
+
+	return runtime_suspend(dev);
+}
+
+static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
+{
+	struct pcmcia_socket *skt = _data;
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+	if (p_dev->socket != skt || !p_dev->suspended)
+		return 0;
+
+	runtime_resume(dev);
+
+	return 0;
+}
+
+static int pcmcia_bus_resume(struct pcmcia_socket *skt)
+{
+	dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
+	bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
+	return 0;
+}
+
+static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
+{
+	dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
+	if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
+			     pcmcia_bus_suspend_callback)) {
+		pcmcia_bus_resume(skt);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int pcmcia_bus_remove(struct pcmcia_socket *skt)
+{
+	atomic_set(&skt->present, 0);
+	pcmcia_card_remove(skt, NULL);
+
+	mutex_lock(&skt->ops_mutex);
+	destroy_cis_cache(skt);
+	pcmcia_cleanup_irq(skt);
+	mutex_unlock(&skt->ops_mutex);
+
+	return 0;
+}
+
+static int pcmcia_bus_add(struct pcmcia_socket *skt)
+{
+	atomic_set(&skt->present, 1);
+
+	mutex_lock(&skt->ops_mutex);
+	skt->pcmcia_pfc = 0;
+	destroy_cis_cache(skt); /* to be on the safe side... */
+	mutex_unlock(&skt->ops_mutex);
+
+	pcmcia_card_add(skt);
+
+	return 0;
+}
+
+static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
+{
+	if (!verify_cis_cache(skt))
+		return 0;
+
+	dev_dbg(&skt->dev, "cis mismatch - different card\n");
+
+	/* first, remove the card */
+	pcmcia_bus_remove(skt);
+
+	mutex_lock(&skt->ops_mutex);
+	destroy_cis_cache(skt);
+	kfree(skt->fake_cis);
+	skt->fake_cis = NULL;
+	skt->functions = 0;
+	mutex_unlock(&skt->ops_mutex);
+
+	/* now, add the new card */
+	pcmcia_bus_add(skt);
+	return 0;
+}
+
+
+/*
+ * NOTE: This is racy. There's no guarantee the card will still be
+ * physically present, even if the call to this function returns
+ * non-NULL. Furthermore, the device driver most likely is unbound
+ * almost immediately, so the timeframe where pcmcia_dev_present
+ * returns NULL is probably really really small.
+ */
+struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_device *ret = NULL;
+
+	p_dev = pcmcia_get_dev(_p_dev);
+	if (!p_dev)
+		return NULL;
+
+	if (atomic_read(&p_dev->socket->present) != 0)
+		ret = p_dev;
+
+	pcmcia_put_dev(p_dev);
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_dev_present);
+
+
+static struct pcmcia_callback pcmcia_bus_callback = {
+	.owner = THIS_MODULE,
+	.add = pcmcia_bus_add,
+	.remove = pcmcia_bus_remove,
+	.requery = pcmcia_requery,
+	.validate = pccard_validate_cis,
+	.suspend = pcmcia_bus_suspend,
+	.early_resume = pcmcia_bus_early_resume,
+	.resume = pcmcia_bus_resume,
+};
+
+static int pcmcia_bus_add_socket(struct device *dev,
+					   struct class_interface *class_intf)
+{
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
+	int ret;
+
+	socket = pcmcia_get_socket(socket);
+	if (!socket) {
+		dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
+		return -ENODEV;
+	}
+
+	ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
+	if (ret) {
+		dev_err(dev, "PCMCIA registration failed\n");
+		pcmcia_put_socket(socket);
+		return ret;
+	}
+
+	INIT_LIST_HEAD(&socket->devices_list);
+	socket->pcmcia_pfc = 0;
+	socket->device_count = 0;
+	atomic_set(&socket->present, 0);
+
+	ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
+	if (ret) {
+		dev_err(dev, "PCMCIA registration failed\n");
+		pcmcia_put_socket(socket);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void pcmcia_bus_remove_socket(struct device *dev,
+				     struct class_interface *class_intf)
+{
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
+
+	if (!socket)
+		return;
+
+	pccard_register_pcmcia(socket, NULL);
+
+	/* unregister any unbound devices */
+	mutex_lock(&socket->skt_mutex);
+	pcmcia_card_remove(socket, NULL);
+	release_cis_mem(socket);
+	mutex_unlock(&socket->skt_mutex);
+
+	sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
+
+	pcmcia_put_socket(socket);
+
+	return;
+}
+
+
+/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
+static struct class_interface pcmcia_bus_interface __refdata = {
+	.class = &pcmcia_socket_class,
+	.add_dev = &pcmcia_bus_add_socket,
+	.remove_dev = &pcmcia_bus_remove_socket,
+};
+
+static const struct dev_pm_ops pcmcia_bus_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
+};
+
+struct bus_type pcmcia_bus_type = {
+	.name = "pcmcia",
+	.uevent = pcmcia_bus_uevent,
+	.match = pcmcia_bus_match,
+	.dev_groups = pcmcia_dev_groups,
+	.probe = pcmcia_device_probe,
+	.remove = pcmcia_device_remove,
+	.pm = &pcmcia_bus_pm_ops,
+};
+
+
+static int __init init_pcmcia_bus(void)
+{
+	int ret;
+
+	ret = bus_register(&pcmcia_bus_type);
+	if (ret < 0) {
+		printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
+		return ret;
+	}
+	ret = class_interface_register(&pcmcia_bus_interface);
+	if (ret < 0) {
+		printk(KERN_WARNING
+			"pcmcia: class_interface_register error: %d\n", ret);
+		bus_unregister(&pcmcia_bus_type);
+		return ret;
+	}
+
+	return 0;
+}
+fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
+			       * pcmcia_socket_class is already registered */
+
+
+static void __exit exit_pcmcia_bus(void)
+{
+	class_interface_unregister(&pcmcia_bus_interface);
+
+	bus_unregister(&pcmcia_bus_type);
+}
+module_exit(exit_pcmcia_bus);
+
+
+MODULE_ALIAS("ds");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/electra_cf.c b/src/kernel/linux/v4.14/drivers/pcmcia/electra_cf.c
new file mode 100644
index 0000000..c6fe2a4
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/electra_cf.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/pcmcia/omap_cf.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include <pcmcia/ss.h>
+
+static const char driver_name[] = "electra-cf";
+
+struct electra_cf_socket {
+	struct pcmcia_socket	socket;
+
+	struct timer_list	timer;
+	unsigned		present:1;
+	unsigned		active:1;
+
+	struct platform_device	*ofdev;
+	unsigned long		mem_phys;
+	void __iomem		*mem_base;
+	unsigned long		mem_size;
+	void __iomem		*io_virt;
+	unsigned int		io_base;
+	unsigned int		io_size;
+	u_int			irq;
+	struct resource		iomem;
+	void __iomem		*gpio_base;
+	int			gpio_detect;
+	int			gpio_vsense;
+	int			gpio_3v;
+	int			gpio_5v;
+};
+
+#define	POLL_INTERVAL		(2 * HZ)
+
+
+static int electra_cf_present(struct electra_cf_socket *cf)
+{
+	unsigned int gpio;
+
+	gpio = in_le32(cf->gpio_base+0x40);
+	return !(gpio & (1 << cf->gpio_detect));
+}
+
+static int electra_cf_ss_init(struct pcmcia_socket *s)
+{
+	return 0;
+}
+
+/* the timer is primarily to kick this socket's pccardd */
+static void electra_cf_timer(unsigned long _cf)
+{
+	struct electra_cf_socket *cf = (void *) _cf;
+	int present = electra_cf_present(cf);
+
+	if (present != cf->present) {
+		cf->present = present;
+		pcmcia_parse_events(&cf->socket, SS_DETECT);
+	}
+
+	if (cf->active)
+		mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+}
+
+static irqreturn_t electra_cf_irq(int irq, void *_cf)
+{
+	electra_cf_timer((unsigned long)_cf);
+	return IRQ_HANDLED;
+}
+
+static int electra_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+	struct electra_cf_socket *cf;
+
+	if (!sp)
+		return -EINVAL;
+
+	cf = container_of(s, struct electra_cf_socket, socket);
+
+	/* NOTE CF is always 3VCARD */
+	if (electra_cf_present(cf)) {
+		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+
+		s->pci_irq = cf->irq;
+	} else
+		*sp = 0;
+	return 0;
+}
+
+static int electra_cf_set_socket(struct pcmcia_socket *sock,
+				 struct socket_state_t *s)
+{
+	unsigned int gpio;
+	unsigned int vcc;
+	struct electra_cf_socket *cf;
+
+	cf = container_of(sock, struct electra_cf_socket, socket);
+
+	/* "reset" means no power in our case */
+	vcc = (s->flags & SS_RESET) ? 0 : s->Vcc;
+
+	switch (vcc) {
+	case 0:
+		gpio = 0;
+		break;
+	case 33:
+		gpio = (1 << cf->gpio_3v);
+		break;
+	case 5:
+		gpio = (1 << cf->gpio_5v);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	gpio |= 1 << (cf->gpio_3v + 16); /* enwr */
+	gpio |= 1 << (cf->gpio_5v + 16); /* enwr */
+	out_le32(cf->gpio_base+0x90, gpio);
+
+	pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
+		driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+	return 0;
+}
+
+static int electra_cf_set_io_map(struct pcmcia_socket *s,
+				 struct pccard_io_map *io)
+{
+	return 0;
+}
+
+static int electra_cf_set_mem_map(struct pcmcia_socket *s,
+				  struct pccard_mem_map *map)
+{
+	struct electra_cf_socket *cf;
+
+	if (map->card_start)
+		return -EINVAL;
+	cf = container_of(s, struct electra_cf_socket, socket);
+	map->static_start = cf->mem_phys;
+	map->flags &= MAP_ACTIVE|MAP_ATTRIB;
+	if (!(map->flags & MAP_ATTRIB))
+		map->static_start += 0x800;
+	return 0;
+}
+
+static struct pccard_operations electra_cf_ops = {
+	.init			= electra_cf_ss_init,
+	.get_status		= electra_cf_get_status,
+	.set_socket		= electra_cf_set_socket,
+	.set_io_map		= electra_cf_set_io_map,
+	.set_mem_map		= electra_cf_set_mem_map,
+};
+
+static int electra_cf_probe(struct platform_device *ofdev)
+{
+	struct device *device = &ofdev->dev;
+	struct device_node *np = ofdev->dev.of_node;
+	struct electra_cf_socket   *cf;
+	struct resource mem, io;
+	int status;
+	const unsigned int *prop;
+	int err;
+	struct vm_struct *area;
+
+	err = of_address_to_resource(np, 0, &mem);
+	if (err)
+		return -EINVAL;
+
+	err = of_address_to_resource(np, 1, &io);
+	if (err)
+		return -EINVAL;
+
+	cf = kzalloc(sizeof(*cf), GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+
+	setup_timer(&cf->timer, electra_cf_timer, (unsigned long)cf);
+	cf->irq = 0;
+
+	cf->ofdev = ofdev;
+	cf->mem_phys = mem.start;
+	cf->mem_size = PAGE_ALIGN(resource_size(&mem));
+	cf->mem_base = ioremap(cf->mem_phys, cf->mem_size);
+	cf->io_size = PAGE_ALIGN(resource_size(&io));
+
+	area = __get_vm_area(cf->io_size, 0, PHB_IO_BASE, PHB_IO_END);
+	if (area == NULL) {
+		status = -ENOMEM;
+		goto fail1;
+	}
+
+	cf->io_virt = (void __iomem *)(area->addr);
+
+	cf->gpio_base = ioremap(0xfc103000, 0x1000);
+	dev_set_drvdata(device, cf);
+
+	if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
+	    (__ioremap_at(io.start, cf->io_virt, cf->io_size,
+		  pgprot_val(pgprot_noncached(__pgprot(0)))) == NULL)) {
+		dev_err(device, "can't ioremap ranges\n");
+		status = -ENOMEM;
+		goto fail1;
+	}
+
+
+	cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
+
+	cf->iomem.start = (unsigned long)cf->mem_base;
+	cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start);
+	cf->iomem.flags = IORESOURCE_MEM;
+
+	cf->irq = irq_of_parse_and_map(np, 0);
+
+	status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED,
+			     driver_name, cf);
+	if (status < 0) {
+		dev_err(device, "request_irq failed\n");
+		goto fail1;
+	}
+
+	cf->socket.pci_irq = cf->irq;
+
+	prop = of_get_property(np, "card-detect-gpio", NULL);
+	if (!prop)
+		goto fail1;
+	cf->gpio_detect = *prop;
+
+	prop = of_get_property(np, "card-vsense-gpio", NULL);
+	if (!prop)
+		goto fail1;
+	cf->gpio_vsense = *prop;
+
+	prop = of_get_property(np, "card-3v-gpio", NULL);
+	if (!prop)
+		goto fail1;
+	cf->gpio_3v = *prop;
+
+	prop = of_get_property(np, "card-5v-gpio", NULL);
+	if (!prop)
+		goto fail1;
+	cf->gpio_5v = *prop;
+
+	cf->socket.io_offset = cf->io_base;
+
+	/* reserve chip-select regions */
+	if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) {
+		status = -ENXIO;
+		dev_err(device, "Can't claim memory region\n");
+		goto fail1;
+	}
+
+	if (!request_region(cf->io_base, cf->io_size, driver_name)) {
+		status = -ENXIO;
+		dev_err(device, "Can't claim I/O region\n");
+		goto fail2;
+	}
+
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.dev.parent = &ofdev->dev;
+	cf->socket.ops = &electra_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
+				SS_CAP_MEM_ALIGN;
+	cf->socket.map_size = 0x800;
+
+	status = pcmcia_register_socket(&cf->socket);
+	if (status < 0) {
+		dev_err(device, "pcmcia_register_socket failed\n");
+		goto fail3;
+	}
+
+	dev_info(device, "at mem 0x%lx io 0x%llx irq %d\n",
+		 cf->mem_phys, io.start, cf->irq);
+
+	cf->active = 1;
+	electra_cf_timer((unsigned long)cf);
+	return 0;
+
+fail3:
+	release_region(cf->io_base, cf->io_size);
+fail2:
+	release_mem_region(cf->mem_phys, cf->mem_size);
+fail1:
+	if (cf->irq)
+		free_irq(cf->irq, cf);
+
+	if (cf->io_virt)
+		__iounmap_at(cf->io_virt, cf->io_size);
+	if (cf->mem_base)
+		iounmap(cf->mem_base);
+	if (cf->gpio_base)
+		iounmap(cf->gpio_base);
+	if (area)
+		device_init_wakeup(&ofdev->dev, 0);
+	kfree(cf);
+	return status;
+
+}
+
+static int electra_cf_remove(struct platform_device *ofdev)
+{
+	struct device *device = &ofdev->dev;
+	struct electra_cf_socket *cf;
+
+	cf = dev_get_drvdata(device);
+
+	cf->active = 0;
+	pcmcia_unregister_socket(&cf->socket);
+	free_irq(cf->irq, cf);
+	del_timer_sync(&cf->timer);
+
+	__iounmap_at(cf->io_virt, cf->io_size);
+	iounmap(cf->mem_base);
+	iounmap(cf->gpio_base);
+	release_mem_region(cf->mem_phys, cf->mem_size);
+	release_region(cf->io_base, cf->io_size);
+
+	kfree(cf);
+
+	return 0;
+}
+
+static const struct of_device_id electra_cf_match[] = {
+	{
+		.compatible   = "electra-cf",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, electra_cf_match);
+
+static struct platform_driver electra_cf_driver = {
+	.driver = {
+		.name = driver_name,
+		.of_match_table = electra_cf_match,
+	},
+	.probe	  = electra_cf_probe,
+	.remove   = electra_cf_remove,
+};
+
+module_platform_driver(electra_cf_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi Electra CF driver");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/i82092.c b/src/kernel/linux/v4.14/drivers/pcmcia/i82092.c
new file mode 100644
index 0000000..aae7e6d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/i82092.c
@@ -0,0 +1,704 @@
+/* 
+ * Driver for Intel I82092AA PCI-PCMCIA bridge.
+ *
+ * (C) 2001 Red Hat, Inc.
+ *
+ * Author: Arjan Van De Ven <arjanv@redhat.com>
+ * Loosly based on i82365.c from the pcmcia-cs package
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/io.h>
+
+#include "i82092aa.h"
+#include "i82365.h"
+
+MODULE_LICENSE("GPL");
+
+/* PCI core routines */
+static const struct pci_device_id i82092aa_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
+
+static struct pci_driver i82092aa_pci_driver = {
+	.name           = "i82092aa",
+	.id_table       = i82092aa_pci_ids,
+	.probe          = i82092aa_pci_probe,
+	.remove         = i82092aa_pci_remove,
+};
+
+
+/* the pccard structure and its functions */
+static struct pccard_operations i82092aa_operations = {
+	.init 		 	= i82092aa_init,
+	.get_status		= i82092aa_get_status,
+	.set_socket		= i82092aa_set_socket,
+	.set_io_map		= i82092aa_set_io_map,
+	.set_mem_map		= i82092aa_set_mem_map,
+};
+
+/* The card can do up to 4 sockets, allocate a structure for each of them */
+
+struct socket_info {
+	int	number;
+	int	card_state; 	/*  0 = no socket,
+				    1 = empty socket, 
+				    2 = card but not initialized,
+				    3 = operational card */
+	unsigned int io_base; 	/* base io address of the socket */
+	
+	struct pcmcia_socket socket;
+	struct pci_dev *dev;	/* The PCI device for the socket */
+};
+
+#define MAX_SOCKETS 4
+static struct socket_info sockets[MAX_SOCKETS];
+static int socket_count;  /* shortcut */                                  	                                	
+
+
+static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned char configbyte;
+	int i, ret;
+	
+	enter("i82092aa_pci_probe");
+	
+	if ((ret = pci_enable_device(dev)))
+		return ret;
+		
+	pci_read_config_byte(dev, 0x40, &configbyte);  /* PCI Configuration Control */
+	switch(configbyte&6) {
+		case 0:
+			socket_count = 2;
+			break;
+		case 2:
+			socket_count = 1;
+			break;
+		case 4:
+		case 6:
+			socket_count = 4;
+			break;
+			
+		default:
+			printk(KERN_ERR "i82092aa: Oops, you did something we didn't think of.\n");
+			ret = -EIO;
+			goto err_out_disable;
+	}
+	printk(KERN_INFO "i82092aa: configured as a %d socket device.\n", socket_count);
+
+	if (!request_region(pci_resource_start(dev, 0), 2, "i82092aa")) {
+		ret = -EBUSY;
+		goto err_out_disable;
+	}
+	
+	for (i = 0;i<socket_count;i++) {
+		sockets[i].card_state = 1; /* 1 = present but empty */
+		sockets[i].io_base = pci_resource_start(dev, 0);
+		sockets[i].socket.features |= SS_CAP_PCCARD;
+		sockets[i].socket.map_size = 0x1000;
+		sockets[i].socket.irq_mask = 0;
+		sockets[i].socket.pci_irq  = dev->irq;
+		sockets[i].socket.cb_dev  = dev;
+		sockets[i].socket.owner = THIS_MODULE;
+
+		sockets[i].number = i;
+		
+		if (card_present(i)) {
+			sockets[i].card_state = 3;
+			dprintk(KERN_DEBUG "i82092aa: slot %i is occupied\n",i);
+		} else {
+			dprintk(KERN_DEBUG "i82092aa: slot %i is vacant\n",i);
+		}
+	}
+		
+	/* Now, specifiy that all interrupts are to be done as PCI interrupts */
+	configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */
+	pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */
+
+	/* Register the interrupt handler */
+	dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq);
+	if ((ret = request_irq(dev->irq, i82092aa_interrupt, IRQF_SHARED, "i82092aa", i82092aa_interrupt))) {
+		printk(KERN_ERR "i82092aa: Failed to register IRQ %d, aborting\n", dev->irq);
+		goto err_out_free_res;
+	}
+
+	for (i = 0; i<socket_count; i++) {
+		sockets[i].socket.dev.parent = &dev->dev;
+		sockets[i].socket.ops = &i82092aa_operations;
+		sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
+		ret = pcmcia_register_socket(&sockets[i].socket);
+		if (ret) {
+			goto err_out_free_sockets;
+		}
+	}
+
+	leave("i82092aa_pci_probe");
+	return 0;
+
+err_out_free_sockets:
+	if (i) {
+		for (i--;i>=0;i--) {
+			pcmcia_unregister_socket(&sockets[i].socket);
+		}
+	}
+	free_irq(dev->irq, i82092aa_interrupt);
+err_out_free_res:
+	release_region(pci_resource_start(dev, 0), 2);
+err_out_disable:
+	pci_disable_device(dev);
+	return ret;			
+}
+
+static void i82092aa_pci_remove(struct pci_dev *dev)
+{
+	int i;
+
+	enter("i82092aa_pci_remove");
+	
+	free_irq(dev->irq, i82092aa_interrupt);
+
+	for (i = 0; i < socket_count; i++)
+		pcmcia_unregister_socket(&sockets[i].socket);
+
+	leave("i82092aa_pci_remove");
+}
+
+static DEFINE_SPINLOCK(port_lock);
+
+/* basic value read/write functions */
+
+static unsigned char indirect_read(int socket, unsigned short reg)
+{
+	unsigned short int port;
+	unsigned char val;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg += socket * 0x40;
+	port = sockets[socket].io_base;
+	outb(reg,port);
+	val = inb(port+1);
+	spin_unlock_irqrestore(&port_lock,flags);
+	return val;
+}
+
+#if 0
+static unsigned short indirect_read16(int socket, unsigned short reg)
+{
+	unsigned short int port;
+	unsigned short tmp;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg  = reg + socket * 0x40;
+	port = sockets[socket].io_base;
+	outb(reg,port);
+	tmp = inb(port+1);
+	reg++;
+	outb(reg,port);
+	tmp = tmp | (inb(port+1)<<8);
+	spin_unlock_irqrestore(&port_lock,flags);
+	return tmp;
+}
+#endif
+
+static void indirect_write(int socket, unsigned short reg, unsigned char value)
+{
+	unsigned short int port;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg = reg + socket * 0x40;
+	port = sockets[socket].io_base; 
+	outb(reg,port);
+	outb(value,port+1);
+	spin_unlock_irqrestore(&port_lock,flags);
+}
+
+static void indirect_setbit(int socket, unsigned short reg, unsigned char mask)
+{
+	unsigned short int port;
+	unsigned char val;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg = reg + socket * 0x40;
+	port = sockets[socket].io_base; 
+	outb(reg,port);
+	val = inb(port+1);
+	val |= mask;
+	outb(reg,port);
+	outb(val,port+1);
+	spin_unlock_irqrestore(&port_lock,flags);
+}
+
+
+static void indirect_resetbit(int socket, unsigned short reg, unsigned char mask)
+{
+	unsigned short int port;
+	unsigned char val;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg = reg + socket * 0x40;
+	port = sockets[socket].io_base; 
+	outb(reg,port);
+	val = inb(port+1);
+	val &= ~mask;
+	outb(reg,port);
+	outb(val,port+1);
+	spin_unlock_irqrestore(&port_lock,flags);
+}
+
+static void indirect_write16(int socket, unsigned short reg, unsigned short value)
+{
+	unsigned short int port;
+	unsigned char val;
+	unsigned long flags;
+	spin_lock_irqsave(&port_lock,flags);
+	reg = reg + socket * 0x40;
+	port = sockets[socket].io_base; 
+	
+	outb(reg,port);
+	val = value & 255;
+	outb(val,port+1);
+	
+	reg++;
+	
+	outb(reg,port);
+	val = value>>8;
+	outb(val,port+1);
+	spin_unlock_irqrestore(&port_lock,flags);
+}
+
+/* simple helper functions */
+/* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
+static int cycle_time = 120;
+
+static int to_cycles(int ns)
+{
+	if (cycle_time!=0)
+		return ns/cycle_time;
+	else
+		return 0;
+}
+    
+
+/* Interrupt handler functionality */
+
+static irqreturn_t i82092aa_interrupt(int irq, void *dev)
+{
+	int i;
+	int loopcount = 0;
+	int handled = 0;
+
+	unsigned int events, active=0;
+	
+/*	enter("i82092aa_interrupt");*/
+	
+	while (1) {
+		loopcount++;
+		if (loopcount>20) {
+			printk(KERN_ERR "i82092aa: infinite eventloop in interrupt \n");
+			break;
+		}
+		
+		active = 0;
+		
+		for (i=0;i<socket_count;i++) {
+			int csc;
+			if (sockets[i].card_state==0) /* Inactive socket, should not happen */
+				continue;
+			
+			csc = indirect_read(i,I365_CSC); /* card status change register */
+			
+			if (csc==0)  /* no events on this socket */
+			   	continue;
+			handled = 1;
+			events = 0;
+			 
+			if (csc & I365_CSC_DETECT) {
+				events |= SS_DETECT;
+				printk("Card detected in socket %i!\n",i);
+			 }
+			
+			if (indirect_read(i,I365_INTCTL) & I365_PC_IOCARD) { 
+				/* For IO/CARDS, bit 0 means "read the card" */
+				events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; 
+			} else {
+				/* Check for battery/ready events */
+				events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+				events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+				events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+			}
+			
+			if (events) {
+				pcmcia_parse_events(&sockets[i].socket, events);
+			}
+			active |= events;
+		}
+				
+		if (active==0) /* no more events to handle */
+			break;				
+		
+	}
+	return IRQ_RETVAL(handled);
+/*	leave("i82092aa_interrupt");*/
+}
+
+
+
+/* socket functions */
+
+static int card_present(int socketno)
+{	
+	unsigned int val;
+	enter("card_present");
+	
+	if ((socketno<0) || (socketno >= MAX_SOCKETS))
+		return 0;
+	if (sockets[socketno].io_base == 0)
+		return 0;
+
+		
+	val = indirect_read(socketno, 1); /* Interface status register */
+	if ((val&12)==12) {
+		leave("card_present 1");
+		return 1;
+	}
+		
+	leave("card_present 0");
+	return 0;
+}
+
+static void set_bridge_state(int sock)
+{
+	enter("set_bridge_state");
+	indirect_write(sock, I365_GBLCTL,0x00);
+	indirect_write(sock, I365_GENCTL,0x00);
+	
+	indirect_setbit(sock, I365_INTCTL,0x08);
+	leave("set_bridge_state");
+}
+
+
+
+
+
+      
+static int i82092aa_init(struct pcmcia_socket *sock)
+{
+	int i;
+	struct resource res = { .start = 0, .end = 0x0fff };
+        pccard_io_map io = { 0, 0, 0, 0, 1 };
+	pccard_mem_map mem = { .res = &res, };
+        
+        enter("i82092aa_init");
+                        
+        for (i = 0; i < 2; i++) {
+        	io.map = i;
+                i82092aa_set_io_map(sock, &io);
+	}
+        for (i = 0; i < 5; i++) {
+        	mem.map = i;
+                i82092aa_set_mem_map(sock, &mem);
+	}
+	
+	leave("i82092aa_init");
+	return 0;
+}
+                                                                                                                                                                                                                                              
+static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value)
+{
+	unsigned int sock = container_of(socket, struct socket_info, socket)->number;
+	unsigned int status;
+	
+	enter("i82092aa_get_status");
+	
+	status = indirect_read(sock,I365_STATUS); /* Interface Status Register */
+	*value = 0;
+	
+	if ((status & I365_CS_DETECT) == I365_CS_DETECT) {
+		*value |= SS_DETECT;
+	}
+		
+	/* IO cards have a different meaning of bits 0,1 */
+	/* Also notice the inverse-logic on the bits */
+	 if (indirect_read(sock, I365_INTCTL) & I365_PC_IOCARD)	{
+	 	/* IO card */
+	 	if (!(status & I365_CS_STSCHG))
+	 		*value |= SS_STSCHG;
+	 } else { /* non I/O card */
+	 	if (!(status & I365_CS_BVD1))
+	 		*value |= SS_BATDEAD;
+	 	if (!(status & I365_CS_BVD2))
+	 		*value |= SS_BATWARN;
+	 		
+	 }
+	 
+	 if (status & I365_CS_WRPROT)
+	 	(*value) |= SS_WRPROT;	/* card is write protected */
+	 
+	 if (status & I365_CS_READY)
+	 	(*value) |= SS_READY;    /* card is not busy */
+	 	
+	 if (status & I365_CS_POWERON)
+	 	(*value) |= SS_POWERON;  /* power is applied to the card */
+
+
+	leave("i82092aa_get_status");
+	return 0;
+}
+
+
+static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state) 
+{
+	unsigned int sock = container_of(socket, struct socket_info, socket)->number;
+	unsigned char reg;
+	
+	enter("i82092aa_set_socket");
+	
+	/* First, set the global controller options */
+	
+	set_bridge_state(sock);
+	
+	/* Values for the IGENC register */
+	
+	reg = 0;
+	if (!(state->flags & SS_RESET)) 	/* The reset bit has "inverse" logic */
+		reg = reg | I365_PC_RESET;  
+	if (state->flags & SS_IOCARD) 
+		reg = reg | I365_PC_IOCARD;
+		
+	indirect_write(sock,I365_INTCTL,reg); /* IGENC, Interrupt and General Control Register */
+	
+	/* Power registers */
+	
+	reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
+	
+	if (state->flags & SS_PWR_AUTO) {
+		printk("Auto power\n");
+		reg |= I365_PWR_AUTO;	/* automatic power mngmnt */
+	}
+	if (state->flags & SS_OUTPUT_ENA) {
+		printk("Power Enabled \n");
+		reg |= I365_PWR_OUT;	/* enable power */
+	}
+	
+	switch (state->Vcc) {
+		case 0:	
+			break;
+		case 50: 
+			printk("setting voltage to Vcc to 5V on socket %i\n",sock);
+			reg |= I365_VCC_5V;
+			break;
+		default:
+			printk("i82092aa: i82092aa_set_socket called with invalid VCC power value: %i ", state->Vcc);
+			leave("i82092aa_set_socket");
+			return -EINVAL;
+	}
+	
+	
+	switch (state->Vpp) {
+		case 0:	
+			printk("not setting Vpp on socket %i\n",sock);
+			break;
+		case 50: 
+			printk("setting Vpp to 5.0 for socket %i\n",sock);
+			reg |= I365_VPP1_5V | I365_VPP2_5V;
+			break;
+		case 120: 
+			printk("setting Vpp to 12.0\n");
+			reg |= I365_VPP1_12V | I365_VPP2_12V;
+			break;
+		default:
+			printk("i82092aa: i82092aa_set_socket called with invalid VPP power value: %i ", state->Vcc);
+			leave("i82092aa_set_socket");
+			return -EINVAL;
+	}
+	
+	if (reg != indirect_read(sock,I365_POWER)) /* only write if changed */
+		indirect_write(sock,I365_POWER,reg);
+		
+	/* Enable specific interrupt events */
+	
+	reg = 0x00;
+	if (state->csc_mask & SS_DETECT) {
+		reg |= I365_CSC_DETECT;
+	}
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG)
+			reg |= I365_CSC_STSCHG;
+	} else {
+		if (state->csc_mask & SS_BATDEAD) 
+			reg |= I365_CSC_BVD1;
+		if (state->csc_mask & SS_BATWARN) 
+			reg |= I365_CSC_BVD2;
+		if (state->csc_mask & SS_READY) 
+			reg |= I365_CSC_READY; 
+		                        
+	}
+	
+	/* now write the value and clear the (probably bogus) pending stuff by doing a dummy read*/
+	
+	indirect_write(sock,I365_CSCINT,reg);
+	(void)indirect_read(sock,I365_CSC);
+
+	leave("i82092aa_set_socket");
+	return 0;
+}
+
+static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(socket, struct socket_info, socket)->number;
+	unsigned char map, ioctl;
+	
+	enter("i82092aa_set_io_map");
+	
+	map = io->map;
+	
+	/* Check error conditions */	
+	if (map > 1) {
+		leave("i82092aa_set_io_map with invalid map");
+		return -EINVAL;
+	}
+	if ((io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)){
+		leave("i82092aa_set_io_map with invalid io");
+		return -EINVAL;
+	}
+
+	/* Turn off the window before changing anything */ 
+	if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+		indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_IO(map));
+
+/*	printk("set_io_map: Setting range to %x - %x \n",io->start,io->stop);  */
+	
+	/* write the new values */
+	indirect_write16(sock,I365_IO(map)+I365_W_START,io->start);            	
+	indirect_write16(sock,I365_IO(map)+I365_W_STOP,io->stop);            	
+	            	
+	ioctl = indirect_read(sock,I365_IOCTL) & ~I365_IOCTL_MASK(map);
+	
+	if (io->flags & (MAP_16BIT|MAP_AUTOSZ))
+		ioctl |= I365_IOCTL_16BIT(map);
+		
+	indirect_write(sock,I365_IOCTL,ioctl);
+	
+	/* Turn the window back on if needed */
+	if (io->flags & MAP_ACTIVE)
+		indirect_setbit(sock,I365_ADDRWIN,I365_ENA_IO(map));
+			
+	leave("i82092aa_set_io_map");	
+	return 0;
+}
+
+static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem)
+{
+	struct socket_info *sock_info = container_of(socket, struct socket_info, socket);
+	unsigned int sock = sock_info->number;
+	struct pci_bus_region region;
+	unsigned short base, i;
+	unsigned char map;
+	
+	enter("i82092aa_set_mem_map");
+
+	pcibios_resource_to_bus(sock_info->dev->bus, &region, mem->res);
+	
+	map = mem->map;
+	if (map > 4) {
+		leave("i82092aa_set_mem_map: invalid map");
+		return -EINVAL;
+	}
+	
+	
+	if ( (mem->card_start > 0x3ffffff) || (region.start > region.end) ||
+	     (mem->speed > 1000) ) {
+		leave("i82092aa_set_mem_map: invalid address / speed");
+		printk("invalid mem map for socket %i: %llx to %llx with a "
+			"start of %x\n",
+			sock,
+			(unsigned long long)region.start,
+			(unsigned long long)region.end,
+			mem->card_start);
+		return -EINVAL;
+	}
+	
+	/* Turn off the window before changing anything */
+	if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+	              indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+	                 
+	                 
+/* 	printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, region.start,region.end,sock,mem->speed,mem->flags & MAP_ACTIVE);  */
+
+	/* write the start address */
+	base = I365_MEM(map);
+	i = (region.start >> 12) & 0x0fff;
+	if (mem->flags & MAP_16BIT) 
+		i |= I365_MEM_16BIT;
+	if (mem->flags & MAP_0WS)
+		i |= I365_MEM_0WS;	
+	indirect_write16(sock,base+I365_W_START,i);
+		               
+	/* write the stop address */
+	
+	i= (region.end >> 12) & 0x0fff;
+	switch (to_cycles(mem->speed)) {
+		case 0:
+			break;
+		case 1:
+			i |= I365_MEM_WS0;
+			break;
+		case 2:
+			i |= I365_MEM_WS1;
+			break;
+		default:
+			i |= I365_MEM_WS1 | I365_MEM_WS0;
+			break;
+	}
+	
+	indirect_write16(sock,base+I365_W_STOP,i);
+	
+	/* card start */
+	
+	i = ((mem->card_start - region.start) >> 12) & 0x3fff;
+	if (mem->flags & MAP_WRPROT)
+		i |= I365_MEM_WRPROT;
+	if (mem->flags & MAP_ATTRIB) {
+/*		printk("requesting attribute memory for socket %i\n",sock);*/
+		i |= I365_MEM_REG;
+	} else {
+/*		printk("requesting normal memory for socket %i\n",sock);*/
+	}
+	indirect_write16(sock,base+I365_W_OFF,i);
+	
+	/* Enable the window if necessary */
+	if (mem->flags & MAP_ACTIVE)
+		indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+	            
+	leave("i82092aa_set_mem_map");
+	return 0;
+}
+
+static int i82092aa_module_init(void)
+{
+	return pci_register_driver(&i82092aa_pci_driver);
+}
+
+static void i82092aa_module_exit(void)
+{
+	enter("i82092aa_module_exit");
+	pci_unregister_driver(&i82092aa_pci_driver);
+	if (sockets[0].io_base>0)
+			 release_region(sockets[0].io_base, 2);
+	leave("i82092aa_module_exit");
+}
+
+module_init(i82092aa_module_init);
+module_exit(i82092aa_module_exit);
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/i82092aa.h b/src/kernel/linux/v4.14/drivers/pcmcia/i82092aa.h
new file mode 100644
index 0000000..fabe08c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/i82092aa.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _INCLUDE_GUARD_i82092aa_H_
+#define _INCLUDE_GUARD_i82092aa_H_
+
+#include <linux/interrupt.h>
+
+/* Debuging defines */
+#ifdef NOTRACE
+#define enter(x)   printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
+#define leave(x)   printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__)
+#define dprintk(fmt, args...) printk(fmt , ## args)
+#else
+#define enter(x)   do {} while (0)
+#define leave(x)   do {} while (0)
+#define dprintk(fmt, args...) do {} while (0)
+#endif
+
+
+
+/* prototypes */
+
+static int  i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void i82092aa_pci_remove(struct pci_dev *dev);
+static int card_present(int socketno);
+static irqreturn_t i82092aa_interrupt(int irq, void *dev);
+
+
+
+
+static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value);
+static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state);
+static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io);
+static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem);
+static int i82092aa_init(struct pcmcia_socket *socket);
+
+#endif
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/i82365.c b/src/kernel/linux/v4.14/drivers/pcmcia/i82365.c
new file mode 100644
index 0000000..fb38cc0
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/i82365.c
@@ -0,0 +1,1348 @@
+/*======================================================================
+
+    Device driver for Intel 82365 and compatible PC Card controllers.
+
+    i82365.c 1.265 1999/11/10 18:36:21
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+
+#include <linux/isapnp.h>
+
+/* ISA-bus controllers */
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "ricoh.h"
+
+
+static irqreturn_t i365_count_irq(int, void *);
+static inline int _check_irq(int irq, int flags)
+{
+    if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
+	return -1;
+    free_irq(irq, i365_count_irq);
+    return 0;
+}
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Default base address for i82365sl and other ISA chips */
+static unsigned long i365_base = 0x3e0;
+/* Should we probe at 0x3e2 for an extra ISA controller? */
+static int extra_sockets = 0;
+/* Specify a socket number to ignore */
+static int ignore = -1;
+/* Bit map or list of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16];
+static unsigned int irq_list_count;
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+/* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
+static int cycle_time = 120;
+
+/* Cirrus options */
+static int has_dma = -1;
+static int has_led = -1;
+static int has_ring = -1;
+static int dynamic_mode = 0;
+static int freq_bypass = -1;
+static int setup_time = -1;
+static int cmd_time = -1;
+static int recov_time = -1;
+
+/* Vadem options */
+static int async_clock = -1;
+static int cable_mode = -1;
+static int wakeup = 0;
+
+module_param_hw(i365_base, ulong, ioport, 0444);
+module_param(ignore, int, 0444);
+module_param(extra_sockets, int, 0444);
+module_param_hw(irq_mask, int, other, 0444);
+module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
+module_param_hw(cs_irq, int, irq, 0444);
+module_param(async_clock, int, 0444);
+module_param(cable_mode, int, 0444);
+module_param(wakeup, int, 0444);
+
+module_param(do_scan, int, 0444);
+module_param(poll_interval, int, 0444);
+module_param(cycle_time, int, 0444);
+module_param(has_dma, int, 0444);
+module_param(has_led, int, 0444);
+module_param(has_ring, int, 0444);
+module_param(dynamic_mode, int, 0444);
+module_param(freq_bypass, int, 0444);
+module_param(setup_time, int, 0444);
+module_param(cmd_time, int, 0444);
+module_param(recov_time, int, 0444);
+
+/*====================================================================*/
+
+struct cirrus_state {
+    u_char		misc1, misc2;
+    u_char		timer[6];
+};
+
+struct vg46x_state {
+    u_char		ctl, ema;
+};
+
+struct i82365_socket {
+    u_short		type, flags;
+    struct pcmcia_socket	socket;
+    unsigned int	number;
+    unsigned int	ioaddr;
+    u_short		psock;
+    u_char		cs_irq, intr;
+    union {
+	struct cirrus_state		cirrus;
+	struct vg46x_state		vg46x;
+    } state;
+};
+
+/* Where we keep track of our sockets... */
+static int sockets = 0;
+static struct i82365_socket socket[8] = {
+    { 0, }, /* ... */
+};
+
+/* Default ISA interrupt mask */
+#define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
+
+static int grab_irq;
+static DEFINE_SPINLOCK(isa_lock);
+#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
+#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
+
+static struct timer_list poll_timer;
+
+/*====================================================================*/
+
+/* These definitions must match the pcic table! */
+enum pcic_id {
+    IS_I82365A, IS_I82365B, IS_I82365DF,
+    IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
+    IS_PD6710, IS_PD672X, IS_VT83C469,
+};
+
+/* Flags for classifying groups of controllers */
+#define IS_VADEM	0x0001
+#define IS_CIRRUS	0x0002
+#define IS_VIA		0x0010
+#define IS_UNKNOWN	0x0400
+#define IS_VG_PWR	0x0800
+#define IS_DF_PWR	0x1000
+#define IS_REGISTERED	0x2000
+#define IS_ALIVE	0x8000
+
+struct pcic {
+    char		*name;
+    u_short		flags;
+};
+
+static struct pcic pcic[] = {
+    { "Intel i82365sl A step", 0 },
+    { "Intel i82365sl B step", 0 },
+    { "Intel i82365sl DF", IS_DF_PWR },
+    { "IBM Clone", 0 },
+    { "Ricoh RF5C296/396", 0 },
+    { "VLSI 82C146", 0 },
+    { "Vadem VG-468", IS_VADEM },
+    { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
+    { "Cirrus PD6710", IS_CIRRUS },
+    { "Cirrus PD672x", IS_CIRRUS },
+    { "VIA VT83C469", IS_CIRRUS|IS_VIA },
+};
+
+#define PCIC_COUNT	ARRAY_SIZE(pcic)
+
+/*====================================================================*/
+
+static DEFINE_SPINLOCK(bus_lock);
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&bus_lock,flags);
+    {
+	unsigned int port = socket[sock].ioaddr;
+	u_char val;
+	reg = I365_REG(socket[sock].psock, reg);
+	outb(reg, port); val = inb(port+1);
+	spin_unlock_irqrestore(&bus_lock,flags);
+	return val;
+    }
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&bus_lock,flags);
+    {
+	unsigned int port = socket[sock].ioaddr;
+	u_char val = I365_REG(socket[sock].psock, reg);
+	outb(val, port); outb(data, port+1);
+	spin_unlock_irqrestore(&bus_lock,flags);
+    }
+}
+
+static void i365_bset(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d |= mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bclr(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
+{
+    u_char d = i365_get(sock, reg);
+    if (b)
+	d |= mask;
+    else
+	d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static u_short i365_get_pair(u_short sock, u_short reg)
+{
+    u_short a, b;
+    a = i365_get(sock, reg);
+    b = i365_get(sock, reg+1);
+    return (a + (b<<8));
+}
+
+static void i365_set_pair(u_short sock, u_short reg, u_short data)
+{
+    i365_set(sock, reg, data & 0xff);
+    i365_set(sock, reg+1, data >> 8);
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Cirrus
+    PD67xx controllers, and to set and report global configuration
+    options.
+
+    The VIA controllers also use these routines, as they are mostly
+    Cirrus lookalikes, without the timing registers.
+    
+======================================================================*/
+
+#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+
+static void cirrus_get_state(u_short s)
+{
+    int i;
+    struct cirrus_state *p = &socket[s].state.cirrus;
+    p->misc1 = i365_get(s, PD67_MISC_CTL_1);
+    p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    p->misc2 = i365_get(s, PD67_MISC_CTL_2);
+    for (i = 0; i < 6; i++)
+	p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
+}
+
+static void cirrus_set_state(u_short s)
+{
+    int i;
+    u_char misc;
+    struct cirrus_state *p = &socket[s].state.cirrus;
+
+    misc = i365_get(s, PD67_MISC_CTL_2);
+    i365_set(s, PD67_MISC_CTL_2, p->misc2);
+    if (misc & PD67_MC2_SUSPEND) mdelay(50);
+    misc = i365_get(s, PD67_MISC_CTL_1);
+    misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
+    for (i = 0; i < 6; i++)
+	i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
+}
+
+static u_int __init cirrus_set_opts(u_short s, char *buf)
+{
+    struct i82365_socket *t = &socket[s];
+    struct cirrus_state *p = &socket[s].state.cirrus;
+    u_int mask = 0xffff;
+
+    if (has_ring == -1) has_ring = 1;
+    flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
+    flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
+    flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
+    if (p->misc2 & PD67_MC2_IRQ15_RI)
+	strcat(buf, " [ring]");
+    if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
+	strcat(buf, " [dyn mode]");
+    if (p->misc2 & PD67_MC2_FREQ_BYPASS)
+	strcat(buf, " [freq bypass]");
+    if (p->misc1 & PD67_MC1_INPACK_ENA)
+	strcat(buf, " [inpack]");
+    if (p->misc2 & PD67_MC2_IRQ15_RI)
+	mask &= ~0x8000;
+    if (has_led > 0) {
+	strcat(buf, " [led]");
+	mask &= ~0x1000;
+    }
+    if (has_dma > 0) {
+	strcat(buf, " [dma]");
+	mask &= ~0x0600;
+    }
+    if (!(t->flags & IS_VIA)) {
+	if (setup_time >= 0)
+	    p->timer[0] = p->timer[3] = setup_time;
+	if (cmd_time > 0) {
+	    p->timer[1] = cmd_time;
+	    p->timer[4] = cmd_time*2+4;
+	}
+	if (p->timer[1] == 0) {
+	    p->timer[1] = 6; p->timer[4] = 16;
+	    if (p->timer[0] == 0)
+		p->timer[0] = p->timer[3] = 1;
+	}
+	if (recov_time >= 0)
+	    p->timer[2] = p->timer[5] = recov_time;
+	buf += strlen(buf);
+	sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
+		p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
+    }
+    return mask;
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Vadem VG468
+    and VG469 controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+static void vg46x_get_state(u_short s)
+{
+    struct vg46x_state *p = &socket[s].state.vg46x;
+    p->ctl = i365_get(s, VG468_CTL);
+    if (socket[s].type == IS_VG469)
+	p->ema = i365_get(s, VG469_EXT_MODE);
+}
+
+static void vg46x_set_state(u_short s)
+{
+    struct vg46x_state *p = &socket[s].state.vg46x;
+    i365_set(s, VG468_CTL, p->ctl);
+    if (socket[s].type == IS_VG469)
+	i365_set(s, VG469_EXT_MODE, p->ema);
+}
+
+static u_int __init vg46x_set_opts(u_short s, char *buf)
+{
+    struct vg46x_state *p = &socket[s].state.vg46x;
+    
+    flip(p->ctl, VG468_CTL_ASYNC, async_clock);
+    flip(p->ema, VG469_MODE_CABLE, cable_mode);
+    if (p->ctl & VG468_CTL_ASYNC)
+	strcat(buf, " [async]");
+    if (p->ctl & VG468_CTL_INPACK)
+	strcat(buf, " [inpack]");
+    if (socket[s].type == IS_VG469) {
+	u_char vsel = i365_get(s, VG469_VSELECT);
+	if (vsel & VG469_VSEL_EXT_STAT) {
+	    strcat(buf, " [ext mode]");
+	    if (vsel & VG469_VSEL_EXT_BUS)
+		strcat(buf, " [isa buf]");
+	}
+	if (p->ema & VG469_MODE_CABLE)
+	    strcat(buf, " [cable]");
+	if (p->ema & VG469_MODE_COMPAT)
+	    strcat(buf, " [c step]");
+    }
+    return 0xffff;
+}
+
+/*======================================================================
+
+    Generic routines to get and set controller options
+    
+======================================================================*/
+
+static void get_bridge_state(u_short s)
+{
+    struct i82365_socket *t = &socket[s];
+    if (t->flags & IS_CIRRUS)
+	cirrus_get_state(s);
+    else if (t->flags & IS_VADEM)
+	vg46x_get_state(s);
+}
+
+static void set_bridge_state(u_short s)
+{
+    struct i82365_socket *t = &socket[s];
+    if (t->flags & IS_CIRRUS)
+	cirrus_set_state(s);
+    else {
+	i365_set(s, I365_GBLCTL, 0x00);
+	i365_set(s, I365_GENCTL, 0x00);
+    }
+    i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
+    if (t->flags & IS_VADEM)
+	vg46x_set_state(s);
+}
+
+static u_int __init set_bridge_opts(u_short s, u_short ns)
+{
+    u_short i;
+    u_int m = 0xffff;
+    char buf[128];
+
+    for (i = s; i < s+ns; i++) {
+	if (socket[i].flags & IS_ALIVE) {
+	    printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
+	    continue;
+	}
+	buf[0] = '\0';
+	get_bridge_state(i);
+	if (socket[i].flags & IS_CIRRUS)
+	    m = cirrus_set_opts(i, buf);
+	else if (socket[i].flags & IS_VADEM)
+	    m = vg46x_set_opts(i, buf);
+	set_bridge_state(i);
+	printk(KERN_INFO "    host opts [%d]:%s\n", i,
+	       (*buf) ? buf : " none");
+    }
+    return m;
+}
+
+/*======================================================================
+
+    Interrupt testing code, for ISA and PCI interrupts
+    
+======================================================================*/
+
+static volatile u_int irq_hits;
+static u_short irq_sock;
+
+static irqreturn_t i365_count_irq(int irq, void *dev)
+{
+    i365_get(irq_sock, I365_CSC);
+    irq_hits++;
+    pr_debug("i82365: -> hit on irq %d\n", irq);
+    return IRQ_HANDLED;
+}
+
+static u_int __init test_irq(u_short sock, int irq)
+{
+    pr_debug("i82365:  testing ISA irq %d\n", irq);
+    if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
+			i365_count_irq) != 0)
+	return 1;
+    irq_hits = 0; irq_sock = sock;
+    msleep(10);
+    if (irq_hits) {
+	free_irq(irq, i365_count_irq);
+	pr_debug("i82365:    spurious hit!\n");
+	return 1;
+    }
+
+    /* Generate one interrupt */
+    i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
+    i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
+    udelay(1000);
+
+    free_irq(irq, i365_count_irq);
+
+    /* mask all interrupts */
+    i365_set(sock, I365_CSCINT, 0);
+    pr_debug("i82365:    hits = %d\n", irq_hits);
+    
+    return (irq_hits != 1);
+}
+
+static u_int __init isa_scan(u_short sock, u_int mask0)
+{
+    u_int mask1 = 0;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
+#endif
+    
+    if (do_scan) {
+	set_bridge_state(sock);
+	i365_set(sock, I365_CSCINT, 0);
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
+		mask1 |= (1 << i);
+	for (i = 0; i < 16; i++)
+	    if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
+		mask1 ^= (1 << i);
+    }
+    
+    printk(KERN_INFO "    ISA irqs (");
+    if (mask1) {
+	printk("scanned");
+    } else {
+	/* Fallback: just find interrupts that aren't in use */
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
+		mask1 |= (1 << i);
+	printk("default");
+	/* If scan failed, default to polled status */
+	if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
+    }
+    printk(") = ");
+    
+    for (i = 0; i < 16; i++)
+	if (mask1 & (1<<i))
+	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    if (mask1 == 0) printk("none!");
+    
+    return mask1;
+}
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    return ns/cycle_time;
+}
+
+/*====================================================================*/
+
+static int __init identify(unsigned int port, u_short sock)
+{
+    u_char val;
+    int type = -1;
+
+    /* Use the next free entry in the socket table */
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = sock;
+    
+    /* Wake up a sleepy Cirrus controller */
+    if (wakeup) {
+	i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+	/* Pause at least 50 ms */
+	mdelay(50);
+    }
+    
+    if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
+	return -1;
+    switch (val) {
+    case 0x82:
+	type = IS_I82365A; break;
+    case 0x83:
+	type = IS_I82365B; break;
+    case 0x84:
+	type = IS_I82365DF; break;
+    case 0x88: case 0x89: case 0x8a:
+	type = IS_IBM; break;
+    }
+    
+    /* Check for Vadem VG-468 chips */
+    outb(0x0e, port);
+    outb(0x37, port);
+    i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+    val = i365_get(sockets, I365_IDENT);
+    if (val & I365_IDENT_VADEM) {
+	i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+    }
+
+    /* Check for Ricoh chips */
+    val = i365_get(sockets, RF5C_CHIP_ID);
+    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+	type = IS_RF5Cx96;
+    
+    /* Check for Cirrus CL-PD67xx chips */
+    i365_set(sockets, PD67_CHIP_INFO, 0);
+    val = i365_get(sockets, PD67_CHIP_INFO);
+    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	val = i365_get(sockets, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == 0) {
+	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+	    i365_set(sockets, PD67_EXT_INDEX, 0xe5);
+	    if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
+		type = IS_VT83C469;
+	}
+    }
+    return type;
+} /* identify */
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non PC Card) Linux driver.  We leave these alone.
+
+    We make an exception for cards that seem to be serial devices.
+    
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+    u_char stat;
+    unsigned int start, stop;
+    
+    stat = i365_get(sock, I365_STATUS);
+    start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
+    stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
+    if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
+	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
+	(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
+	((start & 0xfeef) != 0x02e8)) {
+	if (!request_region(start, stop-start+1, "i82365"))
+	    return 1;
+	release_region(start, stop-start+1);
+    }
+
+    return 0;
+}
+
+/*====================================================================*/
+
+static void __init add_socket(unsigned int port, int psock, int type)
+{
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = psock;
+    socket[sockets].type = type;
+    socket[sockets].flags = pcic[type].flags;
+    if (is_alive(sockets))
+	socket[sockets].flags |= IS_ALIVE;
+    sockets++;
+}
+
+static void __init add_pcic(int ns, int type)
+{
+    u_int mask = 0, i, base;
+    int isa_irq = 0;
+    struct i82365_socket *t = &socket[sockets-ns];
+
+    base = sockets-ns;
+    if (base == 0) printk("\n");
+    printk(KERN_INFO "  %s", pcic[type].name);
+    printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
+	       t->ioaddr, t->psock*0x40);
+    printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
+
+    /* Set host options, build basic interrupt mask */
+    if (irq_list_count == 0)
+	mask = irq_mask;
+    else
+	for (i = mask = 0; i < irq_list_count; i++)
+	    mask |= (1<<irq_list[i]);
+    mask &= I365_MASK & set_bridge_opts(base, ns);
+    /* Scan for ISA interrupts */
+    mask = isa_scan(base, mask);
+        
+    /* Poll if only two interrupts available */
+    if (!poll_interval) {
+	u_int tmp = (mask & 0xff20);
+	tmp = tmp & (tmp-1);
+	if ((tmp & (tmp-1)) == 0)
+	    poll_interval = HZ;
+    }
+    /* Only try an ISA cs_irq if this is the first controller */
+    if (!grab_irq && (cs_irq || !poll_interval)) {
+	/* Avoid irq 12 unless it is explicitly requested */
+	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+	for (cs_irq = 15; cs_irq > 0; cs_irq--)
+	    if ((cs_mask & (1 << cs_irq)) &&
+		(_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
+		break;
+	if (cs_irq) {
+	    grab_irq = 1;
+	    isa_irq = cs_irq;
+	    printk(" status change on irq %d\n", cs_irq);
+	}
+    }
+    
+    if (!isa_irq) {
+	if (poll_interval == 0)
+	    poll_interval = HZ;
+	printk(" polling interval = %d ms\n",
+	       poll_interval * 1000 / HZ);
+	
+    }
+    
+    /* Update socket interrupt information, capabilities */
+    for (i = 0; i < ns; i++) {
+	t[i].socket.features |= SS_CAP_PCCARD;
+	t[i].socket.map_size = 0x1000;
+	t[i].socket.irq_mask = mask;
+	t[i].cs_irq = isa_irq;
+    }
+
+} /* add_pcic */
+
+/*====================================================================*/
+
+#ifdef CONFIG_PNP
+static struct isapnp_device_id id_table[] __initdata = {
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
+	{	0 }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+static struct pnp_dev *i82365_pnpdev;
+#endif
+
+static void __init isa_probe(void)
+{
+    int i, j, sock, k, ns, id;
+    unsigned int port;
+#ifdef CONFIG_PNP
+    struct isapnp_device_id *devid;
+    struct pnp_dev *dev;
+
+    for (devid = id_table; devid->vendor; devid++) {
+	if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
+	
+	    if (pnp_device_attach(dev) < 0)
+	    	continue;
+
+	    if (pnp_activate_dev(dev) < 0) {
+		printk("activate failed\n");
+		pnp_device_detach(dev);
+		break;
+	    }
+
+	    if (!pnp_port_valid(dev, 0)) {
+		printk("invalid resources ?\n");
+		pnp_device_detach(dev);
+		break;
+	    }
+	    i365_base = pnp_port_start(dev, 0);
+	    i82365_pnpdev = dev;
+	    break;
+	}
+    }
+#endif
+
+    if (!request_region(i365_base, 2, "i82365")) {
+	if (sockets == 0)
+	    printk("port conflict at %#lx\n", i365_base);
+	return;
+    }
+
+    id = identify(i365_base, 0);
+    if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
+	for (i = 0; i < 4; i++) {
+	    if (i == ignore) continue;
+	    port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
+	    sock = (i & 1) << 1;
+	    if (identify(port, sock) == IS_I82365DF) {
+		add_socket(port, sock, IS_VLSI);
+		add_pcic(1, IS_VLSI);
+	    }
+	}
+    } else {
+	for (i = 0; i < 8; i += 2) {
+	    if (sockets && !extra_sockets && (i == 4))
+		break;
+	    port = i365_base + 2*(i>>2);
+	    sock = (i & 3);
+	    id = identify(port, sock);
+	    if (id < 0) continue;
+
+	    for (j = ns = 0; j < 2; j++) {
+		/* Does the socket exist? */
+		if ((ignore == i+j) || (identify(port, sock+j) < 0))
+		    continue;
+		/* Check for bad socket decode */
+		for (k = 0; k <= sockets; k++)
+		    i365_set(k, I365_MEM(0)+I365_W_OFF, k);
+		for (k = 0; k <= sockets; k++)
+		    if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
+			break;
+		if (k <= sockets) break;
+		add_socket(port, sock+j, id); ns++;
+	    }
+	    if (ns != 0) add_pcic(ns, id);
+	}
+    }
+}
+
+/*====================================================================*/
+
+static irqreturn_t pcic_interrupt(int irq, void *dev)
+{
+    int i, j, csc;
+    u_int events, active;
+    u_long flags = 0;
+    int handled = 0;
+
+    pr_debug("pcic_interrupt(%d)\n", irq);
+
+    for (j = 0; j < 20; j++) {
+	active = 0;
+	for (i = 0; i < sockets; i++) {
+	    if (socket[i].cs_irq != irq)
+		continue;
+	    handled = 1;
+	    ISA_LOCK(i, flags);
+	    csc = i365_get(i, I365_CSC);
+	    if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
+		ISA_UNLOCK(i, flags);
+		continue;
+	    }
+	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+
+	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+	    else {
+		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+	    }
+	    ISA_UNLOCK(i, flags);
+	    pr_debug("socket %d event 0x%02x\n", i, events);
+
+	    if (events)
+		pcmcia_parse_events(&socket[i].socket, events);
+
+	    active |= events;
+	}
+	if (!active) break;
+    }
+    if (j == 20)
+	printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
+
+    pr_debug("pcic_interrupt done\n");
+    return IRQ_RETVAL(handled);
+} /* pcic_interrupt */
+
+static void pcic_interrupt_wrapper(u_long data)
+{
+    pcic_interrupt(0, NULL);
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int i365_get_status(u_short sock, u_int *value)
+{
+    u_int status;
+    
+    status = i365_get(sock, I365_STATUS);
+    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+	? SS_DETECT : 0;
+	
+    if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+    else {
+	*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+	*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+    }
+    *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+    *value |= (status & I365_CS_READY) ? SS_READY : 0;
+    *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+
+    if (socket[sock].type == IS_VG469) {
+	status = i365_get(sock, VG469_VSENSE);
+	if (socket[sock].psock & 1) {
+	    *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
+	    *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
+	} else {
+	    *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
+	    *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+	}
+    }
+    
+    pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value);
+    return 0;
+} /* i365_get_status */
+
+/*====================================================================*/
+
+static int i365_set_socket(u_short sock, socket_state_t *state)
+{
+    struct i82365_socket *t = &socket[sock];
+    u_char reg;
+    
+    pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    
+    /* First set global controller options */
+    set_bridge_state(sock);
+    
+    /* IO card, RESET flag, IO interrupt */
+    reg = t->intr;
+    reg |= state->io_irq;
+    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+    i365_set(sock, I365_INTCTL, reg);
+    
+    reg = I365_PWR_NORESET;
+    if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+    if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+
+    if (t->flags & IS_CIRRUS) {
+	if (state->Vpp != 0) {
+	    if (state->Vpp == 120)
+		reg |= I365_VPP1_12V;
+	    else if (state->Vpp == state->Vcc)
+		reg |= I365_VPP1_5V;
+	    else return -EINVAL;
+	}
+	if (state->Vcc != 0) {
+	    reg |= I365_VCC_5V;
+	    if (state->Vcc == 33)
+		i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else if (state->Vcc == 50)
+		i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else return -EINVAL;
+	}
+    } else if (t->flags & IS_VG_PWR) {
+	if (state->Vpp != 0) {
+	    if (state->Vpp == 120)
+		reg |= I365_VPP1_12V;
+	    else if (state->Vpp == state->Vcc)
+		reg |= I365_VPP1_5V;
+	    else return -EINVAL;
+	}
+	if (state->Vcc != 0) {
+	    reg |= I365_VCC_5V;
+	    if (state->Vcc == 33)
+		i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
+	    else if (state->Vcc == 50)
+		i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
+	    else return -EINVAL;
+	}
+    } else if (t->flags & IS_DF_PWR) {
+	switch (state->Vcc) {
+	case 0:		break;
+	case 33:   	reg |= I365_VCC_3V; break;
+	case 50:	reg |= I365_VCC_5V; break;
+	default:	return -EINVAL;
+	}
+	switch (state->Vpp) {
+	case 0:		break;
+	case 50:   	reg |= I365_VPP1_5V; break;
+	case 120:	reg |= I365_VPP1_12V; break;
+	default:	return -EINVAL;
+	}
+    } else {
+	switch (state->Vcc) {
+	case 0:		break;
+	case 50:	reg |= I365_VCC_5V; break;
+	default:	return -EINVAL;
+	}
+	switch (state->Vpp) {
+	case 0:		break;
+	case 50:	reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+	case 120:	reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+	default:	return -EINVAL;
+	}
+    }
+    
+    if (reg != i365_get(sock, I365_POWER))
+	i365_set(sock, I365_POWER, reg);
+
+    /* Chipset-specific functions */
+    if (t->flags & IS_CIRRUS) {
+	/* Speaker control */
+	i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+		   state->flags & SS_SPKR_ENA);
+    }
+    
+    /* Card status change interrupt mask */
+    reg = t->cs_irq << 4;
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    if (state->flags & SS_IOCARD) {
+	if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+    } else {
+	if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
+	if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
+	if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+    }
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+    
+    return 0;
+} /* i365_set_socket */
+
+/*====================================================================*/
+
+static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl;
+    
+    pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, "
+	  "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
+	  (unsigned long long)io->start, (unsigned long long)io->stop);
+    map = io->map;
+    if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+	(io->stop < io->start)) return -EINVAL;
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+	i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
+    i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
+    ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+    if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
+    if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+    if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+    if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+    i365_set(sock, I365_IOCTL, ioctl);
+    /* Turn on the window if necessary */
+    if (io->flags & MAP_ACTIVE)
+	i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    return 0;
+} /* i365_set_io_map */
+
+/*====================================================================*/
+
+static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map;
+    
+    pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
+	  "%#x)\n", sock, mem->map, mem->flags, mem->speed,
+	  (unsigned long long)mem->res->start,
+	  (unsigned long long)mem->res->end, mem->card_start);
+
+    map = mem->map;
+    if ((map > 4) || (mem->card_start > 0x3ffffff) ||
+	(mem->res->start > mem->res->end) || (mem->speed > 1000))
+	return -EINVAL;
+    if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
+	return -EINVAL;
+	
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+	i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+    
+    base = I365_MEM(map);
+    i = (mem->res->start >> 12) & 0x0fff;
+    if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+    if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+    i365_set_pair(sock, base+I365_W_START, i);
+    
+    i = (mem->res->end >> 12) & 0x0fff;
+    switch (to_cycles(mem->speed)) {
+    case 0:	break;
+    case 1:	i |= I365_MEM_WS0; break;
+    case 2:	i |= I365_MEM_WS1; break;
+    default:	i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+    }
+    i365_set_pair(sock, base+I365_W_STOP, i);
+    
+    i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
+    if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+    if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+    i365_set_pair(sock, base+I365_W_OFF, i);
+    
+    /* Turn on the window if necessary */
+    if (mem->flags & MAP_ACTIVE)
+	i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+    return 0;
+} /* i365_set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+    Routines for accessing socket information and register dumps via
+    /sys/class/pcmcia_socket/...
+    
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
+	return sprintf(buf, "type:     %s\npsock:    %d\n",
+		       pcic[s->type].name, s->psock);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
+	unsigned short sock;
+	int i;
+	ssize_t ret = 0;
+	unsigned long flags = 0;
+
+	sock = s->number;
+
+	ISA_LOCK(sock, flags);
+	for (i = 0; i < 0x40; i += 4) {
+		ret += sprintf(buf, "%02x %02x %02x %02x%s",
+			       i365_get(sock,i), i365_get(sock,i+1),
+			       i365_get(sock,i+2), i365_get(sock,i+3),
+			       ((i % 16) == 12) ? "\n" : " ");
+		buf += ret;
+	}
+	ISA_UNLOCK(sock, flags);
+
+	return ret;
+}
+
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at 
+ * some time... */
+#define LOCKED(x) do { \
+	int retval; \
+	unsigned long flags; \
+	spin_lock_irqsave(&isa_lock, flags); \
+	retval = x; \
+	spin_unlock_irqrestore(&isa_lock, flags); \
+	return retval; \
+} while (0)
+	
+
+static int pcic_get_status(struct pcmcia_socket *s, u_int *value)
+{
+	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		*value = 0;
+		return -EINVAL;
+	}
+
+	LOCKED(i365_get_status(sock, value));
+}
+
+static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(i365_set_socket(sock, state));
+}
+
+static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(i365_set_io_map(sock, io));
+}
+
+static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(i365_set_mem_map(sock, mem));
+}
+
+static int pcic_init(struct pcmcia_socket *s)
+{
+	int i;
+	struct resource res = { .start = 0, .end = 0x1000 };
+	pccard_io_map io = { 0, 0, 0, 0, 1 };
+	pccard_mem_map mem = { .res = &res, };
+
+	for (i = 0; i < 2; i++) {
+		io.map = i;
+		pcic_set_io_map(s, &io);
+	}
+	for (i = 0; i < 5; i++) {
+		mem.map = i;
+		pcic_set_mem_map(s, &mem);
+	}
+	return 0;
+}
+
+
+static struct pccard_operations pcic_operations = {
+	.init			= pcic_init,
+	.get_status		= pcic_get_status,
+	.set_socket		= pcic_set_socket,
+	.set_io_map		= pcic_set_io_map,
+	.set_mem_map		= pcic_set_mem_map,
+};
+
+/*====================================================================*/
+
+static struct platform_driver i82365_driver = {
+	.driver = {
+		.name = "i82365",
+	},
+};
+
+static struct platform_device *i82365_device;
+
+static int __init init_i82365(void)
+{
+    int i, ret;
+
+    ret = platform_driver_register(&i82365_driver);
+    if (ret)
+	goto err_out;
+
+    i82365_device = platform_device_alloc("i82365", 0);
+    if (i82365_device) {
+	    ret = platform_device_add(i82365_device);
+	    if (ret)
+		    platform_device_put(i82365_device);
+    } else
+	    ret = -ENOMEM;
+
+    if (ret)
+	goto err_driver_unregister;
+
+    printk(KERN_INFO "Intel ISA PCIC probe: ");
+    sockets = 0;
+
+    isa_probe();
+
+    if (sockets == 0) {
+	printk("not found.\n");
+	ret = -ENODEV;
+	goto err_dev_unregister;
+    }
+
+    /* Set up interrupt handler(s) */
+    if (grab_irq != 0)
+	ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
+
+    if (ret)
+	goto err_socket_release;
+
+    /* register sockets with the pcmcia core */
+    for (i = 0; i < sockets; i++) {
+	    socket[i].socket.dev.parent = &i82365_device->dev;
+	    socket[i].socket.ops = &pcic_operations;
+	    socket[i].socket.resource_ops = &pccard_nonstatic_ops;
+	    socket[i].socket.owner = THIS_MODULE;
+	    socket[i].number = i;
+	    ret = pcmcia_register_socket(&socket[i].socket);
+	    if (!ret)
+		    socket[i].flags |= IS_REGISTERED;
+    }
+
+    /* Finally, schedule a polling interrupt */
+    if (poll_interval != 0) {
+	poll_timer.function = pcic_interrupt_wrapper;
+	poll_timer.data = 0;
+	init_timer(&poll_timer);
+    	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+    }
+    
+    return 0;
+err_socket_release:
+    for (i = 0; i < sockets; i++) {
+	/* Turn off all interrupt sources! */
+	i365_set(i, I365_CSCINT, 0);
+	release_region(socket[i].ioaddr, 2);
+    }
+err_dev_unregister:
+    platform_device_unregister(i82365_device);
+    release_region(i365_base, 2);
+#ifdef CONFIG_PNP
+    if (i82365_pnpdev)
+	pnp_disable_dev(i82365_pnpdev);
+#endif
+err_driver_unregister:
+    platform_driver_unregister(&i82365_driver);
+err_out:
+    return ret;
+} /* init_i82365 */
+
+static void __exit exit_i82365(void)
+{
+    int i;
+
+    for (i = 0; i < sockets; i++) {
+	    if (socket[i].flags & IS_REGISTERED)
+		    pcmcia_unregister_socket(&socket[i].socket);
+    }
+    platform_device_unregister(i82365_device);
+    if (poll_interval != 0)
+	del_timer_sync(&poll_timer);
+    if (grab_irq != 0)
+	free_irq(cs_irq, pcic_interrupt);
+    for (i = 0; i < sockets; i++) {
+	/* Turn off all interrupt sources! */
+	i365_set(i, I365_CSCINT, 0);
+	release_region(socket[i].ioaddr, 2);
+    }
+    release_region(i365_base, 2);
+#ifdef CONFIG_PNP
+    if (i82365_pnpdev)
+    		pnp_disable_dev(i82365_pnpdev);
+#endif
+    platform_driver_unregister(&i82365_driver);
+} /* exit_i82365 */
+
+module_init(init_i82365);
+module_exit(exit_i82365);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/i82365.h b/src/kernel/linux/v4.14/drivers/pcmcia/i82365.h
new file mode 100644
index 0000000..3f84d7a
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/i82365.h
@@ -0,0 +1,136 @@
+/*
+ * i82365.h 1.15 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT	0x00	/* Identification and revision */
+#define I365_STATUS	0x01	/* Interface status */
+#define I365_POWER	0x02	/* Power and RESETDRV control */
+#define I365_INTCTL	0x03	/* Interrupt and general control */
+#define I365_CSC	0x04	/* Card status change */
+#define I365_CSCINT	0x05	/* Card status change interrupt control */
+#define I365_ADDRWIN	0x06	/* Address window enable */
+#define I365_IOCTL	0x07	/* I/O control */
+#define I365_GENCTL	0x16	/* Card detect and general control */
+#define I365_GBLCTL	0x1E	/* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map)	(0x08+((map)<<2))
+#define I365_MEM(map)	(0x10+((map)<<3))
+#define I365_W_START	0
+#define I365_W_STOP	2
+#define I365_W_OFF	4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1	0x01
+#define I365_CS_STSCHG	0x01
+#define I365_CS_BVD2	0x02
+#define I365_CS_SPKR	0x02
+#define I365_CS_DETECT	0x0C
+#define I365_CS_WRPROT	0x10
+#define I365_CS_READY	0x20	/* Inverted */
+#define I365_CS_POWERON	0x40
+#define I365_CS_GPI	0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF	0x00	/* Turn off the socket */
+#define I365_PWR_OUT	0x80	/* Output enable */
+#define I365_PWR_NORESET 0x40	/* Disable RESETDRV on resume */
+#define I365_PWR_AUTO	0x20	/* Auto pwr switch enable */
+#define I365_VCC_MASK	0x18	/* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+   step has independent Vpp1/Vpp2 control, and the DF step has only
+   Vpp1 control, plus 3V control */
+#define I365_VCC_5V	0x10	/* Vcc = 5.0v */
+#define I365_VCC_3V	0x18	/* Vcc = 3.3v */
+#define I365_VPP2_MASK	0x0c	/* Mask for turning off Vpp2 */
+#define I365_VPP2_5V	0x04	/* Vpp2 = 5.0v */
+#define I365_VPP2_12V	0x08	/* Vpp2 = 12.0v */
+#define I365_VPP1_MASK	0x03	/* Mask for turning off Vpp1 */
+#define I365_VPP1_5V	0x01	/* Vpp1 = 5.0v */
+#define I365_VPP1_12V	0x02	/* Vpp1 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA	0x80
+#define I365_PC_RESET	0x40
+#define I365_PC_IOCARD	0x20
+#define I365_INTR_ENA	0x10
+#define I365_IRQ_MASK	0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1	0x01
+#define I365_CSC_STSCHG	0x01
+#define I365_CSC_BVD2	0x02
+#define I365_CSC_READY	0x04
+#define I365_CSC_DETECT	0x08
+#define I365_CSC_ANY	0x0F
+#define I365_CSC_GPI	0x10
+#define I365_CSC_IRQ_MASK	0xF0
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map)	(0x40 << (map))
+#define I365_ENA_MEM(map)	(0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map)	(0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map)	(0x08 << (map<<2))
+#define I365_IOCTL_0WS(map)	(0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map)	(0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map)	(0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY	0x01
+#define I365_CTL_RESET		0x02
+#define I365_CTL_GPI_ENA	0x04
+#define I365_CTL_GPI_CTL	0x08
+#define I365_CTL_RESUME		0x10
+#define I365_CTL_SW_IRQ		0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN	0x01
+#define I365_GBL_CSC_LEV	0x02
+#define I365_GBL_WRBACK		0x04
+#define I365_GBL_IRQ_0_LEV	0x08
+#define I365_GBL_IRQ_1_LEV	0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT	0x8000	/* In memory start high byte */
+#define I365_MEM_0WS	0x4000
+#define I365_MEM_WS1	0x8000	/* In memory stop high byte */
+#define I365_MEM_WS0	0x4000
+#define I365_MEM_WRPROT	0x8000	/* In offset high byte */
+#define I365_MEM_REG	0x4000
+
+#define I365_REG(slot, reg)	(((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.c b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.c
new file mode 100644
index 0000000..70b0894
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.c
@@ -0,0 +1,789 @@
+/*
+ *  drivers/pcmcia/m32r_cfc.c
+ *
+ *  Device driver for the CFC functionality of M32R.
+ *
+ *  Copyright (c) 2001, 2002, 2003, 2004
+ *    Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+
+#undef MAX_IO_WIN	/* FIXME */
+#define MAX_IO_WIN 1
+#undef MAX_WIN		/* FIXME */
+#define MAX_WIN 1
+
+#include "m32r_cfc.h"
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket {
+	u_short			type, flags;
+	struct pcmcia_socket	socket;
+	unsigned int		number;
+	unsigned int		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq1, cs_irq2, intr;
+	pccard_io_map		io_map[MAX_IO_WIN];
+	pccard_mem_map		mem_map[MAX_WIN];
+	u_char			io_win;
+	u_char			mem_win;
+	pcc_as_t		current_space;
+	u_char			last_iodbex;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc;
+#endif
+} pcc_socket_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_t socket[M32R_MAX_PCC] = {
+	{ 0, }, /* ... */
+};
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static DEFINE_SPINLOCK(pcc_lock);
+
+#if !defined(CONFIG_PLAT_USRV)
+static inline u_long pcc_port2addr(unsigned long port, int size) {
+	u_long addr = 0;
+	u_long odd;
+
+	if (size == 1) {	/* byte access */
+		odd = (port&1) << 11;
+		port -= port & 1;
+		addr = CFC_IO_MAPBASE_BYTE - CFC_IOPORT_BASE + odd + port;
+	} else if (size == 2)
+		addr = CFC_IO_MAPBASE_WORD - CFC_IOPORT_BASE + port;
+
+	return addr;
+}
+#else	/* CONFIG_PLAT_USRV */
+static inline u_long pcc_port2addr(unsigned long port, int size) {
+	u_long odd;
+	u_long addr = ((port - CFC_IOPORT_BASE) & 0xf000) << 8;
+
+	if (size == 1) {	/* byte access */
+		odd = port & 1;
+		port -= odd;
+		odd <<= 11;
+		addr = (addr | CFC_IO_MAPBASE_BYTE) + odd + (port & 0xfff);
+	} else if (size == 2)	/* word access */
+		addr = (addr | CFC_IO_MAPBASE_WORD) + (port & 0xfff);
+
+	return addr;
+}
+#endif	/* CONFIG_PLAT_USRV */
+
+void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size,
+	size_t nmemb, int flag)
+{
+	u_long addr;
+	unsigned char *bp = (unsigned char *)buf;
+	unsigned long flags;
+
+	pr_debug("m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, "
+		 "size=%u, nmemb=%d, flag=%d\n",
+		  sock, port, buf, size, nmemb, flag);
+
+	addr = pcc_port2addr(port, 1);
+	if (!addr) {
+		printk("m32r_cfc:ioread_byte null port :%#lx\n",port);
+		return;
+	}
+	pr_debug("m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr);
+
+	spin_lock_irqsave(&pcc_lock, flags);
+	/* read Byte */
+	while (nmemb--)
+		*bp++ = readb(addr);
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size,
+	size_t nmemb, int flag)
+{
+	u_long addr;
+	unsigned short *bp = (unsigned short *)buf;
+	unsigned long flags;
+
+	pr_debug("m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	if (size != 2)
+		printk("m32r_cfc: ioread_word :illigal size %u : %#lx\n", size,
+			port);
+	if (size == 9)
+		printk("m32r_cfc: ioread_word :insw \n");
+
+	addr = pcc_port2addr(port, 2);
+	if (!addr) {
+		printk("m32r_cfc:ioread_word null port :%#lx\n",port);
+		return;
+	}
+	pr_debug("m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr);
+
+	spin_lock_irqsave(&pcc_lock, flags);
+	/* read Word */
+	while (nmemb--)
+		*bp++ = readw(addr);
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size,
+	size_t nmemb, int flag)
+{
+	u_long addr;
+	unsigned char *bp = (unsigned char *)buf;
+	unsigned long flags;
+
+	pr_debug("m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	/* write Byte */
+	addr = pcc_port2addr(port, 1);
+	if (!addr) {
+		printk("m32r_cfc:iowrite_byte null port:%#lx\n",port);
+		return;
+	}
+	pr_debug("m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr);
+
+	spin_lock_irqsave(&pcc_lock, flags);
+	while (nmemb--)
+		writeb(*bp++, addr);
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size,
+	size_t nmemb, int flag)
+{
+	u_long addr;
+	unsigned short *bp = (unsigned short *)buf;
+	unsigned long flags;
+
+	pr_debug("m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	if(size != 2)
+		printk("m32r_cfc: iowrite_word :illigal size %u : %#lx\n",
+			size, port);
+	if(size == 9)
+		printk("m32r_cfc: iowrite_word :outsw \n");
+
+	addr = pcc_port2addr(port, 2);
+	if (!addr) {
+		printk("m32r_cfc:iowrite_word null addr :%#lx\n",port);
+		return;
+	}
+#if 1
+	if (addr & 1) {
+		printk("m32r_cfc:iowrite_word port addr (%#lx):%#lx\n", port,
+			addr);
+		return;
+	}
+#endif
+	pr_debug("m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr);
+
+	spin_lock_irqsave(&pcc_lock, flags);
+	while (nmemb--)
+		writew(*bp++, addr);
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+/*====================================================================*/
+
+#define IS_REGISTERED		0x2000
+#define IS_ALIVE		0x8000
+
+typedef struct pcc_t {
+	char			*name;
+	u_short			flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+#if !defined(CONFIG_PLAT_USRV)
+	{ "m32r_cfc", 0 }, { "", 0 },
+#else	/* CONFIG_PLAT_USRV */
+	{ "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 },
+	{ "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "", 0 },
+#endif	/* CONFIG_PLAT_USRV */
+};
+
+static irqreturn_t pcc_interrupt(int, void *);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+	unsigned int val = inw(reg);
+	pr_debug("m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val);
+	return val;
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+	outw(data, reg);
+	pr_debug("m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data);
+}
+
+/*======================================================================
+
+	See if a card is present, powered up, in IO mode, and already
+	bound to a (non PC Card) Linux driver.  We leave these alone.
+
+	We make an exception for cards that seem to be serial devices.
+
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+	unsigned int stat;
+
+	pr_debug("m32r_cfc: is_alive:\n");
+
+	printk("CF: ");
+	stat = pcc_get(sock, (unsigned int)PLD_CFSTS);
+	if (!stat)
+		printk("No ");
+	printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat);
+	pr_debug("m32r_cfc: is_alive: sock stat is 0x%04x\n", stat);
+
+	return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr,
+			   unsigned int ioaddr)
+{
+	pcc_socket_t *t = &socket[pcc_sockets];
+
+	pr_debug("m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, "
+		 "mapaddr=%#lx, ioaddr=%08x\n",
+		 base, irq, mapaddr, ioaddr);
+
+	/* add sockets */
+	t->ioaddr = ioaddr;
+	t->mapaddr = mapaddr;
+#if !defined(CONFIG_PLAT_USRV)
+	t->base = 0;
+	t->flags = 0;
+	t->cs_irq1 = irq;		// insert irq
+	t->cs_irq2 = irq + 1;		// eject irq
+#else	/* CONFIG_PLAT_USRV */
+	t->base = base;
+	t->flags = 0;
+	t->cs_irq1 = 0;			// insert irq
+	t->cs_irq2 = 0;			// eject irq
+#endif	/* CONFIG_PLAT_USRV */
+
+	if (is_alive(pcc_sockets))
+		t->flags |= IS_ALIVE;
+
+	/* add pcc */
+#if !defined(CONFIG_PLAT_USRV)
+	request_region((unsigned int)PLD_CFRSTCR, 0x20, "m32r_cfc");
+#else	/* CONFIG_PLAT_USRV */
+	{
+		unsigned int reg_base;
+
+		reg_base = (unsigned int)PLD_CFRSTCR;
+		reg_base |= pcc_sockets << 8;
+		request_region(reg_base, 0x20, "m32r_cfc");
+	}
+#endif	/* CONFIG_PLAT_USRV */
+	printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+	printk("pcc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->socket.map_size = M32R_PCC_MAPSIZE;
+	t->socket.io_offset = ioaddr;	/* use for io access offset */
+	t->socket.irq_mask = 0;
+#if !defined(CONFIG_PLAT_USRV)
+	t->socket.pci_irq = PLD_IRQ_CFIREQ ;	/* card interrupt */
+#else	/* CONFIG_PLAT_USRV */
+	t->socket.pci_irq = PLD_IRQ_CF0 + pcc_sockets;
+#endif	/* CONFIG_PLAT_USRV */
+
+#ifndef CONFIG_PLAT_USRV
+	/* insert interrupt */
+	request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+#ifndef CONFIG_PLAT_MAPPI3
+	/* eject interrupt */
+	request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+#endif
+	pr_debug("m32r_cfc: enable CFMSK, RDYSEL\n");
+	pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01);
+#endif	/* CONFIG_PLAT_USRV */
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+	pcc_sockets++;
+
+	return;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev)
+{
+	int i;
+	u_int events = 0;
+	int handled = 0;
+
+	pr_debug("m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev);
+	for (i = 0; i < pcc_sockets; i++) {
+		if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq)
+			continue;
+
+		handled = 1;
+		pr_debug("m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ",
+			i, irq);
+		events |= SS_DETECT;	/* insert or eject */
+		if (events)
+			pcmcia_parse_events(&socket[i].socket, events);
+	}
+	pr_debug("m32r_cfc: pcc_interrupt: done\n");
+
+	return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	pr_debug("m32r_cfc: pcc_interrupt_wrapper:\n");
+	pcc_interrupt(0, NULL);
+	init_timer(&poll_timer);
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+	u_int status;
+
+	pr_debug("m32r_cfc: _pcc_get_status:\n");
+	status = pcc_get(sock, (unsigned int)PLD_CFSTS);
+	*value = (status) ? SS_DETECT : 0;
+	pr_debug("m32r_cfc: _pcc_get_status: status=0x%08x\n", status);
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	if ( status ) {
+		/* enable CF power */
+		status = inw((unsigned int)PLD_CPCR);
+		if (!(status & PLD_CPCR_CF)) {
+			pr_debug("m32r_cfc: _pcc_get_status: "
+				 "power on (CPCR=0x%08x)\n", status);
+			status |= PLD_CPCR_CF;
+			outw(status, (unsigned int)PLD_CPCR);
+			udelay(100);
+		}
+		*value |= SS_POWERON;
+
+		pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);/* enable buffer */
+		udelay(100);
+
+		*value |= SS_READY; 		/* always ready */
+		*value |= SS_3VCARD;
+	} else {
+		/* disable CF power */
+		status = inw((unsigned int)PLD_CPCR);
+		status &= ~PLD_CPCR_CF;
+		outw(status, (unsigned int)PLD_CPCR);
+		udelay(100);
+		pr_debug("m32r_cfc: _pcc_get_status: "
+			 "power off (CPCR=0x%08x)\n", status);
+	}
+#elif defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
+	if ( status ) {
+		status = pcc_get(sock, (unsigned int)PLD_CPCR);
+		if (status == 0) { /* power off */
+			pcc_set(sock, (unsigned int)PLD_CPCR, 1);
+			pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */
+			udelay(50);
+		}
+		*value |= SS_POWERON;
+
+		pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);
+		udelay(50);
+		pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101);
+		udelay(25); /* for IDE reset */
+		pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100);
+		mdelay(2);  /* for IDE reset */
+
+		*value |= SS_READY;
+		*value |= SS_3VCARD;
+	} else {
+		/* disable CF power */
+	        pcc_set(sock, (unsigned int)PLD_CPCR, 0);
+		udelay(100);
+		pr_debug("m32r_cfc: _pcc_get_status: "
+			 "power off (CPCR=0x%08x)\n", status);
+	}
+#else
+#error no platform configuration
+#endif
+	pr_debug("m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n",
+		 sock, *value);
+	return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+	pr_debug("m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
+	if (state->Vcc) {
+		if ((state->Vcc != 50) && (state->Vcc != 33))
+			return -EINVAL;
+		/* accept 5V and 3.3V */
+	}
+#endif
+	if (state->flags & SS_RESET) {
+		pr_debug(":RESET\n");
+		pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101);
+	}else{
+		pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x100);
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		pr_debug(":OUTPUT_ENA\n");
+		/* bit clear */
+		pcc_set(sock,(unsigned int)PLD_CFBUFCR,0);
+	} else {
+		pcc_set(sock,(unsigned int)PLD_CFBUFCR,1);
+	}
+
+	if(state->flags & SS_IOCARD){
+		pr_debug(":IOCARD");
+	}
+	if (state->flags & SS_PWR_AUTO) {
+		pr_debug(":PWR_AUTO");
+	}
+	if (state->csc_mask & SS_DETECT)
+		pr_debug(":csc-SS_DETECT");
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG)
+			pr_debug(":STSCHG");
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			pr_debug(":BATDEAD");
+		if (state->csc_mask & SS_BATWARN)
+			pr_debug(":BATWARN");
+		if (state->csc_mask & SS_READY)
+			pr_debug(":READY");
+	}
+	pr_debug("\n");
+	return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+
+	pr_debug("m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+		  "%#llx-%#llx)\n", sock, io->map, io->flags,
+		  io->speed, (unsigned long long)io->start,
+		  (unsigned long long)io->stop);
+	map = io->map;
+
+	return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long addr;
+	pcc_socket_t *t = &socket[sock];
+
+	pr_debug("m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, "
+		 "%#llx, %#x)\n", sock, map, mem->flags,
+		 mem->speed, (unsigned long long)mem->static_start,
+		 mem->card_start);
+
+	/*
+	 * sanity check
+	 */
+	if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){
+		return -EINVAL;
+	}
+
+	/*
+	 * de-activate
+	 */
+	if ((mem->flags & MAP_ACTIVE) == 0) {
+		t->current_space = as_none;
+		return 0;
+	}
+
+	/*
+	 * Set mode
+	 */
+	if (mem->flags & MAP_ATTRIB) {
+		t->current_space = as_attr;
+	} else {
+		t->current_space = as_comm;
+	}
+
+	/*
+	 * Set address
+	 */
+	addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+	mem->static_start = addr + mem->card_start;
+
+	return 0;
+
+} /* _set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+	pcc_socket_t *s = container_of(class_dev, struct pcc_socket,
+		socket.dev);
+
+	return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+		pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at
+ * some time... */
+#define LOCKED(x) do {					\
+	int retval;					\
+	unsigned long flags;				\
+	spin_lock_irqsave(&pcc_lock, flags);		\
+	retval = x;					\
+	spin_unlock_irqrestore(&pcc_lock, flags);	\
+	return retval;					\
+} while (0)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		dev_dbg(&s->dev, "pcc_get_status: sock(%d) -EINVAL\n", sock);
+		*value = 0;
+		return -EINVAL;
+	}
+	dev_dbg(&s->dev, "pcc_get_status: sock(%d)\n", sock);
+	LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		dev_dbg(&s->dev, "pcc_set_socket: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	dev_dbg(&s->dev, "pcc_set_socket: sock(%d)\n", sock);
+	LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		dev_dbg(&s->dev, "pcc_set_io_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	dev_dbg(&s->dev, "pcc_set_io_map: sock(%d)\n", sock);
+	LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		dev_dbg(&s->dev, "pcc_set_mem_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	dev_dbg(&s->dev, "pcc_set_mem_map: sock(%d)\n", sock);
+	LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(struct pcmcia_socket *s)
+{
+	dev_dbg(&s->dev, "pcc_init()\n");
+	return 0;
+}
+
+static struct pccard_operations pcc_operations = {
+	.init			= pcc_init,
+	.get_status		= pcc_get_status,
+	.set_socket		= pcc_set_socket,
+	.set_io_map		= pcc_set_io_map,
+	.set_mem_map		= pcc_set_mem_map,
+};
+
+
+/*====================================================================*/
+
+static struct platform_driver pcc_driver = {
+	.driver = {
+		.name		= "cfc",
+	},
+};
+
+static struct platform_device pcc_device = {
+	.name = "cfc",
+	.id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+	int i, ret;
+
+	ret = platform_driver_register(&pcc_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_device_register(&pcc_device);
+	if (ret){
+		platform_driver_unregister(&pcc_driver);
+		return ret;
+	}
+
+#if defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
+	pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f);
+	pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+
+	pcc_sockets = 0;
+
+#if !defined(CONFIG_PLAT_USRV)
+	add_pcc_socket(M32R_PCC0_BASE, PLD_IRQ_CFC_INSERT, CFC_ATTR_MAPBASE,
+		       CFC_IOPORT_BASE);
+#else	/* CONFIG_PLAT_USRV */
+	{
+		ulong base, mapaddr;
+		unsigned int ioaddr;
+
+		for (i = 0 ; i < M32R_MAX_PCC ; i++) {
+			base = (ulong)PLD_CFRSTCR;
+			base = base | (i << 8);
+			ioaddr = (i + 1) << 12;
+			mapaddr = CFC_ATTR_MAPBASE | (i << 20);
+			add_pcc_socket(base, 0, mapaddr, ioaddr);
+		}
+	}
+#endif	/* CONFIG_PLAT_USRV */
+
+	if (pcc_sockets == 0) {
+		printk("socket is not found.\n");
+		platform_device_unregister(&pcc_device);
+		platform_driver_unregister(&pcc_driver);
+		return -ENODEV;
+	}
+
+	/* Set up interrupt handler(s) */
+
+	for (i = 0 ; i < pcc_sockets ; i++) {
+		socket[i].socket.dev.parent = &pcc_device.dev;
+		socket[i].socket.ops = &pcc_operations;
+		socket[i].socket.resource_ops = &pccard_static_ops;
+		socket[i].socket.owner = THIS_MODULE;
+		socket[i].number = i;
+		ret = pcmcia_register_socket(&socket[i].socket);
+		if (!ret)
+			socket[i].flags |= IS_REGISTERED;
+	}
+
+	/* Finally, schedule a polling interrupt */
+	if (poll_interval != 0) {
+		poll_timer.function = pcc_interrupt_wrapper;
+		poll_timer.data = 0;
+		init_timer(&poll_timer);
+		poll_timer.expires = jiffies + poll_interval;
+		add_timer(&poll_timer);
+	}
+
+	return 0;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+	int i;
+
+	for (i = 0; i < pcc_sockets; i++)
+		if (socket[i].flags & IS_REGISTERED)
+			pcmcia_unregister_socket(&socket[i].socket);
+
+	platform_device_unregister(&pcc_device);
+	if (poll_interval != 0)
+		del_timer_sync(&poll_timer);
+
+	platform_driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.h b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.h
new file mode 100644
index 0000000..05fec98
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_cfc.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+#if !defined(CONFIG_M32R_CFC_NUM)
+#define M32R_MAX_PCC	2
+#else
+#define M32R_MAX_PCC	CONFIG_M32R_CFC_NUM
+#endif
+
+/*
+ * M32R PC Card Controller
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB	(1UL<<(31-19))
+#define PCMOD_AS_IO	(1UL<<(31-18))
+
+#define PCMOD_CBSZ	(1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX	(1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX		 0x02000000
+
+#define M32R_PCC_MAPSIZE	 0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK     	(~(M32R_PCC_MAPMAX-1))
+
+#define CFC_IOPORT_BASE		0x1000
+
+#if defined(CONFIG_PLAT_MAPPI3)
+#define CFC_ATTR_MAPBASE	0x14014000
+#define CFC_IO_MAPBASE_BYTE	0xb4012000
+#define CFC_IO_MAPBASE_WORD	0xb4002000
+#elif !defined(CONFIG_PLAT_USRV)
+#define CFC_ATTR_MAPBASE        0x0c014000
+#define CFC_IO_MAPBASE_BYTE     0xac012000
+#define CFC_IO_MAPBASE_WORD     0xac002000
+#else
+#define CFC_ATTR_MAPBASE	0x04014000
+#define CFC_IO_MAPBASE_BYTE	0xa4012000
+#define CFC_IO_MAPBASE_WORD	0xa4002000
+#endif	/* CONFIG_PLAT_USRV */
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.c b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.c
new file mode 100644
index 0000000..e50bbf8
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.c
@@ -0,0 +1,766 @@
+/*
+ *  drivers/pcmcia/m32r_pcc.c
+ *
+ *  Device driver for the PCMCIA functionality of M32R.
+ *
+ *  Copyright (c) 2001, 2002, 2003, 2004
+ *    Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#include <pcmcia/ss.h>
+
+/* XXX: should be moved into asm/irq.h */
+#define PCC0_IRQ 24
+#define PCC1_IRQ 25
+
+#include "m32r_pcc.h"
+
+#define CHAOS_PCC_DEBUG
+#ifdef CHAOS_PCC_DEBUG
+	static volatile u_short dummy_readbuf;
+#endif
+
+#define PCC_DEBUG_DBEX
+
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket {
+	u_short			type, flags;
+	struct pcmcia_socket	socket;
+	unsigned int		number;
+	unsigned int		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq, intr;
+	pccard_io_map		io_map[MAX_IO_WIN];
+	pccard_mem_map		mem_map[MAX_WIN];
+	u_char			io_win;
+	u_char			mem_win;
+	pcc_as_t		current_space;
+	u_char			last_iodbex;
+#ifdef CHAOS_PCC_DEBUG
+	u_char			last_iosize;
+#endif
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc;
+#endif
+} pcc_socket_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_t socket[M32R_MAX_PCC] = {
+	{ 0, }, /* ... */
+};
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static DEFINE_SPINLOCK(pcc_lock);
+
+void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag)
+{
+	u_long addr;
+	u_long flags;
+	int need_ex;
+#ifdef PCC_DEBUG_DBEX
+	int _dbex;
+#endif
+	pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+	int map_changed = 0;
+#endif
+
+	/* Need lock ? */
+	spin_lock_irqsave(&pcc_lock, flags);
+
+	/*
+	 * Check if need dbex
+	 */
+	need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0;
+#ifdef PCC_DEBUG_DBEX
+	_dbex = need_ex;
+	need_ex = 0;
+#endif
+
+	/*
+	 * calculate access address
+	 */
+	addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */
+
+	/*
+	 * Check current mapping
+	 */
+	if (t->current_space != as_io || t->last_iodbex != need_ex) {
+
+		u_long cbsz;
+
+		/*
+		 * Disable first
+		 */
+		pcc_set(sock, PCCR, 0);
+
+		/*
+		 * Set mode and io address
+		 */
+		cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ;
+		pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex);
+		pcc_set(sock, PCADR, addr & 0x1ff00000);
+
+		/*
+		 * Enable and read it
+		 */
+		pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+		map_changed = (t->current_space == as_attr && size == 2); /* XXX */
+#else
+		map_changed = 1;
+#endif
+#endif
+		t->current_space = as_io;
+	}
+
+	/*
+	 * access to IO space
+	 */
+	if (size == 1) {
+		/* Byte */
+		unsigned char *bp = (unsigned char *)buf;
+
+#ifdef CHAOS_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readb(addr);
+		}
+#endif
+		if (wr) {
+			/* write Byte */
+			while (nmemb--) {
+				writeb(*bp++, addr);
+			}
+		} else {
+			/* read Byte */
+			while (nmemb--) {
+	    		*bp++ = readb(addr);
+			}
+		}
+	} else {
+		/* Word */
+		unsigned short *bp = (unsigned short *)buf;
+
+#ifdef CHAOS_PCC_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readw(addr);
+		}
+#endif
+		if (wr) {
+			/* write Word */
+			while (nmemb--) {
+#ifdef PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = cp[1] << 8 | cp[0];
+					writew(tmp, addr);
+					bp++;
+				} else
+#endif
+				writew(*bp++, addr);
+	    	}
+	    } else {
+	    	/* read Word */
+	    	while (nmemb--) {
+#ifdef  PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = readw(addr);
+					cp[0] = tmp & 0xff;
+					cp[1] = (tmp >> 8) & 0xff;
+					bp++;
+				} else
+#endif
+				*bp++ = readw(addr);
+	    	}
+	    }
+	}
+
+#if 1
+	/* addr is no longer used */
+	if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) {
+	  printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n",
+			 port, size * 8);
+	  pcc_set(sock, PCIRC, addr);
+	}
+#endif
+	/*
+	 * save state
+	 */
+	t->last_iosize = size;
+	t->last_iodbex = need_ex;
+
+	/* Need lock ? */
+
+	spin_unlock_irqrestore(&pcc_lock,flags);
+
+	return;
+}
+
+void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	pcc_iorw(sock, port, buf, size, nmemb, 0, flag);
+}
+
+void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+    pcc_iorw(sock, port, buf, size, nmemb, 1, flag);
+}
+
+/*====================================================================*/
+
+#define IS_REGISTERED		0x2000
+#define IS_ALIVE		0x8000
+
+typedef struct pcc_t {
+	char			*name;
+	u_short			flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+	{ "xnux2", 0 }, { "xnux2", 0 },
+};
+
+static irqreturn_t pcc_interrupt(int, void *);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+	return inl(socket[sock].base + reg);
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+  	outl(data, socket[sock].base + reg);
+}
+
+/*======================================================================
+
+	See if a card is present, powered up, in IO mode, and already
+	bound to a (non PC Card) Linux driver.  We leave these alone.
+
+	We make an exception for cards that seem to be serial devices.
+
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+	unsigned int stat;
+	unsigned int f;
+
+	stat = pcc_get(sock, PCIRC);
+	f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16;
+	if(!f){
+		printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock);
+		return 0;
+	}
+	if(f!=3)
+		printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock);
+	else
+		printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,stat);
+	return 0;
+}
+
+static int add_pcc_socket(ulong base, int irq, ulong mapaddr,
+			  unsigned int ioaddr)
+{
+  	pcc_socket_t *t = &socket[pcc_sockets];
+	int err;
+
+	/* add sockets */
+	t->ioaddr = ioaddr;
+	t->mapaddr = mapaddr;
+	t->base = base;
+#ifdef CHAOS_PCC_DEBUG
+	t->flags = MAP_16BIT;
+#else
+	t->flags = 0;
+#endif
+	if (is_alive(pcc_sockets))
+		t->flags |= IS_ALIVE;
+
+	/* add pcc */
+	if (t->base > 0) {
+		request_region(t->base, 0x20, "m32r-pcc");
+	}
+
+	printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+	printk("pcc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->socket.map_size = M32R_PCC_MAPSIZE;
+	t->socket.io_offset = ioaddr;	/* use for io access offset */
+	t->socket.irq_mask = 0;
+	t->socket.pci_irq = 2 + pcc_sockets; /* XXX */
+
+	err = request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt);
+	if (err) {
+		if (t->base > 0)
+			release_region(t->base, 0x20);
+		return err;
+	}
+
+	pcc_sockets++;
+
+	return 0;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev)
+{
+	int i, j, irc;
+	u_int events, active;
+	int handled = 0;
+
+	pr_debug("m32r_pcc: pcc_interrupt(%d)\n", irq);
+
+	for (j = 0; j < 20; j++) {
+		active = 0;
+		for (i = 0; i < pcc_sockets; i++) {
+			if ((socket[i].cs_irq != irq) &&
+				(socket[i].socket.pci_irq != irq))
+				continue;
+			handled = 1;
+			irc = pcc_get(i, PCIRC);
+			irc >>=16;
+			pr_debug("m32r_pcc: interrupt: socket %d pcirc 0x%02x ",
+				i, irc);
+			if (!irc)
+				continue;
+
+			events = (irc) ? SS_DETECT : 0;
+			events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0;
+			pr_debug("m32r_pcc: event 0x%02x\n", events);
+
+			if (events)
+				pcmcia_parse_events(&socket[i].socket, events);
+
+			active |= events;
+			active = 0;
+		}
+		if (!active) break;
+	}
+	if (j == 20)
+		printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n");
+
+	pr_debug("m32r_pcc: interrupt done\n");
+
+	return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	pcc_interrupt(0, NULL);
+	init_timer(&poll_timer);
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+	u_int status;
+
+	status = pcc_get(sock,PCIRC);
+	*value = ((status & PCIRC_CDIN1) && (status & PCIRC_CDIN2))
+		? SS_DETECT : 0;
+
+	status = pcc_get(sock,PCCR);
+
+#if 0
+	*value |= (status & PCCR_PCEN) ? SS_READY : 0;
+#else
+	*value |= SS_READY; /* XXX: always */
+#endif
+
+	status = pcc_get(sock,PCCSIGCR);
+	*value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0;
+
+	pr_debug("m32r_pcc: GetStatus(%d) = %#4.4x\n", sock, *value);
+	return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+	u_long reg = 0;
+
+	pr_debug("m32r_pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x)", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+	if (state->Vcc) {
+		/*
+		 * 5V only
+		 */
+		if (state->Vcc == 50) {
+			reg |= PCCSIGCR_VEN;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	if (state->flags & SS_RESET) {
+		pr_debug("m32r_pcc: :RESET\n");
+		reg |= PCCSIGCR_CRST;
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		pr_debug("m32r_pcc: :OUTPUT_ENA\n");
+		/* bit clear */
+	} else {
+		reg |= PCCSIGCR_SEN;
+	}
+
+	pcc_set(sock,PCCSIGCR,reg);
+
+	if(state->flags & SS_IOCARD){
+		pr_debug("m32r_pcc: :IOCARD");
+	}
+	if (state->flags & SS_PWR_AUTO) {
+		pr_debug("m32r_pcc: :PWR_AUTO");
+	}
+	if (state->csc_mask & SS_DETECT)
+		pr_debug("m32r_pcc: :csc-SS_DETECT");
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG)
+			pr_debug("m32r_pcc: :STSCHG");
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			pr_debug("m32r_pcc: :BATDEAD");
+		if (state->csc_mask & SS_BATWARN)
+			pr_debug("m32r_pcc: :BATWARN");
+		if (state->csc_mask & SS_READY)
+			pr_debug("m32r_pcc: :READY");
+	}
+	pr_debug("m32r_pcc: \n");
+	return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+
+	pr_debug("m32r_pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+		  "%#llx-%#llx)\n", sock, io->map, io->flags,
+		  io->speed, (unsigned long long)io->start,
+		  (unsigned long long)io->stop);
+	map = io->map;
+
+	return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long mode;
+	u_long addr;
+	pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+	pcc_as_t last = t->current_space;
+#endif
+#endif
+
+	pr_debug("m32r_pcc: SetMemMap(%d, %d, %#2.2x, %d ns, "
+		 "%#llx,  %#x)\n", sock, map, mem->flags,
+		 mem->speed, (unsigned long long)mem->static_start,
+		 mem->card_start);
+
+	/*
+	 * sanity check
+	 */
+	if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){
+		return -EINVAL;
+	}
+
+	/*
+	 * de-activate
+	 */
+	if ((mem->flags & MAP_ACTIVE) == 0) {
+		t->current_space = as_none;
+		return 0;
+	}
+
+	/*
+	 * Disable first
+	 */
+	pcc_set(sock, PCCR, 0);
+
+	/*
+	 * Set mode
+	 */
+	if (mem->flags & MAP_ATTRIB) {
+		mode = PCMOD_AS_ATTRIB | PCMOD_CBSZ;
+		t->current_space = as_attr;
+	} else {
+		mode = 0; /* common memory */
+		t->current_space = as_comm;
+	}
+	pcc_set(sock, PCMOD, mode);
+
+	/*
+	 * Set address
+	 */
+	addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+	pcc_set(sock, PCADR, addr);
+
+	mem->static_start = addr + mem->card_start;
+
+	/*
+	 * Enable again
+	 */
+	pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+	if (last != as_attr) {
+#else
+	if (1) {
+#endif
+		dummy_readbuf = *(u_char *)(addr + KSEG1);
+	}
+#endif
+
+	return 0;
+
+} /* _set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+	pcc_socket_t *s = container_of(class_dev, struct pcc_socket,
+		socket.dev);
+
+	return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+		pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at
+ * some time... */
+#define LOCKED(x) do {					\
+	int retval;					\
+	unsigned long flags;				\
+	spin_lock_irqsave(&pcc_lock, flags);		\
+	retval = x;					\
+	spin_unlock_irqrestore(&pcc_lock, flags);	\
+	return retval;					\
+} while (0)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		*value = 0;
+		return -EINVAL;
+	}
+	LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(struct pcmcia_socket *s)
+{
+	pr_debug("m32r_pcc: init call\n");
+	return 0;
+}
+
+static struct pccard_operations pcc_operations = {
+	.init			= pcc_init,
+	.get_status		= pcc_get_status,
+	.set_socket		= pcc_set_socket,
+	.set_io_map		= pcc_set_io_map,
+	.set_mem_map		= pcc_set_mem_map,
+};
+
+/*====================================================================*/
+
+static struct platform_driver pcc_driver = {
+	.driver = {
+		.name		= "pcc",
+	},
+};
+
+static struct platform_device pcc_device = {
+	.name = "pcc",
+	.id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+	int i, ret;
+
+	ret = platform_driver_register(&pcc_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_device_register(&pcc_device);
+	if (ret)
+		goto unreg_driv;
+
+	printk(KERN_INFO "m32r PCC probe:\n");
+
+	pcc_sockets = 0;
+
+	ret = add_pcc_socket(M32R_PCC0_BASE, PCC0_IRQ, M32R_PCC0_MAPBASE,
+			     0x1000);
+	if (ret)
+		goto unreg_dev;
+
+#ifdef CONFIG_M32RPCC_SLOT2
+	ret = add_pcc_socket(M32R_PCC1_BASE, PCC1_IRQ, M32R_PCC1_MAPBASE,
+			     0x2000);
+	if (ret)
+		goto unreg_dev;
+#endif
+
+	if (pcc_sockets == 0) {
+		printk("socket is not found.\n");
+		ret = -ENODEV;
+		goto unreg_dev;
+	}
+
+	/* Set up interrupt handler(s) */
+
+	for (i = 0 ; i < pcc_sockets ; i++) {
+		socket[i].socket.dev.parent = &pcc_device.dev;
+		socket[i].socket.ops = &pcc_operations;
+		socket[i].socket.resource_ops = &pccard_static_ops;
+		socket[i].socket.owner = THIS_MODULE;
+		socket[i].number = i;
+		ret = pcmcia_register_socket(&socket[i].socket);
+		if (!ret)
+			socket[i].flags |= IS_REGISTERED;
+	}
+
+	/* Finally, schedule a polling interrupt */
+	if (poll_interval != 0) {
+		poll_timer.function = pcc_interrupt_wrapper;
+		poll_timer.data = 0;
+		init_timer(&poll_timer);
+		poll_timer.expires = jiffies + poll_interval;
+		add_timer(&poll_timer);
+	}
+
+	return 0;
+
+unreg_dev:
+	platform_device_unregister(&pcc_device);
+unreg_driv:
+	platform_driver_unregister(&pcc_driver);
+	return ret;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+	int i;
+
+	for (i = 0; i < pcc_sockets; i++)
+		if (socket[i].flags & IS_REGISTERED)
+			pcmcia_unregister_socket(&socket[i].socket);
+
+	platform_device_unregister(&pcc_device);
+	if (poll_interval != 0)
+		del_timer_sync(&poll_timer);
+
+	platform_driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.h b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.h
new file mode 100644
index 0000000..d99ad38
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/m32r_pcc.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+#define M32R_MAX_PCC	2
+
+/*
+ * M32R PC Card Controller
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB	(1UL<<(31-19))
+#define PCMOD_AS_IO	(1UL<<(31-18))
+
+#define PCMOD_CBSZ	(1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX	(1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX		 0x02000000
+
+#define M32R_PCC_MAPSIZE	 0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK     	(~(M32R_PCC_MAPMAX-1))
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/o2micro.h b/src/kernel/linux/v4.14/drivers/pcmcia/o2micro.h
new file mode 100644
index 0000000..5096e92
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/o2micro.h
@@ -0,0 +1,183 @@
+/*
+ * o2micro.h 1.13 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_O2MICRO_H
+#define _LINUX_O2MICRO_H
+
+/* Additional PCI configuration registers */
+
+#define O2_MUX_CONTROL		0x90	/* 32 bit */
+#define  O2_MUX_RING_OUT	0x0000000f
+#define  O2_MUX_SKTB_ACTV	0x000000f0
+#define  O2_MUX_SCTA_ACTV_ENA	0x00000100
+#define  O2_MUX_SCTB_ACTV_ENA	0x00000200
+#define  O2_MUX_SER_IRQ_ROUTE	0x0000e000
+#define  O2_MUX_SER_PCI		0x00010000
+
+#define  O2_MUX_SKTA_TURBO	0x000c0000	/* for 6833, 6860 */
+#define  O2_MUX_SKTB_TURBO	0x00300000
+#define  O2_MUX_AUX_VCC_3V	0x00400000
+#define  O2_MUX_PCI_VCC_5V	0x00800000
+#define  O2_MUX_PME_MUX		0x0f000000
+
+/* Additional ExCA registers */
+
+#define O2_MODE_A		0x38
+#define O2_MODE_A_2		0x26	/* for 6833B, 6860C */
+#define  O2_MODE_A_CD_PULSE	0x04
+#define  O2_MODE_A_SUSP_EDGE	0x08
+#define  O2_MODE_A_HOST_SUSP	0x10
+#define  O2_MODE_A_PWR_MASK	0x60
+#define  O2_MODE_A_QUIET	0x80
+
+#define O2_MODE_B		0x39
+#define O2_MODE_B_2		0x2e	/* for 6833B, 6860C */
+#define  O2_MODE_B_IDENT	0x03
+#define  O2_MODE_B_ID_BSTEP	0x00
+#define  O2_MODE_B_ID_CSTEP	0x01
+#define  O2_MODE_B_ID_O2	0x02
+#define  O2_MODE_B_VS1		0x04
+#define  O2_MODE_B_VS2		0x08
+#define  O2_MODE_B_IRQ15_RI	0x80
+
+#define O2_MODE_C		0x3a
+#define  O2_MODE_C_DREQ_MASK	0x03
+#define  O2_MODE_C_DREQ_INPACK	0x01
+#define  O2_MODE_C_DREQ_WP	0x02
+#define  O2_MODE_C_DREQ_BVD2	0x03
+#define  O2_MODE_C_ZVIDEO	0x08
+#define  O2_MODE_C_IREQ_SEL	0x30
+#define  O2_MODE_C_MGMT_SEL	0xc0
+
+#define O2_MODE_D		0x3b
+#define  O2_MODE_D_IRQ_MODE	0x03
+#define  O2_MODE_D_PCI_CLKRUN	0x04
+#define  O2_MODE_D_CB_CLKRUN	0x08
+#define  O2_MODE_D_SKT_ACTV	0x20
+#define  O2_MODE_D_PCI_FIFO	0x40	/* for OZ6729, OZ6730 */
+#define  O2_MODE_D_W97_IRQ	0x40
+#define  O2_MODE_D_ISA_IRQ	0x80
+
+#define O2_MHPG_DMA		0x3c
+#define  O2_MHPG_CHANNEL	0x07
+#define  O2_MHPG_CINT_ENA	0x08
+#define  O2_MHPG_CSC_ENA	0x10
+
+#define O2_FIFO_ENA		0x3d
+#define  O2_FIFO_ZVIDEO_3	0x08
+#define  O2_FIFO_PCI_FIFO	0x10
+#define  O2_FIFO_POSTWR		0x40
+#define  O2_FIFO_BUFFER		0x80
+
+#define O2_MODE_E		0x3e
+#define  O2_MODE_E_MHPG_DMA	0x01
+#define  O2_MODE_E_SPKR_OUT	0x02
+#define  O2_MODE_E_LED_OUT	0x08
+#define  O2_MODE_E_SKTA_ACTV	0x10
+
+#define O2_RESERVED1		0x94
+#define O2_RESERVED2		0xD4
+#define O2_RES_READ_PREFETCH	0x02
+#define O2_RES_WRITE_BURST	0x08
+
+static int o2micro_override(struct yenta_socket *socket)
+{
+	/*
+	 * 'reserved' register at 0x94/D4. allows setting read prefetch and write
+	 * bursting. read prefetching for example makes the RME Hammerfall DSP
+	 * working. for some bridges it is at 0x94, for others at 0xD4. it's
+	 * ok to write to both registers on all O2 bridges.
+	 * from Eric Still, 02Micro.
+	 */
+	u8 a, b;
+	bool use_speedup;
+
+	if (PCI_FUNC(socket->dev->devfn) == 0) {
+		a = config_readb(socket, O2_RESERVED1);
+		b = config_readb(socket, O2_RESERVED2);
+		dev_dbg(&socket->dev->dev, "O2: 0x94/0xD4: %02x/%02x\n", a, b);
+
+		switch (socket->dev->device) {
+		/*
+		 * older bridges have problems with both read prefetch and write
+		 * bursting depending on the combination of the chipset, bridge
+		 * and the cardbus card. so disable them to be on the safe side.
+		 */
+		case PCI_DEVICE_ID_O2_6729:
+		case PCI_DEVICE_ID_O2_6730:
+		case PCI_DEVICE_ID_O2_6812:
+		case PCI_DEVICE_ID_O2_6832:
+		case PCI_DEVICE_ID_O2_6836:
+		case PCI_DEVICE_ID_O2_6933:
+			use_speedup = false;
+			break;
+		default:
+			use_speedup = true;
+			break;
+		}
+
+		/* the user may override our decision */
+		if (strcasecmp(o2_speedup, "on") == 0)
+			use_speedup = true;
+		else if (strcasecmp(o2_speedup, "off") == 0)
+			use_speedup = false;
+		else if (strcasecmp(o2_speedup, "default") != 0)
+			dev_warn(&socket->dev->dev,
+				"O2: Unknown parameter, using 'default'");
+
+		if (use_speedup) {
+			dev_info(&socket->dev->dev,
+				"O2: enabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=off'\n");
+			config_writeb(socket, O2_RESERVED1,
+				      a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+			config_writeb(socket, O2_RESERVED2,
+				      b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+		} else {
+			dev_info(&socket->dev->dev,
+				"O2: disabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=on'\n");
+			config_writeb(socket, O2_RESERVED1,
+				      a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
+			config_writeb(socket, O2_RESERVED2,
+				      b & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
+		}
+	}
+
+	return 0;
+}
+
+static void o2micro_restore_state(struct yenta_socket *socket)
+{
+	/*
+	 * as long as read prefetch is the only thing in
+	 * o2micro_override, it's safe to call it from here
+	 */
+	o2micro_override(socket);
+}
+
+#endif /* _LINUX_O2MICRO_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/omap_cf.c b/src/kernel/linux/v4.14/drivers/pcmcia/omap_cf.c
new file mode 100644
index 0000000..4e2f501
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/omap_cf.c
@@ -0,0 +1,357 @@
+/*
+ * omap_cf.c -- OMAP 16xx CompactFlash controller driver
+ *
+ * Copyright (c) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <pcmcia/ss.h>
+
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <mach/mux.h>
+#include <mach/tc.h>
+
+
+/* NOTE:  don't expect this to support many I/O cards.  The 16xx chips have
+ * hard-wired timings to support Compact Flash memory cards; they won't work
+ * with various other devices (like WLAN adapters) without some external
+ * logic to help out.
+ *
+ * NOTE:  CF controller docs disagree with address space docs as to where
+ * CF_BASE really lives; this is a doc erratum.
+ */
+#define	CF_BASE	0xfffe2800
+
+/* status; read after IRQ */
+#define CF_STATUS			(CF_BASE + 0x00)
+#	define	CF_STATUS_BAD_READ	(1 << 2)
+#	define	CF_STATUS_BAD_WRITE	(1 << 1)
+#	define	CF_STATUS_CARD_DETECT	(1 << 0)
+
+/* which chipselect (CS0..CS3) is used for CF (active low) */
+#define CF_CFG				(CF_BASE + 0x02)
+
+/* card reset */
+#define CF_CONTROL			(CF_BASE + 0x04)
+#	define	CF_CONTROL_RESET	(1 << 0)
+
+#define omap_cf_present() (!(omap_readw(CF_STATUS) & CF_STATUS_CARD_DETECT))
+
+/*--------------------------------------------------------------------------*/
+
+static const char driver_name[] = "omap_cf";
+
+struct omap_cf_socket {
+	struct pcmcia_socket	socket;
+
+	struct timer_list	timer;
+	unsigned		present:1;
+	unsigned		active:1;
+
+	struct platform_device	*pdev;
+	unsigned long		phys_cf;
+	u_int			irq;
+	struct resource		iomem;
+};
+
+#define	POLL_INTERVAL		(2 * HZ)
+
+/*--------------------------------------------------------------------------*/
+
+static int omap_cf_ss_init(struct pcmcia_socket *s)
+{
+	return 0;
+}
+
+/* the timer is primarily to kick this socket's pccardd */
+static void omap_cf_timer(unsigned long _cf)
+{
+	struct omap_cf_socket	*cf = (void *) _cf;
+	unsigned		present = omap_cf_present();
+
+	if (present != cf->present) {
+		cf->present = present;
+		pr_debug("%s: card %s\n", driver_name,
+			present ? "present" : "gone");
+		pcmcia_parse_events(&cf->socket, SS_DETECT);
+	}
+
+	if (cf->active)
+		mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+}
+
+/* This irq handler prevents "irqNNN: nobody cared" messages as drivers
+ * claim the card's IRQ.  It may also detect some card insertions, but
+ * not removals; it can't always eliminate timer irqs.
+ */
+static irqreturn_t omap_cf_irq(int irq, void *_cf)
+{
+	omap_cf_timer((unsigned long)_cf);
+	return IRQ_HANDLED;
+}
+
+static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+	if (!sp)
+		return -EINVAL;
+
+	/* NOTE CF is always 3VCARD */
+	if (omap_cf_present()) {
+		struct omap_cf_socket	*cf;
+
+		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+		cf = container_of(s, struct omap_cf_socket, socket);
+		s->pcmcia_irq = 0;
+		s->pci_irq = cf->irq;
+	} else
+		*sp = 0;
+	return 0;
+}
+
+static int
+omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+	u16		control;
+
+	/* REVISIT some non-OSK boards may support power switching */
+	switch (s->Vcc) {
+	case 0:
+	case 33:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	control = omap_readw(CF_CONTROL);
+	if (s->flags & SS_RESET)
+		omap_writew(CF_CONTROL_RESET, CF_CONTROL);
+	else
+		omap_writew(0, CF_CONTROL);
+
+	pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
+		driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+	return 0;
+}
+
+static int omap_cf_ss_suspend(struct pcmcia_socket *s)
+{
+	pr_debug("%s: %s\n", driver_name, __func__);
+	return omap_cf_set_socket(s, &dead_socket);
+}
+
+/* regions are 2K each:  mem, attrib, io (and reserved-for-ide) */
+
+static int
+omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	struct omap_cf_socket	*cf;
+
+	cf = container_of(s, struct omap_cf_socket, socket);
+	io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
+	io->start = cf->phys_cf + SZ_4K;
+	io->stop = io->start + SZ_2K - 1;
+	return 0;
+}
+
+static int
+omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+	struct omap_cf_socket	*cf;
+
+	if (map->card_start)
+		return -EINVAL;
+	cf = container_of(s, struct omap_cf_socket, socket);
+	map->static_start = cf->phys_cf;
+	map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
+	if (map->flags & MAP_ATTRIB)
+		map->static_start += SZ_2K;
+	return 0;
+}
+
+static struct pccard_operations omap_cf_ops = {
+	.init			= omap_cf_ss_init,
+	.suspend		= omap_cf_ss_suspend,
+	.get_status		= omap_cf_get_status,
+	.set_socket		= omap_cf_set_socket,
+	.set_io_map		= omap_cf_set_io_map,
+	.set_mem_map		= omap_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * NOTE:  right now the only board-specific platform_data is
+ * "what chipselect is used".  Boards could want more.
+ */
+
+static int __init omap_cf_probe(struct platform_device *pdev)
+{
+	unsigned		seg;
+	struct omap_cf_socket	*cf;
+	int			irq;
+	int			status;
+
+	seg = (int) pdev->dev.platform_data;
+	if (seg == 0 || seg > 3)
+		return -ENODEV;
+
+	/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -EINVAL;
+
+	cf = kzalloc(sizeof *cf, GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+	setup_timer(&cf->timer, omap_cf_timer, (unsigned long)cf);
+
+	cf->pdev = pdev;
+	platform_set_drvdata(pdev, cf);
+
+	/* this primarily just shuts up irq handling noise */
+	status = request_irq(irq, omap_cf_irq, IRQF_SHARED,
+			driver_name, cf);
+	if (status < 0)
+		goto fail0;
+	cf->irq = irq;
+	cf->socket.pci_irq = irq;
+
+	switch (seg) {
+	/* NOTE: CS0 could be configured too ... */
+	case 1:
+		cf->phys_cf = OMAP_CS1_PHYS;
+		break;
+	case 2:
+		cf->phys_cf = OMAP_CS2_PHYS;
+		break;
+	case 3:
+		cf->phys_cf = omap_cs3_phys();
+		break;
+	default:
+		goto  fail1;
+	}
+	cf->iomem.start = cf->phys_cf;
+	cf->iomem.end = cf->iomem.end + SZ_8K - 1;
+	cf->iomem.flags = IORESOURCE_MEM;
+
+	/* pcmcia layer only remaps "real" memory */
+	cf->socket.io_offset = (unsigned long)
+			ioremap(cf->phys_cf + SZ_4K, SZ_2K);
+	if (!cf->socket.io_offset)
+		goto fail1;
+
+	if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name))
+		goto fail1;
+
+	/* NOTE:  CF conflicts with MMC1 */
+	omap_cfg_reg(W11_1610_CF_CD1);
+	omap_cfg_reg(P11_1610_CF_CD2);
+	omap_cfg_reg(R11_1610_CF_IOIS16);
+	omap_cfg_reg(V10_1610_CF_IREQ);
+	omap_cfg_reg(W10_1610_CF_RESET);
+
+	omap_writew(~(1 << seg), CF_CFG);
+
+	pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq);
+
+	/* NOTE:  better EMIFS setup might support more cards; but the
+	 * TRM only shows how to affect regular flash signals, not their
+	 * CF/PCMCIA variants...
+	 */
+	pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", driver_name,
+		seg, omap_readl(EMIFS_CCS(seg)), omap_readl(EMIFS_ACS(seg)));
+	omap_writel(0x0004a1b3, EMIFS_CCS(seg));	/* synch mode 4 etc */
+	omap_writel(0x00000000, EMIFS_ACS(seg));	/* OE hold/setup */
+
+	/* CF uses armxor_ck, which is "always" available */
+
+	pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name,
+		omap_readw(CF_STATUS), omap_readw(CF_CFG),
+		omap_readw(CF_CONTROL),
+		omap_cf_present() ? "present" : "(not present)");
+
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.dev.parent = &pdev->dev;
+	cf->socket.ops = &omap_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+				| SS_CAP_MEM_ALIGN;
+	cf->socket.map_size = SZ_2K;
+	cf->socket.io[0].res = &cf->iomem;
+
+	status = pcmcia_register_socket(&cf->socket);
+	if (status < 0)
+		goto fail2;
+
+	cf->active = 1;
+	mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+	return 0;
+
+fail2:
+	release_mem_region(cf->phys_cf, SZ_8K);
+fail1:
+	if (cf->socket.io_offset)
+		iounmap((void __iomem *) cf->socket.io_offset);
+	free_irq(irq, cf);
+fail0:
+	kfree(cf);
+	return status;
+}
+
+static int __exit omap_cf_remove(struct platform_device *pdev)
+{
+	struct omap_cf_socket *cf = platform_get_drvdata(pdev);
+
+	cf->active = 0;
+	pcmcia_unregister_socket(&cf->socket);
+	del_timer_sync(&cf->timer);
+	iounmap((void __iomem *) cf->socket.io_offset);
+	release_mem_region(cf->phys_cf, SZ_8K);
+	free_irq(cf->irq, cf);
+	kfree(cf);
+	return 0;
+}
+
+static struct platform_driver omap_cf_driver = {
+	.driver = {
+		.name	= (char *) driver_name,
+	},
+	.remove		= __exit_p(omap_cf_remove),
+};
+
+static int __init omap_cf_init(void)
+{
+	if (cpu_is_omap16xx())
+		return platform_driver_probe(&omap_cf_driver, omap_cf_probe);
+	return -ENODEV;
+}
+
+static void __exit omap_cf_exit(void)
+{
+	if (cpu_is_omap16xx())
+		platform_driver_unregister(&omap_cf_driver);
+}
+
+module_init(omap_cf_init);
+module_exit(omap_cf_exit);
+
+MODULE_DESCRIPTION("OMAP CF Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap_cf");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_cis.c b/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_cis.c
new file mode 100644
index 0000000..1c05d74
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_cis.c
@@ -0,0 +1,438 @@
+/*
+ * PCMCIA high-level CIS access functions
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Copyright (C) 1999	     David A. Hinds
+ * Copyright (C) 2004-2010   Dominik Brodowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/ds.h>
+#include "cs_internal.h"
+
+
+/**
+ * pccard_read_tuple() - internal CIS tuple access
+ * @s:		the struct pcmcia_socket where the card is inserted
+ * @function:	the device function we loop for
+ * @code:	which CIS code shall we look for?
+ * @parse:	buffer where the tuple shall be parsed (or NULL, if no parse)
+ *
+ * pccard_read_tuple() reads out one tuple and attempts to parse it
+ */
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
+		cisdata_t code, void *parse)
+{
+	tuple_t tuple;
+	cisdata_t *buf;
+	int ret;
+
+	buf = kmalloc(256, GFP_KERNEL);
+	if (buf == NULL) {
+		dev_warn(&s->dev, "no memory to read tuple\n");
+		return -ENOMEM;
+	}
+	tuple.DesiredTuple = code;
+	tuple.Attributes = 0;
+	if (function == BIND_FN_ALL)
+		tuple.Attributes = TUPLE_RETURN_COMMON;
+	ret = pccard_get_first_tuple(s, function, &tuple);
+	if (ret != 0)
+		goto done;
+	tuple.TupleData = buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	ret = pccard_get_tuple_data(s, &tuple);
+	if (ret != 0)
+		goto done;
+	ret = pcmcia_parse_tuple(&tuple, parse);
+done:
+	kfree(buf);
+	return ret;
+}
+
+
+/**
+ * pccard_loop_tuple() - loop over tuples in the CIS
+ * @s:		the struct pcmcia_socket where the card is inserted
+ * @function:	the device function we loop for
+ * @code:	which CIS code shall we look for?
+ * @parse:	buffer where the tuple shall be parsed (or NULL, if no parse)
+ * @priv_data:	private data to be passed to the loop_tuple function.
+ * @loop_tuple:	function to call for each CIS entry of type @function. IT
+ *		gets passed the raw tuple, the paresed tuple (if @parse is
+ *		set) and @priv_data.
+ *
+ * pccard_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
+		      cisdata_t code, cisparse_t *parse, void *priv_data,
+		      int (*loop_tuple) (tuple_t *tuple,
+					 cisparse_t *parse,
+					 void *priv_data))
+{
+	tuple_t tuple;
+	cisdata_t *buf;
+	int ret;
+
+	buf = kzalloc(256, GFP_KERNEL);
+	if (buf == NULL) {
+		dev_warn(&s->dev, "no memory to read tuple\n");
+		return -ENOMEM;
+	}
+
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = 255;
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = code;
+	tuple.Attributes = 0;
+
+	ret = pccard_get_first_tuple(s, function, &tuple);
+	while (!ret) {
+		if (pccard_get_tuple_data(s, &tuple))
+			goto next_entry;
+
+		if (parse)
+			if (pcmcia_parse_tuple(&tuple, parse))
+				goto next_entry;
+
+		ret = loop_tuple(&tuple, parse, priv_data);
+		if (!ret)
+			break;
+
+next_entry:
+		ret = pccard_get_next_tuple(s, function, &tuple);
+	}
+
+	kfree(buf);
+	return ret;
+}
+
+
+/**
+ * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter
+ */
+static int pcmcia_io_cfg_data_width(unsigned int flags)
+{
+	if (!(flags & CISTPL_IO_8BIT))
+		return IO_DATA_PATH_WIDTH_16;
+	if (!(flags & CISTPL_IO_16BIT))
+		return IO_DATA_PATH_WIDTH_8;
+	return IO_DATA_PATH_WIDTH_AUTO;
+}
+
+
+struct pcmcia_cfg_mem {
+	struct pcmcia_device *p_dev;
+	int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data);
+	void *priv_data;
+	cisparse_t parse;
+	cistpl_cftable_entry_t dflt;
+};
+
+/**
+ * pcmcia_do_loop_config() - internal helper for pcmcia_loop_config()
+ *
+ * pcmcia_do_loop_config() is the internal callback for the call from
+ * pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred
+ * by a struct pcmcia_cfg_mem.
+ */
+static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
+{
+	struct pcmcia_cfg_mem *cfg_mem = priv;
+	struct pcmcia_device *p_dev = cfg_mem->p_dev;
+	cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
+	cistpl_cftable_entry_t *dflt = &cfg_mem->dflt;
+	unsigned int flags = p_dev->config_flags;
+	unsigned int vcc = p_dev->socket->socket.Vcc;
+
+	dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n",
+		cfg->index, flags);
+
+	/* default values */
+	cfg_mem->p_dev->config_index = cfg->index;
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+		cfg_mem->dflt = *cfg;
+
+	/* check for matching Vcc? */
+	if (flags & CONF_AUTO_CHECK_VCC) {
+		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+				return -ENODEV;
+		}
+	}
+
+	/* set Vpp? */
+	if (flags & CONF_AUTO_SET_VPP) {
+		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+			p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+			p_dev->vpp =
+				dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+	}
+
+	/* enable audio? */
+	if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO))
+		p_dev->config_flags |= CONF_ENABLE_SPKR;
+
+
+	/* IO window settings? */
+	if (flags & CONF_AUTO_SET_IO) {
+		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+		int i = 0;
+
+		p_dev->resource[0]->start = p_dev->resource[0]->end = 0;
+		p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
+		if (io->nwin == 0)
+			return -ENODEV;
+
+		p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+		p_dev->resource[0]->flags |=
+					pcmcia_io_cfg_data_width(io->flags);
+		if (io->nwin > 1) {
+			/* For multifunction cards, by convention, we
+			 * configure the network function with window 0,
+			 * and serial with window 1 */
+			i = (io->win[1].len > io->win[0].len);
+			p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+			p_dev->resource[1]->start = io->win[1-i].base;
+			p_dev->resource[1]->end = io->win[1-i].len;
+		}
+		p_dev->resource[0]->start = io->win[i].base;
+		p_dev->resource[0]->end = io->win[i].len;
+		p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+	}
+
+	/* MEM window settings? */
+	if (flags & CONF_AUTO_SET_IOMEM) {
+		/* so far, we only set one memory window */
+		cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+
+		p_dev->resource[2]->start = p_dev->resource[2]->end = 0;
+		if (mem->nwin == 0)
+			return -ENODEV;
+
+		p_dev->resource[2]->start = mem->win[0].host_addr;
+		p_dev->resource[2]->end = mem->win[0].len;
+		if (p_dev->resource[2]->end < 0x1000)
+			p_dev->resource[2]->end = 0x1000;
+		p_dev->card_addr = mem->win[0].card_addr;
+	}
+
+	dev_dbg(&p_dev->dev,
+		"checking configuration %x: %pr %pr %pr (%d lines)\n",
+		p_dev->config_index, p_dev->resource[0], p_dev->resource[1],
+		p_dev->resource[2], p_dev->io_lines);
+
+	return cfg_mem->conf_check(p_dev, cfg_mem->priv_data);
+}
+
+/**
+ * pcmcia_loop_config() - loop over configuration options
+ * @p_dev:	the struct pcmcia_device which we need to loop for.
+ * @conf_check:	function to call for each configuration option.
+ *		It gets passed the struct pcmcia_device and private data
+ *		being passed to pcmcia_loop_config()
+ * @priv_data:	private data to be passed to the conf_check function.
+ *
+ * pcmcia_loop_config() loops over all configuration options, and calls
+ * the driver-specific conf_check() for each one, checking whether
+ * it is a valid one. Returns 0 on success or errorcode otherwise.
+ */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+		       int	(*conf_check)	(struct pcmcia_device *p_dev,
+						 void *priv_data),
+		       void *priv_data)
+{
+	struct pcmcia_cfg_mem *cfg_mem;
+	int ret;
+
+	cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
+	if (cfg_mem == NULL)
+		return -ENOMEM;
+
+	cfg_mem->p_dev = p_dev;
+	cfg_mem->conf_check = conf_check;
+	cfg_mem->priv_data = priv_data;
+
+	ret = pccard_loop_tuple(p_dev->socket, p_dev->func,
+				CISTPL_CFTABLE_ENTRY, &cfg_mem->parse,
+				cfg_mem, pcmcia_do_loop_config);
+
+	kfree(cfg_mem);
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_loop_config);
+
+
+struct pcmcia_loop_mem {
+	struct pcmcia_device *p_dev;
+	void *priv_data;
+	int (*loop_tuple) (struct pcmcia_device *p_dev,
+			   tuple_t *tuple,
+			   void *priv_data);
+};
+
+/**
+ * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
+ *
+ * pcmcia_do_loop_tuple() is the internal callback for the call from
+ * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
+ * by a struct pcmcia_cfg_mem.
+ */
+static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
+{
+	struct pcmcia_loop_mem *loop = priv;
+
+	return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
+};
+
+/**
+ * pcmcia_loop_tuple() - loop over tuples in the CIS
+ * @p_dev:	the struct pcmcia_device which we need to loop for.
+ * @code:	which CIS code shall we look for?
+ * @priv_data:	private data to be passed to the loop_tuple function.
+ * @loop_tuple:	function to call for each CIS entry of type @function. IT
+ *		gets passed the raw tuple and @priv_data.
+ *
+ * pcmcia_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+		      int (*loop_tuple) (struct pcmcia_device *p_dev,
+					 tuple_t *tuple,
+					 void *priv_data),
+		      void *priv_data)
+{
+	struct pcmcia_loop_mem loop = {
+		.p_dev = p_dev,
+		.loop_tuple = loop_tuple,
+		.priv_data = priv_data};
+
+	return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
+				 &loop, pcmcia_do_loop_tuple);
+}
+EXPORT_SYMBOL(pcmcia_loop_tuple);
+
+
+struct pcmcia_loop_get {
+	size_t len;
+	cisdata_t **buf;
+};
+
+/**
+ * pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple()
+ *
+ * pcmcia_do_get_tuple() is the internal callback for the call from
+ * pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in
+ * the first tuple, return 0 unconditionally. Create a memory buffer large
+ * enough to hold the content of the tuple, and fill it with the tuple data.
+ * The caller is responsible to free the buffer.
+ */
+static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
+			       void *priv)
+{
+	struct pcmcia_loop_get *get = priv;
+
+	*get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL);
+	if (*get->buf) {
+		get->len = tuple->TupleDataLen;
+		memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen);
+	} else
+		dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n");
+	return 0;
+}
+
+/**
+ * pcmcia_get_tuple() - get first tuple from CIS
+ * @p_dev:	the struct pcmcia_device which we need to loop for.
+ * @code:	which CIS code shall we look for?
+ * @buf:        pointer to store the buffer to.
+ *
+ * pcmcia_get_tuple() gets the content of the first CIS entry of type @code.
+ * It returns the buffer length (or zero). The caller is responsible to free
+ * the buffer passed in @buf.
+ */
+size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+			unsigned char **buf)
+{
+	struct pcmcia_loop_get get = {
+		.len = 0,
+		.buf = buf,
+	};
+
+	*get.buf = NULL;
+	pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
+
+	return get.len;
+}
+EXPORT_SYMBOL(pcmcia_get_tuple);
+
+
+/**
+ * pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis()
+ *
+ * pcmcia_do_get_mac() is the internal callback for the call from
+ * pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the
+ * tuple contains a proper LAN_NODE_ID of length 6, and copy the data
+ * to struct net_device->dev_addr[i].
+ */
+static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
+			     void *priv)
+{
+	struct net_device *dev = priv;
+	int i;
+
+	if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
+		return -EINVAL;
+	if (tuple->TupleDataLen < ETH_ALEN + 2) {
+		dev_warn(&p_dev->dev, "Invalid CIS tuple length for "
+			"LAN_NODE_ID\n");
+		return -EINVAL;
+	}
+
+	if (tuple->TupleData[1] != ETH_ALEN) {
+		dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = tuple->TupleData[i+2];
+	return 0;
+}
+
+/**
+ * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
+ * @p_dev:	the struct pcmcia_device for which we want the address.
+ * @dev:	a properly prepared struct net_device to store the info to.
+ *
+ * pcmcia_get_mac_from_cis() reads out the hardware MAC address from
+ * CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which
+ * must be set up properly by the driver (see examples!).
+ */
+int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
+{
+	return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
+}
+EXPORT_SYMBOL(pcmcia_get_mac_from_cis);
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_resource.c b/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_resource.c
new file mode 100644
index 0000000..34aad89
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pcmcia_resource.c
@@ -0,0 +1,997 @@
+/*
+ * PCMCIA 16-bit resource management functions
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Copyright (C) 1999	     David A. Hinds
+ * Copyright (C) 2004-2010   Dominik Brodowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "cs_internal.h"
+
+
+/* Access speed for IO windows */
+static int io_speed;
+module_param(io_speed, int, 0444);
+
+
+int pcmcia_validate_mem(struct pcmcia_socket *s)
+{
+	if (s->resource_ops->validate_mem)
+		return s->resource_ops->validate_mem(s);
+	/* if there is no callback, we can assume that everything is OK */
+	return 0;
+}
+
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
+				 int low, struct pcmcia_socket *s)
+{
+	if (s->resource_ops->find_mem)
+		return s->resource_ops->find_mem(base, num, align, low, s);
+	return NULL;
+}
+
+
+/**
+ * release_io_space() - release IO ports allocated with alloc_io_space()
+ * @s: pcmcia socket
+ * @res: resource to release
+ *
+ */
+static void release_io_space(struct pcmcia_socket *s, struct resource *res)
+{
+	resource_size_t num = resource_size(res);
+	int i;
+
+	dev_dbg(&s->dev, "release_io_space for %pR\n", res);
+
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		if (!s->io[i].res)
+			continue;
+		if ((s->io[i].res->start <= res->start) &&
+		    (s->io[i].res->end >= res->end)) {
+			s->io[i].InUse -= num;
+			if (res->parent)
+				release_resource(res);
+			res->start = res->end = 0;
+			res->flags = IORESOURCE_IO;
+			/* Free the window if no one else is using it */
+			if (s->io[i].InUse == 0) {
+				release_resource(s->io[i].res);
+				kfree(s->io[i].res);
+				s->io[i].res = NULL;
+			}
+		}
+	}
+}
+
+
+/**
+ * alloc_io_space() - allocate IO ports for use by a PCMCIA device
+ * @s: pcmcia socket
+ * @res: resource to allocate (begin: begin, end: size)
+ * @lines: number of IO lines decoded by the PCMCIA card
+ *
+ * Special stuff for managing IO windows, because they are scarce
+ */
+static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
+			unsigned int lines)
+{
+	unsigned int align;
+	unsigned int base = res->start;
+	unsigned int num = res->end;
+	int ret;
+
+	res->flags |= IORESOURCE_IO;
+
+	dev_dbg(&s->dev, "alloc_io_space request for %pR, %d lines\n",
+		res, lines);
+
+	align = base ? (lines ? 1<<lines : 0) : 1;
+	if (align && (align < num)) {
+		if (base) {
+			dev_dbg(&s->dev, "odd IO request\n");
+			align = 0;
+		} else
+			while (align && (align < num))
+				align <<= 1;
+	}
+	if (base & ~(align-1)) {
+		dev_dbg(&s->dev, "odd IO request\n");
+		align = 0;
+	}
+
+	ret = s->resource_ops->find_io(s, res->flags, &base, num, align,
+				&res->parent);
+	if (ret) {
+		dev_dbg(&s->dev, "alloc_io_space request failed (%d)\n", ret);
+		return -EINVAL;
+	}
+
+	res->start = base;
+	res->end = res->start + num - 1;
+
+	if (res->parent) {
+		ret = request_resource(res->parent, res);
+		if (ret) {
+			dev_warn(&s->dev,
+				"request_resource %pR failed: %d\n", res, ret);
+			res->parent = NULL;
+			release_io_space(s, res);
+		}
+	}
+	dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res);
+	return ret;
+}
+
+
+/**
+ * pcmcia_access_config() - read or write card configuration registers
+ *
+ * pcmcia_access_config() reads and writes configuration registers in
+ * attribute memory.  Memory window 0 is reserved for this and the tuple
+ * reading services. Drivers must use pcmcia_read_config_byte() or
+ * pcmcia_write_config_byte().
+ */
+static int pcmcia_access_config(struct pcmcia_device *p_dev,
+				off_t where, u8 *val,
+				int (*accessf) (struct pcmcia_socket *s,
+						int attr, unsigned int addr,
+						unsigned int len, void *ptr))
+{
+	struct pcmcia_socket *s;
+	config_t *c;
+	int addr;
+	int ret = 0;
+
+	s = p_dev->socket;
+
+	mutex_lock(&s->ops_mutex);
+	c = p_dev->function_config;
+
+	if (!(c->state & CONFIG_LOCKED)) {
+		dev_dbg(&p_dev->dev, "Configuration isn't locked\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EACCES;
+	}
+
+	addr = (p_dev->config_base + where) >> 1;
+
+	ret = accessf(s, 1, addr, 1, val);
+
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+}
+
+
+/**
+ * pcmcia_read_config_byte() - read a byte from a card configuration register
+ *
+ * pcmcia_read_config_byte() reads a byte from a configuration register in
+ * attribute memory.
+ */
+int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val)
+{
+	return pcmcia_access_config(p_dev, where, val, pcmcia_read_cis_mem);
+}
+EXPORT_SYMBOL(pcmcia_read_config_byte);
+
+
+/**
+ * pcmcia_write_config_byte() - write a byte to a card configuration register
+ *
+ * pcmcia_write_config_byte() writes a byte to a configuration register in
+ * attribute memory.
+ */
+int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val)
+{
+	return pcmcia_access_config(p_dev, where, &val, pcmcia_write_cis_mem);
+}
+EXPORT_SYMBOL(pcmcia_write_config_byte);
+
+
+/**
+ * pcmcia_map_mem_page() - modify iomem window to point to a different offset
+ * @p_dev: pcmcia device
+ * @res: iomem resource already enabled by pcmcia_request_window()
+ * @offset: card_offset to map
+ *
+ * pcmcia_map_mem_page() modifies what can be read and written by accessing
+ * an iomem range previously enabled by pcmcia_request_window(), by setting
+ * the card_offset value to @offset.
+ */
+int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res,
+			unsigned int offset)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	unsigned int w;
+	int ret;
+
+	w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1;
+	if (w >= MAX_WIN)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	s->win[w].card_start = offset;
+	ret = s->ops->set_mem_map(s, &s->win[w]);
+	if (ret)
+		dev_warn(&p_dev->dev, "failed to set_mem_map\n");
+	mutex_unlock(&s->ops_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_map_mem_page);
+
+
+/**
+ * pcmcia_fixup_iowidth() - reduce io width to 8bit
+ * @p_dev: pcmcia device
+ *
+ * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the
+ * IO width to 8bit after having called pcmcia_enable_device()
+ * previously.
+ */
+int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	pccard_io_map io_off = { 0, 0, 0, 0, 1 };
+	pccard_io_map io_on;
+	int i, ret = 0;
+
+	mutex_lock(&s->ops_mutex);
+
+	dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n");
+
+	if (!(s->state & SOCKET_PRESENT) ||
+		!(p_dev->function_config->state & CONFIG_LOCKED)) {
+		dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
+		ret = -EACCES;
+		goto unlock;
+	}
+
+	io_on.speed = io_speed;
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		if (!s->io[i].res)
+			continue;
+		io_off.map = i;
+		io_on.map = i;
+
+		io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
+		io_on.start = s->io[i].res->start;
+		io_on.stop = s->io[i].res->end;
+
+		s->ops->set_io_map(s, &io_off);
+		mdelay(40);
+		s->ops->set_io_map(s, &io_on);
+	}
+unlock:
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_fixup_iowidth);
+
+
+/**
+ * pcmcia_fixup_vpp() - set Vpp to a new voltage level
+ * @p_dev: pcmcia device
+ * @new_vpp: new Vpp voltage
+ *
+ * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to
+ * a new voltage level between calls to pcmcia_enable_device()
+ * and pcmcia_disable_device().
+ */
+int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	int ret = 0;
+
+	mutex_lock(&s->ops_mutex);
+
+	dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp);
+
+	if (!(s->state & SOCKET_PRESENT) ||
+		!(p_dev->function_config->state & CONFIG_LOCKED)) {
+		dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
+		ret = -EACCES;
+		goto unlock;
+	}
+
+	s->socket.Vpp = new_vpp;
+	if (s->ops->set_socket(s, &s->socket)) {
+		dev_warn(&p_dev->dev, "Unable to set VPP\n");
+		ret = -EIO;
+		goto unlock;
+	}
+	p_dev->vpp = new_vpp;
+
+unlock:
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_fixup_vpp);
+
+
+/**
+ * pcmcia_release_configuration() - physically disable a PCMCIA device
+ * @p_dev: pcmcia device
+ *
+ * pcmcia_release_configuration() is the 1:1 counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used by any
+ * driver, the Vpp voltage is set to 0, IRQs will no longer be generated,
+ * and I/O ranges will be disabled. As pcmcia_release_io() and
+ * pcmcia_release_window() still need to be called, device drivers are
+ * expected to call pcmcia_disable_device() instead.
+ */
+int pcmcia_release_configuration(struct pcmcia_device *p_dev)
+{
+	pccard_io_map io = { 0, 0, 0, 0, 1 };
+	struct pcmcia_socket *s = p_dev->socket;
+	config_t *c;
+	int i;
+
+	mutex_lock(&s->ops_mutex);
+	c = p_dev->function_config;
+	if (p_dev->_locked) {
+		p_dev->_locked = 0;
+		if (--(s->lock_count) == 0) {
+			s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
+			s->socket.Vpp = 0;
+			s->socket.io_irq = 0;
+			s->ops->set_socket(s, &s->socket);
+		}
+	}
+	if (c->state & CONFIG_LOCKED) {
+		c->state &= ~CONFIG_LOCKED;
+		if (c->state & CONFIG_IO_REQ)
+			for (i = 0; i < MAX_IO_WIN; i++) {
+				if (!s->io[i].res)
+					continue;
+				s->io[i].Config--;
+				if (s->io[i].Config != 0)
+					continue;
+				io.map = i;
+				s->ops->set_io_map(s, &io);
+			}
+	}
+	mutex_unlock(&s->ops_mutex);
+
+	return 0;
+}
+
+
+/**
+ * pcmcia_release_io() - release I/O allocated by a PCMCIA device
+ * @p_dev: pcmcia device
+ *
+ * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA
+ * device.  This may be invoked some time after a card ejection has
+ * already dumped the actual socket configuration, so if the client is
+ * "stale", we don't bother checking the port ranges against the
+ * current socket values.
+ */
+static int pcmcia_release_io(struct pcmcia_device *p_dev)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	int ret = -EINVAL;
+	config_t *c;
+
+	mutex_lock(&s->ops_mutex);
+	if (!p_dev->_io)
+		goto out;
+
+	c = p_dev->function_config;
+
+	release_io_space(s, &c->io[0]);
+
+	if (c->io[1].end)
+		release_io_space(s, &c->io[1]);
+
+	p_dev->_io = 0;
+	c->state &= ~CONFIG_IO_REQ;
+
+out:
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+} /* pcmcia_release_io */
+
+
+/**
+ * pcmcia_release_window() - release reserved iomem for PCMCIA devices
+ * @p_dev: pcmcia device
+ * @res: iomem resource to release
+ *
+ * pcmcia_release_window() releases &struct resource *res which was
+ * previously reserved by calling pcmcia_request_window().
+ */
+int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	pccard_mem_map *win;
+	unsigned int w;
+
+	dev_dbg(&p_dev->dev, "releasing window %pR\n", res);
+
+	w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1;
+	if (w >= MAX_WIN)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	win = &s->win[w];
+
+	if (!(p_dev->_win & CLIENT_WIN_REQ(w))) {
+		dev_dbg(&p_dev->dev, "not releasing unknown window\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EINVAL;
+	}
+
+	/* Shut down memory window */
+	win->flags &= ~MAP_ACTIVE;
+	s->ops->set_mem_map(s, win);
+	s->state &= ~SOCKET_WIN_REQ(w);
+
+	/* Release system memory */
+	if (win->res) {
+		release_resource(res);
+		release_resource(win->res);
+		kfree(win->res);
+		win->res = NULL;
+	}
+	res->start = res->end = 0;
+	res->flags = IORESOURCE_MEM;
+	p_dev->_win &= ~CLIENT_WIN_REQ(w);
+	mutex_unlock(&s->ops_mutex);
+
+	return 0;
+} /* pcmcia_release_window */
+EXPORT_SYMBOL(pcmcia_release_window);
+
+
+/**
+ * pcmcia_enable_device() - set up and activate a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_enable_device() physically enables a PCMCIA device. It parses
+ * the flags passed to in @flags and stored in @p_dev->flags and sets up
+ * the Vpp voltage, enables the speaker line, I/O ports and store proper
+ * values to configuration registers.
+ */
+int pcmcia_enable_device(struct pcmcia_device *p_dev)
+{
+	int i;
+	unsigned int base;
+	struct pcmcia_socket *s = p_dev->socket;
+	config_t *c;
+	pccard_io_map iomap;
+	unsigned char status = 0;
+	unsigned char ext_status = 0;
+	unsigned char option = 0;
+	unsigned int flags = p_dev->config_flags;
+
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+
+	mutex_lock(&s->ops_mutex);
+	c = p_dev->function_config;
+	if (c->state & CONFIG_LOCKED) {
+		mutex_unlock(&s->ops_mutex);
+		dev_dbg(&p_dev->dev, "Configuration is locked\n");
+		return -EACCES;
+	}
+
+	/* Do power control.  We don't allow changes in Vcc. */
+	s->socket.Vpp = p_dev->vpp;
+	if (s->ops->set_socket(s, &s->socket)) {
+		mutex_unlock(&s->ops_mutex);
+		dev_warn(&p_dev->dev, "Unable to set socket state\n");
+		return -EINVAL;
+	}
+
+	/* Pick memory or I/O card, DMA mode, interrupt */
+	if (p_dev->_io || flags & CONF_ENABLE_IRQ)
+		flags |= CONF_ENABLE_IOCARD;
+	if (flags & CONF_ENABLE_IOCARD)
+		s->socket.flags |= SS_IOCARD;
+	if (flags & CONF_ENABLE_ZVCARD)
+		s->socket.flags |= SS_ZVCARD | SS_IOCARD;
+	if (flags & CONF_ENABLE_SPKR) {
+		s->socket.flags |= SS_SPKR_ENA;
+		status = CCSR_AUDIO_ENA;
+		if (!(p_dev->config_regs & PRESENT_STATUS))
+			dev_warn(&p_dev->dev, "speaker requested, but "
+					      "PRESENT_STATUS not set!\n");
+	}
+	if (flags & CONF_ENABLE_IRQ)
+		s->socket.io_irq = s->pcmcia_irq;
+	else
+		s->socket.io_irq = 0;
+	if (flags & CONF_ENABLE_ESR) {
+		p_dev->config_regs |= PRESENT_EXT_STATUS;
+		ext_status = ESR_REQ_ATTN_ENA;
+	}
+	s->ops->set_socket(s, &s->socket);
+	s->lock_count++;
+
+	dev_dbg(&p_dev->dev,
+		"enable_device: V %d, flags %x, base %x, regs %x, idx %x\n",
+		p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs,
+		p_dev->config_index);
+
+	/* Set up CIS configuration registers */
+	base = p_dev->config_base;
+	if (p_dev->config_regs & PRESENT_COPY) {
+		u16 tmp = 0;
+		dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n");
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp);
+	}
+	if (p_dev->config_regs & PRESENT_PIN_REPLACE) {
+		u16 tmp = 0;
+		dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n");
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp);
+	}
+	if (p_dev->config_regs & PRESENT_OPTION) {
+		if (s->functions == 1) {
+			option = p_dev->config_index & COR_CONFIG_MASK;
+		} else {
+			option = p_dev->config_index & COR_MFC_CONFIG_MASK;
+			option |= COR_FUNC_ENA|COR_IREQ_ENA;
+			if (p_dev->config_regs & PRESENT_IOBASE_0)
+				option |= COR_ADDR_DECODE;
+		}
+		if ((flags & CONF_ENABLE_IRQ) &&
+			!(flags & CONF_ENABLE_PULSE_IRQ))
+			option |= COR_LEVEL_REQ;
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
+		mdelay(40);
+	}
+	if (p_dev->config_regs & PRESENT_STATUS)
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
+
+	if (p_dev->config_regs & PRESENT_EXT_STATUS)
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1,
+					&ext_status);
+
+	if (p_dev->config_regs & PRESENT_IOBASE_0) {
+		u8 b = c->io[0].start & 0xff;
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
+		b = (c->io[0].start >> 8) & 0xff;
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
+	}
+	if (p_dev->config_regs & PRESENT_IOSIZE) {
+		u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
+		pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
+	}
+
+	/* Configure I/O windows */
+	if (c->state & CONFIG_IO_REQ) {
+		iomap.speed = io_speed;
+		for (i = 0; i < MAX_IO_WIN; i++)
+			if (s->io[i].res) {
+				iomap.map = i;
+				iomap.flags = MAP_ACTIVE;
+				switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) {
+				case IO_DATA_PATH_WIDTH_16:
+					iomap.flags |= MAP_16BIT; break;
+				case IO_DATA_PATH_WIDTH_AUTO:
+					iomap.flags |= MAP_AUTOSZ; break;
+				default:
+					break;
+				}
+				iomap.start = s->io[i].res->start;
+				iomap.stop = s->io[i].res->end;
+				s->ops->set_io_map(s, &iomap);
+				s->io[i].Config++;
+			}
+	}
+
+	c->state |= CONFIG_LOCKED;
+	p_dev->_locked = 1;
+	mutex_unlock(&s->ops_mutex);
+	return 0;
+} /* pcmcia_enable_device */
+EXPORT_SYMBOL(pcmcia_enable_device);
+
+
+/**
+ * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_request_io() attempts to reserve the IO port ranges specified in
+ * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The
+ * "start" value is the requested start of the IO port resource; "end"
+ * reflects the number of ports requested. The number of IO lines requested
+ * is specified in &struct pcmcia_device @p_dev->io_lines.
+ */
+int pcmcia_request_io(struct pcmcia_device *p_dev)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	config_t *c = p_dev->function_config;
+	int ret = -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	dev_dbg(&p_dev->dev, "pcmcia_request_io: %pR , %pR",
+		&c->io[0], &c->io[1]);
+
+	if (!(s->state & SOCKET_PRESENT)) {
+		dev_dbg(&p_dev->dev, "pcmcia_request_io: No card present\n");
+		goto out;
+	}
+
+	if (c->state & CONFIG_LOCKED) {
+		dev_dbg(&p_dev->dev, "Configuration is locked\n");
+		goto out;
+	}
+	if (c->state & CONFIG_IO_REQ) {
+		dev_dbg(&p_dev->dev, "IO already configured\n");
+		goto out;
+	}
+
+	ret = alloc_io_space(s, &c->io[0], p_dev->io_lines);
+	if (ret)
+		goto out;
+
+	if (c->io[1].end) {
+		ret = alloc_io_space(s, &c->io[1], p_dev->io_lines);
+		if (ret) {
+			struct resource tmp = c->io[0];
+			/* release the previously allocated resource */
+			release_io_space(s, &c->io[0]);
+			/* but preserve the settings, for they worked... */
+			c->io[0].end = resource_size(&tmp);
+			c->io[0].start = tmp.start;
+			c->io[0].flags = tmp.flags;
+			goto out;
+		}
+	} else
+		c->io[1].start = 0;
+
+	c->state |= CONFIG_IO_REQ;
+	p_dev->_io = 1;
+
+	dev_dbg(&p_dev->dev, "pcmcia_request_io succeeded: %pR , %pR",
+		&c->io[0], &c->io[1]);
+out:
+	mutex_unlock(&s->ops_mutex);
+
+	return ret;
+} /* pcmcia_request_io */
+EXPORT_SYMBOL(pcmcia_request_io);
+
+
+/**
+ * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
+ *
+ * pcmcia_request_irq() is a wrapper around request_irq() which allows
+ * the PCMCIA core to clean up the registration in pcmcia_disable_device().
+ * Drivers are free to use request_irq() directly, but then they need to
+ * call free_irq() themselfves, too. Also, only %IRQF_SHARED capable IRQ
+ * handlers are allowed.
+ */
+int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
+				    irq_handler_t handler)
+{
+	int ret;
+
+	if (!p_dev->irq)
+		return -EINVAL;
+
+	ret = request_irq(p_dev->irq, handler, IRQF_SHARED,
+			p_dev->devname, p_dev->priv);
+	if (!ret)
+		p_dev->_irq = 1;
+
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_request_irq);
+
+
+/**
+ * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
+ *
+ * pcmcia_request_exclusive_irq() is a wrapper around request_irq() which
+ * attempts first to request an exclusive IRQ. If it fails, it also accepts
+ * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for
+ * IRQ sharing and either use request_irq directly (then they need to call
+ * free_irq() themselves, too), or the pcmcia_request_irq() function.
+ */
+int __must_check
+__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
+			irq_handler_t handler)
+{
+	int ret;
+
+	if (!p_dev->irq)
+		return -EINVAL;
+
+	ret = request_irq(p_dev->irq, handler, 0, p_dev->devname, p_dev->priv);
+	if (ret) {
+		ret = pcmcia_request_irq(p_dev, handler);
+		dev_warn(&p_dev->dev, "pcmcia: request for exclusive IRQ could not be fulfilled\n");
+		dev_warn(&p_dev->dev, "pcmcia: the driver needs updating to supported shared IRQ lines\n");
+	}
+	if (ret)
+		dev_info(&p_dev->dev, "request_irq() failed\n");
+	else
+		p_dev->_irq = 1;
+
+	return ret;
+} /* pcmcia_request_exclusive_irq */
+EXPORT_SYMBOL(__pcmcia_request_exclusive_irq);
+
+
+#ifdef CONFIG_PCMCIA_PROBE
+
+/* mask of IRQs already reserved by other cards, we should avoid using them */
+static u8 pcmcia_used_irq[32];
+
+static irqreturn_t test_action(int cpl, void *dev_id)
+{
+	return IRQ_NONE;
+}
+
+/**
+ * pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used
+ * @p_dev - the associated PCMCIA device
+ *
+ * locking note: must be called with ops_mutex locked.
+ */
+static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	unsigned int try, irq;
+	u32 mask = s->irq_mask;
+	int ret = -ENODEV;
+
+	for (try = 0; try < 64; try++) {
+		irq = try % 32;
+
+		if (irq > NR_IRQS)
+			continue;
+
+		/* marked as available by driver, not blocked by userspace? */
+		if (!((mask >> irq) & 1))
+			continue;
+
+		/* avoid an IRQ which is already used by another PCMCIA card */
+		if ((try < 32) && pcmcia_used_irq[irq])
+			continue;
+
+		/* register the correct driver, if possible, to check whether
+		 * registering a dummy handle works, i.e. if the IRQ isn't
+		 * marked as used by the kernel resource management core */
+		ret = request_irq(irq, test_action, type, p_dev->devname,
+				  p_dev);
+		if (!ret) {
+			free_irq(irq, p_dev);
+			p_dev->irq = s->pcmcia_irq = irq;
+			pcmcia_used_irq[irq]++;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+void pcmcia_cleanup_irq(struct pcmcia_socket *s)
+{
+	pcmcia_used_irq[s->pcmcia_irq]--;
+	s->pcmcia_irq = 0;
+}
+
+#else /* CONFIG_PCMCIA_PROBE */
+
+static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
+{
+	return -EINVAL;
+}
+
+void pcmcia_cleanup_irq(struct pcmcia_socket *s)
+{
+	s->pcmcia_irq = 0;
+	return;
+}
+
+#endif  /* CONFIG_PCMCIA_PROBE */
+
+
+/**
+ * pcmcia_setup_irq() - determine IRQ to be used for device
+ * @p_dev - the associated PCMCIA device
+ *
+ * locking note: must be called with ops_mutex locked.
+ */
+int pcmcia_setup_irq(struct pcmcia_device *p_dev)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+
+	if (p_dev->irq)
+		return 0;
+
+	/* already assigned? */
+	if (s->pcmcia_irq) {
+		p_dev->irq = s->pcmcia_irq;
+		return 0;
+	}
+
+	/* prefer an exclusive ISA irq */
+	if (!pcmcia_setup_isa_irq(p_dev, 0))
+		return 0;
+
+	/* but accept a shared ISA irq */
+	if (!pcmcia_setup_isa_irq(p_dev, IRQF_SHARED))
+		return 0;
+
+	/* but use the PCI irq otherwise */
+	if (s->pci_irq) {
+		p_dev->irq = s->pcmcia_irq = s->pci_irq;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+
+/**
+ * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
+ * @res: &struct resource pointing to p_dev->resource[2..5]
+ * @speed: access speed
+ *
+ * pcmcia_request_window() attepts to reserve an iomem ranges specified in
+ * &struct resource @res pointing to one of the entries in
+ * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the
+ * requested start of the IO mem resource; "end" reflects the size
+ * requested.
+ */
+int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res,
+			unsigned int speed)
+{
+	struct pcmcia_socket *s = p_dev->socket;
+	pccard_mem_map *win;
+	u_long align;
+	int w;
+
+	dev_dbg(&p_dev->dev, "request_window %pR %d\n", res, speed);
+
+	if (!(s->state & SOCKET_PRESENT)) {
+		dev_dbg(&p_dev->dev, "No card present\n");
+		return -ENODEV;
+	}
+
+	/* Window size defaults to smallest available */
+	if (res->end == 0)
+		res->end = s->map_size;
+	align = (s->features & SS_CAP_MEM_ALIGN) ? res->end : s->map_size;
+	if (res->end & (s->map_size-1)) {
+		dev_dbg(&p_dev->dev, "invalid map size\n");
+		return -EINVAL;
+	}
+	if ((res->start && (s->features & SS_CAP_STATIC_MAP)) ||
+	    (res->start & (align-1))) {
+		dev_dbg(&p_dev->dev, "invalid base address\n");
+		return -EINVAL;
+	}
+	if (res->start)
+		align = 0;
+
+	/* Allocate system memory window */
+	mutex_lock(&s->ops_mutex);
+	for (w = 0; w < MAX_WIN; w++)
+		if (!(s->state & SOCKET_WIN_REQ(w)))
+			break;
+	if (w == MAX_WIN) {
+		dev_dbg(&p_dev->dev, "all windows are used already\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EINVAL;
+	}
+
+	win = &s->win[w];
+
+	if (!(s->features & SS_CAP_STATIC_MAP)) {
+		win->res = pcmcia_find_mem_region(res->start, res->end, align,
+						0, s);
+		if (!win->res) {
+			dev_dbg(&p_dev->dev, "allocating mem region failed\n");
+			mutex_unlock(&s->ops_mutex);
+			return -EINVAL;
+		}
+	}
+	p_dev->_win |= CLIENT_WIN_REQ(w);
+
+	/* Configure the socket controller */
+	win->map = w+1;
+	win->flags = res->flags & WIN_FLAGS_MAP;
+	win->speed = speed;
+	win->card_start = 0;
+
+	if (s->ops->set_mem_map(s, win) != 0) {
+		dev_dbg(&p_dev->dev, "failed to set memory mapping\n");
+		mutex_unlock(&s->ops_mutex);
+		return -EIO;
+	}
+	s->state |= SOCKET_WIN_REQ(w);
+
+	/* Return window handle */
+	if (s->features & SS_CAP_STATIC_MAP)
+		res->start = win->static_start;
+	else
+		res->start = win->res->start;
+
+	/* convert to new-style resources */
+	res->end += res->start - 1;
+	res->flags &= ~WIN_FLAGS_REQ;
+	res->flags |= (win->map << 2) | IORESOURCE_MEM;
+	res->parent = win->res;
+	if (win->res)
+		request_resource(&iomem_resource, res);
+
+	dev_dbg(&p_dev->dev, "request_window results in %pR\n", res);
+
+	mutex_unlock(&s->ops_mutex);
+
+	return 0;
+} /* pcmcia_request_window */
+EXPORT_SYMBOL(pcmcia_request_window);
+
+
+/**
+ * pcmcia_disable_device() - disable and clean up a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_disable_device() is the driver-callable counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used,
+ * drivers are expected to clean up and disable the device by calling
+ * this function. Any I/O ranges (iomem and ioports) will be released,
+ * the Vpp voltage will be set to 0, and IRQs will no longer be
+ * generated -- at least if there is no other card function (of
+ * multifunction devices) being used.
+ */
+void pcmcia_disable_device(struct pcmcia_device *p_dev)
+{
+	int i;
+
+	dev_dbg(&p_dev->dev, "disabling device\n");
+
+	for (i = 0; i < MAX_WIN; i++) {
+		struct resource *res = p_dev->resource[MAX_IO_WIN + i];
+		if (res->flags & WIN_FLAGS_REQ)
+			pcmcia_release_window(p_dev, res);
+	}
+
+	pcmcia_release_configuration(p_dev);
+	pcmcia_release_io(p_dev);
+	if (p_dev->_irq) {
+		free_irq(p_dev->irq, p_dev->priv);
+		p_dev->_irq = 0;
+	}
+}
+EXPORT_SYMBOL(pcmcia_disable_device);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.c b/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.c
new file mode 100644
index 0000000..0f70b4d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.c
@@ -0,0 +1,778 @@
+/*
+ * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
+ *
+ * Based on the i82092.c driver.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <pcmcia/ss.h>
+
+
+#include "pd6729.h"
+#include "i82365.h"
+#include "cirrus.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge");
+MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
+
+#define MAX_SOCKETS 2
+
+/*
+ * simple helper functions
+ * External clock time, in nanoseconds.  120 ns = 8.33 MHz
+ */
+#define to_cycles(ns)	((ns)/120)
+
+#ifndef NO_IRQ
+#define NO_IRQ	((unsigned int)(0))
+#endif
+
+/*
+ * PARAMETERS
+ *  irq_mode=n
+ *     Specifies the interrupt delivery mode.  The default (1) is to use PCI
+ *     interrupts; a value of 0 selects ISA interrupts. This must be set for
+ *     correct operation of PCI card readers.
+ */
+
+static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
+
+module_param(irq_mode, int, 0444);
+MODULE_PARM_DESC(irq_mode,
+		"interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1");
+
+static DEFINE_SPINLOCK(port_lock);
+
+/* basic value read/write functions */
+
+static unsigned char indirect_read(struct pd6729_socket *socket,
+				   unsigned short reg)
+{
+	unsigned long port;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg += socket->number * 0x40;
+	port = socket->io_base;
+	outb(reg, port);
+	val = inb(port + 1);
+	spin_unlock_irqrestore(&port_lock, flags);
+
+	return val;
+}
+
+static unsigned short indirect_read16(struct pd6729_socket *socket,
+				      unsigned short reg)
+{
+	unsigned long port;
+	unsigned short tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg  = reg + socket->number * 0x40;
+	port = socket->io_base;
+	outb(reg, port);
+	tmp = inb(port + 1);
+	reg++;
+	outb(reg, port);
+	tmp = tmp | (inb(port + 1) << 8);
+	spin_unlock_irqrestore(&port_lock, flags);
+
+	return tmp;
+}
+
+static void indirect_write(struct pd6729_socket *socket, unsigned short reg,
+			   unsigned char value)
+{
+	unsigned long port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg = reg + socket->number * 0x40;
+	port = socket->io_base;
+	outb(reg, port);
+	outb(value, port + 1);
+	spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg,
+			    unsigned char mask)
+{
+	unsigned long port;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg = reg + socket->number * 0x40;
+	port = socket->io_base;
+	outb(reg, port);
+	val = inb(port + 1);
+	val |= mask;
+	outb(reg, port);
+	outb(val, port + 1);
+	spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg,
+			      unsigned char mask)
+{
+	unsigned long port;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg = reg + socket->number * 0x40;
+	port = socket->io_base;
+	outb(reg, port);
+	val = inb(port + 1);
+	val &= ~mask;
+	outb(reg, port);
+	outb(val, port + 1);
+	spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_write16(struct pd6729_socket *socket, unsigned short reg,
+			     unsigned short value)
+{
+	unsigned long port;
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port_lock, flags);
+	reg = reg + socket->number * 0x40;
+	port = socket->io_base;
+
+	outb(reg, port);
+	val = value & 255;
+	outb(val, port + 1);
+
+	reg++;
+
+	outb(reg, port);
+	val = value >> 8;
+	outb(val, port + 1);
+	spin_unlock_irqrestore(&port_lock, flags);
+}
+
+/* Interrupt handler functionality */
+
+static irqreturn_t pd6729_interrupt(int irq, void *dev)
+{
+	struct pd6729_socket *socket = (struct pd6729_socket *)dev;
+	int i;
+	int loopcount = 0;
+	int handled = 0;
+	unsigned int events, active = 0;
+
+	while (1) {
+		loopcount++;
+		if (loopcount > 20) {
+			printk(KERN_ERR "pd6729: infinite eventloop "
+			       "in interrupt\n");
+			break;
+		}
+
+		active = 0;
+
+		for (i = 0; i < MAX_SOCKETS; i++) {
+			unsigned int csc;
+
+			/* card status change register */
+			csc = indirect_read(&socket[i], I365_CSC);
+			if (csc == 0)  /* no events on this socket */
+				continue;
+
+			handled = 1;
+			events = 0;
+
+			if (csc & I365_CSC_DETECT) {
+				events |= SS_DETECT;
+				dev_vdbg(&socket[i].socket.dev,
+					"Card detected in socket %i!\n", i);
+			}
+
+			if (indirect_read(&socket[i], I365_INTCTL)
+						& I365_PC_IOCARD) {
+				/* For IO/CARDS, bit 0 means "read the card" */
+				events |= (csc & I365_CSC_STSCHG)
+						? SS_STSCHG : 0;
+			} else {
+				/* Check for battery/ready events */
+				events |= (csc & I365_CSC_BVD1)
+						? SS_BATDEAD : 0;
+				events |= (csc & I365_CSC_BVD2)
+						? SS_BATWARN : 0;
+				events |= (csc & I365_CSC_READY)
+						? SS_READY : 0;
+			}
+
+			if (events)
+				pcmcia_parse_events(&socket[i].socket, events);
+
+			active |= events;
+		}
+
+		if (active == 0) /* no more events to handle */
+			break;
+	}
+	return IRQ_RETVAL(handled);
+}
+
+/* socket functions */
+
+static void pd6729_interrupt_wrapper(unsigned long data)
+{
+	struct pd6729_socket *socket = (struct pd6729_socket *) data;
+
+	pd6729_interrupt(0, (void *)socket);
+	mod_timer(&socket->poll_timer, jiffies + HZ);
+}
+
+static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+	struct pd6729_socket *socket
+			= container_of(sock, struct pd6729_socket, socket);
+	unsigned int status;
+	unsigned int data;
+	struct pd6729_socket *t;
+
+	/* Interface Status Register */
+	status = indirect_read(socket, I365_STATUS);
+	*value = 0;
+
+	if ((status & I365_CS_DETECT) == I365_CS_DETECT)
+		*value |= SS_DETECT;
+
+	/*
+	 * IO cards have a different meaning of bits 0,1
+	 * Also notice the inverse-logic on the bits
+	 */
+	if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) {
+		/* IO card */
+		if (!(status & I365_CS_STSCHG))
+			*value |= SS_STSCHG;
+	} else {
+		/* non I/O card */
+		if (!(status & I365_CS_BVD1))
+			*value |= SS_BATDEAD;
+		if (!(status & I365_CS_BVD2))
+			*value |= SS_BATWARN;
+	}
+
+	if (status & I365_CS_WRPROT)
+		*value |= SS_WRPROT;	/* card is write protected */
+
+	if (status & I365_CS_READY)
+		*value |= SS_READY;	/* card is not busy */
+
+	if (status & I365_CS_POWERON)
+		*value |= SS_POWERON;	/* power is applied to the card */
+
+	t = (socket->number) ? socket : socket + 1;
+	indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA);
+	data = indirect_read16(t, PD67_EXT_DATA);
+	*value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD;
+
+	return 0;
+}
+
+
+static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+	struct pd6729_socket *socket
+			= container_of(sock, struct pd6729_socket, socket);
+	unsigned char reg, data;
+
+	/* First, set the global controller options */
+	indirect_write(socket, I365_GBLCTL, 0x00);
+	indirect_write(socket, I365_GENCTL, 0x00);
+
+	/* Values for the IGENC register */
+	socket->card_irq = state->io_irq;
+
+	reg = 0;
+	/* The reset bit has "inverse" logic */
+	if (!(state->flags & SS_RESET))
+		reg |= I365_PC_RESET;
+	if (state->flags & SS_IOCARD)
+		reg |= I365_PC_IOCARD;
+
+	/* IGENC, Interrupt and General Control Register */
+	indirect_write(socket, I365_INTCTL, reg);
+
+	/* Power registers */
+
+	reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
+
+	if (state->flags & SS_PWR_AUTO) {
+		dev_dbg(&sock->dev, "Auto power\n");
+		reg |= I365_PWR_AUTO;	/* automatic power mngmnt */
+	}
+	if (state->flags & SS_OUTPUT_ENA) {
+		dev_dbg(&sock->dev, "Power Enabled\n");
+		reg |= I365_PWR_OUT;	/* enable power */
+	}
+
+	switch (state->Vcc) {
+	case 0:
+		break;
+	case 33:
+		dev_dbg(&sock->dev,
+			"setting voltage to Vcc to 3.3V on socket %i\n",
+			socket->number);
+		reg |= I365_VCC_5V;
+		indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+		break;
+	case 50:
+		dev_dbg(&sock->dev,
+			"setting voltage to Vcc to 5V on socket %i\n",
+			socket->number);
+		reg |= I365_VCC_5V;
+		indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+		break;
+	default:
+		dev_dbg(&sock->dev,
+			"pd6729_set_socket called with invalid VCC power "
+			"value: %i\n", state->Vcc);
+		return -EINVAL;
+	}
+
+	switch (state->Vpp) {
+	case 0:
+		dev_dbg(&sock->dev, "not setting Vpp on socket %i\n",
+			socket->number);
+		break;
+	case 33:
+	case 50:
+		dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i\n",
+			socket->number);
+		reg |= I365_VPP1_5V;
+		break;
+	case 120:
+		dev_dbg(&sock->dev, "setting Vpp to 12.0\n");
+		reg |= I365_VPP1_12V;
+		break;
+	default:
+		dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with "
+			"invalid VPP power value: %i\n", state->Vpp);
+		return -EINVAL;
+	}
+
+	/* only write if changed */
+	if (reg != indirect_read(socket, I365_POWER))
+		indirect_write(socket, I365_POWER, reg);
+
+	if (irq_mode == 1) {
+		/* all interrupts are to be done as PCI interrupts */
+		data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
+	} else
+		data = 0;
+
+	indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1);
+	indirect_write(socket, PD67_EXT_DATA, data);
+
+	/* Enable specific interrupt events */
+
+	reg = 0x00;
+	if (state->csc_mask & SS_DETECT)
+		reg |= I365_CSC_DETECT;
+
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG)
+			reg |= I365_CSC_STSCHG;
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			reg |= I365_CSC_BVD1;
+		if (state->csc_mask & SS_BATWARN)
+			reg |= I365_CSC_BVD2;
+		if (state->csc_mask & SS_READY)
+			reg |= I365_CSC_READY;
+	}
+	if (irq_mode == 1)
+		reg |= 0x30;	/* management IRQ: PCI INTA# = "irq 3" */
+	indirect_write(socket, I365_CSCINT, reg);
+
+	reg = indirect_read(socket, I365_INTCTL);
+	if (irq_mode == 1)
+		reg |= 0x03;	/* card IRQ: PCI INTA# = "irq 3" */
+	else
+		reg |= socket->card_irq;
+	indirect_write(socket, I365_INTCTL, reg);
+
+	/* now clear the (probably bogus) pending stuff by doing a dummy read */
+	(void)indirect_read(socket, I365_CSC);
+
+	return 0;
+}
+
+static int pd6729_set_io_map(struct pcmcia_socket *sock,
+			     struct pccard_io_map *io)
+{
+	struct pd6729_socket *socket
+			= container_of(sock, struct pd6729_socket, socket);
+	unsigned char map, ioctl;
+
+	map = io->map;
+
+	/* Check error conditions */
+	if (map > 1) {
+		dev_dbg(&sock->dev, "pd6729_set_io_map with invalid map\n");
+		return -EINVAL;
+	}
+
+	/* Turn off the window before changing anything */
+	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map))
+		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
+
+	/* dev_dbg(&sock->dev, "set_io_map: Setting range to %x - %x\n",
+	   io->start, io->stop);*/
+
+	/* write the new values */
+	indirect_write16(socket, I365_IO(map)+I365_W_START, io->start);
+	indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop);
+
+	ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+
+	if (io->flags & MAP_0WS)
+		ioctl |= I365_IOCTL_0WS(map);
+	if (io->flags & MAP_16BIT)
+		ioctl |= I365_IOCTL_16BIT(map);
+	if (io->flags & MAP_AUTOSZ)
+		ioctl |= I365_IOCTL_IOCS16(map);
+
+	indirect_write(socket, I365_IOCTL, ioctl);
+
+	/* Turn the window back on if needed */
+	if (io->flags & MAP_ACTIVE)
+		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
+
+	return 0;
+}
+
+static int pd6729_set_mem_map(struct pcmcia_socket *sock,
+			      struct pccard_mem_map *mem)
+{
+	struct pd6729_socket *socket
+			 = container_of(sock, struct pd6729_socket, socket);
+	unsigned short base, i;
+	unsigned char map;
+
+	map = mem->map;
+	if (map > 4) {
+		dev_warn(&sock->dev, "invalid map requested\n");
+		return -EINVAL;
+	}
+
+	if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) {
+		dev_warn(&sock->dev, "invalid invalid address / speed\n");
+		return -EINVAL;
+	}
+
+	/* Turn off the window before changing anything */
+	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map))
+		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
+
+	/* write the start address */
+	base = I365_MEM(map);
+	i = (mem->res->start >> 12) & 0x0fff;
+	if (mem->flags & MAP_16BIT)
+		i |= I365_MEM_16BIT;
+	if (mem->flags & MAP_0WS)
+		i |= I365_MEM_0WS;
+	indirect_write16(socket, base + I365_W_START, i);
+
+	/* write the stop address */
+
+	i = (mem->res->end >> 12) & 0x0fff;
+	switch (to_cycles(mem->speed)) {
+	case 0:
+		break;
+	case 1:
+		i |= I365_MEM_WS0;
+		break;
+	case 2:
+		i |= I365_MEM_WS1;
+		break;
+	default:
+		i |= I365_MEM_WS1 | I365_MEM_WS0;
+		break;
+	}
+
+	indirect_write16(socket, base + I365_W_STOP, i);
+
+	/* Take care of high byte */
+	indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+	indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24);
+
+	/* card start */
+
+	i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
+	if (mem->flags & MAP_WRPROT)
+		i |= I365_MEM_WRPROT;
+	if (mem->flags & MAP_ATTRIB) {
+		/* dev_dbg(&sock->dev, "requesting attribute memory for "
+		   "socket %i\n", socket->number);*/
+		i |= I365_MEM_REG;
+	} else {
+		/* dev_dbg(&sock->dev, "requesting normal memory for "
+		   "socket %i\n", socket->number);*/
+	}
+	indirect_write16(socket, base + I365_W_OFF, i);
+
+	/* Enable the window if necessary */
+	if (mem->flags & MAP_ACTIVE)
+		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
+
+	return 0;
+}
+
+static int pd6729_init(struct pcmcia_socket *sock)
+{
+	int i;
+	struct resource res = { .end = 0x0fff };
+	pccard_io_map io = { 0, 0, 0, 0, 1 };
+	pccard_mem_map mem = { .res = &res, };
+
+	pd6729_set_socket(sock, &dead_socket);
+	for (i = 0; i < 2; i++) {
+		io.map = i;
+		pd6729_set_io_map(sock, &io);
+	}
+	for (i = 0; i < 5; i++) {
+		mem.map = i;
+		pd6729_set_mem_map(sock, &mem);
+	}
+
+	return 0;
+}
+
+
+/* the pccard structure and its functions */
+static struct pccard_operations pd6729_operations = {
+	.init			= pd6729_init,
+	.get_status		= pd6729_get_status,
+	.set_socket		= pd6729_set_socket,
+	.set_io_map		= pd6729_set_io_map,
+	.set_mem_map		= pd6729_set_mem_map,
+};
+
+static irqreturn_t pd6729_test(int irq, void *dev)
+{
+	pr_devel("-> hit on irq %d\n", irq);
+	return IRQ_HANDLED;
+}
+
+static int pd6729_check_irq(int irq)
+{
+	int ret;
+
+	ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x",
+			  pd6729_test);
+	if (ret)
+		return -1;
+
+	free_irq(irq, pd6729_test);
+	return 0;
+}
+
+static u_int pd6729_isa_scan(void)
+{
+	u_int mask0, mask = 0;
+	int i;
+
+	if (irq_mode == 1) {
+		printk(KERN_INFO "pd6729: PCI card interrupts, "
+		       "PCI status changes\n");
+		return 0;
+	}
+
+	mask0 = PD67_MASK;
+
+	/* just find interrupts that aren't in use */
+	for (i = 0; i < 16; i++)
+		if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0))
+			mask |= (1 << i);
+
+	printk(KERN_INFO "pd6729: ISA irqs = ");
+	for (i = 0; i < 16; i++)
+		if (mask & (1<<i))
+			printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i);
+
+	if (mask == 0)
+		printk("none!");
+	else
+		printk("  polling status changes.\n");
+
+	return mask;
+}
+
+static int pd6729_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *id)
+{
+	int i, j, ret;
+	u_int mask;
+	char configbyte;
+	struct pd6729_socket *socket;
+
+	socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS,
+			 GFP_KERNEL);
+	if (!socket) {
+		dev_warn(&dev->dev, "failed to kzalloc socket.\n");
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret) {
+		dev_warn(&dev->dev, "failed to enable pci_device.\n");
+		goto err_out_free_mem;
+	}
+
+	if (!pci_resource_start(dev, 0)) {
+		dev_warn(&dev->dev, "refusing to load the driver as the "
+			"io_base is NULL.\n");
+		ret = -ENOMEM;
+		goto err_out_disable;
+	}
+
+	dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx "
+		"on irq %d\n",
+		(unsigned long long)pci_resource_start(dev, 0), dev->irq);
+	/*
+	 * Since we have no memory BARs some firmware may not
+	 * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
+	 */
+	pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
+	if (!(configbyte & PCI_COMMAND_MEMORY)) {
+		dev_dbg(&dev->dev, "pd6729: Enabling PCI_COMMAND_MEMORY.\n");
+		configbyte |= PCI_COMMAND_MEMORY;
+		pci_write_config_byte(dev, PCI_COMMAND, configbyte);
+	}
+
+	ret = pci_request_regions(dev, "pd6729");
+	if (ret) {
+		dev_warn(&dev->dev, "pci request region failed.\n");
+		goto err_out_disable;
+	}
+
+	if (dev->irq == NO_IRQ)
+		irq_mode = 0;	/* fall back to ISA interrupt mode */
+
+	mask = pd6729_isa_scan();
+	if (irq_mode == 0 && mask == 0) {
+		dev_warn(&dev->dev, "no ISA interrupt is available.\n");
+		ret = -ENODEV;
+		goto err_out_free_res;
+	}
+
+	for (i = 0; i < MAX_SOCKETS; i++) {
+		socket[i].io_base = pci_resource_start(dev, 0);
+		socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
+		socket[i].socket.map_size = 0x1000;
+		socket[i].socket.irq_mask = mask;
+		socket[i].socket.pci_irq  = dev->irq;
+		socket[i].socket.cb_dev = dev;
+		socket[i].socket.owner = THIS_MODULE;
+
+		socket[i].number = i;
+
+		socket[i].socket.ops = &pd6729_operations;
+		socket[i].socket.resource_ops = &pccard_nonstatic_ops;
+		socket[i].socket.dev.parent = &dev->dev;
+		socket[i].socket.driver_data = &socket[i];
+	}
+
+	pci_set_drvdata(dev, socket);
+	if (irq_mode == 1) {
+		/* Register the interrupt handler */
+		ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
+				  "pd6729", socket);
+		if (ret) {
+			dev_err(&dev->dev, "Failed to register irq %d\n",
+				dev->irq);
+			goto err_out_free_res;
+		}
+	} else {
+		/* poll Card status change */
+		setup_timer(&socket->poll_timer, pd6729_interrupt_wrapper,
+			    (unsigned long)socket);
+		mod_timer(&socket->poll_timer, jiffies + HZ);
+	}
+
+	for (i = 0; i < MAX_SOCKETS; i++) {
+		ret = pcmcia_register_socket(&socket[i].socket);
+		if (ret) {
+			dev_warn(&dev->dev, "pcmcia_register_socket failed.\n");
+			for (j = 0; j < i ; j++)
+				pcmcia_unregister_socket(&socket[j].socket);
+			goto err_out_free_res2;
+		}
+	}
+
+	return 0;
+
+err_out_free_res2:
+	if (irq_mode == 1)
+		free_irq(dev->irq, socket);
+	else
+		del_timer_sync(&socket->poll_timer);
+err_out_free_res:
+	pci_release_regions(dev);
+err_out_disable:
+	pci_disable_device(dev);
+
+err_out_free_mem:
+	kfree(socket);
+	return ret;
+}
+
+static void pd6729_pci_remove(struct pci_dev *dev)
+{
+	int i;
+	struct pd6729_socket *socket = pci_get_drvdata(dev);
+
+	for (i = 0; i < MAX_SOCKETS; i++) {
+		/* Turn off all interrupt sources */
+		indirect_write(&socket[i], I365_CSCINT, 0);
+		indirect_write(&socket[i], I365_INTCTL, 0);
+
+		pcmcia_unregister_socket(&socket[i].socket);
+	}
+
+	if (irq_mode == 1)
+		free_irq(dev->irq, socket);
+	else
+		del_timer_sync(&socket->poll_timer);
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+
+	kfree(socket);
+}
+
+static const struct pci_device_id pd6729_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
+
+static struct pci_driver pd6729_pci_driver = {
+	.name		= "pd6729",
+	.id_table	= pd6729_pci_ids,
+	.probe		= pd6729_pci_probe,
+	.remove		= pd6729_pci_remove,
+};
+
+module_pci_driver(pd6729_pci_driver);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.h b/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.h
new file mode 100644
index 0000000..605cc2c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pd6729.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _INCLUDE_GUARD_PD6729_H_
+#define _INCLUDE_GUARD_PD6729_H_
+
+/* Flags for I365_GENCTL */
+#define I365_DF_VS1		0x40	/* DF-step Voltage Sense */
+#define I365_DF_VS2		0x80
+
+/* Fields in PD67_EXTERN_DATA */
+#define PD67_EXD_VS1(s)		(0x01 << ((s) << 1))
+#define PD67_EXD_VS2(s)		(0x02 << ((s) << 1))
+
+/* Default ISA interrupt mask */
+#define PD67_MASK	0x0eb8	/* irq 11,10,9,7,5,4,3 */
+
+struct pd6729_socket {
+	int	number;
+	int	card_irq;
+	unsigned long io_base;	/* base io address of the socket */
+	struct pcmcia_socket socket;
+	struct timer_list poll_timer;
+};
+
+#endif
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_balloon3.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_balloon3.c
new file mode 100644
index 0000000..2ef576c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_balloon3.c
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_balloon3.c
+ *
+ * Balloon3 PCMCIA specific routines.
+ *
+ *  Author:	Nick Bane
+ *  Created:	June, 2006
+ *  Copyright:	Toby Churchill Ltd
+ *  Derived from pxa2xx_mainstone.c, by Nico Pitre
+ *
+ * Various modification by Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/balloon3.h>
+
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	uint16_t ver;
+
+	ver = __raw_readw(BALLOON3_FPGA_VER);
+	if (ver < 0x4f08)
+		pr_warn("The FPGA code, version 0x%04x, is too old. "
+			"PCMCIA/CF support might be broken in this version!",
+			ver);
+
+	skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ;
+	skt->stat[SOC_STAT_CD].gpio = BALLOON3_GPIO_S0_CD;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_BVD1].irq = BALLOON3_BP_NSTSCHG_IRQ;
+	skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
+
+	return 0;
+}
+
+static unsigned long balloon3_pcmcia_status[2] = {
+	BALLOON3_CF_nSTSCHG_BVD1,
+	BALLOON3_CF_nSTSCHG_BVD1
+};
+
+static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				    struct pcmcia_state *state)
+{
+	uint16_t status;
+	int flip;
+
+	/* This actually reads the STATUS register */
+	status = __raw_readw(BALLOON3_CF_STATUS_REG);
+	flip = (status ^ balloon3_pcmcia_status[skt->nr])
+		& BALLOON3_CF_nSTSCHG_BVD1;
+	/*
+	 * Workaround for STSCHG which can't be deasserted:
+	 * We therefore disable/enable corresponding IRQs
+	 * as needed to avoid IRQ locks.
+	 */
+	if (flip) {
+		balloon3_pcmcia_status[skt->nr] = status;
+		if (status & BALLOON3_CF_nSTSCHG_BVD1)
+			enable_irq(BALLOON3_BP_NSTSCHG_IRQ);
+		else
+			disable_irq(BALLOON3_BP_NSTSCHG_IRQ);
+	}
+
+	state->ready	= !!(status & BALLOON3_CF_nIRQ);
+	state->bvd1	= !!(status & BALLOON3_CF_nSTSCHG_BVD1);
+	state->bvd2	= 0;	/* not available */
+	state->vs_3v	= 1;	/* Always true its a CF card */
+	state->vs_Xv	= 0;	/* not available */
+}
+
+static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				       const socket_state_t *state)
+{
+	__raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG +
+			((state->flags & SS_RESET) ?
+			BALLOON3_FPGA_SETnCLR : 0));
+	return 0;
+}
+
+static struct pcmcia_low_level balloon3_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.hw_init		= balloon3_pcmcia_hw_init,
+	.socket_state		= balloon3_pcmcia_socket_state,
+	.configure_socket	= balloon3_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 1,
+};
+
+static struct platform_device *balloon3_pcmcia_device;
+
+static int __init balloon3_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_balloon3())
+		return -ENODEV;
+
+	balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!balloon3_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(balloon3_pcmcia_device,
+			&balloon3_pcmcia_ops, sizeof(balloon3_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(balloon3_pcmcia_device);
+
+	if (ret)
+		platform_device_put(balloon3_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit balloon3_pcmcia_exit(void)
+{
+	platform_device_unregister(balloon3_pcmcia_device);
+}
+
+module_init(balloon3_pcmcia_init);
+module_exit(balloon3_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nick Bane <nick@cecomputing.co.uk>");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_DESCRIPTION("Balloon3 board CF/PCMCIA driver");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.c
new file mode 100644
index 0000000..91b5f57
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.c
@@ -0,0 +1,385 @@
+/*======================================================================
+
+  Device driver for the PCMCIA control functionality of PXA2xx
+  microprocessors.
+
+    The contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL")
+
+    (c) Ian Molton (spyro@f2s.com) 2003
+    (c) Stefan Eletzhofer (stefan.eletzhofer@inquant.de) 2003,4
+
+    derived from sa11xx_base.c
+
+     Portions created by John G. Dorsey are
+     Copyright (C) 1999 John G. Dorsey.
+
+  ======================================================================*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/smemc.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/pxa2xx-regs.h>
+#include <asm/mach-types.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include "soc_common.h"
+#include "pxa2xx_base.h"
+
+/*
+ * Personal Computer Memory Card International Association (PCMCIA) sockets
+ */
+
+#define PCMCIAPrtSp	0x04000000	/* PCMCIA Partition Space [byte]   */
+#define PCMCIASp	(4*PCMCIAPrtSp)	/* PCMCIA Space [byte]             */
+#define PCMCIAIOSp	PCMCIAPrtSp	/* PCMCIA I/O Space [byte]         */
+#define PCMCIAAttrSp	PCMCIAPrtSp	/* PCMCIA Attribute Space [byte]   */
+#define PCMCIAMemSp	PCMCIAPrtSp	/* PCMCIA Memory Space [byte]      */
+
+#define PCMCIA0Sp	PCMCIASp	/* PCMCIA 0 Space [byte]           */
+#define PCMCIA0IOSp	PCMCIAIOSp	/* PCMCIA 0 I/O Space [byte]       */
+#define PCMCIA0AttrSp	PCMCIAAttrSp	/* PCMCIA 0 Attribute Space [byte] */
+#define PCMCIA0MemSp	PCMCIAMemSp	/* PCMCIA 0 Memory Space [byte]    */
+
+#define PCMCIA1Sp	PCMCIASp	/* PCMCIA 1 Space [byte]           */
+#define PCMCIA1IOSp	PCMCIAIOSp	/* PCMCIA 1 I/O Space [byte]       */
+#define PCMCIA1AttrSp	PCMCIAAttrSp	/* PCMCIA 1 Attribute Space [byte] */
+#define PCMCIA1MemSp	PCMCIAMemSp	/* PCMCIA 1 Memory Space [byte]    */
+
+#define _PCMCIA(Nb)			/* PCMCIA [0..1]                   */ \
+			(0x20000000 + (Nb) * PCMCIASp)
+#define _PCMCIAIO(Nb)	_PCMCIA(Nb)	/* PCMCIA I/O [0..1]               */
+#define _PCMCIAAttr(Nb)			/* PCMCIA Attribute [0..1]         */ \
+			(_PCMCIA(Nb) + 2 * PCMCIAPrtSp)
+#define _PCMCIAMem(Nb)			/* PCMCIA Memory [0..1]            */ \
+			(_PCMCIA(Nb) + 3 * PCMCIAPrtSp)
+
+#define _PCMCIA0	_PCMCIA(0)	/* PCMCIA 0                        */
+#define _PCMCIA0IO	_PCMCIAIO(0)	/* PCMCIA 0 I/O                    */
+#define _PCMCIA0Attr	_PCMCIAAttr(0)	/* PCMCIA 0 Attribute              */
+#define _PCMCIA0Mem	_PCMCIAMem(0)	/* PCMCIA 0 Memory                 */
+
+#define _PCMCIA1	_PCMCIA(1)	/* PCMCIA 1                        */
+#define _PCMCIA1IO	_PCMCIAIO(1)	/* PCMCIA 1 I/O                    */
+#define _PCMCIA1Attr	_PCMCIAAttr(1)	/* PCMCIA 1 Attribute              */
+#define _PCMCIA1Mem	_PCMCIAMem(1)	/* PCMCIA 1 Memory                 */
+
+
+#define MCXX_SETUP_MASK     (0x7f)
+#define MCXX_ASST_MASK      (0x1f)
+#define MCXX_HOLD_MASK      (0x3f)
+#define MCXX_SETUP_SHIFT    (0)
+#define MCXX_ASST_SHIFT     (7)
+#define MCXX_HOLD_SHIFT     (14)
+
+static inline u_int pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns,
+				     u_int mem_clk_10khz)
+{
+	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
+	return (code / 300000) + ((code % 300000) ? 1 : 0) - 1;
+}
+
+static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns,
+				     u_int mem_clk_10khz)
+{
+	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
+	return (code / 300000) + ((code % 300000) ? 1 : 0) + 1;
+}
+
+static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns,
+				      u_int mem_clk_10khz)
+{
+	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
+	return (code / 100000) + ((code % 100000) ? 1 : 0) - 1;
+}
+
+/* This function returns the (approximate) command assertion period, in
+ * nanoseconds, for a given CPU clock frequency and MCXX_ASST value:
+ */
+static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz,
+					   u_int pcmcia_mcxx_asst)
+{
+	return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz);
+}
+
+static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock )
+{
+	uint32_t val;
+
+	val = ((pxa2xx_mcxx_setup(speed, clock)
+		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
+		| ((pxa2xx_mcxx_asst(speed, clock)
+		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
+		| ((pxa2xx_mcxx_hold(speed, clock)
+		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+
+	__raw_writel(val, MCMEM(sock));
+
+	return 0;
+}
+
+static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock )
+{
+	uint32_t val;
+
+	val = ((pxa2xx_mcxx_setup(speed, clock)
+		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
+		| ((pxa2xx_mcxx_asst(speed, clock)
+		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
+		| ((pxa2xx_mcxx_hold(speed, clock)
+		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+
+	__raw_writel(val, MCIO(sock));
+
+	return 0;
+}
+
+static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock )
+{
+	uint32_t val;
+
+	val = ((pxa2xx_mcxx_setup(speed, clock)
+		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
+		| ((pxa2xx_mcxx_asst(speed, clock)
+		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
+		| ((pxa2xx_mcxx_hold(speed, clock)
+		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+
+	__raw_writel(val, MCATT(sock));
+
+	return 0;
+}
+
+static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int clk)
+{
+	struct soc_pcmcia_timing timing;
+	int sock = skt->nr;
+
+	soc_common_pcmcia_get_timing(skt, &timing);
+
+	pxa2xx_pcmcia_set_mcmem(sock, timing.mem, clk);
+	pxa2xx_pcmcia_set_mcatt(sock, timing.attr, clk);
+	pxa2xx_pcmcia_set_mcio(sock, timing.io, clk);
+
+	return 0;
+}
+
+static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
+{
+	unsigned long clk = clk_get_rate(skt->clk);
+	return pxa2xx_pcmcia_set_mcxx(skt, clk / 10000);
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+static int
+pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
+			       unsigned long val,
+			       struct cpufreq_freqs *freqs)
+{
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if (freqs->new > freqs->old) {
+			debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, "
+			       "pre-updating\n",
+			       freqs->new / 1000, (freqs->new / 100) % 10,
+			       freqs->old / 1000, (freqs->old / 100) % 10);
+			pxa2xx_pcmcia_set_timing(skt);
+		}
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		if (freqs->new < freqs->old) {
+			debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, "
+			       "post-updating\n",
+			       freqs->new / 1000, (freqs->new / 100) % 10,
+			       freqs->old / 1000, (freqs->old / 100) % 10);
+			pxa2xx_pcmcia_set_timing(skt);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+void pxa2xx_configure_sockets(struct device *dev, struct pcmcia_low_level *ops)
+{
+	/*
+	 * We have at least one socket, so set MECR:CIT
+	 * (Card Is There)
+	 */
+	uint32_t mecr = MECR_CIT;
+
+	/* Set MECR:NOS (Number Of Sockets) */
+	if ((ops->first + ops->nr) > 1 ||
+	    machine_is_viper() || machine_is_arcom_zeus())
+		mecr |= MECR_NOS;
+
+	__raw_writel(mecr, MECR);
+}
+EXPORT_SYMBOL(pxa2xx_configure_sockets);
+
+static const char *skt_names[] = {
+	"PCMCIA socket 0",
+	"PCMCIA socket 1",
+};
+
+#define SKT_DEV_INFO_SIZE(n) \
+	(sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
+
+int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
+{
+	skt->res_skt.start = _PCMCIA(skt->nr);
+	skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
+	skt->res_skt.name = skt_names[skt->nr];
+	skt->res_skt.flags = IORESOURCE_MEM;
+
+	skt->res_io.start = _PCMCIAIO(skt->nr);
+	skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
+	skt->res_io.name = "io";
+	skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+	skt->res_mem.start = _PCMCIAMem(skt->nr);
+	skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
+	skt->res_mem.name = "memory";
+	skt->res_mem.flags = IORESOURCE_MEM;
+
+	skt->res_attr.start = _PCMCIAAttr(skt->nr);
+	skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
+	skt->res_attr.name = "attribute";
+	skt->res_attr.flags = IORESOURCE_MEM;
+
+	return soc_pcmcia_add_one(skt);
+}
+EXPORT_SYMBOL(pxa2xx_drv_pcmcia_add_one);
+
+void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
+{
+	/* Provide our PXA2xx specific timing routines. */
+	ops->set_timing  = pxa2xx_pcmcia_set_timing;
+#ifdef CONFIG_CPU_FREQ
+	ops->frequency_change = pxa2xx_pcmcia_frequency_change;
+#endif
+}
+EXPORT_SYMBOL(pxa2xx_drv_pcmcia_ops);
+
+static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
+{
+	int i, ret = 0;
+	struct pcmcia_low_level *ops;
+	struct skt_dev_info *sinfo;
+	struct soc_pcmcia_socket *skt;
+	struct clk *clk;
+
+	ops = (struct pcmcia_low_level *)dev->dev.platform_data;
+	if (!ops) {
+		ret = -ENODEV;
+		goto err0;
+	}
+
+	if (cpu_is_pxa320() && ops->nr > 1) {
+		dev_err(&dev->dev, "pxa320 supports only one pcmcia slot");
+		ret = -EINVAL;
+		goto err0;
+	}
+
+	clk = devm_clk_get(&dev->dev, NULL);
+	if (IS_ERR(clk))
+		return -ENODEV;
+
+	pxa2xx_drv_pcmcia_ops(ops);
+
+	sinfo = devm_kzalloc(&dev->dev, SKT_DEV_INFO_SIZE(ops->nr),
+			     GFP_KERNEL);
+	if (!sinfo)
+		return -ENOMEM;
+
+	sinfo->nskt = ops->nr;
+
+	/* Initialize processor specific parameters */
+	for (i = 0; i < ops->nr; i++) {
+		skt = &sinfo->skt[i];
+
+		skt->nr = ops->first + i;
+		skt->clk = clk;
+		soc_pcmcia_init_one(skt, ops, &dev->dev);
+
+		ret = pxa2xx_drv_pcmcia_add_one(skt);
+		if (ret)
+			goto err1;
+	}
+
+	pxa2xx_configure_sockets(&dev->dev, ops);
+	dev_set_drvdata(&dev->dev, sinfo);
+
+	return 0;
+
+err1:
+	while (--i >= 0)
+		soc_pcmcia_remove_one(&sinfo->skt[i]);
+
+err0:
+	return ret;
+}
+
+static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
+{
+	struct skt_dev_info *sinfo = platform_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < sinfo->nskt; i++)
+		soc_pcmcia_remove_one(&sinfo->skt[i]);
+
+	return 0;
+}
+
+static int pxa2xx_drv_pcmcia_resume(struct device *dev)
+{
+	struct pcmcia_low_level *ops = (struct pcmcia_low_level *)dev->platform_data;
+
+	pxa2xx_configure_sockets(dev, ops);
+	return 0;
+}
+
+static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = {
+	.resume		= pxa2xx_drv_pcmcia_resume,
+};
+
+static struct platform_driver pxa2xx_pcmcia_driver = {
+	.probe		= pxa2xx_drv_pcmcia_probe,
+	.remove		= pxa2xx_drv_pcmcia_remove,
+	.driver		= {
+		.name	= "pxa2xx-pcmcia",
+		.pm	= &pxa2xx_drv_pcmcia_pm_ops,
+	},
+};
+
+static int __init pxa2xx_pcmcia_init(void)
+{
+	return platform_driver_register(&pxa2xx_pcmcia_driver);
+}
+
+static void __exit pxa2xx_pcmcia_exit(void)
+{
+	platform_driver_unregister(&pxa2xx_pcmcia_driver);
+}
+
+fs_initcall(pxa2xx_pcmcia_init);
+module_exit(pxa2xx_pcmcia_exit);
+
+MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA2xx core socket driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.h b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.h
new file mode 100644
index 0000000..e58c7a4
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_base.h
@@ -0,0 +1,4 @@
+int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt);
+void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops);
+void pxa2xx_configure_sockets(struct device *dev, struct pcmcia_low_level *ops);
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x255.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x255.c
new file mode 100644
index 0000000..da40908
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x255.c
@@ -0,0 +1,128 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x255.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Compulab Ltd., 2003, 2007, 2008
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+
+#include "soc_common.h"
+
+#define GPIO_PCMCIA_SKTSEL	(54)
+#define GPIO_PCMCIA_S0_CD_VALID	(16)
+#define GPIO_PCMCIA_S1_CD_VALID	(17)
+#define GPIO_PCMCIA_S0_RDYINT	(6)
+#define GPIO_PCMCIA_S1_RDYINT	(8)
+#define GPIO_PCMCIA_RESET	(9)
+
+static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
+	if (ret)
+		return ret;
+	gpio_direction_output(GPIO_PCMCIA_RESET, 0);
+
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S1_CD_VALID;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S1_RDYINT;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA1 RDY";
+	}
+
+	return 0;
+}
+
+static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free(GPIO_PCMCIA_RESET);
+}
+
+
+static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				       struct pcmcia_state *state)
+{
+	state->vs_3v  = 0;
+	state->vs_Xv  = 0;
+}
+
+
+static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					  const socket_state_t *state)
+{
+	switch (skt->nr) {
+	case 0:
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_PCMCIA_SKTSEL, 0);
+			udelay(1);
+			gpio_set_value(GPIO_PCMCIA_RESET, 1);
+			udelay(10);
+			gpio_set_value(GPIO_PCMCIA_RESET, 0);
+		}
+		break;
+	case 1:
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_PCMCIA_SKTSEL, 1);
+			udelay(1);
+			gpio_set_value(GPIO_PCMCIA_RESET, 1);
+			udelay(10);
+			gpio_set_value(GPIO_PCMCIA_RESET, 0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = {
+	.owner			= THIS_MODULE,
+	.hw_init		= cmx255_pcmcia_hw_init,
+	.hw_shutdown		= cmx255_pcmcia_shutdown,
+	.socket_state		= cmx255_pcmcia_socket_state,
+	.configure_socket	= cmx255_pcmcia_configure_socket,
+	.nr			= 1,
+};
+
+static struct platform_device *cmx255_pcmcia_device;
+
+int __init cmx255_pcmcia_init(void)
+{
+	int ret;
+
+	cmx255_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+	if (!cmx255_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(cmx255_pcmcia_device, &cmx255_pcmcia_ops,
+				       sizeof(cmx255_pcmcia_ops));
+
+	if (ret == 0) {
+		printk(KERN_INFO "Registering cm-x255 PCMCIA interface.\n");
+		ret = platform_device_add(cmx255_pcmcia_device);
+	}
+
+	if (ret)
+		platform_device_put(cmx255_pcmcia_device);
+
+	return ret;
+}
+
+void __exit cmx255_pcmcia_exit(void)
+{
+	platform_device_unregister(cmx255_pcmcia_device);
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x270.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x270.c
new file mode 100644
index 0000000..f59223f
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -0,0 +1,107 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x270.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Compulab Ltd., 2003, 2007, 2008
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+
+#include "soc_common.h"
+
+#define GPIO_PCMCIA_S0_CD_VALID	(84)
+#define GPIO_PCMCIA_S0_RDYINT	(82)
+#define GPIO_PCMCIA_RESET	(53)
+
+static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
+	if (ret)
+		return ret;
+	gpio_direction_output(GPIO_PCMCIA_RESET, 0);
+
+	skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+
+	return ret;
+}
+
+static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free(GPIO_PCMCIA_RESET);
+}
+
+
+static void cmx270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				       struct pcmcia_state *state)
+{
+	state->vs_3v  = 0;
+	state->vs_Xv  = 0;
+}
+
+
+static int cmx270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					  const socket_state_t *state)
+{
+	switch (skt->nr) {
+	case 0:
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_PCMCIA_RESET, 1);
+			udelay(10);
+			gpio_set_value(GPIO_PCMCIA_RESET, 0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level cmx270_pcmcia_ops __initdata = {
+	.owner			= THIS_MODULE,
+	.hw_init		= cmx270_pcmcia_hw_init,
+	.hw_shutdown		= cmx270_pcmcia_shutdown,
+	.socket_state		= cmx270_pcmcia_socket_state,
+	.configure_socket	= cmx270_pcmcia_configure_socket,
+	.nr			= 1,
+};
+
+static struct platform_device *cmx270_pcmcia_device;
+
+int __init cmx270_pcmcia_init(void)
+{
+	int ret;
+
+	cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+	if (!cmx270_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(cmx270_pcmcia_device, &cmx270_pcmcia_ops,
+				       sizeof(cmx270_pcmcia_ops));
+
+	if (ret == 0) {
+		printk(KERN_INFO "Registering cm-x270 PCMCIA interface.\n");
+		ret = platform_device_add(cmx270_pcmcia_device);
+	}
+
+	if (ret)
+		platform_device_put(cmx270_pcmcia_device);
+
+	return ret;
+}
+
+void __exit cmx270_pcmcia_exit(void)
+{
+	platform_device_unregister(cmx270_pcmcia_device);
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x2xx.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x2xx.c
new file mode 100644
index 0000000..6e7dcfd
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_cm_x2xx.c
@@ -0,0 +1,48 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x2xx.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Compulab Ltd., 2003, 2007, 2008
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+int cmx255_pcmcia_init(void);
+int cmx270_pcmcia_init(void);
+void cmx255_pcmcia_exit(void);
+void cmx270_pcmcia_exit(void);
+
+static int __init cmx2xx_pcmcia_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_armcore() && cpu_is_pxa25x())
+		ret = cmx255_pcmcia_init();
+	else if (machine_is_armcore() && cpu_is_pxa27x())
+		ret = cmx270_pcmcia_init();
+
+	return ret;
+}
+
+static void __exit cmx2xx_pcmcia_exit(void)
+{
+	if (machine_is_armcore() && cpu_is_pxa25x())
+		cmx255_pcmcia_exit();
+	else if (machine_is_armcore() && cpu_is_pxa27x())
+		cmx270_pcmcia_exit();
+}
+
+module_init(cmx2xx_pcmcia_init);
+module_exit(cmx2xx_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("CM-x2xx PCMCIA driver");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_colibri.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_colibri.c
new file mode 100644
index 0000000..4dee7b2
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_colibri.c
@@ -0,0 +1,169 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_colibri.c
+ *
+ * Driver for Toradex Colibri PXA270 CF socket
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+#define	COLIBRI270_RESET_GPIO	53
+#define	COLIBRI270_PPEN_GPIO	107
+#define	COLIBRI270_BVD1_GPIO	83
+#define	COLIBRI270_BVD2_GPIO	82
+#define	COLIBRI270_DETECT_GPIO	84
+#define	COLIBRI270_READY_GPIO	1
+
+#define	COLIBRI320_RESET_GPIO	77
+#define	COLIBRI320_PPEN_GPIO	57
+#define	COLIBRI320_BVD1_GPIO	53
+#define	COLIBRI320_BVD2_GPIO	79
+#define	COLIBRI320_DETECT_GPIO	81
+#define	COLIBRI320_READY_GPIO	29
+
+enum {
+	DETECT = 0,
+	READY = 1,
+	BVD1 = 2,
+	BVD2 = 3,
+	PPEN = 4,
+	RESET = 5,
+};
+
+/* Contents of this array are configured on-the-fly in init function */
+static struct gpio colibri_pcmcia_gpios[] = {
+	{ 0,	GPIOF_IN,	"PCMCIA Detect" },
+	{ 0,	GPIOF_IN,	"PCMCIA Ready" },
+	{ 0,	GPIOF_IN,	"PCMCIA BVD1" },
+	{ 0,	GPIOF_IN,	"PCMCIA BVD2" },
+	{ 0,	GPIOF_INIT_LOW,	"PCMCIA PPEN" },
+	{ 0,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
+};
+
+static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(colibri_pcmcia_gpios,
+				ARRAY_SIZE(colibri_pcmcia_gpios));
+	if (ret)
+		goto err1;
+
+	skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio);
+	skt->stat[SOC_STAT_CD].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
+	skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+
+err1:
+	return ret;
+}
+
+static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(colibri_pcmcia_gpios,
+			ARRAY_SIZE(colibri_pcmcia_gpios));
+}
+
+static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+
+	state->detect = !!gpio_get_value(colibri_pcmcia_gpios[DETECT].gpio);
+	state->ready  = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio);
+	state->bvd1   = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio);
+	state->bvd2   = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio);
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int
+colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	gpio_set_value(colibri_pcmcia_gpios[PPEN].gpio,
+			!(state->Vcc == 33 && state->Vpp < 50));
+	gpio_set_value(colibri_pcmcia_gpios[RESET].gpio,
+			state->flags & SS_RESET);
+	return 0;
+}
+
+static struct pcmcia_low_level colibri_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 0,
+	.nr			= 1,
+
+	.hw_init		= colibri_pcmcia_hw_init,
+	.hw_shutdown		= colibri_pcmcia_hw_shutdown,
+
+	.socket_state		= colibri_pcmcia_socket_state,
+	.configure_socket	= colibri_pcmcia_configure_socket,
+};
+
+static struct platform_device *colibri_pcmcia_device;
+
+static int __init colibri_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_colibri() && !machine_is_colibri320())
+		return -ENODEV;
+
+	colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!colibri_pcmcia_device)
+		return -ENOMEM;
+
+	/* Colibri PXA270 */
+	if (machine_is_colibri()) {
+		colibri_pcmcia_gpios[RESET].gpio	= COLIBRI270_RESET_GPIO;
+		colibri_pcmcia_gpios[PPEN].gpio		= COLIBRI270_PPEN_GPIO;
+		colibri_pcmcia_gpios[BVD1].gpio		= COLIBRI270_BVD1_GPIO;
+		colibri_pcmcia_gpios[BVD2].gpio		= COLIBRI270_BVD2_GPIO;
+		colibri_pcmcia_gpios[DETECT].gpio	= COLIBRI270_DETECT_GPIO;
+		colibri_pcmcia_gpios[READY].gpio	= COLIBRI270_READY_GPIO;
+	/* Colibri PXA320 */
+	} else if (machine_is_colibri320()) {
+		colibri_pcmcia_gpios[RESET].gpio	= COLIBRI320_RESET_GPIO;
+		colibri_pcmcia_gpios[PPEN].gpio		= COLIBRI320_PPEN_GPIO;
+		colibri_pcmcia_gpios[BVD1].gpio		= COLIBRI320_BVD1_GPIO;
+		colibri_pcmcia_gpios[BVD2].gpio		= COLIBRI320_BVD2_GPIO;
+		colibri_pcmcia_gpios[DETECT].gpio	= COLIBRI320_DETECT_GPIO;
+		colibri_pcmcia_gpios[READY].gpio	= COLIBRI320_READY_GPIO;
+	}
+
+	ret = platform_device_add_data(colibri_pcmcia_device,
+		&colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(colibri_pcmcia_device);
+
+	if (ret)
+		platform_device_put(colibri_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit colibri_pcmcia_exit(void)
+{
+	platform_device_unregister(colibri_pcmcia_device);
+}
+
+module_init(colibri_pcmcia_init);
+module_exit(colibri_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_e740.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_e740.c
new file mode 100644
index 0000000..8751a32
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_e740.c
@@ -0,0 +1,130 @@
+/*
+ * Toshiba e740 PCMCIA specific routines.
+ *
+ * (c) 2004 Ian Molton <spyro@f2s.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <mach/eseries-gpio.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD0;
+		skt->stat[SOC_STAT_CD].name = "CF card detect";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY0;
+		skt->stat[SOC_STAT_RDY].name = "CF ready";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD1;
+		skt->stat[SOC_STAT_CD].name = "Wifi switch";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY1;
+		skt->stat[SOC_STAT_RDY].name = "Wifi ready";
+	}
+
+	return 0;
+}
+
+static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					const socket_state_t *state)
+{
+	if (state->flags & SS_RESET) {
+		if (skt->nr == 0)
+			gpio_set_value(GPIO_E740_PCMCIA_RST0, 1);
+		else
+			gpio_set_value(GPIO_E740_PCMCIA_RST1, 1);
+	} else {
+		if (skt->nr == 0)
+			gpio_set_value(GPIO_E740_PCMCIA_RST0, 0);
+		else
+			gpio_set_value(GPIO_E740_PCMCIA_RST1, 0);
+	}
+
+	switch (state->Vcc) {
+	case 0:	/* Socket off */
+		if (skt->nr == 0)
+			gpio_set_value(GPIO_E740_PCMCIA_PWR0, 0);
+		else
+			gpio_set_value(GPIO_E740_PCMCIA_PWR1, 1);
+		break;
+	case 50:
+	case 33: /* socket on */
+		if (skt->nr == 0)
+			gpio_set_value(GPIO_E740_PCMCIA_PWR0, 1);
+		else
+			gpio_set_value(GPIO_E740_PCMCIA_PWR1, 0);
+		break;
+	default:
+		printk(KERN_ERR "e740_cs: Unsupported Vcc: %d\n", state->Vcc);
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level e740_pcmcia_ops = {
+	.owner            = THIS_MODULE,
+	.hw_init          = e740_pcmcia_hw_init,
+	.socket_state     = e740_pcmcia_socket_state,
+	.configure_socket = e740_pcmcia_configure_socket,
+	.nr               = 2,
+};
+
+static struct platform_device *e740_pcmcia_device;
+
+static int __init e740_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_e740())
+		return -ENODEV;
+
+	e740_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!e740_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(e740_pcmcia_device, &e740_pcmcia_ops,
+					sizeof(e740_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(e740_pcmcia_device);
+
+	if (ret)
+		platform_device_put(e740_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit e740_pcmcia_exit(void)
+{
+	platform_device_unregister(e740_pcmcia_device);
+}
+
+module_init(e740_pcmcia_init);
+module_exit(e740_pcmcia_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_DESCRIPTION("e740 PCMCIA platform support");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_hx4700.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_hx4700.c
new file mode 100644
index 0000000..7dfef3e
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_hx4700.c
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <mach/hx4700.h>
+
+#include "soc_common.h"
+
+static struct gpio gpios[] = {
+	{ GPIO114_HX4700_CF_RESET,    GPIOF_OUT_INIT_LOW,   "CF reset"        },
+	{ EGPIO4_CF_3V3_ON,           GPIOF_OUT_INIT_LOW,   "CF 3.3V enable"  },
+};
+
+static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+	if (ret)
+		goto out;
+
+	/*
+	 * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq().
+	 * The asic3 default IRQ type is level trigger low level detect, exactly
+	 * the the signal present on GPIOD4_CF_nCD when a CF card is inserted.
+	 * If the IRQ type is not changed, the asic3 interrupt handler will loop
+	 * repeatedly because it is unable to clear the level trigger interrupt.
+	 */
+	irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH);
+
+	skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+out:
+	return ret;
+}
+
+static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(gpios, ARRAY_SIZE(gpios));
+}
+
+static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+	struct pcmcia_state *state)
+{
+	state->vs_3v = 1;
+	state->vs_Xv = 0;
+}
+
+static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+	const socket_state_t *state)
+{
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(EGPIO4_CF_3V3_ON, 0);
+		break;
+	case 33:
+		gpio_set_value(EGPIO4_CF_3V3_ON, 1);
+		break;
+	default:
+		printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc);
+		return -EINVAL;
+	}
+
+	gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0);
+
+	return 0;
+}
+
+static struct pcmcia_low_level hx4700_pcmcia_ops = {
+	.owner          = THIS_MODULE,
+	.nr             = 1,
+	.hw_init        = hx4700_pcmcia_hw_init,
+	.hw_shutdown    = hx4700_pcmcia_hw_shutdown,
+	.socket_state   = hx4700_pcmcia_socket_state,
+	.configure_socket = hx4700_pcmcia_configure_socket,
+};
+
+static struct platform_device *hx4700_pcmcia_device;
+
+static int __init hx4700_pcmcia_init(void)
+{
+	struct platform_device *pdev;
+
+	if (!machine_is_h4700())
+		return -ENODEV;
+
+	pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1,
+		&hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops));
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	hx4700_pcmcia_device = pdev;
+
+	return 0;
+}
+
+static void __exit hx4700_pcmcia_exit(void)
+{
+	platform_device_unregister(hx4700_pcmcia_device);
+}
+
+module_init(hx4700_pcmcia_init);
+module_exit(hx4700_pcmcia_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_mainstone.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_mainstone.c
new file mode 100644
index 0000000..7e32e25
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_mainstone.c
@@ -0,0 +1,170 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_mainstone.c
+ *
+ * Mainstone PCMCIA specific routines.
+ *
+ * Created:	May 12, 2004
+ * Author:	Nicolas Pitre
+ * Copyright:	MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <mach/mainstone.h>
+
+#include "soc_common.h"
+
+
+static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	/*
+	 * Setup default state of GPIO outputs
+	 * before we enable them as outputs.
+	 */
+	if (skt->nr == 0) {
+		skt->socket.pci_irq = MAINSTONE_S0_IRQ;
+		skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+		skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
+		skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
+	} else {
+		skt->socket.pci_irq = MAINSTONE_S1_IRQ;
+		skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+		skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
+		skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
+	}
+	return 0;
+}
+
+static unsigned long mst_pcmcia_status[2];
+
+static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				    struct pcmcia_state *state)
+{
+	unsigned long status, flip;
+
+	status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
+	flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
+
+	/*
+	 * Workaround for STSCHG which can't be deasserted:
+	 * We therefore disable/enable corresponding IRQs
+	 * as needed to avoid IRQ locks.
+	 */
+	if (flip) {
+		mst_pcmcia_status[skt->nr] = status;
+		if (status & MST_PCMCIA_nSTSCHG_BVD1)
+			enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
+						   : MAINSTONE_S1_STSCHG_IRQ );
+		else
+			disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
+						    : MAINSTONE_S1_STSCHG_IRQ );
+	}
+
+	state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1;
+	state->ready  = (status & MST_PCMCIA_nIRQ) ? 1 : 0;
+	state->bvd1   = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0;
+	state->bvd2   = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
+	state->vs_3v  = (status & MST_PCMCIA_nVS1) ? 0 : 1;
+	state->vs_Xv  = (status & MST_PCMCIA_nVS2) ? 0 : 1;
+}
+
+static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				       const socket_state_t *state)
+{
+	unsigned long power = 0;
+	int ret = 0;
+
+	switch (state->Vcc) {
+	case 0:  power |= MST_PCMCIA_PWR_VCC_0;  break;
+	case 33: power |= MST_PCMCIA_PWR_VCC_33; break;
+	case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
+	default:
+		 printk(KERN_ERR "%s(): bad Vcc %u\n",
+				 __func__, state->Vcc);
+		 ret = -1;
+	}
+
+	switch (state->Vpp) {
+	case 0:   power |= MST_PCMCIA_PWR_VPP_0;   break;
+	case 120: power |= MST_PCMCIA_PWR_VPP_120; break;
+	default:
+		  if(state->Vpp == state->Vcc) {
+			  power |= MST_PCMCIA_PWR_VPP_VCC;
+		  } else {
+			  printk(KERN_ERR "%s(): bad Vpp %u\n",
+					  __func__, state->Vpp);
+			  ret = -1;
+		  }
+	}
+
+	if (state->flags & SS_RESET)
+	       power |= MST_PCMCIA_RESET;
+
+	switch (skt->nr) {
+	case 0:  MST_PCMCIA0 = power; break;
+	case 1:  MST_PCMCIA1 = power; break;
+	default: ret = -1;
+	}
+
+	return ret;
+}
+
+static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
+	.owner			= THIS_MODULE,
+	.hw_init		= mst_pcmcia_hw_init,
+	.socket_state		= mst_pcmcia_socket_state,
+	.configure_socket	= mst_pcmcia_configure_socket,
+	.nr			= 2,
+};
+
+static struct platform_device *mst_pcmcia_device;
+
+static int __init mst_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_mainstone())
+		return -ENODEV;
+
+	mst_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!mst_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(mst_pcmcia_device, &mst_pcmcia_ops,
+				       sizeof(mst_pcmcia_ops));
+	if (ret == 0)
+		ret = platform_device_add(mst_pcmcia_device);
+
+	if (ret)
+		platform_device_put(mst_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit mst_pcmcia_exit(void)
+{
+	platform_device_unregister(mst_pcmcia_device);
+}
+
+fs_initcall(mst_pcmcia_init);
+module_exit(mst_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmld.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmld.c
new file mode 100644
index 0000000..ed7d4db
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmld.c
@@ -0,0 +1,114 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_palmld.c
+ *
+ * Driver for Palm LifeDrive PCMCIA
+ *
+ * Copyright (C) 2006 Alex Osborne <ato@meshy.org>
+ * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <mach/palmld.h>
+#include "soc_common.h"
+
+static struct gpio palmld_pcmcia_gpios[] = {
+	{ GPIO_NR_PALMLD_PCMCIA_POWER,	GPIOF_INIT_LOW,	"PCMCIA Power" },
+	{ GPIO_NR_PALMLD_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
+};
+
+static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(palmld_pcmcia_gpios,
+				ARRAY_SIZE(palmld_pcmcia_gpios));
+
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMLD_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+	return ret;
+}
+
+static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(palmld_pcmcia_gpios, ARRAY_SIZE(palmld_pcmcia_gpios));
+}
+
+static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->detect = 1; /* always inserted */
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					const socket_state_t *state)
+{
+	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1);
+	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET,
+			!!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static struct pcmcia_low_level palmld_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 1,
+	.nr			= 1,
+
+	.hw_init		= palmld_pcmcia_hw_init,
+	.hw_shutdown		= palmld_pcmcia_hw_shutdown,
+
+	.socket_state		= palmld_pcmcia_socket_state,
+	.configure_socket	= palmld_pcmcia_configure_socket,
+};
+
+static struct platform_device *palmld_pcmcia_device;
+
+static int __init palmld_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_palmld())
+		return -ENODEV;
+
+	palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!palmld_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops,
+					sizeof(palmld_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(palmld_pcmcia_device);
+
+	if (ret)
+		platform_device_put(palmld_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit palmld_pcmcia_exit(void)
+{
+	platform_device_unregister(palmld_pcmcia_device);
+}
+
+module_init(palmld_pcmcia_init);
+module_exit(palmld_pcmcia_exit);
+
+MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
+	    " Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtc.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtc.c
new file mode 100644
index 0000000..81225a7
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtc.c
@@ -0,0 +1,166 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_palmtc.c
+ *
+ * Driver for Palm Tungsten|C PCMCIA
+ *
+ * Copyright (C) 2008 Alex Osborne <ato@meshy.org>
+ * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <asm/mach-types.h>
+#include <mach/palmtc.h>
+#include "soc_common.h"
+
+static struct gpio palmtc_pcmcia_gpios[] = {
+	{ GPIO_NR_PALMTC_PCMCIA_POWER1,	GPIOF_INIT_LOW,	"PCMCIA Power 1" },
+	{ GPIO_NR_PALMTC_PCMCIA_POWER2,	GPIOF_INIT_LOW,	"PCMCIA Power 2" },
+	{ GPIO_NR_PALMTC_PCMCIA_POWER3,	GPIOF_INIT_LOW,	"PCMCIA Power 3" },
+	{ GPIO_NR_PALMTC_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
+	{ GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN,	"PCMCIA Power Ready" },
+};
+
+static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(palmtc_pcmcia_gpios,
+				ARRAY_SIZE(palmtc_pcmcia_gpios));
+
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+	return ret;
+}
+
+static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios));
+}
+
+static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->detect = 1; /* always inserted */
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int palmtc_wifi_powerdown(void)
+{
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
+	mdelay(40);
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
+	return 0;
+}
+
+static int palmtc_wifi_powerup(void)
+{
+	int timeout = 50;
+
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
+	mdelay(50);
+
+	/* Power up the card, 1.8V first, after a while 3.3V */
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
+	mdelay(100);
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
+
+	/* Wait till the card is ready */
+	while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
+		timeout) {
+		mdelay(1);
+		timeout--;
+	}
+
+	/* Power down the WiFi in case of error */
+	if (!timeout) {
+		palmtc_wifi_powerdown();
+		return 1;
+	}
+
+	/* Reset the card */
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
+	mdelay(20);
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
+	mdelay(25);
+
+	gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
+
+	return 0;
+}
+
+static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					const socket_state_t *state)
+{
+	int ret = 1;
+
+	if (state->Vcc == 0)
+		ret = palmtc_wifi_powerdown();
+	else if (state->Vcc == 33)
+		ret = palmtc_wifi_powerup();
+
+	return ret;
+}
+
+static struct pcmcia_low_level palmtc_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 0,
+	.nr			= 1,
+
+	.hw_init		= palmtc_pcmcia_hw_init,
+	.hw_shutdown		= palmtc_pcmcia_hw_shutdown,
+
+	.socket_state		= palmtc_pcmcia_socket_state,
+	.configure_socket	= palmtc_pcmcia_configure_socket,
+};
+
+static struct platform_device *palmtc_pcmcia_device;
+
+static int __init palmtc_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_palmtc())
+		return -ENODEV;
+
+	palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!palmtc_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
+					sizeof(palmtc_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(palmtc_pcmcia_device);
+
+	if (ret)
+		platform_device_put(palmtc_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit palmtc_pcmcia_exit(void)
+{
+	platform_device_unregister(palmtc_pcmcia_device);
+}
+
+module_init(palmtc_pcmcia_init);
+module_exit(palmtc_pcmcia_exit);
+
+MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
+	    " Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtx.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtx.c
new file mode 100644
index 0000000..069b6bb
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_palmtx.c
@@ -0,0 +1,115 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_palmtx.c
+ *
+ * Driver for Palm T|X PCMCIA
+ *
+ * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <mach/palmtx.h>
+#include "soc_common.h"
+
+static struct gpio palmtx_pcmcia_gpios[] = {
+	{ GPIO_NR_PALMTX_PCMCIA_POWER1,	GPIOF_INIT_LOW,	"PCMCIA Power 1" },
+	{ GPIO_NR_PALMTX_PCMCIA_POWER2,	GPIOF_INIT_LOW,	"PCMCIA Power 2" },
+	{ GPIO_NR_PALMTX_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
+};
+
+static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_array(palmtx_pcmcia_gpios,
+				ARRAY_SIZE(palmtx_pcmcia_gpios));
+
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTX_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+	return ret;
+}
+
+static void palmtx_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free_array(palmtx_pcmcia_gpios, ARRAY_SIZE(palmtx_pcmcia_gpios));
+}
+
+static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->detect = 1; /* always inserted */
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int
+palmtx_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER1, 1);
+	gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER2, 1);
+	gpio_set_value(GPIO_NR_PALMTX_PCMCIA_RESET,
+			!!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static struct pcmcia_low_level palmtx_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 0,
+	.nr			= 1,
+
+	.hw_init		= palmtx_pcmcia_hw_init,
+	.hw_shutdown		= palmtx_pcmcia_hw_shutdown,
+
+	.socket_state		= palmtx_pcmcia_socket_state,
+	.configure_socket	= palmtx_pcmcia_configure_socket,
+};
+
+static struct platform_device *palmtx_pcmcia_device;
+
+static int __init palmtx_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_palmtx())
+		return -ENODEV;
+
+	palmtx_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!palmtx_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(palmtx_pcmcia_device, &palmtx_pcmcia_ops,
+					sizeof(palmtx_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(palmtx_pcmcia_device);
+
+	if (ret)
+		platform_device_put(palmtx_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit palmtx_pcmcia_exit(void)
+{
+	platform_device_unregister(palmtx_pcmcia_device);
+}
+
+module_init(palmtx_pcmcia_init);
+module_exit(palmtx_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Palm T|X");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_sharpsl.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_sharpsl.c
new file mode 100644
index 0000000..89ebd8c
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -0,0 +1,262 @@
+/*
+ * Sharp SL-C7xx Series PCMCIA routines
+ *
+ * Copyright (c) 2004-2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/hardware/scoop.h>
+
+#include "soc_common.h"
+
+#define	NO_KEEP_VS 0x0001
+#define SCOOP_DEV platform_scoop_config->devs
+
+static void sharpsl_pcmcia_init_reset(struct soc_pcmcia_socket *skt)
+{
+	struct scoop_pcmcia_dev *scoopdev = &SCOOP_DEV[skt->nr];
+
+	reset_scoop(scoopdev->dev);
+
+	/* Shared power controls need to be handled carefully */
+	if (platform_scoop_config->power_ctrl)
+		platform_scoop_config->power_ctrl(scoopdev->dev, 0x0000, skt->nr);
+	else
+		write_scoop_reg(scoopdev->dev, SCOOP_CPR, 0x0000);
+
+	scoopdev->keep_vs = NO_KEEP_VS;
+	scoopdev->keep_rd = 0;
+}
+
+static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
+		skt->stat[SOC_STAT_CD].irq = SCOOP_DEV[skt->nr].cd_irq;
+		skt->stat[SOC_STAT_CD].name = SCOOP_DEV[skt->nr].cd_irq_str;
+	}
+
+	skt->socket.pci_irq = SCOOP_DEV[skt->nr].irq;
+
+	return 0;
+}
+
+static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				    struct pcmcia_state *state)
+{
+	unsigned short cpr, csr;
+	struct device *scoop = SCOOP_DEV[skt->nr].dev;
+
+	cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR);
+
+	write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
+	write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
+	write_scoop_reg(scoop, SCOOP_IRM, 0x0000);
+	csr = read_scoop_reg(scoop, SCOOP_CSR);
+	if (csr & 0x0004) {
+		/* card eject */
+		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+		SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
+	}
+	else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) {
+		/* keep vs1,vs2 */
+		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+		csr |= SCOOP_DEV[skt->nr].keep_vs;
+	}
+	else if (cpr & 0x0003) {
+		/* power on */
+		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+		SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0);
+	}
+	else {
+		/* card detect */
+	        if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) {
+	                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+	        } else {
+		        write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+	        }
+	}
+
+	state->detect = (csr & 0x0004) ? 0 : 1;
+	state->ready  = (csr & 0x0002) ? 1 : 0;
+	state->bvd1   = (csr & 0x0010) ? 1 : 0;
+	state->bvd2   = (csr & 0x0020) ? 1 : 0;
+	state->wrprot = (csr & 0x0008) ? 1 : 0;
+	state->vs_3v  = (csr & 0x0040) ? 0 : 1;
+	state->vs_Xv  = (csr & 0x0080) ? 0 : 1;
+
+	if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) {
+		printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr);
+	}
+}
+
+
+static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				       const socket_state_t *state)
+{
+	unsigned long flags;
+	struct device *scoop = SCOOP_DEV[skt->nr].dev;
+
+	unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
+
+	switch (state->Vcc) {
+	case	0:  	break;
+	case 	33: 	break;
+	case	50: 	break;
+	default:
+		 printk(KERN_ERR "sharpsl_pcmcia_configure_socket(): bad Vcc %u\n", state->Vcc);
+		 return -1;
+	}
+
+	if ((state->Vpp!=state->Vcc) && (state->Vpp!=0)) {
+		printk(KERN_ERR "CF slot cannot support Vpp %u\n", state->Vpp);
+		return -1;
+	}
+
+	local_irq_save(flags);
+
+	nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010;
+	ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083;
+	nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
+	nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
+
+	if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) {
+	        ncpr |= (state->Vcc == 33) ? 0x0002 :
+		        (state->Vcc == 50) ? 0x0002 : 0;
+	} else {
+	        ncpr |= (state->Vcc == 33) ? 0x0001 :
+		        (state->Vcc == 50) ? 0x0002 : 0;
+	}
+	nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0;
+	ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0;
+	nccr |= (state->flags&SS_RESET)? 0x0080: 0;
+	nimr |=	((skt->status&SS_DETECT) ? 0x0004 : 0)|
+			((skt->status&SS_READY)  ? 0x0002 : 0)|
+			((skt->status&SS_BATDEAD)? 0x0010 : 0)|
+			((skt->status&SS_BATWARN)? 0x0020 : 0)|
+			((skt->status&SS_STSCHG) ? 0x0010 : 0)|
+			((skt->status&SS_WRPROT) ? 0x0008 : 0);
+
+	if (!(ncpr & 0x0003)) {
+		SCOOP_DEV[skt->nr].keep_rd = 0;
+	} else if (!SCOOP_DEV[skt->nr].keep_rd) {
+		if (nccr & 0x0080)
+			SCOOP_DEV[skt->nr].keep_rd = 1;
+		else
+			nccr |= 0x0080;
+	}
+
+	if (mcr != nmcr)
+		write_scoop_reg(scoop, SCOOP_MCR, nmcr);
+	if (cpr != ncpr) {
+		if (platform_scoop_config->power_ctrl)
+			platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr);
+		else
+		        write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+	}
+	if (ccr != nccr)
+		write_scoop_reg(scoop, SCOOP_CCR, nccr);
+	if (imr != nimr)
+		write_scoop_reg(scoop, SCOOP_IMR, nimr);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+	sharpsl_pcmcia_init_reset(skt);
+
+	/* Enable interrupt */
+	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
+	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
+	SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
+}
+
+static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	sharpsl_pcmcia_init_reset(skt);
+}
+
+static struct pcmcia_low_level sharpsl_pcmcia_ops = {
+	.owner                  = THIS_MODULE,
+	.hw_init                = sharpsl_pcmcia_hw_init,
+	.socket_state           = sharpsl_pcmcia_socket_state,
+	.configure_socket       = sharpsl_pcmcia_configure_socket,
+	.socket_init            = sharpsl_pcmcia_socket_init,
+	.socket_suspend         = sharpsl_pcmcia_socket_suspend,
+	.first                  = 0,
+	.nr                     = 0,
+};
+
+#ifdef CONFIG_SA1100_COLLIE
+#include "sa11xx_base.h"
+
+int pcmcia_collie_init(struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (machine_is_collie())
+               ret = sa11xx_drv_pcmcia_probe(dev, &sharpsl_pcmcia_ops, 0, 1);
+
+       return ret;
+}
+
+#else
+
+static struct platform_device *sharpsl_pcmcia_device;
+
+static int __init sharpsl_pcmcia_init(void)
+{
+	int ret;
+
+	if (!platform_scoop_config)
+		return -ENODEV;
+
+	sharpsl_pcmcia_ops.nr = platform_scoop_config->num_devs;
+	sharpsl_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+	if (!sharpsl_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(sharpsl_pcmcia_device,
+			&sharpsl_pcmcia_ops, sizeof(sharpsl_pcmcia_ops));
+	if (ret == 0) {
+		sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
+		ret = platform_device_add(sharpsl_pcmcia_device);
+	}
+
+	if (ret)
+		platform_device_put(sharpsl_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit sharpsl_pcmcia_exit(void)
+{
+	platform_device_unregister(sharpsl_pcmcia_device);
+}
+
+fs_initcall(sharpsl_pcmcia_init);
+module_exit(sharpsl_pcmcia_exit);
+#endif
+
+MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_stargate2.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_stargate2.c
new file mode 100644
index 0000000..1d73c44
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_stargate2.c
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_stargate2.c
+ *
+ * Stargate 2 PCMCIA specific routines.
+ *
+ * Created:	December 6, 2005
+ * Author:	Ed C. Epp
+ * Copyright:	Intel Corp 2005
+ *              Jonathan Cameron <jic23@cam.ac.uk> 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+#define SG2_S0_POWER_CTL	108
+#define SG2_S0_GPIO_RESET	82
+#define SG2_S0_GPIO_DETECT	53
+#define SG2_S0_GPIO_READY	81
+
+static struct gpio sg2_pcmcia_gpios[] = {
+	{ SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
+	{ SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
+};
+
+static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	skt->stat[SOC_STAT_CD].gpio = SG2_S0_GPIO_DETECT;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_RDY].gpio = SG2_S0_GPIO_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+	return 0;
+}
+
+static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				    struct pcmcia_state *state)
+{
+	state->bvd1   = 0; /* not available - battery detect on card */
+	state->bvd2   = 0; /* not available */
+	state->vs_3v  = 1; /* not available - voltage detect for card */
+	state->vs_Xv  = 0; /* not available */
+}
+
+static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				       const socket_state_t *state)
+{
+	/* Enable card power */
+	switch (state->Vcc) {
+	case 0:
+		/* sets power ctl register high */
+		gpio_set_value(SG2_S0_POWER_CTL, 1);
+		break;
+	case 33:
+	case 50:
+		/* sets power control register low (clear) */
+		gpio_set_value(SG2_S0_POWER_CTL, 0);
+		msleep(100);
+		break;
+	default:
+		pr_err("%s(): bad Vcc %u\n",
+		       __func__, state->Vcc);
+		return -1;
+	}
+
+	/* reset */
+	gpio_set_value(SG2_S0_GPIO_RESET, !!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static struct pcmcia_low_level sg2_pcmcia_ops __initdata = {
+	.owner			= THIS_MODULE,
+	.hw_init		= sg2_pcmcia_hw_init,
+	.socket_state		= sg2_pcmcia_socket_state,
+	.configure_socket	= sg2_pcmcia_configure_socket,
+	.nr			= 1,
+};
+
+static struct platform_device *sg2_pcmcia_device;
+
+static int __init sg2_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_stargate2())
+		return -ENODEV;
+
+	sg2_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!sg2_pcmcia_device)
+		return -ENOMEM;
+
+	ret = gpio_request_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
+	if (ret)
+		goto error_put_platform_device;
+
+	ret = platform_device_add_data(sg2_pcmcia_device,
+				       &sg2_pcmcia_ops,
+				       sizeof(sg2_pcmcia_ops));
+	if (ret)
+		goto error_free_gpios;
+
+	ret = platform_device_add(sg2_pcmcia_device);
+	if (ret)
+		goto error_free_gpios;
+
+	return 0;
+error_free_gpios:
+	gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
+error_put_platform_device:
+	platform_device_put(sg2_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit sg2_pcmcia_exit(void)
+{
+	platform_device_unregister(sg2_pcmcia_device);
+	gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
+}
+
+fs_initcall(sg2_pcmcia_init);
+module_exit(sg2_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_trizeps4.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_trizeps4.c
new file mode 100644
index 0000000..d326ba1
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_trizeps4.c
@@ -0,0 +1,203 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_trizeps4.c
+ *
+ * TRIZEPS PCMCIA specific routines.
+ *
+ * Author:	Jürgen Schindele
+ * Created:	20 02, 2006
+ * Copyright:	Jürgen Schindele
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <mach/trizeps4.h>
+
+#include "soc_common.h"
+
+extern void board_pcmcia_power(int power);
+
+static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	/* we dont have voltage/card/ready detection
+	 * so we dont need interrupts for it
+	 */
+	switch (skt->nr) {
+	case 0:
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCD;
+		skt->stat[SOC_STAT_CD].name = "cs0_cd";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY;
+		skt->stat[SOC_STAT_RDY].name = "cs0_rdy";
+		break;
+	default:
+		break;
+	}
+	/* release the reset of this card */
+	pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
+
+	return 0;
+}
+
+static unsigned long trizeps_pcmcia_status[2];
+
+static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				struct pcmcia_state *state)
+{
+	unsigned short status = 0, change;
+	status = CFSR_readw();
+	change = (status ^ trizeps_pcmcia_status[skt->nr]) &
+				ConXS_CFSR_BVD_MASK;
+	if (change) {
+		trizeps_pcmcia_status[skt->nr] = status;
+		if (status & ConXS_CFSR_BVD1) {
+			/* enable_irq empty */
+		} else {
+			/* disable_irq empty */
+		}
+	}
+
+	switch (skt->nr) {
+	case 0:
+		/* just fill in fix states */
+		state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
+		state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
+		state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
+		state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
+		break;
+
+#ifndef CONFIG_MACH_TRIZEPS_CONXS
+	/* on ConXS we only have one slot. Second is inactive */
+	case 1:
+		state->detect = 0;
+		state->ready  = 0;
+		state->bvd1   = 0;
+		state->bvd2   = 0;
+		state->vs_3v  = 0;
+		state->vs_Xv  = 0;
+		break;
+
+#endif
+	}
+}
+
+static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	int ret = 0;
+	unsigned short power = 0;
+
+	/* we do nothing here just check a bit */
+	switch (state->Vcc) {
+	case 0:  power &= 0xfc; break;
+	case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
+	case 50:
+		pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
+		break;
+	default:
+		pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
+		ret = -1;
+	}
+
+	switch (state->Vpp) {
+	case 0:  power &= 0xf3; break;
+	case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
+	case 120:
+		pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
+		break;
+	default:
+		if (state->Vpp != state->Vcc) {
+			pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
+			ret = -1;
+		}
+	}
+
+	switch (skt->nr) {
+	case 0:			 /* we only have 3.3V */
+		board_pcmcia_power(power);
+		break;
+
+#ifndef CONFIG_MACH_TRIZEPS_CONXS
+	/* on ConXS we only have one slot. Second is inactive */
+	case 1:
+#endif
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+	/* default is on */
+	board_pcmcia_power(0x9);
+}
+
+static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	board_pcmcia_power(0x0);
+}
+
+static struct pcmcia_low_level trizeps_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.hw_init		= trizeps_pcmcia_hw_init,
+	.socket_state		= trizeps_pcmcia_socket_state,
+	.configure_socket	= trizeps_pcmcia_configure_socket,
+	.socket_init		= trizeps_pcmcia_socket_init,
+	.socket_suspend		= trizeps_pcmcia_socket_suspend,
+#ifdef CONFIG_MACH_TRIZEPS_CONXS
+	.nr			= 1,
+#else
+	.nr			= 2,
+#endif
+	.first			= 0,
+};
+
+static struct platform_device *trizeps_pcmcia_device;
+
+static int __init trizeps_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_trizeps4() && !machine_is_trizeps4wl())
+		return -ENODEV;
+
+	trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!trizeps_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(trizeps_pcmcia_device,
+			&trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
+
+	if (ret == 0)
+		ret = platform_device_add(trizeps_pcmcia_device);
+
+	if (ret)
+		platform_device_put(trizeps_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit trizeps_pcmcia_exit(void)
+{
+	platform_device_unregister(trizeps_pcmcia_device);
+}
+
+fs_initcall(trizeps_pcmcia_init);
+module_exit(trizeps_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juergen Schindele");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_viper.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_viper.c
new file mode 100644
index 0000000..7ac6647
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_viper.c
@@ -0,0 +1,182 @@
+/*
+ * Viper/Zeus PCMCIA support
+ *   Copyright 2004 Arcom Control Systems
+ *
+ * Maintained by Marc Zyngier <maz@misterjones.org>
+ *
+ * Based on:
+ *   iPAQ h2200 PCMCIA support
+ *   Copyright 2004 Koen Kooi <koen@vestingbar.nl>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/irq.h>
+
+#include <linux/platform_data/pcmcia-pxa2xx_viper.h>
+
+#include "soc_common.h"
+#include "pxa2xx_base.h"
+
+static struct platform_device *arcom_pcmcia_dev;
+
+static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
+{
+	return arcom_pcmcia_dev->dev.platform_data;
+}
+
+static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+	unsigned long flags;
+
+	skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA_CD";
+	skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio;
+	skt->stat[SOC_STAT_RDY].name = "CF ready";
+
+	if (gpio_request(pdata->pwr_gpio, "CF power"))
+		goto err_request_pwr;
+
+	local_irq_save(flags);
+
+	if (gpio_direction_output(pdata->pwr_gpio, 0)) {
+		local_irq_restore(flags);
+		goto err_dir;
+	}
+
+	local_irq_restore(flags);
+
+	return 0;
+
+err_dir:
+	gpio_free(pdata->pwr_gpio);
+err_request_pwr:
+	dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
+	return -1;
+}
+
+/*
+ * Release all resources.
+ */
+static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+
+	gpio_free(pdata->pwr_gpio);
+}
+
+static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				      struct pcmcia_state *state)
+{
+	state->vs_3v  = 1; /* Can only apply 3.3V */
+	state->vs_Xv  = 0;
+}
+
+static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+					 const socket_state_t *state)
+{
+	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+
+	/* Silently ignore Vpp, output enable, speaker enable. */
+	pdata->reset(state->flags & SS_RESET);
+
+	/* Apply socket voltage */
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(pdata->pwr_gpio, 0);
+		break;
+	case 33:
+		gpio_set_value(pdata->pwr_gpio, 1);
+		break;
+	default:
+		dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc);
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level viper_pcmcia_ops = {
+	.owner          	= THIS_MODULE,
+	.hw_init        	= viper_pcmcia_hw_init,
+	.hw_shutdown		= viper_pcmcia_hw_shutdown,
+	.socket_state		= viper_pcmcia_socket_state,
+	.configure_socket	= viper_pcmcia_configure_socket,
+	.nr         		= 1,
+};
+
+static struct platform_device *viper_pcmcia_device;
+
+static int viper_pcmcia_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	/* I can't imagine more than one device, but you never know... */
+	if (arcom_pcmcia_dev)
+		return -EEXIST;
+
+	if (!pdev->dev.platform_data)
+		return -EINVAL;
+
+	viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!viper_pcmcia_device)
+		return -ENOMEM;
+
+	arcom_pcmcia_dev = pdev;
+
+	viper_pcmcia_device->dev.parent = &pdev->dev;
+
+	ret = platform_device_add_data(viper_pcmcia_device,
+				       &viper_pcmcia_ops,
+				       sizeof(viper_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(viper_pcmcia_device);
+
+	if (ret) {
+		platform_device_put(viper_pcmcia_device);
+		arcom_pcmcia_dev = NULL;
+	}
+
+	return ret;
+}
+
+static int viper_pcmcia_remove(struct platform_device *pdev)
+{
+	platform_device_unregister(viper_pcmcia_device);
+	arcom_pcmcia_dev = NULL;
+	return 0;
+}
+
+static struct platform_device_id viper_pcmcia_id_table[] = {
+	{ .name = "viper-pcmcia", },
+	{ .name = "zeus-pcmcia",  },
+	{ },
+};
+
+static struct platform_driver viper_pcmcia_driver = {
+	.probe		= viper_pcmcia_probe,
+	.remove		= viper_pcmcia_remove,
+	.driver		= {
+		.name	= "arcom-pcmcia",
+	},
+	.id_table	= viper_pcmcia_id_table,
+};
+
+module_platform_driver(viper_pcmcia_driver);
+
+MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_vpac270.c b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_vpac270.c
new file mode 100644
index 0000000..33c5b88
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/pxa2xx_vpac270.c
@@ -0,0 +1,141 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_vpac270.c
+ *
+ * Driver for Voipac PXA270 PCMCIA and CF sockets
+ *
+ * Copyright (C) 2010-2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/vpac270.h>
+
+#include "soc_common.h"
+
+static struct gpio vpac270_pcmcia_gpios[] = {
+	{ GPIO107_VPAC270_PCMCIA_PPEN,	GPIOF_INIT_LOW,	"PCMCIA PPEN" },
+	{ GPIO11_VPAC270_PCMCIA_RESET,	GPIOF_INIT_LOW,	"PCMCIA Reset" },
+};
+
+static struct gpio vpac270_cf_gpios[] = {
+	{ GPIO16_VPAC270_CF_RESET,	GPIOF_INIT_LOW,	"CF Reset" },
+};
+
+static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	if (skt->nr == 0) {
+		ret = gpio_request_array(vpac270_pcmcia_gpios,
+				ARRAY_SIZE(vpac270_pcmcia_gpios));
+
+		skt->stat[SOC_STAT_CD].gpio = GPIO84_VPAC270_PCMCIA_CD;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO35_VPAC270_PCMCIA_RDY;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+	} else {
+		ret = gpio_request_array(vpac270_cf_gpios,
+				ARRAY_SIZE(vpac270_cf_gpios));
+
+		skt->stat[SOC_STAT_CD].gpio = GPIO17_VPAC270_CF_CD;
+		skt->stat[SOC_STAT_CD].name = "CF CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO12_VPAC270_CF_RDY;
+		skt->stat[SOC_STAT_RDY].name = "CF Ready";
+	}
+
+	return ret;
+}
+
+static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	if (skt->nr == 0)
+		gpio_free_array(vpac270_pcmcia_gpios,
+					ARRAY_SIZE(vpac270_pcmcia_gpios));
+	else
+		gpio_free_array(vpac270_cf_gpios,
+					ARRAY_SIZE(vpac270_cf_gpios));
+}
+
+static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+					struct pcmcia_state *state)
+{
+	state->vs_3v  = 1;
+	state->vs_Xv  = 0;
+}
+
+static int
+vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	if (skt->nr == 0) {
+		gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
+			(state->flags & SS_RESET));
+		gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
+			!(state->Vcc == 33 || state->Vcc == 50));
+	} else {
+		gpio_set_value(GPIO16_VPAC270_CF_RESET,
+			(state->flags & SS_RESET));
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level vpac270_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.first			= 0,
+	.nr			= 2,
+
+	.hw_init		= vpac270_pcmcia_hw_init,
+	.hw_shutdown		= vpac270_pcmcia_hw_shutdown,
+
+	.socket_state		= vpac270_pcmcia_socket_state,
+	.configure_socket	= vpac270_pcmcia_configure_socket,
+};
+
+static struct platform_device *vpac270_pcmcia_device;
+
+static int __init vpac270_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_vpac270())
+		return -ENODEV;
+
+	vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!vpac270_pcmcia_device)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(vpac270_pcmcia_device,
+		&vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
+
+	if (!ret)
+		ret = platform_device_add(vpac270_pcmcia_device);
+
+	if (ret)
+		platform_device_put(vpac270_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit vpac270_pcmcia_exit(void)
+{
+	platform_device_unregister(vpac270_pcmcia_device);
+}
+
+module_init(vpac270_pcmcia_init);
+module_exit(vpac270_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/ricoh.h b/src/kernel/linux/v4.14/drivers/pcmcia/ricoh.h
new file mode 100644
index 0000000..8ac7b13
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/ricoh.h
@@ -0,0 +1,241 @@
+/*
+ * ricoh.h 1.9 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_RICOH_H
+#define _LINUX_RICOH_H
+
+
+#define RF5C_MODE_CTL		0x1f	/* Mode control */
+#define RF5C_PWR_CTL		0x2f	/* Mixed voltage control */
+#define RF5C_CHIP_ID		0x3a	/* Chip identification */
+#define RF5C_MODE_CTL_3		0x3b	/* Mode control 3 */
+
+/* I/O window address offset */
+#define RF5C_IO_OFF(w)		(0x36+((w)<<1))
+
+/* Flags for RF5C_MODE_CTL */
+#define RF5C_MODE_ATA		0x01	/* ATA mode */
+#define RF5C_MODE_LED_ENA	0x02	/* IRQ 12 is LED */
+#define RF5C_MODE_CA21		0x04
+#define RF5C_MODE_CA22		0x08
+#define RF5C_MODE_CA23		0x10
+#define RF5C_MODE_CA24		0x20
+#define RF5C_MODE_CA25		0x40
+#define RF5C_MODE_3STATE_BIT7	0x80
+
+/* Flags for RF5C_PWR_CTL */
+#define RF5C_PWR_VCC_3V		0x01
+#define RF5C_PWR_IREQ_HIGH	0x02
+#define RF5C_PWR_INPACK_ENA	0x04
+#define RF5C_PWR_5V_DET		0x08
+#define RF5C_PWR_TC_SEL		0x10	/* Terminal Count: irq 11 or 15 */
+#define RF5C_PWR_DREQ_LOW	0x20
+#define RF5C_PWR_DREQ_OFF	0x00	/* DREQ steering control */
+#define RF5C_PWR_DREQ_INPACK	0x40
+#define RF5C_PWR_DREQ_SPKR	0x80
+#define RF5C_PWR_DREQ_IOIS16	0xc0
+
+/* Values for RF5C_CHIP_ID */
+#define RF5C_CHIP_RF5C296	0x32
+#define RF5C_CHIP_RF5C396	0xb2
+
+/* Flags for RF5C_MODE_CTL_3 */
+#define RF5C_MCTL3_DISABLE	0x01	/* Disable PCMCIA interface */
+#define RF5C_MCTL3_DMA_ENA	0x02
+
+/* Register definitions for Ricoh PCI-to-CardBus bridges */
+
+/* Extra bits in CB_BRIDGE_CONTROL */
+#define RL5C46X_BCR_3E0_ENA		0x0800
+#define RL5C46X_BCR_3E2_ENA		0x1000
+
+/* Bridge Configuration Register */
+#define RL5C4XX_CONFIG			0x80	/* 16 bit */
+#define  RL5C4XX_CONFIG_IO_1_MODE	0x0200
+#define  RL5C4XX_CONFIG_IO_0_MODE	0x0100
+#define  RL5C4XX_CONFIG_PREFETCH	0x0001
+
+/* Misc Control Register */
+#define RL5C4XX_MISC			0x0082	/* 16 bit */
+#define  RL5C4XX_MISC_HW_SUSPEND_ENA	0x0002
+#define  RL5C4XX_MISC_VCCEN_POL		0x0100
+#define  RL5C4XX_MISC_VPPEN_POL		0x0200
+#define  RL5C46X_MISC_SUSPEND		0x0001
+#define  RL5C46X_MISC_PWR_SAVE_2	0x0004
+#define  RL5C46X_MISC_IFACE_BUSY	0x0008
+#define  RL5C46X_MISC_B_LOCK		0x0010
+#define  RL5C46X_MISC_A_LOCK		0x0020
+#define  RL5C46X_MISC_PCI_LOCK		0x0040
+#define  RL5C47X_MISC_IFACE_BUSY	0x0004
+#define  RL5C47X_MISC_PCI_INT_MASK	0x0018
+#define  RL5C47X_MISC_PCI_INT_DIS	0x0020
+#define  RL5C47X_MISC_SUBSYS_WR		0x0040
+#define  RL5C47X_MISC_SRIRQ_ENA		0x0080
+#define  RL5C47X_MISC_5V_DISABLE	0x0400
+#define  RL5C47X_MISC_LED_POL		0x0800
+
+/* 16-bit Interface Control Register */
+#define RL5C4XX_16BIT_CTL		0x0084	/* 16 bit */
+#define  RL5C4XX_16CTL_IO_TIMING	0x0100
+#define  RL5C4XX_16CTL_MEM_TIMING	0x0200
+#define  RL5C46X_16CTL_LEVEL_1		0x0010
+#define  RL5C46X_16CTL_LEVEL_2		0x0020
+
+/* 16-bit IO and memory timing registers */
+#define RL5C4XX_16BIT_IO_0		0x0088	/* 16 bit */
+#define RL5C4XX_16BIT_MEM_0		0x008a	/* 16 bit */
+#define  RL5C4XX_SETUP_MASK		0x0007
+#define  RL5C4XX_SETUP_SHIFT		0
+#define  RL5C4XX_CMD_MASK		0x01f0
+#define  RL5C4XX_CMD_SHIFT		4
+#define  RL5C4XX_HOLD_MASK		0x1c00
+#define  RL5C4XX_HOLD_SHIFT		10
+#define  RL5C4XX_MISC_CONTROL           0x2F /* 8 bit */
+#define  RL5C4XX_ZV_ENABLE              0x08
+
+/* Misc Control 3 Register */
+#define RL5C4XX_MISC3			0x00A2 /* 16 bit */
+#define  RL5C47X_MISC3_CB_CLKRUN_DIS	BIT(1)
+
+#ifdef __YENTA_H
+
+#define rl_misc(socket)		((socket)->private[0])
+#define rl_ctl(socket)		((socket)->private[1])
+#define rl_io(socket)		((socket)->private[2])
+#define rl_mem(socket)		((socket)->private[3])
+#define rl_config(socket)	((socket)->private[4])
+
+static void ricoh_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+        u8 reg;
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+        reg = config_readb(socket, RL5C4XX_MISC_CONTROL);
+        if (onoff)
+                /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
+                reg |=  RL5C4XX_ZV_ENABLE;
+        else
+                reg &= ~RL5C4XX_ZV_ENABLE;
+	
+        config_writeb(socket, RL5C4XX_MISC_CONTROL, reg);
+}
+
+static void ricoh_set_zv(struct yenta_socket *socket)
+{
+        if(socket->dev->vendor == PCI_VENDOR_ID_RICOH)
+        {
+                switch(socket->dev->device)
+                {
+                        /* There may be more .. */
+		case  PCI_DEVICE_ID_RICOH_RL5C478:
+			socket->socket.zoom_video = ricoh_zoom_video;
+			break;  
+                }
+        }
+}
+
+static void ricoh_set_clkrun(struct yenta_socket *socket, bool quiet)
+{
+	u16 misc3;
+
+	/*
+	 * RL5C475II likely has this setting, too, however no datasheet
+	 * is publicly available for this chip
+	 */
+	if (socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C476 &&
+	    socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C478)
+		return;
+
+	if (socket->dev->revision < 0x80)
+		return;
+
+	misc3 = config_readw(socket, RL5C4XX_MISC3);
+	if (misc3 & RL5C47X_MISC3_CB_CLKRUN_DIS) {
+		if (!quiet)
+			dev_dbg(&socket->dev->dev,
+				"CLKRUN feature already disabled\n");
+	} else if (disable_clkrun) {
+		if (!quiet)
+			dev_info(&socket->dev->dev,
+				 "Disabling CLKRUN feature\n");
+		misc3 |= RL5C47X_MISC3_CB_CLKRUN_DIS;
+		config_writew(socket, RL5C4XX_MISC3, misc3);
+	}
+}
+
+static void ricoh_save_state(struct yenta_socket *socket)
+{
+	rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
+	rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
+	rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
+	rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
+	rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
+}
+
+static void ricoh_restore_state(struct yenta_socket *socket)
+{
+	config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
+	config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
+	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
+	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+	config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
+	ricoh_set_clkrun(socket, true);
+}
+
+
+/*
+ * Magic Ricoh initialization code..
+ */
+static int ricoh_override(struct yenta_socket *socket)
+{
+	u16 config, ctl;
+
+	config = config_readw(socket, RL5C4XX_CONFIG);
+
+	/* Set the default timings, don't trust the original values */
+	ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+
+	if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) {
+		ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+	} else {
+		config |= RL5C4XX_CONFIG_PREFETCH;
+	}
+
+	config_writew(socket, RL5C4XX_16BIT_CTL, ctl);
+	config_writew(socket, RL5C4XX_CONFIG, config);
+
+	ricoh_set_zv(socket);
+	ricoh_set_clkrun(socket, false);
+
+	return 0;
+}
+
+#endif /* CONFIG_CARDBUS */
+
+#endif /* _LINUX_RICOH_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_iodyn.c b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_iodyn.c
new file mode 100644
index 0000000..f53c237
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_iodyn.c
@@ -0,0 +1,171 @@
+/*
+ * rsrc_iodyn.c -- Resource management routines for MEM-static sockets.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+
+struct pcmcia_align_data {
+	unsigned long	mask;
+	unsigned long	offset;
+};
+
+static resource_size_t pcmcia_align(void *align_data,
+				const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	struct pcmcia_align_data *data = align_data;
+	resource_size_t start;
+
+	start = (res->start & ~data->mask) + data->offset;
+	if (start < res->start)
+		start += data->mask + 1;
+
+#ifdef CONFIG_X86
+	if (res->flags & IORESOURCE_IO) {
+		if (start & 0x300)
+			start = (start + 0x3ff) & ~0x3ff;
+	}
+#endif
+
+#ifdef CONFIG_M68K
+	if (res->flags & IORESOURCE_IO) {
+		if ((res->start + size - 1) >= 1024)
+			start = res->end;
+	}
+#endif
+
+	return start;
+}
+
+
+static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
+					unsigned long base, int num,
+					unsigned long align)
+{
+	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
+						dev_name(&s->dev));
+	struct pcmcia_align_data data;
+	unsigned long min = base;
+	int ret;
+
+	data.mask = align - 1;
+	data.offset = base & data.mask;
+
+#ifdef CONFIG_PCI
+	if (s->cb_dev) {
+		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
+					     min, 0, pcmcia_align, &data);
+	} else
+#endif
+		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
+					1, pcmcia_align, &data);
+
+	if (ret != 0) {
+		kfree(res);
+		res = NULL;
+	}
+	return res;
+}
+
+static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
+			unsigned int *base, unsigned int num,
+			unsigned int align, struct resource **parent)
+{
+	int i, ret = 0;
+
+	/* Check for an already-allocated window that must conflict with
+	 * what was asked for.  It is a hack because it does not catch all
+	 * potential conflicts, just the most obvious ones.
+	 */
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		if (!s->io[i].res)
+			continue;
+
+		if (!*base)
+			continue;
+
+		if ((s->io[i].res->start & (align-1)) == *base)
+			return -EBUSY;
+	}
+
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		struct resource *res = s->io[i].res;
+		unsigned int try;
+
+		if (res && (res->flags & IORESOURCE_BITS) !=
+			(attr & IORESOURCE_BITS))
+			continue;
+
+		if (!res) {
+			if (align == 0)
+				align = 0x10000;
+
+			res = s->io[i].res = __iodyn_find_io_region(s, *base,
+								num, align);
+			if (!res)
+				return -EINVAL;
+
+			*base = res->start;
+			s->io[i].res->flags =
+				((res->flags & ~IORESOURCE_BITS) |
+					(attr & IORESOURCE_BITS));
+			s->io[i].InUse = num;
+			*parent = res;
+			return 0;
+		}
+
+		/* Try to extend top of window */
+		try = res->end + 1;
+		if ((*base == 0) || (*base == try)) {
+			if (adjust_resource(s->io[i].res, res->start,
+					    resource_size(res) + num))
+				continue;
+			*base = try;
+			s->io[i].InUse += num;
+			*parent = res;
+			return 0;
+		}
+
+		/* Try to extend bottom of window */
+		try = res->start - num;
+		if ((*base == 0) || (*base == try)) {
+			if (adjust_resource(s->io[i].res,
+					    res->start - num,
+					    resource_size(res) + num))
+				continue;
+			*base = try;
+			s->io[i].InUse += num;
+			*parent = res;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+
+struct pccard_resource_ops pccard_iodyn_ops = {
+	.validate_mem = NULL,
+	.find_io = iodyn_find_io,
+	.find_mem = NULL,
+	.init = static_init,
+	.exit = NULL,
+};
+EXPORT_SYMBOL(pccard_iodyn_ops);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_mgr.c b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_mgr.c
new file mode 100644
index 0000000..df2cb70
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_mgr.c
@@ -0,0 +1,73 @@
+/*
+ * rsrc_mgr.c -- Resource management routines and/or wrappers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+int static_init(struct pcmcia_socket *s)
+{
+	/* the good thing about SS_CAP_STATIC_MAP sockets is
+	 * that they don't need a resource database */
+
+	s->resource_setup_done = 1;
+
+	return 0;
+}
+
+struct resource *pcmcia_make_resource(resource_size_t start,
+					resource_size_t end,
+					unsigned long flags, const char *name)
+{
+	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+
+	if (res) {
+		res->name = name;
+		res->start = start;
+		res->end = start + end - 1;
+		res->flags = flags;
+	}
+	return res;
+}
+
+static int static_find_io(struct pcmcia_socket *s, unsigned int attr,
+			unsigned int *base, unsigned int num,
+			unsigned int align, struct resource **parent)
+{
+	if (!s->io_offset)
+		return -EINVAL;
+	*base = s->io_offset | (*base & 0x0fff);
+	*parent = NULL;
+
+	return 0;
+}
+
+
+struct pccard_resource_ops pccard_static_ops = {
+	.validate_mem = NULL,
+	.find_io = static_find_io,
+	.find_mem = NULL,
+	.init = static_init,
+	.exit = NULL,
+};
+EXPORT_SYMBOL(pccard_static_ops);
+
+
+MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("rsrc_nonstatic");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_nonstatic.c b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_nonstatic.c
new file mode 100644
index 0000000..5ef7b46
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/rsrc_nonstatic.c
@@ -0,0 +1,1237 @@
+/*
+ * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999		David A. Hinds
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+/* moved to rsrc_mgr.c
+MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
+MODULE_LICENSE("GPL");
+*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
+
+INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
+#ifdef CONFIG_PCMCIA_PROBE
+INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
+INT_MODULE_PARM(mem_limit,	0x10000);
+#endif
+
+/* for io_db and mem_db */
+struct resource_map {
+	u_long			base, num;
+	struct resource_map	*next;
+};
+
+struct socket_data {
+	struct resource_map		mem_db;
+	struct resource_map		mem_db_valid;
+	struct resource_map		io_db;
+};
+
+#define MEM_PROBE_LOW	(1 << 0)
+#define MEM_PROBE_HIGH	(1 << 1)
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE		1
+#define ADD_MANAGED_RESOURCE		2
+
+/*======================================================================
+
+    Linux resource management extensions
+
+======================================================================*/
+
+static struct resource *
+claim_region(struct pcmcia_socket *s, resource_size_t base,
+		resource_size_t size, int type, char *name)
+{
+	struct resource *res, *parent;
+
+	parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
+	res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
+
+	if (res) {
+#ifdef CONFIG_PCI
+		if (s && s->cb_dev)
+			parent = pci_find_parent_resource(s->cb_dev, res);
+#endif
+		if (!parent || request_resource(parent, res)) {
+			kfree(res);
+			res = NULL;
+		}
+	}
+	return res;
+}
+
+static void free_region(struct resource *res)
+{
+	if (res) {
+		release_resource(res);
+		kfree(res);
+	}
+}
+
+/*======================================================================
+
+    These manage the internal databases of available resources.
+
+======================================================================*/
+
+static int add_interval(struct resource_map *map, u_long base, u_long num)
+{
+	struct resource_map *p, *q;
+
+	for (p = map; ; p = p->next) {
+		if ((p != map) && (p->base+p->num >= base)) {
+			p->num = max(num + base - p->base, p->num);
+			return 0;
+		}
+		if ((p->next == map) || (p->next->base > base+num-1))
+			break;
+	}
+	q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
+	if (!q) {
+		printk(KERN_WARNING "out of memory to update resources\n");
+		return -ENOMEM;
+	}
+	q->base = base; q->num = num;
+	q->next = p->next; p->next = q;
+	return 0;
+}
+
+/*====================================================================*/
+
+static int sub_interval(struct resource_map *map, u_long base, u_long num)
+{
+	struct resource_map *p, *q;
+
+	for (p = map; ; p = q) {
+		q = p->next;
+		if (q == map)
+			break;
+		if ((q->base+q->num > base) && (base+num > q->base)) {
+			if (q->base >= base) {
+				if (q->base+q->num <= base+num) {
+					/* Delete whole block */
+					p->next = q->next;
+					kfree(q);
+					/* don't advance the pointer yet */
+					q = p;
+				} else {
+					/* Cut off bit from the front */
+					q->num = q->base + q->num - base - num;
+					q->base = base + num;
+				}
+			} else if (q->base+q->num <= base+num) {
+				/* Cut off bit from the end */
+				q->num = base - q->base;
+			} else {
+				/* Split the block into two pieces */
+				p = kmalloc(sizeof(struct resource_map),
+					GFP_KERNEL);
+				if (!p) {
+					printk(KERN_WARNING "out of memory to update resources\n");
+					return -ENOMEM;
+				}
+				p->base = base+num;
+				p->num = q->base+q->num - p->base;
+				q->num = base - q->base;
+				p->next = q->next ; q->next = p;
+			}
+		}
+	}
+	return 0;
+}
+
+/*======================================================================
+
+    These routines examine a region of IO or memory addresses to
+    determine what ranges might be genuinely available.
+
+======================================================================*/
+
+#ifdef CONFIG_PCMCIA_PROBE
+static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
+			unsigned int num)
+{
+	struct resource *res;
+	struct socket_data *s_data = s->resource_data;
+	unsigned int i, j, bad;
+	int any;
+	u_char *b, hole, most;
+
+	dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
+
+	/* First, what does a floating port look like? */
+	b = kzalloc(256, GFP_KERNEL);
+	if (!b) {
+		pr_cont("\n");
+		dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
+		return;
+	}
+	for (i = base, most = 0; i < base+num; i += 8) {
+		res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+		if (!res)
+			continue;
+		hole = inb(i);
+		for (j = 1; j < 8; j++)
+			if (inb(i+j) != hole)
+				break;
+		free_region(res);
+		if ((j == 8) && (++b[hole] > b[most]))
+			most = hole;
+		if (b[most] == 127)
+			break;
+	}
+	kfree(b);
+
+	bad = any = 0;
+	for (i = base; i < base+num; i += 8) {
+		res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+		if (!res) {
+			if (!any)
+				pr_cont(" excluding");
+			if (!bad)
+				bad = any = i;
+			continue;
+		}
+		for (j = 0; j < 8; j++)
+			if (inb(i+j) != most)
+				break;
+		free_region(res);
+		if (j < 8) {
+			if (!any)
+				pr_cont(" excluding");
+			if (!bad)
+				bad = any = i;
+		} else {
+			if (bad) {
+				sub_interval(&s_data->io_db, bad, i-bad);
+				pr_cont(" %#x-%#x", bad, i-1);
+				bad = 0;
+			}
+		}
+	}
+	if (bad) {
+		if ((num > 16) && (bad == base) && (i == base+num)) {
+			sub_interval(&s_data->io_db, bad, i-bad);
+			pr_cont(" nothing: probe failed.\n");
+			return;
+		} else {
+			sub_interval(&s_data->io_db, bad, i-bad);
+			pr_cont(" %#x-%#x", bad, i-1);
+		}
+	}
+
+	pr_cont("%s\n", !any ? " clean" : "");
+}
+#endif
+
+/*======================================================================*/
+
+/**
+ * readable() - iomem validation function for cards with a valid CIS
+ */
+static int readable(struct pcmcia_socket *s, struct resource *res,
+		    unsigned int *count)
+{
+	int ret = -EINVAL;
+
+	if (s->fake_cis) {
+		dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
+		return 0;
+	}
+
+	s->cis_mem.res = res;
+	s->cis_virt = ioremap(res->start, s->map_size);
+	if (s->cis_virt) {
+		mutex_unlock(&s->ops_mutex);
+		/* as we're only called from pcmcia.c, we're safe */
+		if (s->callback->validate)
+			ret = s->callback->validate(s, count);
+		/* invalidate mapping */
+		mutex_lock(&s->ops_mutex);
+		iounmap(s->cis_virt);
+		s->cis_virt = NULL;
+	}
+	s->cis_mem.res = NULL;
+	if ((ret) || (*count == 0))
+		return -EINVAL;
+	return 0;
+}
+
+/**
+ * checksum() - iomem validation function for simple memory cards
+ */
+static int checksum(struct pcmcia_socket *s, struct resource *res,
+		    unsigned int *value)
+{
+	pccard_mem_map map;
+	int i, a = 0, b = -1, d;
+	void __iomem *virt;
+
+	virt = ioremap(res->start, s->map_size);
+	if (virt) {
+		map.map = 0;
+		map.flags = MAP_ACTIVE;
+		map.speed = 0;
+		map.res = res;
+		map.card_start = 0;
+		s->ops->set_mem_map(s, &map);
+
+		/* Don't bother checking every word... */
+		for (i = 0; i < s->map_size; i += 44) {
+			d = readl(virt+i);
+			a += d;
+			b &= d;
+		}
+
+		map.flags = 0;
+		s->ops->set_mem_map(s, &map);
+
+		iounmap(virt);
+	}
+
+	if (b == -1)
+		return -EINVAL;
+
+	*value = a;
+
+	return 0;
+}
+
+/**
+ * do_validate_mem() - low level validate a memory region for PCMCIA use
+ * @s:		PCMCIA socket to validate
+ * @base:	start address of resource to check
+ * @size:	size of resource to check
+ * @validate:	validation function to use
+ *
+ * do_validate_mem() splits up the memory region which is to be checked
+ * into two parts. Both are passed to the @validate() function. If
+ * @validate() returns non-zero, or the value parameter to @validate()
+ * is zero, or the value parameter is different between both calls,
+ * the check fails, and -EINVAL is returned. Else, 0 is returned.
+ */
+static int do_validate_mem(struct pcmcia_socket *s,
+			   unsigned long base, unsigned long size,
+			   int validate (struct pcmcia_socket *s,
+					 struct resource *res,
+					 unsigned int *value))
+{
+	struct socket_data *s_data = s->resource_data;
+	struct resource *res1, *res2;
+	unsigned int info1 = 1, info2 = 1;
+	int ret = -EINVAL;
+
+	res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
+	res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
+			"PCMCIA memprobe");
+
+	if (res1 && res2) {
+		ret = 0;
+		if (validate) {
+			ret = validate(s, res1, &info1);
+			ret += validate(s, res2, &info2);
+		}
+	}
+
+	dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
+		base, base+size-1, res1, res2, ret, info1, info2);
+
+	free_region(res2);
+	free_region(res1);
+
+	if ((ret) || (info1 != info2) || (info1 == 0))
+		return -EINVAL;
+
+	if (validate && !s->fake_cis) {
+		/* move it to the validated data set */
+		add_interval(&s_data->mem_db_valid, base, size);
+		sub_interval(&s_data->mem_db, base, size);
+	}
+
+	return 0;
+}
+
+
+/**
+ * do_mem_probe() - validate a memory region for PCMCIA use
+ * @s:		PCMCIA socket to validate
+ * @base:	start address of resource to check
+ * @num:	size of resource to check
+ * @validate:	validation function to use
+ * @fallback:	validation function to use if validate fails
+ *
+ * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
+ * To do so, the area is split up into sensible parts, and then passed
+ * into the @validate() function. Only if @validate() and @fallback() fail,
+ * the area is marked as unavaibale for use by the PCMCIA subsystem. The
+ * function returns the size of the usable memory area.
+ */
+static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
+			int validate (struct pcmcia_socket *s,
+				      struct resource *res,
+				      unsigned int *value),
+			int fallback (struct pcmcia_socket *s,
+				      struct resource *res,
+				      unsigned int *value))
+{
+	struct socket_data *s_data = s->resource_data;
+	u_long i, j, bad, fail, step;
+
+	dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
+		 base, base+num-1);
+	bad = fail = 0;
+	step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+	/* don't allow too large steps */
+	if (step > 0x800000)
+		step = 0x800000;
+	/* cis_readable wants to map 2x map_size */
+	if (step < 2 * s->map_size)
+		step = 2 * s->map_size;
+	for (i = j = base; i < base+num; i = j + step) {
+		if (!fail) {
+			for (j = i; j < base+num; j += step) {
+				if (!do_validate_mem(s, j, step, validate))
+					break;
+			}
+			fail = ((i == base) && (j == base+num));
+		}
+		if ((fail) && (fallback)) {
+			for (j = i; j < base+num; j += step)
+				if (!do_validate_mem(s, j, step, fallback))
+					break;
+		}
+		if (i != j) {
+			if (!bad)
+				pr_cont(" excluding");
+			pr_cont(" %#05lx-%#05lx", i, j-1);
+			sub_interval(&s_data->mem_db, i, j-i);
+			bad += j-i;
+		}
+	}
+	pr_cont("%s\n", !bad ? " clean" : "");
+	return num - bad;
+}
+
+
+#ifdef CONFIG_PCMCIA_PROBE
+
+/**
+ * inv_probe() - top-to-bottom search for one usuable high memory area
+ * @s:		PCMCIA socket to validate
+ * @m:		resource_map to check
+ */
+static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
+{
+	struct socket_data *s_data = s->resource_data;
+	u_long ok;
+	if (m == &s_data->mem_db)
+		return 0;
+	ok = inv_probe(m->next, s);
+	if (ok) {
+		if (m->base >= 0x100000)
+			sub_interval(&s_data->mem_db, m->base, m->num);
+		return ok;
+	}
+	if (m->base < 0x100000)
+		return 0;
+	return do_mem_probe(s, m->base, m->num, readable, checksum);
+}
+
+/**
+ * validate_mem() - memory probe function
+ * @s:		PCMCIA socket to validate
+ * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
+ *
+ * The memory probe.  If the memory list includes a 64K-aligned block
+ * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+ * least mem_limit free space, we quit. Returns 0 on usuable ports.
+ */
+static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
+{
+	struct resource_map *m, mm;
+	static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+	unsigned long b, i, ok = 0;
+	struct socket_data *s_data = s->resource_data;
+
+	/* We do up to four passes through the list */
+	if (probe_mask & MEM_PROBE_HIGH) {
+		if (inv_probe(s_data->mem_db.next, s) > 0)
+			return 0;
+		if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+			return 0;
+		dev_notice(&s->dev,
+			   "cs: warning: no high memory space available!\n");
+		return -ENODEV;
+	}
+
+	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
+		mm = *m;
+		/* Only probe < 1 MB */
+		if (mm.base >= 0x100000)
+			continue;
+		if ((mm.base | mm.num) & 0xffff) {
+			ok += do_mem_probe(s, mm.base, mm.num, readable,
+					   checksum);
+			continue;
+		}
+		/* Special probe for 64K-aligned block */
+		for (i = 0; i < 4; i++) {
+			b = order[i] << 12;
+			if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
+				if (ok >= mem_limit)
+					sub_interval(&s_data->mem_db, b, 0x10000);
+				else
+					ok += do_mem_probe(s, b, 0x10000,
+							   readable, checksum);
+			}
+		}
+	}
+
+	if (ok > 0)
+		return 0;
+
+	return -ENODEV;
+}
+
+#else /* CONFIG_PCMCIA_PROBE */
+
+/**
+ * validate_mem() - memory probe function
+ * @s:		PCMCIA socket to validate
+ * @probe_mask: ignored
+ *
+ * Returns 0 on usuable ports.
+ */
+static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
+{
+	struct resource_map *m, mm;
+	struct socket_data *s_data = s->resource_data;
+	unsigned long ok = 0;
+
+	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
+		mm = *m;
+		ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
+	}
+	if (ok > 0)
+		return 0;
+	return -ENODEV;
+}
+
+#endif /* CONFIG_PCMCIA_PROBE */
+
+
+/**
+ * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
+ * @s:		PCMCIA socket to validate
+ *
+ * This is tricky... when we set up CIS memory, we try to validate
+ * the memory window space allocations.
+ *
+ * Locking note: Must be called with skt_mutex held!
+ */
+static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
+{
+	struct socket_data *s_data = s->resource_data;
+	unsigned int probe_mask = MEM_PROBE_LOW;
+	int ret;
+
+	if (!probe_mem || !(s->state & SOCKET_PRESENT))
+		return 0;
+
+	if (s->features & SS_CAP_PAGE_REGS)
+		probe_mask = MEM_PROBE_HIGH;
+
+	ret = validate_mem(s, probe_mask);
+
+	if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+		return 0;
+
+	return ret;
+}
+
+struct pcmcia_align_data {
+	unsigned long	mask;
+	unsigned long	offset;
+	struct resource_map	*map;
+};
+
+static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
+					resource_size_t start)
+{
+	resource_size_t ret;
+	/*
+	 * Ensure that we have the correct start address
+	 */
+	ret = (start & ~align_data->mask) + align_data->offset;
+	if (ret < start)
+		ret += align_data->mask + 1;
+	return ret;
+}
+
+static resource_size_t
+pcmcia_align(void *align_data, const struct resource *res,
+	resource_size_t size, resource_size_t align)
+{
+	struct pcmcia_align_data *data = align_data;
+	struct resource_map *m;
+	resource_size_t start;
+
+	start = pcmcia_common_align(data, res->start);
+
+	for (m = data->map->next; m != data->map; m = m->next) {
+		unsigned long map_start = m->base;
+		unsigned long map_end = m->base + m->num - 1;
+
+		/*
+		 * If the lower resources are not available, try aligning
+		 * to this entry of the resource database to see if it'll
+		 * fit here.
+		 */
+		if (start < map_start)
+			start = pcmcia_common_align(data, map_start);
+
+		/*
+		 * If we're above the area which was passed in, there's
+		 * no point proceeding.
+		 */
+		if (start >= res->end)
+			break;
+
+		if ((start + size - 1) <= map_end)
+			break;
+	}
+
+	/*
+	 * If we failed to find something suitable, ensure we fail.
+	 */
+	if (m == data->map)
+		start = res->end;
+
+	return start;
+}
+
+/*
+ * Adjust an existing IO region allocation, but making sure that we don't
+ * encroach outside the resources which the user supplied.
+ */
+static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
+					unsigned long r_start,
+					unsigned long r_end)
+{
+	struct resource_map *m;
+	struct socket_data *s_data = s->resource_data;
+	int ret = -ENOMEM;
+
+	for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
+		unsigned long start = m->base;
+		unsigned long end = m->base + m->num - 1;
+
+		if (start > r_start || r_end > end)
+			continue;
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*======================================================================
+
+    These find ranges of I/O ports or memory addresses that are not
+    currently allocated by other devices.
+
+    The 'align' field should reflect the number of bits of address
+    that need to be preserved from the initial value of *base.  It
+    should be a power of two, greater than or equal to 'num'.  A value
+    of 0 means that all bits of *base are significant.  *base should
+    also be strictly less than 'align'.
+
+======================================================================*/
+
+static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
+						unsigned long base, int num,
+						unsigned long align)
+{
+	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
+						dev_name(&s->dev));
+	struct socket_data *s_data = s->resource_data;
+	struct pcmcia_align_data data;
+	unsigned long min = base;
+	int ret;
+
+	data.mask = align - 1;
+	data.offset = base & data.mask;
+	data.map = &s_data->io_db;
+
+#ifdef CONFIG_PCI
+	if (s->cb_dev) {
+		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
+					     min, 0, pcmcia_align, &data);
+	} else
+#endif
+		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
+					1, pcmcia_align, &data);
+
+	if (ret != 0) {
+		kfree(res);
+		res = NULL;
+	}
+	return res;
+}
+
+static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
+			unsigned int *base, unsigned int num,
+			unsigned int align, struct resource **parent)
+{
+	int i, ret = 0;
+
+	/* Check for an already-allocated window that must conflict with
+	 * what was asked for.  It is a hack because it does not catch all
+	 * potential conflicts, just the most obvious ones.
+	 */
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		if (!s->io[i].res)
+			continue;
+
+		if (!*base)
+			continue;
+
+		if ((s->io[i].res->start & (align-1)) == *base)
+			return -EBUSY;
+	}
+
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		struct resource *res = s->io[i].res;
+		unsigned int try;
+
+		if (res && (res->flags & IORESOURCE_BITS) !=
+			(attr & IORESOURCE_BITS))
+			continue;
+
+		if (!res) {
+			if (align == 0)
+				align = 0x10000;
+
+			res = s->io[i].res = __nonstatic_find_io_region(s,
+								*base, num,
+								align);
+			if (!res)
+				return -EINVAL;
+
+			*base = res->start;
+			s->io[i].res->flags =
+				((res->flags & ~IORESOURCE_BITS) |
+					(attr & IORESOURCE_BITS));
+			s->io[i].InUse = num;
+			*parent = res;
+			return 0;
+		}
+
+		/* Try to extend top of window */
+		try = res->end + 1;
+		if ((*base == 0) || (*base == try)) {
+			ret =  __nonstatic_adjust_io_region(s, res->start,
+							res->end + num);
+			if (!ret) {
+				ret = adjust_resource(s->io[i].res, res->start,
+						      resource_size(res) + num);
+				if (ret)
+					continue;
+				*base = try;
+				s->io[i].InUse += num;
+				*parent = res;
+				return 0;
+			}
+		}
+
+		/* Try to extend bottom of window */
+		try = res->start - num;
+		if ((*base == 0) || (*base == try)) {
+			ret =  __nonstatic_adjust_io_region(s,
+							res->start - num,
+							res->end);
+			if (!ret) {
+				ret = adjust_resource(s->io[i].res,
+						      res->start - num,
+						      resource_size(res) + num);
+				if (ret)
+					continue;
+				*base = try;
+				s->io[i].InUse += num;
+				*parent = res;
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+
+static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
+		u_long align, int low, struct pcmcia_socket *s)
+{
+	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
+						dev_name(&s->dev));
+	struct socket_data *s_data = s->resource_data;
+	struct pcmcia_align_data data;
+	unsigned long min, max;
+	int ret, i, j;
+
+	low = low || !(s->features & SS_CAP_PAGE_REGS);
+
+	data.mask = align - 1;
+	data.offset = base & data.mask;
+
+	for (i = 0; i < 2; i++) {
+		data.map = &s_data->mem_db_valid;
+		if (low) {
+			max = 0x100000UL;
+			min = base < max ? base : 0;
+		} else {
+			max = ~0UL;
+			min = 0x100000UL + base;
+		}
+
+		for (j = 0; j < 2; j++) {
+#ifdef CONFIG_PCI
+			if (s->cb_dev) {
+				ret = pci_bus_alloc_resource(s->cb_dev->bus,
+							res, num, 1, min, 0,
+							pcmcia_align, &data);
+			} else
+#endif
+			{
+				ret = allocate_resource(&iomem_resource,
+							res, num, min, max, 1,
+							pcmcia_align, &data);
+			}
+			if (ret == 0)
+				break;
+			data.map = &s_data->mem_db;
+		}
+		if (ret == 0 || low)
+			break;
+		low = 1;
+	}
+
+	if (ret != 0) {
+		kfree(res);
+		res = NULL;
+	}
+	return res;
+}
+
+
+static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
+{
+	struct socket_data *data = s->resource_data;
+	unsigned long size = end - start + 1;
+	int ret = 0;
+
+	if (end < start)
+		return -EINVAL;
+
+	switch (action) {
+	case ADD_MANAGED_RESOURCE:
+		ret = add_interval(&data->mem_db, start, size);
+		if (!ret)
+			do_mem_probe(s, start, size, NULL, NULL);
+		break;
+	case REMOVE_MANAGED_RESOURCE:
+		ret = sub_interval(&data->mem_db, start, size);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+
+static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
+{
+	struct socket_data *data = s->resource_data;
+	unsigned long size;
+	int ret = 0;
+
+#if defined(CONFIG_X86)
+	/* on x86, avoid anything < 0x100 for it is often used for
+	 * legacy platform devices */
+	if (start < 0x100)
+		start = 0x100;
+#endif
+
+	size = end - start + 1;
+
+	if (end < start)
+		return -EINVAL;
+
+	if (end > IO_SPACE_LIMIT)
+		return -EINVAL;
+
+	switch (action) {
+	case ADD_MANAGED_RESOURCE:
+		if (add_interval(&data->io_db, start, size) != 0) {
+			ret = -EBUSY;
+			break;
+		}
+#ifdef CONFIG_PCMCIA_PROBE
+		if (probe_io)
+			do_io_probe(s, start, size);
+#endif
+		break;
+	case REMOVE_MANAGED_RESOURCE:
+		sub_interval(&data->io_db, start, size);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+
+#ifdef CONFIG_PCI
+static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+	struct resource *res;
+	int i, done = 0;
+
+	if (!s->cb_dev || !s->cb_dev->bus)
+		return -ENODEV;
+
+#if defined(CONFIG_X86)
+	/* If this is the root bus, the risk of hitting some strange
+	 * system devices is too high: If a driver isn't loaded, the
+	 * resources are not claimed; even if a driver is loaded, it
+	 * may not request all resources or even the wrong one. We
+	 * can neither trust the rest of the kernel nor ACPI/PNP and
+	 * CRS parsing to get it right. Therefore, use several
+	 * safeguards:
+	 *
+	 * - Do not auto-add resources if the CardBus bridge is on
+	 *   the PCI root bus
+	 *
+	 * - Avoid any I/O ports < 0x100.
+	 *
+	 * - On PCI-PCI bridges, only use resources which are set up
+	 *   exclusively for the secondary PCI bus: the risk of hitting
+	 *   system devices is quite low, as they usually aren't
+	 *   connected to the secondary PCI bus.
+	 */
+	if (s->cb_dev->bus->number == 0)
+		return -EINVAL;
+
+	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
+		res = s->cb_dev->bus->resource[i];
+#else
+	pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
+#endif
+		if (!res)
+			continue;
+
+		if (res->flags & IORESOURCE_IO) {
+			/* safeguard against the root resource, where the
+			 * risk of hitting any other device would be too
+			 * high */
+			if (res == &ioport_resource)
+				continue;
+
+			dev_info(&s->cb_dev->dev,
+				 "pcmcia: parent PCI bridge window: %pR\n",
+				 res);
+			if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+				done |= IORESOURCE_IO;
+
+		}
+
+		if (res->flags & IORESOURCE_MEM) {
+			/* safeguard against the root resource, where the
+			 * risk of hitting any other device would be too
+			 * high */
+			if (res == &iomem_resource)
+				continue;
+
+			dev_info(&s->cb_dev->dev,
+				 "pcmcia: parent PCI bridge window: %pR\n",
+				 res);
+			if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+				done |= IORESOURCE_MEM;
+		}
+	}
+
+	/* if we got at least one of IO, and one of MEM, we can be glad and
+	 * activate the PCMCIA subsystem */
+	if (done == (IORESOURCE_MEM | IORESOURCE_IO))
+		s->resource_setup_done = 1;
+
+	return 0;
+}
+
+#else
+
+static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+	return -ENODEV;
+}
+
+#endif
+
+
+static int nonstatic_init(struct pcmcia_socket *s)
+{
+	struct socket_data *data;
+
+	data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->mem_db.next = &data->mem_db;
+	data->mem_db_valid.next = &data->mem_db_valid;
+	data->io_db.next = &data->io_db;
+
+	s->resource_data = (void *) data;
+
+	nonstatic_autoadd_resources(s);
+
+	return 0;
+}
+
+static void nonstatic_release_resource_db(struct pcmcia_socket *s)
+{
+	struct socket_data *data = s->resource_data;
+	struct resource_map *p, *q;
+
+	for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
+		q = p->next;
+		kfree(p);
+	}
+	for (p = data->mem_db.next; p != &data->mem_db; p = q) {
+		q = p->next;
+		kfree(p);
+	}
+	for (p = data->io_db.next; p != &data->io_db; p = q) {
+		q = p->next;
+		kfree(p);
+	}
+}
+
+
+struct pccard_resource_ops pccard_nonstatic_ops = {
+	.validate_mem = pcmcia_nonstatic_validate_mem,
+	.find_io = nonstatic_find_io,
+	.find_mem = nonstatic_find_mem_region,
+	.init = nonstatic_init,
+	.exit = nonstatic_release_resource_db,
+};
+EXPORT_SYMBOL(pccard_nonstatic_ops);
+
+
+/* sysfs interface to the resource database */
+
+static ssize_t show_io_db(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	struct socket_data *data;
+	struct resource_map *p;
+	ssize_t ret = 0;
+
+	mutex_lock(&s->ops_mutex);
+	data = s->resource_data;
+
+	for (p = data->io_db.next; p != &data->io_db; p = p->next) {
+		if (ret > (PAGE_SIZE - 10))
+			continue;
+		ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+				"0x%08lx - 0x%08lx\n",
+				((unsigned long) p->base),
+				((unsigned long) p->base + p->num - 1));
+	}
+
+	mutex_unlock(&s->ops_mutex);
+	return ret;
+}
+
+static ssize_t store_io_db(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	unsigned long start_addr, end_addr;
+	unsigned int add = ADD_MANAGED_RESOURCE;
+	ssize_t ret = 0;
+
+	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+	if (ret != 2) {
+		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+		add = REMOVE_MANAGED_RESOURCE;
+		if (ret != 2) {
+			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
+				&end_addr);
+			add = ADD_MANAGED_RESOURCE;
+			if (ret != 2)
+				return -EINVAL;
+		}
+	}
+	if (end_addr < start_addr)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	ret = adjust_io(s, add, start_addr, end_addr);
+	mutex_unlock(&s->ops_mutex);
+
+	return ret ? ret : count;
+}
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+
+static ssize_t show_mem_db(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	struct socket_data *data;
+	struct resource_map *p;
+	ssize_t ret = 0;
+
+	mutex_lock(&s->ops_mutex);
+	data = s->resource_data;
+
+	for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
+	     p = p->next) {
+		if (ret > (PAGE_SIZE - 10))
+			continue;
+		ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+				"0x%08lx - 0x%08lx\n",
+				((unsigned long) p->base),
+				((unsigned long) p->base + p->num - 1));
+	}
+
+	for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
+		if (ret > (PAGE_SIZE - 10))
+			continue;
+		ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+				"0x%08lx - 0x%08lx\n",
+				((unsigned long) p->base),
+				((unsigned long) p->base + p->num - 1));
+	}
+
+	mutex_unlock(&s->ops_mutex);
+	return ret;
+}
+
+static ssize_t store_mem_db(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	unsigned long start_addr, end_addr;
+	unsigned int add = ADD_MANAGED_RESOURCE;
+	ssize_t ret = 0;
+
+	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+	if (ret != 2) {
+		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+		add = REMOVE_MANAGED_RESOURCE;
+		if (ret != 2) {
+			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
+				&end_addr);
+			add = ADD_MANAGED_RESOURCE;
+			if (ret != 2)
+				return -EINVAL;
+		}
+	}
+	if (end_addr < start_addr)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	ret = adjust_memory(s, add, start_addr, end_addr);
+	mutex_unlock(&s->ops_mutex);
+
+	return ret ? ret : count;
+}
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+
+static struct attribute *pccard_rsrc_attributes[] = {
+	&dev_attr_available_resources_io.attr,
+	&dev_attr_available_resources_mem.attr,
+	NULL,
+};
+
+static const struct attribute_group rsrc_attributes = {
+	.attrs = pccard_rsrc_attributes,
+};
+
+static int pccard_sysfs_add_rsrc(struct device *dev,
+					   struct class_interface *class_intf)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+
+	if (s->resource_ops != &pccard_nonstatic_ops)
+		return 0;
+	return sysfs_create_group(&dev->kobj, &rsrc_attributes);
+}
+
+static void pccard_sysfs_remove_rsrc(struct device *dev,
+					       struct class_interface *class_intf)
+{
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+
+	if (s->resource_ops != &pccard_nonstatic_ops)
+		return;
+	sysfs_remove_group(&dev->kobj, &rsrc_attributes);
+}
+
+static struct class_interface pccard_rsrc_interface __refdata = {
+	.class = &pcmcia_socket_class,
+	.add_dev = &pccard_sysfs_add_rsrc,
+	.remove_dev = &pccard_sysfs_remove_rsrc,
+};
+
+static int __init nonstatic_sysfs_init(void)
+{
+	return class_interface_register(&pccard_rsrc_interface);
+}
+
+static void __exit nonstatic_sysfs_exit(void)
+{
+	class_interface_unregister(&pccard_rsrc_interface);
+}
+
+module_init(nonstatic_sysfs_init);
+module_exit(nonstatic_sysfs_exit);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_assabet.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_assabet.c
new file mode 100644
index 0000000..78ad2bb
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_assabet.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_assabet.c
+ *
+ * PCMCIA implementation routines for Assabet
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <mach/assabet.h>
+
+#include "sa1100_generic.h"
+
+static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	skt->stat[SOC_STAT_CD].gpio = ASSABET_GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF CD";
+	skt->stat[SOC_STAT_BVD1].gpio = ASSABET_GPIO_CF_BVD1;
+	skt->stat[SOC_STAT_BVD1].name = "CF BVD1";
+	skt->stat[SOC_STAT_BVD2].gpio = ASSABET_GPIO_CF_BVD2;
+	skt->stat[SOC_STAT_BVD2].name = "CF BVD2";
+	skt->stat[SOC_STAT_RDY].gpio = ASSABET_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF RDY";
+
+	return 0;
+}
+
+static int
+assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	unsigned int mask;
+
+	switch (state->Vcc) {
+	case 0:
+		mask = 0;
+		break;
+
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__func__);
+
+	case 33:  /* Can only apply 3.3V to the CF slot. */
+		mask = ASSABET_BCR_CF_PWR;
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__,
+			state->Vcc);
+		return -1;
+	}
+
+	/* Silently ignore Vpp, speaker enable. */
+
+	if (state->flags & SS_RESET)
+		mask |= ASSABET_BCR_CF_RST;
+	if (!(state->flags & SS_OUTPUT_ENA))
+		mask |= ASSABET_BCR_CF_BUS_OFF;
+
+	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR |
+			ASSABET_BCR_CF_BUS_OFF, mask);
+
+	return 0;
+}
+
+/*
+ * Disable card status IRQs on suspend.
+ */
+static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	/*
+	 * Tristate the CF bus signals.  Also assert CF
+	 * reset as per user guide page 4-11.
+	 */
+	ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
+}
+
+static struct pcmcia_low_level assabet_pcmcia_ops = { 
+	.owner			= THIS_MODULE,
+	.hw_init		= assabet_pcmcia_hw_init,
+	.socket_state		= soc_common_cf_socket_state,
+	.configure_socket	= assabet_pcmcia_configure_socket,
+	.socket_suspend		= assabet_pcmcia_socket_suspend,
+};
+
+int pcmcia_assabet_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_assabet() && !machine_has_neponset())
+		ret = sa11xx_drv_pcmcia_probe(dev, &assabet_pcmcia_ops, 1, 1);
+
+	return ret;
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_cerf.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_cerf.c
new file mode 100644
index 0000000..2a54081
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_cerf.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_cerf.c
+ *
+ * PCMCIA implementation routines for CerfBoard
+ * Based off the Assabet.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <mach/cerf.h>
+#include "sa1100_generic.h"
+
+#define CERF_SOCKET	1
+
+static int cerf_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	ret = gpio_request_one(CERF_GPIO_CF_RESET, GPIOF_OUT_INIT_LOW, "CF_RESET");
+	if (ret)
+		return ret;
+
+	skt->stat[SOC_STAT_CD].gpio = CERF_GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF_CD";
+	skt->stat[SOC_STAT_BVD1].gpio = CERF_GPIO_CF_BVD1;
+	skt->stat[SOC_STAT_BVD1].name = "CF_BVD1";
+	skt->stat[SOC_STAT_BVD2].gpio = CERF_GPIO_CF_BVD2;
+	skt->stat[SOC_STAT_BVD2].name = "CF_BVD2";
+	skt->stat[SOC_STAT_RDY].gpio = CERF_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF_IRQ";
+
+	return 0;
+}
+
+static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free(CERF_GPIO_CF_RESET);
+}
+
+static int
+cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+			     const socket_state_t *state)
+{
+	switch (state->Vcc) {
+	case 0:
+	case 50:
+	case 33:
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__func__, state->Vcc);
+		return -1;
+	}
+
+	gpio_set_value(CERF_GPIO_CF_RESET, !!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static struct pcmcia_low_level cerf_pcmcia_ops = { 
+	.owner			= THIS_MODULE,
+	.hw_init		= cerf_pcmcia_hw_init,
+	.hw_shutdown		= cerf_pcmcia_hw_shutdown,
+	.socket_state		= soc_common_cf_socket_state,
+	.configure_socket	= cerf_pcmcia_configure_socket,
+};
+
+int pcmcia_cerf_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_cerf())
+		ret = sa11xx_drv_pcmcia_probe(dev, &cerf_pcmcia_ops, CERF_SOCKET, 1);
+
+	return ret;
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.c
new file mode 100644
index 0000000..66acdc8
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.c
@@ -0,0 +1,135 @@
+/*======================================================================
+
+    Device driver for the PCMCIA control functionality of StrongARM
+    SA-1100 microprocessors.
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/hardware/scoop.h>
+
+#include "sa1100_generic.h"
+
+int __init pcmcia_collie_init(struct device *dev);
+
+static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
+#ifdef CONFIG_SA1100_ASSABET
+	pcmcia_assabet_init,
+#endif
+#ifdef CONFIG_SA1100_CERF
+	pcmcia_cerf_init,
+#endif
+#if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
+	pcmcia_h3600_init,
+#endif
+#ifdef CONFIG_SA1100_NANOENGINE
+	pcmcia_nanoengine_init,
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	pcmcia_shannon_init,
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+	pcmcia_simpad_init,
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+       pcmcia_collie_init,
+#endif
+};
+
+static int sa11x0_drv_pcmcia_probe(struct platform_device *dev)
+{
+	int i, ret = -ENODEV;
+
+	/*
+	 * Initialise any "on-board" PCMCIA sockets.
+	 */
+	for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) {
+		ret = sa11x0_pcmcia_hw_init[i](&dev->dev);
+		if (ret == 0)
+			break;
+	}
+
+	return ret;
+}
+
+static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
+{
+	struct skt_dev_info *sinfo = platform_get_drvdata(dev);
+	int i;
+
+	platform_set_drvdata(dev, NULL);
+
+	for (i = 0; i < sinfo->nskt; i++)
+		soc_pcmcia_remove_one(&sinfo->skt[i]);
+
+	return 0;
+}
+
+static struct platform_driver sa11x0_pcmcia_driver = {
+	.driver = {
+		.name		= "sa11x0-pcmcia",
+	},
+	.probe		= sa11x0_drv_pcmcia_probe,
+	.remove		= sa11x0_drv_pcmcia_remove,
+};
+
+/* sa11x0_pcmcia_init()
+ * ^^^^^^^^^^^^^^^^^^^^
+ *
+ * This routine performs low-level PCMCIA initialization and then
+ * registers this socket driver with Card Services.
+ *
+ * Returns: 0 on success, -ve error code on failure
+ */
+static int __init sa11x0_pcmcia_init(void)
+{
+	return platform_driver_register(&sa11x0_pcmcia_driver);
+}
+
+/* sa11x0_pcmcia_exit()
+ * ^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa11x0_pcmcia_exit(void)
+{
+	platform_driver_unregister(&sa11x0_pcmcia_driver);
+}
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
+MODULE_LICENSE("Dual MPL/GPL");
+
+fs_initcall(sa11x0_pcmcia_init);
+module_exit(sa11x0_pcmcia_exit);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.h b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.h
new file mode 100644
index 0000000..a5f1f1d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_generic.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include "soc_common.h"
+#include "sa11xx_base.h"
+
+/*
+ * Declaration for all machine specific init/exit functions.
+ */
+extern int pcmcia_adsbitsy_init(struct device *);
+extern int pcmcia_assabet_init(struct device *);
+extern int pcmcia_badge4_init(struct device *);
+extern int pcmcia_cerf_init(struct device *);
+extern int pcmcia_flexanet_init(struct device *);
+extern int pcmcia_freebird_init(struct device *);
+extern int pcmcia_gcplus_init(struct device *);
+extern int pcmcia_graphicsmaster_init(struct device *);
+extern int pcmcia_h3600_init(struct device *);
+extern int pcmcia_nanoengine_init(struct device *);
+extern int pcmcia_pangolin_init(struct device *);
+extern int pcmcia_pfs168_init(struct device *);
+extern int pcmcia_shannon_init(struct device *);
+extern int pcmcia_simpad_init(struct device *);
+extern int pcmcia_stork_init(struct device *);
+extern int pcmcia_system3_init(struct device *);
+extern int pcmcia_trizeps_init(struct device *);
+extern int pcmcia_xp860_init(struct device *);
+extern int pcmcia_yopy_init(struct device *);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_h3600.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_h3600.c
new file mode 100644
index 0000000..aebf9a6
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_h3600.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_h3600.c
+ *
+ * PCMCIA implementation routines for H3600
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <mach/h3xxx.h>
+
+#include "sa1100_generic.h"
+
+static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int err;
+
+	switch (skt->nr) {
+	case 0:
+		skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD0;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD0";
+		skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ0;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ0";
+
+		err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON");
+		if (err)
+			goto err01;
+		err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
+		if (err)
+			goto err03;
+		err = gpio_request(H3XXX_EGPIO_OPT_ON, "OPT ON");
+		if (err)
+			goto err03;
+		err = gpio_direction_output(H3XXX_EGPIO_OPT_ON, 0);
+		if (err)
+			goto err04;
+		err = gpio_request(H3XXX_EGPIO_OPT_RESET, "OPT RESET");
+		if (err)
+			goto err04;
+		err = gpio_direction_output(H3XXX_EGPIO_OPT_RESET, 0);
+		if (err)
+			goto err05;
+		err = gpio_request(H3XXX_EGPIO_CARD_RESET, "PCMCIA CARD RESET");
+		if (err)
+			goto err05;
+		err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0);
+		if (err)
+			goto err06;
+		break;
+	case 1:
+		skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD1;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD1";
+		skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ1;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ1";
+		break;
+	}
+	return 0;
+
+err06:	gpio_free(H3XXX_EGPIO_CARD_RESET);
+err05:	gpio_free(H3XXX_EGPIO_OPT_RESET);
+err04:	gpio_free(H3XXX_EGPIO_OPT_ON);
+err03:	gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
+err01:	gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
+	return err;
+}
+
+static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	switch (skt->nr) {
+	case 0:
+		/* Disable CF bus: */
+		gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
+		gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
+		gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
+
+		gpio_free(H3XXX_EGPIO_CARD_RESET);
+		gpio_free(H3XXX_EGPIO_OPT_RESET);
+		gpio_free(H3XXX_EGPIO_OPT_ON);
+		gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
+		break;
+	case 1:
+		break;
+	}
+}
+
+static void
+h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
+{
+	state->bvd1 = 0;
+	state->bvd2 = 0;
+	state->vs_3v = 0;
+	state->vs_Xv = 0;
+}
+
+static int
+h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) {
+		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
+		       state->Vcc / 10, state->Vcc % 10);
+		return -1;
+	}
+
+	gpio_set_value(H3XXX_EGPIO_CARD_RESET, !!(state->flags & SS_RESET));
+
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	return 0;
+}
+
+static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+	/* Enable CF bus: */
+	gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 1);
+	gpio_set_value(H3XXX_EGPIO_OPT_ON, 1);
+	gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0);
+
+	msleep(10);
+}
+
+static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	/*
+	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
+	 * the generic PCMCIA layer to deal with the idea of two sockets
+	 * on one bus.  We rely on the cs.c behaviour shutting down
+	 * socket 0 then socket 1.
+	 */
+	if (skt->nr == 1) {
+		gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
+		gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
+		/* hmm, does this suck power? */
+		gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
+	}
+}
+
+struct pcmcia_low_level h3600_pcmcia_ops = { 
+	.owner			= THIS_MODULE,
+	.hw_init		= h3600_pcmcia_hw_init,
+	.hw_shutdown		= h3600_pcmcia_hw_shutdown,
+	.socket_state		= h3600_pcmcia_socket_state,
+	.configure_socket	= h3600_pcmcia_configure_socket,
+
+	.socket_init		= h3600_pcmcia_socket_init,
+	.socket_suspend		= h3600_pcmcia_socket_suspend,
+};
+
+int pcmcia_h3600_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_h3600() || machine_is_h3100())
+		ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2);
+
+	return ret;
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_nanoengine.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_nanoengine.c
new file mode 100644
index 0000000..35c30ff
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_nanoengine.c
@@ -0,0 +1,133 @@
+/*
+ * drivers/pcmcia/sa1100_nanoengine.c
+ *
+ * PCMCIA implementation routines for BSI nanoEngine.
+ *
+ * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine
+ * board you should carefully read this:
+ * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/
+ *
+ * Copyright (C) 2010 Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
+ *
+ * Based on original work for kernel 2.4 by
+ * Miguel Freitas <miguel@cpti.cetuc.puc-rio.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/nanoengine.h>
+
+#include "sa1100_generic.h"
+
+struct nanoengine_pins {
+	unsigned output_pins;
+	unsigned clear_outputs;
+	int gpio_rst;
+	int gpio_cd;
+	int gpio_rdy;
+};
+
+static struct nanoengine_pins nano_skts[] = {
+	{
+		.gpio_rst		= GPIO_PC_RESET0,
+		.gpio_cd		= GPIO_PC_CD0,
+		.gpio_rdy		= GPIO_PC_READY0,
+	}, {
+		.gpio_rst		= GPIO_PC_RESET1,
+		.gpio_cd		= GPIO_PC_CD1,
+		.gpio_rdy		= GPIO_PC_READY1,
+	}
+};
+
+unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts);
+
+static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	unsigned i = skt->nr;
+	int ret;
+
+	if (i >= num_nano_pcmcia_sockets)
+		return -ENXIO;
+
+	ret = gpio_request_one(nano_skts[i].gpio_rst, GPIOF_OUT_INIT_LOW,
+		i ? "PC RST1" : "PC RST0");
+	if (ret)
+		return ret;
+
+	skt->stat[SOC_STAT_CD].gpio = nano_skts[i].gpio_cd;
+	skt->stat[SOC_STAT_CD].name = i ? "PC CD1" : "PC CD0";
+	skt->stat[SOC_STAT_RDY].gpio = nano_skts[i].gpio_rdy;
+	skt->stat[SOC_STAT_RDY].name = i ? "PC RDY1" : "PC RDY0";
+
+	return 0;
+}
+
+static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	gpio_free(nano_skts[skt->nr].gpio_rst);
+}
+
+static int nanoengine_pcmcia_configure_socket(
+	struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	unsigned i = skt->nr;
+
+	if (i >= num_nano_pcmcia_sockets)
+		return -ENXIO;
+
+	gpio_set_value(nano_skts[skt->nr].gpio_rst, !!(state->flags & SS_RESET));
+
+	return 0;
+}
+
+static void nanoengine_pcmcia_socket_state(
+	struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
+{
+	unsigned i = skt->nr;
+
+	if (i >= num_nano_pcmcia_sockets)
+		return;
+
+	state->bvd1 = 1;
+	state->bvd2 = 1;
+	state->vs_3v = 1; /* Can only apply 3.3V */
+	state->vs_Xv = 0;
+}
+
+static struct pcmcia_low_level nanoengine_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.hw_init		= nanoengine_pcmcia_hw_init,
+	.hw_shutdown		= nanoengine_pcmcia_hw_shutdown,
+
+	.configure_socket	= nanoengine_pcmcia_configure_socket,
+	.socket_state		= nanoengine_pcmcia_socket_state,
+};
+
+int pcmcia_nanoengine_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_nanoengine())
+		ret = sa11xx_drv_pcmcia_probe(
+			dev, &nanoengine_pcmcia_ops, 0, 2);
+
+	return ret;
+}
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_shannon.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_shannon.c
new file mode 100644
index 0000000..0e52a57
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_shannon.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_shannon.c
+ *
+ * PCMCIA implementation routines for Shannon
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/shannon.h>
+#include <asm/irq.h>
+#include "sa1100_generic.h"
+
+static int shannon_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	/* All those are inputs */
+	GAFR &= ~(GPIO_GPIO(SHANNON_GPIO_EJECT_0) |
+		  GPIO_GPIO(SHANNON_GPIO_EJECT_1) |
+		  GPIO_GPIO(SHANNON_GPIO_RDY_0) |
+		  GPIO_GPIO(SHANNON_GPIO_RDY_1));
+
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_0;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_0";
+		skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_0;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_0";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_1;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_1";
+		skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_1;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_1";
+	}
+
+	return 0;
+}
+
+static void
+shannon_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+			    struct pcmcia_state *state)
+{
+	switch (skt->nr) {
+	case 0:
+		state->bvd1   = 1; 
+		state->bvd2   = 1; 
+		state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+		state->vs_Xv  = 0;
+		break;
+
+	case 1:
+		state->bvd1   = 1; 
+		state->bvd2   = 1; 
+		state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+		state->vs_Xv  = 0;
+		break;
+	}
+}
+
+static int
+shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	switch (state->Vcc) {
+	case 0:	/* power off */
+		printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__);
+		break;
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__);
+	case 33:
+		break;
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+		       __func__, state->Vcc);
+		return -1;
+	}
+
+	printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__);
+	
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	return 0;
+}
+
+static struct pcmcia_low_level shannon_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.hw_init		= shannon_pcmcia_hw_init,
+	.socket_state		= shannon_pcmcia_socket_state,
+	.configure_socket	= shannon_pcmcia_configure_socket,
+};
+
+int pcmcia_shannon_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_shannon())
+		ret = sa11xx_drv_pcmcia_probe(dev, &shannon_pcmcia_ops, 0, 2);
+
+	return ret;
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_simpad.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_simpad.c
new file mode 100644
index 0000000..7ce65bb
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1100_simpad.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_simpad.c
+ *
+ * PCMCIA implementation routines for simpad
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <mach/simpad.h>
+#include "sa1100_generic.h"
+ 
+static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+
+	simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+
+	skt->stat[SOC_STAT_CD].gpio = GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF_CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF_RDY";
+
+	return 0;
+}
+
+static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	/* Disable CF bus: */
+	/*simpad_set_cs3_bit(PCMCIA_BUFF_DIS);*/
+	simpad_clear_cs3_bit(PCMCIA_RESET);
+}
+
+static void
+simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+			   struct pcmcia_state *state)
+{
+	long cs3reg = simpad_get_cs3_ro();
+
+	/* the detect signal is inverted - fix that up here */
+	state->detect = !state->detect;
+
+	state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
+	state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
+
+	if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
+			(PCMCIA_VS1|PCMCIA_VS2)) {
+		state->vs_3v=0;
+		state->vs_Xv=0;
+	} else {
+		state->vs_3v=1;
+		state->vs_Xv=0;
+	}
+}
+
+static int
+simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+			       const socket_state_t *state)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* Murphy: see table of MIC2562a-1 */
+	switch (state->Vcc) {
+	case 0:
+		simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+		break;
+
+	case 33:  
+		simpad_clear_cs3_bit(VCC_3V_EN|EN1);
+		simpad_set_cs3_bit(VCC_5V_EN|EN0);
+		break;
+
+	case 50:
+		simpad_clear_cs3_bit(VCC_5V_EN|EN1);
+		simpad_set_cs3_bit(VCC_3V_EN|EN0);
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__func__, state->Vcc);
+		simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+		local_irq_restore(flags);
+		return -1;
+	}
+
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	simpad_set_cs3_bit(PCMCIA_RESET);
+}
+
+static struct pcmcia_low_level simpad_pcmcia_ops = { 
+	.owner			= THIS_MODULE,
+	.hw_init		= simpad_pcmcia_hw_init,
+	.hw_shutdown		= simpad_pcmcia_hw_shutdown,
+	.socket_state		= simpad_pcmcia_socket_state,
+	.configure_socket	= simpad_pcmcia_configure_socket,
+	.socket_suspend		= simpad_pcmcia_socket_suspend,
+};
+
+int pcmcia_simpad_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_simpad())
+		ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1);
+
+	return ret;
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_badge4.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_badge4.c
new file mode 100644
index 0000000..2f49093
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_badge4.c
@@ -0,0 +1,160 @@
+/*
+ * linux/drivers/pcmcia/sa1100_badge4.c
+ *
+ * BadgePAD 4 PCMCIA specific routines
+ *
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * BadgePAD 4 Details
+ *
+ * PCM Vcc:
+ *
+ *  PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3
+ *  on JP6) or 5v0 (short pins 3 and 5 on JP6).
+ *
+ * PCM Vpp:
+ *
+ *  PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6
+ *  on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6).  N.B.,
+ *  12v0 operation requires that the power supply actually supply 12v0
+ *  via pin 7 of JP7.
+ *
+ * CF Vcc:
+ *
+ *  CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1
+ *  and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10).
+ *
+ * Unfortunately there's no way programmatically to determine how a
+ * given board is jumpered.  This code assumes a default jumpering
+ * as described below.
+ *
+ * If the defaults aren't correct, you may override them with a pcmv
+ * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>.  The units are
+ * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0
+ * PCM Vpp, and 5v0 CF Vcc.
+ *
+ */
+
+static int badge4_pcmvcc = 50;  /* pins 3 and 5 jumpered on JP6 */
+static int badge4_pcmvpp = 50;  /* pins 2 and 4 jumpered on JP6 */
+static int badge4_cfvcc = 33;   /* pins 1 and 2 jumpered on JP10 */
+
+static void complain_about_jumpering(const char *whom,
+				     const char *supply,
+				     int given, int wanted)
+{
+	printk(KERN_ERR
+	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
+	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
+	       whom, supply,
+	       wanted / 10, wanted % 10,
+	       supply,
+	       given / 10, given % 10);
+}
+
+static int
+badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	int ret;
+
+	switch (skt->nr) {
+	case 0:
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_pcmvcc)) {
+			complain_about_jumpering(__func__, "pcmvcc",
+						 badge4_pcmvcc, state->Vcc);
+			// Apply power regardless of the jumpering.
+			// return -1;
+		}
+		if ((state->Vpp != 0) &&
+		    (state->Vpp != badge4_pcmvpp)) {
+			complain_about_jumpering(__func__, "pcmvpp",
+						 badge4_pcmvpp, state->Vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_cfvcc)) {
+			complain_about_jumpering(__func__, "cfvcc",
+						 badge4_cfvcc, state->Vcc);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		unsigned long flags;
+		int need5V;
+
+		local_irq_save(flags);
+
+		need5V = ((state->Vcc == 50) || (state->Vpp == 50));
+
+		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
+
+		local_irq_restore(flags);
+	}
+
+	return ret;
+}
+
+static struct pcmcia_low_level badge4_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= badge4_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int pcmcia_badge4_init(struct sa1111_dev *dev)
+{
+	printk(KERN_INFO
+	       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+	       __func__,
+	       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
+
+	sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops);
+	return sa1111_pcmcia_add(dev, &badge4_pcmcia_ops,
+				 sa11xx_drv_pcmcia_add_one);
+}
+
+static int __init pcmv_setup(char *s)
+{
+	int v[4];
+
+	s = get_options(s, ARRAY_SIZE(v), v);
+
+	if (v[0] >= 1) badge4_pcmvcc = v[1];
+	if (v[0] >= 2) badge4_pcmvpp = v[2];
+	if (v[0] >= 3) badge4_cfvcc = v[3];
+
+	return 1;
+}
+
+__setup("pcmv=", pcmv_setup);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.c
new file mode 100644
index 0000000..3d95dff
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.c
@@ -0,0 +1,273 @@
+/*
+ * linux/drivers/pcmcia/sa1111_generic.c
+ *
+ * We implement the generic parts of a SA1111 PCMCIA driver.  This
+ * basically means we handle everything except controlling the
+ * power.  Power is machine specific...
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <pcmcia/ss.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * These are offsets from the above base.
+ */
+#define PCCR	0x0000
+#define PCSSR	0x0004
+#define PCSR	0x0008
+
+#define PCSR_S0_READY	(1<<0)
+#define PCSR_S1_READY	(1<<1)
+#define PCSR_S0_DETECT	(1<<2)
+#define PCSR_S1_DETECT	(1<<3)
+#define PCSR_S0_VS1	(1<<4)
+#define PCSR_S0_VS2	(1<<5)
+#define PCSR_S1_VS1	(1<<6)
+#define PCSR_S1_VS2	(1<<7)
+#define PCSR_S0_WP	(1<<8)
+#define PCSR_S1_WP	(1<<9)
+#define PCSR_S0_BVD1	(1<<10)
+#define PCSR_S0_BVD2	(1<<11)
+#define PCSR_S1_BVD1	(1<<12)
+#define PCSR_S1_BVD2	(1<<13)
+
+#define PCCR_S0_RST	(1<<0)
+#define PCCR_S1_RST	(1<<1)
+#define PCCR_S0_FLT	(1<<2)
+#define PCCR_S1_FLT	(1<<3)
+#define PCCR_S0_PWAITEN	(1<<4)
+#define PCCR_S1_PWAITEN	(1<<5)
+#define PCCR_S0_PSE	(1<<6)
+#define PCCR_S1_PSE	(1<<7)
+
+#define PCSSR_S0_SLEEP	(1<<0)
+#define PCSSR_S1_SLEEP	(1<<1)
+
+#define IDX_IRQ_S0_READY_NINT	(0)
+#define IDX_IRQ_S0_CD_VALID	(1)
+#define IDX_IRQ_S0_BVD1_STSCHG	(2)
+#define IDX_IRQ_S1_READY_NINT	(3)
+#define IDX_IRQ_S1_CD_VALID	(4)
+#define IDX_IRQ_S1_BVD1_STSCHG	(5)
+
+void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
+
+	switch (skt->nr) {
+	case 0:
+		state->detect = status & PCSR_S0_DETECT ? 0 : 1;
+		state->ready  = status & PCSR_S0_READY  ? 1 : 0;
+		state->bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
+		state->bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
+		state->wrprot = status & PCSR_S0_WP     ? 1 : 0;
+		state->vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
+		state->vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
+		break;
+
+	case 1:
+		state->detect = status & PCSR_S1_DETECT ? 0 : 1;
+		state->ready  = status & PCSR_S1_READY  ? 1 : 0;
+		state->bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
+		state->bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
+		state->wrprot = status & PCSR_S1_WP     ? 1 : 0;
+		state->vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
+		state->vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
+		break;
+	}
+}
+
+int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int pccr_skt_mask, pccr_set_mask, val;
+	unsigned long flags;
+
+	switch (skt->nr) {
+	case 0:
+		pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE;
+		break;
+
+	case 1:
+		pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE;
+		break;
+
+	default:
+		return -1;
+	}
+
+	pccr_set_mask = 0;
+
+	if (state->Vcc != 0)
+		pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN;
+	if (state->Vcc == 50)
+		pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE;
+	if (state->flags & SS_RESET)
+		pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST;
+	if (state->flags & SS_OUTPUT_ENA)
+		pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
+
+	local_irq_save(flags);
+	val = sa1111_readl(s->dev->mapbase + PCCR);
+	val &= ~pccr_skt_mask;
+	val |= pccr_set_mask & pccr_skt_mask;
+	sa1111_writel(val, s->dev->mapbase + PCCR);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
+	int (*add)(struct soc_pcmcia_socket *))
+{
+	struct sa1111_pcmcia_socket *s;
+	struct clk *clk;
+	int i, ret = 0;
+
+	clk = devm_clk_get(&dev->dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ops->socket_state = sa1111_pcmcia_socket_state;
+
+	for (i = 0; i < ops->nr; i++) {
+		s = kzalloc(sizeof(*s), GFP_KERNEL);
+		if (!s)
+			return -ENOMEM;
+
+		s->soc.nr = ops->first + i;
+		s->soc.clk = clk;
+
+		soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
+		s->dev = dev;
+		if (s->soc.nr) {
+			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S1_READY_NINT];
+			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
+			s->soc.stat[SOC_STAT_CD].name = "SA1111 CF card detect";
+			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
+			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 CF BVD1";
+		} else {
+			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S0_READY_NINT];
+			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
+			s->soc.stat[SOC_STAT_CD].name = "SA1111 PCMCIA card detect";
+			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
+			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 PCMCIA BVD1";
+		}
+
+		ret = add(&s->soc);
+		if (ret == 0) {
+			s->next = dev_get_drvdata(&dev->dev);
+			dev_set_drvdata(&dev->dev, s);
+		} else
+			kfree(s);
+	}
+
+	return ret;
+}
+
+static int pcmcia_probe(struct sa1111_dev *dev)
+{
+	void __iomem *base;
+	int ret;
+
+	ret = sa1111_enable_device(dev);
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(&dev->dev, NULL);
+
+	if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
+		sa1111_disable_device(dev);
+		return -EBUSY;
+	}
+
+	base = dev->mapbase;
+
+	/*
+	 * Initialise the suspend state.
+	 */
+	sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
+	sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
+
+	ret = -ENODEV;
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4())
+		ret = pcmcia_badge4_init(dev);
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	if (machine_is_jornada720())
+		ret = pcmcia_jornada720_init(dev);
+#endif
+#ifdef CONFIG_ARCH_LUBBOCK
+	if (machine_is_lubbock())
+		ret = pcmcia_lubbock_init(dev);
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+	if (machine_is_assabet())
+		ret = pcmcia_neponset_init(dev);
+#endif
+
+	if (ret) {
+		release_mem_region(dev->res.start, 512);
+		sa1111_disable_device(dev);
+	}
+
+	return ret;
+}
+
+static int pcmcia_remove(struct sa1111_dev *dev)
+{
+	struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev);
+
+	dev_set_drvdata(&dev->dev, NULL);
+
+	for (; s; s = next) {
+		next = s->next;
+		soc_pcmcia_remove_one(&s->soc);
+		kfree(s);
+	}
+
+	release_mem_region(dev->res.start, 512);
+	sa1111_disable_device(dev);
+	return 0;
+}
+
+static struct sa1111_driver pcmcia_driver = {
+	.drv = {
+		.name	= "sa1111-pcmcia",
+	},
+	.devid		= SA1111_DEVID_PCMCIA,
+	.probe		= pcmcia_probe,
+	.remove		= pcmcia_remove,
+};
+
+static int __init sa1111_drv_pcmcia_init(void)
+{
+	return sa1111_driver_register(&pcmcia_driver);
+}
+
+static void __exit sa1111_drv_pcmcia_exit(void)
+{
+	sa1111_driver_unregister(&pcmcia_driver);
+}
+
+fs_initcall(sa1111_drv_pcmcia_init);
+module_exit(sa1111_drv_pcmcia_exit);
+
+MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.h b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.h
new file mode 100644
index 0000000..c01571d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_generic.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include "soc_common.h"
+#include "sa11xx_base.h"
+
+struct sa1111_pcmcia_socket {
+	struct soc_pcmcia_socket soc;
+	struct sa1111_dev *dev;
+	struct sa1111_pcmcia_socket *next;
+};
+
+static inline struct sa1111_pcmcia_socket *to_skt(struct soc_pcmcia_socket *s)
+{
+	return container_of(s, struct sa1111_pcmcia_socket, soc);
+}
+
+int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
+	int (*add)(struct soc_pcmcia_socket *));
+
+extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *);
+extern int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *, const socket_state_t *);
+
+extern int pcmcia_badge4_init(struct sa1111_dev *);
+extern int pcmcia_jornada720_init(struct sa1111_dev *);
+extern int pcmcia_lubbock_init(struct sa1111_dev *);
+extern int pcmcia_neponset_init(struct sa1111_dev *);
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_jornada720.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_jornada720.c
new file mode 100644
index 0000000..3d4ca87
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_jornada720.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/pcmcia/sa1100_jornada720.c
+ *
+ * Jornada720 PCMCIA specific routines
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+
+#include "sa1111_generic.h"
+
+/* Does SOCKET1_3V actually do anything? */
+#define SOCKET0_POWER	GPIO_GPIO0
+#define SOCKET0_3V	GPIO_GPIO2
+#define SOCKET1_POWER	(GPIO_GPIO1 | GPIO_GPIO3)
+#define SOCKET1_3V	GPIO_GPIO3
+
+static int
+jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int pa_dwr_mask, pa_dwr_set;
+	int ret;
+
+	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
+		skt->nr, state->Vcc, state->Vpp);
+
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
+
+		switch (state->Vcc) {
+		default:
+		case  0:
+			pa_dwr_set = 0;
+			break;
+		case 33:
+			pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
+			break;
+		case 50:
+			pa_dwr_set = SOCKET0_POWER;
+			break;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = SOCKET1_POWER;
+
+		switch (state->Vcc) {
+		default:
+		case 0:
+			pa_dwr_set = 0;
+			break;
+		case 33:
+			pa_dwr_set = SOCKET1_POWER;
+			break;
+		case 50:
+			pa_dwr_set = SOCKET1_POWER;
+			break;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	if (state->Vpp != state->Vcc && state->Vpp != 0) {
+		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
+			__func__, state->Vpp);
+		return -EPERM;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0)
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+
+	return ret;
+}
+
+static struct pcmcia_low_level jornada720_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= jornada720_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int pcmcia_jornada720_init(struct sa1111_dev *sadev)
+{
+	unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+	/* Fixme: why messing around with SA11x0's GPIO1? */
+	GRER |= 0x00000002;
+
+	/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
+	sa1111_set_io_dir(sadev, pin, 0, 0);
+	sa1111_set_io(sadev, pin, 0);
+	sa1111_set_sleep_io(sadev, pin, 0);
+
+	sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
+	return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
+				 sa11xx_drv_pcmcia_add_one);
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_lubbock.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_lubbock.c
new file mode 100644
index 0000000..e741f49
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_lubbock.c
@@ -0,0 +1,230 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_lubbock.c
+ *
+ * Author:	George Davis
+ * Created:	Jan 10, 2002
+ * Copyright:	MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Lubbock PCMCIA specific routines.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+#include <mach/lubbock.h>
+
+#include "sa1111_generic.h"
+
+static int
+lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
+	int ret = 0;
+
+	pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
+
+	/* Lubbock uses the Maxim MAX1602, with the following connections:
+	 *
+	 * Socket 0 (PCMCIA):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
+	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
+	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
+	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	+12V
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 * Socket 1 (CF):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	GND		VPP is not connected
+	 *	A1VPP	GND		VPP is not connected
+	 *	A0VCC	S1_PWR0		MISC_WR<14>
+	 *	A1VCC	S1_PWR1		MISC_WR<15>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	GND		VPP is not connected
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 */
+
+ again:
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			pa_dwr_set |= GPIO_A3;
+			break;
+
+		case 50: /* VX */
+			pa_dwr_set |= GPIO_A2;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __func__, state->Vcc);
+			ret = -1;
+		}
+
+		switch (state->Vpp) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 120: /* 12IN */
+			pa_dwr_set |= GPIO_A1;
+			break;
+
+		default: /* VCC */
+			if (state->Vpp == state->Vcc)
+				pa_dwr_set |= GPIO_A0;
+			else {
+				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+				       __func__, state->Vpp);
+				ret = -1;
+				break;
+			}
+		}
+		break;
+
+	case 1:
+		misc_mask = (1 << 15) | (1 << 14);
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			misc_set |= 1 << 15;
+			break;
+
+		case 50: /* VX */
+			misc_set |= 1 << 14;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __func__, state->Vcc);
+			ret = -1;
+			break;
+		}
+
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+			       __func__, state->Vpp);
+			ret = -1;
+			break;
+		}
+		break;
+
+	default:
+		ret = -1;
+	}
+
+	if (ret == 0)
+		ret = sa1111_pcmcia_configure_socket(skt, state);
+
+	if (ret == 0) {
+		lubbock_set_misc_wr(misc_mask, misc_set);
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+	}
+
+#if 1
+	if (ret == 0 && state->Vcc == 33) {
+		struct pcmcia_state new_state;
+
+		/*
+		 * HACK ALERT:
+		 * We can't sense the voltage properly on Lubbock before
+		 * actually applying some power to the socket (catch 22).
+		 * Resense the socket Voltage Sense pins after applying
+		 * socket power.
+		 *
+		 * Note: It takes about 2.5ms for the MAX1602 VCC output
+		 * to rise.
+		 */
+		mdelay(3);
+
+		sa1111_pcmcia_socket_state(skt, &new_state);
+
+		if (!new_state.vs_3v && !new_state.vs_Xv) {
+			/*
+			 * Switch to 5V,  Configure socket with 5V voltage
+			 */
+			lubbock_set_misc_wr(misc_mask, 0);
+			sa1111_set_io(s->dev, pa_dwr_mask, 0);
+
+			/*
+			 * It takes about 100ms to turn off Vcc.
+			 */
+			mdelay(100);
+
+			/*
+			 * We need to hack around the const qualifier as
+			 * well to keep this ugly workaround localized and
+			 * not force it to the rest of the code. Barf bags
+			 * available in the seat pocket in front of you!
+			 */
+			((socket_state_t *)state)->Vcc = 50;
+			((socket_state_t *)state)->Vpp = 50;
+			goto again;
+		}
+	}
+#endif
+
+	return ret;
+}
+
+static struct pcmcia_low_level lubbock_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= lubbock_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+#include "pxa2xx_base.h"
+
+int pcmcia_lubbock_init(struct sa1111_dev *sadev)
+{
+	/*
+	 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+	 * and switch to standby mode.
+	 */
+	sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+	sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+	sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+
+	/* Set CF Socket 1 power to standby mode. */
+	lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
+
+	pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
+	pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
+	return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
+				 pxa2xx_drv_pcmcia_add_one);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_neponset.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_neponset.c
new file mode 100644
index 0000000..0ccf05a
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa1111_neponset.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Neponset PCMCIA specific routines
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/neponset.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ *   MAX1600      Neponset
+ *
+ *    A0VCC        SA-1111 GPIO A<1>
+ *    A1VCC        SA-1111 GPIO A<0>
+ *    A0VPP        CPLD NCR A0VPP
+ *    A1VPP        CPLD NCR A1VPP
+ *    B0VCC        SA-1111 GPIO A<2>
+ *    B1VCC        SA-1111 GPIO A<3>
+ *    B0VPP        ground (slot B is CF)
+ *    B1VPP        ground (slot B is CF)
+ *
+ *     VX          VCC (5V)
+ *     VY          VCC3_3 (3.3V)
+ *     12INA       12V
+ *     12INB       ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in 
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
+static int
+neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
+	int ret;
+
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_A0 | GPIO_A1;
+		ncr_mask = NCR_A0VPP | NCR_A1VPP;
+
+		if (state->Vpp == 0)
+			ncr_set = 0;
+		else if (state->Vpp == 120)
+			ncr_set = NCR_A1VPP;
+		else if (state->Vpp == state->Vcc)
+			ncr_set = NCR_A0VPP;
+		else {
+			printk(KERN_ERR "%s(): unrecognized VPP %u\n",
+			       __func__, state->Vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_A2 | GPIO_A3;
+		ncr_mask = 0;
+		ncr_set = 0;
+
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+			       __func__, state->Vpp);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	/*
+	 * pa_dwr_set is the mask for selecting Vcc on both sockets.
+	 * pa_dwr_mask selects which bits (and therefore socket) we change.
+	 */
+	switch (state->Vcc) {
+	default:
+	case 0:  pa_dwr_set = 0;		break;
+	case 33: pa_dwr_set = GPIO_A1|GPIO_A2;	break;
+	case 50: pa_dwr_set = GPIO_A0|GPIO_A3;	break;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		neponset_ncr_frob(ncr_mask, ncr_set);
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+	}
+
+	return ret;
+}
+
+static struct pcmcia_low_level neponset_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= neponset_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int pcmcia_neponset_init(struct sa1111_dev *sadev)
+{
+	/*
+	 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+	 * and switch to standby mode.
+	 */
+	sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+	sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+	sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+	sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
+	return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
+				 sa11xx_drv_pcmcia_add_one);
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.c b/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.c
new file mode 100644
index 0000000..48140ac
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.c
@@ -0,0 +1,263 @@
+/*======================================================================
+
+    Device driver for the PCMCIA control functionality of StrongARM
+    SA-1100 microprocessors.
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include "soc_common.h"
+#include "sa11xx_base.h"
+
+
+/*
+ * sa1100_pcmcia_default_mecr_timing
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Calculate MECR clock wait states for given CPU clock
+ * speed and command wait state. This function can be over-
+ * written by a board specific version.
+ *
+ * The default is to simply calculate the BS values as specified in
+ * the INTEL SA1100 development manual
+ * "Expansion Memory (PCMCIA) Configuration Register (MECR)"
+ * that's section 10.2.5 in _my_ version of the manual ;)
+ */
+static unsigned int
+sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
+				  unsigned int cpu_speed,
+				  unsigned int cmd_time)
+{
+	return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
+}
+
+/* sa1100_pcmcia_set_mecr()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * set MECR value for socket <sock> based on this sockets
+ * io, mem and attribute space access speed.
+ * Call board specific BS value calculation to allow boards
+ * to tweak the BS values.
+ */
+static int
+sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
+{
+	struct soc_pcmcia_timing timing;
+	u32 mecr, old_mecr;
+	unsigned long flags;
+	unsigned int bs_io, bs_mem, bs_attr;
+
+	soc_common_pcmcia_get_timing(skt, &timing);
+
+	bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
+	bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
+	bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
+
+	local_irq_save(flags);
+
+	old_mecr = mecr = MECR;
+	MECR_FAST_SET(mecr, skt->nr, 0);
+	MECR_BSIO_SET(mecr, skt->nr, bs_io);
+	MECR_BSA_SET(mecr, skt->nr, bs_attr);
+	MECR_BSM_SET(mecr, skt->nr, bs_mem);
+	if (old_mecr != mecr)
+		MECR = mecr;
+
+	local_irq_restore(flags);
+
+	debug(skt, 2, "FAST %X  BSM %X  BSA %X  BSIO %X\n",
+	      MECR_FAST_GET(mecr, skt->nr),
+	      MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
+	      MECR_BSIO_GET(mecr, skt->nr));
+
+	return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
+			       unsigned long val,
+			       struct cpufreq_freqs *freqs)
+{
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if (freqs->new > freqs->old)
+			sa1100_pcmcia_set_mecr(skt, freqs->new);
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		if (freqs->new < freqs->old)
+			sa1100_pcmcia_set_mecr(skt, freqs->new);
+		break;
+	}
+
+	return 0;
+}
+
+#endif
+
+static int
+sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
+{
+	unsigned long clk = clk_get_rate(skt->clk);
+
+	return sa1100_pcmcia_set_mecr(skt, clk / 1000);
+}
+
+static int
+sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
+{
+	struct soc_pcmcia_timing timing;
+	unsigned int clock = clk_get_rate(skt->clk) / 1000;
+	unsigned long mecr = MECR;
+	char *p = buf;
+
+	soc_common_pcmcia_get_timing(skt, &timing);
+
+	p+=sprintf(p, "I/O      : %uns (%uns)\n", timing.io,
+		   sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
+
+	p+=sprintf(p, "attribute: %uns (%uns)\n", timing.attr,
+		   sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
+
+	p+=sprintf(p, "common   : %uns (%uns)\n", timing.mem,
+		   sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
+
+	return p - buf;
+}
+
+static const char *skt_names[] = {
+	"PCMCIA socket 0",
+	"PCMCIA socket 1",
+};
+
+#define SKT_DEV_INFO_SIZE(n) \
+	(sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
+
+int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
+{
+	skt->res_skt.start = _PCMCIA(skt->nr);
+	skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
+	skt->res_skt.name = skt_names[skt->nr];
+	skt->res_skt.flags = IORESOURCE_MEM;
+
+	skt->res_io.start = _PCMCIAIO(skt->nr);
+	skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
+	skt->res_io.name = "io";
+	skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+	skt->res_mem.start = _PCMCIAMem(skt->nr);
+	skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
+	skt->res_mem.name = "memory";
+	skt->res_mem.flags = IORESOURCE_MEM;
+
+	skt->res_attr.start = _PCMCIAAttr(skt->nr);
+	skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
+	skt->res_attr.name = "attribute";
+	skt->res_attr.flags = IORESOURCE_MEM;
+
+	return soc_pcmcia_add_one(skt);
+}
+EXPORT_SYMBOL(sa11xx_drv_pcmcia_add_one);
+
+void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
+{
+	/*
+	 * set default MECR calculation if the board specific
+	 * code did not specify one...
+	 */
+	if (!ops->get_timing)
+		ops->get_timing = sa1100_pcmcia_default_mecr_timing;
+
+	/* Provide our SA11x0 specific timing routines. */
+	ops->set_timing  = sa1100_pcmcia_set_timing;
+	ops->show_timing = sa1100_pcmcia_show_timing;
+#ifdef CONFIG_CPU_FREQ
+	ops->frequency_change = sa1100_pcmcia_frequency_change;
+#endif
+}
+EXPORT_SYMBOL(sa11xx_drv_pcmcia_ops);
+
+int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
+			    int first, int nr)
+{
+	struct skt_dev_info *sinfo;
+	struct soc_pcmcia_socket *skt;
+	int i, ret = 0;
+	struct clk *clk;
+
+	clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	sa11xx_drv_pcmcia_ops(ops);
+
+	sinfo = devm_kzalloc(dev, SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
+	if (!sinfo)
+		return -ENOMEM;
+
+	sinfo->nskt = nr;
+
+	/* Initialize processor specific parameters */
+	for (i = 0; i < nr; i++) {
+		skt = &sinfo->skt[i];
+
+		skt->nr = first + i;
+		skt->clk = clk;
+		soc_pcmcia_init_one(skt, ops, dev);
+
+		ret = sa11xx_drv_pcmcia_add_one(skt);
+		if (ret)
+			break;
+	}
+
+	if (ret) {
+		while (--i >= 0)
+			soc_pcmcia_remove_one(&sinfo->skt[i]);
+	} else {
+		dev_set_drvdata(dev, sinfo);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
+MODULE_LICENSE("Dual MPL/GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.h b/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.h
new file mode 100644
index 0000000..3d76d72
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/sa11xx_base.h
@@ -0,0 +1,125 @@
+/*======================================================================
+
+    Device driver for the PCMCIA control functionality of StrongARM
+    SA-1100 microprocessors.
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+
+======================================================================*/
+
+#if !defined(_PCMCIA_SA1100_H)
+# define _PCMCIA_SA1100_H
+
+/* SA-1100 PCMCIA Memory and I/O timing
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * The SA-1110 Developer's Manual, section 10.2.5, says the following:
+ *
+ *  "To calculate the recommended BS_xx value for each address space:
+ *   divide the command width time (the greater of twIOWR and twIORD,
+ *   or the greater of twWE and twOE) by processor cycle time; divide
+ *   by 2; divide again by 3 (number of BCLK's per command assertion);
+ *   round up to the next whole number; and subtract 1."
+ */
+
+/* MECR: Expansion Memory Configuration Register
+ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
+ *
+ * MECR layout is:
+ *
+ *   FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0>
+ *
+ * (This layout is actually true only for the SA-1110; the FASTn bits are
+ * reserved on the SA-1100.)
+ */
+
+#define MECR_SOCKET_0_SHIFT (0)
+#define MECR_SOCKET_1_SHIFT (16)
+
+#define MECR_BS_MASK        (0x1f)
+#define MECR_FAST_MODE_MASK (0x01)
+
+#define MECR_BSIO_SHIFT (0)
+#define MECR_BSA_SHIFT  (5)
+#define MECR_BSM_SHIFT  (10)
+#define MECR_FAST_SHIFT (15)
+
+#define MECR_SET(mecr, sock, shift, mask, bs) \
+((mecr)=((mecr)&~(((mask)<<(shift))<<\
+                  ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\
+        (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))
+
+#define MECR_GET(mecr, sock, shift, mask) \
+((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\
+ (shift))&(mask))
+
+#define MECR_BSIO_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSIO_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK)
+
+#define MECR_BSA_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSA_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK)
+
+#define MECR_BSM_SET(mecr, sock, bs) \
+MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs))
+
+#define MECR_BSM_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK)
+
+#define MECR_FAST_SET(mecr, sock, fast) \
+MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast))
+
+#define MECR_FAST_GET(mecr, sock) \
+MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK)
+
+
+/* This function implements the BS value calculation for setting the MECR
+ * using integer arithmetic:
+ */
+static inline unsigned int sa1100_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns,
+						 unsigned int cpu_clock_khz){
+  unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000;
+  return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1);
+}
+
+/* This function returns the (approximate) command assertion period, in
+ * nanoseconds, for a given CPU clock frequency and MECR BS value:
+ */
+static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz,
+						  unsigned int pcmcia_mecr_bs){
+  return (((10000000 * 2) / cpu_clock_khz) * (3 * (pcmcia_mecr_bs + 1))) / 10;
+}
+
+
+int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt);
+void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops);
+extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
+
+#endif  /* !defined(_PCMCIA_SA1100_H) */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.c b/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.c
new file mode 100644
index 0000000..b6b316d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.c
@@ -0,0 +1,890 @@
+/*======================================================================
+
+    Common support code for the PCMCIA control functionality of
+    integrated SOCs like the SA-11x0 and PXA2xx microprocessors.
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is John G. Dorsey
+    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
+    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+
+======================================================================*/
+
+
+#include <linux/cpufreq.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+
+#include <mach/hardware.h>
+
+#include "soc_common.h"
+
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
+
+#ifdef CONFIG_PCMCIA_DEBUG
+
+static int pc_debug;
+module_param(pc_debug, int, 0644);
+
+void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
+		      int lvl, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	if (pc_debug > lvl) {
+		va_start(args, fmt);
+
+		vaf.fmt = fmt;
+		vaf.va = &args;
+
+		printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
+
+		va_end(args);
+	}
+}
+EXPORT_SYMBOL(soc_pcmcia_debug);
+
+#endif
+
+#define to_soc_pcmcia_socket(x)	\
+	container_of(x, struct soc_pcmcia_socket, socket)
+
+int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
+	struct soc_pcmcia_regulator *r, int v)
+{
+	bool on;
+	int ret;
+
+	if (!r->reg)
+		return 0;
+
+	on = v != 0;
+	if (r->on == on)
+		return 0;
+
+	if (on) {
+		ret = regulator_set_voltage(r->reg, v * 100000, v * 100000);
+		if (ret) {
+			int vout = regulator_get_voltage(r->reg) / 100000;
+
+			dev_warn(&skt->socket.dev,
+				 "CS requested %s=%u.%uV, applying %u.%uV\n",
+				 r == &skt->vcc ? "Vcc" : "Vpp",
+				 v / 10, v % 10, vout / 10, vout % 10);
+		}
+
+		ret = regulator_enable(r->reg);
+	} else {
+		ret = regulator_disable(r->reg);
+	}
+	if (ret == 0)
+		r->on = on;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(soc_pcmcia_regulator_set);
+
+static unsigned short
+calc_speed(unsigned short *spds, int num, unsigned short dflt)
+{
+	unsigned short speed = 0;
+	int i;
+
+	for (i = 0; i < num; i++)
+		if (speed < spds[i])
+			speed = spds[i];
+	if (speed == 0)
+		speed = dflt;
+
+	return speed;
+}
+
+void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
+	struct soc_pcmcia_timing *timing)
+{
+	timing->io =
+		calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
+	timing->mem =
+		calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
+	timing->attr =
+		calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
+}
+EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
+
+static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
+	unsigned int nr)
+{
+	unsigned int i;
+
+	for (i = 0; i < nr; i++)
+		if (skt->stat[i].irq)
+			free_irq(skt->stat[i].irq, skt);
+
+	if (skt->ops->hw_shutdown)
+		skt->ops->hw_shutdown(skt);
+
+	clk_disable_unprepare(skt->clk);
+}
+
+static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	__soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
+}
+
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
+{
+	struct device *dev = skt->socket.dev.parent;
+	struct gpio_desc *desc;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+		if (!skt->stat[i].name)
+			continue;
+
+		desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN);
+		if (IS_ERR(desc)) {
+			dev_err(dev, "Failed to get GPIO for %s: %ld\n",
+				skt->stat[i].name, PTR_ERR(desc));
+			return PTR_ERR(desc);
+		}
+
+		skt->stat[i].desc = desc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
+
+static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret = 0, i;
+
+	clk_prepare_enable(skt->clk);
+
+	if (skt->ops->hw_init) {
+		ret = skt->ops->hw_init(skt);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+		if (gpio_is_valid(skt->stat[i].gpio)) {
+			unsigned long flags = GPIOF_IN;
+
+			/* CD is active low by default */
+			if (i == SOC_STAT_CD)
+				flags |= GPIOF_ACTIVE_LOW;
+
+			ret = devm_gpio_request_one(skt->socket.dev.parent,
+						    skt->stat[i].gpio, flags,
+						    skt->stat[i].name);
+			if (ret) {
+				__soc_pcmcia_hw_shutdown(skt, i);
+				return ret;
+			}
+
+			skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
+		}
+
+		if (i < SOC_STAT_VS1 && skt->stat[i].desc) {
+			int irq = gpiod_to_irq(skt->stat[i].desc);
+
+			if (irq > 0) {
+				if (i == SOC_STAT_RDY)
+					skt->socket.pci_irq = irq;
+				else
+					skt->stat[i].irq = irq;
+			}
+		}
+
+		if (skt->stat[i].irq) {
+			ret = request_irq(skt->stat[i].irq,
+					  soc_common_pcmcia_interrupt,
+					  IRQF_TRIGGER_NONE,
+					  skt->stat[i].name, skt);
+			if (ret) {
+				__soc_pcmcia_hw_shutdown(skt, i);
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		if (skt->stat[i].irq) {
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
+		}
+}
+
+static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		if (skt->stat[i].irq)
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
+}
+
+/*
+ * The CF 3.0 specification says that cards tie VS1 to ground and leave
+ * VS2 open.  Many implementations do not wire up the VS signals, so we
+ * provide hard-coded values as per the CF 3.0 spec.
+ */
+void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
+	struct pcmcia_state *state)
+{
+	state->vs_3v = 1;
+}
+EXPORT_SYMBOL_GPL(soc_common_cf_socket_state);
+
+static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
+{
+	struct pcmcia_state state;
+	unsigned int stat;
+
+	memset(&state, 0, sizeof(struct pcmcia_state));
+
+	/* Make battery voltage state report 'good' */
+	state.bvd1 = 1;
+	state.bvd2 = 1;
+
+	if (skt->stat[SOC_STAT_CD].desc)
+		state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc);
+	if (skt->stat[SOC_STAT_RDY].desc)
+		state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
+	if (skt->stat[SOC_STAT_BVD1].desc)
+		state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
+	if (skt->stat[SOC_STAT_BVD2].desc)
+		state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
+	if (skt->stat[SOC_STAT_VS1].desc)
+		state.vs_3v = !!gpiod_get_value(skt->stat[SOC_STAT_VS1].desc);
+	if (skt->stat[SOC_STAT_VS2].desc)
+		state.vs_Xv = !!gpiod_get_value(skt->stat[SOC_STAT_VS2].desc);
+
+	skt->ops->socket_state(skt, &state);
+
+	stat = state.detect  ? SS_DETECT : 0;
+	stat |= state.ready  ? SS_READY  : 0;
+	stat |= state.wrprot ? SS_WRPROT : 0;
+	stat |= state.vs_3v  ? SS_3VCARD : 0;
+	stat |= state.vs_Xv  ? SS_XVCARD : 0;
+
+	/* The power status of individual sockets is not available
+	 * explicitly from the hardware, so we just remember the state
+	 * and regurgitate it upon request:
+	 */
+	stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
+
+	if (skt->cs_state.flags & SS_IOCARD)
+		stat |= state.bvd1 ? 0 : SS_STSCHG;
+	else {
+		if (state.bvd1 == 0)
+			stat |= SS_BATDEAD;
+		else if (state.bvd2 == 0)
+			stat |= SS_BATWARN;
+	}
+	return stat;
+}
+
+/*
+ * soc_common_pcmcia_config_skt
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Convert PCMCIA socket state to our socket configure structure.
+ */
+static int soc_common_pcmcia_config_skt(
+	struct soc_pcmcia_socket *skt, socket_state_t *state)
+{
+	int ret;
+
+	ret = skt->ops->configure_socket(skt, state);
+	if (ret < 0) {
+		pr_err("soc_common_pcmcia: unable to configure socket %d\n",
+		       skt->nr);
+		/* restore the previous state */
+		WARN_ON(skt->ops->configure_socket(skt, &skt->cs_state));
+		return ret;
+	}
+
+	if (ret == 0) {
+		struct gpio_desc *descs[2];
+		int values[2], n = 0;
+
+		if (skt->gpio_reset) {
+			descs[n] = skt->gpio_reset;
+			values[n++] = !!(state->flags & SS_RESET);
+		}
+		if (skt->gpio_bus_enable) {
+			descs[n] = skt->gpio_bus_enable;
+			values[n++] = !!(state->flags & SS_OUTPUT_ENA);
+		}
+
+		if (n)
+			gpiod_set_array_value_cansleep(n, descs, values);
+
+		/*
+		 * This really needs a better solution.  The IRQ
+		 * may or may not be claimed by the driver.
+		 */
+		if (skt->irq_state != 1 && state->io_irq) {
+			skt->irq_state = 1;
+			irq_set_irq_type(skt->socket.pci_irq,
+					 IRQ_TYPE_EDGE_FALLING);
+		} else if (skt->irq_state == 1 && state->io_irq == 0) {
+			skt->irq_state = 0;
+			irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
+		}
+
+		skt->cs_state = *state;
+	}
+
+	return ret;
+}
+
+/* soc_common_pcmcia_sock_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus.  This must wait for power to stabilise
+ * so that the card status signals report correctly.
+ *
+ * Returns: 0
+ */
+static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+
+	debug(skt, 2, "initializing socket\n");
+	if (skt->ops->socket_init)
+		skt->ops->socket_init(skt);
+	soc_pcmcia_hw_enable(skt);
+	return 0;
+}
+
+
+/*
+ * soc_common_pcmcia_suspend()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
+ *
+ * Returns: 0
+ */
+static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+
+	debug(skt, 2, "suspending socket\n");
+
+	soc_pcmcia_hw_disable(skt);
+	if (skt->ops->socket_suspend)
+		skt->ops->socket_suspend(skt);
+
+	return 0;
+}
+
+static DEFINE_SPINLOCK(status_lock);
+
+static void soc_common_check_status(struct soc_pcmcia_socket *skt)
+{
+	unsigned int events;
+
+	debug(skt, 4, "entering PCMCIA monitoring thread\n");
+
+	do {
+		unsigned int status;
+		unsigned long flags;
+
+		status = soc_common_pcmcia_skt_state(skt);
+
+		spin_lock_irqsave(&status_lock, flags);
+		events = (status ^ skt->status) & skt->cs_state.csc_mask;
+		skt->status = status;
+		spin_unlock_irqrestore(&status_lock, flags);
+
+		debug(skt, 4, "events: %s%s%s%s%s%s\n",
+			events == 0         ? "<NONE>"   : "",
+			events & SS_DETECT  ? "DETECT "  : "",
+			events & SS_READY   ? "READY "   : "",
+			events & SS_BATDEAD ? "BATDEAD " : "",
+			events & SS_BATWARN ? "BATWARN " : "",
+			events & SS_STSCHG  ? "STSCHG "  : "");
+
+		if (events)
+			pcmcia_parse_events(&skt->socket, events);
+	} while (events);
+}
+
+/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
+static void soc_common_pcmcia_poll_event(unsigned long dummy)
+{
+	struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
+	debug(skt, 4, "polling for events\n");
+
+	mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
+
+	soc_common_check_status(skt);
+}
+
+
+/*
+ * Service routine for socket driver interrupts (requested by the
+ * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
+ * The actual interrupt-servicing work is performed by
+ * soc_common_pcmcia_thread(), largely because the Card Services event-
+ * handling code performs scheduling operations which cannot be
+ * executed from within an interrupt context.
+ */
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
+{
+	struct soc_pcmcia_socket *skt = dev;
+
+	debug(skt, 3, "servicing IRQ %d\n", irq);
+
+	soc_common_check_status(skt);
+
+	return IRQ_HANDLED;
+}
+
+
+/*
+ *  Implements the get_status() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetStatus in Card Services). Essentially just
+ * fills in bits in `status' according to internal driver state or
+ * the value of the voltage detect chipselect register.
+ *
+ * As a debugging note, during card startup, the PCMCIA core issues
+ * three set_socket() commands in a row the first with RESET deasserted,
+ * the second with RESET asserted, and the last with RESET deasserted
+ * again. Following the third set_socket(), a get_status() command will
+ * be issued. The kernel is looking for the SS_READY flag (see
+ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
+ *
+ * Returns: 0
+ */
+static int
+soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+
+	skt->status = soc_common_pcmcia_skt_state(skt);
+	*status = skt->status;
+
+	return 0;
+}
+
+
+/*
+ * Implements the set_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetSocket in Card Services). We more or
+ * less punt all of this work and let the kernel handle the details
+ * of power configuration, reset, &c. We also record the value of
+ * `state' in order to regurgitate it to the PCMCIA core later.
+ */
+static int soc_common_pcmcia_set_socket(
+	struct pcmcia_socket *sock, socket_state_t *state)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+
+	debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
+			(state->csc_mask == 0)		? "<NONE> " :	"",
+			(state->csc_mask & SS_DETECT)	? "DETECT " :	"",
+			(state->csc_mask & SS_READY)	? "READY " :	"",
+			(state->csc_mask & SS_BATDEAD)	? "BATDEAD " :	"",
+			(state->csc_mask & SS_BATWARN)	? "BATWARN " :	"",
+			(state->csc_mask & SS_STSCHG)	? "STSCHG " :	"",
+			(state->flags == 0)		? "<NONE> " :	"",
+			(state->flags & SS_PWR_AUTO)	? "PWR_AUTO " :	"",
+			(state->flags & SS_IOCARD)	? "IOCARD " :	"",
+			(state->flags & SS_RESET)	? "RESET " :	"",
+			(state->flags & SS_SPKR_ENA)	? "SPKR_ENA " :	"",
+			(state->flags & SS_OUTPUT_ENA)	? "OUTPUT_ENA " : "",
+			state->Vcc, state->Vpp, state->io_irq);
+
+	return soc_common_pcmcia_config_skt(skt, state);
+}
+
+
+/*
+ * Implements the set_io_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetIOMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int soc_common_pcmcia_set_io_map(
+	struct pcmcia_socket *sock, struct pccard_io_map *map)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+	unsigned short speed = map->speed;
+
+	debug(skt, 2, "map %u  speed %u start 0x%08llx stop 0x%08llx\n",
+		map->map, map->speed, (unsigned long long)map->start,
+		(unsigned long long)map->stop);
+	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
+		(map->flags == 0)		? "<NONE>"	: "",
+		(map->flags & MAP_ACTIVE)	? "ACTIVE "	: "",
+		(map->flags & MAP_16BIT)	? "16BIT "	: "",
+		(map->flags & MAP_AUTOSZ)	? "AUTOSZ "	: "",
+		(map->flags & MAP_0WS)		? "0WS "	: "",
+		(map->flags & MAP_WRPROT)	? "WRPROT "	: "",
+		(map->flags & MAP_USE_WAIT)	? "USE_WAIT "	: "",
+		(map->flags & MAP_PREFETCH)	? "PREFETCH "	: "");
+
+	if (map->map >= MAX_IO_WIN) {
+		printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
+		       map->map);
+		return -1;
+	}
+
+	if (map->flags & MAP_ACTIVE) {
+		if (speed == 0)
+			speed = SOC_PCMCIA_IO_ACCESS;
+	} else {
+		speed = 0;
+	}
+
+	skt->spd_io[map->map] = speed;
+	skt->ops->set_timing(skt);
+
+	if (map->stop == 1)
+		map->stop = PAGE_SIZE-1;
+
+	map->stop -= map->start;
+	map->stop += skt->socket.io_offset;
+	map->start = skt->socket.io_offset;
+
+	return 0;
+}
+
+
+/*
+ * Implements the set_mem_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetMemMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -ERRNO on error
+ */
+static int soc_common_pcmcia_set_mem_map(
+	struct pcmcia_socket *sock, struct pccard_mem_map *map)
+{
+	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
+	struct resource *res;
+	unsigned short speed = map->speed;
+
+	debug(skt, 2, "map %u speed %u card_start %08x\n",
+		map->map, map->speed, map->card_start);
+	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
+		(map->flags == 0)		? "<NONE>"	: "",
+		(map->flags & MAP_ACTIVE)	? "ACTIVE "	: "",
+		(map->flags & MAP_16BIT)	? "16BIT "	: "",
+		(map->flags & MAP_AUTOSZ)	? "AUTOSZ "	: "",
+		(map->flags & MAP_0WS)		? "0WS "	: "",
+		(map->flags & MAP_WRPROT)	? "WRPROT "	: "",
+		(map->flags & MAP_ATTRIB)	? "ATTRIB "	: "",
+		(map->flags & MAP_USE_WAIT)	? "USE_WAIT "	: "");
+
+	if (map->map >= MAX_WIN)
+		return -EINVAL;
+
+	if (map->flags & MAP_ACTIVE) {
+		if (speed == 0)
+			speed = 300;
+	} else {
+		speed = 0;
+	}
+
+	if (map->flags & MAP_ATTRIB) {
+		res = &skt->res_attr;
+		skt->spd_attr[map->map] = speed;
+		skt->spd_mem[map->map] = 0;
+	} else {
+		res = &skt->res_mem;
+		skt->spd_attr[map->map] = 0;
+		skt->spd_mem[map->map] = speed;
+	}
+
+	skt->ops->set_timing(skt);
+
+	map->static_start = res->start + map->card_start;
+
+	return 0;
+}
+
+struct bittbl {
+	unsigned int mask;
+	const char *name;
+};
+
+static struct bittbl status_bits[] = {
+	{ SS_WRPROT,		"SS_WRPROT"	},
+	{ SS_BATDEAD,		"SS_BATDEAD"	},
+	{ SS_BATWARN,		"SS_BATWARN"	},
+	{ SS_READY,		"SS_READY"	},
+	{ SS_DETECT,		"SS_DETECT"	},
+	{ SS_POWERON,		"SS_POWERON"	},
+	{ SS_STSCHG,		"SS_STSCHG"	},
+	{ SS_3VCARD,		"SS_3VCARD"	},
+	{ SS_XVCARD,		"SS_XVCARD"	},
+};
+
+static struct bittbl conf_bits[] = {
+	{ SS_PWR_AUTO,		"SS_PWR_AUTO"	},
+	{ SS_IOCARD,		"SS_IOCARD"	},
+	{ SS_RESET,		"SS_RESET"	},
+	{ SS_DMA_MODE,		"SS_DMA_MODE"	},
+	{ SS_SPKR_ENA,		"SS_SPKR_ENA"	},
+	{ SS_OUTPUT_ENA,	"SS_OUTPUT_ENA"	},
+};
+
+static void dump_bits(char **p, const char *prefix,
+	unsigned int val, struct bittbl *bits, int sz)
+{
+	char *b = *p;
+	int i;
+
+	b += sprintf(b, "%-9s:", prefix);
+	for (i = 0; i < sz; i++)
+		if (val & bits[i].mask)
+			b += sprintf(b, " %s", bits[i].name);
+	*b++ = '\n';
+	*p = b;
+}
+
+/*
+ * Implements the /sys/class/pcmcia_socket/??/status file.
+ *
+ * Returns: the number of characters added to the buffer
+ */
+static ssize_t show_status(
+	struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct soc_pcmcia_socket *skt =
+		container_of(dev, struct soc_pcmcia_socket, socket.dev);
+	char *p = buf;
+
+	p += sprintf(p, "slot     : %d\n", skt->nr);
+
+	dump_bits(&p, "status", skt->status,
+		  status_bits, ARRAY_SIZE(status_bits));
+	dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
+		  status_bits, ARRAY_SIZE(status_bits));
+	dump_bits(&p, "cs_flags", skt->cs_state.flags,
+		  conf_bits, ARRAY_SIZE(conf_bits));
+
+	p += sprintf(p, "Vcc      : %d\n", skt->cs_state.Vcc);
+	p += sprintf(p, "Vpp      : %d\n", skt->cs_state.Vpp);
+	p += sprintf(p, "IRQ      : %d (%d)\n", skt->cs_state.io_irq,
+		skt->socket.pci_irq);
+	if (skt->ops->show_timing)
+		p += skt->ops->show_timing(skt, p);
+
+	return p-buf;
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+
+static struct pccard_operations soc_common_pcmcia_operations = {
+	.init			= soc_common_pcmcia_sock_init,
+	.suspend		= soc_common_pcmcia_suspend,
+	.get_status		= soc_common_pcmcia_get_status,
+	.set_socket		= soc_common_pcmcia_set_socket,
+	.set_io_map		= soc_common_pcmcia_set_io_map,
+	.set_mem_map		= soc_common_pcmcia_set_mem_map,
+};
+
+
+#ifdef CONFIG_CPU_FREQ
+static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb,
+	unsigned long val, void *data)
+{
+	struct soc_pcmcia_socket *skt = container_of(nb, struct soc_pcmcia_socket, cpufreq_nb);
+	struct cpufreq_freqs *freqs = data;
+
+	return skt->ops->frequency_change(skt, val, freqs);
+}
+#endif
+
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+	const struct pcmcia_low_level *ops, struct device *dev)
+{
+	int i;
+
+	skt->ops = ops;
+	skt->socket.owner = ops->owner;
+	skt->socket.dev.parent = dev;
+	skt->socket.pci_irq = NO_IRQ;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		skt->stat[i].gpio = -EINVAL;
+}
+EXPORT_SYMBOL(soc_pcmcia_init_one);
+
+void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
+{
+	del_timer_sync(&skt->poll_timer);
+
+	pcmcia_unregister_socket(&skt->socket);
+
+#ifdef CONFIG_CPU_FREQ
+	if (skt->ops->frequency_change)
+		cpufreq_unregister_notifier(&skt->cpufreq_nb,
+					    CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+	soc_pcmcia_hw_shutdown(skt);
+
+	/* should not be required; violates some lowlevel drivers */
+	soc_common_pcmcia_config_skt(skt, &dead_socket);
+
+	iounmap(skt->virt_io);
+	skt->virt_io = NULL;
+	release_resource(&skt->res_attr);
+	release_resource(&skt->res_mem);
+	release_resource(&skt->res_io);
+	release_resource(&skt->res_skt);
+}
+EXPORT_SYMBOL(soc_pcmcia_remove_one);
+
+int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
+{
+	int ret;
+
+	skt->cs_state = dead_socket;
+
+	setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
+		    (unsigned long)skt);
+	skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
+
+	ret = request_resource(&iomem_resource, &skt->res_skt);
+	if (ret)
+		goto out_err_1;
+
+	ret = request_resource(&skt->res_skt, &skt->res_io);
+	if (ret)
+		goto out_err_2;
+
+	ret = request_resource(&skt->res_skt, &skt->res_mem);
+	if (ret)
+		goto out_err_3;
+
+	ret = request_resource(&skt->res_skt, &skt->res_attr);
+	if (ret)
+		goto out_err_4;
+
+	skt->virt_io = ioremap(skt->res_io.start, 0x10000);
+	if (skt->virt_io == NULL) {
+		ret = -ENOMEM;
+		goto out_err_5;
+	}
+
+	/*
+	 * We initialize default socket timing here, because
+	 * we are not guaranteed to see a SetIOMap operation at
+	 * runtime.
+	 */
+	skt->ops->set_timing(skt);
+
+	ret = soc_pcmcia_hw_init(skt);
+	if (ret)
+		goto out_err_6;
+
+	skt->socket.ops = &soc_common_pcmcia_operations;
+	skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
+	skt->socket.resource_ops = &pccard_static_ops;
+	skt->socket.irq_mask = 0;
+	skt->socket.map_size = PAGE_SIZE;
+	skt->socket.io_offset = (unsigned long)skt->virt_io;
+
+	skt->status = soc_common_pcmcia_skt_state(skt);
+
+#ifdef CONFIG_CPU_FREQ
+	if (skt->ops->frequency_change) {
+		skt->cpufreq_nb.notifier_call = soc_common_pcmcia_cpufreq_nb;
+
+		ret = cpufreq_register_notifier(&skt->cpufreq_nb,
+						CPUFREQ_TRANSITION_NOTIFIER);
+		if (ret < 0)
+			dev_err(skt->socket.dev.parent,
+				"unable to register CPU frequency change notifier for PCMCIA (%d)\n",
+				ret);
+	}
+#endif
+
+	ret = pcmcia_register_socket(&skt->socket);
+	if (ret)
+		goto out_err_7;
+
+	ret = device_create_file(&skt->socket.dev, &dev_attr_status);
+	if (ret)
+		goto out_err_8;
+
+	return ret;
+
+ out_err_8:
+	del_timer_sync(&skt->poll_timer);
+	pcmcia_unregister_socket(&skt->socket);
+
+ out_err_7:
+	soc_pcmcia_hw_shutdown(skt);
+ out_err_6:
+	iounmap(skt->virt_io);
+ out_err_5:
+	release_resource(&skt->res_attr);
+ out_err_4:
+	release_resource(&skt->res_mem);
+ out_err_3:
+	release_resource(&skt->res_io);
+ out_err_2:
+	release_resource(&skt->res_skt);
+ out_err_1:
+
+	return ret;
+}
+EXPORT_SYMBOL(soc_pcmcia_add_one);
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
+MODULE_LICENSE("Dual MPL/GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.h b/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.h
new file mode 100644
index 0000000..b7f993f
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/soc_common.h
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * linux/drivers/pcmcia/soc_common.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the PCMCIA support code common to
+ * integrated SOCs like the SA-11x0 and PXA2xx microprocessors.
+ */
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+/* include the world */
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+
+struct device;
+struct gpio_desc;
+struct pcmcia_low_level;
+struct regulator;
+
+struct soc_pcmcia_regulator {
+	struct regulator	*reg;
+	bool			on;
+};
+
+/*
+ * This structure encapsulates per-socket state which we might need to
+ * use when responding to a Card Services query of some kind.
+ */
+struct soc_pcmcia_socket {
+	struct pcmcia_socket	socket;
+
+	/*
+	 * Info from low level handler
+	 */
+	unsigned int		nr;
+	struct clk		*clk;
+
+	/*
+	 * Core PCMCIA state
+	 */
+	const struct pcmcia_low_level *ops;
+
+	unsigned int		status;
+	socket_state_t		cs_state;
+
+	unsigned short		spd_io[MAX_IO_WIN];
+	unsigned short		spd_mem[MAX_WIN];
+	unsigned short		spd_attr[MAX_WIN];
+
+	struct resource		res_skt;
+	struct resource		res_io;
+	struct resource		res_mem;
+	struct resource		res_attr;
+	void __iomem		*virt_io;
+
+	struct {
+		int		gpio;
+		struct gpio_desc *desc;
+		unsigned int	irq;
+		const char	*name;
+	} stat[6];
+#define SOC_STAT_CD		0	/* Card detect */
+#define SOC_STAT_BVD1		1	/* BATDEAD / IOSTSCHG */
+#define SOC_STAT_BVD2		2	/* BATWARN / IOSPKR */
+#define SOC_STAT_RDY		3	/* Ready / Interrupt */
+#define SOC_STAT_VS1		4	/* Voltage sense 1 */
+#define SOC_STAT_VS2		5	/* Voltage sense 2 */
+
+	struct gpio_desc	*gpio_reset;
+	struct gpio_desc	*gpio_bus_enable;
+	struct soc_pcmcia_regulator vcc;
+	struct soc_pcmcia_regulator vpp;
+
+	unsigned int		irq_state;
+
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	cpufreq_nb;
+#endif
+	struct timer_list	poll_timer;
+	struct list_head	node;
+	void *driver_data;
+};
+
+struct skt_dev_info {
+	int nskt;
+	struct soc_pcmcia_socket skt[0];
+};
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+             bvd1: 1,
+             bvd2: 1,
+           wrprot: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+struct pcmcia_low_level {
+	struct module *owner;
+
+	/* first socket in system */
+	int first;
+	/* nr of sockets */
+	int nr;
+
+	int (*hw_init)(struct soc_pcmcia_socket *);
+	void (*hw_shutdown)(struct soc_pcmcia_socket *);
+
+	void (*socket_state)(struct soc_pcmcia_socket *, struct pcmcia_state *);
+	int (*configure_socket)(struct soc_pcmcia_socket *, const socket_state_t *);
+
+	/*
+	 * Enable card status IRQs on (re-)initialisation.  This can
+	 * be called at initialisation, power management event, or
+	 * pcmcia event.
+	 */
+	void (*socket_init)(struct soc_pcmcia_socket *);
+
+	/*
+	 * Disable card status IRQs and PCMCIA bus on suspend.
+	 */
+	void (*socket_suspend)(struct soc_pcmcia_socket *);
+
+	/*
+	 * Hardware specific timing routines.
+	 * If provided, the get_timing routine overrides the SOC default.
+	 */
+	unsigned int (*get_timing)(struct soc_pcmcia_socket *, unsigned int, unsigned int);
+	int (*set_timing)(struct soc_pcmcia_socket *);
+	int (*show_timing)(struct soc_pcmcia_socket *, char *);
+
+#ifdef CONFIG_CPU_FREQ
+	/*
+	 * CPUFREQ support.
+	 */
+	int (*frequency_change)(struct soc_pcmcia_socket *, unsigned long, struct cpufreq_freqs *);
+#endif
+};
+
+
+struct soc_pcmcia_timing {
+	unsigned short io;
+	unsigned short mem;
+	unsigned short attr;
+};
+
+extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
+
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+	const struct pcmcia_low_level *ops, struct device *dev);
+void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
+int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt);
+
+void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
+	struct pcmcia_state *state);
+
+int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
+	struct soc_pcmcia_regulator *r, int v);
+
+#ifdef CONFIG_PCMCIA_DEBUG
+
+extern void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
+			     int lvl, const char *fmt, ...);
+
+#define debug(skt, lvl, fmt, arg...) \
+	soc_pcmcia_debug(skt, __func__, lvl, fmt , ## arg)
+
+#else
+#define debug(skt, lvl, fmt, arg...) do { } while (0)
+#endif
+
+
+/*
+ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD
+ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has
+ * a minimum value of 165ns, as well. Section 4.7.2 (describing
+ * common and attribute memory write timing) says that twWE has a
+ * minimum value of 150ns for a 250ns cycle time (for 5V operation;
+ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V
+ * operation, also section 4.7.4). Section 4.7.3 says that taOE
+ * has a maximum value of 150ns for a 300ns cycle time (for 5V
+ * operation), or 300ns for a 600ns cycle time (for 3.3V operation).
+ *
+ * When configuring memory maps, Card Services appears to adopt the policy
+ * that a memory access time of "0" means "use the default." The default
+ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute
+ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and
+ * memory command width time is 300ns.
+ */
+#define SOC_PCMCIA_IO_ACCESS		(165)
+#define SOC_PCMCIA_5V_MEM_ACCESS	(150)
+#define SOC_PCMCIA_3V_MEM_ACCESS	(300)
+#define SOC_PCMCIA_ATTR_MEM_ACCESS	(300)
+
+/*
+ * The socket driver actually works nicely in interrupt-driven form,
+ * so the (relatively infrequent) polling is "just to be sure."
+ */
+#define SOC_PCMCIA_POLL_PERIOD    (2*HZ)
+
+
+/* I/O pins replacing memory pins
+ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
+ *
+ * These signals change meaning when going from memory-only to
+ * memory-or-I/O interface:
+ */
+#define iostschg bvd1
+#define iospkr   bvd2
+
+#endif
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/socket_sysfs.c b/src/kernel/linux/v4.14/drivers/pcmcia/socket_sysfs.c
new file mode 100644
index 0000000..d688151
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/socket_sysfs.c
@@ -0,0 +1,231 @@
+/*
+ * socket_sysfs.c -- most of socket-related sysfs output
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * (C) 2003 - 2004		Dominik Brodowski
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <asm/irq.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include "cs_internal.h"
+
+#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
+
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+	if (s->state & SOCKET_CARDBUS)
+		return sprintf(buf, "32-bit\n");
+	return sprintf(buf, "16-bit\n");
+}
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+				   char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+	if (s->socket.Vcc)
+		return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10,
+			       s->socket.Vcc % 10);
+	return sprintf(buf, "X.XV\n");
+}
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+			       char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+	return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
+}
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+			       char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	if (!(s->state & SOCKET_PRESENT))
+		return -ENODEV;
+	return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
+}
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+
+
+static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
+
+	return count;
+}
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+
+
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
+}
+
+static ssize_t pccard_store_card_pm_state(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	ssize_t ret = count;
+
+	if (!count)
+		return -EINVAL;
+
+	if (!strncmp(buf, "off", 3))
+		pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
+	else {
+		if (!strncmp(buf, "on", 2))
+			pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
+		else
+			ret = -EINVAL;
+	}
+
+	return ret;
+}
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+
+static ssize_t pccard_store_eject(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
+
+	return count;
+}
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+
+
+static ssize_t pccard_show_irq_mask(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	return sprintf(buf, "0x%04x\n", s->irq_mask);
+}
+
+static ssize_t pccard_store_irq_mask(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	ssize_t ret;
+	struct pcmcia_socket *s = to_socket(dev);
+	u32 mask;
+
+	if (!count)
+		return -EINVAL;
+
+	ret = sscanf(buf, "0x%x\n", &mask);
+
+	if (ret == 1) {
+		mutex_lock(&s->ops_mutex);
+		s->irq_mask &= mask;
+		mutex_unlock(&s->ops_mutex);
+		ret = 0;
+	}
+
+	return ret ? ret : count;
+}
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+
+
+static ssize_t pccard_show_resource(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
+}
+
+static ssize_t pccard_store_resource(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	mutex_lock(&s->ops_mutex);
+	if (!s->resource_setup_done)
+		s->resource_setup_done = 1;
+	mutex_unlock(&s->ops_mutex);
+
+	pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+
+	return count;
+}
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+static struct attribute *pccard_socket_attributes[] = {
+	&dev_attr_card_type.attr,
+	&dev_attr_card_voltage.attr,
+	&dev_attr_card_vpp.attr,
+	&dev_attr_card_vcc.attr,
+	&dev_attr_card_insert.attr,
+	&dev_attr_card_pm_state.attr,
+	&dev_attr_card_eject.attr,
+	&dev_attr_card_irq_mask.attr,
+	&dev_attr_available_resources_setup_done.attr,
+	NULL,
+};
+
+static const struct attribute_group socket_attrs = {
+	.attrs = pccard_socket_attributes,
+};
+
+int pccard_sysfs_add_socket(struct device *dev)
+{
+	return sysfs_create_group(&dev->kobj, &socket_attrs);
+}
+
+void pccard_sysfs_remove_socket(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &socket_attrs);
+}
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/tcic.c b/src/kernel/linux/v4.14/drivers/pcmcia/tcic.c
new file mode 100644
index 0000000..a1ac72d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/tcic.c
@@ -0,0 +1,807 @@
+/*======================================================================
+
+    Device driver for Databook TCIC-2 PCMCIA controller
+
+    tcic.c 1.111 2000/02/15 04:13:12
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+#include "tcic.h"
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The base port address of the TCIC-2 chip */
+static unsigned long tcic_base = TCIC_BASE;
+
+/* Specify a socket number to ignore */
+static int ignore = -1;
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16];
+static unsigned int irq_list_count;
+
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq;
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval;
+
+/* Delay for card status double-checking */
+static int poll_quick = HZ/20;
+
+/* CCLK external clock time, in nanoseconds.  70 ns = 14.31818 MHz */
+static int cycle_time = 70;
+
+module_param_hw(tcic_base, ulong, ioport, 0444);
+module_param(ignore, int, 0444);
+module_param(do_scan, int, 0444);
+module_param_hw(irq_mask, int, other, 0444);
+module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
+module_param_hw(cs_irq, int, irq, 0444);
+module_param(poll_interval, int, 0444);
+module_param(poll_quick, int, 0444);
+module_param(cycle_time, int, 0444);
+
+/*====================================================================*/
+
+static irqreturn_t tcic_interrupt(int irq, void *dev);
+static void tcic_timer(u_long data);
+static struct pccard_operations tcic_operations;
+
+struct tcic_socket {
+    u_short	psock;
+    u_char	last_sstat;
+    u_char	id;
+    struct pcmcia_socket	socket;
+};
+
+static struct timer_list poll_timer;
+static int tcic_timer_pending;
+
+static int sockets;
+static struct tcic_socket socket_table[2];
+
+/*====================================================================*/
+
+/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
+   to map to irq 11, but is coded as 0 or 1 in the irq registers. */
+#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
+
+#ifdef DEBUG_X
+static u_char tcic_getb(u_char reg)
+{
+    u_char val = inb(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getb(%#lx) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static u_short tcic_getw(u_char reg)
+{
+    u_short val = inw(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getw(%#lx) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static void tcic_setb(u_char reg, u_char data)
+{
+    printk(KERN_DEBUG "tcic_setb(%#lx, %#x)\n", tcic_base+reg, data);
+    outb(data, tcic_base+reg);
+}
+
+static void tcic_setw(u_char reg, u_short data)
+{
+    printk(KERN_DEBUG "tcic_setw(%#lx, %#x)\n", tcic_base+reg, data);
+    outw(data, tcic_base+reg);
+}
+#else
+#define tcic_getb(reg) inb(tcic_base+reg)
+#define tcic_getw(reg) inw(tcic_base+reg)
+#define tcic_setb(reg, data) outb(data, tcic_base+reg)
+#define tcic_setw(reg, data) outw(data, tcic_base+reg)
+#endif
+
+static void tcic_setl(u_char reg, u_int data)
+{
+#ifdef DEBUG_X
+    printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
+#endif
+    outw(data & 0xffff, tcic_base+reg);
+    outw(data >> 16, tcic_base+reg+2);
+}
+
+static void tcic_aux_setb(u_short reg, u_char data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setb(TCIC_AUX, data);
+}
+
+static u_short tcic_aux_getw(u_short reg)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    return tcic_getw(TCIC_AUX);
+}
+
+static void tcic_aux_setw(u_short reg, u_short data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setw(TCIC_AUX, data);
+}
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    if (ns < 14)
+	return 0;
+    else
+	return 2*(ns-14)/cycle_time;
+}
+
+/*====================================================================*/
+
+static volatile u_int irq_hits;
+
+static irqreturn_t __init tcic_irq_count(int irq, void *dev)
+{
+    irq_hits++;
+    return IRQ_HANDLED;
+}
+
+static u_int __init try_irq(int irq)
+{
+    u_short cfg;
+
+    irq_hits = 0;
+    if (request_irq(irq, tcic_irq_count, 0, "irq scan", tcic_irq_count) != 0)
+	return -1;
+    mdelay(10);
+    if (irq_hits) {
+	free_irq(irq, tcic_irq_count);
+	return -1;
+    }
+
+    /* Generate one interrupt */
+    cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
+    tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
+    tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
+
+    udelay(1000);
+    free_irq(irq, tcic_irq_count);
+
+    /* Turn off interrupts */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
+    while (tcic_getb(TCIC_ICSR))
+	tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
+    
+    return (irq_hits != 1);
+}
+
+static u_int __init irq_scan(u_int mask0)
+{
+    u_int mask1;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
+    if (level_mask)
+	mask0 &= ~level_mask;
+#endif
+
+    mask1 = 0;
+    if (do_scan) {
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (try_irq(i) == 0))
+		mask1 |= (1 << i);
+	for (i = 0; i < 16; i++)
+	    if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
+		mask1 ^= (1 << i);
+	    }
+    }
+    
+    if (mask1) {
+	printk("scanned");
+    } else {
+	/* Fallback: just find interrupts that aren't in use */
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) &&
+		(request_irq(i, tcic_irq_count, 0, "x", tcic_irq_count) == 0)) {
+		mask1 |= (1 << i);
+		free_irq(i, tcic_irq_count);
+	    }
+	printk("default");
+    }
+    
+    printk(") = ");
+    for (i = 0; i < 16; i++)
+	if (mask1 & (1<<i))
+	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    printk(" ");
+    
+    return mask1;
+}
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non-PCMCIA) Linux driver.
+
+    We make an exception for cards that look like serial devices.
+    
+======================================================================*/
+
+static int __init is_active(int s)
+{
+    u_short scf1, ioctl, base, num;
+    u_char pwr, sstat;
+    u_int addr;
+    
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(s));
+    scf1 = tcic_getw(TCIC_DATA);
+    pwr = tcic_getb(TCIC_PWR);
+    sstat = tcic_getb(TCIC_SSTAT);
+    addr = TCIC_IWIN(s, 0);
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    ioctl = tcic_getw(TCIC_DATA);
+
+    if (ioctl & TCIC_ICTL_TINY)
+	num = 1;
+    else {
+	num = (base ^ (base-1));
+	base = base & (base-1);
+    }
+
+    if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
+	(scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
+	((base & 0xfeef) != 0x02e8)) {
+	struct resource *res = request_region(base, num, "tcic-2");
+	if (!res) /* region is busy */
+	    return 1;
+	release_region(base, num);
+    }
+
+    return 0;
+}
+
+/*======================================================================
+
+    This returns the revision code for the specified socket.
+    
+======================================================================*/
+
+static int __init get_tcic_id(void)
+{
+    u_short id;
+    
+    tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
+    id = tcic_aux_getw(TCIC_AUX_ILOCK);
+    id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+    tcic_aux_setw(TCIC_AUX_TEST, 0);
+    return id;
+}
+
+/*====================================================================*/
+
+static struct platform_driver tcic_driver = {
+	.driver = {
+		.name = "tcic-pcmcia",
+	},
+};
+
+static struct platform_device tcic_device = {
+	.name = "tcic-pcmcia",
+	.id = 0,
+};
+
+
+static int __init init_tcic(void)
+{
+    int i, sock, ret = 0;
+    u_int mask, scan;
+
+    if (platform_driver_register(&tcic_driver))
+	return -1;
+    
+    printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
+    sock = 0;
+
+    if (!request_region(tcic_base, 16, "tcic-2")) {
+	printk("could not allocate ports,\n ");
+	platform_driver_unregister(&tcic_driver);
+	return -ENODEV;
+    }
+    else {
+	tcic_setw(TCIC_ADDR, 0);
+	if (tcic_getw(TCIC_ADDR) == 0) {
+	    tcic_setw(TCIC_ADDR, 0xc3a5);
+	    if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+	}
+	if (sock == 0) {
+	    /* See if resetting the controller does any good */
+	    tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
+	    tcic_setb(TCIC_SCTRL, 0);
+	    tcic_setw(TCIC_ADDR, 0);
+	    if (tcic_getw(TCIC_ADDR) == 0) {
+		tcic_setw(TCIC_ADDR, 0xc3a5);
+		if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+	    }
+	}
+    }
+    if (sock == 0) {
+	printk("not found.\n");
+	release_region(tcic_base, 16);
+	platform_driver_unregister(&tcic_driver);
+	return -ENODEV;
+    }
+
+    sockets = 0;
+    for (i = 0; i < sock; i++) {
+	if ((i == ignore) || is_active(i)) continue;
+	socket_table[sockets].psock = i;
+	socket_table[sockets].id = get_tcic_id();
+
+	socket_table[sockets].socket.owner = THIS_MODULE;
+	/* only 16-bit cards, memory windows must be size-aligned */
+	/* No PCI or CardBus support */
+	socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN;
+	/* irq 14, 11, 10, 7, 6, 5, 4, 3 */
+	socket_table[sockets].socket.irq_mask = 0x4cf8;
+	/* 4K minimum window size */
+	socket_table[sockets].socket.map_size = 0x1000;		
+	sockets++;
+    }
+
+    switch (socket_table[0].id) {
+    case TCIC_ID_DB86082:
+	printk("DB86082"); break;
+    case TCIC_ID_DB86082A:
+	printk("DB86082A"); break;
+    case TCIC_ID_DB86084:
+	printk("DB86084"); break;
+    case TCIC_ID_DB86084A:
+	printk("DB86084A"); break;
+    case TCIC_ID_DB86072:
+	printk("DB86072"); break;
+    case TCIC_ID_DB86184:
+	printk("DB86184"); break;
+    case TCIC_ID_DB86082B:
+	printk("DB86082B"); break;
+    default:
+	printk("Unknown ID 0x%02x", socket_table[0].id);
+    }
+    
+    /* Set up polling */
+    poll_timer.function = &tcic_timer;
+    poll_timer.data = 0;
+    init_timer(&poll_timer);
+
+    /* Build interrupt mask */
+    printk(KERN_CONT ", %d sockets\n", sockets);
+    printk(KERN_INFO "  irq list (");
+    if (irq_list_count == 0)
+	mask = irq_mask;
+    else
+	for (i = mask = 0; i < irq_list_count; i++)
+	    mask |= (1<<irq_list[i]);
+
+    /* irq 14, 11, 10, 7, 6, 5, 4, 3 */
+    mask &= 0x4cf8;
+    /* Scan interrupts */
+    mask = irq_scan(mask);
+    for (i=0;i<sockets;i++)
+	    socket_table[i].socket.irq_mask = mask;
+    
+    /* Check for only two interrupts available */
+    scan = (mask & (mask-1));
+    if (((scan & (scan-1)) == 0) && (poll_interval == 0))
+	poll_interval = HZ;
+    
+    if (poll_interval == 0) {
+	/* Avoid irq 12 unless it is explicitly requested */
+	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+	for (i = 15; i > 0; i--)
+	    if ((cs_mask & (1 << i)) &&
+		(request_irq(i, tcic_interrupt, 0, "tcic",
+			     tcic_interrupt) == 0))
+		break;
+	cs_irq = i;
+	if (cs_irq == 0) poll_interval = HZ;
+    }
+    
+    if (socket_table[0].socket.irq_mask & (1 << 11))
+	printk("sktirq is irq 11, ");
+    if (cs_irq != 0)
+	printk("status change on irq %d\n", cs_irq);
+    else
+	printk("polled status, interval = %d ms\n",
+	       poll_interval * 1000 / HZ);
+    
+    for (i = 0; i < sockets; i++) {
+	tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
+	socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
+    }
+    
+    /* jump start interrupt handler, if needed */
+    tcic_interrupt(0, NULL);
+
+    platform_device_register(&tcic_device);
+
+    for (i = 0; i < sockets; i++) {
+	    socket_table[i].socket.ops = &tcic_operations;
+	    socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
+	    socket_table[i].socket.dev.parent = &tcic_device.dev;
+	    ret = pcmcia_register_socket(&socket_table[i].socket);
+	    if (ret && i)
+		    pcmcia_unregister_socket(&socket_table[0].socket);
+    }
+    
+    return ret;
+
+    return 0;
+    
+} /* init_tcic */
+
+/*====================================================================*/
+
+static void __exit exit_tcic(void)
+{
+    int i;
+
+    del_timer_sync(&poll_timer);
+    if (cs_irq != 0) {
+	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
+	free_irq(cs_irq, tcic_interrupt);
+    }
+    release_region(tcic_base, 16);
+
+    for (i = 0; i < sockets; i++) {
+	    pcmcia_unregister_socket(&socket_table[i].socket);	    
+    }
+
+    platform_device_unregister(&tcic_device);
+    platform_driver_unregister(&tcic_driver);
+} /* exit_tcic */
+
+/*====================================================================*/
+
+static irqreturn_t tcic_interrupt(int irq, void *dev)
+{
+    int i, quick = 0;
+    u_char latch, sstat;
+    u_short psock;
+    u_int events;
+    static volatile int active = 0;
+
+    if (active) {
+	printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
+	return IRQ_NONE;
+    } else
+	active = 1;
+
+    pr_debug("tcic_interrupt()\n");
+    
+    for (i = 0; i < sockets; i++) {
+	psock = socket_table[i].psock;
+	tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+		  | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+	sstat = tcic_getb(TCIC_SSTAT);
+	latch = sstat ^ socket_table[psock].last_sstat;
+	socket_table[i].last_sstat = sstat;
+	if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
+	    tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
+	    quick = 1;
+	}
+	if (latch == 0)
+	    continue;
+	events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+	events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+	if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+	} else {
+	    events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
+	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+	    events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+	}
+	if (events) {
+		pcmcia_parse_events(&socket_table[i].socket, events);
+	}
+    }
+
+    /* Schedule next poll, if needed */
+    if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
+	poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
+	add_timer(&poll_timer);
+	tcic_timer_pending = 1;
+    }
+    active = 0;
+    
+    pr_debug("interrupt done\n");
+    return IRQ_HANDLED;
+} /* tcic_interrupt */
+
+static void tcic_timer(u_long data)
+{
+    pr_debug("tcic_timer()\n");
+    tcic_timer_pending = 0;
+    tcic_interrupt(0, NULL);
+} /* tcic_timer */
+
+/*====================================================================*/
+
+static int tcic_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
+    u_char reg;
+
+    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+    reg = tcic_getb(TCIC_SSTAT);
+    *value  = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+    *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+    if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+    } else {
+	*value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
+	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+	*value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+    }
+    reg = tcic_getb(TCIC_PWR);
+    if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
+	*value |= SS_POWERON;
+    dev_dbg(&sock->dev, "GetStatus(%d) = %#2.2x\n", psock, *value);
+    return 0;
+} /* tcic_get_status */
+
+/*====================================================================*/
+
+static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
+    u_char reg;
+    u_short scf1, scf2;
+
+    dev_dbg(&sock->dev, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
+
+    reg = tcic_getb(TCIC_PWR);
+    reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
+
+    if (state->Vcc == 50) {
+	switch (state->Vpp) {
+	case 0:   reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
+	case 50:  reg |= TCIC_PWR_VCC(psock); break;
+	case 120: reg |= TCIC_PWR_VPP(psock); break;
+	default:  return -EINVAL;
+	}
+    } else if (state->Vcc != 0)
+	return -EINVAL;
+
+    if (reg != tcic_getb(TCIC_PWR))
+	tcic_setb(TCIC_PWR, reg);
+
+    reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
+    if (state->flags & SS_OUTPUT_ENA) {
+	tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
+	reg |= TCIC_ILOCK_CRESENA;
+    } else
+	tcic_setb(TCIC_SCTRL, 0);
+    if (state->flags & SS_RESET)
+	reg |= TCIC_ILOCK_CRESET;
+    tcic_aux_setb(TCIC_AUX_ILOCK, reg);
+    
+    tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
+    scf1 = TCIC_SCF1_FINPACK;
+    scf1 |= TCIC_IRQ(state->io_irq);
+    if (state->flags & SS_IOCARD) {
+	scf1 |= TCIC_SCF1_IOSTS;
+	if (state->flags & SS_SPKR_ENA)
+	    scf1 |= TCIC_SCF1_SPKR;
+	if (state->flags & SS_DMA_MODE)
+	    scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
+    }
+    tcic_setw(TCIC_DATA, scf1);
+
+    /* Some general setup stuff, and configure status interrupt */
+    reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
+    tcic_aux_setb(TCIC_AUX_WCTL, reg);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
+		  TCIC_IRQ(cs_irq));
+    
+    /* Card status change interrupt mask */
+    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+    scf2 = TCIC_SCF2_MALL;
+    if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
+    if (state->flags & SS_IOCARD) {
+	if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
+    } else {
+	if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
+	if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
+	if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
+    }
+    tcic_setw(TCIC_DATA, scf2);
+    /* For the ISA bus, the irq should be active-high totem-pole */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
+
+    return 0;
+} /* tcic_set_socket */
+  
+/*====================================================================*/
+
+static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
+{
+    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
+    u_int addr;
+    u_short base, len, ioctl;
+    
+    dev_dbg(&sock->dev, "SetIOMap(%d, %d, %#2.2x, %d ns, "
+	  "%#llx-%#llx)\n", psock, io->map, io->flags, io->speed,
+	  (unsigned long long)io->start, (unsigned long long)io->stop);
+    if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+	(io->stop < io->start)) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_IWIN(psock, io->map);
+
+    base = io->start; len = io->stop - io->start;
+    /* Check to see that len+1 is power of two, etc */
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    base |= (len+1)>>1;
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    ioctl  = (psock << TCIC_ICTL_SS_SHFT);
+    ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
+    ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
+    ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
+    if (!(io->flags & MAP_AUTOSZ)) {
+	ioctl |= TCIC_ICTL_QUIET;
+	ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
+    }
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    tcic_setw(TCIC_DATA, ioctl);
+    
+    return 0;
+} /* tcic_set_io_map */
+
+/*====================================================================*/
+
+static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+{
+    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
+    u_short addr, ctl;
+    u_long base, len, mmap;
+
+    dev_dbg(&sock->dev, "SetMemMap(%d, %d, %#2.2x, %d ns, "
+	  "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
+	  mem->speed, (unsigned long long)mem->res->start,
+	  (unsigned long long)mem->res->end, mem->card_start);
+    if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
+	(mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
+	(mem->res->start > mem->res->end) || (mem->speed > 1000))
+	return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_MWIN(psock, mem->map);
+
+    base = mem->res->start; len = mem->res->end - mem->res->start;
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    if (len == 0x0fff)
+	base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
+    else
+	base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    mmap = mem->card_start - mem->res->start;
+    mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
+    if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+    tcic_setw(TCIC_DATA, mmap);
+
+    ctl  = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
+    ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
+    ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
+    ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
+    ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+    tcic_setw(TCIC_DATA, ctl);
+    
+    return 0;
+} /* tcic_set_mem_map */
+
+/*====================================================================*/
+
+static int tcic_init(struct pcmcia_socket *s)
+{
+	int i;
+	struct resource res = { .start = 0, .end = 0x1000 };
+	pccard_io_map io = { 0, 0, 0, 0, 1 };
+	pccard_mem_map mem = { .res = &res, };
+
+	for (i = 0; i < 2; i++) {
+		io.map = i;
+		tcic_set_io_map(s, &io);
+	}
+	for (i = 0; i < 5; i++) {
+		mem.map = i;
+		tcic_set_mem_map(s, &mem);
+	}
+	return 0;
+}
+
+static struct pccard_operations tcic_operations = {
+	.init		   = tcic_init,
+	.get_status	   = tcic_get_status,
+	.set_socket	   = tcic_set_socket,
+	.set_io_map	   = tcic_set_io_map,
+	.set_mem_map	   = tcic_set_mem_map,
+};
+
+/*====================================================================*/
+
+module_init(init_tcic);
+module_exit(exit_tcic);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/tcic.h b/src/kernel/linux/v4.14/drivers/pcmcia/tcic.h
new file mode 100644
index 0000000..2c0b8f6
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/tcic.h
@@ -0,0 +1,266 @@
+/*
+ * tcic.h 1.13 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TCIC_H
+#define _LINUX_TCIC_H
+
+#define TCIC_BASE		0x240
+
+/* offsets of registers from TCIC_BASE */
+#define TCIC_DATA		0x00
+#define TCIC_ADDR		0x02
+#define TCIC_SCTRL		0x06
+#define TCIC_SSTAT		0x07
+#define TCIC_MODE		0x08
+#define TCIC_PWR		0x09
+#define TCIC_EDC		0x0A
+#define TCIC_ICSR		0x0C
+#define TCIC_IENA		0x0D
+#define TCIC_AUX		0x0E
+
+#define TCIC_SS_SHFT		12
+#define TCIC_SS_MASK		0x7000
+
+/* Flags for TCIC_ADDR */
+#define TCIC_ADR2_REG		0x8000
+#define TCIC_ADR2_INDREG	0x0800
+
+#define TCIC_ADDR_REG		0x80000000
+#define TCIC_ADDR_SS_SHFT	(TCIC_SS_SHFT+16)
+#define TCIC_ADDR_SS_MASK	(TCIC_SS_MASK<<16)
+#define TCIC_ADDR_INDREG	0x08000000
+#define TCIC_ADDR_IO		0x04000000
+#define TCIC_ADDR_MASK		0x03ffffff
+
+/* Flags for TCIC_SCTRL */
+#define TCIC_SCTRL_ENA		0x01
+#define TCIC_SCTRL_INCMODE	0x18
+#define TCIC_SCTRL_INCMODE_HOLD	0x00
+#define TCIC_SCTRL_INCMODE_WORD	0x08
+#define TCIC_SCTRL_INCMODE_REG	0x10
+#define TCIC_SCTRL_INCMODE_AUTO	0x18
+#define TCIC_SCTRL_EDCSUM	0x20
+#define TCIC_SCTRL_RESET	0x80
+
+/* Flags for TCIC_SSTAT */
+#define TCIC_SSTAT_6US		0x01
+#define TCIC_SSTAT_10US		0x02
+#define TCIC_SSTAT_PROGTIME	0x04
+#define TCIC_SSTAT_LBAT1	0x08
+#define TCIC_SSTAT_LBAT2	0x10
+#define TCIC_SSTAT_RDY		0x20	/* Inverted */
+#define TCIC_SSTAT_WP		0x40
+#define TCIC_SSTAT_CD		0x80	/* Card detect */
+
+/* Flags for TCIC_MODE */
+#define TCIC_MODE_PGMMASK	0x1f
+#define TCIC_MODE_NORMAL	0x00
+#define TCIC_MODE_PGMWR		0x01
+#define TCIC_MODE_PGMRD		0x02
+#define TCIC_MODE_PGMCE		0x04
+#define TCIC_MODE_PGMDBW	0x08
+#define TCIC_MODE_PGMWORD	0x10
+#define TCIC_MODE_AUXSEL_MASK	0xe0
+
+/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
+#define TCIC_AUX_TCTL		(0<<5)
+#define TCIC_AUX_PCTL		(1<<5)
+#define TCIC_AUX_WCTL		(2<<5)
+#define TCIC_AUX_EXTERN		(3<<5)
+#define TCIC_AUX_PDATA		(4<<5)
+#define TCIC_AUX_SYSCFG		(5<<5)
+#define TCIC_AUX_ILOCK		(6<<5)
+#define TCIC_AUX_TEST		(7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock)	(0x01<<(sock))
+#define TCIC_PWR_VCC_MASK	0x03
+#define TCIC_PWR_VPP(sock)	(0x08<<(sock))
+#define TCIC_PWR_VPP_MASK	0x18
+#define TCIC_PWR_CLIMENA	0x40
+#define TCIC_PWR_CLIMSTAT	0x80
+
+/* Flags for TCIC_ICSR */
+#define TCIC_ICSR_CLEAR		0x01
+#define TCIC_ICSR_SET		0x02
+#define TCIC_ICSR_JAM		(TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
+#define TCIC_ICSR_STOPCPU	0x04
+#define TCIC_ICSR_ILOCK		0x08
+#define TCIC_ICSR_PROGTIME	0x10
+#define TCIC_ICSR_ERR		0x20
+#define TCIC_ICSR_CDCHG		0x40
+#define TCIC_ICSR_IOCHK		0x80
+
+/* Flags for TCIC_IENA */
+#define TCIC_IENA_CFG_MASK	0x03
+#define TCIC_IENA_CFG_OFF	0x00	/* disabled */
+#define TCIC_IENA_CFG_OD	0x01	/* active low, open drain */
+#define TCIC_IENA_CFG_LOW	0x02	/* active low, totem pole */
+#define TCIC_IENA_CFG_HIGH	0x03	/* active high, totem pole */
+#define TCIC_IENA_ILOCK		0x08
+#define TCIC_IENA_PROGTIME	0x10
+#define TCIC_IENA_ERR		0x20	/* overcurrent or iochk */
+#define TCIC_IENA_CDCHG		0x40
+
+/* Flags for TCIC_AUX_WCTL */
+#define TCIC_WAIT_COUNT_MASK	0x001f
+#define TCIC_WAIT_ASYNC		0x0020
+#define TCIC_WAIT_SENSE		0x0040
+#define TCIC_WAIT_SRC		0x0080
+#define TCIC_WCTL_WR		0x0100
+#define TCIC_WCTL_RD		0x0200
+#define TCIC_WCTL_CE		0x0400
+#define TCIC_WCTL_LLBAT1	0x0800
+#define TCIC_WCTL_LLBAT2	0x1000
+#define TCIC_WCTL_LRDY		0x2000
+#define TCIC_WCTL_LWP		0x4000
+#define TCIC_WCTL_LCD		0x8000
+
+/* Flags for TCIC_AUX_SYSCFG */
+#define TCIC_SYSCFG_IRQ_MASK	0x000f
+#define TCIC_SYSCFG_MCSFULL	0x0010
+#define TCIC_SYSCFG_IO1723	0x0020
+#define TCIC_SYSCFG_MCSXB	0x0040
+#define TCIC_SYSCFG_ICSXB	0x0080
+#define TCIC_SYSCFG_NOPDN	0x0100
+#define TCIC_SYSCFG_MPSEL_SHFT	9
+#define TCIC_SYSCFG_MPSEL_MASK	0x0e00
+#define TCIC_SYSCFG_MPSENSE	0x2000
+#define TCIC_SYSCFG_AUTOBUSY	0x4000
+#define TCIC_SYSCFG_ACC		0x8000
+
+#define TCIC_ILOCK_OUT		0x01
+#define TCIC_ILOCK_SENSE	0x02
+#define TCIC_ILOCK_CRESET	0x04
+#define TCIC_ILOCK_CRESENA	0x08
+#define TCIC_ILOCK_CWAIT	0x10
+#define TCIC_ILOCK_CWAITSNS	0x20
+#define TCIC_ILOCK_HOLD_MASK	0xc0
+#define TCIC_ILOCK_HOLD_CCLK	0xc0
+
+#define TCIC_ILOCKTEST_ID_SH	8
+#define TCIC_ILOCKTEST_ID_MASK	0x7f00
+#define TCIC_ILOCKTEST_MCIC_1	0x8000
+
+#define TCIC_ID_DB86082		0x02
+#define TCIC_ID_DB86082A	0x03
+#define TCIC_ID_DB86084		0x04
+#define TCIC_ID_DB86084A	0x08
+#define TCIC_ID_DB86072		0x15
+#define TCIC_ID_DB86184		0x14
+#define TCIC_ID_DB86082B	0x17
+
+#define TCIC_TEST_DIAG		0x8000
+
+/*
+ * Indirectly addressed registers
+ */
+
+#define TCIC_SCF1(sock)	((sock)<<3)
+#define TCIC_SCF2(sock) (((sock)<<3)+2)
+
+/* Flags for SCF1 */
+#define TCIC_SCF1_IRQ_MASK	0x000f
+#define TCIC_SCF1_IRQ_OFF	0x0000
+#define TCIC_SCF1_IRQOC		0x0010
+#define TCIC_SCF1_PCVT		0x0020
+#define TCIC_SCF1_IRDY		0x0040
+#define TCIC_SCF1_ATA		0x0080
+#define TCIC_SCF1_DMA_SHIFT	8
+#define TCIC_SCF1_DMA_MASK	0x0700
+#define TCIC_SCF1_DMA_OFF	0
+#define TCIC_SCF1_DREQ2		2
+#define TCIC_SCF1_IOSTS		0x0800
+#define TCIC_SCF1_SPKR		0x1000
+#define TCIC_SCF1_FINPACK	0x2000
+#define TCIC_SCF1_DELWR		0x4000
+#define TCIC_SCF1_HD7IDE	0x8000
+
+/* Flags for SCF2 */
+#define TCIC_SCF2_RI		0x0001
+#define TCIC_SCF2_IDBR		0x0002
+#define TCIC_SCF2_MDBR		0x0004
+#define TCIC_SCF2_MLBAT1	0x0008
+#define TCIC_SCF2_MLBAT2	0x0010
+#define TCIC_SCF2_MRDY		0x0020
+#define TCIC_SCF2_MWP		0x0040
+#define TCIC_SCF2_MCD		0x0080
+#define TCIC_SCF2_MALL		0x00f8
+
+/* Indirect addresses for memory window registers */
+#define TCIC_MWIN(sock,map)	(0x100+(((map)+((sock)<<2))<<3))
+#define TCIC_MBASE_X		2
+#define TCIC_MMAP_X		4
+#define TCIC_MCTL_X		6
+
+#define TCIC_MBASE_4K_BIT	0x4000
+#define TCIC_MBASE_HA_SHFT	12
+#define TCIC_MBASE_HA_MASK	0x0fff
+
+#define TCIC_MMAP_REG		0x8000
+#define TCIC_MMAP_CA_SHFT	12
+#define TCIC_MMAP_CA_MASK	0x3fff
+
+#define TCIC_MCTL_WSCNT_MASK	0x001f
+#define TCIC_MCTL_WCLK		0x0020
+#define TCIC_MCTL_WCLK_CCLK	0x0000
+#define TCIC_MCTL_WCLK_BCLK	0x0020
+#define TCIC_MCTL_QUIET		0x0040
+#define TCIC_MCTL_WP		0x0080
+#define TCIC_MCTL_ACC		0x0100
+#define TCIC_MCTL_KE		0x0200
+#define TCIC_MCTL_EDC		0x0400
+#define TCIC_MCTL_B8		0x0800
+#define TCIC_MCTL_SS_SHFT	TCIC_SS_SHFT
+#define TCIC_MCTL_SS_MASK	TCIC_SS_MASK
+#define TCIC_MCTL_ENA		0x8000
+
+/* Indirect addresses for I/O window registers */
+#define TCIC_IWIN(sock,map)	(0x200+(((map)+((sock)<<1))<<2))
+#define TCIC_IBASE_X		0
+#define TCIC_ICTL_X		2
+
+#define TCIC_ICTL_WSCNT_MASK	TCIC_MCTL_WSCNT_MASK
+#define TCIC_ICTL_QUIET		TCIC_MCTL_QUIET
+#define TCIC_ICTL_1K		0x0080
+#define TCIC_ICTL_PASS16	0x0100
+#define TCIC_ICTL_ACC		TCIC_MCTL_ACC
+#define TCIC_ICTL_TINY		0x0200
+#define TCIC_ICTL_B16		0x0400
+#define TCIC_ICTL_B8		TCIC_MCTL_B8
+#define TCIC_ICTL_BW_MASK	(TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_BW_DYN	0
+#define TCIC_ICTL_BW_8		TCIC_ICTL_B8
+#define TCIC_ICTL_BW_16		TCIC_ICTL_B16
+#define TCIC_ICTL_BW_ATA	(TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_SS_SHFT	TCIC_SS_SHFT
+#define TCIC_ICTL_SS_MASK	TCIC_SS_MASK
+#define TCIC_ICTL_ENA		TCIC_MCTL_ENA
+
+#endif /* _LINUX_TCIC_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/ti113x.h b/src/kernel/linux/v4.14/drivers/pcmcia/ti113x.h
new file mode 100644
index 0000000..5cb670e
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/ti113x.h
@@ -0,0 +1,978 @@
+/*
+ * ti113x.h 1.16 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TI113X_H
+#define _LINUX_TI113X_H
+
+
+/* Register definitions for TI 113X PCI-to-CardBus bridges */
+
+/* System Control Register */
+#define TI113X_SYSTEM_CONTROL		0x0080	/* 32 bit */
+#define  TI113X_SCR_SMIROUTE		0x04000000
+#define  TI113X_SCR_SMISTATUS		0x02000000
+#define  TI113X_SCR_SMIENB		0x01000000
+#define  TI113X_SCR_VCCPROT		0x00200000
+#define  TI113X_SCR_REDUCEZV		0x00100000
+#define  TI113X_SCR_CDREQEN		0x00080000
+#define  TI113X_SCR_CDMACHAN		0x00070000
+#define  TI113X_SCR_SOCACTIVE		0x00002000
+#define  TI113X_SCR_PWRSTREAM		0x00000800
+#define  TI113X_SCR_DELAYUP		0x00000400
+#define  TI113X_SCR_DELAYDOWN		0x00000200
+#define  TI113X_SCR_INTERROGATE		0x00000100
+#define  TI113X_SCR_CLKRUN_SEL		0x00000080
+#define  TI113X_SCR_PWRSAVINGS		0x00000040
+#define  TI113X_SCR_SUBSYSRW		0x00000020
+#define  TI113X_SCR_CB_DPAR		0x00000010
+#define  TI113X_SCR_CDMA_EN		0x00000008
+#define  TI113X_SCR_ASYNC_IRQ		0x00000004
+#define  TI113X_SCR_KEEPCLK		0x00000002
+#define  TI113X_SCR_CLKRUN_ENA		0x00000001  
+
+#define  TI122X_SCR_SER_STEP		0xc0000000
+#define  TI122X_SCR_INTRTIE		0x20000000
+#define  TIXX21_SCR_TIEALL		0x10000000
+#define  TI122X_SCR_CBRSVD		0x00400000
+#define  TI122X_SCR_MRBURSTDN		0x00008000
+#define  TI122X_SCR_MRBURSTUP		0x00004000
+#define  TI122X_SCR_RIMUX		0x00000001
+
+/* Multimedia Control Register */
+#define TI1250_MULTIMEDIA_CTL		0x0084	/* 8 bit */
+#define  TI1250_MMC_ZVOUTEN		0x80
+#define  TI1250_MMC_PORTSEL		0x40
+#define  TI1250_MMC_ZVEN1		0x02
+#define  TI1250_MMC_ZVEN0		0x01
+
+#define TI1250_GENERAL_STATUS		0x0085	/* 8 bit */
+#define TI1250_GPIO0_CONTROL		0x0088	/* 8 bit */
+#define TI1250_GPIO1_CONTROL		0x0089	/* 8 bit */
+#define TI1250_GPIO2_CONTROL		0x008a	/* 8 bit */
+#define TI1250_GPIO3_CONTROL		0x008b	/* 8 bit */
+#define TI1250_GPIO_MODE_MASK		0xc0
+
+/* IRQMUX/MFUNC Register */
+#define TI122X_MFUNC			0x008c	/* 32 bit */
+#define TI122X_MFUNC0_MASK		0x0000000f
+#define TI122X_MFUNC1_MASK		0x000000f0
+#define TI122X_MFUNC2_MASK		0x00000f00
+#define TI122X_MFUNC3_MASK		0x0000f000
+#define TI122X_MFUNC4_MASK		0x000f0000
+#define TI122X_MFUNC5_MASK		0x00f00000
+#define TI122X_MFUNC6_MASK		0x0f000000
+
+#define TI122X_MFUNC0_INTA		0x00000002
+#define TI125X_MFUNC0_INTB		0x00000001
+#define TI122X_MFUNC1_INTB		0x00000020
+#define TI122X_MFUNC3_IRQSER		0x00001000
+
+
+/* Retry Status Register */
+#define TI113X_RETRY_STATUS		0x0090	/* 8 bit */
+#define  TI113X_RSR_PCIRETRY		0x80
+#define  TI113X_RSR_CBRETRY		0x40
+#define  TI113X_RSR_TEXP_CBB		0x20
+#define  TI113X_RSR_MEXP_CBB		0x10
+#define  TI113X_RSR_TEXP_CBA		0x08
+#define  TI113X_RSR_MEXP_CBA		0x04
+#define  TI113X_RSR_TEXP_PCI		0x02
+#define  TI113X_RSR_MEXP_PCI		0x01
+
+/* Card Control Register */
+#define TI113X_CARD_CONTROL		0x0091	/* 8 bit */
+#define  TI113X_CCR_RIENB		0x80
+#define  TI113X_CCR_ZVENABLE		0x40
+#define  TI113X_CCR_PCI_IRQ_ENA		0x20
+#define  TI113X_CCR_PCI_IREQ		0x10
+#define  TI113X_CCR_PCI_CSC		0x08
+#define  TI113X_CCR_SPKROUTEN		0x02
+#define  TI113X_CCR_IFG			0x01
+
+#define  TI1220_CCR_PORT_SEL		0x20
+#define  TI122X_CCR_AUD2MUX		0x04
+
+/* Device Control Register */
+#define TI113X_DEVICE_CONTROL		0x0092	/* 8 bit */
+#define  TI113X_DCR_5V_FORCE		0x40
+#define  TI113X_DCR_3V_FORCE		0x20
+#define  TI113X_DCR_IMODE_MASK		0x06
+#define  TI113X_DCR_IMODE_ISA		0x02
+#define  TI113X_DCR_IMODE_SERIAL	0x04
+
+#define  TI12XX_DCR_IMODE_PCI_ONLY	0x00
+#define  TI12XX_DCR_IMODE_ALL_SERIAL	0x06
+
+/* Buffer Control Register */
+#define TI113X_BUFFER_CONTROL		0x0093	/* 8 bit */
+#define  TI113X_BCR_CB_READ_DEPTH	0x08
+#define  TI113X_BCR_CB_WRITE_DEPTH	0x04
+#define  TI113X_BCR_PCI_READ_DEPTH	0x02
+#define  TI113X_BCR_PCI_WRITE_DEPTH	0x01
+
+/* Diagnostic Register */
+#define TI1250_DIAGNOSTIC		0x0093	/* 8 bit */
+#define  TI1250_DIAG_TRUE_VALUE		0x80
+#define  TI1250_DIAG_PCI_IREQ		0x40
+#define  TI1250_DIAG_PCI_CSC		0x20
+#define  TI1250_DIAG_ASYNC_CSC		0x01
+
+/* DMA Registers */
+#define TI113X_DMA_0			0x0094	/* 32 bit */
+#define TI113X_DMA_1			0x0098	/* 32 bit */
+
+/* ExCA IO offset registers */
+#define TI113X_IO_OFFSET(map)		(0x36+((map)<<1))
+
+/* EnE test register */
+#define ENE_TEST_C9			0xc9	/* 8bit */
+#define ENE_TEST_C9_TLTENABLE		0x02
+#define ENE_TEST_C9_PFENABLE_F0		0x04
+#define ENE_TEST_C9_PFENABLE_F1		0x08
+#define ENE_TEST_C9_PFENABLE		(ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F1)
+#define ENE_TEST_C9_WPDISALBLE_F0	0x40
+#define ENE_TEST_C9_WPDISALBLE_F1	0x80
+#define ENE_TEST_C9_WPDISALBLE		(ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1)
+
+/*
+ * Texas Instruments CardBus controller overrides.
+ */
+#define ti_sysctl(socket)	((socket)->private[0])
+#define ti_cardctl(socket)	((socket)->private[1])
+#define ti_devctl(socket)	((socket)->private[2])
+#define ti_diag(socket)		((socket)->private[3])
+#define ti_mfunc(socket)	((socket)->private[4])
+#define ene_test_c9(socket)	((socket)->private[5])
+
+/*
+ * These are the TI specific power management handlers.
+ */
+static void ti_save_state(struct yenta_socket *socket)
+{
+	ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	ti_mfunc(socket) = config_readl(socket, TI122X_MFUNC);
+	ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL);
+	ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL);
+	ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC);
+
+	if (socket->dev->vendor == PCI_VENDOR_ID_ENE)
+		ene_test_c9(socket) = config_readb(socket, ENE_TEST_C9);
+}
+
+static void ti_restore_state(struct yenta_socket *socket)
+{
+	config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
+	config_writel(socket, TI122X_MFUNC, ti_mfunc(socket));
+	config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
+	config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
+	config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
+
+	if (socket->dev->vendor == PCI_VENDOR_ID_ENE)
+		config_writeb(socket, ENE_TEST_C9, ene_test_c9(socket));
+}
+
+/*
+ *	Zoom video control for TI122x/113x chips
+ */
+
+static void ti_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+	u8 reg;
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+	/* If we don't have a Zoom Video switch this is harmless,
+	   we just tristate the unused (ZV) lines */
+	reg = config_readb(socket, TI113X_CARD_CONTROL);
+	if (onoff)
+		/* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
+		reg |= TI113X_CCR_ZVENABLE;
+	else
+		reg &= ~TI113X_CCR_ZVENABLE;
+	config_writeb(socket, TI113X_CARD_CONTROL, reg);
+}
+
+/*
+ *	The 145x series can also use this. They have an additional
+ *	ZV autodetect mode we don't use but don't actually need.
+ *	FIXME: manual says its in func0 and func1 but disagrees with
+ *	itself about this - do we need to force func0, if so we need
+ *	to know a lot more about socket pairings in pcmcia_socket than
+ *	we do now.. uggh.
+ */
+ 
+static void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff)
+{	
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	int shift = 0;
+	u8 reg;
+
+	ti_zoom_video(sock, onoff);
+
+	reg = config_readb(socket, TI1250_MULTIMEDIA_CTL);
+	reg |= TI1250_MMC_ZVOUTEN;	/* ZV bus enable */
+
+	if(PCI_FUNC(socket->dev->devfn)==1)
+		shift = 1;
+	
+	if(onoff)
+	{
+		reg &= ~(1<<6); 	/* Clear select bit */
+		reg |= shift<<6;	/* Favour our socket */
+		reg |= 1<<shift;	/* Socket zoom video on */
+	}
+	else
+	{
+		reg &= ~(1<<6); 	/* Clear select bit */
+		reg |= (1^shift)<<6;	/* Favour other socket */
+		reg &= ~(1<<shift);	/* Socket zoon video off */
+	}
+
+	config_writeb(socket, TI1250_MULTIMEDIA_CTL, reg);
+}
+
+static void ti_set_zv(struct yenta_socket *socket)
+{
+	if(socket->dev->vendor == PCI_VENDOR_ID_TI)
+	{
+		switch(socket->dev->device)
+		{
+			/* There may be more .. */
+			case PCI_DEVICE_ID_TI_1220:
+			case PCI_DEVICE_ID_TI_1221:
+			case PCI_DEVICE_ID_TI_1225:
+			case PCI_DEVICE_ID_TI_4510:
+				socket->socket.zoom_video = ti_zoom_video;
+				break;	
+			case PCI_DEVICE_ID_TI_1250:
+			case PCI_DEVICE_ID_TI_1251A:
+			case PCI_DEVICE_ID_TI_1251B:
+			case PCI_DEVICE_ID_TI_1450:
+				socket->socket.zoom_video = ti1250_zoom_video;
+		}
+	}
+}
+
+
+/*
+ * Generic TI init - TI has an extension for the
+ * INTCTL register that sets the PCI CSC interrupt.
+ * Make sure we set it correctly at open and init
+ * time
+ * - override: disable the PCI CSC interrupt. This makes
+ *   it possible to use the CSC interrupt to probe the
+ *   ISA interrupts.
+ * - init: set the interrupt to match our PCI state.
+ *   This makes us correctly get PCI CSC interrupt
+ *   events.
+ */
+static int ti_init(struct yenta_socket *socket)
+{
+	u8 new, reg = exca_readb(socket, I365_INTCTL);
+
+	new = reg & ~I365_INTR_ENA;
+	if (socket->dev->irq)
+		new |= I365_INTR_ENA;
+	if (new != reg)
+		exca_writeb(socket, I365_INTCTL, new);
+	return 0;
+}
+
+static int ti_override(struct yenta_socket *socket)
+{
+	u8 new, reg = exca_readb(socket, I365_INTCTL);
+
+	new = reg & ~I365_INTR_ENA;
+	if (new != reg)
+		exca_writeb(socket, I365_INTCTL, new);
+
+	ti_set_zv(socket);
+
+	return 0;
+}
+
+static void ti113x_use_isa_irq(struct yenta_socket *socket)
+{
+	int isa_irq = -1;
+	u8 intctl;
+	u32 isa_irq_mask = 0;
+
+	if (!isa_probe)
+		return;
+
+	/* get a free isa int */
+	isa_irq_mask = yenta_probe_irq(socket, isa_interrupts);
+	if (!isa_irq_mask)
+		return; /* no useable isa irq found */
+
+	/* choose highest available */
+	for (; isa_irq_mask; isa_irq++)
+		isa_irq_mask >>= 1;
+	socket->cb_irq = isa_irq;
+
+	exca_writeb(socket, I365_CSCINT, (isa_irq << 4));
+
+	intctl = exca_readb(socket, I365_INTCTL);
+	intctl &= ~(I365_INTR_ENA | I365_IRQ_MASK);     /* CSC Enable */
+	exca_writeb(socket, I365_INTCTL, intctl);
+
+	dev_info(&socket->dev->dev,
+		"Yenta TI113x: using isa irq %d for CardBus\n", isa_irq);
+}
+
+
+static int ti113x_override(struct yenta_socket *socket)
+{
+	u8 cardctl;
+
+	cardctl = config_readb(socket, TI113X_CARD_CONTROL);
+	cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
+	if (socket->dev->irq)
+		cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
+	else
+		ti113x_use_isa_irq(socket);
+
+	config_writeb(socket, TI113X_CARD_CONTROL, cardctl);
+
+	return ti_override(socket);
+}
+
+
+/* irqrouting for func0, probes PCI interrupt and ISA interrupts */
+static void ti12xx_irqroute_func0(struct yenta_socket *socket)
+{
+	u32 mfunc, mfunc_old, devctl;
+	u8 gpio3, gpio3_old;
+	int pci_irq_status;
+
+	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
+	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
+	dev_info(&socket->dev->dev, "TI: mfunc 0x%08x, devctl 0x%02x\n",
+		 mfunc, devctl);
+
+	/* make sure PCI interrupts are enabled before probing */
+	ti_init(socket);
+
+	/* test PCI interrupts first. only try fixing if return value is 0! */
+	pci_irq_status = yenta_probe_cb_irq(socket);
+	if (pci_irq_status)
+		goto out;
+
+	/*
+	 * We're here which means PCI interrupts are _not_ delivered. try to
+	 * find the right setting (all serial or parallel)
+	 */
+	dev_info(&socket->dev->dev,
+		 "TI: probing PCI interrupt failed, trying to fix\n");
+
+	/* for serial PCI make sure MFUNC3 is set to IRQSER */
+	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
+		switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1250:
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+		case PCI_DEVICE_ID_TI_1451A:
+		case PCI_DEVICE_ID_TI_4450:
+		case PCI_DEVICE_ID_TI_4451:
+			/* these chips have no IRQSER setting in MFUNC3  */
+			break;
+
+		default:
+			mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER;
+
+			/* write down if changed, probe */
+			if (mfunc != mfunc_old) {
+				config_writel(socket, TI122X_MFUNC, mfunc);
+
+				pci_irq_status = yenta_probe_cb_irq(socket);
+				if (pci_irq_status == 1) {
+					dev_info(&socket->dev->dev,
+						 "TI: all-serial interrupts ok\n");
+					mfunc_old = mfunc;
+					goto out;
+				}
+
+				/* not working, back to old value */
+				mfunc = mfunc_old;
+				config_writel(socket, TI122X_MFUNC, mfunc);
+
+				if (pci_irq_status == -1)
+					goto out;
+			}
+		}
+
+		/* serial PCI interrupts not working fall back to parallel */
+		dev_info(&socket->dev->dev,
+			 "TI: falling back to parallel PCI interrupts\n");
+		devctl &= ~TI113X_DCR_IMODE_MASK;
+		devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */
+		config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
+	}
+
+	/* parallel PCI interrupts: route INTA */
+	switch (socket->dev->device) {
+	case PCI_DEVICE_ID_TI_1250:
+	case PCI_DEVICE_ID_TI_1251A:
+	case PCI_DEVICE_ID_TI_1251B:
+	case PCI_DEVICE_ID_TI_1450:
+		/* make sure GPIO3 is set to INTA */
+		gpio3 = gpio3_old = config_readb(socket, TI1250_GPIO3_CONTROL);
+		gpio3 &= ~TI1250_GPIO_MODE_MASK;
+		if (gpio3 != gpio3_old)
+			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3);
+		break;
+
+	default:
+		gpio3 = gpio3_old = 0;
+
+		mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI122X_MFUNC0_INTA;
+		if (mfunc != mfunc_old)
+			config_writel(socket, TI122X_MFUNC, mfunc);
+	}
+
+	/* time to probe again */
+	pci_irq_status = yenta_probe_cb_irq(socket);
+	if (pci_irq_status == 1) {
+		mfunc_old = mfunc;
+		dev_info(&socket->dev->dev, "TI: parallel PCI interrupts ok\n");
+	} else {
+		/* not working, back to old value */
+		mfunc = mfunc_old;
+		config_writel(socket, TI122X_MFUNC, mfunc);
+		if (gpio3 != gpio3_old)
+			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3_old);
+	}
+
+out:
+	if (pci_irq_status < 1) {
+		socket->cb_irq = 0;
+		dev_info(&socket->dev->dev,
+			 "Yenta TI: no PCI interrupts. Fish. Please report.\n");
+	}
+}
+
+
+/* changes the irq of func1 to match that of func0 */
+static int ti12xx_align_irqs(struct yenta_socket *socket, int *old_irq)
+{
+	struct pci_dev *func0;
+
+	/* find func0 device */
+	func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07);
+	if (!func0)
+		return 0;
+
+	if (old_irq)
+		*old_irq = socket->cb_irq;
+	socket->cb_irq = socket->dev->irq = func0->irq;
+
+	pci_dev_put(func0);
+
+	return 1;
+}
+
+/*
+ * ties INTA and INTB together. also changes the devices irq to that of
+ * the function 0 device. call from func1 only.
+ * returns 1 if INTRTIE changed, 0 otherwise.
+ */
+static int ti12xx_tie_interrupts(struct yenta_socket *socket, int *old_irq)
+{
+	u32 sysctl;
+	int ret;
+
+	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	if (sysctl & TI122X_SCR_INTRTIE)
+		return 0;
+
+	/* align */
+	ret = ti12xx_align_irqs(socket, old_irq);
+	if (!ret)
+		return 0;
+
+	/* tie */
+	sysctl |= TI122X_SCR_INTRTIE;
+	config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl);
+
+	return 1;
+}
+
+/* undo what ti12xx_tie_interrupts() did */
+static void ti12xx_untie_interrupts(struct yenta_socket *socket, int old_irq)
+{
+	u32 sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	sysctl &= ~TI122X_SCR_INTRTIE;
+	config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl);
+
+	socket->cb_irq = socket->dev->irq = old_irq;
+}
+
+/* 
+ * irqrouting for func1, plays with INTB routing
+ * only touches MFUNC for INTB routing. all other bits are taken
+ * care of in func0 already.
+ */
+static void ti12xx_irqroute_func1(struct yenta_socket *socket)
+{
+	u32 mfunc, mfunc_old, devctl, sysctl;
+	int pci_irq_status;
+
+	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
+	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
+	dev_info(&socket->dev->dev, "TI: mfunc 0x%08x, devctl 0x%02x\n",
+		 mfunc, devctl);
+
+	/* if IRQs are configured as tied, align irq of func1 with func0 */
+	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	if (sysctl & TI122X_SCR_INTRTIE)
+		ti12xx_align_irqs(socket, NULL);
+
+	/* make sure PCI interrupts are enabled before probing */
+	ti_init(socket);
+
+	/* test PCI interrupts first. only try fixing if return value is 0! */
+	pci_irq_status = yenta_probe_cb_irq(socket);
+	if (pci_irq_status)
+		goto out;
+
+	/*
+	 * We're here which means PCI interrupts are _not_ delivered. try to
+	 * find the right setting
+	 */
+	dev_info(&socket->dev->dev,
+		 "TI: probing PCI interrupt failed, trying to fix\n");
+
+	/* if all serial: set INTRTIE, probe again */
+	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
+		int old_irq;
+
+		if (ti12xx_tie_interrupts(socket, &old_irq)) {
+			pci_irq_status = yenta_probe_cb_irq(socket);
+			if (pci_irq_status == 1) {
+				dev_info(&socket->dev->dev,
+					 "TI: all-serial interrupts, tied ok\n");
+				goto out;
+			}
+
+			ti12xx_untie_interrupts(socket, old_irq);
+		}
+	}
+	/* parallel PCI: route INTB, probe again */
+	else {
+		int old_irq;
+
+		switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1250:
+			/* the 1250 has one pin for IRQSER/INTB depending on devctl */
+			break;
+
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+			/*
+			 *  those have a pin for IRQSER/INTB plus INTB in MFUNC0
+			 *  we alread probed the shared pin, now go for MFUNC0
+			 */
+			mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI125X_MFUNC0_INTB;
+			break;
+
+		default:
+			mfunc = (mfunc & ~TI122X_MFUNC1_MASK) | TI122X_MFUNC1_INTB;
+			break;
+		}
+
+		/* write, probe */
+		if (mfunc != mfunc_old) {
+			config_writel(socket, TI122X_MFUNC, mfunc);
+
+			pci_irq_status = yenta_probe_cb_irq(socket);
+			if (pci_irq_status == 1) {
+				dev_info(&socket->dev->dev,
+					 "TI: parallel PCI interrupts ok\n");
+				goto out;
+			}
+
+			mfunc = mfunc_old;
+			config_writel(socket, TI122X_MFUNC, mfunc);
+
+			if (pci_irq_status == -1)
+				goto out;
+		}
+
+		/* still nothing: set INTRTIE */
+		if (ti12xx_tie_interrupts(socket, &old_irq)) {
+			pci_irq_status = yenta_probe_cb_irq(socket);
+			if (pci_irq_status == 1) {
+				dev_info(&socket->dev->dev,
+					 "TI: parallel PCI interrupts, tied ok\n");
+				goto out;
+			}
+
+			ti12xx_untie_interrupts(socket, old_irq);
+		}
+	}
+
+out:
+	if (pci_irq_status < 1) {
+		socket->cb_irq = 0;
+		dev_info(&socket->dev->dev,
+			 "TI: no PCI interrupts. Fish. Please report.\n");
+	}
+}
+
+
+/* Returns true value if the second slot of a two-slot controller is empty */
+static int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
+{
+	struct pci_dev *func;
+	struct yenta_socket *slot2;
+	int devfn;
+	unsigned int state;
+	int ret = 1;
+	u32 sysctl;
+
+	/* catch the two-slot controllers */
+	switch (socket->dev->device) {
+	case PCI_DEVICE_ID_TI_1220:
+	case PCI_DEVICE_ID_TI_1221:
+	case PCI_DEVICE_ID_TI_1225:
+	case PCI_DEVICE_ID_TI_1251A:
+	case PCI_DEVICE_ID_TI_1251B:
+	case PCI_DEVICE_ID_TI_1420:
+	case PCI_DEVICE_ID_TI_1450:
+	case PCI_DEVICE_ID_TI_1451A:
+	case PCI_DEVICE_ID_TI_1520:
+	case PCI_DEVICE_ID_TI_1620:
+	case PCI_DEVICE_ID_TI_4520:
+	case PCI_DEVICE_ID_TI_4450:
+	case PCI_DEVICE_ID_TI_4451:
+		/*
+		 * there are way more, but they need to be added in yenta_socket.c
+		 * and pci_ids.h first anyway.
+		 */
+		break;
+
+	case PCI_DEVICE_ID_TI_XX12:
+	case PCI_DEVICE_ID_TI_X515:
+	case PCI_DEVICE_ID_TI_X420:
+	case PCI_DEVICE_ID_TI_X620:
+	case PCI_DEVICE_ID_TI_XX21_XX11:
+	case PCI_DEVICE_ID_TI_7410:
+	case PCI_DEVICE_ID_TI_7610:
+		/*
+		 * those are either single or dual slot CB with additional functions
+		 * like 1394, smartcard reader, etc. check the TIEALL flag for them
+		 * the TIEALL flag binds the IRQ of all functions together.
+		 * we catch the single slot variants later.
+		 */
+		sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+		if (sysctl & TIXX21_SCR_TIEALL)
+			return 0;
+
+		break;
+
+	/* single-slot controllers have the 2nd slot empty always :) */
+	default:
+		return 1;
+	}
+
+	/* get other slot */
+	devfn = socket->dev->devfn & ~0x07;
+	func = pci_get_slot(socket->dev->bus,
+	                    (socket->dev->devfn & 0x07) ? devfn : devfn | 0x01);
+	if (!func)
+		return 1;
+
+	/*
+	 * check that the device id of both slots match. this is needed for the
+	 * XX21 and the XX11 controller that share the same device id for single
+	 * and dual slot controllers. return '2nd slot empty'. we already checked
+	 * if the interrupt is tied to another function.
+	 */
+	if (socket->dev->device != func->device)
+		goto out;
+
+	slot2 = pci_get_drvdata(func);
+	if (!slot2)
+		goto out;
+
+	/* check state */
+	yenta_get_status(&slot2->socket, &state);
+	if (state & SS_DETECT) {
+		ret = 0;
+		goto out;
+	}
+
+out:
+	pci_dev_put(func);
+	return ret;
+}
+
+/*
+ * TI specifiy parts for the power hook.
+ *
+ * some TI's with some CB's produces interrupt storm on power on. it has been
+ * seen with atheros wlan cards on TI1225 and TI1410. solution is simply to
+ * disable any CB interrupts during this time.
+ */
+static int ti12xx_power_hook(struct pcmcia_socket *sock, int operation)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	u32 mfunc, devctl, sysctl;
+	u8 gpio3;
+
+	/* only POWER_PRE and POWER_POST are interesting */
+	if ((operation != HOOK_POWER_PRE) && (operation != HOOK_POWER_POST))
+		return 0;
+
+	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
+	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	mfunc = config_readl(socket, TI122X_MFUNC);
+
+	/*
+	 * all serial/tied: only disable when modparm set. always doing it
+	 * would mean a regression for working setups 'cos it disables the
+	 * interrupts for both both slots on 2-slot controllers
+	 * (and users of single slot controllers where it's save have to
+	 * live with setting the modparm, most don't have to anyway)
+	 */
+	if (((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) &&
+	    (pwr_irqs_off || ti12xx_2nd_slot_empty(socket))) {
+		switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1250:
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+		case PCI_DEVICE_ID_TI_1451A:
+		case PCI_DEVICE_ID_TI_4450:
+		case PCI_DEVICE_ID_TI_4451:
+			/* these chips have no IRQSER setting in MFUNC3  */
+			break;
+
+		default:
+			if (operation == HOOK_POWER_PRE)
+				mfunc = (mfunc & ~TI122X_MFUNC3_MASK);
+			else
+				mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER;
+		}
+
+		return 0;
+	}
+
+	/* do the job differently for func0/1 */
+	if ((PCI_FUNC(socket->dev->devfn) == 0) ||
+	    ((sysctl & TI122X_SCR_INTRTIE) &&
+	     (pwr_irqs_off || ti12xx_2nd_slot_empty(socket)))) {
+		/* some bridges are different */
+		switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1250:
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+			/* those oldies use gpio3 for INTA */
+			gpio3 = config_readb(socket, TI1250_GPIO3_CONTROL);
+			if (operation == HOOK_POWER_PRE)
+				gpio3 = (gpio3 & ~TI1250_GPIO_MODE_MASK) | 0x40;
+			else
+				gpio3 &= ~TI1250_GPIO_MODE_MASK;
+			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3);
+			break;
+
+		default:
+			/* all new bridges are the same */
+			if (operation == HOOK_POWER_PRE)
+				mfunc &= ~TI122X_MFUNC0_MASK;
+			else
+				mfunc |= TI122X_MFUNC0_INTA;
+			config_writel(socket, TI122X_MFUNC, mfunc);
+		}
+	} else {
+		switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+			/* those have INTA elsewhere and INTB in MFUNC0 */
+			if (operation == HOOK_POWER_PRE)
+				mfunc &= ~TI122X_MFUNC0_MASK;
+			else
+				mfunc |= TI125X_MFUNC0_INTB;
+			config_writel(socket, TI122X_MFUNC, mfunc);
+
+			break;
+
+		default:
+			/* all new bridges are the same */
+			if (operation == HOOK_POWER_PRE)
+				mfunc &= ~TI122X_MFUNC1_MASK;
+			else
+				mfunc |= TI122X_MFUNC1_INTB;
+			config_writel(socket, TI122X_MFUNC, mfunc);
+		}
+	}
+
+	return 0;
+}
+
+static int ti12xx_override(struct yenta_socket *socket)
+{
+	u32 val, val_orig;
+
+	/* make sure that memory burst is active */
+	val_orig = val = config_readl(socket, TI113X_SYSTEM_CONTROL);
+	if (disable_clkrun && PCI_FUNC(socket->dev->devfn) == 0) {
+		dev_info(&socket->dev->dev, "Disabling CLKRUN feature\n");
+		val |= TI113X_SCR_KEEPCLK;
+	}
+	if (!(val & TI122X_SCR_MRBURSTUP)) {
+		dev_info(&socket->dev->dev,
+			 "Enabling burst memory read transactions\n");
+		val |= TI122X_SCR_MRBURSTUP;
+	}
+	if (val_orig != val)
+		config_writel(socket, TI113X_SYSTEM_CONTROL, val);
+
+	/*
+	 * Yenta expects controllers to use CSCINT to route
+	 * CSC interrupts to PCI rather than INTVAL.
+	 */
+	val = config_readb(socket, TI1250_DIAGNOSTIC);
+	dev_info(&socket->dev->dev, "Using %s to route CSC interrupts to PCI\n",
+		 (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
+	dev_info(&socket->dev->dev, "Routing CardBus interrupts to %s\n",
+		 (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
+
+	/* do irqrouting, depending on function */
+	if (PCI_FUNC(socket->dev->devfn) == 0)
+		ti12xx_irqroute_func0(socket);
+	else
+		ti12xx_irqroute_func1(socket);
+
+	/* install power hook */
+	socket->socket.power_hook = ti12xx_power_hook;
+
+	return ti_override(socket);
+}
+
+
+static int ti1250_override(struct yenta_socket *socket)
+{
+	u8 old, diag;
+
+	old = config_readb(socket, TI1250_DIAGNOSTIC);
+	diag = old & ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ);
+	if (socket->cb_irq)
+		diag |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
+
+	if (diag != old) {
+		dev_info(&socket->dev->dev,
+			 "adjusting diagnostic: %02x -> %02x\n",
+			 old, diag);
+		config_writeb(socket, TI1250_DIAGNOSTIC, diag);
+	}
+
+	return ti12xx_override(socket);
+}
+
+
+/**
+ * EnE specific part. EnE bridges are register compatible with TI bridges but
+ * have their own test registers and more important their own little problems.
+ * Some fixup code to make everybody happy (TM).
+ */
+
+#ifdef CONFIG_YENTA_ENE_TUNE
+/*
+ * set/clear various test bits:
+ * Defaults to clear the bit.
+ * - mask (u8) defines what bits to change
+ * - bits (u8) is the values to change them to
+ * -> it's
+ * 	current = (current & ~mask) | bits
+ */
+/* pci ids of devices that wants to have the bit set */
+#define DEVID(_vend,_dev,_subvend,_subdev,mask,bits) {		\
+		.vendor		= _vend,			\
+		.device		= _dev,				\
+		.subvendor	= _subvend,			\
+		.subdevice	= _subdev,			\
+		.driver_data	= ((mask) << 8 | (bits)),	\
+	}
+static struct pci_device_id ene_tune_tbl[] = {
+	/* Echo Audio products based on motorola DSP56301 and DSP56361 */
+	DEVID(PCI_VENDOR_ID_MOTOROLA, 0x1801, 0xECC0, PCI_ANY_ID,
+		ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE),
+	DEVID(PCI_VENDOR_ID_MOTOROLA, 0x3410, 0xECC0, PCI_ANY_ID,
+		ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE),
+
+	{}
+};
+
+static void ene_tune_bridge(struct pcmcia_socket *sock, struct pci_bus *bus)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	struct pci_dev *dev;
+	struct pci_device_id *id = NULL;
+	u8 test_c9, old_c9, mask, bits;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		id = (struct pci_device_id *) pci_match_id(ene_tune_tbl, dev);
+		if (id)
+			break;
+	}
+
+	test_c9 = old_c9 = config_readb(socket, ENE_TEST_C9);
+	if (id) {
+		mask = (id->driver_data >> 8) & 0xFF;
+		bits = id->driver_data & 0xFF;
+
+		test_c9 = (test_c9 & ~mask) | bits;
+	}
+	else
+		/* default to clear TLTEnable bit, old behaviour */
+		test_c9 &= ~ENE_TEST_C9_TLTENABLE;
+
+	dev_info(&socket->dev->dev,
+		 "EnE: changing testregister 0xC9, %02x -> %02x\n",
+		 old_c9, test_c9);
+	config_writeb(socket, ENE_TEST_C9, test_c9);
+}
+
+static int ene_override(struct yenta_socket *socket)
+{
+	/* install tune_bridge() function */
+	socket->socket.tune_bridge = ene_tune_bridge;
+
+	return ti1250_override(socket);
+}
+#else
+#  define ene_override ti1250_override
+#endif /* !CONFIG_YENTA_ENE_TUNE */
+
+#endif /* _LINUX_TI113X_H */
+
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/topic.h b/src/kernel/linux/v4.14/drivers/pcmcia/topic.h
new file mode 100644
index 0000000..582688f
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/topic.h
@@ -0,0 +1,168 @@
+/*
+ * topic.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * topic.h $Release$ 1999/08/28 04:01:47
+ */
+
+#ifndef _LINUX_TOPIC_H
+#define _LINUX_TOPIC_H
+
+/* Register definitions for Toshiba ToPIC95/97/100 controllers */
+
+#define TOPIC_SOCKET_CONTROL		0x0090	/* 32 bit */
+#define  TOPIC_SCR_IRQSEL		0x00000001
+
+#define TOPIC_SLOT_CONTROL		0x00a0	/* 8 bit */
+#define  TOPIC_SLOT_SLOTON		0x80
+#define  TOPIC_SLOT_SLOTEN		0x40
+#define  TOPIC_SLOT_ID_LOCK		0x20
+#define  TOPIC_SLOT_ID_WP		0x10
+#define  TOPIC_SLOT_PORT_MASK		0x0c
+#define  TOPIC_SLOT_PORT_SHIFT		2
+#define  TOPIC_SLOT_OFS_MASK		0x03
+
+#define TOPIC_CARD_CONTROL		0x00a1	/* 8 bit */
+#define  TOPIC_CCR_INTB			0x20
+#define  TOPIC_CCR_INTA			0x10
+#define  TOPIC_CCR_CLOCK		0x0c
+#define  TOPIC_CCR_PCICLK		0x0c
+#define  TOPIC_CCR_PCICLK_2		0x08
+#define  TOPIC_CCR_CCLK			0x04
+
+#define TOPIC97_INT_CONTROL		0x00a1	/* 8 bit */
+#define  TOPIC97_ICR_INTB		0x20
+#define  TOPIC97_ICR_INTA		0x10
+#define  TOPIC97_ICR_STSIRQNP		0x04
+#define  TOPIC97_ICR_IRQNP		0x02
+#define  TOPIC97_ICR_IRQSEL		0x01
+
+#define TOPIC_CARD_DETECT		0x00a3	/* 8 bit */
+#define  TOPIC_CDR_MODE_PC32		0x80
+#define  TOPIC_CDR_VS1			0x04
+#define  TOPIC_CDR_VS2			0x02
+#define  TOPIC_CDR_SW_DETECT		0x01
+
+#define TOPIC_REGISTER_CONTROL		0x00a4	/* 32 bit */
+#define  TOPIC_RCR_RESUME_RESET		0x80000000
+#define  TOPIC_RCR_REMOVE_RESET		0x40000000
+#define  TOPIC97_RCR_CLKRUN_ENA		0x20000000
+#define  TOPIC97_RCR_TESTMODE		0x10000000
+#define  TOPIC97_RCR_IOPLUP		0x08000000
+#define  TOPIC_RCR_BUFOFF_PWROFF	0x02000000
+#define  TOPIC_RCR_BUFOFF_SIGOFF	0x01000000
+#define  TOPIC97_RCR_CB_DEV_MASK	0x0000f800
+#define  TOPIC97_RCR_CB_DEV_SHIFT	11
+#define  TOPIC97_RCR_RI_DISABLE		0x00000004
+#define  TOPIC97_RCR_CAUDIO_OFF		0x00000002
+#define  TOPIC_RCR_CAUDIO_INVERT	0x00000001
+
+#define TOPIC97_MISC1			0x00ad  /* 8bit */
+#define  TOPIC97_MISC1_CLOCKRUN_ENABLE	0x80
+#define  TOPIC97_MISC1_CLOCKRUN_MODE	0x40
+#define  TOPIC97_MISC1_DETECT_REQ_ENA	0x10
+#define  TOPIC97_MISC1_SCK_CLEAR_DIS	0x04
+#define  TOPIC97_MISC1_R2_LOW_ENABLE	0x10
+
+#define TOPIC97_MISC2			0x00ae  /* 8 bit */
+#define  TOPIC97_MISC2_SPWRCLK_MASK	0x70
+#define  TOPIC97_MISC2_SPWRMOD		0x08
+#define  TOPIC97_MISC2_SPWR_ENABLE	0x04
+#define  TOPIC97_MISC2_ZV_MODE		0x02
+#define  TOPIC97_MISC2_ZV_ENABLE	0x01
+
+#define TOPIC97_ZOOM_VIDEO_CONTROL	0x009c  /* 8 bit */
+#define  TOPIC97_ZV_CONTROL_ENABLE	0x01
+
+#define TOPIC97_AUDIO_VIDEO_SWITCH	0x003c  /* 8 bit */
+#define  TOPIC97_AVS_AUDIO_CONTROL	0x02
+#define  TOPIC97_AVS_VIDEO_CONTROL	0x01
+
+#define TOPIC_EXCA_IF_CONTROL		0x3e	/* 8 bit */
+#define TOPIC_EXCA_IFC_33V_ENA		0x01
+
+#define TOPIC_PCI_CFG_PPBCN		0x3e	/* 16-bit */
+#define TOPIC_PCI_CFG_PPBCN_WBEN	0x0400
+
+static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	u8 reg_zv, reg;
+
+	reg_zv = config_readb(socket, TOPIC97_ZOOM_VIDEO_CONTROL);
+	if (onoff) {
+		reg_zv |= TOPIC97_ZV_CONTROL_ENABLE;
+		config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv);
+
+		reg = config_readb(socket, TOPIC97_AUDIO_VIDEO_SWITCH);
+		reg |= TOPIC97_AVS_AUDIO_CONTROL | TOPIC97_AVS_VIDEO_CONTROL;
+		config_writeb(socket, TOPIC97_AUDIO_VIDEO_SWITCH, reg);
+	} else {
+		reg_zv &= ~TOPIC97_ZV_CONTROL_ENABLE;
+		config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv);
+
+		reg = config_readb(socket, TOPIC97_AUDIO_VIDEO_SWITCH);
+		reg &= ~(TOPIC97_AVS_AUDIO_CONTROL | TOPIC97_AVS_VIDEO_CONTROL);
+		config_writeb(socket, TOPIC97_AUDIO_VIDEO_SWITCH, reg);
+	}
+}
+
+static int topic97_override(struct yenta_socket *socket)
+{
+	/* ToPIC97/100 support ZV */
+	socket->socket.zoom_video = topic97_zoom_video;
+	return 0;
+}
+
+
+static int topic95_override(struct yenta_socket *socket)
+{
+	u8 fctrl;
+	u16 ppbcn;
+
+	/* enable 3.3V support for 16bit cards */
+	fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL);
+	exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA);
+
+	/* tell yenta to use exca registers to power 16bit cards */
+	socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF;
+
+	/* Disable write buffers to prevent lockups under load with numerous
+	   Cardbus cards, observed on Tecra 500CDT and reported elsewhere on the
+	   net.  This is not a power-on default according to the datasheet
+	   but some BIOSes seem to set it. */
+	if (pci_read_config_word(socket->dev, TOPIC_PCI_CFG_PPBCN, &ppbcn) == 0
+	    && socket->dev->revision <= 7
+	    && (ppbcn & TOPIC_PCI_CFG_PPBCN_WBEN)) {
+		ppbcn &= ~TOPIC_PCI_CFG_PPBCN_WBEN;
+		pci_write_config_word(socket->dev, TOPIC_PCI_CFG_PPBCN, ppbcn);
+		dev_info(&socket->dev->dev, "Disabled ToPIC95 Cardbus write buffers.\n");
+	}
+
+	return 0;
+}
+
+#endif /* _LINUX_TOPIC_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/vg468.h b/src/kernel/linux/v4.14/drivers/pcmcia/vg468.h
new file mode 100644
index 0000000..88c2b48
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/vg468.h
@@ -0,0 +1,106 @@
+/*
+ * vg468.h 1.11 1999/10/25 20:03:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM	0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK		0x0c
+#define VG468_VPP2_5V		0x04
+#define VG468_VPP2_12V		0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE		0x1f	/* Card voltage sense */
+#define VG469_VSELECT		0x2f	/* Card voltage select */
+#define VG468_CTL		0x38	/* Control register */
+#define VG468_TIMER		0x39	/* Timer control */
+#define VG468_MISC		0x3a	/* Miscellaneous */
+#define VG468_GPIO_CFG		0x3b	/* GPIO configuration */
+#define VG469_EXT_MODE		0x3c	/* Extended mode register */
+#define VG468_SELECT		0x3d	/* Programmable chip select */
+#define VG468_SELECT_CFG	0x3e	/* Chip select configuration */
+#define VG468_ATA		0x3f	/* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1	0x01
+#define VG469_VSENSE_A_VS2	0x02
+#define VG469_VSENSE_B_VS1	0x04
+#define VG469_VSENSE_B_VS2	0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC		0x03
+#define VG469_VSEL_5V		0x00
+#define VG469_VSEL_3V		0x03
+#define VG469_VSEL_MAX		0x0c
+#define VG469_VSEL_EXT_STAT	0x10
+#define VG469_VSEL_EXT_BUS	0x20
+#define VG469_VSEL_MIXED	0x40
+#define VG469_VSEL_ISA		0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW		0x01	/* 600ns memory timing */
+#define VG468_CTL_ASYNC		0x02	/* Asynchronous bus clocking */
+#define VG468_CTL_TSSI		0x08	/* Tri-state some outputs */
+#define VG468_CTL_DELAY		0x10	/* Card detect debounce */
+#define VG468_CTL_INPACK	0x20	/* Obey INPACK signal? */
+#define VG468_CTL_POLARITY	0x40	/* VCCEN polarity */
+#define VG468_CTL_COMPAT	0x80	/* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT	0x04	/* Wait state compatibility */
+#define VG469_CTL_STRETCH	0x10	/* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR	0x10	/* Zero power control */
+#define VG468_TIMER_SIGEN	0x20	/* Power up */
+#define VG468_TIMER_STATUS	0x40	/* Activity timer status */
+#define VG468_TIMER_RES		0x80	/* Timer resolution */
+#define VG468_TIMER_MASK	0x0f	/* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO		0x04	/* General-purpose IO */
+#define VG468_MISC_DMAWSB	0x08	/* DMA wait state control */
+#define VG469_MISC_LEDENA	0x10	/* LED enable */
+#define VG468_MISC_VADEMREV	0x40	/* Vadem revision control */
+#define VG468_MISC_UNLOCK	0x80	/* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST	0x03	/* Vpp steering control */
+#define VG469_MODE_INT_SENSE	0x04	/* Internal voltage sense */
+#define VG469_MODE_CABLE	0x08
+#define VG469_MODE_COMPAT	0x10	/* i82365sl B or DF step */
+#define VG469_MODE_TEST		0x20
+#define VG469_MODE_RIO		0x40	/* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V		0x01	/* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/vrc4171_card.c b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4171_card.c
new file mode 100644
index 0000000..1e5fa21
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4171_card.c
@@ -0,0 +1,758 @@
+/*
+ * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
+ *
+ * Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+
+#include "i82365.h"
+
+MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_LICENSE("GPL");
+
+#define CARD_MAX_SLOTS		2
+#define CARD_SLOTA		0
+#define CARD_SLOTB		1
+#define CARD_SLOTB_OFFSET	0x40
+
+#define CARD_MEM_START		0x10000000
+#define CARD_MEM_END		0x13ffffff
+#define CARD_MAX_MEM_OFFSET	0x3ffffff
+#define CARD_MAX_MEM_SPEED	1000
+
+#define CARD_CONTROLLER_INDEX	0x03e0
+#define CARD_CONTROLLER_DATA	0x03e1
+ /* Power register */
+  #define VPP_GET_VCC		0x01
+  #define POWER_ENABLE		0x10
+ #define CARD_VOLTAGE_SENSE	0x1f
+  #define VCC_3VORXV_CAPABLE	0x00
+  #define VCC_XV_ONLY		0x01
+  #define VCC_3V_CAPABLE	0x02
+  #define VCC_5V_ONLY		0x03
+ #define CARD_VOLTAGE_SELECT	0x2f
+  #define VCC_3V		0x01
+  #define VCC_5V		0x00
+  #define VCC_XV		0x02
+  #define VCC_STATUS_3V		0x02
+  #define VCC_STATUS_5V		0x01
+  #define VCC_STATUS_XV		0x03
+ #define GLOBAL_CONTROL		0x1e
+  #define EXWRBK		0x04
+  #define IRQPM_EN		0x08
+  #define CLRPMIRQ		0x10
+
+#define INTERRUPT_STATUS	0x05fa
+ #define IRQ_A			0x02
+ #define IRQ_B			0x04
+
+#define CONFIGURATION1		0x05fe
+ #define SLOTB_CONFIG		0xc000
+ #define SLOTB_NONE		0x0000
+ #define SLOTB_PCCARD		0x4000
+ #define SLOTB_CF		0x8000
+ #define SLOTB_FLASHROM		0xc000
+
+#define CARD_CONTROLLER_START	CARD_CONTROLLER_INDEX
+#define CARD_CONTROLLER_END	CARD_CONTROLLER_DATA
+
+#define IO_MAX_MAPS	2
+#define MEM_MAX_MAPS	5
+
+enum vrc4171_slot {
+	SLOT_PROBE = 0,
+	SLOT_NOPROBE_IO,
+	SLOT_NOPROBE_MEM,
+	SLOT_NOPROBE_ALL,
+	SLOT_INITIALIZED,
+};
+
+enum vrc4171_slotb {
+	SLOTB_IS_NONE,
+	SLOTB_IS_PCCARD,
+	SLOTB_IS_CF,
+	SLOTB_IS_FLASHROM,
+};
+
+struct vrc4171_socket {
+	enum vrc4171_slot slot;
+	struct pcmcia_socket pcmcia_socket;
+	char name[24];
+	int csc_irq;
+	int io_irq;
+	spinlock_t lock;
+};
+
+static struct vrc4171_socket vrc4171_sockets[CARD_MAX_SLOTS];
+static enum vrc4171_slotb vrc4171_slotb = SLOTB_IS_NONE;
+static char vrc4171_card_name[] = "NEC VRC4171 Card Controller";
+static unsigned int vrc4171_irq;
+static uint16_t vrc4171_irq_mask = 0xdeb8;
+
+static struct resource vrc4171_card_resource[3] = {
+	{	.name		= vrc4171_card_name,
+		.start		= CARD_CONTROLLER_START,
+		.end		= CARD_CONTROLLER_END,
+		.flags		= IORESOURCE_IO,	},
+	{	.name		= vrc4171_card_name,
+		.start		= INTERRUPT_STATUS,
+		.end		= INTERRUPT_STATUS,
+		.flags		= IORESOURCE_IO,	},
+	{	.name		= vrc4171_card_name,
+		.start		= CONFIGURATION1,
+		.end		= CONFIGURATION1,
+		.flags		= IORESOURCE_IO,	},
+};
+
+static struct platform_device vrc4171_card_device = {
+	.name		= vrc4171_card_name,
+	.id		= 0,
+	.num_resources	= 3,
+	.resource	= vrc4171_card_resource,
+};
+
+static inline uint16_t vrc4171_get_irq_status(void)
+{
+	return inw(INTERRUPT_STATUS);
+}
+
+static inline void vrc4171_set_multifunction_pin(enum vrc4171_slotb config)
+{
+	uint16_t config1;
+
+	config1 = inw(CONFIGURATION1);
+	config1 &= ~SLOTB_CONFIG;
+
+	switch (config) {
+	case SLOTB_IS_NONE:
+		config1 |= SLOTB_NONE;
+		break;
+	case SLOTB_IS_PCCARD:
+		config1 |= SLOTB_PCCARD;
+		break;
+	case SLOTB_IS_CF:
+		config1 |= SLOTB_CF;
+		break;
+	case SLOTB_IS_FLASHROM:
+		config1 |= SLOTB_FLASHROM;
+		break;
+	default:
+		break;
+	}
+
+	outw(config1, CONFIGURATION1);
+}
+
+static inline uint8_t exca_read_byte(int slot, uint8_t index)
+{
+	if (slot == CARD_SLOTB)
+		index += CARD_SLOTB_OFFSET;
+
+	outb(index, CARD_CONTROLLER_INDEX);
+	return inb(CARD_CONTROLLER_DATA);
+}
+
+static inline uint16_t exca_read_word(int slot, uint8_t index)
+{
+	uint16_t data;
+
+	if (slot == CARD_SLOTB)
+		index += CARD_SLOTB_OFFSET;
+
+	outb(index++, CARD_CONTROLLER_INDEX);
+	data = inb(CARD_CONTROLLER_DATA);
+
+	outb(index, CARD_CONTROLLER_INDEX);
+	data |= ((uint16_t)inb(CARD_CONTROLLER_DATA)) << 8;
+
+	return data;
+}
+
+static inline uint8_t exca_write_byte(int slot, uint8_t index, uint8_t data)
+{
+	if (slot == CARD_SLOTB)
+		index += CARD_SLOTB_OFFSET;
+
+	outb(index, CARD_CONTROLLER_INDEX);
+	outb(data, CARD_CONTROLLER_DATA);
+
+	return data;
+}
+
+static inline uint16_t exca_write_word(int slot, uint8_t index, uint16_t data)
+{
+	if (slot == CARD_SLOTB)
+		index += CARD_SLOTB_OFFSET;
+
+	outb(index++, CARD_CONTROLLER_INDEX);
+	outb(data, CARD_CONTROLLER_DATA);
+
+	outb(index, CARD_CONTROLLER_INDEX);
+	outb((uint8_t)(data >> 8), CARD_CONTROLLER_DATA);
+
+	return data;
+}
+
+static inline int search_nonuse_irq(void)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		if (vrc4171_irq_mask & (1 << i)) {
+			vrc4171_irq_mask &= ~(1 << i);
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static int pccard_init(struct pcmcia_socket *sock)
+{
+	struct vrc4171_socket *socket;
+	unsigned int slot;
+
+	sock->features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
+	sock->irq_mask = 0;
+	sock->map_size = 0x1000;
+	sock->pci_irq = vrc4171_irq;
+
+	slot = sock->sock;
+	socket = &vrc4171_sockets[slot];
+	socket->csc_irq = search_nonuse_irq();
+	socket->io_irq = search_nonuse_irq();
+	spin_lock_init(&socket->lock);
+
+	return 0;
+}
+
+static int pccard_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+	unsigned int slot;
+	uint8_t status, sense;
+	u_int val = 0;
+
+	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || value == NULL)
+		return -EINVAL;
+
+	slot = sock->sock;
+
+	status = exca_read_byte(slot, I365_STATUS);
+	if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
+		if (status & I365_CS_STSCHG)
+			val |= SS_STSCHG;
+	} else {
+		if (!(status & I365_CS_BVD1))
+			val |= SS_BATDEAD;
+		else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
+			val |= SS_BATWARN;
+	}
+	if ((status & I365_CS_DETECT) == I365_CS_DETECT)
+		val |= SS_DETECT;
+	if (status & I365_CS_WRPROT)
+		val |= SS_WRPROT;
+	if (status & I365_CS_READY)
+		val |= SS_READY;
+	if (status & I365_CS_POWERON)
+		val |= SS_POWERON;
+
+	sense = exca_read_byte(slot, CARD_VOLTAGE_SENSE);
+	switch (sense) {
+	case VCC_3VORXV_CAPABLE:
+		val |= SS_3VCARD | SS_XVCARD;
+		break;
+	case VCC_XV_ONLY:
+		val |= SS_XVCARD;
+		break;
+	case VCC_3V_CAPABLE:
+		val |= SS_3VCARD;
+		break;
+	default:
+		/* 5V only */
+		break;
+	}
+
+	*value = val;
+
+	return 0;
+}
+
+static inline uint8_t set_Vcc_value(u_char Vcc)
+{
+	switch (Vcc) {
+	case 33:
+		return VCC_3V;
+	case 50:
+		return VCC_5V;
+	}
+
+	/* Small voltage is chosen for safety. */
+	return VCC_3V;
+}
+
+static int pccard_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+	struct vrc4171_socket *socket;
+	unsigned int slot;
+	uint8_t voltage, power, control, cscint;
+
+	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||
+	    (state->Vpp != state->Vcc && state->Vpp != 0) ||
+	    (state->Vcc != 50 && state->Vcc != 33 && state->Vcc != 0))
+		return -EINVAL;
+
+	slot = sock->sock;
+	socket = &vrc4171_sockets[slot];
+
+	spin_lock_irq(&socket->lock);
+
+	voltage = set_Vcc_value(state->Vcc);
+	exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage);
+
+	power = POWER_ENABLE;
+	if (state->Vpp == state->Vcc)
+		power |= VPP_GET_VCC;
+	if (state->flags & SS_OUTPUT_ENA)
+		power |= I365_PWR_OUT;
+	exca_write_byte(slot, I365_POWER, power);
+
+	control = 0;
+	if (state->io_irq != 0)
+		control |= socket->io_irq;
+	if (state->flags & SS_IOCARD)
+		control |= I365_PC_IOCARD;
+	if (state->flags & SS_RESET)
+		control	&= ~I365_PC_RESET;
+	else
+		control |= I365_PC_RESET;
+	exca_write_byte(slot, I365_INTCTL, control);
+
+        cscint = 0;
+        exca_write_byte(slot, I365_CSCINT, cscint);
+	exca_read_byte(slot, I365_CSC);	/* clear CardStatus change */
+	if (state->csc_mask != 0)
+		cscint |= socket->csc_irq << 8;
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG)
+			cscint |= I365_CSC_STSCHG;
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			cscint |= I365_CSC_BVD1;
+		if (state->csc_mask & SS_BATWARN)
+			cscint |= I365_CSC_BVD2;
+	}
+	if (state->csc_mask & SS_READY)
+		cscint |= I365_CSC_READY;
+	if (state->csc_mask & SS_DETECT)
+		cscint |= I365_CSC_DETECT;
+        exca_write_byte(slot, I365_CSCINT, cscint);
+
+	spin_unlock_irq(&socket->lock);
+
+	return 0;
+}
+
+static int pccard_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
+{
+	unsigned int slot;
+	uint8_t ioctl, addrwin;
+	u_char map;
+
+	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||
+	    io == NULL || io->map >= IO_MAX_MAPS ||
+	    io->start > 0xffff || io->stop > 0xffff || io->start > io->stop)
+		return -EINVAL;
+
+	slot = sock->sock;
+	map = io->map;
+
+	addrwin = exca_read_byte(slot, I365_ADDRWIN);
+	if (addrwin & I365_ENA_IO(map)) {
+		addrwin &= ~I365_ENA_IO(map);
+		exca_write_byte(slot, I365_ADDRWIN, addrwin);
+	}
+
+	exca_write_word(slot, I365_IO(map)+I365_W_START, io->start);
+	exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop);
+
+	ioctl = 0;
+	if (io->speed > 0)
+		ioctl |= I365_IOCTL_WAIT(map);
+	if (io->flags & MAP_16BIT)
+		ioctl |= I365_IOCTL_16BIT(map);
+	if (io->flags & MAP_AUTOSZ)
+		ioctl |= I365_IOCTL_IOCS16(map);
+	if (io->flags & MAP_0WS)
+		ioctl |= I365_IOCTL_0WS(map);
+	exca_write_byte(slot, I365_IOCTL, ioctl);
+
+	if (io->flags & MAP_ACTIVE) {
+		addrwin |= I365_ENA_IO(map);
+		exca_write_byte(slot, I365_ADDRWIN, addrwin);
+	}
+
+	return 0;
+}
+
+static int pccard_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+{
+	unsigned int slot;
+	uint16_t start, stop, offset;
+	uint8_t addrwin;
+	u_char map;
+
+	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||
+	    mem == NULL || mem->map >= MEM_MAX_MAPS ||
+	    mem->res->start < CARD_MEM_START || mem->res->start > CARD_MEM_END ||
+	    mem->res->end < CARD_MEM_START || mem->res->end > CARD_MEM_END ||
+	    mem->res->start > mem->res->end ||
+	    mem->card_start > CARD_MAX_MEM_OFFSET ||
+	    mem->speed > CARD_MAX_MEM_SPEED)
+		return -EINVAL;
+
+	slot = sock->sock;
+	map = mem->map;
+
+	addrwin = exca_read_byte(slot, I365_ADDRWIN);
+	if (addrwin & I365_ENA_MEM(map)) {
+		addrwin &= ~I365_ENA_MEM(map);
+		exca_write_byte(slot, I365_ADDRWIN, addrwin);
+	}
+
+	start = (mem->res->start >> 12) & 0x3fff;
+	if (mem->flags & MAP_16BIT)
+		start |= I365_MEM_16BIT;
+	exca_write_word(slot, I365_MEM(map)+I365_W_START, start);
+
+	stop = (mem->res->end >> 12) & 0x3fff;
+	switch (mem->speed) {
+	case 0:
+		break;
+	case 1:
+		stop |= I365_MEM_WS0;
+		break;
+	case 2:
+		stop |= I365_MEM_WS1;
+		break;
+	default:
+		stop |= I365_MEM_WS0 | I365_MEM_WS1;
+		break;
+	}
+	exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop);
+
+	offset = (mem->card_start >> 12) & 0x3fff;
+	if (mem->flags & MAP_ATTRIB)
+		offset |= I365_MEM_REG;
+	if (mem->flags & MAP_WRPROT)
+		offset |= I365_MEM_WRPROT;
+	exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset);
+
+	if (mem->flags & MAP_ACTIVE) {
+		addrwin |= I365_ENA_MEM(map);
+		exca_write_byte(slot, I365_ADDRWIN, addrwin);
+	}
+
+	return 0;
+}
+
+static struct pccard_operations vrc4171_pccard_operations = {
+	.init			= pccard_init,
+	.get_status		= pccard_get_status,
+	.set_socket		= pccard_set_socket,
+	.set_io_map		= pccard_set_io_map,
+	.set_mem_map		= pccard_set_mem_map,
+};
+
+static inline unsigned int get_events(int slot)
+{
+	unsigned int events = 0;
+	uint8_t status, csc;
+
+	status = exca_read_byte(slot, I365_STATUS);
+	csc = exca_read_byte(slot, I365_CSC);
+
+	if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
+		if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG))
+			events |= SS_STSCHG;
+	} else {
+		if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) {
+			if (!(status & I365_CS_BVD1))
+				events |= SS_BATDEAD;
+			else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
+				events |= SS_BATWARN;
+		}
+	}
+	if ((csc & I365_CSC_READY) && (status & I365_CS_READY))
+		events |= SS_READY;
+	if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT))
+		events |= SS_DETECT;
+
+	return events;
+}
+
+static irqreturn_t pccard_interrupt(int irq, void *dev_id)
+{
+	struct vrc4171_socket *socket;
+	unsigned int events;
+	irqreturn_t retval = IRQ_NONE;
+	uint16_t status;
+
+	status = vrc4171_get_irq_status();
+	if (status & IRQ_A) {
+		socket = &vrc4171_sockets[CARD_SLOTA];
+		if (socket->slot == SLOT_INITIALIZED) {
+			if (status & (1 << socket->csc_irq)) {
+				events = get_events(CARD_SLOTA);
+				if (events != 0) {
+					pcmcia_parse_events(&socket->pcmcia_socket, events);
+					retval = IRQ_HANDLED;
+				}
+			}
+		}
+	}
+
+	if (status & IRQ_B) {
+		socket = &vrc4171_sockets[CARD_SLOTB];
+		if (socket->slot == SLOT_INITIALIZED) {
+			if (status & (1 << socket->csc_irq)) {
+				events = get_events(CARD_SLOTB);
+				if (events != 0) {
+					pcmcia_parse_events(&socket->pcmcia_socket, events);
+					retval = IRQ_HANDLED;
+				}
+			}
+		}
+	}
+
+	return retval;
+}
+
+static inline void reserve_using_irq(int slot)
+{
+	unsigned int irq;
+
+	irq = exca_read_byte(slot, I365_INTCTL);
+	irq &= 0x0f;
+	vrc4171_irq_mask &= ~(1 << irq);
+
+	irq = exca_read_byte(slot, I365_CSCINT);
+	irq = (irq & 0xf0) >> 4;
+	vrc4171_irq_mask &= ~(1 << irq);
+}
+
+static int vrc4171_add_sockets(void)
+{
+	struct vrc4171_socket *socket;
+	int slot, retval;
+
+	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
+		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
+			continue;
+
+		socket = &vrc4171_sockets[slot];
+		if (socket->slot != SLOT_PROBE) {
+			uint8_t addrwin;
+
+			switch (socket->slot) {
+			case SLOT_NOPROBE_MEM:
+				addrwin = exca_read_byte(slot, I365_ADDRWIN);
+				addrwin &= 0x1f;
+				exca_write_byte(slot, I365_ADDRWIN, addrwin);
+				break;
+			case SLOT_NOPROBE_IO:
+				addrwin = exca_read_byte(slot, I365_ADDRWIN);
+				addrwin &= 0xc0;
+				exca_write_byte(slot, I365_ADDRWIN, addrwin);
+				break;
+			default:
+				break;
+			}
+
+			reserve_using_irq(slot);
+			continue;
+		}
+
+		sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
+		socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;
+		socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
+		socket->pcmcia_socket.owner = THIS_MODULE;
+
+		retval = pcmcia_register_socket(&socket->pcmcia_socket);
+		if (retval < 0)
+			return retval;
+
+		exca_write_byte(slot, I365_ADDRWIN, 0);
+		exca_write_byte(slot, GLOBAL_CONTROL, 0);
+
+		socket->slot = SLOT_INITIALIZED;
+	}
+
+	return 0;
+}
+
+static void vrc4171_remove_sockets(void)
+{
+	struct vrc4171_socket *socket;
+	int slot;
+
+	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
+		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
+			continue;
+
+		socket = &vrc4171_sockets[slot];
+		if (socket->slot == SLOT_INITIALIZED)
+			pcmcia_unregister_socket(&socket->pcmcia_socket);
+
+		socket->slot = SLOT_PROBE;
+	}
+}
+
+static int vrc4171_card_setup(char *options)
+{
+	if (options == NULL || *options == '\0')
+		return 1;
+
+	if (strncmp(options, "irq:", 4) == 0) {
+		int irq;
+		options += 4;
+		irq = simple_strtoul(options, &options, 0);
+		if (irq >= 0 && irq < nr_irqs)
+			vrc4171_irq = irq;
+
+		if (*options != ',')
+			return 1;
+		options++;
+	}
+
+	if (strncmp(options, "slota:", 6) == 0) {
+		options += 6;
+		if (*options != '\0') {
+			if (strncmp(options, "memnoprobe", 10) == 0) {
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_MEM;
+				options += 10;
+			} else if (strncmp(options, "ionoprobe", 9) == 0) {
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_IO;
+				options += 9;
+			} else if ( strncmp(options, "noprobe", 7) == 0) {
+				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_ALL;
+				options += 7;
+			}
+
+			if (*options != ',')
+				return 1;
+			options++;
+		} else
+			return 1;
+
+	}
+
+	if (strncmp(options, "slotb:", 6) == 0) {
+		options += 6;
+		if (*options != '\0') {
+			if (strncmp(options, "pccard", 6) == 0) {
+				vrc4171_slotb = SLOTB_IS_PCCARD;
+				options += 6;
+			} else if (strncmp(options, "cf", 2) == 0) {
+				vrc4171_slotb = SLOTB_IS_CF;
+				options += 2;
+			} else if (strncmp(options, "flashrom", 8) == 0) {
+				vrc4171_slotb = SLOTB_IS_FLASHROM;
+				options += 8;
+			} else if (strncmp(options, "none", 4) == 0) {
+				vrc4171_slotb = SLOTB_IS_NONE;
+				options += 4;
+			}
+
+			if (*options != ',')
+				return 1;
+			options++;
+
+			if (strncmp(options, "memnoprobe", 10) == 0)
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_MEM;
+			if (strncmp(options, "ionoprobe", 9) == 0)
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_IO;
+			if (strncmp(options, "noprobe", 7) == 0)
+				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_ALL;
+		}
+	}
+
+	return 1;
+}
+
+__setup("vrc4171_card=", vrc4171_card_setup);
+
+static struct platform_driver vrc4171_card_driver = {
+	.driver = {
+		.name		= vrc4171_card_name,
+	},
+};
+
+static int vrc4171_card_init(void)
+{
+	int retval;
+
+	retval = platform_driver_register(&vrc4171_card_driver);
+	if (retval < 0)
+		return retval;
+
+	retval = platform_device_register(&vrc4171_card_device);
+	if (retval < 0) {
+		platform_driver_unregister(&vrc4171_card_driver);
+		return retval;
+	}
+
+	vrc4171_set_multifunction_pin(vrc4171_slotb);
+
+	retval = vrc4171_add_sockets();
+	if (retval == 0)
+		retval = request_irq(vrc4171_irq, pccard_interrupt, IRQF_SHARED,
+		                     vrc4171_card_name, vrc4171_sockets);
+
+	if (retval < 0) {
+		vrc4171_remove_sockets();
+		platform_device_unregister(&vrc4171_card_device);
+		platform_driver_unregister(&vrc4171_card_driver);
+		return retval;
+	}
+
+	printk(KERN_INFO "%s, connected to IRQ %d\n",
+		vrc4171_card_driver.driver.name, vrc4171_irq);
+
+	return 0;
+}
+
+static void vrc4171_card_exit(void)
+{
+	free_irq(vrc4171_irq, vrc4171_sockets);
+	vrc4171_remove_sockets();
+	platform_device_unregister(&vrc4171_card_device);
+	platform_driver_unregister(&vrc4171_card_driver);
+}
+
+module_init(vrc4171_card_init);
+module_exit(vrc4171_card_exit);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.c b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.c
new file mode 100644
index 0000000..9fb0c3a
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.c
@@ -0,0 +1,591 @@
+/*
+ * FILE NAME
+ *	drivers/pcmcia/vrc4173_cardu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * 	NEC VRC4173 CARDU driver for Socket Services
+ *	(This device doesn't support CardBus. it is supporting only 16bit PC Card.)
+ *
+ * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+#include <pcmcia/ss.h>
+
+#include "vrc4173_cardu.h"
+
+MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_LICENSE("GPL");
+
+static int vrc4173_cardu_slots;
+
+static vrc4173_socket_t cardu_sockets[CARDU_MAX_SOCKETS];
+
+extern struct socket_info_t *pcmcia_register_socket (int slot,
+                                                     struct pccard_operations *vtable,
+                                                     int use_bus_pm);
+extern void pcmcia_unregister_socket(struct socket_info_t *s);
+
+static inline uint8_t exca_readb(vrc4173_socket_t *socket, uint16_t offset)
+{
+	return readb(socket->base + EXCA_REGS_BASE + offset);
+}
+
+static inline uint16_t exca_readw(vrc4173_socket_t *socket, uint16_t offset)
+{
+	uint16_t val;
+
+	val = readb(socket->base + EXCA_REGS_BASE + offset);
+	val |= (u16)readb(socket->base + EXCA_REGS_BASE + offset + 1) << 8;
+
+	return val;
+}
+
+static inline void exca_writeb(vrc4173_socket_t *socket, uint16_t offset, uint8_t val)
+{
+	writeb(val, socket->base + EXCA_REGS_BASE + offset);
+}
+
+static inline void exca_writew(vrc4173_socket_t *socket, uint8_t offset, uint16_t val)
+{
+	writeb((u8)val, socket->base + EXCA_REGS_BASE + offset);
+	writeb((u8)(val >> 8), socket->base + EXCA_REGS_BASE + offset + 1);
+}
+
+static inline uint32_t cardbus_socket_readl(vrc4173_socket_t *socket, u16 offset)
+{
+	return readl(socket->base + CARDBUS_SOCKET_REGS_BASE + offset);
+}
+
+static inline void cardbus_socket_writel(vrc4173_socket_t *socket, u16 offset, uint32_t val)
+{
+	writel(val, socket->base + CARDBUS_SOCKET_REGS_BASE + offset);
+}
+
+static void cardu_pciregs_init(struct pci_dev *dev)
+{
+	u32 syscnt;
+	u16 brgcnt;
+	u8 devcnt;
+
+	pci_write_config_dword(dev, 0x1c, 0x10000000);
+	pci_write_config_dword(dev, 0x20, 0x17fff000);
+	pci_write_config_dword(dev, 0x2c, 0);
+	pci_write_config_dword(dev, 0x30, 0xfffc);
+
+	pci_read_config_word(dev, BRGCNT, &brgcnt);
+	brgcnt &= ~IREQ_INT;
+	pci_write_config_word(dev, BRGCNT, brgcnt);
+
+	pci_read_config_dword(dev, SYSCNT, &syscnt);
+	syscnt &= ~(BAD_VCC_REQ_DISB|PCPCI_EN|CH_ASSIGN_MASK|SUB_ID_WR_EN|PCI_CLK_RIN);
+	syscnt |= (CH_ASSIGN_NODMA|ASYN_INT_MODE);
+	pci_write_config_dword(dev, SYSCNT, syscnt);
+
+	pci_read_config_byte(dev, DEVCNT, &devcnt);
+	devcnt &= ~(ZOOM_VIDEO_EN|SR_PCI_INT_SEL_MASK|PCI_INT_MODE|IRQ_MODE);
+	devcnt |= (SR_PCI_INT_SEL_NONE|IFG);
+	pci_write_config_byte(dev, DEVCNT, devcnt);
+
+	pci_write_config_byte(dev, CHIPCNT, S_PREF_DISB);
+
+	pci_write_config_byte(dev, SERRDIS, 0);
+}
+
+static int cardu_init(unsigned int slot)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[slot];
+
+	cardu_pciregs_init(socket->dev);
+
+	/* CARD_SC bits are cleared by reading CARD_SC. */
+	exca_writeb(socket, GLO_CNT, 0);
+
+	socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
+	socket->cap.irq_mask = 0;
+	socket->cap.map_size = 0x1000;
+	socket->cap.pci_irq  = socket->dev->irq;
+	socket->events = 0;
+	spin_lock_init(socket->event_lock);
+
+	/* Enable PC Card status interrupts */
+	exca_writeb(socket, CARD_SCI, CARD_DT_EN|RDY_EN|BAT_WAR_EN|BAT_DEAD_EN);
+
+	return 0;
+}
+
+static int cardu_register_callback(unsigned int sock,
+                                           void (*handler)(void *, unsigned int),
+                                           void * info)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+
+	socket->handler = handler;
+	socket->info = info;
+
+	return 0;
+}
+
+static int cardu_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+
+	*cap = socket->cap;
+
+	return 0;
+}
+
+static int cardu_get_status(unsigned int sock, u_int *value)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint32_t state;
+	uint8_t status;
+	u_int val = 0;
+
+	status = exca_readb(socket, IF_STATUS);
+	if (status & CARD_PWR) val |= SS_POWERON;
+	if (status & READY) val |= SS_READY;
+	if (status & CARD_WP) val |= SS_WRPROT;
+	if ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2))
+		val |= SS_DETECT;
+	if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) {
+		if (status & STSCHG) val |= SS_STSCHG;
+	} else {
+		status &= BV_DETECT_MASK;
+		if (status != BV_DETECT_GOOD) {
+			if (status == BV_DETECT_WARN) val |= SS_BATWARN;
+			else val |= SS_BATDEAD;
+		}
+	}
+
+	state = cardbus_socket_readl(socket, SKT_PRE_STATE);
+	if (state & VOL_3V_CARD_DT) val |= SS_3VCARD;
+	if (state & VOL_XV_CARD_DT) val |= SS_XVCARD;
+	if (state & CB_CARD_DT) val |= SS_CARDBUS;
+	if (!(state &
+	      (VOL_YV_CARD_DT|VOL_XV_CARD_DT|VOL_3V_CARD_DT|VOL_5V_CARD_DT|CCD20|CCD10)))
+		val |= SS_PENDING;
+
+	*value = val;
+
+	return 0;
+}
+
+static inline uint8_t set_Vcc_value(u_char Vcc)
+{
+	switch (Vcc) {
+	case 33:
+		return VCC_3V;
+	case 50:
+		return VCC_5V;
+	}
+
+	return VCC_0V;
+}
+
+static inline uint8_t set_Vpp_value(u_char Vpp)
+{
+	switch (Vpp) {
+	case 33:
+	case 50:
+		return VPP_VCC;
+	case 120:
+		return VPP_12V;
+	}
+
+	return VPP_0V;
+}
+
+static int cardu_set_socket(unsigned int sock, socket_state_t *state)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint8_t val;
+
+	if (((state->Vpp == 33) || (state->Vpp == 50)) && (state->Vpp != state->Vcc))
+			return -EINVAL;
+
+	val = set_Vcc_value(state->Vcc);
+	val |= set_Vpp_value(state->Vpp);
+	if (state->flags & SS_OUTPUT_ENA) val |= CARD_OUT_EN;
+	exca_writeb(socket, PWR_CNT, val);
+
+	val = exca_readb(socket, INT_GEN_CNT) & CARD_REST0;
+	if (state->flags & SS_RESET) val &= ~CARD_REST0;
+	else val |= CARD_REST0;
+	if (state->flags & SS_IOCARD) val |= CARD_TYPE_IO;
+	exca_writeb(socket, INT_GEN_CNT, val);
+
+	return 0;
+}
+
+static int cardu_get_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint8_t ioctl, window;
+	u_char map;
+
+	map = io->map;
+	if (map > 1)
+		return -EINVAL;
+
+	io->start = exca_readw(socket, IO_WIN_SA(map));
+	io->stop = exca_readw(socket, IO_WIN_EA(map));
+
+	ioctl = exca_readb(socket, IO_WIN_CNT);
+	window = exca_readb(socket, ADR_WIN_EN);
+	io->flags  = (window & IO_WIN_EN(map)) ? MAP_ACTIVE : 0;
+	if (ioctl & IO_WIN_DATA_AUTOSZ(map))
+		io->flags |= MAP_AUTOSZ;
+	else if (ioctl & IO_WIN_DATA_16BIT(map))
+		io->flags |= MAP_16BIT;
+
+	return 0;
+}
+
+static int cardu_set_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint16_t ioctl;
+	uint8_t window, enable;
+	u_char map;
+
+	map = io->map;
+	if (map > 1)
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	enable = IO_WIN_EN(map);
+
+	if (window & enable) {
+		window &= ~enable;
+		exca_writeb(socket, ADR_WIN_EN, window);
+	}
+
+	exca_writew(socket, IO_WIN_SA(map), io->start);
+	exca_writew(socket, IO_WIN_EA(map), io->stop);
+
+	ioctl = exca_readb(socket, IO_WIN_CNT) & ~IO_WIN_CNT_MASK(map);
+	if (io->flags & MAP_AUTOSZ) ioctl |= IO_WIN_DATA_AUTOSZ(map);
+	else if (io->flags & MAP_16BIT) ioctl |= IO_WIN_DATA_16BIT(map);
+	exca_writeb(socket, IO_WIN_CNT, ioctl);
+
+	if (io->flags & MAP_ACTIVE)
+		exca_writeb(socket, ADR_WIN_EN, window | enable);
+
+	return 0;
+}
+
+static int cardu_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint32_t start, stop, offset, page;
+	uint8_t window;
+	u_char map;
+
+	map = mem->map;
+	if (map > 4)
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	mem->flags = (window & MEM_WIN_EN(map)) ? MAP_ACTIVE : 0;
+
+	start = exca_readw(socket, MEM_WIN_SA(map));
+	mem->flags |= (start & MEM_WIN_DSIZE) ? MAP_16BIT : 0;
+	start = (start & 0x0fff) << 12;
+
+	stop = exca_readw(socket, MEM_WIN_EA(map));
+	stop = ((stop & 0x0fff) << 12) + 0x0fff;
+
+	offset = exca_readw(socket, MEM_WIN_OA(map));
+	mem->flags |= (offset & MEM_WIN_WP) ? MAP_WRPROT : 0;
+	mem->flags |= (offset & MEM_WIN_REGSET) ? MAP_ATTRIB : 0;
+	offset = ((offset & 0x3fff) << 12) + start;
+	mem->card_start = offset & 0x03ffffff;
+
+	page = exca_readb(socket, MEM_WIN_SAU(map)) << 24;
+	mem->sys_start = start + page;
+	mem->sys_stop = start + page;
+
+	return 0;
+}
+
+static int cardu_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	vrc4173_socket_t *socket = &cardu_sockets[sock];
+	uint16_t value;
+	uint8_t window, enable;
+	u_long sys_start, sys_stop, card_start;
+	u_char map;
+
+	map = mem->map;
+	sys_start = mem->sys_start;
+	sys_stop = mem->sys_stop;
+	card_start = mem->card_start;
+
+	if (map > 4 || sys_start > sys_stop || ((sys_start ^ sys_stop) >> 24) ||
+	    (card_start >> 26))
+		return -EINVAL;
+
+	window = exca_readb(socket, ADR_WIN_EN);
+	enable = MEM_WIN_EN(map);
+	if (window & enable) {
+		window &= ~enable;
+		exca_writeb(socket, ADR_WIN_EN, window);
+	}
+
+	exca_writeb(socket, MEM_WIN_SAU(map), sys_start >> 24);
+
+	value = (sys_start >> 12) & 0x0fff;
+	if (mem->flags & MAP_16BIT) value |= MEM_WIN_DSIZE;
+	exca_writew(socket, MEM_WIN_SA(map), value);
+
+	value = (sys_stop >> 12) & 0x0fff;
+	exca_writew(socket, MEM_WIN_EA(map), value);
+
+	value = ((card_start - sys_start) >> 12) & 0x3fff;
+	if (mem->flags & MAP_WRPROT) value |= MEM_WIN_WP;
+	if (mem->flags & MAP_ATTRIB) value |= MEM_WIN_REGSET;
+	exca_writew(socket, MEM_WIN_OA(map), value);
+
+	if (mem->flags & MAP_ACTIVE)
+		exca_writeb(socket, ADR_WIN_EN, window | enable);
+
+	return 0;
+}
+
+static void cardu_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+}
+
+static struct pccard_operations cardu_operations = {
+	.init			= cardu_init,
+	.register_callback	= cardu_register_callback,
+	.inquire_socket		= cardu_inquire_socket,
+	.get_status		= cardu_get_status,
+	.set_socket		= cardu_set_socket,
+	.get_io_map		= cardu_get_io_map,
+	.set_io_map		= cardu_set_io_map,
+	.get_mem_map		= cardu_get_mem_map,
+	.set_mem_map		= cardu_set_mem_map,
+	.proc_setup		= cardu_proc_setup,
+};
+
+static void cardu_bh(void *data)
+{
+	vrc4173_socket_t *socket = (vrc4173_socket_t *)data;
+	uint16_t events;
+
+	spin_lock_irq(&socket->event_lock);
+	events = socket->events;
+	socket->events = 0;
+	spin_unlock_irq(&socket->event_lock);
+
+	if (socket->handler)
+		socket->handler(socket->info, events);
+}
+
+static uint16_t get_events(vrc4173_socket_t *socket)
+{
+	uint16_t events = 0;
+	uint8_t csc, status;
+
+	status = exca_readb(socket, IF_STATUS);
+	csc = exca_readb(socket, CARD_SC);
+	if ((csc & CARD_DT_CHG) &&
+	    ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2)))
+		events |= SS_DETECT;
+
+	if ((csc & RDY_CHG) && (status & READY))
+		events |= SS_READY;
+
+	if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) {
+		if ((csc & BAT_DEAD_ST_CHG) && (status & STSCHG))
+			events |= SS_STSCHG;
+	} else {
+		if (csc & (BAT_WAR_CHG|BAT_DEAD_ST_CHG)) {
+			if ((status & BV_DETECT_MASK) != BV_DETECT_GOOD) {
+				if (status == BV_DETECT_WARN) events |= SS_BATWARN;
+				else events |= SS_BATDEAD;
+			}
+		}
+	}
+
+	return events;
+}
+
+static void cardu_interrupt(int irq, void *dev_id)
+{
+	vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id;
+	uint16_t events;
+
+	INIT_WORK(&socket->tq_work, cardu_bh, socket);
+
+	events = get_events(socket);
+	if (events) {
+		spin_lock(&socket->event_lock);
+		socket->events |= events;
+		spin_unlock(&socket->event_lock);
+		schedule_work(&socket->tq_work);
+	}
+}
+
+static int vrc4173_cardu_probe(struct pci_dev *dev,
+                                         const struct pci_device_id *ent)
+{
+	vrc4173_socket_t *socket;
+	unsigned long start, len, flags;
+	int slot, err, ret;
+
+	slot = vrc4173_cardu_slots++;
+	socket = &cardu_sockets[slot];
+	if (socket->noprobe != 0)
+		return -EBUSY;
+
+	sprintf(socket->name, "NEC VRC4173 CARDU%1d", slot+1);
+
+	if ((err = pci_enable_device(dev)) < 0)
+		return err;
+
+	start = pci_resource_start(dev, 0);
+	if (start == 0) {
+		ret = -ENODEV;
+		goto disable;
+	}
+
+	len = pci_resource_len(dev, 0);
+	if (len == 0) {
+		ret = -ENODEV;
+		goto disable;
+	}
+
+	flags = pci_resource_flags(dev, 0);
+	if ((flags & IORESOURCE_MEM) == 0) {
+		ret = -EBUSY;
+		goto disable;
+	}
+
+	err = pci_request_regions(dev, socket->name);
+	if (err < 0) {
+		ret = err;
+		goto disable;
+	}
+
+	socket->base = ioremap(start, len);
+	if (socket->base == NULL) {
+		ret = -ENODEV;
+		goto release;
+	}
+
+	socket->dev = dev;
+
+	socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1);
+	if (socket->pcmcia_socket == NULL) {
+		ret =  -ENOMEM;
+		goto unmap;
+	}
+
+	if (request_irq(dev->irq, cardu_interrupt, IRQF_SHARED, socket->name, socket) < 0) {
+		ret = -EBUSY;
+		goto unregister;
+	}
+
+	printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq);
+
+	return 0;
+
+unregister:
+	pcmcia_unregister_socket(socket->pcmcia_socket);
+	socket->pcmcia_socket = NULL;
+unmap:
+	iounmap(socket->base);
+	socket->base = NULL;
+release:
+	pci_release_regions(dev);
+disable:
+	pci_disable_device(dev);
+	return ret;
+}
+
+static int vrc4173_cardu_setup(char *options)
+{
+	if (options == NULL || *options == '\0')
+		return 1;
+
+	if (strncmp(options, "cardu1:", 7) == 0) {
+		options += 7;
+		if (*options != '\0') {
+			if (strncmp(options, "noprobe", 7) == 0) {
+				cardu_sockets[CARDU1].noprobe = 1;
+				options += 7;
+			}
+
+			if (*options != ',')
+				return 1;
+		} else
+			return 1;
+	}
+
+	if (strncmp(options, "cardu2:", 7) == 0) {
+		options += 7;
+		if ((*options != '\0') && (strncmp(options, "noprobe", 7) == 0))
+			cardu_sockets[CARDU2].noprobe = 1;
+	}
+
+	return 1;
+}
+
+__setup("vrc4173_cardu=", vrc4173_cardu_setup);
+
+static const struct pci_device_id vrc4173_cardu_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NAPCCARD) },
+        {0, }
+};
+
+static struct pci_driver vrc4173_cardu_driver = {
+	.name		= "NEC VRC4173 CARDU",
+	.probe		= vrc4173_cardu_probe,
+	.id_table	= vrc4173_cardu_id_table,
+};
+
+static int vrc4173_cardu_init(void)
+{
+	vrc4173_cardu_slots = 0;
+
+	return pci_register_driver(&vrc4173_cardu_driver);
+}
+
+static void vrc4173_cardu_exit(void)
+{
+	pci_unregister_driver(&vrc4173_cardu_driver);
+}
+
+module_init(vrc4173_cardu_init);
+module_exit(vrc4173_cardu_exit);
+MODULE_DEVICE_TABLE(pci, vrc4173_cardu_id_table);
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.h b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.h
new file mode 100644
index 0000000..a7d9601
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/vrc4173_cardu.h
@@ -0,0 +1,247 @@
+/*
+ * FILE NAME
+ *	drivers/pcmcia/vrc4173_cardu.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Include file for NEC VRC4173 CARDU.
+ *
+ * Copyright 2002 Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _VRC4173_CARDU_H
+#define _VRC4173_CARDU_H
+
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+
+#define CARDU_MAX_SOCKETS	2
+#define CARDU1			0
+#define CARDU2			1
+
+/*
+ * PCI Configuration Registers
+ */
+#define BRGCNT			0x3e
+ #define POST_WR_EN		0x0400
+ #define MEM1_PREF_EN		0x0200
+ #define MEM0_PREF_EN		0x0100
+ #define IREQ_INT		0x0080
+ #define CARD_RST		0x0040
+ #define MABORT_MODE		0x0020
+ #define VGA_EN			0x0008
+ #define ISA_EN			0x0004
+ #define SERR_EN		0x0002
+ #define PERR_EN		0x0001
+
+#define SYSCNT			0x80
+ #define BAD_VCC_REQ_DISB	0x00200000
+ #define PCPCI_EN		0x00080000
+ #define CH_ASSIGN_MASK		0x00070000
+ #define CH_ASSIGN_NODMA	0x00040000
+ #define SUB_ID_WR_EN		0x00000008
+ #define ASYN_INT_MODE		0x00000004
+ #define PCI_CLK_RIN		0x00000002
+
+#define DEVCNT			0x91
+ #define ZOOM_VIDEO_EN		0x40
+ #define SR_PCI_INT_SEL_MASK	0x18
+ #define SR_PCI_INT_SEL_NONE	0x00
+ #define PCI_INT_MODE		0x04
+ #define IRQ_MODE		0x02
+ #define IFG			0x01
+
+#define CHIPCNT			0x9c
+ #define S_PREF_DISB		0x10
+
+#define SERRDIS			0x9f
+ #define SERR_DIS_MAB		0x10
+ #define SERR_DIS_TAB		0x08
+ #define SERR_DIS_DT_PERR	0x04
+
+/*
+ * ExCA Registers
+ */
+#define EXCA_REGS_BASE		0x800
+#define EXCA_REGS_SIZE		0x800
+
+#define ID_REV			0x000
+ #define IF_TYPE_16BIT		0x80
+
+#define IF_STATUS		0x001
+ #define CARD_PWR		0x40
+ #define READY			0x20
+ #define CARD_WP		0x10
+ #define CARD_DETECT2		0x08
+ #define CARD_DETECT1		0x04
+ #define BV_DETECT_MASK		0x03
+ #define BV_DETECT_GOOD		0x03	/* Memory card */
+ #define BV_DETECT_WARN		0x02
+ #define BV_DETECT_BAD1		0x01
+ #define BV_DETECT_BAD0		0x00
+ #define STSCHG			0x02	/* I/O card */
+ #define SPKR			0x01
+
+#define PWR_CNT			0x002
+ #define CARD_OUT_EN		0x80
+ #define VCC_MASK		0x18
+ #define VCC_3V			0x18
+ #define VCC_5V			0x10
+ #define VCC_0V			0x00
+ #define VPP_MASK		0x03
+ #define VPP_12V		0x02
+ #define VPP_VCC		0x01
+ #define VPP_0V			0x00
+
+#define INT_GEN_CNT		0x003
+ #define CARD_REST0		0x40
+ #define CARD_TYPE_MASK		0x20
+ #define CARD_TYPE_IO		0x20
+ #define CARD_TYPE_MEM		0x00
+
+#define CARD_SC			0x004
+ #define CARD_DT_CHG		0x08
+ #define RDY_CHG		0x04
+ #define BAT_WAR_CHG		0x02
+ #define BAT_DEAD_ST_CHG	0x01
+
+#define CARD_SCI		0x005
+ #define CARD_DT_EN		0x08
+ #define RDY_EN			0x04
+ #define BAT_WAR_EN		0x02
+ #define BAT_DEAD_EN		0x01
+
+#define ADR_WIN_EN		0x006
+ #define IO_WIN_EN(x)		(0x40 << (x))
+ #define MEM_WIN_EN(x)		(0x01 << (x))
+
+#define IO_WIN_CNT		0x007
+ #define IO_WIN_CNT_MASK(x)	(0x03 << ((x) << 2))
+ #define IO_WIN_DATA_AUTOSZ(x)	(0x02 << ((x) << 2))
+ #define IO_WIN_DATA_16BIT(x)	(0x01 << ((x) << 2))
+
+#define IO_WIN_SA(x)		(0x008 + ((x) << 2))
+#define IO_WIN_EA(x)		(0x00a + ((x) << 2))
+
+#define MEM_WIN_SA(x)		(0x010 + ((x) << 3))
+ #define MEM_WIN_DSIZE		0x8000
+
+#define MEM_WIN_EA(x)		(0x012 + ((x) << 3))
+
+#define MEM_WIN_OA(x)		(0x014 + ((x) << 3))
+ #define MEM_WIN_WP		0x8000
+ #define MEM_WIN_REGSET		0x4000
+
+#define GEN_CNT			0x016
+ #define VS2_STATUS		0x80
+ #define VS1_STATUS		0x40
+ #define EXCA_REG_RST_EN	0x02
+
+#define GLO_CNT			0x01e
+ #define FUN_INT_LEV		0x08
+ #define INT_WB_CLR		0x04
+ #define CSC_INT_LEV		0x02
+
+#define IO_WIN_OAL(x)		(0x036 + ((x) << 1))
+#define IO_WIN_OAH(x)		(0x037 + ((x) << 1))
+
+#define MEM_WIN_SAU(x)		(0x040 + (x))
+
+#define IO_SETUP_TIM		0x080
+#define IO_CMD_TIM		0x081
+#define IO_HOLD_TIM		0x082
+#define MEM_SETUP_TIM(x)	(0x084 + ((x) << 2))
+#define MEM_CMD_TIM(x)		(0x085 + ((x) << 2))
+#define MEM_HOLD_TIM(x)		(0x086 + ((x) << 2))
+ #define TIM_CLOCKS(x)		((x) - 1)
+
+#define MEM_TIM_SEL1		0x08c
+#define MEM_TIM_SEL2		0x08d
+ #define MEM_WIN_TIMSEL1(x)	(0x03 << (((x) & 3) << 1))
+
+#define MEM_WIN_PWEN		0x091
+ #define POSTWEN		0x01
+
+/*
+ * CardBus Socket Registers
+ */
+#define CARDBUS_SOCKET_REGS_BASE	0x000
+#define CARDBUS_SOCKET_REGS_SIZE	0x800
+
+#define SKT_EV			0x000
+ #define POW_CYC_EV		0x00000008
+ #define CCD2_EV		0x00000004
+ #define CCD1_EV		0x00000002
+ #define CSTSCHG_EV		0x00000001
+
+#define SKT_MASK		0x004
+ #define POW_CYC_MASK		0x00000008
+ #define CCD_MASK		0x00000006
+ #define CSC_MASK		0x00000001
+
+#define SKT_PRE_STATE		0x008
+#define SKT_FORCE_EV		0x00c
+ #define VOL_3V_SKT		0x20000000
+ #define VOL_5V_SKT		0x10000000
+ #define CVS_TEST		0x00004000
+ #define VOL_YV_CARD_DT		0x00002000
+ #define VOL_XV_CARD_DT		0x00001000
+ #define VOL_3V_CARD_DT		0x00000800
+ #define VOL_5V_CARD_DT		0x00000400
+ #define BAD_VCC_REQ		0x00000200
+ #define DATA_LOST		0x00000100
+ #define NOT_A_CARD		0x00000080
+ #define CREADY			0x00000040
+ #define CB_CARD_DT		0x00000020
+ #define R2_CARD_DT		0x00000010
+ #define POW_UP			0x00000008
+ #define CCD20			0x00000004
+ #define CCD10			0x00000002
+ #define CSTSCHG		0x00000001
+
+#define SKT_CNT			0x010
+ #define STP_CLK_EN		0x00000080
+ #define VCC_CNT_MASK		0x00000070
+ #define VCC_CNT_3V		0x00000030
+ #define VCC_CNT_5V		0x00000020
+ #define VCC_CNT_0V		0x00000000
+ #define VPP_CNT_MASK		0x00000007
+ #define VPP_CNT_3V		0x00000003
+ #define VPP_CNT_5V		0x00000002
+ #define VPP_CNT_12V		0x00000001
+ #define VPP_CNT_0V		0x00000000
+
+typedef struct vrc4173_socket {
+	int noprobe;
+	struct pci_dev *dev;
+	void *base;
+	void (*handler)(void *, unsigned int);
+	void *info;
+	socket_cap_t cap;
+	spinlock_t event_lock;
+	uint16_t events;
+	struct socket_info_t *pcmcia_socket;
+	struct work_struct tq_work;
+	char name[20];
+} vrc4173_socket_t;
+
+#endif /* _VRC4173_CARDU_H */
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/xxs1500_ss.c b/src/kernel/linux/v4.14/drivers/pcmcia/xxs1500_ss.c
new file mode 100644
index 0000000..b2a1895
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/xxs1500_ss.c
@@ -0,0 +1,327 @@
+/*
+ * PCMCIA socket code for the MyCable XXS1500 system.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include <asm/irq.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define MEM_MAP_SIZE	0x400000
+#define IO_MAP_SIZE	0x1000
+
+
+/*
+ * 3.3V cards only; all interfacing is done via gpios:
+ *
+ * 0/1:  carddetect (00 = card present, xx = huh)
+ * 4:	 card irq
+ * 204:  reset (high-act)
+ * 205:  buffer enable (low-act)
+ * 208/209: card voltage key (00,01,10,11)
+ * 210:  battwarn
+ * 211:  batdead
+ * 214:  power (low-act)
+ */
+#define GPIO_CDA	0
+#define GPIO_CDB	1
+#define GPIO_CARDIRQ	4
+#define GPIO_RESET	204
+#define GPIO_OUTEN	205
+#define GPIO_VSL	208
+#define GPIO_VSH	209
+#define GPIO_BATTDEAD	210
+#define GPIO_BATTWARN	211
+#define GPIO_POWER	214
+
+struct xxs1500_pcmcia_sock {
+	struct pcmcia_socket	socket;
+	void		*virt_io;
+
+	phys_addr_t	phys_io;
+	phys_addr_t	phys_attr;
+	phys_addr_t	phys_mem;
+
+	/* previous flags for set_socket() */
+	unsigned int old_flags;
+};
+
+#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock, socket)
+
+static irqreturn_t cdirq(int irq, void *data)
+{
+	struct xxs1500_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
+				    struct socket_state_t *state)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+	unsigned int changed;
+
+	/* power control */
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(GPIO_POWER, 1);	/* power off */
+		break;
+	case 33:
+		gpio_set_value(GPIO_POWER, 0);	/* power on */
+		break;
+	case 50:
+	default:
+		return -EINVAL;
+	}
+
+	changed = state->flags ^ sock->old_flags;
+
+	if (changed & SS_RESET) {
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_RESET, 1);	/* assert reset */
+			gpio_set_value(GPIO_OUTEN, 1);	/* buffers off */
+		} else {
+			gpio_set_value(GPIO_RESET, 0);	/* deassert reset */
+			gpio_set_value(GPIO_OUTEN, 0);	/* buffers on */
+			msleep(500);
+		}
+	}
+
+	sock->old_flags = state->flags;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
+				     unsigned int *value)
+{
+	unsigned int status;
+	int i;
+
+	status = 0;
+
+	/* check carddetects: GPIO[0:1] must both be low */
+	if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
+		status |= SS_DETECT;
+
+	/* determine card voltage: GPIO[208:209] binary value */
+	i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
+
+	switch (i) {
+	case 0:
+	case 1:
+	case 2:
+		status |= SS_3VCARD;	/* 3V card */
+		break;
+	case 3:				/* 5V card, unsupported */
+	default:
+		status |= SS_XVCARD;	/* treated as unsupported in core */
+	}
+
+	/* GPIO214: low active power switch */
+	status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
+
+	/* GPIO204: high-active reset line */
+	status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
+
+	/* other stuff */
+	status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
+	status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
+
+	*value = status;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+	gpio_direction_input(GPIO_CDA);
+	gpio_direction_input(GPIO_CDB);
+	gpio_direction_input(GPIO_VSL);
+	gpio_direction_input(GPIO_VSH);
+	gpio_direction_input(GPIO_BATTDEAD);
+	gpio_direction_input(GPIO_BATTWARN);
+	gpio_direction_output(GPIO_RESET, 1);	/* assert reset */
+	gpio_direction_output(GPIO_OUTEN, 1);	/* disable buffers */
+	gpio_direction_output(GPIO_POWER, 1);	/* power off */
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+				    struct pccard_io_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	map->start = (u32)sock->virt_io;
+	map->stop = map->start + IO_MAP_SIZE;
+
+	return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+				     struct pccard_mem_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = sock->phys_attr + map->card_start;
+	else
+		map->static_start = sock->phys_mem + map->card_start;
+
+	return 0;
+}
+
+static struct pccard_operations xxs1500_pcmcia_operations = {
+	.init			= xxs1500_pcmcia_sock_init,
+	.suspend		= xxs1500_pcmcia_sock_suspend,
+	.get_status		= xxs1500_pcmcia_get_status,
+	.set_socket		= xxs1500_pcmcia_configure,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static int xxs1500_pcmcia_probe(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock;
+	struct resource *r;
+	int ret, irq;
+
+	sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
+	if (!sock)
+		return -ENOMEM;
+
+	ret = -ENODEV;
+
+	/* 36bit PCMCIA Attribute area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pcmcia-attr' resource!\n");
+		goto out0;
+	}
+	sock->phys_attr = r->start;
+
+	/* 36bit PCMCIA Memory area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pcmcia-mem' resource!\n");
+		goto out0;
+	}
+	sock->phys_mem = r->start;
+
+	/* 36bit PCMCIA IO area address */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pcmcia-io' resource!\n");
+		goto out0;
+	}
+	sock->phys_io = r->start;
+
+
+	/*
+	 * PCMCIA client drivers use the inb/outb macros to access
+	 * the IO registers.  Since mips_io_port_base is added
+	 * to the access address of the mips implementation of
+	 * inb/outb, we need to subtract it here because we want
+	 * to access the I/O or MEM address directly, without
+	 * going through this "mips_io_port_base" mechanism.
+	 */
+	sock->virt_io = (void *)(ioremap(sock->phys_io, IO_MAP_SIZE) -
+				 mips_io_port_base);
+
+	if (!sock->virt_io) {
+		dev_err(&pdev->dev, "cannot remap IO area\n");
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	sock->socket.ops	= &xxs1500_pcmcia_operations;
+	sock->socket.owner	= THIS_MODULE;
+	sock->socket.pci_irq	= gpio_to_irq(GPIO_CARDIRQ);
+	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->socket.map_size	= MEM_MAP_SIZE;
+	sock->socket.io_offset	= (unsigned long)sock->virt_io;
+	sock->socket.dev.parent	= &pdev->dev;
+	sock->socket.resource_ops = &pccard_static_ops;
+
+	platform_set_drvdata(pdev, sock);
+
+	/* setup carddetect irq: use one of the 2 GPIOs as an
+	 * edge detector.
+	 */
+	irq = gpio_to_irq(GPIO_CDA);
+	irq_set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+	ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot setup cd irq\n");
+		goto out1;
+	}
+
+	ret = pcmcia_register_socket(&sock->socket);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register\n");
+		goto out2;
+	}
+
+	printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
+
+	return 0;
+
+out2:
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+out1:
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+	kfree(sock);
+	return ret;
+}
+
+static int xxs1500_pcmcia_remove(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+	pcmcia_unregister_socket(&sock->socket);
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+	kfree(sock);
+
+	return 0;
+}
+
+static struct platform_driver xxs1500_pcmcia_socket_driver = {
+	.driver	= {
+		.name	= "xxs1500_pcmcia",
+	},
+	.probe		= xxs1500_pcmcia_probe,
+	.remove		= xxs1500_pcmcia_remove,
+};
+
+module_platform_driver(xxs1500_pcmcia_socket_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.c b/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.c
new file mode 100644
index 0000000..5034422
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.c
@@ -0,0 +1,1447 @@
+/*
+ * Regular cardbus driver ("yenta_socket")
+ *
+ * (C) Copyright 1999, 2000 Linus Torvalds
+ *
+ * Changelog:
+ * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
+ * 	Dynamically adjust the size of the bridge resource
+ *
+ * May 2003: Dominik Brodowski <linux@brodo.de>
+ * 	Merge pci_socket.c and yenta.c into one file
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <pcmcia/ss.h>
+
+#include "yenta_socket.h"
+#include "i82365.h"
+
+static bool disable_clkrun;
+module_param(disable_clkrun, bool, 0444);
+MODULE_PARM_DESC(disable_clkrun,
+		 "If PC card doesn't function properly, please try this option (TI and Ricoh bridges only)");
+
+static bool isa_probe = 1;
+module_param(isa_probe, bool, 0444);
+MODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing");
+
+static bool pwr_irqs_off;
+module_param(pwr_irqs_off, bool, 0644);
+MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
+
+static char o2_speedup[] = "default";
+module_param_string(o2_speedup, o2_speedup, sizeof(o2_speedup), 0444);
+MODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
+	"or 'default' (uses recommended behaviour for the detected bridge)");
+
+/*
+ * Only probe "regular" interrupts, don't
+ * touch dangerous spots like the mouse irq,
+ * because there are mice that apparently
+ * get really confused if they get fondled
+ * too intimately.
+ *
+ * Default to 11, 10, 9, 7, 6, 5, 4, 3.
+ */
+static u32 isa_interrupts = 0x0ef8;
+
+
+#define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
+
+/* Don't ask.. */
+#define to_cycles(ns)	((ns)/120)
+#define to_ns(cycles)	((cycles)*120)
+
+/*
+ * yenta PCI irq probing.
+ * currently only used in the TI/EnE initialization code
+ */
+#ifdef CONFIG_YENTA_TI
+static int yenta_probe_cb_irq(struct yenta_socket *socket);
+static unsigned int yenta_probe_irq(struct yenta_socket *socket,
+				u32 isa_irq_mask);
+#endif
+
+
+static unsigned int override_bios;
+module_param(override_bios, uint, 0000);
+MODULE_PARM_DESC(override_bios, "yenta ignore bios resource allocation");
+
+/*
+ * Generate easy-to-use ways of reading a cardbus sockets
+ * regular memory space ("cb_xxx"), configuration space
+ * ("config_xxx") and compatibility space ("exca_xxxx")
+ */
+static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg)
+{
+	u32 val = readl(socket->base + reg);
+	debug("%04x %08x\n", socket, reg, val);
+	return val;
+}
+
+static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val)
+{
+	debug("%04x %08x\n", socket, reg, val);
+	writel(val, socket->base + reg);
+	readl(socket->base + reg); /* avoid problems with PCI write posting */
+}
+
+static inline u8 config_readb(struct yenta_socket *socket, unsigned offset)
+{
+	u8 val;
+	pci_read_config_byte(socket->dev, offset, &val);
+	debug("%04x %02x\n", socket, offset, val);
+	return val;
+}
+
+static inline u16 config_readw(struct yenta_socket *socket, unsigned offset)
+{
+	u16 val;
+	pci_read_config_word(socket->dev, offset, &val);
+	debug("%04x %04x\n", socket, offset, val);
+	return val;
+}
+
+static inline u32 config_readl(struct yenta_socket *socket, unsigned offset)
+{
+	u32 val;
+	pci_read_config_dword(socket->dev, offset, &val);
+	debug("%04x %08x\n", socket, offset, val);
+	return val;
+}
+
+static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val)
+{
+	debug("%04x %02x\n", socket, offset, val);
+	pci_write_config_byte(socket->dev, offset, val);
+}
+
+static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val)
+{
+	debug("%04x %04x\n", socket, offset, val);
+	pci_write_config_word(socket->dev, offset, val);
+}
+
+static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val)
+{
+	debug("%04x %08x\n", socket, offset, val);
+	pci_write_config_dword(socket->dev, offset, val);
+}
+
+static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg)
+{
+	u8 val = readb(socket->base + 0x800 + reg);
+	debug("%04x %02x\n", socket, reg, val);
+	return val;
+}
+
+static inline u8 exca_readw(struct yenta_socket *socket, unsigned reg)
+{
+	u16 val;
+	val = readb(socket->base + 0x800 + reg);
+	val |= readb(socket->base + 0x800 + reg + 1) << 8;
+	debug("%04x %04x\n", socket, reg, val);
+	return val;
+}
+
+static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val)
+{
+	debug("%04x %02x\n", socket, reg, val);
+	writeb(val, socket->base + 0x800 + reg);
+	readb(socket->base + 0x800 + reg); /* PCI write posting... */
+}
+
+static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val)
+{
+	debug("%04x %04x\n", socket, reg, val);
+	writeb(val, socket->base + 0x800 + reg);
+	writeb(val >> 8, socket->base + 0x800 + reg + 1);
+
+	/* PCI write posting... */
+	readb(socket->base + 0x800 + reg);
+	readb(socket->base + 0x800 + reg + 1);
+}
+
+static ssize_t show_yenta_registers(struct device *yentadev, struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *dev = to_pci_dev(yentadev);
+	struct yenta_socket *socket = pci_get_drvdata(dev);
+	int offset = 0, i;
+
+	offset = snprintf(buf, PAGE_SIZE, "CB registers:");
+	for (i = 0; i < 0x24; i += 4) {
+		unsigned val;
+		if (!(i & 15))
+			offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i);
+		val = cb_readl(socket, i);
+		offset += snprintf(buf + offset, PAGE_SIZE - offset, " %08x", val);
+	}
+
+	offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n\nExCA registers:");
+	for (i = 0; i < 0x45; i++) {
+		unsigned char val;
+		if (!(i & 7)) {
+			if (i & 8) {
+				memcpy(buf + offset, " -", 2);
+				offset += 2;
+			} else
+				offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i);
+		}
+		val = exca_readb(socket, i);
+		offset += snprintf(buf + offset, PAGE_SIZE - offset, " %02x", val);
+	}
+	buf[offset++] = '\n';
+	return offset;
+}
+
+static DEVICE_ATTR(yenta_registers, S_IRUSR, show_yenta_registers, NULL);
+
+/*
+ * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend
+ * on what kind of card is inserted..
+ */
+static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	unsigned int val;
+	u32 state = cb_readl(socket, CB_SOCKET_STATE);
+
+	val  = (state & CB_3VCARD) ? SS_3VCARD : 0;
+	val |= (state & CB_XVCARD) ? SS_XVCARD : 0;
+	val |= (state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING;
+	val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? SS_PENDING : 0;
+
+
+	if (state & CB_CBCARD) {
+		val |= SS_CARDBUS;
+		val |= (state & CB_CARDSTS) ? SS_STSCHG : 0;
+		val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT;
+		val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0;
+	} else if (state & CB_16BITCARD) {
+		u8 status = exca_readb(socket, I365_STATUS);
+		val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0;
+		if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) {
+			val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+		} else {
+			val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+			val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+		}
+		val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+		val |= (status & I365_CS_READY) ? SS_READY : 0;
+		val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+	}
+
+	*value = val;
+	return 0;
+}
+
+static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
+{
+	/* some birdges require to use the ExCA registers to power 16bit cards */
+	if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+	    (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+		u8 reg, old;
+		reg = old = exca_readb(socket, I365_POWER);
+		reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
+
+		/* i82365SL-DF style */
+		if (socket->flags & YENTA_16BIT_POWER_DF) {
+			switch (state->Vcc) {
+			case 33:
+				reg |= I365_VCC_3V;
+				break;
+			case 50:
+				reg |= I365_VCC_5V;
+				break;
+			default:
+				reg = 0;
+				break;
+			}
+			switch (state->Vpp) {
+			case 33:
+			case 50:
+				reg |= I365_VPP1_5V;
+				break;
+			case 120:
+				reg |= I365_VPP1_12V;
+				break;
+			}
+		} else {
+			/* i82365SL-B style */
+			switch (state->Vcc) {
+			case 50:
+				reg |= I365_VCC_5V;
+				break;
+			default:
+				reg = 0;
+				break;
+			}
+			switch (state->Vpp) {
+			case 50:
+				reg |= I365_VPP1_5V | I365_VPP2_5V;
+				break;
+			case 120:
+				reg |= I365_VPP1_12V | I365_VPP2_12V;
+				break;
+			}
+		}
+
+		if (reg != old)
+			exca_writeb(socket, I365_POWER, reg);
+	} else {
+		u32 reg = 0;	/* CB_SC_STPCLK? */
+		switch (state->Vcc) {
+		case 33:
+			reg = CB_SC_VCC_3V;
+			break;
+		case 50:
+			reg = CB_SC_VCC_5V;
+			break;
+		default:
+			reg = 0;
+			break;
+		}
+		switch (state->Vpp) {
+		case 33:
+			reg |= CB_SC_VPP_3V;
+			break;
+		case 50:
+			reg |= CB_SC_VPP_5V;
+			break;
+		case 120:
+			reg |= CB_SC_VPP_12V;
+			break;
+		}
+		if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
+			cb_writel(socket, CB_SOCKET_CONTROL, reg);
+	}
+}
+
+static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	u16 bridge;
+
+	/* if powering down: do it immediately */
+	if (state->Vcc == 0)
+		yenta_set_power(socket, state);
+
+	socket->io_irq = state->io_irq;
+	bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
+	if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
+		u8 intr;
+		bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
+
+		/* ISA interrupt control? */
+		intr = exca_readb(socket, I365_INTCTL);
+		intr = (intr & ~0xf);
+		if (!socket->dev->irq) {
+			intr |= socket->cb_irq ? socket->cb_irq : state->io_irq;
+			bridge |= CB_BRIDGE_INTR;
+		}
+		exca_writeb(socket, I365_INTCTL, intr);
+	}  else {
+		u8 reg;
+
+		reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
+		reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+		reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+		if (state->io_irq != socket->dev->irq) {
+			reg |= state->io_irq;
+			bridge |= CB_BRIDGE_INTR;
+		}
+		exca_writeb(socket, I365_INTCTL, reg);
+
+		reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK);
+		reg |= I365_PWR_NORESET;
+		if (state->flags & SS_PWR_AUTO)
+			reg |= I365_PWR_AUTO;
+		if (state->flags & SS_OUTPUT_ENA)
+			reg |= I365_PWR_OUT;
+		if (exca_readb(socket, I365_POWER) != reg)
+			exca_writeb(socket, I365_POWER, reg);
+
+		/* CSC interrupt: no ISA irq for CSC */
+		reg = exca_readb(socket, I365_CSCINT);
+		reg &= I365_CSC_IRQ_MASK;
+		reg |= I365_CSC_DETECT;
+		if (state->flags & SS_IOCARD) {
+			if (state->csc_mask & SS_STSCHG)
+				reg |= I365_CSC_STSCHG;
+		} else {
+			if (state->csc_mask & SS_BATDEAD)
+				reg |= I365_CSC_BVD1;
+			if (state->csc_mask & SS_BATWARN)
+				reg |= I365_CSC_BVD2;
+			if (state->csc_mask & SS_READY)
+				reg |= I365_CSC_READY;
+		}
+		exca_writeb(socket, I365_CSCINT, reg);
+		exca_readb(socket, I365_CSC);
+		if (sock->zoom_video)
+			sock->zoom_video(sock, state->flags & SS_ZVCARD);
+	}
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge);
+	/* Socket event mask: get card insert/remove events.. */
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
+
+	/* if powering up: do it as the last step when the socket is configured */
+	if (state->Vcc != 0)
+		yenta_set_power(socket, state);
+	return 0;
+}
+
+static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	int map;
+	unsigned char ioctl, addr, enable;
+
+	map = io->map;
+
+	if (map > 1)
+		return -EINVAL;
+
+	enable = I365_ENA_IO(map);
+	addr = exca_readb(socket, I365_ADDRWIN);
+
+	/* Disable the window before changing it.. */
+	if (addr & enable) {
+		addr &= ~enable;
+		exca_writeb(socket, I365_ADDRWIN, addr);
+	}
+
+	exca_writew(socket, I365_IO(map)+I365_W_START, io->start);
+	exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop);
+
+	ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+	if (io->flags & MAP_0WS)
+		ioctl |= I365_IOCTL_0WS(map);
+	if (io->flags & MAP_16BIT)
+		ioctl |= I365_IOCTL_16BIT(map);
+	if (io->flags & MAP_AUTOSZ)
+		ioctl |= I365_IOCTL_IOCS16(map);
+	exca_writeb(socket, I365_IOCTL, ioctl);
+
+	if (io->flags & MAP_ACTIVE)
+		exca_writeb(socket, I365_ADDRWIN, addr | enable);
+	return 0;
+}
+
+static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+	struct pci_bus_region region;
+	int map;
+	unsigned char addr, enable;
+	unsigned int start, stop, card_start;
+	unsigned short word;
+
+	pcibios_resource_to_bus(socket->dev->bus, &region, mem->res);
+
+	map = mem->map;
+	start = region.start;
+	stop = region.end;
+	card_start = mem->card_start;
+
+	if (map > 4 || start > stop || ((start ^ stop) >> 24) ||
+	    (card_start >> 26) || mem->speed > 1000)
+		return -EINVAL;
+
+	enable = I365_ENA_MEM(map);
+	addr = exca_readb(socket, I365_ADDRWIN);
+	if (addr & enable) {
+		addr &= ~enable;
+		exca_writeb(socket, I365_ADDRWIN, addr);
+	}
+
+	exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
+
+	word = (start >> 12) & 0x0fff;
+	if (mem->flags & MAP_16BIT)
+		word |= I365_MEM_16BIT;
+	if (mem->flags & MAP_0WS)
+		word |= I365_MEM_0WS;
+	exca_writew(socket, I365_MEM(map) + I365_W_START, word);
+
+	word = (stop >> 12) & 0x0fff;
+	switch (to_cycles(mem->speed)) {
+	case 0:
+		break;
+	case 1:
+		word |= I365_MEM_WS0;
+		break;
+	case 2:
+		word |= I365_MEM_WS1;
+		break;
+	default:
+		word |= I365_MEM_WS1 | I365_MEM_WS0;
+		break;
+	}
+	exca_writew(socket, I365_MEM(map) + I365_W_STOP, word);
+
+	word = ((card_start - start) >> 12) & 0x3fff;
+	if (mem->flags & MAP_WRPROT)
+		word |= I365_MEM_WRPROT;
+	if (mem->flags & MAP_ATTRIB)
+		word |= I365_MEM_REG;
+	exca_writew(socket, I365_MEM(map) + I365_W_OFF, word);
+
+	if (mem->flags & MAP_ACTIVE)
+		exca_writeb(socket, I365_ADDRWIN, addr | enable);
+	return 0;
+}
+
+
+
+static irqreturn_t yenta_interrupt(int irq, void *dev_id)
+{
+	unsigned int events;
+	struct yenta_socket *socket = (struct yenta_socket *) dev_id;
+	u8 csc;
+	u32 cb_event;
+
+	/* Clear interrupt status for the event */
+	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
+	cb_writel(socket, CB_SOCKET_EVENT, cb_event);
+
+	csc = exca_readb(socket, I365_CSC);
+
+	if (!(cb_event || csc))
+		return IRQ_NONE;
+
+	events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ;
+	events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+	if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) {
+		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+	} else {
+		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+	}
+
+	if (events)
+		pcmcia_parse_events(&socket->socket, events);
+
+	return IRQ_HANDLED;
+}
+
+static void yenta_interrupt_wrapper(unsigned long data)
+{
+	struct yenta_socket *socket = (struct yenta_socket *) data;
+
+	yenta_interrupt(0, (void *)socket);
+	socket->poll_timer.expires = jiffies + HZ;
+	add_timer(&socket->poll_timer);
+}
+
+static void yenta_clear_maps(struct yenta_socket *socket)
+{
+	int i;
+	struct resource res = { .start = 0, .end = 0x0fff };
+	pccard_io_map io = { 0, 0, 0, 0, 1 };
+	pccard_mem_map mem = { .res = &res, };
+
+	yenta_set_socket(&socket->socket, &dead_socket);
+	for (i = 0; i < 2; i++) {
+		io.map = i;
+		yenta_set_io_map(&socket->socket, &io);
+	}
+	for (i = 0; i < 5; i++) {
+		mem.map = i;
+		yenta_set_mem_map(&socket->socket, &mem);
+	}
+}
+
+/* redoes voltage interrogation if required */
+static void yenta_interrogate(struct yenta_socket *socket)
+{
+	u32 state;
+
+	state = cb_readl(socket, CB_SOCKET_STATE);
+	if (!(state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) ||
+	    (state & (CB_CDETECT1 | CB_CDETECT2 | CB_NOTACARD | CB_BADVCCREQ)) ||
+	    ((state & (CB_16BITCARD | CB_CBCARD)) == (CB_16BITCARD | CB_CBCARD)))
+		cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
+}
+
+/* Called at resume and initialization events */
+static int yenta_sock_init(struct pcmcia_socket *sock)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+	exca_writeb(socket, I365_GBLCTL, 0x00);
+	exca_writeb(socket, I365_GENCTL, 0x00);
+
+	/* Redo card voltage interrogation */
+	yenta_interrogate(socket);
+
+	yenta_clear_maps(socket);
+
+	if (socket->type && socket->type->sock_init)
+		socket->type->sock_init(socket);
+
+	/* Re-enable CSC interrupts */
+	cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
+
+	return 0;
+}
+
+static int yenta_sock_suspend(struct pcmcia_socket *sock)
+{
+	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+	/* Disable CSC interrupts */
+	cb_writel(socket, CB_SOCKET_MASK, 0x0);
+
+	return 0;
+}
+
+/*
+ * Use an adaptive allocation for the memory resource,
+ * sometimes the memory behind pci bridges is limited:
+ * 1/8 of the size of the io window of the parent.
+ * max 4 MB, min 16 kB. We try very hard to not get below
+ * the "ACC" values, though.
+ */
+#define BRIDGE_MEM_MAX (4*1024*1024)
+#define BRIDGE_MEM_ACC (128*1024)
+#define BRIDGE_MEM_MIN (16*1024)
+
+#define BRIDGE_IO_MAX 512
+#define BRIDGE_IO_ACC 256
+#define BRIDGE_IO_MIN 32
+
+#ifndef PCIBIOS_MIN_CARDBUS_IO
+#define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO
+#endif
+
+static int yenta_search_one_res(struct resource *root, struct resource *res,
+				u32 min)
+{
+	u32 align, size, start, end;
+
+	if (res->flags & IORESOURCE_IO) {
+		align = 1024;
+		size = BRIDGE_IO_MAX;
+		start = PCIBIOS_MIN_CARDBUS_IO;
+		end = ~0U;
+	} else {
+		unsigned long avail = root->end - root->start;
+		int i;
+		size = BRIDGE_MEM_MAX;
+		if (size > avail/8) {
+			size = (avail+1)/8;
+			/* round size down to next power of 2 */
+			i = 0;
+			while ((size /= 2) != 0)
+				i++;
+			size = 1 << i;
+		}
+		if (size < min)
+			size = min;
+		align = size;
+		start = PCIBIOS_MIN_MEM;
+		end = ~0U;
+	}
+
+	do {
+		if (allocate_resource(root, res, size, start, end, align,
+				      NULL, NULL) == 0) {
+			return 1;
+		}
+		size = size/2;
+		align = size;
+	} while (size >= min);
+
+	return 0;
+}
+
+
+static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
+			    u32 min)
+{
+	struct resource *root;
+	int i;
+
+	pci_bus_for_each_resource(socket->dev->bus, root, i) {
+		if (!root)
+			continue;
+
+		if ((res->flags ^ root->flags) &
+		    (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH))
+			continue; /* Wrong type */
+
+		if (yenta_search_one_res(root, res, min))
+			return 1;
+	}
+	return 0;
+}
+
+static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end)
+{
+	struct pci_dev *dev = socket->dev;
+	struct resource *res;
+	struct pci_bus_region region;
+	unsigned mask;
+
+	res = dev->resource + PCI_BRIDGE_RESOURCES + nr;
+	/* Already allocated? */
+	if (res->parent)
+		return 0;
+
+	/* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
+	mask = ~0xfff;
+	if (type & IORESOURCE_IO)
+		mask = ~3;
+
+	res->name = dev->subordinate->name;
+	res->flags = type;
+
+	region.start = config_readl(socket, addr_start) & mask;
+	region.end = config_readl(socket, addr_end) | ~mask;
+	if (region.start && region.end > region.start && !override_bios) {
+		pcibios_bus_to_resource(dev->bus, res, &region);
+		if (pci_claim_resource(dev, PCI_BRIDGE_RESOURCES + nr) == 0)
+			return 0;
+		dev_info(&dev->dev,
+			 "Preassigned resource %d busy or not available, reconfiguring...\n",
+			 nr);
+	}
+
+	if (type & IORESOURCE_IO) {
+		if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) ||
+		    (yenta_search_res(socket, res, BRIDGE_IO_ACC)) ||
+		    (yenta_search_res(socket, res, BRIDGE_IO_MIN)))
+			return 1;
+	} else {
+		if (type & IORESOURCE_PREFETCH) {
+			if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
+			    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
+			    (yenta_search_res(socket, res, BRIDGE_MEM_MIN)))
+				return 1;
+			/* Approximating prefetchable by non-prefetchable */
+			res->flags = IORESOURCE_MEM;
+		}
+		if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
+		    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
+		    (yenta_search_res(socket, res, BRIDGE_MEM_MIN)))
+			return 1;
+	}
+
+	dev_info(&dev->dev,
+		 "no resource of type %x available, trying to continue...\n",
+		 type);
+	res->start = res->end = res->flags = 0;
+	return 0;
+}
+
+/*
+ * Allocate the bridge mappings for the device..
+ */
+static void yenta_allocate_resources(struct yenta_socket *socket)
+{
+	int program = 0;
+	program += yenta_allocate_res(socket, 0, IORESOURCE_IO,
+			   PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0);
+	program += yenta_allocate_res(socket, 1, IORESOURCE_IO,
+			   PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1);
+	program += yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH,
+			   PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0);
+	program += yenta_allocate_res(socket, 3, IORESOURCE_MEM,
+			   PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
+	if (program)
+		pci_setup_cardbus(socket->dev->subordinate);
+}
+
+
+/*
+ * Free the bridge mappings for the device..
+ */
+static void yenta_free_resources(struct yenta_socket *socket)
+{
+	int i;
+	for (i = 0; i < 4; i++) {
+		struct resource *res;
+		res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
+		if (res->start != 0 && res->end != 0)
+			release_resource(res);
+		res->start = res->end = res->flags = 0;
+	}
+}
+
+
+/*
+ * Close it down - release our resources and go home..
+ */
+static void yenta_close(struct pci_dev *dev)
+{
+	struct yenta_socket *sock = pci_get_drvdata(dev);
+
+	/* Remove the register attributes */
+	device_remove_file(&dev->dev, &dev_attr_yenta_registers);
+
+	/* we don't want a dying socket registered */
+	pcmcia_unregister_socket(&sock->socket);
+
+	/* Disable all events so we don't die in an IRQ storm */
+	cb_writel(sock, CB_SOCKET_MASK, 0x0);
+	exca_writeb(sock, I365_CSCINT, 0);
+
+	if (sock->cb_irq)
+		free_irq(sock->cb_irq, sock);
+	else
+		del_timer_sync(&sock->poll_timer);
+
+	iounmap(sock->base);
+	yenta_free_resources(sock);
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+	kfree(sock);
+}
+
+
+static struct pccard_operations yenta_socket_operations = {
+	.init			= yenta_sock_init,
+	.suspend		= yenta_sock_suspend,
+	.get_status		= yenta_get_status,
+	.set_socket		= yenta_set_socket,
+	.set_io_map		= yenta_set_io_map,
+	.set_mem_map		= yenta_set_mem_map,
+};
+
+
+#ifdef CONFIG_YENTA_TI
+#include "ti113x.h"
+#endif
+#ifdef CONFIG_YENTA_RICOH
+#include "ricoh.h"
+#endif
+#ifdef CONFIG_YENTA_TOSHIBA
+#include "topic.h"
+#endif
+#ifdef CONFIG_YENTA_O2
+#include "o2micro.h"
+#endif
+
+enum {
+	CARDBUS_TYPE_DEFAULT = -1,
+	CARDBUS_TYPE_TI,
+	CARDBUS_TYPE_TI113X,
+	CARDBUS_TYPE_TI12XX,
+	CARDBUS_TYPE_TI1250,
+	CARDBUS_TYPE_RICOH,
+	CARDBUS_TYPE_TOPIC95,
+	CARDBUS_TYPE_TOPIC97,
+	CARDBUS_TYPE_O2MICRO,
+	CARDBUS_TYPE_ENE,
+};
+
+/*
+ * Different cardbus controllers have slightly different
+ * initialization sequences etc details. List them here..
+ */
+static struct cardbus_type cardbus_type[] = {
+#ifdef CONFIG_YENTA_TI
+	[CARDBUS_TYPE_TI]	= {
+		.override	= ti_override,
+		.save_state	= ti_save_state,
+		.restore_state	= ti_restore_state,
+		.sock_init	= ti_init,
+	},
+	[CARDBUS_TYPE_TI113X]	= {
+		.override	= ti113x_override,
+		.save_state	= ti_save_state,
+		.restore_state	= ti_restore_state,
+		.sock_init	= ti_init,
+	},
+	[CARDBUS_TYPE_TI12XX]	= {
+		.override	= ti12xx_override,
+		.save_state	= ti_save_state,
+		.restore_state	= ti_restore_state,
+		.sock_init	= ti_init,
+	},
+	[CARDBUS_TYPE_TI1250]	= {
+		.override	= ti1250_override,
+		.save_state	= ti_save_state,
+		.restore_state	= ti_restore_state,
+		.sock_init	= ti_init,
+	},
+	[CARDBUS_TYPE_ENE]	= {
+		.override	= ene_override,
+		.save_state	= ti_save_state,
+		.restore_state	= ti_restore_state,
+		.sock_init	= ti_init,
+	},
+#endif
+#ifdef CONFIG_YENTA_RICOH
+	[CARDBUS_TYPE_RICOH]	= {
+		.override	= ricoh_override,
+		.save_state	= ricoh_save_state,
+		.restore_state	= ricoh_restore_state,
+	},
+#endif
+#ifdef CONFIG_YENTA_TOSHIBA
+	[CARDBUS_TYPE_TOPIC95]	= {
+		.override	= topic95_override,
+	},
+	[CARDBUS_TYPE_TOPIC97]	= {
+		.override	= topic97_override,
+	},
+#endif
+#ifdef CONFIG_YENTA_O2
+	[CARDBUS_TYPE_O2MICRO]	= {
+		.override	= o2micro_override,
+		.restore_state	= o2micro_restore_state,
+	},
+#endif
+};
+
+
+static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask)
+{
+	int i;
+	unsigned long val;
+	u32 mask;
+	u8 reg;
+
+	/*
+	 * Probe for usable interrupts using the force
+	 * register to generate bogus card status events.
+	 */
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+	reg = exca_readb(socket, I365_CSCINT);
+	exca_writeb(socket, I365_CSCINT, 0);
+	val = probe_irq_on() & isa_irq_mask;
+	for (i = 1; i < 16; i++) {
+		if (!((val >> i) & 1))
+			continue;
+		exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
+		cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
+		udelay(100);
+		cb_writel(socket, CB_SOCKET_EVENT, -1);
+	}
+	cb_writel(socket, CB_SOCKET_MASK, 0);
+	exca_writeb(socket, I365_CSCINT, reg);
+
+	mask = probe_irq_mask(val) & 0xffff;
+
+	return mask;
+}
+
+
+/*
+ * yenta PCI irq probing.
+ * currently only used in the TI/EnE initialization code
+ */
+#ifdef CONFIG_YENTA_TI
+
+/* interrupt handler, only used during probing */
+static irqreturn_t yenta_probe_handler(int irq, void *dev_id)
+{
+	struct yenta_socket *socket = (struct yenta_socket *) dev_id;
+	u8 csc;
+	u32 cb_event;
+
+	/* Clear interrupt status for the event */
+	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	csc = exca_readb(socket, I365_CSC);
+
+	if (cb_event || csc) {
+		socket->probe_status = 1;
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+/* probes the PCI interrupt, use only on override functions */
+static int yenta_probe_cb_irq(struct yenta_socket *socket)
+{
+	u8 reg = 0;
+
+	if (!socket->cb_irq)
+		return -1;
+
+	socket->probe_status = 0;
+
+	if (request_irq(socket->cb_irq, yenta_probe_handler, IRQF_SHARED, "yenta", socket)) {
+		dev_warn(&socket->dev->dev,
+			 "request_irq() in yenta_probe_cb_irq() failed!\n");
+		return -1;
+	}
+
+	/* generate interrupt, wait */
+	if (!socket->dev->irq)
+		reg = exca_readb(socket, I365_CSCINT);
+	exca_writeb(socket, I365_CSCINT, reg | I365_CSC_STSCHG);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+	cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
+
+	msleep(100);
+
+	/* disable interrupts */
+	cb_writel(socket, CB_SOCKET_MASK, 0);
+	exca_writeb(socket, I365_CSCINT, reg);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	exca_readb(socket, I365_CSC);
+
+	free_irq(socket->cb_irq, socket);
+
+	return (int) socket->probe_status;
+}
+
+#endif /* CONFIG_YENTA_TI */
+
+
+/*
+ * Set static data that doesn't need re-initializing..
+ */
+static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
+{
+	socket->socket.pci_irq = socket->cb_irq;
+	if (isa_probe)
+		socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
+	else
+		socket->socket.irq_mask = 0;
+
+	dev_info(&socket->dev->dev, "ISA IRQ mask 0x%04x, PCI irq %d\n",
+		 socket->socket.irq_mask, socket->cb_irq);
+}
+
+/*
+ * Initialize the standard cardbus registers
+ */
+static void yenta_config_init(struct yenta_socket *socket)
+{
+	u16 bridge;
+	struct pci_dev *dev = socket->dev;
+	struct pci_bus_region region;
+
+	pcibios_resource_to_bus(socket->dev->bus, &region, &dev->resource[0]);
+
+	config_writel(socket, CB_LEGACY_MODE_BASE, 0);
+	config_writel(socket, PCI_BASE_ADDRESS_0, region.start);
+	config_writew(socket, PCI_COMMAND,
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER |
+			PCI_COMMAND_WAIT);
+
+	/* MAGIC NUMBERS! Fixme */
+	config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
+	config_writeb(socket, PCI_LATENCY_TIMER, 168);
+	config_writel(socket, PCI_PRIMARY_BUS,
+		(176 << 24) |			   /* sec. latency timer */
+		((unsigned int)dev->subordinate->busn_res.end << 16) | /* subordinate bus */
+		((unsigned int)dev->subordinate->busn_res.start << 8) |  /* secondary bus */
+		dev->subordinate->primary);		   /* primary bus */
+
+	/*
+	 * Set up the bridging state:
+	 *  - enable write posting.
+	 *  - memory window 0 prefetchable, window 1 non-prefetchable
+	 *  - PCI interrupts enabled if a PCI interrupt exists..
+	 */
+	bridge = config_readw(socket, CB_BRIDGE_CONTROL);
+	bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN);
+	bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge);
+}
+
+/**
+ * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge
+ * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
+ *
+ * Checks if devices on the bus which the CardBus bridge bridges to would be
+ * invisible during PCI scans because of a misconfigured subordinate number
+ * of the parent brige - some BIOSes seem to be too lazy to set it right.
+ * Does the fixup carefully by checking how far it can go without conflicts.
+ * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
+ */
+static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
+{
+	struct pci_bus *sibling;
+	unsigned char upper_limit;
+	/*
+	 * We only check and fix the parent bridge: All systems which need
+	 * this fixup that have been reviewed are laptops and the only bridge
+	 * which needed fixing was the parent bridge of the CardBus bridge:
+	 */
+	struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
+
+	/* Check bus numbers are already set up correctly: */
+	if (bridge_to_fix->busn_res.end >= cardbus_bridge->busn_res.end)
+		return; /* The subordinate number is ok, nothing to do */
+
+	if (!bridge_to_fix->parent)
+		return; /* Root bridges are ok */
+
+	/* stay within the limits of the bus range of the parent: */
+	upper_limit = bridge_to_fix->parent->busn_res.end;
+
+	/* check the bus ranges of all sibling bridges to prevent overlap */
+	list_for_each_entry(sibling, &bridge_to_fix->parent->children,
+			node) {
+		/*
+		 * If the sibling has a higher secondary bus number
+		 * and it's secondary is equal or smaller than our
+		 * current upper limit, set the new upper limit to
+		 * the bus number below the sibling's range:
+		 */
+		if (sibling->busn_res.start > bridge_to_fix->busn_res.end
+		    && sibling->busn_res.start <= upper_limit)
+			upper_limit = sibling->busn_res.start - 1;
+	}
+
+	/* Show that the wanted subordinate number is not possible: */
+	if (cardbus_bridge->busn_res.end > upper_limit)
+		dev_warn(&cardbus_bridge->dev,
+			 "Upper limit for fixing this bridge's parent bridge: #%02x\n",
+			 upper_limit);
+
+	/* If we have room to increase the bridge's subordinate number, */
+	if (bridge_to_fix->busn_res.end < upper_limit) {
+
+		/* use the highest number of the hidden bus, within limits */
+		unsigned char subordinate_to_assign =
+			min_t(int, cardbus_bridge->busn_res.end, upper_limit);
+
+		dev_info(&bridge_to_fix->dev,
+			 "Raising subordinate bus# of parent bus (#%02x) from #%02x to #%02x\n",
+			 bridge_to_fix->number,
+			 (int)bridge_to_fix->busn_res.end,
+			 subordinate_to_assign);
+
+		/* Save the new subordinate in the bus struct of the bridge */
+		bridge_to_fix->busn_res.end = subordinate_to_assign;
+
+		/* and update the PCI config space with the new subordinate */
+		pci_write_config_byte(bridge_to_fix->self,
+			PCI_SUBORDINATE_BUS, bridge_to_fix->busn_res.end);
+	}
+}
+
+/*
+ * Initialize a cardbus controller. Make sure we have a usable
+ * interrupt, and that we can map the cardbus area. Fill in the
+ * socket information structure..
+ */
+static int yenta_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct yenta_socket *socket;
+	int ret;
+
+	/*
+	 * If we failed to assign proper bus numbers for this cardbus
+	 * controller during PCI probe, its subordinate pci_bus is NULL.
+	 * Bail out if so.
+	 */
+	if (!dev->subordinate) {
+		dev_err(&dev->dev, "no bus associated! (try 'pci=assign-busses')\n");
+		return -ENODEV;
+	}
+
+	socket = kzalloc(sizeof(struct yenta_socket), GFP_KERNEL);
+	if (!socket)
+		return -ENOMEM;
+
+	/* prepare pcmcia_socket */
+	socket->socket.ops = &yenta_socket_operations;
+	socket->socket.resource_ops = &pccard_nonstatic_ops;
+	socket->socket.dev.parent = &dev->dev;
+	socket->socket.driver_data = socket;
+	socket->socket.owner = THIS_MODULE;
+	socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
+	socket->socket.map_size = 0x1000;
+	socket->socket.cb_dev = dev;
+
+	/* prepare struct yenta_socket */
+	socket->dev = dev;
+	pci_set_drvdata(dev, socket);
+
+	/*
+	 * Do some basic sanity checking..
+	 */
+	if (pci_enable_device(dev)) {
+		ret = -EBUSY;
+		goto free;
+	}
+
+	ret = pci_request_regions(dev, "yenta_socket");
+	if (ret)
+		goto disable;
+
+	if (!pci_resource_start(dev, 0)) {
+		dev_err(&dev->dev, "No cardbus resource!\n");
+		ret = -ENODEV;
+		goto release;
+	}
+
+	/*
+	 * Ok, start setup.. Map the cardbus registers,
+	 * and request the IRQ.
+	 */
+	socket->base = ioremap(pci_resource_start(dev, 0), 0x1000);
+	if (!socket->base) {
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	/*
+	 * report the subsystem vendor and device for help debugging
+	 * the irq stuff...
+	 */
+	dev_info(&dev->dev, "CardBus bridge found [%04x:%04x]\n",
+		 dev->subsystem_vendor, dev->subsystem_device);
+
+	yenta_config_init(socket);
+
+	/* Disable all events */
+	cb_writel(socket, CB_SOCKET_MASK, 0x0);
+
+	/* Set up the bridge regions.. */
+	yenta_allocate_resources(socket);
+
+	socket->cb_irq = dev->irq;
+
+	/* Do we have special options for the device? */
+	if (id->driver_data != CARDBUS_TYPE_DEFAULT &&
+	    id->driver_data < ARRAY_SIZE(cardbus_type)) {
+		socket->type = &cardbus_type[id->driver_data];
+
+		ret = socket->type->override(socket);
+		if (ret < 0)
+			goto unmap;
+	}
+
+	/* We must finish initialization here */
+
+	if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, IRQF_SHARED, "yenta", socket)) {
+		/* No IRQ or request_irq failed. Poll */
+		socket->cb_irq = 0; /* But zero is a valid IRQ number. */
+		setup_timer(&socket->poll_timer, yenta_interrupt_wrapper,
+			    (unsigned long)socket);
+		mod_timer(&socket->poll_timer, jiffies + HZ);
+		dev_info(&dev->dev,
+			 "no PCI IRQ, CardBus support disabled for this socket.\n");
+		dev_info(&dev->dev,
+			 "check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+	} else {
+		socket->socket.features |= SS_CAP_CARDBUS;
+	}
+
+	/* Figure out what the dang thing can do for the PCMCIA layer... */
+	yenta_interrogate(socket);
+	yenta_get_socket_capabilities(socket, isa_interrupts);
+	dev_info(&dev->dev, "Socket status: %08x\n",
+		 cb_readl(socket, CB_SOCKET_STATE));
+
+	yenta_fixup_parent_bridge(dev->subordinate);
+
+	/* Register it with the pcmcia layer.. */
+	ret = pcmcia_register_socket(&socket->socket);
+	if (ret)
+		goto free_irq;
+
+	/* Add the yenta register attributes */
+	ret = device_create_file(&dev->dev, &dev_attr_yenta_registers);
+	if (ret)
+		goto unregister_socket;
+
+	return ret;
+
+	/* error path... */
+ unregister_socket:
+	pcmcia_unregister_socket(&socket->socket);
+ free_irq:
+	if (socket->cb_irq)
+		free_irq(socket->cb_irq, socket);
+	else
+		del_timer_sync(&socket->poll_timer);
+ unmap:
+	iounmap(socket->base);
+	yenta_free_resources(socket);
+ release:
+	pci_release_regions(dev);
+ disable:
+	pci_disable_device(dev);
+ free:
+	pci_set_drvdata(dev, NULL);
+	kfree(socket);
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int yenta_dev_suspend_noirq(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct yenta_socket *socket = pci_get_drvdata(pdev);
+
+	if (!socket)
+		return 0;
+
+	if (socket->type && socket->type->save_state)
+		socket->type->save_state(socket);
+
+	pci_save_state(pdev);
+	pci_read_config_dword(pdev, 16*4, &socket->saved_state[0]);
+	pci_read_config_dword(pdev, 17*4, &socket->saved_state[1]);
+	pci_disable_device(pdev);
+
+	return 0;
+}
+
+static int yenta_dev_resume_noirq(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct yenta_socket *socket = pci_get_drvdata(pdev);
+	int ret;
+
+	if (!socket)
+		return 0;
+
+	pci_write_config_dword(pdev, 16*4, socket->saved_state[0]);
+	pci_write_config_dword(pdev, 17*4, socket->saved_state[1]);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	pci_set_master(pdev);
+
+	if (socket->type && socket->type->restore_state)
+		socket->type->restore_state(socket);
+
+	return 0;
+}
+
+static const struct dev_pm_ops yenta_pm_ops = {
+	.suspend_noirq = yenta_dev_suspend_noirq,
+	.resume_noirq = yenta_dev_resume_noirq,
+	.freeze_noirq = yenta_dev_suspend_noirq,
+	.thaw_noirq = yenta_dev_resume_noirq,
+	.poweroff_noirq = yenta_dev_suspend_noirq,
+	.restore_noirq = yenta_dev_resume_noirq,
+};
+
+#define YENTA_PM_OPS	(&yenta_pm_ops)
+#else
+#define YENTA_PM_OPS	NULL
+#endif
+
+#define CB_ID(vend, dev, type)				\
+	{						\
+		.vendor		= vend,			\
+		.device		= dev,			\
+		.subvendor	= PCI_ANY_ID,		\
+		.subdevice	= PCI_ANY_ID,		\
+		.class		= PCI_CLASS_BRIDGE_CARDBUS << 8, \
+		.class_mask	= ~0,			\
+		.driver_data	= CARDBUS_TYPE_##type,	\
+	}
+
+static const struct pci_device_id yenta_table[] = {
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI),
+
+	/*
+	 * TBD: Check if these TI variants can use more
+	 * advanced overrides instead.  (I can't get the
+	 * data sheets for these devices. --rmk)
+	 */
+#ifdef CONFIG_YENTA_TI
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI),
+
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X),
+
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1620, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4510, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX),
+
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250),
+
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX),
+
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, ENE),
+#endif /* CONFIG_YENTA_TI */
+
+#ifdef CONFIG_YENTA_RICOH
+	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH),
+	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH),
+	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH),
+	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
+	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
+#endif
+
+#ifdef CONFIG_YENTA_TOSHIBA
+	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
+	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
+	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
+#endif
+
+#ifdef CONFIG_YENTA_O2
+	CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO),
+#endif
+
+	/* match any cardbus bridge */
+	CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT),
+	{ /* all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, yenta_table);
+
+
+static struct pci_driver yenta_cardbus_driver = {
+	.name		= "yenta_cardbus",
+	.id_table	= yenta_table,
+	.probe		= yenta_probe,
+	.remove		= yenta_close,
+	.driver.pm	= YENTA_PM_OPS,
+};
+
+module_pci_driver(yenta_cardbus_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.h b/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.h
new file mode 100644
index 0000000..efeed19
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/pcmcia/yenta_socket.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __YENTA_H
+#define __YENTA_H
+
+#include <asm/io.h>
+
+#define CB_SOCKET_EVENT		0x00
+#define    CB_CSTSEVENT		0x00000001	/* Card status event */
+#define    CB_CD1EVENT		0x00000002	/* Card detect 1 change event */
+#define    CB_CD2EVENT		0x00000004	/* Card detect 2 change event */
+#define    CB_PWREVENT		0x00000008	/* PWRCYCLE change event */
+
+#define CB_SOCKET_MASK		0x04
+#define    CB_CSTSMASK		0x00000001	/* Card status mask */
+#define    CB_CDMASK		0x00000006	/* Card detect 1&2 mask */
+#define    CB_PWRMASK		0x00000008	/* PWRCYCLE change mask */
+
+#define CB_SOCKET_STATE		0x08
+#define    CB_CARDSTS		0x00000001	/* CSTSCHG status */
+#define    CB_CDETECT1		0x00000002	/* Card detect status 1 */
+#define    CB_CDETECT2		0x00000004	/* Card detect status 2 */
+#define    CB_PWRCYCLE		0x00000008	/* Socket powered */
+#define    CB_16BITCARD		0x00000010	/* 16-bit card detected */
+#define    CB_CBCARD		0x00000020	/* CardBus card detected */
+#define    CB_IREQCINT		0x00000040	/* READY(xIRQ)/xCINT high */
+#define    CB_NOTACARD		0x00000080	/* Unrecognizable PC card detected */
+#define    CB_DATALOST		0x00000100	/* Potential data loss due to card removal */
+#define    CB_BADVCCREQ		0x00000200	/* Invalid Vcc request by host software */
+#define    CB_5VCARD		0x00000400	/* Card Vcc at 5.0 volts? */
+#define    CB_3VCARD		0x00000800	/* Card Vcc at 3.3 volts? */
+#define    CB_XVCARD		0x00001000	/* Card Vcc at X.X volts? */
+#define    CB_YVCARD		0x00002000	/* Card Vcc at Y.Y volts? */
+#define    CB_5VSOCKET		0x10000000	/* Socket Vcc at 5.0 volts? */
+#define    CB_3VSOCKET		0x20000000	/* Socket Vcc at 3.3 volts? */
+#define    CB_XVSOCKET		0x40000000	/* Socket Vcc at X.X volts? */
+#define    CB_YVSOCKET		0x80000000	/* Socket Vcc at Y.Y volts? */
+
+#define CB_SOCKET_FORCE		0x0C
+#define    CB_FCARDSTS		0x00000001	/* Force CSTSCHG */
+#define    CB_FCDETECT1		0x00000002	/* Force CD1EVENT */
+#define    CB_FCDETECT2		0x00000004	/* Force CD2EVENT */
+#define    CB_FPWRCYCLE		0x00000008	/* Force PWREVENT */
+#define    CB_F16BITCARD	0x00000010	/* Force 16-bit PCMCIA card */
+#define    CB_FCBCARD		0x00000020	/* Force CardBus line */
+#define    CB_FNOTACARD		0x00000080	/* Force NOTACARD */
+#define    CB_FDATALOST		0x00000100	/* Force data lost */
+#define    CB_FBADVCCREQ	0x00000200	/* Force bad Vcc request */
+#define    CB_F5VCARD		0x00000400	/* Force 5.0 volt card */
+#define    CB_F3VCARD		0x00000800	/* Force 3.3 volt card */
+#define    CB_FXVCARD		0x00001000	/* Force X.X volt card */
+#define    CB_FYVCARD		0x00002000	/* Force Y.Y volt card */
+#define    CB_CVSTEST		0x00004000	/* Card VS test */
+
+#define CB_SOCKET_CONTROL	0x10
+#define  CB_SC_VPP_MASK		0x00000007
+#define   CB_SC_VPP_OFF		0x00000000
+#define   CB_SC_VPP_12V		0x00000001
+#define   CB_SC_VPP_5V		0x00000002
+#define   CB_SC_VPP_3V		0x00000003
+#define   CB_SC_VPP_XV		0x00000004
+#define   CB_SC_VPP_YV		0x00000005
+#define  CB_SC_VCC_MASK		0x00000070
+#define   CB_SC_VCC_OFF		0x00000000
+#define   CB_SC_VCC_5V		0x00000020
+#define   CB_SC_VCC_3V		0x00000030
+#define   CB_SC_VCC_XV		0x00000040
+#define   CB_SC_VCC_YV		0x00000050
+#define  CB_SC_CCLK_STOP	0x00000080
+
+#define CB_SOCKET_POWER		0x20
+#define    CB_SKTACCES		0x02000000	/* A PC card access has occurred (clear on read) */
+#define    CB_SKTMODE		0x01000000	/* Clock frequency has changed (clear on read) */
+#define    CB_CLKCTRLEN		0x00010000	/* Clock control enabled (RW) */
+#define    CB_CLKCTRL		0x00000001	/* Stop(0) or slow(1) CB clock (RW) */
+
+/*
+ * Cardbus configuration space
+ */
+#define CB_BRIDGE_BASE(m)	(0x1c + 8*(m))
+#define CB_BRIDGE_LIMIT(m)	(0x20 + 8*(m))
+#define CB_BRIDGE_CONTROL	0x3e
+#define   CB_BRIDGE_CPERREN	0x00000001
+#define   CB_BRIDGE_CSERREN	0x00000002
+#define   CB_BRIDGE_ISAEN	0x00000004
+#define   CB_BRIDGE_VGAEN	0x00000008
+#define   CB_BRIDGE_MABTMODE	0x00000020
+#define   CB_BRIDGE_CRST	0x00000040
+#define   CB_BRIDGE_INTR	0x00000080
+#define   CB_BRIDGE_PREFETCH0	0x00000100
+#define   CB_BRIDGE_PREFETCH1	0x00000200
+#define   CB_BRIDGE_POSTEN	0x00000400
+#define CB_LEGACY_MODE_BASE	0x44
+
+/*
+ * ExCA area extensions in Yenta
+ */
+#define CB_MEM_PAGE(map)	(0x40 + (map))
+
+
+/* control how 16bit cards are powered */
+#define YENTA_16BIT_POWER_EXCA	0x00000001
+#define YENTA_16BIT_POWER_DF	0x00000002
+
+
+struct yenta_socket;
+
+struct cardbus_type {
+	int	(*override)(struct yenta_socket *);
+	void	(*save_state)(struct yenta_socket *);
+	void	(*restore_state)(struct yenta_socket *);
+	int	(*sock_init)(struct yenta_socket *);
+};
+
+struct yenta_socket {
+	struct pci_dev *dev;
+	int cb_irq, io_irq;
+	void __iomem *base;
+	struct timer_list poll_timer;
+
+	struct pcmcia_socket socket;
+	struct cardbus_type *type;
+
+	u32 flags;
+
+	/* for PCI interrupt probing */
+	unsigned int probe_status;
+
+	/* A few words of private data for special stuff of overrides... */
+	unsigned int private[8];
+
+	/* PCI saved state */
+	u32 saved_state[2];
+};
+
+
+#endif