## Automatically generated incremental diff
## From:   linux-2.5.66-bk5
## To:     linux-2.5.66-bk6
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.5.66-bk5/Makefile linux-2.5.66-bk6/Makefile
--- linux-2.5.66-bk5/Makefile	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/Makefile	Mon Mar 31 12:52:28 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 66
-EXTRAVERSION = -bk5
+EXTRAVERSION = -bk6
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.66-bk5/drivers/pcmcia/Kconfig linux-2.5.66-bk6/drivers/pcmcia/Kconfig
--- linux-2.5.66-bk5/drivers/pcmcia/Kconfig	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/Kconfig	Mon Mar 31 12:52:29 2003
@@ -82,10 +82,22 @@
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
+	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 PCMCIA_SA1100 && SA1111
+	depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA
+	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_PROBE
 	bool
diff -urN linux-2.5.66-bk5/drivers/pcmcia/Makefile linux-2.5.66-bk6/drivers/pcmcia/Makefile
--- linux-2.5.66-bk5/drivers/pcmcia/Makefile	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/Makefile	Mon Mar 31 12:52:29 2003
@@ -11,8 +11,8 @@
 obj-$(CONFIG_I82092)				+= i82092.o
 obj-$(CONFIG_TCIC)				+= tcic.o
 obj-$(CONFIG_HD64465_PCMCIA)			+= hd64465_ss.o
-obj-$(CONFIG_PCMCIA_SA1100)			+= sa1100_cs.o
-obj-$(CONFIG_PCMCIA_SA1111)			+= sa1111_cs.o
+obj-$(CONFIG_PCMCIA_SA1100)			+= sa11xx_core.o sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)			+= sa11xx_core.o sa1111_cs.o
 
 yenta_socket-y					+= pci_socket.o yenta.o
 
diff -urN linux-2.5.66-bk5/drivers/pcmcia/cs.c linux-2.5.66-bk6/drivers/pcmcia/cs.c
--- linux-2.5.66-bk5/drivers/pcmcia/cs.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/cs.c	Mon Mar 31 12:52:29 2003
@@ -111,13 +111,6 @@
 /* Access speed for IO windows */
 INT_MODULE_PARM(io_speed,	0);		/* ns */
 
-/* Optional features */
-#ifdef CONFIG_PM
-INT_MODULE_PARM(do_apm,		1);
-#else
-INT_MODULE_PARM(do_apm,		0);
-#endif
-
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 static const char *version =
@@ -348,7 +341,6 @@
 		/* base address = 0, map = 0 */
 		s->cis_mem.flags = 0;
 		s->cis_mem.speed = cis_speed;
-		s->use_bus_pm = cls_d->use_bus_pm;
 		s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
 		spin_lock_init(&s->lock);
     
@@ -655,6 +647,8 @@
     DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",
 	  s->sock, event, priority);
     ret = 0;
+    if (s->state & SOCKET_CARDBUS)
+	    return 0;
     for (; client; client = client->next) { 
 	if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
 	    continue;
@@ -756,33 +750,47 @@
 	parse_events(s, SS_DETECT);
 }
 
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
+
+int pcmcia_socket_dev_suspend(struct device * dev, u32 state, u32 level)
 {
-    int i;
-    socket_info_t *s;
+	struct pcmcia_socket_class_data *cls_d = to_class_data(dev);
+	socket_info_t *s;
+	int i;
+
+	if ((!cls_d) || (level != SUSPEND_SAVE_STATE))
+		return 0;
 
-    /* only for busses that don't suspend/resume slots directly */
+	s = (socket_info_t *) cls_d->s_info;
 
-    switch (rqst) {
-    case PM_SUSPEND:
-	DEBUG(1, "cs: received suspend notification\n");
-	for (i = 0; i < sockets; i++) {
-	    s = socket_table [i];
-	    if (!s->use_bus_pm)
-		pcmcia_suspend_socket (socket_table [i]);
+	for (i = 0; i < cls_d->nsock; i++) {
+		pcmcia_suspend_socket(s);
+		s++;
 	}
-	break;
-    case PM_RESUME:
-	DEBUG(1, "cs: received resume notification\n");
-	for (i = 0; i < sockets; i++) {
-	    s = socket_table [i];
-	    if (!s->use_bus_pm)
-		pcmcia_resume_socket (socket_table [i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
+
+int pcmcia_socket_dev_resume(struct device * dev, u32 level)
+{
+	struct pcmcia_socket_class_data *cls_d = to_class_data(dev);
+	socket_info_t *s;
+	int i;
+
+	if ((!cls_d) || (level != RESUME_RESTORE_STATE))
+		return 0;
+
+	s = (socket_info_t *) cls_d->s_info;
+
+	for (i = 0; i < cls_d->nsock; i++) {
+		pcmcia_resume_socket(s);
+		s++;
 	}
-	break;
-    }
-    return 0;
-} /* handle_pm_event */
+
+	return 0;
+}
+EXPORT_SYMBOL(pcmcia_socket_dev_resume);
+
 
 /*======================================================================
 
@@ -2429,8 +2437,6 @@
     printk(KERN_INFO "  %s\n", options);
     DEBUG(0, "%s\n", version);
     devclass_register(&pcmcia_socket_class);
-    if (do_apm)
-	pm_register(PM_SYS_DEV, PM_SYS_PCMCIA, handle_pm_event);
 #ifdef CONFIG_PROC_FS
     proc_pccard = proc_mkdir("pccard", proc_bus);
 #endif
@@ -2446,8 +2452,6 @@
 	remove_proc_entry("pccard", proc_bus);
     }
 #endif
-    if (do_apm)
-	pm_unregister_all(handle_pm_event);
     release_resource_db();
     devclass_unregister(&pcmcia_socket_class);
 }
diff -urN linux-2.5.66-bk5/drivers/pcmcia/cs_internal.h linux-2.5.66-bk6/drivers/pcmcia/cs_internal.h
--- linux-2.5.66-bk5/drivers/pcmcia/cs_internal.h	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/cs_internal.h	Mon Mar 31 12:52:29 2003
@@ -157,7 +157,6 @@
 #ifdef CONFIG_PROC_FS
     struct proc_dir_entry	*proc;
 #endif
-    int				use_bus_pm;
 } socket_info_t;
 
 /* Flags in config state */
diff -urN linux-2.5.66-bk5/drivers/pcmcia/ds.c linux-2.5.66-bk6/drivers/pcmcia/ds.c
--- linux-2.5.66-bk5/drivers/pcmcia/ds.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/ds.c	Mon Mar 31 12:52:29 2003
@@ -49,6 +49,7 @@
 #include <linux/poll.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/workqueue.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -103,7 +104,7 @@
 	user_info_t		*user;
 	int			req_pending, req_result;
 	wait_queue_head_t	queue, request;
-	struct timer_list	removal;
+	struct work_struct	removal;
 	socket_bind_t		*bind;
 	struct device		*socket_dev;
 	struct list_head	socket_list;
@@ -299,9 +300,9 @@
     return CS_SUCCESS;
 }
 
-static void handle_removal(u_long sn)
+static void handle_removal(void *data)
 {
-    struct pcmcia_bus_socket *s = get_socket_info_by_nr(sn);
+    struct pcmcia_bus_socket *s = data;
     handle_event(s, CS_EVENT_CARD_REMOVAL);
     s->state &= ~SOCKET_REMOVAL_PENDING;
 }
@@ -326,10 +327,8 @@
     case CS_EVENT_CARD_REMOVAL:
 	s->state &= ~SOCKET_PRESENT;
 	if (!(s->state & SOCKET_REMOVAL_PENDING)) {
-	    s->state |= SOCKET_REMOVAL_PENDING;
-	    init_timer(&s->removal);
-	    s->removal.expires = jiffies + HZ/10;
-	    add_timer(&s->removal);
+		s->state |= SOCKET_REMOVAL_PENDING;
+		schedule_delayed_work(&s->removal,  HZ/10);
 	}
 	break;
 	
@@ -922,9 +921,7 @@
 
 	/* initialize data */
 	s->socket_dev = dev;
-	s->removal.data = s->socket_no;
-	s->removal.function = &handle_removal;
-	init_timer(&s->removal);
+	INIT_WORK(&s->removal, handle_removal, s);
     
 	/* Set up hotline to Card Services */
 	client_reg.dev_info = bind.dev_info = &dev_info;
@@ -986,6 +983,8 @@
 	if (!cls_d)
 		return -ENODEV;
 
+	flush_scheduled_work();
+
 	down_write(&bus_socket_list_rwsem);
 	list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
 		struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list);
diff -urN linux-2.5.66-bk5/drivers/pcmcia/hd64465_ss.c linux-2.5.66-bk6/drivers/pcmcia/hd64465_ss.c
--- linux-2.5.66-bk5/drivers/pcmcia/hd64465_ss.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/hd64465_ss.c	Mon Mar 31 12:52:29 2003
@@ -968,6 +968,8 @@
 	.name = "hd64465-pcmcia",
 	.bus = &platform_bus_type,
 	.devclass = &pcmcia_socket_class,
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device hd64465_device = {
diff -urN linux-2.5.66-bk5/drivers/pcmcia/i82092.c linux-2.5.66-bk6/drivers/pcmcia/i82092.c
--- linux-2.5.66-bk5/drivers/pcmcia/i82092.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/i82092.c	Mon Mar 31 12:52:29 2003
@@ -42,11 +42,23 @@
 };
 MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
 
+static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state)
+{
+	return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
+}
+
+static int i82092aa_socket_resume (struct pci_dev *dev)
+{
+	return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
+}
+
 static struct pci_driver i82092aa_pci_drv = {
 	.name           = "i82092aa",
 	.id_table       = i82092aa_pci_ids,
 	.probe          = i82092aa_pci_probe,
 	.remove         = __devexit_p(i82092aa_pci_remove),
+	.suspend        = i82092aa_socket_suspend,
+	.resume         = i82092aa_socket_resume,
 	.driver		= {
 		.devclass = &pcmcia_socket_class,
 	},
@@ -302,11 +314,6 @@
 		return 0;
 }
     
-static int to_ns(int cycles)
-{
-	return cycle_time*cycles;
-}
-
 
 /* Interrupt handler functionality */
 
diff -urN linux-2.5.66-bk5/drivers/pcmcia/i82365.c linux-2.5.66-bk6/drivers/pcmcia/i82365.c
--- linux-2.5.66-bk5/drivers/pcmcia/i82365.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/i82365.c	Mon Mar 31 12:52:29 2003
@@ -1511,6 +1511,8 @@
 	.name = "i82365",
 	.bus = &platform_bus_type,
 	.devclass = &pcmcia_socket_class,
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device i82365_device = {
diff -urN linux-2.5.66-bk5/drivers/pcmcia/pci_socket.c linux-2.5.66-bk6/drivers/pcmcia/pci_socket.c
--- linux-2.5.66-bk5/drivers/pcmcia/pci_socket.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/pci_socket.c	Mon Mar 31 12:52:29 2003
@@ -31,10 +31,6 @@
 #include "pci_socket.h"
 
 
-extern void pcmcia_suspend_socket (struct socket_info_t *socket);
-extern void pcmcia_resume_socket (struct socket_info_t *socket);
-
-
 /*
  * Arbitrary define. This is the array of active cardbus
  * entries.
@@ -157,7 +153,6 @@
 	socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses
 			     this yet */
 	socket->cls_d.ops = &pci_socket_operations;
-	socket->cls_d.use_bus_pm = 1;
 	dev->dev.class_data = &socket->cls_d;
 
 	/* prepare pci_socket_t */
@@ -204,18 +199,12 @@
 
 static int cardbus_suspend (struct pci_dev *dev, u32 state)
 {
-	pci_socket_t *socket = pci_get_drvdata(dev);
-	if (socket && socket->cls_d.s_info)
-		pcmcia_suspend_socket (socket->cls_d.s_info);
-	return 0;
+	return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
 }
 
 static int cardbus_resume (struct pci_dev *dev)
 {
-	pci_socket_t *socket = pci_get_drvdata(dev);
-	if (socket && socket->cls_d.s_info)
-		pcmcia_resume_socket (socket->cls_d.s_info);
-	return 0;
+	return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
 }
 
 
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100.h linux-2.5.66-bk6/drivers/pcmcia/sa1100.h
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100.h	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100.h	Mon Mar 31 12:52:29 2003
@@ -152,36 +152,6 @@
 
 struct pcmcia_low_level;
 
-/* This structure encapsulates per-socket state which we might need to
- * use when responding to a Card Services query of some kind.
- */
-struct sa1100_pcmcia_socket {
-  /*
-   * Core PCMCIA state
-   */
-  int			nr;
-  struct resource	res;
-  socket_state_t        cs_state;
-  pccard_io_map         io_map[MAX_IO_WIN];
-  pccard_mem_map        pc_mem_map[MAX_WIN];
-  void                  (*handler)(void *, unsigned int);
-  void                  *handler_info;
-
-  struct pcmcia_state   k_state;
-  ioaddr_t              phys_attr, phys_mem;
-  void			*virt_io;
-  unsigned short        speed_io, speed_attr, speed_mem;
-
-  /*
-   * Info from low level handler
-   */
-  unsigned int          irq;
-  unsigned int		irq_state;
-
-  struct pcmcia_low_level *ops;
-};
-
-
 /* I/O pins replacing memory pins
  * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
  *
@@ -191,59 +161,4 @@
 #define iostschg bvd1
 #define iospkr   bvd2
 
-
-/*
- * Declaration for all machine specific init/exit functions.
- */
-extern int pcmcia_adsbitsy_init(struct device *);
-extern void pcmcia_adsbitsy_exit(struct device *);
-
-extern int pcmcia_assabet_init(struct device *);
-extern void pcmcia_assabet_exit(struct device *);
-
-extern int pcmcia_badge4_init(struct device *);
-extern void pcmcia_badge4_exit(struct device *);
-
-extern int pcmcia_cerf_init(struct device *);
-extern void pcmcia_cerf_exit(struct device *);
-
-extern int pcmcia_flexanet_init(struct device *);
-extern void pcmcia_flexanet_exit(struct device *);
-
-extern int pcmcia_freebird_init(struct device *);
-extern void pcmcia_freebird_exit(struct device *);
-
-extern int pcmcia_gcplus_init(struct device *);
-extern void pcmcia_gcplus_exit(struct device *);
-
-extern int pcmcia_graphicsmaster_init(struct device *);
-extern void pcmcia_graphicsmaster_exit(struct device *);
-
-extern int pcmcia_pangolin_init(struct device *);
-extern void pcmcia_pangolin_exit(struct device *);
-
-extern int pcmcia_pfs168_init(struct device *);
-extern void pcmcia_pfs168_exit(struct device *);
-
-extern int pcmcia_shannon_init(struct device *);
-extern void pcmcia_shannon_exit(struct device *);
-
-extern int pcmcia_simpad_init(struct device *);
-extern void pcmcia_simpad_exit(struct device *);
-
-extern int pcmcia_stork_init(struct device *);
-extern void pcmcia_stork_exit(struct device *);
-
-extern int pcmcia_system3_init(struct device *);
-extern void pcmcia_system3_exit(struct device *);
-
-extern int pcmcia_trizeps_init(struct device *);
-extern void pcmcia_trizeps_exit(struct device *);
-
-extern int pcmcia_xp860_init(struct device *);
-extern void pcmcia_xp860_exit(struct device *);
-
-extern int pcmcia_yopy_init(struct device *);
-extern void pcmcia_yopy_exit(struct device *);
-
 #endif  /* !defined(_PCMCIA_SA1100_H) */
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_adsbitsy.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_adsbitsy.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_adsbitsy.c	Mon Mar 24 14:01:52 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_adsbitsy.c	Mon Mar 31 12:52:29 2003
@@ -18,93 +18,86 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
-static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
+static int adsbitsy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
-  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+	/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+	PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  /* Disable Power 3.3V/5V for PCMCIA/CF */
-  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
+	/* Disable Power 3.3V/5V for PCMCIA/CF */
+	PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-  /* Why? */			 
-  MECR = 0x09430943;
+	/* Why? */			 
+	MECR = 0x09430943;
 
-  return sa1111_pcmcia_init(init);
+	return sa1111_pcmcia_init(skt);
 }
 
 static int
-adsbitsy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+adsbitsy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
-  unsigned int pa_dwr_mask, pa_dwr_set;
-  int ret;
+	unsigned int pa_dwr_mask, pa_dwr_set;
+	int ret;
 
-  switch (sock) {
-  case 0:
-    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
-
-    switch (conf->vcc) {
-    default:
-    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
-    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
-    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
-    }
-    break;
-
-  case 1:
-    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
-
-    switch (conf->vcc) {
-    default:
-    case 0:	pa_dwr_set = 0;				break;
-    case 33:	pa_dwr_set = GPIO_GPIO2;		break;
-    case 50:	pa_dwr_set = GPIO_GPIO3;		break;
-    }
-
-  default:
-    return -1;
-  }
-
-  if (conf->vpp != conf->vcc && conf->vpp != 0) {
-    printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-		__FUNCTION__, conf->vpp);
-    return -1;
-  }
-
-  ret = sa1111_pcmcia_configure_socket(sock, conf);
-  if (ret == 0) {
-    unsigned long flags;
-
-    local_irq_save(flags);
-    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
-    local_irq_restore(flags);
-  }
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+
+		switch (state->Vcc) {
+		default:
+		case 0:  pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+		case 33: pa_dwr_set = GPIO_GPIO1;		break;
+		case 50: pa_dwr_set = GPIO_GPIO0;		break;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+
+		switch (state->Vcc) {
+		default:
+		case 0:  pa_dwr_set = 0;			break;
+		case 33: pa_dwr_set = GPIO_GPIO2;		break;
+		case 50: pa_dwr_set = GPIO_GPIO3;		break;
+		}
+
+	default:
+		return -1;
+	}
+
+	if (state->Vpp != state->Vcc && state->Vpp != 0) {
+		printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+			__FUNCTION__, state->Vpp);
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+		local_irq_restore(flags);
+	}
 
-  return ret;
+	return ret;
 }
 
 static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
-  .owner		= THIS_MODULE,
-  .init			= adsbitsy_pcmcia_init,
-  .shutdown		= sa1111_pcmcia_shutdown,
-  .socket_state		= sa1111_pcmcia_socket_state,
-  .configure_socket	= adsbitsy_pcmcia_configure_socket,
-
-  .socket_init		= sa1111_pcmcia_socket_init,
-  .socket_suspend	= sa1111_pcmcia_socket_suspend,
+	.owner			= THIS_MODULE,
+	.hw_init		= adsbitsy_pcmcia_hw_init,
+	.hw_shutdown		= sa1111_pcmcia_hw_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.configure_socket	= adsbitsy_pcmcia_configure_socket,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_adsbitsy_init(struct device *dev)
 {
 	int ret = -ENODEV;
 	if (machine_is_adsbitsy())
-		ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &adsbitsy_pcmcia_ops, 0, 2);
 	return ret;
 }
-
-void __exit pcmcia_adsbitsy_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_assabet.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_assabet.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_assabet.c	Mon Mar 24 14:01:16 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_assabet.c	Mon Mar 31 12:52:29 2003
@@ -20,85 +20,47 @@
 
 #include "sa1100_generic.h"
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ ASSABET_IRQ_GPIO_CF_CD,   "CF_CD"   },
-	{ ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
-	{ ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" },
+static struct pcmcia_irqs irqs[] = {
+	{ 1, ASSABET_IRQ_GPIO_CF_CD,   "CF CD"   },
+	{ 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" },
+	{ 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" },
 };
 
-static int assabet_pcmcia_init(struct pcmcia_init *init)
+static int assabet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i, res;
+	skt->irq = ASSABET_IRQ_GPIO_CF_IRQ;
 
-	/* Register interrupts */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (res)
-			goto irq_err;
-		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-	}
-
-	init->socket_irq[0] = NO_IRQ;
-	init->socket_irq[1] = ASSABET_IRQ_GPIO_CF_IRQ;
-
-	/* There's only one slot, but it's "Slot 1": */
-	return 2;
-
- irq_err:
-	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-		__FUNCTION__, irqs[i].irq, res);
-
-	while (i--)
-		free_irq(irqs[i].irq, NULL);
-
-	return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 /*
  * Release all resources.
  */
-static int assabet_pcmcia_shutdown(void)
+static void assabet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		free_irq(irqs[i].irq, NULL);
-  
-	return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static void
-assabet_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+assabet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
 	unsigned long levels = GPLR;
 
-	if (sock == 1) {
-		state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
-		state->ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
-		state->bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
-		state->bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
-		state->wrprot = 0; /* Not available on Assabet. */
-		state->vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
-		state->vs_Xv  = 0;
-	}
+	state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
+	state->ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
+	state->bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
+	state->bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
+	state->wrprot = 0; /* Not available on Assabet. */
+	state->vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
+	state->vs_Xv  = 0;
 }
 
 static int
-assabet_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure)
+assabet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
 	unsigned int mask;
 
-	if (sock > 1)
-		return -1;
-
-	if (sock == 0)
-		return 0;
-
-	switch (configure->vcc) {
+	switch (state->Vcc) {
 	case 0:
 		mask = 0;
 		break;
@@ -113,13 +75,13 @@
 
 	default:
 		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-			configure->vcc);
+			state->Vcc);
 		return -1;
 	}
 
 	/* Silently ignore Vpp, output enable, speaker enable. */
 
-	if (configure->reset)
+	if (state->flags & SS_RESET)
 		mask |= ASSABET_BCR_CF_RST;
 
 	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
@@ -132,48 +94,36 @@
  * be called at initialisation, power management event, or
  * pcmcia event.
  */
-static int assabet_pcmcia_socket_init(int sock)
+static void assabet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	if (sock == 1) {
-		/*
-		 * Enable CF bus
-		 */
-		ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
+	/*
+	 * Enable CF bus
+	 */
+	ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
 
-		for (i = 0; i < ARRAY_SIZE(irqs); i++)
-			set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
-	}
-
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 /*
  * Disable card status IRQs on suspend.
  */
-static int assabet_pcmcia_socket_suspend(int sock)
+static void assabet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	if (sock == 1) {
-		for (i = 0; i < ARRAY_SIZE(irqs); i++)
-			set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-
-		/*
-		 * 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);
-	}
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 
-	return 0;
+	/*
+	 * 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,
-	.init			= assabet_pcmcia_init,
-	.shutdown		= assabet_pcmcia_shutdown,
+
+	.hw_init		= assabet_pcmcia_hw_init,
+	.hw_shutdown		= assabet_pcmcia_hw_shutdown,
+
 	.socket_state		= assabet_pcmcia_socket_state,
 	.configure_socket	= assabet_pcmcia_configure_socket,
 
@@ -185,20 +135,8 @@
 {
 	int ret = -ENODEV;
 
-	if (machine_is_assabet()) {
-		if (!machine_has_neponset())
-			ret = sa1100_register_pcmcia(&assabet_pcmcia_ops, dev);
-#ifndef CONFIG_ASSABET_NEPONSET
-		else
-			printk(KERN_ERR "Card Services disabled: missing "
-				"Neponset support\n");
-#endif
-	}
-	return ret;
-}
+	if (machine_is_assabet() && !machine_has_neponset())
+		ret = sa11xx_drv_pcmcia_probe(dev, &assabet_pcmcia_ops, 1, 1);
 
-void __exit pcmcia_assabet_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&assabet_pcmcia_ops, dev);
+	return ret;
 }
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_badge4.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_badge4.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_badge4.c	Mon Mar 24 14:00:08 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_badge4.c	Mon Mar 31 12:52:29 2003
@@ -24,7 +24,6 @@
 #include <asm/arch/badge4.h>
 #include <asm/hardware/sa1111.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
 /*
@@ -62,27 +61,6 @@
 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 int badge4_pcmcia_init(struct pcmcia_init *init)
-{
-	printk(KERN_INFO
-	       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
-	       __FUNCTION__,
-	       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
-
-	return sa1111_pcmcia_init(init);
-}
-
-static int badge4_pcmcia_shutdown(void)
-{
-	int rc = sa1111_pcmcia_shutdown();
-
-	/* be sure to disable 5v0 use */
-	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
-	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
-
-	return rc;
-}
-
 static void complain_about_jumpering(const char *whom,
 				     const char *supply,
 				     int given, int wanted)
@@ -97,32 +75,32 @@
 }
 
 static int
-badge4_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+badge4_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
 	int ret;
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
-		if ((conf->vcc != 0) &&
-		    (conf->vcc != badge4_pcmvcc)) {
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_pcmvcc)) {
 			complain_about_jumpering(__FUNCTION__, "pcmvcc",
-						 badge4_pcmvcc, conf->vcc);
+						 badge4_pcmvcc, state->Vcc);
 			// Apply power regardless of the jumpering.
 			// return -1;
 		}
-		if ((conf->vpp != 0) &&
-		    (conf->vpp != badge4_pcmvpp)) {
+		if ((state->Vpp != 0) &&
+		    (state->Vpp != badge4_pcmvpp)) {
 			complain_about_jumpering(__FUNCTION__, "pcmvpp",
-						 badge4_pcmvpp, conf->vpp);
+						 badge4_pcmvpp, state->Vpp);
 			return -1;
 		}
 		break;
 
 	case 1:
-		if ((conf->vcc != 0) &&
-		    (conf->vcc != badge4_cfvcc)) {
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_cfvcc)) {
 			complain_about_jumpering(__FUNCTION__, "cfvcc",
-						 badge4_cfvcc, conf->vcc);
+						 badge4_cfvcc, state->Vcc);
 			return -1;
 		}
 		break;
@@ -131,16 +109,16 @@
 		return -1;
 	}
 
-	ret = sa1111_pcmcia_configure_socket(sock, conf);
+	ret = sa1111_pcmcia_configure_socket(skt, state);
 	if (ret == 0) {
 		unsigned long flags;
 		int need5V;
 
 		local_irq_save(flags);
 
-		need5V = ((conf->vcc == 50) || (conf->vpp == 50));
+		need5V = ((state->Vcc == 50) || (state->Vpp == 50));
 
-		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
+		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
 
 		local_irq_restore(flags);
 	}
@@ -150,8 +128,8 @@
 
 static struct pcmcia_low_level badge4_pcmcia_ops = {
 	.owner			= THIS_MODULE,
-	.init			= badge4_pcmcia_init,
-	.shutdown		= badge4_pcmcia_shutdown,
+	.init			= sa1111_pcmcia_hw_init,
+	.shutdown		= sa1111_pcmcia_hw_shutdown,
 	.socket_state		= sa1111_pcmcia_socket_state,
 	.configure_socket	= badge4_pcmcia_configure_socket,
 
@@ -163,15 +141,16 @@
 {
 	int ret = -ENODEV;
 
-	if (machine_is_badge4())
-		ret = sa1100_register_pcmcia(&badge4_pcmcia_ops, dev);
+	if (machine_is_badge4()) {
+		printk(KERN_INFO
+		       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+		       __FUNCTION__,
+		       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
 
-	return ret;
-}
+		ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2);
+	}
 
-void __devexit pcmcia_badge4_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&badge4_pcmcia_ops, dev);
+	return ret;
 }
 
 static int __init pcmv_setup(char *s)
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_cerf.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_cerf.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_cerf.c	Mon Mar 24 14:01:26 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_cerf.c	Mon Mar 31 12:52:29 2003
@@ -23,139 +23,91 @@
 #define CERF_SOCKET	1
 #endif
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_GPIO_CF_CD,   "CF_CD"   },
-	{ IRQ_GPIO_CF_BVD2, "CF_BVD2" },
-	{ IRQ_GPIO_CF_BVD1, "CF_BVD1" }
+static struct pcmcia_irqs irqs[] = {
+	{ CERF_SOCKET, IRQ_GPIO_CF_CD,   "CF_CD"   },
+	{ CERF_SOCKET, IRQ_GPIO_CF_BVD2, "CF_BVD2" },
+	{ CERF_SOCKET, IRQ_GPIO_CF_BVD1, "CF_BVD1" }
 };
 
-static int cerf_pcmcia_init(struct pcmcia_init *init)
+static int cerf_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-  int i, res;
+	skt->irq = IRQ_GPIO_CF_IRQ;
 
-  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-    res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT,
-		      irqs[i].str, NULL);
-    if (res)
-      goto irq_err;
-    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-  }
-
-  init->socket_irq[CERF_SOCKET] = IRQ_GPIO_CF_IRQ;
-
-  return 2;
-
- irq_err:
-  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	 __FUNCTION__, irqs[i].irq, res);
-
-  while (i--)
-    free_irq(irqs[i].irq, NULL);
-
-  return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int cerf_pcmcia_shutdown(void)
+static void cerf_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  int i;
-
-  for (i = 0; i < ARRAY_SIZE(irqs); i++)
-    free_irq(irqs[i].irq, NULL);
-
-  return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static void cerf_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+cerf_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-  unsigned long levels=GPLR;
+	unsigned long levels = GPLR;
 
-  if (sock == CERF_SOCKET) {
-    state->detect=((levels & GPIO_CF_CD)==0)?1:0;
-    state->ready=(levels & GPIO_CF_IRQ)?1:0;
-    state->bvd1=(levels & GPIO_CF_BVD1)?1:0;
-    state->bvd2=(levels & GPIO_CF_BVD2)?1:0;
-    state->wrprot=0;
-    state->vs_3v=1;
-    state->vs_Xv=0;
-  }
+	state->detect=((levels & GPIO_CF_CD)==0)?1:0;
+	state->ready=(levels & GPIO_CF_IRQ)?1:0;
+	state->bvd1=(levels & GPIO_CF_BVD1)?1:0;
+	state->bvd2=(levels & GPIO_CF_BVD2)?1:0;
+	state->wrprot=0;
+	state->vs_3v=1;
+	state->vs_Xv=0;
 }
 
-static int cerf_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+cerf_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			     const socket_state_t *state)
 {
-  if (sock>1)
-    return -1;
-
-  if (sock != CERF_SOCKET)
-    return 0;
+	switch (state->Vcc) {
+	case 0:
+		break;
 
-  switch(configure->vcc){
-  case 0:
-    break;
-
-  case 50:
-  case 33:
+	case 50:
+	case 33:
 #ifdef CONFIG_SA1100_CERF_CPLD
-     GPCR = GPIO_PWR_SHUTDOWN;
+		GPCR = GPIO_PWR_SHUTDOWN;
 #endif
-     break;
+		break;
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    return -1;
-  }
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__FUNCTION__, state->Vcc);
+		return -1;
+	}
 
-  if(configure->reset)
-  {
+	if (state->flags & SS_RESET) {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPSR = GPIO_CF_RESET;
+		GPSR = GPIO_CF_RESET;
 #endif
-  }
-  else
-  {
+	} else {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPCR = GPIO_CF_RESET;
+		GPCR = GPIO_CF_RESET;
 #endif
-  }
+	}
 
-  return 0;
+	return 0;
 }
 
-static int cerf_pcmcia_socket_init(int sock)
+static void cerf_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  int i;
-
-  if (sock == CERF_SOCKET)
-    for (i = 0; i < ARRAY_SIZE(irqs); i++)
-      set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
-
-  return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int cerf_pcmcia_socket_suspend(int sock)
+static void cerf_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  int i;
-
-  if (sock == CERF_SOCKET)
-    for (i = 0; i < ARRAY_SIZE(irqs); i++)
-      set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-
-  return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level cerf_pcmcia_ops = { 
-  .owner		= THIS_MODULE,
-  .init			= cerf_pcmcia_init,
-  .shutdown		= cerf_pcmcia_shutdown,
-  .socket_state		= cerf_pcmcia_socket_state,
-  .configure_socket	= cerf_pcmcia_configure_socket,
+	.owner			= THIS_MODULE,
+	.init			= cerf_pcmcia_hw_init,
+	.shutdown		= cerf_pcmcia_hw_shutdown,
+	.socket_state		= cerf_pcmcia_socket_state,
+	.configure_socket	= cerf_pcmcia_configure_socket,
 
-  .socket_init		= cerf_pcmcia_socket_init,
-  .socket_suspend	= cerf_pcmcia_socket_suspend,
+	.socket_init		= cerf_pcmcia_socket_init,
+	.socket_suspend		= cerf_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_cerf_init(struct device *dev)
@@ -163,12 +115,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_cerf())
-		ret = sa1100_register_pcmcia(&cerf_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &cerf_pcmcia_ops, CERF_SOCKET, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_cerf_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&cerf_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_flexanet.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_flexanet.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_flexanet.c	Mon Mar 24 14:00:37 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_flexanet.c	Mon Mar 31 12:52:29 2003
@@ -16,69 +16,32 @@
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
-static struct {
-  int irq;
-  const char *name;
-} irqs[] = {
-  { IRQ_GPIO_CF1_CD,   "CF1_CD"   },
-  { IRQ_GPIO_CF1_BVD1, "CF1_BVD1" },
-  { IRQ_GPIO_CF2_CD,   "CF2_CD"   },
-  { IRQ_GPIO_CF2_BVD1, "CF2_BVD1" }
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO_CF1_CD,   "CF1_CD"   },
+	{ 0, IRQ_GPIO_CF1_BVD1, "CF1_BVD1" },
+	{ 1, IRQ_GPIO_CF2_CD,   "CF2_CD"   },
+	{ 1, IRQ_GPIO_CF2_BVD1, "CF2_BVD1" }
 };
 
 /*
  * Socket initialization.
  *
  * Called by sa1100_pcmcia_driver_init on startup.
- * Must return the number of slots.
- *
  */
-static int flexanet_pcmcia_init(struct pcmcia_init *init)
+static int flexanet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-  int i, res;
-
-  /* Configure the GPIOs as inputs (BVD2 is not implemented) */
-  GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
-            GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
-
-  /* Register the socket interrupts (not the card interrupts) */
-  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-    res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT,
-		      irqs[i].name, NULL);
-    if (res < 0)
-      break;
-    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-  }
-
-  init->socket_irq[0] = IRQ_GPIO_CF1_IRQ;
-  init->socket_irq[1] = IRQ_GPIO_CF2_IRQ;
-
-  /* If we failed, then free all interrupts requested thus far. */
-  if (res < 0) {
-    printk(KERN_ERR "%s: request for IRQ%d failed: %d\n",
-	   __FUNCTION__, irqs[i].irq, res);
-    while (i--)
-      free_irq(irqs[i].irq, NULL);
-    return res;
-  }
+	skt->irq = skt->nr ? IRQ_GPIO_CF2_IRQ : IRQ_GPIO_CF1_IRQ;
 
-  return 2;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 
 /*
  * Socket shutdown
- *
  */
-static int flexanet_pcmcia_shutdown(void)
+static void flexanet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  int i;
-
-  /* disable IRQs */
-  for (i = 0; i < ARRAY_SIZE(irqs); i++)
-    free_irq(irqs[i].irq, NULL);
-
-  return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 
@@ -88,109 +51,96 @@
  *  Sockets in Flexanet are 3.3V only, without BVD2.
  *
  */
-static void flexanet_pcmcia_socket_state(int sock, struct pcmcia_state *state)
-{
-  unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */
-
-  switch (sock) {
-  case 0: /* Socket 0 */
-    state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
-    state->ready  = (levels & GPIO_CF1_IRQ)?1:0;
-    state->bvd1   = (levels & GPIO_CF1_BVD1)?1:0;
-    state->bvd2   = 1;
-    state->wrprot = 0;
-    state->vs_3v  = 1;
-    state->vs_Xv  = 0;
-    break;
-
-  case 1: /* Socket 1 */
-    state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
-    state->ready  = (levels & GPIO_CF2_IRQ)?1:0;
-    state->bvd1   = (levels & GPIO_CF2_BVD1)?1:0;
-    state->bvd2   = 1;
-    state->wrprot = 0;
-    state->vs_3v  = 1;
-    state->vs_Xv  = 0;
-    break;
-  }
+static void
+flexanet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			     struct pcmcia_state *state)
+{
+	unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */
+
+	switch (skt->nr) {
+	ase 0: /* Socket 0 */
+		state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
+		state->ready  = (levels & GPIO_CF1_IRQ)?1:0;
+		state->bvd1   = (levels & GPIO_CF1_BVD1)?1:0;
+		state->bvd2   = 1;
+		state->wrprot = 0;
+		state->vs_3v  = 1;
+		state->vs_Xv  = 0;
+		break;
+
+	case 1: /* Socket 1 */
+		state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
+		state->ready  = (levels & GPIO_CF2_IRQ)?1:0;
+		state->bvd1   = (levels & GPIO_CF2_BVD1)?1:0;
+		state->bvd2   = 1;
+		state->wrprot = 0;
+		state->vs_3v  = 1;
+		state->vs_Xv  = 0;
+		break;
+	}
 }
 
 
 /*
  *
  */
-static int flexanet_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+flexanet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				 const socket_state_t *state)
 {
-  unsigned long value, flags, mask;
-
-  if (sock > 1)
-    return -1;
+	unsigned long value, flags, mask;
 
-  /* Ignore the VCC level since it is 3.3V and always on */
-  switch (configure->vcc)
-  {
-    case 0:
-      printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
-      break;
+	/* Ignore the VCC level since it is 3.3V and always on */
+	switch (state->Vcc) {
+	case 0:
+		printk(KERN_WARNING "%s(): CS asked to power off.\n",
+			__FUNCTION__);
+		break;
 
-    case 50:
-      printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-  	   __FUNCTION__);
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__FUNCTION__);
 
-    case 33:
-      break;
+	case 33:
+		break;
 
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-  	   configure->vcc);
-      return -1;
-  }
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+		       state->Vcc);
+		return -1;
+	}
 
-  /* Reset the slot(s) using the controls in the BCR */
-  mask = 0;
+	/* Reset the slot(s) using the controls in the BCR */
+	mask = 0;
 
-  switch (sock)
-  {
-    case 0 : mask = FHH_BCR_CF1_RST; break;
-    case 1 : mask = FHH_BCR_CF2_RST; break;
-  }
+	switch (skt->nr) {
+	case 0:
+		mask = FHH_BCR_CF1_RST;
+		break;
+	case 1:
+		mask = FHH_BCR_CF2_RST;
+		break;
+	}
 
-  local_irq_save(flags);
+	local_irq_save(flags);
 
-  value = flexanet_BCR;
-  value = (configure->reset) ? (value | mask) : (value & ~mask);
-  FHH_BCR = flexanet_BCR = value;
+	value = flexanet_BCR;
+	value = (state->flags & SS_RESET) ? (value | mask) : (value & ~mask);
+	FHH_BCR = flexanet_BCR = value;
 
-  local_irq_restore(flags);
+	local_irq_restore(flags);
 
-  return 0;
+	return 0;
 }
 
-static int flexanet_pcmcia_socket_init(int sock)
+static void flexanet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 0) {
-    set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE);
-    set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE);
-  } else if (sock == 1) {
-    set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE);
-    set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE);
-  }
-
-  return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int flexanet_pcmcia_socket_suspend(int sock)
+static void flexanet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 0) {
-    set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE);
-    set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE);
-  } else if (sock == 1) {
-    set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE);
-    set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE);
-  }
-
-  return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 /*
@@ -198,14 +148,13 @@
  *
  */
 static struct pcmcia_low_level flexanet_pcmcia_ops = {
-  .owner		= THIS_MODULE,
-  .init			= flexanet_pcmcia_init,
-  .shutdown		= flexanet_pcmcia_shutdown,
-  .socket_state		= flexanet_pcmcia_socket_state,
-  .configure_socket	= flexanet_pcmcia_configure_socket,
-
-  .socket_init		= flexanet_pcmcia_socket_init,
-  .socket_suspend	= flexanet_pcmcia_socket_suspend,
+	.owner			= THIS_MODULE,
+	.hw_init		= flexanet_pcmcia_hw_init,
+	.hw_shutdown		= flexanet_pcmcia_hw_shutdown,
+	.socket_state		= flexanet_pcmcia_socket_state,
+	.configure_socket	= flexanet_pcmcia_configure_socket,
+	.socket_init		= flexanet_pcmcia_socket_init,
+	.socket_suspend		= flexanet_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_flexanet_init(struct device *dev)
@@ -213,13 +162,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_flexanet())
-		ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &flexanet_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_flexanet_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&flexanet_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_freebird.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_freebird.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_freebird.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_freebird.c	Mon Mar 31 12:52:29 2003
@@ -15,155 +15,113 @@
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_GPIO_FREEBIRD_CF_CD,  "CF_CD"   },
-	{ IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" },
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO_FREEBIRD_CF_CD,  "CF_CD"   },
+	{ 0, IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" },
 };
 
-static int freebird_pcmcia_init(struct pcmcia_init *init){
-  int i, res;
-
-  /* Enable Linkup CF card */
-  LINKUP_PRC = 0xc0;
-  mdelay(100);
-  LINKUP_PRC = 0xc1;
-  mdelay(100);
-  LINKUP_PRC = 0xd1;
-  mdelay(100);
-  LINKUP_PRC = 0xd1;
-  mdelay(100);
-  LINKUP_PRC = 0xc0;
-
-  /* Register interrupts */
-  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-    res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT,
-    		      irqs[i].str, NULL);
-    if (res)
-      goto irq_err;
-    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-  }
-
-  init->socket_irq[0] = IRQ_GPIO_FREEBIRD_CF_IRQ;
-
-  /* There's only one slot, but it's "Slot 1": */
-  return 2;
-
-irq_err:
-  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	 __FUNCTION__, irqs[i].irq, res);
+static int freebird_pcmcia_init(struct sa1100_pcmcia_socket *skt)
+{
+	/* Enable Linkup CF card */
+	LINKUP_PRC = 0xc0;
+	mdelay(100);
+	LINKUP_PRC = 0xc1;
+	mdelay(100);
+	LINKUP_PRC = 0xd1;
+	mdelay(100);
+	LINKUP_PRC = 0xd1;
+	mdelay(100);
+	LINKUP_PRC = 0xc0;
 
-  while (i--)
-    free_irq(irqs[i].irq, NULL);
+	skt->irq = IRQ_GPIO_FREEBIRD_CF_IRQ;
 
-  return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int freebird_pcmcia_shutdown(void)
+static void freebird_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  int i;
-
-  /* disable IRQs */
-  for (i = 0; i < ARRAY_SIZE(irqs); i++)
-    free_irq(irqs[i].irq, NULL);
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs);
 
-  /* Disable CF card */
-  LINKUP_PRC = 0x40;  /* SSP=1   SOE=0 */
-  mdelay(100);
-
-  return 0;
+	/* Disable CF card */
+	LINKUP_PRC = 0x40;  /* SSP=1   SOE=0 */
+	mdelay(100);
 }
 
-static void freebird_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+freebird_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-  unsigned long levels = LINKUP_PRS;
-//printk("LINKUP_PRS=%x\n",levels);
+	unsigned long levels = LINKUP_PRS;
+//	printk("LINKUP_PRS=%x\n",levels);
 
-  if (sock == 0) {
-    state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
-    state->ready  = (levels & LINKUP_RDY)?1:0;
-    state->bvd1   = (levels & LINKUP_BVD1)?1:0;
-    state->bvd2   = (levels & LINKUP_BVD2)?1:0;
-    state->wrprot = 0; /* Not available on Assabet. */
-    state->vs_3v  = 1;  /* Can only apply 3.3V on Assabet. */
-    state->vs_Xv  = 0;
-  }
+	state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
+	state->ready  = (levels & LINKUP_RDY)?1:0;
+	state->bvd1   = (levels & LINKUP_BVD1)?1:0;
+	state->bvd2   = (levels & LINKUP_BVD2)?1:0;
+	state->wrprot = 0; /* Not available on Assabet. */
+	state->vs_3v  = 1;  /* Can only apply 3.3V on Assabet. */
+	state->vs_Xv  = 0;
 }
 
-static int freebird_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+freebird_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				 socket_state_t *state)
 {
-  unsigned long value, flags;
-
-  if(sock>1) return -1;
-
-  if(sock==1) return 0;
-
-  local_irq_save(flags);
+	unsigned long value, flags;
 
-  value = 0xc0;   /* SSP=1  SOE=1  CFE=1 */
+	local_irq_save(flags);
 
-  switch(configure->vcc){
-  case 0:
+	value = 0xc0;   /* SSP=1  SOE=1  CFE=1 */
 
-    break;
+	switch (state->Vcc) {
+	case 0:
+		break;
 
-  case 50:
-    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-	   __FUNCTION__);
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__FUNCTION__);
 
-  case 33:  /* Can only apply 3.3V to the CF slot. */
-    value |= LINKUP_S1;
-    break;
+	case 33:  /* Can only apply 3.3V to the CF slot. */
+		value |= LINKUP_S1;
+		break;
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    local_irq_restore(flags);
-    return -1;
-  }
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__FUNCTION__, state->Vcc);
+		local_irq_restore(flags);
+		return -1;
+	}
 
-  if (configure->reset)
-  value = (configure->reset) ? (value | LINKUP_RESET) : (value & ~LINKUP_RESET);
+	if (state->flags & SS_RESET)
+		value |= LINKUP_RESET;
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	/* Silently ignore Vpp, output enable, speaker enable. */
 
-  LINKUP_PRC = value;
-//printk("LINKUP_PRC=%x\n",value);
-  local_irq_restore(flags);
+	LINKUP_PRC = value;
+//	printk("LINKUP_PRC=%x\n",value);
+	local_irq_restore(flags);
 
-  return 0;
+	return 0;
 }
 
-static int freebird_pcmcia_socket_init(int sock)
+static void freebird_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 1) {
-    set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
-    set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
-  }
-  return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int freebird_pcmcia_socket_suspend(int sock)
+static void freebird_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 1) {
-    set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE);
-    set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE);
-  }
-  return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level freebird_pcmcia_ops = {
-  .owner		= THIS_MODULE,
-  .init			= freebird_pcmcia_init,
-  .shutdown		= freebird_pcmcia_shutdown,
-  .socket_state		= freebird_pcmcia_socket_state,
-  .configure_socket	= freebird_pcmcia_configure_socket,
+	.owner			= THIS_MODULE,
+	.hw_init		= freebird_pcmcia_hw_init,
+	.hw_shutdown		= freebird_pcmcia_hw_shutdown,
+	.socket_state		= freebird_pcmcia_socket_state,
+	.configure_socket	= freebird_pcmcia_configure_socket,
 
-  .socket_init		= freebird_pcmcia_socket_init,
-  .socket_suspend	= freebird_pcmcia_socket_suspend,
+	.socket_init		= freebird_pcmcia_socket_init,
+	.socket_suspend		= freebird_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_freebird_init(struct device *dev)
@@ -171,12 +129,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_freebird())
-		ret = sa1100_register_pcmcia(&freebird_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &freebird_pcmcia_ops, 0, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_freebird_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&freebird_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_generic.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_generic.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_generic.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_generic.c	Mon Mar 31 12:52:29 2003
@@ -37,1118 +37,124 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/config.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/workqueue.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/arch/assabet.h>
-
 #include "sa1100.h"
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug;
-#endif
-
-/* This structure maintains housekeeping state for each socket, such
- * as the last known values of the card detect pins, or the Card Services
- * callback value associated with the socket:
- */
-static int sa1100_pcmcia_socket_count;
-static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
-
-#define PCMCIA_SOCKET(x)	(sa1100_pcmcia_socket + (x))
-
-/* Returned by the low-level PCMCIA interface: */
-static struct pcmcia_low_level *pcmcia_low_level;
-
-static struct timer_list poll_timer;
-static struct work_struct sa1100_pcmcia_task;
-
-/*
- * 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 manuial ;)
- */
-static unsigned int
-sa1100_pcmcia_default_mecr_timing(unsigned int sock, 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 sa1100_pcmcia_socket *skt, unsigned int cpu_clock)
-{
-	u32 mecr;
-	unsigned long flags;
-	unsigned int bs;
-
-	local_irq_save(flags);
-
-	bs = skt->ops->socket_get_timing(skt->nr, cpu_clock, skt->speed_io);
-
-	mecr = MECR;
-	MECR_FAST_SET(mecr, skt->nr, 0);
-	MECR_BSIO_SET(mecr, skt->nr, bs );
-	MECR_BSA_SET(mecr, skt->nr, bs );
-	MECR_BSM_SET(mecr, skt->nr, bs );
-	MECR = mecr;
-
-	local_irq_restore(flags);
-
-	DEBUG(4, "%s(): sock %u FAST %X  BSM %X  BSA %X  BSIO %X\n",
-	      __FUNCTION__, skt->nr, 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;
-}
-
-/*
- * sa1100_pcmcia_config_skt
- * ^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * Convert PCMCIA socket state to our socket configure structure.
- */
-static int
-sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state)
-{
-	struct pcmcia_configure conf;
-	int ret;
-
-	conf.vcc     = state->Vcc;
-	conf.vpp     = state->Vpp;
-	conf.output  = state->flags & SS_OUTPUT_ENA ? 1 : 0;
-	conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0;
-	conf.reset   = state->flags & SS_RESET ? 1 : 0;
-
-	ret = skt->ops->configure_socket(skt->nr, &conf);
-	if (ret == 0) {
-		/*
-		 * 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;
-			set_irq_type(skt->irq, IRQT_FALLING);
-		} else if (skt->irq_state == 1 && state->io_irq == 0) {
-		  	skt->irq_state = 0;
-			set_irq_type(skt->irq, IRQT_NOEDGE);
-		}
-
-		skt->cs_state = *state;
-	}
-
-	if (ret < 0)
-		printk(KERN_ERR "sa1100_pcmcia: unable to configure "
-		       "socket %d\n", skt->nr);
-
-	return ret;
-}
-
-/* sa1100_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 sa1100_pcmcia_sock_init(unsigned int sock)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-
-  DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
-
-  sa1100_pcmcia_config_skt(skt, &dead_socket);
-
-  return skt->ops->socket_init(skt->nr);
-}
-
-
-/*
- * sa1100_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 sa1100_pcmcia_suspend(unsigned int sock)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  int ret;
-
-  DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr);
-
-  ret = sa1100_pcmcia_config_skt(skt, &dead_socket);
-
-  if (ret == 0)
-    ret = skt->ops->socket_suspend(skt->nr);
-
-  return ret;
-}
-
-
-/* sa1100_pcmcia_events()
- * ^^^^^^^^^^^^^^^^^^^^^^
- * Helper routine to generate a Card Services event mask based on
- * state information obtained from the kernel low-level PCMCIA layer
- * in a recent (and previous) sampling. Updates `prev_state'.
- *
- * Returns: an event mask for the given socket state.
- */
-static inline unsigned int
-sa1100_pcmcia_events(struct pcmcia_state *state,
-		     struct pcmcia_state *prev_state,
-		     unsigned int mask, unsigned int flags)
-{
-  unsigned int events = 0;
-
-  if (state->detect != prev_state->detect) {
-    DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
-
-    events |= SS_DETECT;
-  }
-
-  if (state->ready != prev_state->ready) {
-    DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
-
-    events |= flags & SS_IOCARD ? 0 : SS_READY;
-  }
-
-  if (state->bvd1 != prev_state->bvd1) {
-    DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
-
-    events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD;
-  }
-
-  if (state->bvd2 != prev_state->bvd2) {
-    DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
-
-    events |= flags & SS_IOCARD ? 0 : SS_BATWARN;
-  }
-
-  *prev_state = *state;
-
-  events &= mask;
-
-  DEBUG(2, "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 "  : "");
-
-  return events;
-}  /* sa1100_pcmcia_events() */
-
-
-/* sa1100_pcmcia_task_handler()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Processes serviceable socket events using the "eventd" thread context.
- *
- * Event processing (specifically, the invocation of the Card Services event
- * callback) occurs in this thread rather than in the actual interrupt
- * handler due to the use of scheduling operations in the PCMCIA core.
- */
-static void sa1100_pcmcia_task_handler(void *data)
-{
-  struct pcmcia_state state;
-  unsigned int all_events;
-
-  DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
-
-  do {
-    unsigned int events;
-    int i;
-
-    DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
-
-    all_events = 0;
-
-    for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
-      struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-
-      memset(&state, 0, sizeof(state));
-
-      skt->ops->socket_state(skt->nr, &state);
-
-      events = sa1100_pcmcia_events(&state, &skt->k_state,
-				    skt->cs_state.csc_mask,
-				    skt->cs_state.flags);
-
-      if (events && skt->handler != NULL)
-	skt->handler(skt->handler_info, events);
-      all_events |= events;
-    }
-  } while(all_events);
-}  /* sa1100_pcmcia_task_handler() */
-
-static DECLARE_WORK(sa1100_pcmcia_task, sa1100_pcmcia_task_handler, NULL);
-
-
-/* sa1100_pcmcia_poll_event()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Let's poll for events in addition to IRQs since IRQ only is unreliable...
- */
-static void sa1100_pcmcia_poll_event(unsigned long dummy)
-{
-  DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
-  init_timer(&poll_timer);
-  poll_timer.function = sa1100_pcmcia_poll_event;
-  poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
-  add_timer(&poll_timer);
-  schedule_work(&sa1100_pcmcia_task);
-}
-
-
-/* sa1100_pcmcia_interrupt()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^
- * Service routine for socket driver interrupts (requested by the
- * low-level PCMCIA init() operation via sa1100_pcmcia_thread()).
- * The actual interrupt-servicing work is performed by
- * sa1100_pcmcia_thread(), largely because the Card Services event-
- * handling code performs scheduling operations which cannot be
- * executed from within an interrupt context.
- */
-void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
-{
-  DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
-  schedule_work(&sa1100_pcmcia_task);
-}
-
-
-/* sa1100_pcmcia_register_callback()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the register_callback() operation for the in-kernel
- * PCMCIA service (formerly SS_RegisterCallback in Card Services). If 
- * the function pointer `handler' is not NULL, remember the callback 
- * location in the state for `sock', and increment the usage counter 
- * for the driver module. (The callback is invoked from the interrupt
- * service routine, sa1100_pcmcia_interrupt(), to notify Card Services
- * of interesting events.) Otherwise, clear the callback pointer in the
- * socket state and decrement the module usage count.
- *
- * Returns: 0
- */
-static int
-sa1100_pcmcia_register_callback(unsigned int sock,
-				void (*handler)(void *, unsigned int),
-				void *info)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-
-  if (handler && !try_module_get(skt->ops->owner))
-  	return -ENODEV;
-  if (handler == NULL) {
-    skt->handler = NULL;
-  } else {
-    skt->handler_info = info;
-    skt->handler = handler;
-  }
-  if (!handler)
-  	module_put(skt->ops->owner);
-
-  return 0;
-}
-
-
-/* sa1100_pcmcia_inquire_socket()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the inquire_socket() operation for the in-kernel PCMCIA
- * service (formerly SS_InquireSocket in Card Services). Of note is
- * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of
- * `cap' to "trick" Card Services into tolerating large "I/O memory" 
- * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory
- * resource database check. (Mapped memory is set up within the socket
- * driver itself.)
- *
- * In conjunction with the STATIC_MAP capability is a new field,
- * `io_offset', recommended by David Hinds. Rather than go through
- * the SetIOMap interface (which is not quite suited for communicating
- * window locations up from the socket driver), we just pass up
- * an offset which is applied to client-requested base I/O addresses
- * in alloc_io_space().
- *
- * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
- *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
- *   general, the mapped * addresses of the PCMCIA memory regions
- *   will not be within 0xffff, setting force_low would be
- *   undesirable.
- *
- * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
- *   resource database; we instead pass up physical address ranges
- *   and allow other parts of Card Services to deal with remapping.
- *
- * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
- *   not 32-bit CardBus devices.
- *
- * Return value is irrelevant; the pcmcia subsystem ignores it.
- */
-static int
-sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  int ret = -1;
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  if (sock < sa1100_pcmcia_socket_count) {
-    cap->features  = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
-    cap->irq_mask  = 0;
-    cap->map_size  = PAGE_SIZE;
-    cap->pci_irq   = skt->irq;
-    cap->io_offset = (unsigned long)skt->virt_io;
-
-    ret = 0;
-  }
-
-  return ret;
-}
-
-
-/* sa1100_pcmcia_get_status()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * 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
-sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  struct pcmcia_state state;
-  unsigned int stat;
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  memset(&state, 0, sizeof(state));
-
-  skt->ops->socket_state(skt->nr, &state);
-  skt->k_state = state;
-
-  stat = state.detect ? SS_DETECT : 0;
-  stat |= state.ready ? SS_READY  : 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 ? SS_STSCHG : 0;
-  else {
-    if (state.bvd1 == 0)
-      stat |= SS_BATDEAD;
-    else if (state.bvd2 == 0)
-      stat |= SS_BATWARN;
-  }
-
-  DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
-	stat & SS_DETECT  ? "DETECT "  : "",
-	stat & SS_READY   ? "READY "   : "", 
-	stat & SS_BATDEAD ? "BATDEAD " : "",
-	stat & SS_BATWARN ? "BATWARN " : "",
-	stat & SS_POWERON ? "POWERON " : "",
-	stat & SS_STSCHG  ? "STSCHG "  : "",
-	stat & SS_3VCARD  ? "3VCARD "  : "",
-	stat & SS_XVCARD  ? "XVCARD "  : "");
-
-  *status = stat;
-
-  return 0;
-}  /* sa1100_pcmcia_get_status() */
-
-
-/* sa1100_pcmcia_get_socket()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the get_socket() operation for the in-kernel PCMCIA
- * service (formerly SS_GetSocket in Card Services). Not a very 
- * exciting routine.
- *
- * Returns: 0
- */
-static int
-sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  *state = skt->cs_state;
-
-  return 0;
-}
-
-/* sa1100_pcmcia_set_socket()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * 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.
- *
- * Returns: 0
- */
-static int
-sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\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 ":"");
-  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
-	state->Vcc, state->Vpp, state->io_irq);
-
-  return sa1100_pcmcia_config_skt(skt, state);
-}  /* sa1100_pcmcia_set_socket() */
-
-
-/* sa1100_pcmcia_set_io_map()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * 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
-sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  DEBUG(3, "\tmap %u  speed %u\n\tstart 0x%08x  stop 0x%08x\n",
-	map->map, map->speed, map->start, map->stop);
-  DEBUG(3, "\tflags: %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", __FUNCTION__,
-	   map->map);
-    return -1;
-  }
-
-  if (map->flags & MAP_ACTIVE) {
-    if ( map->speed == 0)
-       map->speed = SA1100_PCMCIA_IO_ACCESS;
-
-	sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
-  }
-
-  if (map->stop == 1)
-    map->stop = PAGE_SIZE-1;
-
-  map->stop -= map->start;
-  map->stop += (unsigned long)skt->virt_io;
-  map->start = (unsigned long)skt->virt_io;
-
-  skt->io_map[map->map] = *map;
-
-  return 0;
-}  /* sa1100_pcmcia_set_io_map() */
-
-
-/* sa1100_pcmcia_set_mem_map()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * 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, -1 on error
- */
-static int
-sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
-{
-  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-  unsigned long start;
-
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n",
-	map->map, map->speed, map->sys_start, map->sys_stop, map->card_start);
-  DEBUG(3, "\tflags: %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) {
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
-  }
-
-  if (map->flags & MAP_ACTIVE) {
-	  /*
-	   * When clients issue RequestMap, the access speed is not always
-	   * properly configured.  Choose some sensible defaults.
-	   */
-	  if (map->speed == 0) {
-		  if (skt->cs_state.Vcc == 33)
-			  map->speed = SA1100_PCMCIA_3V_MEM_ACCESS;
-		  else
-			  map->speed = SA1100_PCMCIA_5V_MEM_ACCESS;
-	  }
-
-	  sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
-
-  }
-
-  if (map->sys_stop == 0)
-    map->sys_stop = PAGE_SIZE-1;
-
-  start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;
-  map->sys_stop -= map->sys_start;
-  map->sys_stop += start + map->card_start;
-  map->sys_start = start + map->card_start;
-
-  skt->pc_mem_map[map->map] = *map;
-
-  return 0;
-}  /* sa1100_pcmcia_set_mem_map() */
-
-
-#if defined(CONFIG_PROC_FS)
-
-/* sa1100_pcmcia_proc_status()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the /proc/bus/pccard/??/status file.
- *
- * Returns: the number of characters added to the buffer
- */
-static int
-sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-			  int count, int *eof, void *data)
-{
-  struct sa1100_pcmcia_socket *skt = data;
-  unsigned int clock = cpufreq_get(0);
-  unsigned long mecr = MECR;
-  char *p = buf;
-
-  p+=sprintf(p, "k_state  : %s%s%s%s%s%s%s\n", 
-	     skt->k_state.detect ? "detect " : "",
-	     skt->k_state.ready  ? "ready "  : "",
-	     skt->k_state.bvd1   ? "bvd1 "   : "",
-	     skt->k_state.bvd2   ? "bvd2 "   : "",
-	     skt->k_state.wrprot ? "wrprot " : "",
-	     skt->k_state.vs_3v  ? "vs_3v "  : "",
-	     skt->k_state.vs_Xv  ? "vs_Xv "  : "");
-
-  p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
-	     skt->k_state.detect ? "SS_DETECT " : "",
-	     skt->k_state.ready  ? "SS_READY " : "",
-	     skt->cs_state.Vcc   ? "SS_POWERON " : "",
-	     skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
-	     (skt->cs_state.flags & SS_IOCARD &&
-	      skt->k_state.bvd1) ? "SS_STSCHG " : "",
-	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
-	      (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "",
-	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
-	      (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "",
-	     skt->k_state.vs_3v  ? "SS_3VCARD " : "",
-	     skt->k_state.vs_Xv  ? "SS_XVCARD " : "");
-
-  p+=sprintf(p, "mask     : %s%s%s%s%s\n",
-	     skt->cs_state.csc_mask & SS_DETECT  ? "SS_DETECT "  : "",
-	     skt->cs_state.csc_mask & SS_READY   ? "SS_READY "   : "",
-	     skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "",
-	     skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "",
-	     skt->cs_state.csc_mask & SS_STSCHG  ? "SS_STSCHG "  : "");
-
-  p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
-	     skt->cs_state.flags & SS_PWR_AUTO   ? "SS_PWR_AUTO "   : "",
-	     skt->cs_state.flags & SS_IOCARD     ? "SS_IOCARD "     : "",
-	     skt->cs_state.flags & SS_RESET      ? "SS_RESET "      : "",
-	     skt->cs_state.flags & SS_SPKR_ENA   ? "SS_SPKR_ENA "   : "",
-	     skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : "");
-
-  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\n", skt->cs_state.io_irq);
-
-  p+=sprintf(p, "I/O      : %u (%u)\n", skt->speed_io,
-	     sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
-
-  p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr,
-	     sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
-
-  p+=sprintf(p, "common   : %u (%u)\n", skt->speed_mem,
-	     sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
-
-  return p-buf;
-}
-
-/* sa1100_pcmcia_proc_setup()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the proc_setup() operation for the in-kernel PCMCIA
- * service (formerly SS_ProcSetup in Card Services).
- *
- * Returns: 0 on success, -1 on error
- */
-static void
-sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
-{
-  struct proc_dir_entry *entry;
-
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if ((entry = create_proc_entry("status", 0, base)) == NULL){
-    printk(KERN_ERR "unable to install \"status\" procfs entry\n");
-    return;
-  }
-
-  entry->read_proc = sa1100_pcmcia_proc_status;
-  entry->data = PCMCIA_SOCKET(sock);
-}
-
-#endif  /* defined(CONFIG_PROC_FS) */
-
-static struct pccard_operations sa1100_pcmcia_operations = {
-  .owner		= THIS_MODULE,
-  .init			= sa1100_pcmcia_sock_init,
-  .suspend		= sa1100_pcmcia_suspend,
-  .register_callback	= sa1100_pcmcia_register_callback,
-  .inquire_socket	= sa1100_pcmcia_inquire_socket,
-  .get_status		= sa1100_pcmcia_get_status,
-  .get_socket		= sa1100_pcmcia_get_socket,
-  .set_socket		= sa1100_pcmcia_set_socket,
-  .set_io_map		= sa1100_pcmcia_set_io_map,
-  .set_mem_map		= sa1100_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
-  .proc_setup		= sa1100_pcmcia_proc_setup
-#endif
-};
-
-#ifdef CONFIG_CPU_FREQ
-
-/* sa1100_pcmcia_update_mecr()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due
- * to a core clock frequency change) is needed, this routine establishes
- * new BS_xx values consistent with the clock speed `clock'.
- */
-static void sa1100_pcmcia_update_mecr(unsigned int clock)
-{
-	unsigned int sock;
-
-	for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) {
-		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
-		sa1100_pcmcia_set_mecr(skt, clock);
-	}
-}
-
-/* sa1100_pcmcia_notifier()
- * ^^^^^^^^^^^^^^^^^^^^^^^^
- * When changing the processor core clock frequency, it is necessary
- * to adjust the MECR timings accordingly. We've recorded the timings
- * requested by Card Services, so this is just a matter of finding
- * out what our current speed is, and then recomputing the new MECR
- * values.
- *
- * Returns: 0 on success, -1 on error
- */
-static int
-sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
-		       void *data)
-{
-	struct cpufreq_freqs *freqs = data;
-
-	switch (val) {
-	case CPUFREQ_PRECHANGE:
-		if (freqs->new > freqs->old) {
-			DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
-				"pre-updating\n", __FUNCTION__,
-			    freqs->new / 1000, (freqs->new / 100) % 10,
-			    freqs->old / 1000, (freqs->old / 100) % 10);
-			sa1100_pcmcia_update_mecr(freqs->new);
-		}
-		break;
-
-	case CPUFREQ_POSTCHANGE:
-		if (freqs->new < freqs->old) {
-			DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
-				"post-updating\n", __FUNCTION__,
-			    freqs->new / 1000, (freqs->new / 100) % 10,
-			    freqs->old / 1000, (freqs->old / 100) % 10);
-			sa1100_pcmcia_update_mecr(freqs->new);
-		}
-		break;
-	}
-
-	return 0;
-}
-
-static struct notifier_block sa1100_pcmcia_notifier_block = {
-	.notifier_call	= sa1100_pcmcia_notifier
-};
-#endif
-
-/* sa1100_register_pcmcia()
- * ^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * Register an SA1100 PCMCIA low level driver with the SA1100 core.
- */
-int sa1100_register_pcmcia(struct pcmcia_low_level *ops, struct device *dev)
-{
-	struct pcmcia_init pcmcia_init;
-	struct pcmcia_socket_class_data *cls;
-	unsigned int i, cpu_clock;
-	int ret;
-
-	/*
-	 * Refuse to replace an existing driver.
-	 */
-	if (pcmcia_low_level)
-		return -EBUSY;
-
-	pcmcia_low_level = ops;
-
-	/*
-	 * set default MECR calculation if the board specific
-	 * code did not specify one...
-	 */
-	if (!ops->socket_get_timing)
-		ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing;
-
-	pcmcia_init.socket_irq[0] = NO_IRQ;
-	pcmcia_init.socket_irq[1] = NO_IRQ;
-	ret = ops->init(&pcmcia_init);
-	if (ret < 0) {
-		printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret);
-		goto out;
-	}
-
-	sa1100_pcmcia_socket_count = ret;
-
-	cpu_clock = cpufreq_get(0);
-
-	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
-		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-		memset(skt, 0, sizeof(*skt));
-	}
-
-	/*
-	 * We initialize the MECR to default values here, because we are
-	 * not guaranteed to see a SetIOMap operation at runtime.
-	 */
-	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
-		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-
-		skt->res.start	= _PCMCIA(i);
-		skt->res.end	= _PCMCIA(i) + PCMCIASp - 1;
-		skt->res.name	= "PCMCIA";
-		skt->res.flags	= IORESOURCE_MEM;
-
-		ret = request_resource(&iomem_resource, &skt->res);
-		if (ret)
-			goto out_err;
-
-		skt->nr		= i;
-		skt->ops	= ops;
-		skt->irq	= pcmcia_init.socket_irq[i];
-		skt->irq_state	= 0;
-		skt->speed_io   = SA1100_PCMCIA_IO_ACCESS;
-		skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS;
-		skt->speed_mem  = SA1100_PCMCIA_5V_MEM_ACCESS;
-		skt->phys_attr  = _PCMCIAAttr(i);
-		skt->phys_mem   = _PCMCIAMem(i);
-		skt->virt_io    = ioremap(_PCMCIAIO(i), 0x10000);
-
-		if (skt->virt_io == NULL) {
-			ret = -ENOMEM;
-			goto out_err;
-		}
-
-		ops->socket_state(skt->nr, &skt->k_state);
-		sa1100_pcmcia_set_mecr(skt, cpu_clock);
-	}
-
-	cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL);
-	if (!cls) {
-		ret = -ENOMEM;
-		goto out_err;
-	}
-
-	memset(cls, 0, sizeof(struct pcmcia_socket_class_data));
-
-	cls->ops	= &sa1100_pcmcia_operations;
-	cls->nsock	= sa1100_pcmcia_socket_count;
-	dev->class_data = cls;
-
-	/*
-	 * Start the event poll timer.  It will reschedule by itself afterwards.
-	 */
-	sa1100_pcmcia_poll_event(0);
-	return 0;
-
- out_err:
-	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
-		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-		iounmap(skt->virt_io);
-		skt->virt_io = NULL;
-		if (skt->res.start)
-			release_resource(&skt->res);
-	}
-
-	ops->shutdown();
-
- out:
-	pcmcia_low_level = NULL;
-	return ret;
-}
-EXPORT_SYMBOL(sa1100_register_pcmcia);
-
-/* sa1100_unregister_pcmcia()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * Unregister a previously registered pcmcia driver
- */
-void sa1100_unregister_pcmcia(struct pcmcia_low_level *ops, struct device *dev)
-{
-	int i;
-
-	if (!ops)
-		return;
-
-	if (ops != pcmcia_low_level) {
-		printk(KERN_DEBUG "PCMCIA: Trying to unregister wrong "
-			"low-level driver (%p != %p)", ops,
-			pcmcia_low_level);
-		return;
-	}
-
-	del_timer_sync(&poll_timer);
-
-	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
-		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-
-		iounmap(skt->virt_io);
-		skt->virt_io = NULL;
-		
-		release_resource(&skt->res);
-	}
-
-	ops->shutdown();
-
-	flush_scheduled_work();
-
-	kfree(dev->class_data);
-	dev->class_data = NULL;
-
-	pcmcia_low_level = NULL;
-}
-EXPORT_SYMBOL(sa1100_unregister_pcmcia);
-
-static struct device_driver sa1100_pcmcia_driver = {
-	.name		= "sa11x0-pcmcia",
-	.bus		= &platform_bus_type,
-	.devclass	= &pcmcia_socket_class,
-};
-
-static struct platform_device sa1100_pcmcia_device = {
-	.name		= "sa11x0-pcmcia",
-	.id		= 0,
-	.dev		= {
-		.name	= "Intel Corporation SA11x0 [PCMCIA]",
-	},
-};
-
-struct ll_fns {
-	int (*init)(struct device *dev);
-	void (*exit)(struct device *dev);
-};
-
-static struct ll_fns sa1100_ll_fns[] = {
+static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
 #ifdef CONFIG_SA1100_ASSABET
-	{ .init = pcmcia_assabet_init,	.exit = pcmcia_assabet_exit,	},
+	pcmcia_assabet_init,
 #endif
 #ifdef CONFIG_SA1100_CERF
-	{ .init = pcmcia_cerf_init,	.exit = pcmcia_cerf_exit,	},
+	pcmcia_cerf_init,
 #endif
 #ifdef CONFIG_SA1100_FLEXANET
-	{ .init = pcmcia_flexanet_init,	.exit = pcmcia_flexanet_exit,	},
+	pcmcia_flexanet_init,
 #endif
 #ifdef CONFIG_SA1100_FREEBIRD
-	{ .init = pcmcia_freebird_init,	.exit = pcmcia_freebird_exit,	},
+	pcmcia_freebird_init,
 #endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
-	{ .init = pcmcia_gcplus_init,	.exit = pcmcia_gcplus_exit,	},
+	pcmcia_gcplus_init,
 #endif
 #ifdef CONFIG_SA1100_H3600
-	{ .init = pcmcia_h3600_init,	.exit = pcmcia_h3600_exit,	},
+	pcmcia_h3600_init,
 #endif
 #ifdef CONFIG_SA1100_PANGOLIN
-	{ .init = pcmcia_pangolin_init,	.exit = pcmcia_pangolin_exit,	},
+	pcmcia_pangolin_init,
 #endif
 #ifdef CONFIG_SA1100_SHANNON
-	{ .init = pcmcia_shannon_init,	.exit = pcmcia_shannon_exit,	},
+	pcmcia_shannon_init,
 #endif
 #ifdef CONFIG_SA1100_SIMPAD
-	{ .init = pcmcia_simpad_init,	.exit = pcmcia_simpad_exit,	},
+	pcmcia_simpad_init,
 #endif
 #ifdef CONFIG_SA1100_STORK
-	{ .init = pcmcia_stork_init,	.exit = pcmcia_stork_exit,	},
+	pcmcia_stork_init,
 #endif
 #ifdef CONFIG_SA1100_TRIZEPS
-	{ .init = pcmcia_trizeps_init,	.exit = pcmcia_trizeps_exit,	},
+	pcmcia_trizeps_init,
 #endif
 #ifdef CONFIG_SA1100_YOPY
-	{ .init = pcmcia_yopy_init,	.exit = pcmcia_yopy_exit,	},
+	pcmcia_yopy_init,
 #endif
 };
 
-/* sa1100_pcmcia_init()
- * ^^^^^^^^^^^^^^^^^^^^
- *
- * This routine performs a basic sanity check to ensure that this
- * kernel has been built with the appropriate board-specific low-level
- * PCMCIA support, performs low-level PCMCIA initialization, registers
- * this socket driver with Card Services, and then spawns the daemon
- * thread which is the real workhorse of the socket driver.
- *
- * Returns: 0 on success, -1 on error
- */
-static int __init sa1100_pcmcia_init(void)
+static int sa11x0_drv_pcmcia_probe(struct device *dev)
 {
-	servinfo_t info;
-	int ret, i;
-
-	printk(KERN_INFO "SA11x0 PCMCIA (CS release %s)\n", CS_RELEASE);
-
-	CardServices(GetCardServicesInfo, &info);
-	if (info.Revision != CS_RELEASE_CODE) {
-		printk(KERN_ERR "Card Services release codes do not match\n");
-		return -EINVAL;
-	}
-
-#ifdef CONFIG_CPU_FREQ
-	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
-					CPUFREQ_TRANSITION_NOTIFIER);
-	if (ret < 0) {
-		printk(KERN_ERR "Unable to register CPU frequency change "
-			"notifier (%d)\n", ret);
-		driver_unregister(&sa1100_pcmcia_driver);
-		return ret;
-	}
-#endif
-
-	driver_register(&sa1100_pcmcia_driver);
+	int i, ret = -ENODEV;
 
 	/*
 	 * Initialise any "on-board" PCMCIA sockets.
 	 */
-	for (i = 0; i < ARRAY_SIZE(sa1100_ll_fns); i++) {
-		ret = sa1100_ll_fns[i].init(&sa1100_pcmcia_device.dev);
+	for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) {
+		ret = sa11x0_pcmcia_hw_init[i](dev);
 		if (ret == 0)
 			break;
 	}
 
-	if (ret == 0)
-		platform_device_register(&sa1100_pcmcia_device);
-
-	/*
-	 * Don't fail if we don't find any on-board sockets.
-	 */
-	return 0;
+	return ret;
 }
 
-/* sa1100_pcmcia_exit()
+static struct device_driver sa11x0_pcmcia_driver = {
+	.probe		= sa11x0_drv_pcmcia_probe,
+	.remove		= sa11xx_drv_pcmcia_remove,
+	.name		= "sa11x0-pcmcia",
+	.bus		= &platform_bus_type,
+	.devclass	= &pcmcia_socket_class,
+	.suspend 	= pcmcia_socket_dev_suspend,
+	.resume 	= pcmcia_socket_dev_resume,
+};
+
+static struct platform_device sa11x0_pcmcia_device = {
+	.name		= "sa11x0-pcmcia",
+	.id		= 0,
+	.dev		= {
+		.name	= "Intel Corporation SA11x0 [PCMCIA]",
+	},
+};
+
+/* sa11x0_pcmcia_init()
  * ^^^^^^^^^^^^^^^^^^^^
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
+ *
+ * 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 void __exit sa1100_pcmcia_exit(void)
+static int __init sa11x0_pcmcia_init(void)
 {
-	platform_device_unregister(&sa1100_pcmcia_device);
+	int ret;
 
+	ret = driver_register(&sa11x0_pcmcia_driver);
+	if (ret == 0) {
+		ret = platform_device_register(&sa11x0_pcmcia_device);
+		if (ret)
+			driver_unregister(&sa11x0_pcmcia_driver);
+	}
 
-#ifdef CONFIG_CPU_FREQ
-	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
+	return ret;
+}
 
-	driver_unregister(&sa1100_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_device_unregister(&sa11x0_pcmcia_device);
+	driver_unregister(&sa11x0_pcmcia_driver);
 }
 
 MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
 MODULE_LICENSE("Dual MPL/GPL");
 
-module_init(sa1100_pcmcia_init);
-module_exit(sa1100_pcmcia_exit);
+module_init(sa11x0_pcmcia_init);
+module_exit(sa11x0_pcmcia_exit);
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_generic.h linux-2.5.66-bk6/drivers/pcmcia/sa1100_generic.h
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_generic.h	Mon Mar 24 14:00:49 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_generic.h	Mon Mar 31 12:52:29 2003
@@ -1,74 +1,23 @@
-/*
- * linux/include/asm/arch/pcmcia.h
- *
- * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
- *
- * This file contains definitions for the low-level SA-1100 kernel PCMCIA
- * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
- */
-#ifndef _ASM_ARCH_PCMCIA
-#define _ASM_ARCH_PCMCIA
+#include "sa11xx_core.h"
 
-/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
- * has support for two. This shows up in lots of hardwired ways, such
- * as the fact that MECR only has enough bits to configure two sockets.
- * Since it's so entrenched in the hardware, limiting the software
- * in this way doesn't seem too terrible.
+/*
+ * Declaration for all machine specific init/exit functions.
  */
-#define SA1100_PCMCIA_MAX_SOCK   (2)
-
-struct pcmcia_init {
-	int	socket_irq[SA1100_PCMCIA_MAX_SOCK];
-};
-
-struct pcmcia_state {
-  unsigned detect: 1,
-            ready: 1,
-             bvd1: 1,
-             bvd2: 1,
-           wrprot: 1,
-            vs_3v: 1,
-            vs_Xv: 1;
-};
-
-struct pcmcia_configure {
-  unsigned  vcc: 8,
-            vpp: 8,
-         output: 1,
-        speaker: 1,
-          reset: 1,
-            irq: 1;
-};
-
-struct pcmcia_low_level {
-  struct module *owner;
-
-  int (*init)(struct pcmcia_init *);
-  int (*shutdown)(void);
-  void (*socket_state)(int sock, struct pcmcia_state *);
-  int (*configure_socket)(int sock, const struct pcmcia_configure *);
-
-  /*
-   * Enable card status IRQs on (re-)initialisation.  This can
-   * be called at initialisation, power management event, or
-   * pcmcia event.
-   */
-  int (*socket_init)(int sock);
-
-  /*
-   * Disable card status IRQs and PCMCIA bus on suspend.
-   */
-  int (*socket_suspend)(int sock);
-
-  /*
-   * Calculate MECR timing clock wait states
-   */
-  unsigned int (*socket_get_timing)(unsigned int sock,
-		unsigned int cpu_speed, unsigned int cmd_time);
-};
-
-extern int sa1100_register_pcmcia(struct pcmcia_low_level *, struct device *);
-extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *, struct device *);
-extern void sa1100_pcmcia_interrupt(int, void *, struct pt_regs *);
-
-#endif
+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_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 -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_graphicsclient.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_graphicsclient.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_graphicsclient.c	Mon Mar 24 13:59:54 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_graphicsclient.c	Mon Mar 31 12:52:29 2003
@@ -34,126 +34,113 @@
 static volatile unsigned long *PCMCIA_Power = 
 		((volatile unsigned long *) ADS_p2v(_ADS_CS_PR));
 
-static int gcplus_pcmcia_init(struct pcmcia_init *init)
-{
-  int irq, res;
-
-  // Reset PCMCIA
-  // Reset Timing for CPLD(U2) version 8001E or later
-  *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
-  udelay(12);			// 12 uSec
+static struct pcmcia_irqs irqs[] = {
+	{ 0, S0_CD_IRQ, "PCMCIA 0 CD" },
+};
 
-  *PCMCIA_Power |= ADS_CS_PR_A_RESET;
-  mdelay(30);			// 30 mSec
+static int gcplus_pcmcia_init(struct sa1100_pcmcia_socket *skt)
+{
+	// Reset PCMCIA
+	// Reset Timing for CPLD(U2) version 8001E or later
+	*PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
+	udelay(12);			// 12 uSec
 
-  // Turn off 5V
-  *PCMCIA_Power &= ~0x03;
+	*PCMCIA_Power |= ADS_CS_PR_A_RESET;
+	mdelay(30);			// 30 mSec
 
-  /* Register interrupts */
-  irq = S0_CD_IRQ;
-  res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
-  if (res < 0) {
-    printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	   __FUNCTION__, irq, res);
-    return res;
-  }
+	// Turn off 5V
+	*PCMCIA_Power &= ~0x03;
 
-  init->socket_irq[0] = S0_STS_IRQ;
+	skt->irq = S0_STS_IRQ;
 
-  return 1;			// 1 PCMCIA Slot
+	/* Register interrupts */
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int gcplus_pcmcia_shutdown(void)
+static void gcplus_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  /* disable IRQs */
-  free_irq( S0_CD_IRQ, NULL);
+	/* disable IRQs */
+	free_irq(S0_CD_IRQ, skt);
   
-  /* Shutdown PCMCIA power */
-  mdelay(2);						// 2msec
-  *PCMCIA_Power &= ~0x03;
-
-  return 0;
+	/* Shutdown PCMCIA power */
+	mdelay(2);			// 2msec
+	*PCMCIA_Power &= ~0x03;
 }
 
-static void gcplus_pcmcia_socket_state(int sock, struct pcmcia_state *state_array)
+static void
+gcplus_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-  unsigned long levels = *PCMCIA_Status;
+	unsigned long levels = *PCMCIA_Status;
 
-  if (sock == 0) {
-    state->detect=(levels & ADS_CS_ST_A_CD)?1:0;
-    state->ready=(levels & ADS_CS_ST_A_READY)?1:0;
-    state->bvd1= 0;
-    state->bvd2= 0;
-    state->wrprot=0;
-    state->vs_3v=0;
-    state->vs_Xv=0;
-  }
+	state->detect=(levels & ADS_CS_ST_A_CD)?1:0;
+	state->ready=(levels & ADS_CS_ST_A_READY)?1:0;
+	state->bvd1= 0;
+	state->bvd2= 0;
+	state->wrprot=0;
+	state->vs_3v=0;
+	state->vs_Xv=0;
 }
 
-static int gcplus_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+gcplus_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			       const socket_state_t *state)
 {
-  unsigned long flags;
-
-  if(sock>1) return -1;
+	unsigned long flags;
 
-  local_irq_save(flags);
+	local_irq_save(flags);
 
-  switch (configure->vcc) {
-  case 0:
-	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
-    break;
+	switch (state->Vcc) {
+	case 0:
+		*PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+		break;
 
-  case 50:
-	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
-	  *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER;
-	break;
+	case 50:
+		*PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+		*PCMCIA_Power |= ADS_CS_PR_A_5V_POWER;
+		break;
 
-  case 33:
-	  *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
-	  *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER;
-    break;
+	case 33:
+		*PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER);
+		*PCMCIA_Power |= ADS_CS_PR_A_3V_POWER;
+		break;
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    local_irq_restore(flags);
-    return -1;
-  }
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__FUNCTION__, state->Vcc);
+		local_irq_restore(flags);
+		return -1;
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	/* Silently ignore Vpp, output enable, speaker enable. */
 
-  // Reset PCMCIA
-  *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
-  udelay(12);
+	// Reset PCMCIA
+	*PCMCIA_Power &= ~ ADS_CS_PR_A_RESET;
+	udelay(12);
 
-  *PCMCIA_Power |= ADS_CS_PR_A_RESET;
-  mdelay(30);
+	*PCMCIA_Power |= ADS_CS_PR_A_RESET;
+	mdelay(30);
 
-  local_irq_restore(flags);
+	local_irq_restore(flags);
 
-  return 0;
+	return 0;
 }
 
-static int gcplus_pcmcia_socket_init(int sock)
+static void gcplus_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  return 0;
 }
 
-static int gcplus_pcmcia_socket_suspend(int sock)
+static void gcplus_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  return 0;
 }
 
 static struct pcmcia_low_level gcplus_pcmcia_ops = { 
-  .owner		= THIS_MODULE,
-  .init			= gcplus_pcmcia_init,
-  .shutdown		= gcplus_pcmcia_shutdown,
-  .socket_state		= gcplus_pcmcia_socket_state,
-  .configure_socket	= gcplus_pcmcia_configure_socket,
-
-  .socket_init		= gcplus_pcmcia_socket_init,
-  .socket_suspend	= gcplus_pcmcia_socket_suspend,
+	.owner			= THIS_MODULE,
+	.hw_init		= gcplus_pcmcia_hw_init,
+	.hw_shutdown		= gcplus_pcmcia_hw_shutdown,
+	.socket_state		= gcplus_pcmcia_socket_state,
+	.configure_socket	= gcplus_pcmcia_configure_socket,
+	.socket_init		= gcplus_pcmcia_socket_init,
+	.socket_suspend		= gcplus_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_gcplus_init(struct device *dev)
@@ -161,13 +148,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_gcplus())
-		ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &gcplus_pcmcia_ops, 0, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_gcplus_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&gcplus_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_graphicsmaster.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_graphicsmaster.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_graphicsmaster.c	Mon Mar 24 14:01:12 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_graphicsmaster.c	Mon Mar 31 12:52:29 2003
@@ -17,10 +17,9 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
-static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
+static int graphicsmaster_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
   int return_val=0;
 
@@ -33,65 +32,67 @@
   /* why? */
   MECR = 0x09430943;
 
-  return sa1111_pcmcia_init(init);
+  return sa1111_pcmcia_hwinit(skt);
 }
 
 static int
-graphicsmaster_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+graphicsmaster_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				       const socket_state_t *state)
 {
-  unsigned int pa_dwr_mask, pa_dwr_set;
-  int ret;
+	unsigned int pa_dwr_mask, pa_dwr_set;
+	int ret;
 
-  switch (sock) {
-  case 0:
-    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
-
-    switch (conf->vcc) {
-    default:
-    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
-    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
-    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
-    }
-    break;
-
-  case 1:
-    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
-
-    switch (conf->vcc) {
-    default:
-    case 0:	pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;	break;
-    case 33:	pa_dwr_set = GPIO_GPIO3;		break;
-    case 50:	pa_dwr_set = GPIO_GPIO2;		break;
-    }
-  }
-
-  if (conf->vpp != conf->vcc && conf->vpp != 0) {
-    printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	   conf->vpp);
-    return -1;
-  }
-
-  ret = sa1111_pcmcia_configure_socket(sock, conf);
-  if (ret == 0) {
-    unsigned long flags;
-
-    local_irq_save(flags);
-    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
-    local_irq_restore(flags);
-  }
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+
+		switch (state->Vcc) {
+		default:
+		case 0:  pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+		case 33: pa_dwr_set = GPIO_GPIO1;		break;
+		case 50: pa_dwr_set = GPIO_GPIO0;		break;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+
+		switch (state->Vcc) {
+		default:
+		case 0:  pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;	break;
+		case 33: pa_dwr_set = GPIO_GPIO3;		break;
+		case 50: pa_dwr_set = GPIO_GPIO2;		break;
+		}
+		break;
+	}
+
+	if (state->Vpp != state->Vcc && state->Vpp != 0) {
+		printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+			__FUNCTION__, state->Vpp);
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+		local_irq_restore(flags);
+	}
 
-  return ret;
+	return ret;
 }
 
 static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
-  .owner		= THIS_MODULE,
-  .init			= graphicsmaster_pcmcia_init,
-  .shutdown		= sa1111_pcmcia_shutdown,
-  .socket_state		= sa1111_pcmcia_socket_state,
-  .configure_socket	= graphicsmaster_pcmcia_configure_socket,
+	.owner			= THIS_MODULE,
+	.hw_init		= graphicsmaster_pcmcia_init,
+	.hw_shutdown		= sa1111_pcmcia_hw_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.configure_socket	= graphicsmaster_pcmcia_configure_socket,
 
-  .socket_init		= sa1111_pcmcia_socket_init,
-  .socket_suspend	= sa1111_pcmcia_socket_suspend,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_graphicsmaster_init(struct device *dev)
@@ -99,13 +100,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_graphicsmaster())
-		ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &graphicsmaster_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_graphicsmaster_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_h3600.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_h3600.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_h3600.c	Mon Mar 24 14:01:12 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_h3600.c	Mon Mar 31 12:52:29 2003
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
@@ -17,65 +18,36 @@
 
 #include "sa1100_generic.h"
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
-	{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
+	{ 1, IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
 };
 
-static int h3600_pcmcia_init(struct pcmcia_init *init)
+static int h3600_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i, res;
+	skt->irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1
+			   : IRQ_GPIO_H3600_PCMCIA_IRQ0;
 
-	/*
-	 * Register interrupts
-	 */
-	for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
-		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (res)
-			break;
-	}
-
-	if (res) {
-		printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-		       __FUNCTION__, irqs[i].irq, res);
 
-		while (i--)
-			free_irq(irqs[i].irq, NULL);
-	}
-
-	init->socket_irq[0] = IRQ_GPIO_H3600_PCMCIA_IRQ0;
-	init->socket_irq[1] = IRQ_GPIO_H3600_PCMCIA_IRQ1;
-
-	return res ? res : 2;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int h3600_pcmcia_shutdown(void)
+static void h3600_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	/*
-	 * disable IRQs
-	 */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		free_irq(irqs[i].irq, NULL);
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
   
 	/* Disable CF bus: */
 	clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
 	clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
 	set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
-
-	return 0;
 }
 
-static void h3600_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+h3600_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
 	unsigned long levels = GPLR;
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
 		state->detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
 		state->ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
@@ -99,18 +71,15 @@
 }
 
 static int
-h3600_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+h3600_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
-	if (sock > 1)
-		return -1;
-
-	if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
+	if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) {
 		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
-		       conf->vcc / 10, conf->vcc % 10);
+		       state->Vcc / 10, state->Vcc % 10);
 		return -1;
 	}
 
-	if (conf->reset)
+	if (state->flags & SS_RESET)
 		set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
 	else
 		clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
@@ -120,7 +89,7 @@
 	return 0;
 }
 
-static int h3600_pcmcia_socket_init(int sock)
+static void h3600_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
 	/* Enable CF bus: */
 	set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
@@ -130,28 +99,12 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(10*HZ / 1000);
 
-	switch (sock) {
-	case 0:
-		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE);
-		break;
-	case 1:
-		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE);
-		break;
-	}
-
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int h3600_pcmcia_socket_suspend(int sock)
+static void h3600_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	switch (sock) {
-	case 0:
-		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE);
-		break;
-	case 1:
-		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE);
-		break;
-	}
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 
 	/*
 	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
@@ -159,20 +112,18 @@
 	 * on one bus.  We rely on the cs.c behaviour shutting down
 	 * socket 0 then socket 1.
 	 */
-	if (sock == 1) {
+	if (skt->nr == 1) {
 		clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
 		clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
 		/* hmm, does this suck power? */
 		set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
 	}
-
-	return 0;
 }
 
 struct pcmcia_low_level h3600_pcmcia_ops = { 
 	.owner			= THIS_MODULE,
-	.init			= h3600_pcmcia_init,
-	.shutdown		= h3600_pcmcia_shutdown,
+	.hw_init		= h3600_pcmcia_hw_init,
+	.hw_shutdown		= h3600_pcmcia_hw_shutdown,
 	.socket_state		= h3600_pcmcia_socket_state,
 	.configure_socket	= h3600_pcmcia_configure_socket,
 
@@ -185,12 +136,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_h3600())
-		ret = sa1100_register_pcmcia(&h3600_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_h3600_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&h3600_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_jornada720.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_jornada720.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_jornada720.c	Mon Mar 24 14:00:20 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_jornada720.c	Mon Mar 31 12:52:29 2003
@@ -15,7 +15,6 @@
 #include <asm/hardware/sa1111.h>
 #include <asm/mach-types.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
 #define SOCKET0_POWER   GPIO_GPIO0
@@ -24,7 +23,7 @@
 #warning *** Does SOCKET1_3V actually do anything?
 #define SOCKET1_3V	GPIO_GPIO3
 
-static int jornada720_pcmcia_init(struct pcmcia_init *init)
+static int jornada720_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
   /*
    * What is all this crap for?
@@ -46,23 +45,23 @@
   PC_SDR = 0;
   PC_SSR = 0;
 
-  return sa1111_pcmcia_init(init);
+  return sa1111_pcmcia_hw_init(skt);
 }
 
 static int
-jornada720_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+jornada720_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
   unsigned int pa_dwr_mask, pa_dwr_set;
   int ret;
 
 printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
-	       sock, conf->vcc, conf->vpp);
+	skt->nr, state->Vcc, state->Vpp);
 
-  switch (sock) {
+  switch (skt->nr) {
   case 0:
     pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
 
-    switch (conf->vcc) {
+    switch (state->Vcc) {
     default:
     case 0:	pa_dwr_set = 0;					break;
     case 33:	pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;	break;
@@ -73,7 +72,7 @@
   case 1:
     pa_dwr_mask = SOCKET1_POWER;
 
-    switch (conf->vcc) {
+    switch (state->Vcc) {
     default:
     case 0:	pa_dwr_set = 0;					break;
     case 33:	pa_dwr_set = SOCKET1_POWER;			break;
@@ -85,13 +84,13 @@
     return -1;
   }
 
-  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+  if (state->Vpp != state->Vcc && state->Vpp != 0) {
     printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
-	   __FUNCTION__, conf->vpp);
+	   __FUNCTION__, state->Vpp);
     return -1;
   }
 
-  ret = sa1111_pcmcia_configure_socket(sock, conf);
+  ret = sa1111_pcmcia_configure_socket(skt, state);
   if (ret == 0) {
     unsigned long flags;
 
@@ -105,8 +104,8 @@
 
 static struct pcmcia_low_level jornada720_pcmcia_ops = {
   .owner		= THIS_MODULE,
-  .init			= jornada720_pcmcia_init,
-  .shutdown		= sa1111_pcmcia_shutdown,
+  .hw_init		= jornada720_pcmcia_hw_init,
+  .hw_shutdown		= sa1111_pcmcia_hw_shutdown,
   .socket_state		= sa1111_pcmcia_socket_state,
   .configure_socket	= jornada720_pcmcia_configure_socket,
 
@@ -119,12 +118,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_jornada720())
-		ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &jornada720_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __devexit pcmcia_jornada720_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&jornada720_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_neponset.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_neponset.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_neponset.c	Mon Mar 24 14:01:26 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_neponset.c	Mon Mar 31 12:52:29 2003
@@ -15,7 +15,6 @@
 #include <asm/arch/neponset.h>
 #include <asm/hardware/sa1111.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
 /*
@@ -42,52 +41,27 @@
  * the corresponding truth table.
  */
 
-static int neponset_pcmcia_init(struct pcmcia_init *init)
-{
-	NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
-
-	/*
-	 * Set GPIO_A<3:0> to be outputs for the MAX1600,
-	 * and switch to standby mode.
-	 */
-	PA_DDR = 0;
-	PA_SDR = 0;
-	PA_DWR = 0;
-	PA_SSR = 0;
-
-	return sa1111_pcmcia_init(init);
-}
-
 static int
-neponset_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+neponset_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
-	unsigned int ncr_mask, pa_dwr_mask;
-	unsigned int ncr_set, pa_dwr_set;
+	unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
 	int ret;
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
 		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
 		ncr_mask = NCR_A0VPP | NCR_A1VPP;
 
-		switch (conf->vcc) {
-		default:
-		case 0:		pa_dwr_set = 0;			break;
-		case 33:	pa_dwr_set = GPIO_GPIO1;	break;
-		case 50:	pa_dwr_set = GPIO_GPIO0;	break;
-		}
-
-		switch (conf->vpp) {
-		case 0:		ncr_set = 0;			break;
-		case 120:	ncr_set = NCR_A1VPP;		break;
-		default:
-			if (conf->vpp == conf->vcc)
-				ncr_set = NCR_A0VPP;
-			else {
-				printk(KERN_ERR "%s(): unrecognized VPP %u\n",
-				       __FUNCTION__, conf->vpp);
-				return -1;
-			}
+		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",
+			       __FUNCTION__, state->Vpp);
+			return -1;
 		}
 		break;
 
@@ -96,16 +70,9 @@
 		ncr_mask = 0;
 		ncr_set = 0;
 
-		switch (conf->vcc) {
-		default:
-		case 0:		pa_dwr_set = 0;			break;
-		case 33:	pa_dwr_set = GPIO_GPIO2;	break;
-		case 50:	pa_dwr_set = GPIO_GPIO3;	break;
-		}
-
-		if (conf->vpp != conf->vcc && conf->vpp != 0) {
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
 			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-			       __FUNCTION__, conf->vpp);
+			       __FUNCTION__, state->Vpp);
 			return -1;
 		}
 		break;
@@ -114,41 +81,64 @@
 		return -1;
 	}
 
-	ret = sa1111_pcmcia_configure_socket(sock, conf);
+	/*
+	 * 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_GPIO1|GPIO_GPIO2;	break;
+	case 50: pa_dwr_set = GPIO_GPIO0|GPIO_GPIO3;	break;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
 	if (ret == 0) {
 		unsigned long flags;
 
 		local_irq_save(flags);
 		NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
-		PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+
+		PA_DWR = (PA_DWR & ~pa_dwr_mask) | (pa_dwr_set & pa_dwr_mask);
 		local_irq_restore(flags);
 	}
 
 	return 0;
 }
 
-static struct pcmcia_low_level neponset_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-	.init			= neponset_pcmcia_init,
-	.shutdown		= sa1111_pcmcia_shutdown,
-	.socket_state		= sa1111_pcmcia_socket_state,
-	.configure_socket	= neponset_pcmcia_configure_socket,
+static void neponset_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
+{
+	if (skt->nr == 0)
+		NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
 
-	.socket_init		= sa1111_pcmcia_socket_init,
-	.socket_suspend		= sa1111_pcmcia_socket_suspend,
+        sa1111_pcmcia_socket_init(skt);
+}
+
+static struct pcmcia_low_level neponset_pcmcia_ops = {
+        .owner                  = THIS_MODULE,
+        .hw_init                = sa1111_pcmcia_hw_init,
+        .hw_shutdown            = sa1111_pcmcia_hw_shutdown,
+        .socket_state           = sa1111_pcmcia_socket_state,
+        .configure_socket       = neponset_pcmcia_configure_socket,
+        .socket_init            = neponset_pcmcia_socket_init,
+        .socket_suspend         = sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_neponset_init(struct device *dev)
 {
-	int ret = -ENODEV;
+        int ret = -ENODEV;
 
-	if (machine_is_assabet())
-		ret = sa1100_register_pcmcia(&neponset_pcmcia_ops, dev);
+        if (machine_is_assabet()) {
+                /*
+                 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+                 * and switch to standby mode.
+                 */
+                PA_DDR = 0;
+                PA_DWR = 0;
+		PA_SDR = 0;
+		PA_SSR = 0;
+		ret = sa11xx_drv_pcmcia_probe(dev, &neponset_pcmcia_ops, 0, 2);
+	}
 
 	return ret;
 }
-
-void __devexit pcmcia_neponset_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&neponset_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_pangolin.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_pangolin.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_pangolin.c	Mon Mar 24 13:59:55 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_pangolin.c	Mon Mar 31 12:52:29 2003
@@ -22,134 +22,118 @@
 #define PANGOLIN_SOCK	0
 #endif
 
-static int pangolin_pcmcia_init(struct pcmcia_init *init){
-  int res;
+static struct pcmcia_irqs irqs[] = {
+	{ PANGOLIN_SOCK, IRQ_PCMCIA_CD, "PCMCIA CD" },
+};
+
+static int pangolin_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
+{
+	int res;
 
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  /* Enable PCMCIA bus: */
-  GPCR = GPIO_PCMCIA_BUS_ON;
+	/* Enable PCMCIA bus: */
+	GPCR = GPIO_PCMCIA_BUS_ON;
 #endif
 
-  init->socket_irq[PANGOLIN_SOCK] = IRQ_PCMCIA_IRQ;
-
-  /* Set transition detect */
-  set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
-  set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING);
+	skt->irq = IRQ_PCMCIA_IRQ;
 
-  /* Register interrupts */
-  res = request_irq(IRQ_PCMCIA_CD, sa1100_pcmcia_interrupt, SA_INTERRUPT,
-		    "PCMCIA_CD", NULL);
-  if (res >= 0)
-    /* There's only one slot, but it's "Slot 1": */
-    return 2;
-
-irq_err:
-  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	 __FUNCTION__, IRQ_PCMCIA_CD, res);
-
-  return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int pangolin_pcmcia_shutdown(void)
+static void pangolin_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  /* disable IRQs */
-  free_irq(IRQ_PCMCIA_CD, NULL);
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-    /* Disable PCMCIA bus: */
-    GPSR = GPIO_PCMCIA_BUS_ON;
+	/* Disable PCMCIA bus: */
+	GPSR = GPIO_PCMCIA_BUS_ON;
 #endif
-  return 0;
 }
 
-static void pangolin_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+pangolin_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			     struct pcmcia_state *state)
 {
-  unsigned long levels = GPLR;;
+	unsigned long levels = GPLR;;
 
-  if (sock == PANGOLIN_SOCK) {
-    state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
-    state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0;
-    state->bvd1=1; /* Not available on Pangolin. */
-    state->bvd2=1; /* Not available on Pangolin. */
-    state->wrprot=0; /* Not available on Pangolin. */
-    state->vs_3v=1;  /* Can only apply 3.3V on Pangolin. */
-    state->vs_Xv=0;
-  }
+	state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
+	state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0;
+	state->bvd1=1; /* Not available on Pangolin. */
+	state->bvd2=1; /* Not available on Pangolin. */
+	state->wrprot=0; /* Not available on Pangolin. */
+	state->vs_3v=1;  /* Can only apply 3.3V on Pangolin. */
+	state->vs_Xv=0;
 }
 
-static int pangolin_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+pangolin_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				 const socket_state_t *state)
 {
-  unsigned long value, flags;
+	unsigned long value, flags;
 
-  if(sock>1) return -1;
-#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  if(sock==0) return 0;
-#endif
-  local_irq_save(flags);
+	local_irq_save(flags);
 
-  /* Murphy: BUS_ON different from POWER ? */
+	/* Murphy: BUS_ON different from POWER ? */
 
-  switch(configure->vcc){
-  case 0:
-    break;
+	switch (state->Vcc) {
+	case 0:
+		break;
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  case 50:
-    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-	   __FUNCTION__);
-  case 33:  /* Can only apply 3.3V to the CF slot. */
-    break;
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__FUNCTION__);
+	case 33:  /* Can only apply 3.3V to the CF slot. */
+		break;
 #else
-  case 50:
-    printk(KERN_WARNING "%s(): CS asked for 5V, determinded by jumper setting...\n", __FUNCTION__);
-    break;
-  case 33:
-    printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by jumper setting...\n", __FUNCTION__);
-    break;
-#endif
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    local_irq_restore(flags);
-    return -1;
-  }
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, determinded by "
+			"jumper setting...\n", __FUNCTION__);
+		break;
+	case 33:
+		printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by "
+			"jumper setting...\n", __FUNCTION__);
+		break;
+#endif
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__FUNCTION__, state->Vcc);
+		local_irq_restore(flags);
+		return -1;
+	}
 #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  /* reset & unreset request */
-  if(sock==0) {
-	if(configure->reset) {
-		GPSR |= GPIO_PCMCIA_RESET;
-	} else {
-		GPCR |= GPIO_PCMCIA_RESET;
+	/* reset & unreset request */
+	if (skt->nr == 0) {
+		if (state->flags & SS_RESET) {
+			GPSR = GPIO_PCMCIA_RESET;
+		} else {
+			GPCR = GPIO_PCMCIA_RESET;
+		}
 	}
-  }
 #endif
-  /* Silently ignore Vpp, output enable, speaker enable. */
-  local_irq_restore(flags);
-  return 0;
+	/* Silently ignore Vpp, output enable, speaker enable. */
+	local_irq_restore(flags);
+	return 0;
 }
 
-static int pangolin_pcmcia_socket_init(int sock)
+static void pangolin_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 1)
-    set_irq_type(IRQ_PCMCIA_CD, IRQT_BOTHEDGE);
-  return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int pangolin_pcmcia_socket_suspend(int sock)
+static void pangolin_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  if (sock == 1)
-    set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
-  return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level pangolin_pcmcia_ops = { 
-  .owner		= THIS_MODULE,
-  .init			= pangolin_pcmcia_init,
-  .shutdown		= pangolin_pcmcia_shutdown,
-  .socket_state		= pangolin_pcmcia_socket_state,
-  .configure_socket	= pangolin_pcmcia_configure_socket,
+	.owner			= THIS_MODULE,
+	.hw_init		= pangolin_pcmcia_hw_init,
+	.hw_shutdown		= pangolin_pcmcia_hw_shutdown,
+	.socket_state		= pangolin_pcmcia_socket_state,
+	.configure_socket	= pangolin_pcmcia_configure_socket,
 
-  .socket_init		= pangolin_pcmcia_socket_init,
-  .socket_suspend	= pangolin_pcmcia_socket_suspend,
+	.socket_init		= pangolin_pcmcia_socket_init,
+	.socket_suspend		= pangolin_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_pangolin_init(struct device *dev)
@@ -157,13 +141,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_pangolin())
-		ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &pangolin_pcmcia_ops, PANGOLIN_SOCK, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_pangolin_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&pangolin_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_pfs168.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_pfs168.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_pfs168.c	Mon Mar 24 14:00:18 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_pfs168.c	Mon Mar 31 12:52:29 2003
@@ -16,10 +16,9 @@
 #include <asm/mach-types.h>
 #include <asm/irq.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
-static int pfs168_pcmcia_init(struct pcmcia_init *init)
+static int pfs168_pcmcia_init(struct sa1100_pcmcia_socket *skt)
 {
   /* TPS2211 to standby mode: */
   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
@@ -27,11 +26,12 @@
   /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  return sa1111_pcmcia_init(init);
+  return sa1111_pcmcia_init(skt);
 }
 
 static int
-pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+pfs168_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			       const socket_state_t *state)
 {
   unsigned int pa_dwr_mask = 0, pa_dwr_set = 0;
   int ret;
@@ -48,33 +48,33 @@
    *
    */
 
-  switch (sock) {
+  switch (skt->nr) {
   case 0:
     pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-    switch (conf->vcc) {
+    switch (state->Vcc) {
     default:
     case 0:	pa_dwr_set = 0;			break;
     case 33:	pa_dwr_set = GPIO_GPIO0;	break;
     case 50:	pa_dwr_set = GPIO_GPIO1;	break;
     }
 
-    switch (conf->vpp) {
+    switch (state->Vpp) {
     case 0:
       break;
 
     case 120:
       printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n",
-	     __FUNCTION__, conf->vpp / 10);
+	     __FUNCTION__, state->Vpp / 10);
       return -1;
       break;
 
     default:
-      if (conf->vpp == conf->vcc)
+      if (state->Vpp == state->Vcc)
         pa_dwr_set |= GPIO_GPIO3;
       else {
 	printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__,
-	       conf->vpp);
+	       state->Vpp);
 	return -1;
       }
     }
@@ -91,24 +91,24 @@
 
     case 50:
       printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n",
-	     __FUNCTION__, conf->vcc / 10);
+	     __FUNCTION__, state->Vcc / 10);
       return -1;
 
     default:
       printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__,
-	     conf->vcc);
+	     state->Vcc);
       return -1;
     }
 
-    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    if (state->Vpp != state->Vcc && state->Vpp != 0) {
       printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n"
-	     __FUNCTION__, conf->vpp / 10);
+	     __FUNCTION__, state->Vpp / 10);
       return -1;
     }
     break;
   }
 
-  ret = sa1111_pcmcia_configure_socket(sock, conf);
+  ret = sa1111_pcmcia_configure_socket(skt, state);
   if (ret == 0) {
     unsigned long flags;
 
@@ -121,14 +121,13 @@
 }
 
 static struct pcmcia_low_level pfs168_pcmcia_ops = {
-  .owner		= THIS_MODULE,
-  .init			= pfs168_pcmcia_init,
-  .shutdown		= sa1111_pcmcia_shutdown,
-  .socket_state		= sa1111_pcmcia_socket_state,
-  .configure_socket	= pfs168_pcmcia_configure_socket,
-
-  .socket_init		= sa1111_pcmcia_socket_init,
-  .socket_suspend	= sa1111_pcmcia_socket_suspend,
+	.owner			= THIS_MODULE,
+	.hw_init		= pfs168_pcmcia_hw_init,
+	.hw_shutdown		= sa1111_pcmcia_hw_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.configure_socket	= pfs168_pcmcia_configure_socket,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_pfs168_init(struct device *dev)
@@ -136,12 +135,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_pfs168())
-		ret = sa1100_register_pcmcia(&pfs168_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &pfs168_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_pfs168_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&pfs168_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_shannon.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_shannon.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_shannon.c	Mon Mar 24 14:01:25 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_shannon.c	Mon Mar 31 12:52:29 2003
@@ -16,64 +16,36 @@
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
-	{ SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
+static struct pcmcia_irqs irqs[] = {
+	{ 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
+	{ 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
 };
 
-static int shannon_pcmcia_init(struct pcmcia_init *init)
+static int shannon_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i, res;
-
 	/* All those are inputs */
 	GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
 		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
 	GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
 		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
 
-	init->socket_irq[0] = SHANNON_IRQ_GPIO_RDY_0;
-	init->socket_irq[1] = SHANNON_IRQ_GPIO_RDY_1;
-
-	/* Register interrupts */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (res)
-			goto irq_err;
-		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-	}
-
-	return 2;
+	skt->irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0;
 
- irq_err:
-	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-		__FUNCTION__, irqs[i].irq, res);
-
-	while (i--)
-		free_irq(irqs[i].irq, NULL);
-
-	return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int shannon_pcmcia_shutdown(void)
+static void shannon_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	/* disable IRQs */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		free_irq(irqs[i].irq, NULL);
-
-	return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static void shannon_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+shannon_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			    struct pcmcia_state *state)
 {
 	unsigned long levels = GPLR;
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
 		state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
 		state->ready  = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
@@ -96,9 +68,11 @@
 	}
 }
 
-static int shannon_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure)
+static int
+shannon_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				const socket_state_t *state)
 {
-	switch (configure->vcc) {
+	switch (state->Vcc) {
 	case 0:	/* power off */
 		printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n");
 		break;
@@ -108,7 +82,7 @@
 		break;
 	default:
 		printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
-		       configure->vcc);
+		       state->Vcc);
 		return -1;
 	}
 
@@ -119,30 +93,20 @@
 	return 0;
 }
 
-static int shannon_pcmcia_socket_init(int sock)
+static void shannon_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-	if (sock == 0)
-		set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_BOTHEDGE);
-	else if (sock == 1)
-		set_irq_Type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_BOTHEDGE);
-
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int shannon_pcmcia_socket_suspend(int sock)
+static void shannon_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	if (sock == 0)
-		set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_NOEDGE);
-	else if (sock == 1)
-		set_irq_type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_NOEDGE);
-
-	return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level shannon_pcmcia_ops = {
 	.owner			= THIS_MODULE,
-	.init			= shannon_pcmcia_init,
-	.shutdown		= shannon_pcmcia_shutdown,
+	.hw_init		= shannon_pcmcia_hw_init,
+	.hw_shutdown		= shannon_pcmcia_hw_shutdown,
 	.socket_state		= shannon_pcmcia_socket_state,
 	.configure_socket	= shannon_pcmcia_configure_socket,
 
@@ -155,12 +119,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_shannon())
-		ret = sa1100_register_pcmcia(&shannon_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &shannon_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_shannon_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&shannon_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_simpad.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_simpad.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_simpad.c	Mon Mar 24 14:01:47 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_simpad.c	Mon Mar 31 12:52:29 2003
@@ -19,134 +19,110 @@
 extern void set_cs3_bit(int value); 
 extern void clear_cs3_bit(int value);
 
+static struct pcmcia_irqs irqs[] = {
+	{ 1, IRQ_GPIO_CF_CD, "CF_CD" },
+};
 
-static int simpad_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
-
-  set_cs3_bit(PCMCIA_RESET);
-  clear_cs3_bit(PCMCIA_BUFF_DIS);
-  clear_cs3_bit(PCMCIA_RESET);
-
-  clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
-
-  init->socket_irq[1] = IRQ_GPIO_CF_IRQ;
-
-  /* Register interrupts */
-  irq = IRQ_GPIO_CF_CD;
-  res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT,
-		    "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
+static int simpad_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
+{
+	set_cs3_bit(PCMCIA_RESET);
+	clear_cs3_bit(PCMCIA_BUFF_DIS);
+	clear_cs3_bit(PCMCIA_RESET);
 
-  set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE );
+	clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
 
-  /* There's only one slot, but it's "Slot 1": */
-  return 2;
+	skt->irq = IRQ_GPIO_CF_IRQ;
 
-irq_err:
-  printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	 __FUNCTION__, irq, res);
-  return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int simpad_pcmcia_shutdown(void)
+static void simpad_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-  /* disable IRQs */
-  free_irq( IRQ_GPIO_CF_CD, NULL );
-  
-  /* Disable CF bus: */
-  
-  //set_cs3_bit(PCMCIA_BUFF_DIS);
-  clear_cs3_bit(PCMCIA_RESET);       
-  
-  return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+	/* Disable CF bus: */
+	//set_cs3_bit(PCMCIA_BUFF_DIS);
+	clear_cs3_bit(PCMCIA_RESET);       
 }
 
-static void simpad_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+simpad_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			   struct pcmcia_state *state)
 {
-  if (sock == 1) {
-    unsigned long levels = GPLR;
-    unsigned long *cs3reg = CS3_BASE;
+	unsigned long levels = GPLR;
+	unsigned long *cs3reg = CS3_BASE;
 
-    state->detect=((levels & GPIO_CF_CD)==0)?1:0;
-    state->ready=(levels & GPIO_CF_IRQ)?1:0;
-    state->bvd1=1; /* Not available on Simpad. */
-    state->bvd2=1; /* Not available on Simpad. */
-    state->wrprot=0; /* Not available on Simpad. */
+	state->detect=((levels & GPIO_CF_CD)==0)?1:0;
+	state->ready=(levels & GPIO_CF_IRQ)?1:0;
+	state->bvd1=1; /* Not available on Simpad. */
+	state->bvd2=1; /* Not available on Simpad. */
+	state->wrprot=0; /* Not available on Simpad. */
   
-    if((*cs3reg & 0x0c) == 0x0c) {
-      state->vs_3v=0;
-      state->vs_Xv=0;
-    } else {
-      state->vs_3v=1;
-      state->vs_Xv=0;
-    }
-  }
+	if((*cs3reg & 0x0c) == 0x0c) {
+		state->vs_3v=0;
+		state->vs_Xv=0;
+	} else {
+		state->vs_3v=1;
+		state->vs_Xv=0;
+	}
 }
 
-static int simpad_pcmcia_configure_socket(int sock, const struct pcmcia_configure
-					   *configure)
+static int
+simpad_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			       const socket_state_t *state)
 {
-  unsigned long value, flags;
-
-  if(sock>1) return -1;
-
-  if(sock==0) return 0;
-
-  local_irq_save(flags);
-
-  /* Murphy: see table of MIC2562a-1 */
+	unsigned long value, flags;
 
-  switch(configure->vcc){
-  case 0:
-    clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
-    break;
+	local_irq_save(flags);
 
-  case 33:  
-    clear_cs3_bit(VCC_3V_EN|EN0);
-    set_cs3_bit(VCC_5V_EN|EN1);
-    break;
+	/* Murphy: see table of MIC2562a-1 */
+	switch (state->Vcc) {
+	case 0:
+		clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+		break;
 
-  case 50:
-    clear_cs3_bit(VCC_5V_EN|EN1);
-    set_cs3_bit(VCC_3V_EN|EN0);
-    break;
+	case 33:  
+		clear_cs3_bit(VCC_3V_EN|EN0);
+		set_cs3_bit(VCC_5V_EN|EN1);
+		break;
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
-    local_irq_restore(flags);
-    return -1;
-  }
+	case 50:
+		clear_cs3_bit(VCC_5V_EN|EN1);
+		set_cs3_bit(VCC_3V_EN|EN0);
+		break;
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			__FUNCTION__, state->Vcc);
+		clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+		local_irq_restore(flags);
+		return -1;
+	}
 
-  local_irq_restore(flags);
+	/* Silently ignore Vpp, output enable, speaker enable. */
+	local_irq_restore(flags);
 
-  return 0;
+	return 0;
 }
 
-static int simpad_pcmcia_socket_init(int sock)
+static void simpad_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-  set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE);
-  return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int simpad_pcmcia_socket_suspend(int sock)
+static void simpad_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-  set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE);
-  return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level simpad_pcmcia_ops = { 
-  .owner		= THIS_MODULE,
-  .init			= simpad_pcmcia_init,
-  .shutdown		= simpad_pcmcia_shutdown,
-  .socket_state		= simpad_pcmcia_socket_state,
-  .configure_socket	= simpad_pcmcia_configure_socket,
-
-  .socket_init		= simpad_pcmcia_socket_init,
-  .socket_suspend	= simpad_pcmcia_socket_suspend,
+	.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_init		= simpad_pcmcia_socket_init,
+	.socket_suspend		= simpad_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_simpad_init(struct device *dev)
@@ -154,12 +130,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_simpad())
-		ret = sa1100_register_pcmcia(&simpad_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_simpad_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&simpad_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_stork.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_stork.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_stork.c	Mon Mar 24 14:00:40 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_stork.c	Mon Mar 31 12:52:29 2003
@@ -32,62 +32,39 @@
 
 static int debug = 0;
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" },
-	{ IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" },
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" },
+	{ 1, IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" },
 };
 
-static int stork_pcmcia_init(struct pcmcia_init *init)
+static int stork_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int irq, res;
-
 	printk("in stork_pcmcia_init\n");
 
-	init->socket_irq[0] = IRQ_GPIO_STORK_PCMCIA_A_RDY;
-	init->socket_irq[1] = IRQ_GPIO_STORK_PCMCIA_B_RDY;
-
-	/* Register interrupts */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (res)
-			goto irq_err;
-		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-	}
-
-        return 2;
-
- irq_err:
-        printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	       __FUNCTION__, irq, res);
+	skt->irq = skt->nr ? IRQ_GPIO_STORK_PCMCIA_B_RDY
+			   : IRQ_GPIO_STORK_PCMCIA_A_RDY;
 
-	while (i--)
-		free_irq(irqs[i].irq, NULL);
-
-        return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int stork_pcmcia_shutdown(void)
+static void stork_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
 	int i;
 
         printk(__FUNCTION__ "\n");
 
         /* disable IRQs */
-        for (i = 0; i < ARRAY_SIZE(irqs); i++)
-        	free_irq(irqs[i].irq, NULL);
+        sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
   
         /* Disable CF bus: */
         storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
 	storkClearLatchA(STORK_PCMCIA_A_POWER_ON);
 	storkClearLatchA(STORK_PCMCIA_B_POWER_ON);
-        return 0;
 }
 
-static void stork_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+stork_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			  struct pcmcia_state *state)
 {
         unsigned long levels = GPLR;
 
@@ -95,7 +72,7 @@
 		printk(__FUNCTION__ " GPLR=%x IRQ[1:0]=%x\n", levels,
 			(levels & (GPIO_STORK_PCMCIA_A_RDY|GPIO_STORK_PCMCIA_B_RDY)));
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
 		state->detect=((levels & GPIO_STORK_PCMCIA_A_CARD_DETECT)==0)?1:0;
 		state->ready=(levels & GPIO_STORK_PCMCIA_A_RDY)?1:0;
@@ -118,20 +95,19 @@
 	}
 }
 
-static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure)
+static int
+stork_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			      const socket_state_t *state)
 {
 	unsigned long flags;
-
         int DETECT, RDY, POWER, RESET;
 
-        if (sock > 1) return -1;
-
-	printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", 
-                       sock, configure->vcc, configure->vpp, configure->reset);
+	printk("%s: socket=%d vcc=%d vpp=%d reset=%d\n", __FUNCTION__,
+		skt->nr, state->Vcc, state->Vpp, state->flags & SS_RESET ? 1 : 0);
 
 	local_irq_save(flags);
 
-        if (sock == 0) {
+        if (skt->nr == 0) {
     	    DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT;
     	    RDY = GPIO_STORK_PCMCIA_A_RDY;
     	    POWER = STORK_PCMCIA_A_POWER_ON;
@@ -148,7 +124,7 @@
            printk("no card detected - but resetting anyway\r\n");
         }
 */
-	switch (configure->vcc) {
+	switch (state->Vcc) {
 	case 0:
 /*		storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); */
                 storkClearLatchA(POWER);
@@ -162,12 +138,12 @@
 
 	default:
 		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-		       configure->vcc);
+		       state->Vcc);
 		local_irq_restore(flags);
 		return -1;
 	}
 
-	if (configure->reset)
+	if (state->flags & SS_RESET)
                 storkSetLatchB(RESET);
 	else
                 storkClearLatchB(RESET);
@@ -176,43 +152,35 @@
 
         /* silently ignore vpp and speaker enables. */
 
-        printk(__FUNCTION__ ": finished\n");
+        printk("%s: finished\n", __FUNCTION__);
 
         return 0;
 }
 
-static int stork_pcmcia_socket_init(int sock)
+static void stork_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
         storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
 
-        if (sock == 0)
-		set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_BOTHEDGE);
-        else if (sock == 1)
-		set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_BOTHEDGE);
-
-	return 0;
+        sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int stork_pcmcia_socket_suspend(int sock)
+static void stork_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-        if (sock == 0)
-		set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_NOEDGE);
-        else if (sock == 1) {
-		set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_NOEDGE);
-
-		/*
-		 * Hack!
-		 */
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+	/*
+	 * Hack!
+	 */
+	if (skt->nr == 1)
 	        storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
-	}
 
 	return 0;
 }
 
 static struct pcmcia_low_level stork_pcmcia_ops = { 
 	.owner			= THIS_MODULE,
-	.init			= stork_pcmcia_init,
-	.shutdown		= stork_pcmcia_shutdown,
+	.hw_init		= stork_pcmcia_hw_init,
+	.hw_shutdown		= stork_pcmcia_hw_shutdown,
 	.socket_state		= stork_pcmcia_socket_state,
 	.configure_socket	= stork_pcmcia_configure_socket,
 
@@ -225,13 +193,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_stork())
-		ret = sa1100_register_pcmcia(&stork_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &stork_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_stork_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&stork_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_system3.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_system3.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_system3.c	Mon Mar 24 14:01:48 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_system3.c	Mon Mar 31 12:52:29 2003
@@ -37,7 +37,6 @@
 #include <asm/irq.h>
 #include <asm/hardware/sa1111.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
 #define DEBUG 0
@@ -48,34 +47,24 @@
 #	define DPRINTK( x, args... )	/* nix */
 #endif
 
-int system3_pcmcia_init(struct pcmcia_init *init)
+static int system3_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	init->socket_irq[0] = IRQ_S0_READY_NINT;
-	init->socket_irq[1] = IRQ_S1_READY_NINT;
+	skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT;
 
 	/* Don't need no CD and BVD* interrupts */
-	return 2;
-}
-
-int system3_pcmcia_shutdown(void)
-{
 	return 0;
 }
 
-int system3_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+void system3_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	/* only CF ATM */
-	if (sock == 0)
-		return -1;
-
-	return sa1111_pcmcia_configure_socket(sock, conf);
 }
 
-static void system3_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+static void
+system3_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
 	unsigned long status = PCSR;
 
-	switch (sock) {
+	switch (skt->nr) {
 #if 0 /* PCMCIA socket not yet connected */
 	case 0:
 		state->detect = status & PCSR_S0_DETECT ? 0 : 1;
@@ -100,15 +89,15 @@
 	}
 
 	DPRINTK("Sock %d PCSR=0x%08lx, Sx_RDY_nIREQ=%d\n",
-		sock, status, state->ready);
+		skt->nr, status, state->ready);
 }
 
 struct pcmcia_low_level system3_pcmcia_ops = {
 	.owner			= THIS_MODULE,
-	.init			= system3_pcmcia_init,
-	.shutdown		= system3_pcmcia_shutdown,
+	.init			= system3_pcmcia_hw_init,
+	.shutdown		= system3_pcmcia_hw_shutdown,
 	.socket_state		= system3_pcmcia_socket_state,
-	.configure_socket	= system3_pcmcia_configure_socket,
+	.configure_socket	= sa1111_pcmcia_configure_socket,
 
 	.socket_init		= sa1111_pcmcia_socket_init,
 	.socket_suspend		= sa1111_pcmcia_socket_suspend,
@@ -119,12 +108,8 @@
 	int ret = -ENODEV;
 
 	if (machine_is_pt_system3())
-		ret = sa1100_register_pcmcia(&system3_pcmcia_ops, dev);
+		/* only CF ATM */
+		ret = sa11xx_drv_pcmcia_probe(dev, &system3_pcmcia_ops, 1, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_system3_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&system3_pcmcia_ops, dev);
-}
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_trizeps.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_trizeps.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_trizeps.c	Mon Mar 24 14:00:48 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_trizeps.c	Mon Mar 31 12:52:29 2003
@@ -23,15 +23,18 @@
 #include "sa1100_generic.h"
 
 #define NUMBER_OF_TRIZEPS_PCMCIA_SLOTS 1
+
+static struct pcmcia_irqs irqs[] = {
+	{ 0, TRIZEPS_IRQ_PCMCIA_CD0, "PCMCIA_CD0" },
+};
+
 /**
  *
  *
  ******************************************************/
-static int trizeps_pcmcia_init(struct pcmcia_init *init)
+static int trizeps_pcmcia_init(struct sa1100_pcmcia_socket *skt)
 {
-	int res;
-
-	init->socket_irq[0] = TRIZEPS_IRQ_PCMCIA_IRQ0;
+	skt->irq = TRIZEPS_IRQ_PCMCIA_IRQ0;
 
 	/* Enable CF bus: */
 	TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG);
@@ -40,74 +43,54 @@
 	GPDR &= ~((GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0))
 		    | (GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)));
 
-	/* Register SOCKET interrupts */
-	/* WHY? */
-	res = request_irq(TRIZEPS_IRQ_PCMCIA_CD0, sa1100_pcmcia_interrupt,
-			  SA_INTERRUPT, "PCMCIA_CD0", NULL );
-	if( res < 0 ) goto irq_err;
-	set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE);
-
-	//MECR = 0x00060006; // Initialised on trizeps init
-
-	// return=sa1100_pcmcia_socket_count (sa1100_generic.c)
-	//        -> number of PCMCIA Slots
-	// Slot 0 -> Trizeps PCMCIA
-	// Slot 1 -> Trizeps ISA-Bus
-	return NUMBER_OF_TRIZEPS_PCMCIA_SLOTS;
-
- irq_err:
-	printk( KERN_ERR "%s(): PCMCIA Request for IRQ %u failed\n", __FUNCTION__, TRIZEPS_IRQ_PCMCIA_CD0 );
-	return -1;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 /**
  *
  *
  ******************************************************/
-static int trizeps_pcmcia_shutdown(void)
+static void trizeps_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt)
 {
 	printk(">>>>>PCMCIA TRIZEPS shutdown\n");
-	/* disable IRQs */
-	free_irq(TRIZEPS_IRQ_PCMCIA_CD0, NULL );
+
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 
 	/* Disable CF bus: */
 	TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG);
-
-	return 0;
 }
 
 /**
  *
-
  ******************************************************/
-static void trizeps_pcmcia_socket_state(int sock, struct pcmcia_state *state_array)
+static void
+trizeps_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			    struct pcmcia_state *state_array)
 {
 	unsigned long levels = GPLR;
 
-	if (sock == 0) {
-		state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0;
-		state->ready  = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0;
-		state->bvd1   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0;
-		state->bvd2   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0;
-		state->wrprot = 0; // not write protected
-		state->vs_3v  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1
-		state->vs_Xv  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1
-	}
+	state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0;
+	state->ready  = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0;
+	state->bvd1   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0;
+	state->bvd2   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0;
+	state->wrprot = 0; // not write protected
+	state->vs_3v  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1
+	state->vs_Xv  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1
 }
 
 /**
  *
  *
  ******************************************************/
-static int trizeps_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure)
+static int
+trizeps_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+				const socket_state_t *state)
 {
 	unsigned long flags;
 
-	if(sock>1) return -1;
-
 	local_irq_save(flags);
 
-	switch (configure->vcc) {
+	switch (state->Vcc) {
 	case 0:
 		printk(">>> PCMCIA Power off\n");
 		TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG);
@@ -126,19 +109,19 @@
 		break;
 	default:
 		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-		       configure->vcc);
+		       state->Vcc);
 		local_irq_restore(flags);
 		return -1;
 	}
 
-	if (configure->reset)
+	if (state->flags & SS_RESET)
 		TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE);   // Reset
 	else
 		TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // no Reset
 	/*
 	  printk(" vcc=%u vpp=%u -->reset=%i\n",
-	  configure->vcc,
-	  configure->vpp,
+	  state->Vcc,
+	  state->Vpp,
 	  ((BCR_read(1) & nPCM_RESET_DISABLE)? 1:0));
 	*/
 	local_irq_restore(flags);
@@ -146,16 +129,14 @@
 	return 0;
 }
 
-static int trizeps_pcmcia_socket_init(int sock)
+static void trizeps_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-	set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_BOTHEDGE);
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int trizeps_pcmcia_socket_suspend(int sock)
+static void trizeps_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE);
-	return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 /**
@@ -164,8 +145,8 @@
  ******************************************************/
 struct pcmcia_low_level trizeps_pcmcia_ops = {
 	.owner			= THIS_MODULE,
-	.init			= trizeps_pcmcia_init,
-	.shutdown		= trizeps_pcmcia_shutdown,
+	.hw_init		= trizeps_pcmcia_hw_init,
+	.hw_shutdown		= trizeps_pcmcia_hw_shutdown,
 	.socket_state		= trizeps_pcmcia_socket_state,
 	.configure_socket	= trizeps_pcmcia_configure_socket,
 	.socket_init		= trizeps_pcmcia_socket_init,
@@ -174,13 +155,11 @@
 
 int __init pcmcia_trizeps_init(struct device *dev)
 {
-	if (machine_is_trizeps()) {
-		return sa1100_register_pcmcia(&trizeps_pcmcia_ops, dev);
-	}
-	return -ENODEV;
-}
+	int ret = -ENODEV;
 
-void __exit pcmcia_trizeps_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&trizeps_pcmcia_ops, dev);
+	if (machine_is_trizeps())
+		ret = sa11xx_drv_pcmcia_probe(dev, &trizeps_pcmcia_ops, 0,
+					      NUMBER_OF_TRIZEPS_PCMCIA_SLOTS);
+
+	return ret;
 }
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_xp860.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_xp860.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_xp860.c	Mon Mar 24 14:00:19 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_xp860.c	Mon Mar 31 12:52:29 2003
@@ -19,7 +19,7 @@
 #define NCR_A0VPP	(1<<16)
 #define NCR_A1VPP	(1<<17)
 
-static int xp860_pcmcia_init(struct pcmcia_init *init)
+static int xp860_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
@@ -38,11 +38,11 @@
   GPDR |= (NCR_A0VPP | NCR_A1VPP);
   GPCR &= ~(NCR_A0VPP | NCR_A1VPP);
 
-  return sa1111_pcmcia_init(init);
+  return sa1111_pcmcia_hw_init(skt);
 }
 
 static int
-xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+xp860_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
   unsigned int gpio_mask, pa_dwr_mask;
   unsigned int gpio_set, pa_dwr_set;
@@ -72,28 +72,28 @@
    * the corresponding truth table.
    */
 
-  switch (sock) {
+  switch (skt->nr) {
   case 0:
     pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
     gpio_mask = NCR_A0VPP | NCR_A1VPP;
 
-    switch (conf->vcc) {
+    switch (state->Vcc) {
     default:
     case 0:	pa_dwr_set = 0;			break;
     case 33:	pa_dwr_set = GPIO_GPIO1;	break;
     case 50:	pa_dwr_set = GPIO_GPIO0;	break;
     }
 
-    switch (conf->vpp) {
+    switch (state->Vpp) {
     case 0:	gpio_set = 0;			break;
     case 120:	gpio_set = NCR_A1VPP;		break;
 
     default:
-      if (conf->vpp == conf->vcc)
+      if (state->Vpp == state->Vcc)
 	gpio_set = NCR_A0VPP;
       else {
 	printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-	       __FUNCTION__, conf->vpp);
+	       __FUNCTION__, state->Vpp);
 	return -1;
       }
     }
@@ -104,22 +104,22 @@
     gpio_mask = 0;
     gpio_set = 0;
 
-    switch (conf->vcc) {
+    switch (state->Vcc) {
     default:
     case 0:	pa_dwr_set = 0;			break;
     case 33:	pa_dwr_set = GPIO_GPIO2;	break;
     case 50:	pa_dwr_set = GPIO_GPIO3;	break;
     }
 
-    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    if (state->Vpp != state->Vcc && state->Vpp != 0) {
       printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
-	     __FUNCTION__, conf->vpp);
+	     __FUNCTION__, state->Vpp);
       return -1;
     }
     break;
   }
 
-  ret = sa1111_pcmcia_configure_socket(sock, conf);
+  ret = sa1111_pcmcia_configure_socket(skt, state);
   if (ret == 0) {
     unsigned long flags;
 
@@ -134,14 +134,13 @@
 }
 
 static struct pcmcia_low_level xp860_pcmcia_ops = { 
-  .owner		= THIS_MODULE,
-  .init			= xp860_pcmcia_init,
-  .shutdown		= sa1111_pcmcia_shutdown,
-  .socket_state		= sa1111_pcmcia_socket_state,
-  .configure_socket	= xp860_pcmcia_configure_socket,
-
-  .socket_init		= sa1111_pcmcia_socket_init,
-  .socket_suspend	= sa1111_pcmcia_socket_suspend,
+	.owner			= THIS_MODULE,
+	.hw_init		= xp860_pcmcia_hw_init,
+	.hw_shutdown		= sa1111_pcmcia_hw_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.configure_socket	= xp860_pcmcia_configure_socket,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_xp860_init(struct device *dev)
@@ -149,13 +148,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_xp860())
-		ret = sa1100_register_pcmcia(&xp860_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &xp860_pcmcia_ops, 0, 2);
 
 	return ret;
 }
-
-void __exit pcmcia_xp860_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&xp860_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1100_yopy.c linux-2.5.66-bk6/drivers/pcmcia/sa1100_yopy.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1100_yopy.c	Mon Mar 24 14:01:14 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1100_yopy.c	Mon Mar 31 12:52:29 2003
@@ -27,81 +27,51 @@
 	yopy_gpio_set(GPIO_CF_RESET, reset);
 }
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_CF_CD,   "CF_CD"   },
-	{ IRQ_CF_BVD2, "CF_BVD2" },
-	{ IRQ_CF_BVD1, "CF_BVD1" },
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_CF_CD,   "CF_CD"   },
+	{ 0, IRQ_CF_BVD2, "CF_BVD2" },
+	{ 0, IRQ_CF_BVD1, "CF_BVD1" },
 };
 
-static int yopy_pcmcia_init(struct pcmcia_init *init)
+static int yopy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i, res;
-
-	init->socket_irq[0] = IRQ_CF_IREQ;
+	skt->irq = IRQ_CF_IREQ;
 
 	pcmcia_power(0);
 	pcmcia_reset(1);
 
-	/* Register interrupts */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (res)
-			goto irq_err;
-		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-	}
-
-	return 1;
-
- irq_err:
-	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
-	       __FUNCTION__, irqs[i].irq, res);
-
-	while (i--)
-		free_irq(irqs[i].irq, NULL);
-
-	return res;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int yopy_pcmcia_shutdown(void)
+static void yopy_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	/* disable IRQs */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		free_irq(irqs[i].irq, NULL);
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 
 	/* Disable CF */
 	pcmcia_reset(1);
 	pcmcia_power(0);
-
-	return 0;
 }
 
-static void yopy_pcmcia_socket_state(int sock, struct pcmcia_state_array *state)
+static void
+yopy_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
+			 struct pcmcia_state_array *state)
 {
 	unsigned long levels = GPLR;
 
-	if (sock == 0) {
-		state->detect = (levels & GPIO_CF_CD)    ? 0 : 1;
-		state->ready  = (levels & GPIO_CF_READY) ? 1 : 0;
-		state->bvd1   = (levels & GPIO_CF_BVD1)  ? 1 : 0;
-		state->bvd2   = (levels & GPIO_CF_BVD2)  ? 1 : 0;
-		state->wrprot = 0; /* Not available on Yopy. */
-		state->vs_3v  = 0; /* FIXME Can only apply 3.3V on Yopy. */
-		state->vs_Xv  = 0;
-	}
+	state->detect = (levels & GPIO_CF_CD)    ? 0 : 1;
+	state->ready  = (levels & GPIO_CF_READY) ? 1 : 0;
+	state->bvd1   = (levels & GPIO_CF_BVD1)  ? 1 : 0;
+	state->bvd2   = (levels & GPIO_CF_BVD2)  ? 1 : 0;
+	state->wrprot = 0; /* Not available on Yopy. */
+	state->vs_3v  = 0; /* FIXME Can only apply 3.3V on Yopy. */
+	state->vs_Xv  = 0;
 }
 
-static int yopy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure)
+static int
+yopy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt,
+			     const socket_state_t *state)
 {
-	if (sock != 0)
-		return -1;
-
-	switch (configure->vcc) {
+	switch (state->Vcc) {
 	case 0:	/* power off */
 		pcmcia_power(0);
 		break;
@@ -112,35 +82,25 @@
 		break;
 	default:
 		printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
-		       configure->vcc);
+		       state->Vcc);
 		return -1;
 	}
 
-	pcmcia_reset(configure->reset);
+	pcmcia_reset(state->flags & SS_RESET ? 1 : 0);
 
 	/* Silently ignore Vpp, output enable, speaker enable. */
 
 	return 0;
 }
 
-static int yopy_pcmcia_socket_init(int sock)
+static void yopy_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
-
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-static int yopy_pcmcia_socket_suspend(int sock)
+static void yopy_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
-
-	return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static struct pcmcia_low_level yopy_pcmcia_ops = {
@@ -159,13 +119,7 @@
 	int ret = -ENODEV;
 
 	if (machine_is_yopy())
-		ret = sa1100_register_pcmcia(&yopy_pcmcia_ops, dev);
+		ret = sa11xx_drv_pcmcia_probe(dev, &yopy_pcmcia_ops, 0, 1);
 
 	return ret;
 }
-
-void __exit pcmcia_yopy_exit(struct device *dev)
-{
-	sa1100_unregister_pcmcia(&yopy_pcmcia_ops, dev);
-}
-
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1111_generic.c linux-2.5.66-bk6/drivers/pcmcia/sa1111_generic.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa1111_generic.c	Mon Mar 24 14:00:13 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1111_generic.c	Mon Mar 31 12:52:29 2003
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/pcmcia/sa1100_sa1111.c
+ * 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
@@ -19,63 +19,34 @@
 #include <asm/hardware/sa1111.h>
 #include <asm/irq.h>
 
-#include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
-static struct irqs {
-	int irq;
-	const char *str;
-} irqs[] = {
-	{ IRQ_S0_CD_VALID,    "SA1111 PCMCIA card detect" },
-	{ IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
-	{ IRQ_S1_CD_VALID,    "SA1111 CF card detect"     },
-	{ IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_S0_CD_VALID,    "SA1111 PCMCIA card detect" },
+	{ 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
+	{ 1, IRQ_S1_CD_VALID,    "SA1111 CF card detect"     },
+	{ 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
 };
 
-static struct sa1111_dev *pcmcia;
-
-int sa1111_pcmcia_init(struct pcmcia_init *init)
+int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt)
 {
-	int i, ret;
-
-	if (init->socket_irq[0] == NO_IRQ)
-		init->socket_irq[0] = IRQ_S0_READY_NINT;
-	if (init->socket_irq[1] == NO_IRQ)
-		init->socket_irq[1] = IRQ_S1_READY_NINT;
-
-	for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
-		ret = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
-				  SA_INTERRUPT, irqs[i].str, NULL);
-		if (ret)
-			break;
-		set_irq_type(irqs[i].irq, IRQT_FALLING);
-	}
+	if (skt->irq == NO_IRQ)
+		skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT;
 
-	if (i < ARRAY_SIZE(irqs)) {
-		printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n",
-			irqs[i].irq, ret);
-		while (i--)
-			free_irq(irqs[i].irq, NULL);
-	}
-
-	return ret ? -1 : 2;
+	return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-int sa1111_pcmcia_shutdown(void)
+void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		free_irq(irqs[i].irq, NULL);
-
-	return 0;
+	sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *state)
+void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-	unsigned long status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR);
+	struct sa1111_dev *sadev = SA1111_DEV(skt->dev);
+	unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR);
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
 		state->detect = status & PCSR_S0_DETECT ? 0 : 1;
 		state->ready  = status & PCSR_S0_READY  ? 1 : 0;
@@ -98,91 +69,61 @@
 	}
 }
 
-int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf)
+int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state)
 {
-	unsigned int rst, flt, wait, pse, irq, pccr_mask, val;
+	struct sa1111_dev *sadev = SA1111_DEV(skt->dev);
+	unsigned int pccr_skt_mask, pccr_set_mask, val;
 	unsigned long flags;
 
-	switch (sock) {
+	switch (skt->nr) {
 	case 0:
-		rst = PCCR_S0_RST;
-		flt = PCCR_S0_FLT;
-		wait = PCCR_S0_PWAITEN;
-		pse = PCCR_S0_PSE;
-		irq = IRQ_S0_READY_NINT;
+		pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE;
 		break;
 
 	case 1:
-		rst = PCCR_S1_RST;
-		flt = PCCR_S1_FLT;
-		wait = PCCR_S1_PWAITEN;
-		pse = PCCR_S1_PSE;
-		irq = IRQ_S1_READY_NINT;
+		pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE;
 		break;
 
 	default:
 		return -1;
 	}
 
-	switch (conf->vcc) {
-	case 0:
-		pccr_mask = 0;
-		break;
+	pccr_set_mask = 0;
 
-	case 33:
-		pccr_mask = wait;
-		break;
-
-	case 50:
-		pccr_mask = pse | wait;
-		break;
-
-	default:
-		printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n",
-			conf->vcc);
-		return -1;
-	}
-
-	if (conf->reset)
-		pccr_mask |= rst;
-
-	if (conf->output)
-		pccr_mask |= flt;
+	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(pcmcia->mapbase + SA1111_PCCR);
-	val = (val & ~(pse | flt | wait | rst)) | pccr_mask;
-	sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR);
+	val = sa1111_readl(sadev->mapbase + SA1111_PCCR);
+	val &= ~pccr_skt_mask;
+	val |= pccr_set_mask & pccr_skt_mask;
+	sa1111_writel(val, sadev->mapbase + SA1111_PCCR);
 	local_irq_restore(flags);
 
 	return 0;
 }
 
-int sa1111_pcmcia_socket_init(int sock)
+void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt)
 {
-	return 0;
+	sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
-int sa1111_pcmcia_socket_suspend(int sock)
+void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt)
 {
-	return 0;
+	sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static int pcmcia_probe(struct device *dev)
 {
 	struct sa1111_dev *sadev = SA1111_DEV(dev);
-	unsigned long flags;
 	char *base;
 
-	local_irq_save(flags);
-	if (pcmcia) {
-		local_irq_restore(flags);
-		return -EBUSY;
-	}
-
-	pcmcia = sadev;
-	local_irq_restore(flags);
-
 	if (!request_mem_region(sadev->res.start, 512,
 				SA1111_DRIVER_NAME(sadev)))
 		return -EBUSY;
@@ -226,44 +167,8 @@
 {
 	struct sa1111_dev *sadev = SA1111_DEV(dev);
 
-#ifdef CONFIG_SA1100_ADSBITSY
-	pcmcia_adsbitsy_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_BADGE4
-	pcmcia_badge4_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-	pcmcia_graphicsmaster_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-	pcmcia_jornada720_exit(dev);
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
-	pcmcia_neponset_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_PFS168
-	pcmcia_pfs_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_PT_SYSTEM3
-	pcmcia_system3_exit(dev);
-#endif
-#ifdef CONFIG_SA1100_XP860
-	pcmcia_xp860_exit(dev);
-#endif
-
+	sa11xx_drv_pcmcia_remove(dev);
 	release_mem_region(sadev->res.start, 512);
-	pcmcia = NULL;
-
-	return 0;
-}
-
-static int pcmcia_suspend(struct device *dev, u32 state, u32 level)
-{
-	return 0;
-}
-
-static int pcmcia_resume(struct device *dev, u32 level)
-{
 	return 0;
 }
 
@@ -274,8 +179,8 @@
 		.devclass	= &pcmcia_socket_class,
 		.probe		= pcmcia_probe,
 		.remove		= __devexit_p(pcmcia_remove),
-		.suspend	= pcmcia_suspend,
-		.resume		= pcmcia_resume,
+		.suspend 	= pcmcia_socket_dev_suspend,
+		.resume 	= pcmcia_socket_dev_resume,
 	},
 	.devid			= SA1111_DEVID_PCMCIA,
 };
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa1111_generic.h linux-2.5.66-bk6/drivers/pcmcia/sa1111_generic.h
--- linux-2.5.66-bk5/drivers/pcmcia/sa1111_generic.h	Mon Mar 24 14:01:43 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/sa1111_generic.h	Mon Mar 31 12:52:29 2003
@@ -1,14 +1,12 @@
-extern int sa1111_pcmcia_init(struct pcmcia_init *);
-extern int sa1111_pcmcia_shutdown(void);
-extern void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *);
-extern int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *);
-extern int sa1111_pcmcia_socket_init(int);
-extern int sa1111_pcmcia_socket_suspend(int);
+#include "sa11xx_core.h"
 
+extern int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *);
+extern void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *);
+extern void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *, struct pcmcia_state *);
+extern int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *, const socket_state_t *);
+extern void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *);
+extern void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *);
 
 extern int pcmcia_jornada720_init(struct device *);
-extern void pcmcia_jornada720_exit(struct device *);
-
 extern int pcmcia_neponset_init(struct device *);
-extern void pcmcia_neponset_exit(struct device *);
 
diff -urN linux-2.5.66-bk5/drivers/pcmcia/sa11xx_core.c linux-2.5.66-bk6/drivers/pcmcia/sa11xx_core.c
--- linux-2.5.66-bk5/drivers/pcmcia/sa11xx_core.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk6/drivers/pcmcia/sa11xx_core.c	Mon Mar 31 12:52:29 2003
@@ -0,0 +1,1054 @@
+/*======================================================================
+
+    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.
+    
+======================================================================*/
+/*
+ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
+ * on the low-level kernel interface.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "sa11xx_core.h"
+#include "sa1100.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug;
+#endif
+
+/* This structure maintains housekeeping state for each socket, such
+ * as the last known values of the card detect pins, or the Card Services
+ * callback value associated with the socket:
+ */
+static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
+
+#define PCMCIA_SOCKET(x)	(sa1100_pcmcia_socket + (x))
+
+/*
+ * 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 sa1100_pcmcia_socket *skt,
+				  unsigned int cpu_speed,
+				  unsigned int cmd_time)
+{
+	return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
+}
+
+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;
+}
+
+/* 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 sa1100_pcmcia_socket *skt, unsigned int cpu_clock)
+{
+	u32 mecr, old_mecr;
+	unsigned long flags;
+	unsigned short speed;
+	unsigned int bs_io, bs_mem, bs_attr;
+	int i;
+
+	speed = calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS);
+	bs_io = skt->ops->socket_get_timing(skt, cpu_clock, speed);
+
+	speed = calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS);
+	bs_mem = skt->ops->socket_get_timing(skt, cpu_clock, speed);
+
+	speed = calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS);
+	bs_attr = skt->ops->socket_get_timing(skt, cpu_clock, speed);
+
+	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(4, "%s(): sock %u FAST %X  BSM %X  BSA %X  BSIO %X\n",
+	      __FUNCTION__, skt->nr, 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;
+}
+
+static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt)
+{
+	struct pcmcia_state state;
+	unsigned int stat;
+
+	memset(&state, 0, sizeof(struct pcmcia_state));
+
+	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 ? SS_STSCHG : 0;
+	else {
+		if (state.bvd1 == 0)
+			stat |= SS_BATDEAD;
+		else if (state.bvd2 == 0)
+			stat |= SS_BATWARN;
+	}
+	return stat;
+}
+
+/*
+ * sa1100_pcmcia_config_skt
+ * ^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Convert PCMCIA socket state to our socket configure structure.
+ */
+static int
+sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state)
+{
+	int ret;
+
+	ret = skt->ops->configure_socket(skt, state);
+	if (ret == 0) {
+		/*
+		 * 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;
+			set_irq_type(skt->irq, IRQT_FALLING);
+		} else if (skt->irq_state == 1 && state->io_irq == 0) {
+			skt->irq_state = 0;
+			set_irq_type(skt->irq, IRQT_NOEDGE);
+		}
+
+		skt->cs_state = *state;
+	}
+
+	if (ret < 0)
+		printk(KERN_ERR "sa1100_pcmcia: unable to configure "
+		       "socket %d\n", skt->nr);
+
+	return ret;
+}
+
+/* sa1100_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 sa1100_pcmcia_sock_init(unsigned int sock)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+	DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, skt->nr);
+
+	skt->ops->socket_init(skt);
+	sa1100_pcmcia_config_skt(skt, &dead_socket);
+
+	return 0;
+}
+
+
+/*
+ * sa1100_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 sa1100_pcmcia_suspend(unsigned int sock)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+	int ret;
+
+	DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr);
+
+	ret = sa1100_pcmcia_config_skt(skt, &dead_socket);
+	if (ret == 0)
+		skt->ops->socket_suspend(skt);
+
+	return ret;
+}
+
+
+/* sa1100_pcmcia_task_handler()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Processes serviceable socket events using the "eventd" thread context.
+ *
+ * Event processing (specifically, the invocation of the Card Services event
+ * callback) occurs in this thread rather than in the actual interrupt
+ * handler due to the use of scheduling operations in the PCMCIA core.
+ */
+static void sa1100_pcmcia_task_handler(void *data)
+{
+	struct sa1100_pcmcia_socket *skt = data;
+	unsigned int events;
+
+	DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+
+	do {
+		unsigned int status;
+
+		status = sa1100_pcmcia_skt_state(skt);
+
+		events = (status ^ skt->status) & skt->cs_state.csc_mask;
+		skt->status = status;
+
+		DEBUG(2, "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 && skt->handler != NULL)
+			skt->handler(skt->handler_info, events);
+	} while (events);
+}
+
+/* sa1100_pcmcia_poll_event()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Let's poll for events in addition to IRQs since IRQ only is unreliable...
+ */
+static void sa1100_pcmcia_poll_event(unsigned long dummy)
+{
+	struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy;
+	DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
+
+	mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD);
+
+	schedule_work(&skt->work);
+}
+
+
+/* sa1100_pcmcia_interrupt()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Service routine for socket driver interrupts (requested by the
+ * low-level PCMCIA init() operation via sa1100_pcmcia_thread()).
+ * The actual interrupt-servicing work is performed by
+ * sa1100_pcmcia_thread(), largely because the Card Services event-
+ * handling code performs scheduling operations which cannot be
+ * executed from within an interrupt context.
+ */
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	struct sa1100_pcmcia_socket *skt = dev;
+
+	DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
+
+	schedule_work(&skt->work);
+}
+
+/* sa1100_pcmcia_register_callback()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the register_callback() operation for the in-kernel
+ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If 
+ * the function pointer `handler' is not NULL, remember the callback 
+ * location in the state for `sock', and increment the usage counter 
+ * for the driver module. (The callback is invoked from the interrupt
+ * service routine, sa1100_pcmcia_interrupt(), to notify Card Services
+ * of interesting events.) Otherwise, clear the callback pointer in the
+ * socket state and decrement the module usage count.
+ *
+ * Returns: 0
+ */
+static int
+sa1100_pcmcia_register_callback(unsigned int sock,
+				void (*handler)(void *, unsigned int),
+				void *info)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+	if (handler) {
+		if (!try_module_get(skt->ops->owner))
+			return -ENODEV;
+		skt->handler_info = info;
+		skt->handler = handler;
+	} else {
+		skt->handler = NULL;
+		module_put(skt->ops->owner);
+	}
+
+	return 0;
+}
+
+
+/* sa1100_pcmcia_inquire_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the inquire_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_InquireSocket in Card Services).  We set
+ * SS_CAP_STATIC_MAP, which disables the memory resource database
+ * check. (Mapped memory is set up within the socket driver itself.)
+ *
+ * In conjunction with the STATIC_MAP capability is a new field,
+ * `io_offset', recommended by David Hinds. Rather than go through
+ * the SetIOMap interface (which is not quite suited for communicating
+ * window locations up from the socket driver), we just pass up
+ * an offset which is applied to client-requested base I/O addresses
+ * in alloc_io_space().
+ *
+ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
+ *   resource database; we instead pass up physical address ranges
+ *   and allow other parts of Card Services to deal with remapping.
+ *
+ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
+ *   not 32-bit CardBus devices.
+ *
+ * Return value is irrelevant; the pcmcia subsystem ignores it.
+ */
+static int
+sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+	int ret = -1;
+
+	if (skt) {
+		DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+
+		cap->features  = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
+		cap->irq_mask  = 0;
+		cap->map_size  = PAGE_SIZE;
+		cap->pci_irq   = skt->irq;
+		cap->io_offset = (unsigned long)skt->virt_io;
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
+
+/* sa1100_pcmcia_get_status()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * 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
+sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+	skt->status = sa1100_pcmcia_skt_state(skt);
+	*status = skt->status;
+
+	return 0;
+}
+
+
+/* sa1100_pcmcia_get_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the get_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetSocket in Card Services). Not a very 
+ * exciting routine.
+ *
+ * Returns: 0
+ */
+static int
+sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+
+  *state = skt->cs_state;
+
+  return 0;
+}
+
+/* sa1100_pcmcia_set_socket()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * 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.
+ *
+ * Returns: 0
+ */
+static int
+sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+
+  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\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 ":"");
+  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
+	state->Vcc, state->Vpp, state->io_irq);
+
+  return sa1100_pcmcia_config_skt(skt, state);
+}  /* sa1100_pcmcia_set_socket() */
+
+
+/* sa1100_pcmcia_set_io_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * 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
+sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+	unsigned short speed = map->speed;
+
+	DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+
+	DEBUG(3, "\tmap %u  speed %u\n\tstart 0x%08x  stop 0x%08x\n",
+		map->map, map->speed, map->start, map->stop);
+	DEBUG(3, "\tflags: %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", __FUNCTION__,
+		       map->map);
+		return -1;
+	}
+
+	if (map->flags & MAP_ACTIVE) {
+		if (speed == 0)
+			speed = SA1100_PCMCIA_IO_ACCESS;
+	} else {
+		speed = 0;
+	}
+
+	skt->spd_io[map->map] = speed;
+	sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+
+	if (map->stop == 1)
+		map->stop = PAGE_SIZE-1;
+
+	map->stop -= map->start;
+	map->stop += (unsigned long)skt->virt_io;
+	map->start = (unsigned long)skt->virt_io;
+
+	return 0;
+}  /* sa1100_pcmcia_set_io_map() */
+
+
+/* sa1100_pcmcia_set_mem_map()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * 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, -1 on error
+ */
+static int
+sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+	struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+	struct resource *res;
+	unsigned short speed = map->speed;
+
+	DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+
+	DEBUG(3, "\tmap %u speed %u card_start %08x\n",
+		map->map, map->speed, map->card_start);
+	DEBUG(3, "\tflags: %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;
+	}
+
+	sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+
+	map->sys_stop -= map->sys_start;
+	map->sys_stop += res->start + map->card_start;
+	map->sys_start = res->start + map->card_start;
+
+	return 0;
+}
+
+
+#if defined(CONFIG_PROC_FS)
+
+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"	},
+	{ SS_DEBOUNCED,		"SS_DEBOUNCED"	},
+};
+
+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;
+}
+
+/* sa1100_pcmcia_proc_status()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the /proc/bus/pccard/??/status file.
+ *
+ * Returns: the number of characters added to the buffer
+ */
+static int
+sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+	struct sa1100_pcmcia_socket *skt = data;
+	unsigned int clock = cpufreq_get(0);
+	unsigned long mecr = MECR;
+	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->irq);
+
+	p+=sprintf(p, "I/O      : %u (%u)\n",
+		calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS),
+		sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
+
+	p+=sprintf(p, "attribute: %u (%u)\n",
+		calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS),
+		sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
+
+	p+=sprintf(p, "common   : %u (%u)\n",
+		calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS),
+		sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
+
+	return p-buf;
+}
+
+/* sa1100_pcmcia_proc_setup()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the proc_setup() operation for the in-kernel PCMCIA
+ * service (formerly SS_ProcSetup in Card Services).
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static void
+sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+	struct proc_dir_entry *entry;
+
+	if ((entry = create_proc_entry("status", 0, base)) == NULL){
+		printk(KERN_ERR "unable to install \"status\" procfs entry\n");
+		return;
+	}
+	entry->read_proc = sa1100_pcmcia_proc_status;
+	entry->data = PCMCIA_SOCKET(sock);
+}
+#else
+#define sa1100_pcmcia_proc_setup	NULL
+#endif  /* defined(CONFIG_PROC_FS) */
+
+static struct pccard_operations sa11xx_pcmcia_operations = {
+	.owner			= THIS_MODULE,
+	.init			= sa1100_pcmcia_sock_init,
+	.suspend		= sa1100_pcmcia_suspend,
+	.register_callback	= sa1100_pcmcia_register_callback,
+	.inquire_socket		= sa1100_pcmcia_inquire_socket,
+	.get_status		= sa1100_pcmcia_get_status,
+	.get_socket		= sa1100_pcmcia_get_socket,
+	.set_socket		= sa1100_pcmcia_set_socket,
+	.set_io_map		= sa1100_pcmcia_set_io_map,
+	.set_mem_map		= sa1100_pcmcia_set_mem_map,
+	.proc_setup		= sa1100_pcmcia_proc_setup
+};
+
+int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+{
+	int i, res = 0;
+
+	for (i = 0; i < nr; i++) {
+		if (irqs[i].sock != skt->nr)
+			continue;
+		res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt,
+				  SA_INTERRUPT, irqs[i].str, skt);
+		if (res)
+			break;
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+	}
+
+	if (res) {
+		printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n",
+			irqs[i].irq, res);
+
+		while (i--)
+			if (irqs[i].sock == skt->nr)
+				free_irq(irqs[i].irq, skt);
+	}
+	return res;
+}
+EXPORT_SYMBOL(sa11xx_request_irqs);
+
+void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+{
+	int i;
+
+	for (i = 0; i < nr; i++)
+		if (irqs[i].sock == skt->nr)
+			free_irq(irqs[i].irq, skt);
+}
+EXPORT_SYMBOL(sa11xx_free_irqs);
+
+void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+{
+	int i;
+
+	for (i = 0; i < nr; i++)
+		if (irqs[i].sock == skt->nr)
+			set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+}
+EXPORT_SYMBOL(sa11xx_disable_irqs);
+
+void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr)
+{
+	int i;
+
+	for (i = 0; i < nr; i++)
+		if (irqs[i].sock == skt->nr) {
+			set_irq_type(irqs[i].irq, IRQT_RISING);
+			set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
+		}
+}
+EXPORT_SYMBOL(sa11xx_enable_irqs);
+
+static const char *skt_names[] = {
+	"PCMCIA socket 0",
+	"PCMCIA socket 1",
+};
+
+int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
+{
+	struct pcmcia_socket_class_data *cls;
+	unsigned int cpu_clock;
+	int ret, i;
+
+	cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL);
+	if (!cls) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(cls, 0, sizeof(struct pcmcia_socket_class_data));
+	cls->ops	= &sa11xx_pcmcia_operations;
+	cls->nsock	= nr;
+
+	/*
+	 * set default MECR calculation if the board specific
+	 * code did not specify one...
+	 */
+	if (!ops->socket_get_timing)
+		ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing;
+
+	cpu_clock = cpufreq_get(0);
+
+	/*
+	 * Initialise the per-socket structure.
+	 */
+	for (i = 0; i < nr; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+		memset(skt, 0, sizeof(*skt));
+
+		INIT_WORK(&skt->work, sa1100_pcmcia_task_handler, skt);
+
+		init_timer(&skt->poll_timer);
+		skt->poll_timer.function = sa1100_pcmcia_poll_event;
+		skt->poll_timer.data = (unsigned long)skt;
+		skt->poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
+
+		skt->nr		= first + i;
+		skt->irq	= NO_IRQ;
+		skt->dev	= dev;
+		skt->ops	= ops;
+
+		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;
+
+		ret = request_resource(&iomem_resource, &skt->res_skt);
+		if (ret)
+			goto out_err_1;
+
+		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;
+
+		ret = request_resource(&skt->res_skt, &skt->res_io);
+		if (ret)
+			goto out_err_2;
+
+		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;
+
+		ret = request_resource(&skt->res_skt, &skt->res_mem);
+		if (ret)
+			goto out_err_3;
+
+		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;
+		
+		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 the MECR to default values here, because
+		 * we are not guaranteed to see a SetIOMap operation at
+		 * runtime.
+		 */
+		sa1100_pcmcia_set_mecr(skt, cpu_clock);
+
+		ret = ops->hw_init(skt);
+		if (ret)
+			goto out_err_6;
+
+		skt->status = sa1100_pcmcia_skt_state(skt);
+		add_timer(&skt->poll_timer);
+	}
+
+	dev->class_data = cls;
+	return 0;
+
+	do {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+
+		del_timer_sync(&skt->poll_timer);
+		flush_scheduled_work();
+
+		ops->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:
+		i--;
+	} while (i > 0);
+
+	kfree(cls);
+
+ out:
+	return ret;
+}
+EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
+
+int sa11xx_drv_pcmcia_remove(struct device *dev)
+{
+	struct pcmcia_socket_class_data *cls = dev->class_data;
+	int i;
+
+	dev->class_data = NULL;
+
+	for (i = 0; i < cls->nsock; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(cls->sock_offset + i);
+
+		skt->ops->hw_shutdown(skt);
+
+		del_timer_sync(&skt->poll_timer);
+		flush_scheduled_work();
+
+		sa1100_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);
+	}
+
+	kfree(cls);
+
+	return 0;
+}
+EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove);
+
+#ifdef CONFIG_CPU_FREQ
+
+/* sa1100_pcmcia_update_mecr()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due
+ * to a core clock frequency change) is needed, this routine establishes
+ * new BS_xx values consistent with the clock speed `clock'.
+ */
+static void sa1100_pcmcia_update_mecr(unsigned int clock)
+{
+	unsigned int sock;
+
+	for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+		sa1100_pcmcia_set_mecr(skt, clock);
+	}
+}
+
+/* sa1100_pcmcia_notifier()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^
+ * When changing the processor core clock frequency, it is necessary
+ * to adjust the MECR timings accordingly. We've recorded the timings
+ * requested by Card Services, so this is just a matter of finding
+ * out what our current speed is, and then recomputing the new MECR
+ * values.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int
+sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
+	struct cpufreq_freqs *freqs = data;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if (freqs->new > freqs->old) {
+			DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
+				"pre-updating\n", __FUNCTION__,
+			    freqs->new / 1000, (freqs->new / 100) % 10,
+			    freqs->old / 1000, (freqs->old / 100) % 10);
+			sa1100_pcmcia_update_mecr(freqs->new);
+		}
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		if (freqs->new < freqs->old) {
+			DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
+				"post-updating\n", __FUNCTION__,
+			    freqs->new / 1000, (freqs->new / 100) % 10,
+			    freqs->old / 1000, (freqs->old / 100) % 10);
+			sa1100_pcmcia_update_mecr(freqs->new);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block sa1100_pcmcia_notifier_block = {
+	.notifier_call	= sa1100_pcmcia_notifier
+};
+
+static int __init sa11xx_pcmcia_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "SA11xx PCMCIA (CS release %s)\n", CS_RELEASE);
+
+	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
+					CPUFREQ_TRANSITION_NOTIFIER);
+	if (ret < 0)
+		printk(KERN_ERR "Unable to register CPU frequency change "
+			"notifier (%d)\n", ret);
+
+	return ret;
+}
+module_init(sa11xx_pcmcia_init);
+
+static void __exit sa11xx_pcmcia_exit(void)
+{
+	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+module_exit(sa11xx_pcmcia_exit);
+#endif
+
+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 -urN linux-2.5.66-bk5/drivers/pcmcia/sa11xx_core.h linux-2.5.66-bk6/drivers/pcmcia/sa11xx_core.h
--- linux-2.5.66-bk5/drivers/pcmcia/sa11xx_core.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.66-bk6/drivers/pcmcia/sa11xx_core.h	Mon Mar 31 12:52:29 2003
@@ -0,0 +1,122 @@
+/*
+ * linux/include/asm/arch/pcmcia.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the low-level SA-1100 kernel PCMCIA
+ * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
+ */
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+#include <linux/proc_fs.h>
+/* include the world */
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+struct device;
+
+/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
+ * has support for two. This shows up in lots of hardwired ways, such
+ * as the fact that MECR only has enough bits to configure two sockets.
+ * Since it's so entrenched in the hardware, limiting the software
+ * in this way doesn't seem too terrible.
+ */
+#define SA1100_PCMCIA_MAX_SOCK   (2)
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+             bvd1: 1,
+             bvd2: 1,
+           wrprot: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+/*
+ * This structure encapsulates per-socket state which we might need to
+ * use when responding to a Card Services query of some kind.
+ */
+struct sa1100_pcmcia_socket {
+	/*
+	 * Info from low level handler
+	 */
+	struct device		*dev;
+	unsigned int		nr;
+	unsigned int		irq;
+
+	/*
+	 * Core PCMCIA state
+	 */
+	struct pcmcia_low_level *ops;
+
+	unsigned int		status;
+	socket_state_t		cs_state;
+	void			(*handler)(void *, unsigned int);
+	void			*handler_info;
+
+	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			*virt_io;
+
+	unsigned int		irq_state;
+
+	struct timer_list	poll_timer;
+	struct work_struct	work;
+};
+
+struct pcmcia_low_level {
+	struct module *owner;
+
+	int (*hw_init)(struct sa1100_pcmcia_socket *);
+	void (*hw_shutdown)(struct sa1100_pcmcia_socket *);
+
+	void (*socket_state)(struct sa1100_pcmcia_socket *, struct pcmcia_state *);
+	int (*configure_socket)(struct sa1100_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 sa1100_pcmcia_socket *);
+
+	/*
+	 * Disable card status IRQs and PCMCIA bus on suspend.
+	 */
+	void (*socket_suspend)(struct sa1100_pcmcia_socket *);
+
+	/*
+	 * Calculate MECR timing clock wait states
+	 */
+	unsigned int (*socket_get_timing)(struct sa1100_pcmcia_socket *,
+			unsigned int cpu_speed, unsigned int cmd_time);
+};
+
+struct pcmcia_irqs {
+	int sock;
+	int irq;
+	const char *str;
+};
+
+int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
+void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
+void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
+void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
+
+extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
+extern int sa11xx_drv_pcmcia_remove(struct device *dev);
+
+#endif
diff -urN linux-2.5.66-bk5/drivers/pcmcia/tcic.c linux-2.5.66-bk6/drivers/pcmcia/tcic.c
--- linux-2.5.66-bk5/drivers/pcmcia/tcic.c	Mon Mar 31 12:52:24 2003
+++ linux-2.5.66-bk6/drivers/pcmcia/tcic.c	Mon Mar 31 12:52:29 2003
@@ -225,11 +225,6 @@
 	return 2*(ns-14)/cycle_time;
 }
 
-static int to_ns(int cycles)
-{
-    return (cycles*cycle_time)/2 + 14;
-}
-
 /*====================================================================*/
 
 static volatile u_int irq_hits;
@@ -384,6 +379,8 @@
 	.name = "tcic-pcmcia",
 	.bus = &platform_bus_type,
 	.devclass = &pcmcia_socket_class,
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device tcic_device = {
diff -urN linux-2.5.66-bk5/drivers/serial/8250_cs.c linux-2.5.66-bk6/drivers/serial/8250_cs.c
--- linux-2.5.66-bk5/drivers/serial/8250_cs.c	Mon Mar 24 14:00:38 2003
+++ linux-2.5.66-bk6/drivers/serial/8250_cs.c	Mon Mar 31 12:52:29 2003
@@ -690,26 +690,25 @@
 	return 0;
 }
 
-/*====================================================================*/
+static struct pcmcia_driver serial_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "serial_cs",
+	},
+	.attach		= serial_attach,
+	.detach		= serial_detach,
+};
 
 static int __init init_serial_cs(void)
 {
-	servinfo_t serv;
-	DEBUG(0, "%s\n", version);
-	CardServices(GetCardServicesInfo, &serv);
-	if (serv.Revision != CS_RELEASE_CODE) {
-		printk(KERN_NOTICE "serial_cs: Card Services release "
-		       "does not match!\n");
-		return -1;
-	}
-	register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
-	return 0;
+	return pcmcia_register_driver(&serial_cs_driver);
 }
 
 static void __exit exit_serial_cs(void)
 {
-	DEBUG(0, "serial_cs: unloading\n");
-	unregister_pccard_driver(&dev_info);
+	pcmcia_unregister_driver(&serial_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
 	while (dev_list != NULL)
 		serial_detach(dev_list);
 }
diff -urN linux-2.5.66-bk5/fs/proc/base.c linux-2.5.66-bk6/fs/proc/base.c
--- linux-2.5.66-bk5/fs/proc/base.c	Mon Mar 24 14:00:50 2003
+++ linux-2.5.66-bk6/fs/proc/base.c	Mon Mar 31 12:52:29 2003
@@ -565,10 +565,10 @@
 }
 
 static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
-			    char * buffer, int buflen)
+			    char *buffer, int buflen)
 {
 	struct inode * inode;
-	char * tmp = (char*)__get_free_page(GFP_KERNEL), *path;
+	char *tmp = (char*)__get_free_page(GFP_KERNEL), *path;
 	int len;
 
 	if (!tmp)
@@ -576,13 +576,17 @@
 		
 	inode = dentry->d_inode;
 	path = d_path(dentry, mnt, tmp, PAGE_SIZE);
+	len = PTR_ERR(path);
+	if (IS_ERR(path))
+		goto out;
 	len = tmp + PAGE_SIZE - 1 - path;
 
-	if (len < buflen)
-		buflen = len;
-	copy_to_user(buffer, path, buflen);
+	if (len > buflen)
+		len = buflen;
+	copy_to_user(buffer, path, len);
+ out:
 	free_page((unsigned long)tmp);
-	return buflen;
+	return len;
 }
 
 static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
diff -urN linux-2.5.66-bk5/include/pcmcia/ss.h linux-2.5.66-bk6/include/pcmcia/ss.h
--- linux-2.5.66-bk5/include/pcmcia/ss.h	Mon Mar 31 12:52:25 2003
+++ linux-2.5.66-bk6/include/pcmcia/ss.h	Mon Mar 31 12:52:30 2003
@@ -148,9 +148,12 @@
 	 * returned to driver) = sock_offset + (0, 1, .. , (nsock-1) */
 	struct pccard_operations *ops;		/* see above */
 	void *s_info;				/* socket_info_t */
-	unsigned int use_bus_pm;
 };
 
 extern struct device_class pcmcia_socket_class;
 
+/* socket drivers are expected to use these callbacks in their .drv struct */
+int pcmcia_socket_dev_suspend(struct device * dev, u32 state, u32 level);
+int pcmcia_socket_dev_resume(struct device * dev, u32 level);
+
 #endif /* _LINUX_SS_H */
