patch-2.4.19 linux-2.4.19/drivers/pcmcia/sa1100_generic.c

Next file: linux-2.4.19/drivers/pcmcia/sa1100_generic.h
Previous file: linux-2.4.19/drivers/pcmcia/sa1100_freebird.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/pcmcia/sa1100_generic.c linux-2.4.19/drivers/pcmcia/sa1100_generic.c
@@ -29,6 +29,10 @@
     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>
@@ -43,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
+#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -62,338 +67,94 @@
 static int pc_debug;
 #endif
 
-MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
-
 /* 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];
-
 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;
 
-/* Event poll timer structure */
 static struct timer_list poll_timer;
-
-
-/* Prototypes for routines which are used internally: */
-
-static int  sa1100_pcmcia_driver_init(void);
-static void sa1100_pcmcia_driver_shutdown(void);
-static void sa1100_pcmcia_task_handler(void *data);
-static void sa1100_pcmcia_poll_event(unsigned long data);
-static void sa1100_pcmcia_interrupt(int irq, void *dev,
-				    struct pt_regs *regs);
 static struct tq_struct sa1100_pcmcia_task;
 
-#ifdef CONFIG_PROC_FS
-static int  sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-				      int count, int *eof, void *data);
-#endif
-
-
-/* Prototypes for operations which are exported to the
- * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
- */
-
-static int sa1100_pcmcia_init(unsigned int sock);
-static int sa1100_pcmcia_suspend(unsigned int sock);
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *, 
-							   unsigned int),
-					   void *info);
-static int sa1100_pcmcia_inquire_socket(unsigned int sock, 
-					socket_cap_t *cap);
-static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value);
-static int sa1100_pcmcia_get_socket(unsigned int sock, 
-				    socket_state_t *state);
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state);
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-#ifdef CONFIG_PROC_FS
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
-				     struct proc_dir_entry *base);
-#endif
-
-static struct pccard_operations sa1100_pcmcia_operations = {
-  sa1100_pcmcia_init,
-  sa1100_pcmcia_suspend,
-  sa1100_pcmcia_register_callback,
-  sa1100_pcmcia_inquire_socket,
-  sa1100_pcmcia_get_status,
-  sa1100_pcmcia_get_socket,
-  sa1100_pcmcia_set_socket,
-  sa1100_pcmcia_get_io_map,
-  sa1100_pcmcia_set_io_map,
-  sa1100_pcmcia_get_mem_map,
-  sa1100_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
-  sa1100_pcmcia_proc_setup
-#endif
-};
-
-#ifdef CONFIG_CPU_FREQ
-/* forward declaration */
-static struct notifier_block sa1100_pcmcia_notifier_block;
-#endif
-
-
-/* sa1100_pcmcia_driver_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.
+/*
+ * sa1100_pcmcia_state_to_config
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *
- * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
- * on the low-level kernel interface.
- *
- * Returns: 0 on success, -1 on error
- */
-static int __init sa1100_pcmcia_driver_init(void){
-  servinfo_t info;
-  struct pcmcia_init pcmcia_init;
-  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
-  struct pcmcia_state_array state_array;
-  unsigned int i, clock;
-  unsigned long mecr;
-
-  printk(KERN_INFO "SA-1100 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 -1;
-  }
-
-  if(machine_is_assabet()){
-#ifdef CONFIG_SA1100_ASSABET
-    if(machine_has_neponset()){
-#ifdef CONFIG_ASSABET_NEPONSET
-      pcmcia_low_level=&neponset_pcmcia_ops;
-#else
-      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
-      return -1;
-#endif
-    }else{
-      pcmcia_low_level=&assabet_pcmcia_ops;
-    }
-#endif
-  } else if (machine_is_freebird()) {
-#ifdef CONFIG_SA1100_FREEBIRD
-    pcmcia_low_level = &freebird_pcmcia_ops;
-#endif
-  } else if (machine_is_h3600()) {
-#ifdef CONFIG_SA1100_H3600
-    pcmcia_low_level = &h3600_pcmcia_ops;
-#endif    
-  } else if (machine_is_cerf()) {
-#ifdef CONFIG_SA1100_CERF
-    pcmcia_low_level = &cerf_pcmcia_ops;
-#endif
-  } else if (machine_is_graphicsclient()) {
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-    pcmcia_low_level = &gcplus_pcmcia_ops;
-#endif
-  } else if (machine_is_xp860()) {
-#ifdef CONFIG_SA1100_XP860
-    pcmcia_low_level = &xp860_pcmcia_ops;
-#endif
-  } else if (machine_is_yopy()) {
-#ifdef CONFIG_SA1100_YOPY
-    pcmcia_low_level = &yopy_pcmcia_ops;
-#endif
-  } else if (machine_is_pangolin()) {
-#ifdef CONFIG_SA1100_PANGOLIN
-    pcmcia_low_level = &pangolin_pcmcia_ops;
-#endif
-  } else if (machine_is_jornada720()) {
-#ifdef CONFIG_SA1100_JORNADA720
-    pcmcia_low_level = &jornada720_pcmcia_ops;
-#endif
-  } else if(machine_is_pfs168()){
-#ifdef CONFIG_SA1100_PFS168
-    pcmcia_low_level=&pfs168_pcmcia_ops;
-#endif
-  } else if(machine_is_flexanet()){
-#ifdef CONFIG_SA1100_FLEXANET
-    pcmcia_low_level=&flexanet_pcmcia_ops;
-#endif
- } else if(machine_is_simpad()){
-#ifdef CONFIG_SA1100_SIMPAD
-    pcmcia_low_level=&simpad_pcmcia_ops;
-#endif
-  } else if(machine_is_graphicsmaster()) {
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-    pcmcia_low_level=&graphicsmaster_pcmcia_ops;
-#endif
-  } else if(machine_is_adsbitsy()) {
-#ifdef CONFIG_SA1100_ADSBITSY
-    pcmcia_low_level=&adsbitsy_pcmcia_ops;
-#endif
-  } else if(machine_is_stork()) {
-#ifdef CONFIG_SA1100_STORK
-    pcmcia_low_level=&stork_pcmcia_ops;
-#endif
-  }
-
-  if (!pcmcia_low_level) {
-    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
-    return -ENODEV;
-  }
-
-  pcmcia_init.handler=sa1100_pcmcia_interrupt;
-
-  if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
-    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
-    return -EIO;
-  }
-
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
-
-  if(pcmcia_low_level->socket_state(&state_array)<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
-    return -EIO;
-  }
-
-  /* We initialize the MECR to default values here, because we are
-   * not guaranteed to see a SetIOMap operation at runtime.
-   */
-  mecr=0;
-
-  clock = get_cclk_frequency() * 100;
-
-  for(i=0; i<sa1100_pcmcia_socket_count; ++i){
-    sa1100_pcmcia_socket[i].k_state=state[i];
-
-    /* This is an interim fix. Apparently, SetSocket is no longer
-     * called to initialize each socket (prior to the first detect
-     * event). For now, we'll just manually set up the mask.
-     */
-    sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
-
-    sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
-    sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
-    sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
-
-    MECR_FAST_SET(mecr, i, 0);
-    MECR_BSIO_SET(mecr, i,
-		  sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock));
-    MECR_BSA_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-    MECR_BSM_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-
-    sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS;
-    sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS;
-    sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS;
-  }
-
-  MECR=mecr;
-
-#ifdef CONFIG_CPU_FREQ
-  if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){
-    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
-    return -ENXIO;
-  }
-#endif
-
-  /* Only advertise as many sockets as we can detect: */
-  if(register_ss_entry(sa1100_pcmcia_socket_count, 
-		       &sa1100_pcmcia_operations)<0){
-    printk(KERN_ERR "Unable to register socket service routine\n");
-    return -ENXIO;
-  }
-
-  /* Start the event poll timer.  It will reschedule by itself afterwards. */
-  sa1100_pcmcia_poll_event(0);
-
-  DEBUG(1, "sa1100: initialization complete\n");
-
-  return 0;
-
-}  /* sa1100_pcmcia_driver_init() */
-
-module_init(sa1100_pcmcia_driver_init);
-
-
-/* sa1100_pcmcia_driver_shutdown()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
+ * Convert PCMCIA socket state to our socket configure structure.
  */
-static void __exit sa1100_pcmcia_driver_shutdown(void){
+static struct pcmcia_configure
+sa1100_pcmcia_state_to_config(unsigned int sock, socket_state_t *state)
+{
+  struct pcmcia_configure conf;
 
-  del_timer_sync(&poll_timer);
-  unregister_ss_entry(&sa1100_pcmcia_operations);
-#ifdef CONFIG_CPU_FREQ
-  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
-#endif
-  pcmcia_low_level->shutdown();
-  flush_scheduled_tasks();
+  conf.sock    = sock;
+  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;
+  conf.irq     = state->io_irq != 0;
 
-  DEBUG(1, "sa1100: shutdown complete\n");
+  return conf;
 }
 
-module_exit(sa1100_pcmcia_driver_shutdown);
-
-
 /* sa1100_pcmcia_init()
  * ^^^^^^^^^^^^^^^^^^^^
- * We perform all of the interesting initialization tasks in 
- * sa1100_pcmcia_driver_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_init(unsigned int sock){
-  
+static int sa1100_pcmcia_init(unsigned int sock)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
+
   DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
 
-  return 0;
+  skt->cs_state = dead_socket;
+
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
+
+  pcmcia_low_level->configure_socket(&conf);
+
+  return pcmcia_low_level->socket_init(sock);
 }
 
 
-/* sa1100_pcmcia_suspend()
+/*
+ * sa1100_pcmcia_suspend()
  * ^^^^^^^^^^^^^^^^^^^^^^^
- * We don't currently perform any actions on a 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);
   struct pcmcia_configure conf;
   int ret;
 
   DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
 
-  conf.sock = sock;
-  conf.vcc = 0;
-  conf.vpp = 0;
-  conf.output = 0;
-  conf.speaker = 0;
-  conf.reset = 1;
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
 
   ret = pcmcia_low_level->configure_socket(&conf);
 
-  if (ret == 0)
-    sa1100_pcmcia_socket[sock].cs_state = dead_socket;
+  if (ret == 0) {
+    skt->cs_state = dead_socket;
+    ret = pcmcia_low_level->socket_suspend(sock);
+  }
 
   return ret;
 }
@@ -407,52 +168,50 @@
  *
  * Returns: an event mask for the given socket state.
  */
-static inline unsigned 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){
+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;
 
-    DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
+  if (state->detect != prev_state->detect) {
+    DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
 
-    events|=mask&SS_DETECT;
+    events |= SS_DETECT;
   }
 
-  if(state->ready!=prev_state->ready){
+  if (state->ready != prev_state->ready) {
+    DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
 
-    DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
-
-    events|=mask&((flags&SS_IOCARD)?0:SS_READY);
+    events |= flags & SS_IOCARD ? 0 : SS_READY;
   }
 
-  if(state->bvd1!=prev_state->bvd1){
-
-    DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
+  if (state->bvd1 != prev_state->bvd1) {
+    DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
 
-    events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
+    events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD;
   }
 
-  if(state->bvd2!=prev_state->bvd2){
+  if (state->bvd2 != prev_state->bvd2) {
+    DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
 
-    DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
-
-    events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
+    events |= flags & SS_IOCARD ? 0 : SS_BATWARN;
   }
 
-  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 ":"");
+  *prev_state = *state;
 
-  *prev_state=*state;
+  events &= mask;
 
-  return events;
+  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() */
 
 
@@ -464,38 +223,43 @@
  * 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) {
+static void sa1100_pcmcia_task_handler(void *data)
+{
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
-  int i, events, all_events, irq_status;
+  unsigned int all_events;
 
-  DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+  DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
   do {
+    unsigned int events;
+    int ret, i;
 
-    DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
+    memset(state, 0, sizeof(state));
 
-    if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
-      printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
+    DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
 
-    all_events=0;
+    ret = pcmcia_low_level->socket_state(&state_array);
+    if (ret < 0) {
+      printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n");
+      break;
+    }
 
-    if(irq_status>0){
+    all_events = 0;
 
-      for(i=0; i<state_array.size; ++i, all_events|=events)
-	if((events=
-	    sa1100_pcmcia_events(&state[i],
-				 &sa1100_pcmcia_socket[i].k_state,
-				 sa1100_pcmcia_socket[i].cs_state.csc_mask,
-				 sa1100_pcmcia_socket[i].cs_state.flags)))
-	  if(sa1100_pcmcia_socket[i].handler!=NULL)
-	    sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info,
-					    events);
-    }
+    for (i = 0; i < state_array.size; i++, all_events |= events) {
+      struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
 
+      events = sa1100_pcmcia_events(&state[i], &skt->k_state,
+				    skt->cs_state.csc_mask,
+				    skt->cs_state.flags);
+
+      if (events && sa1100_pcmcia_socket[i].handler != NULL)
+	skt->handler(skt->handler_info, events);
+    }
   } while(all_events);
 }  /* sa1100_pcmcia_task_handler() */
 
@@ -510,7 +274,7 @@
  */
 static void sa1100_pcmcia_poll_event(unsigned long dummy)
 {
-  DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
+  DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
   poll_timer.function = sa1100_pcmcia_poll_event;
   poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
   add_timer(&poll_timer);
@@ -527,7 +291,8 @@
  * 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){
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
   DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
   schedule_task(&sa1100_pcmcia_task);
 }
@@ -546,17 +311,20 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *,
-							   unsigned int),
-					   void *info){
-  if(handler==NULL){
-    sa1100_pcmcia_socket[sock].handler=NULL;
+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 == NULL) {
+    skt->handler = NULL;
     MOD_DEC_USE_COUNT;
   } else {
     MOD_INC_USE_COUNT;
-    sa1100_pcmcia_socket[sock].handler=handler;
-    sa1100_pcmcia_socket[sock].handler_info=info;
+    skt->handler_info = info;
+    skt->handler = handler;
   }
 
   return 0;
@@ -580,51 +348,41 @@
  * an offset which is applied to client-requested base I/O addresses
  * in alloc_io_space().
  *
- * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ * 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 pcmcia_irq_info irq_info;
-
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if(sock>=sa1100_pcmcia_socket_count){
-    printk(KERN_ERR "sa1100: socket %u not configured\n", sock);
-    return -1;
-  }
+static int
+sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  /* 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.
-   */
-  cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  irq_info.sock=sock;
-  irq_info.irq=-1;
+  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;
 
-  if(pcmcia_low_level->get_irq_info(&irq_info)<0){
-    printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
-	   sock);
-    return -1;
+    ret = 0;
   }
 
-  cap->irq_mask=0;
-  cap->map_size=PAGE_SIZE;
-  cap->pci_irq=irq_info.irq;
-  cap->io_offset=sa1100_pcmcia_socket[sock].virt_io;
-
-  return 0;
-
-}  /* sa1100_pcmcia_inquire_socket() */
+  return ret;
+}
 
 
 /* sa1100_pcmcia_get_status()
@@ -643,58 +401,61 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_status(unsigned int sock,
-				    unsigned int *status){
+static int
+sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
+  unsigned int stat;
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
-  if((pcmcia_low_level->socket_state(&state_array))<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+  memset(state, 0, sizeof(state));
+
+  if ((pcmcia_low_level->socket_state(&state_array)) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n");
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].k_state=state[sock];
-
-  *status=state[sock].detect?SS_DETECT:0;
+  skt->k_state = state[sock];
 
-  *status|=state[sock].ready?SS_READY:0;
+  stat = state[sock].detect ? SS_DETECT : 0;
+  stat |= state[sock].ready ? SS_READY  : 0;
+  stat |= state[sock].vs_3v ? SS_3VCARD : 0;
+  stat |= state[sock].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:
    */
-  *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
+  stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
 
-  if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
-    *status|=state[sock].bvd1?SS_STSCHG:0;
+  if (skt->cs_state.flags & SS_IOCARD)
+    stat |= state[sock].bvd1 ? SS_STSCHG : 0;
   else {
-    if(state[sock].bvd1==0)
-      *status|=SS_BATDEAD;
-    else if(state[sock].bvd2==0)
-      *status|=SS_BATWARN;
+    if (state[sock].bvd1 == 0)
+      stat |= SS_BATDEAD;
+    else if (state[sock].bvd2 == 0)
+      stat |= SS_BATWARN;
   }
 
-  *status|=state[sock].vs_3v?SS_3VCARD:0;
-
-  *status|=state[sock].vs_Xv?SS_XVCARD:0;
-
   DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
-	(*status&SS_DETECT)?"DETECT ":"",
-	(*status&SS_READY)?"READY ":"", 
-	(*status&SS_BATDEAD)?"BATDEAD ":"",
-	(*status&SS_BATWARN)?"BATWARN ":"",
-	(*status&SS_POWERON)?"POWERON ":"",
-	(*status&SS_STSCHG)?"STSCHG ":"",
-	(*status&SS_3VCARD)?"3VCARD ":"",
-	(*status&SS_XVCARD)?"XVCARD ":"");
+	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 "  : "");
 
-  return 0;
+  *status = stat;
 
+  return 0;
 }  /* sa1100_pcmcia_get_status() */
 
 
@@ -706,20 +467,18 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_socket(unsigned int sock,
-				    socket_state_t *state){
+static int
+sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  /* This information was given to us in an earlier call to set_socket(),
-   * so we're just regurgitating it here:
-   */
-  *state=sa1100_pcmcia_socket[sock].cs_state;
+  *state = skt->cs_state;
 
   return 0;
 }
 
-
 /* sa1100_pcmcia_set_socket()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the set_socket() operation for the in-kernel PCMCIA
@@ -730,14 +489,15 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state){
-  struct pcmcia_configure configure;
+static int
+sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
-	"\tVcc %d  Vpp %d  irq %d\n",
+  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 ":"",
@@ -749,25 +509,20 @@
 	(state->flags&SS_IOCARD)?"IOCARD ":"",
 	(state->flags&SS_RESET)?"RESET ":"",
 	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
+  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
 	state->Vcc, state->Vpp, state->io_irq);
 
-  configure.sock=sock;
-  configure.vcc=state->Vcc;
-  configure.vpp=state->Vpp;
-  configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
-  configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
-  configure.reset=(state->flags&SS_RESET)?1:0;
+  conf = sa1100_pcmcia_state_to_config(sock, state);
 
-  if(pcmcia_low_level->configure_socket(&configure)<0){
-    printk(KERN_ERR "Unable to configure socket %u\n", sock);
+  if (pcmcia_low_level->configure_socket(&conf) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock);
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].cs_state=*state;
+  skt->cs_state = *state;
   
   return 0;
-
 }  /* sa1100_pcmcia_set_socket() */
 
 
@@ -779,20 +534,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
+static int
+sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_IO_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_IO_WIN) {
+    *map = skt->io_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].io_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -805,16 +560,16 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->start, map->stop,
+  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 ":"",
@@ -824,45 +579,45 @@
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
 	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
 
-  if(map->map>=MAX_IO_WIN){
+  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->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
 
-    speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS;
+    if (speed == 0)
+      speed = SA1100_PCMCIA_IO_ACCESS;
 
-    clock = get_cclk_frequency() * 100;
+    clock = cpufreq_get(0);
 
-    mecr=MECR;
+    mecr = MECR;
 
     MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
 
-    sa1100_pcmcia_socket[sock].speed_io=speed;
+    skt->speed_io = speed;
 
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
 
-    MECR=mecr;
-
+    MECR = mecr;
   }
 
-  start=map->start;
+  if (map->stop == 1)
+    map->stop = PAGE_SIZE-1;
 
-  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;
 
-  map->start=sa1100_pcmcia_socket[sock].virt_io;
-  map->stop=map->start+(map->stop-start);
-
-  sa1100_pcmcia_socket[sock].io_map[map->map]=*map;
+  skt->io_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_io_map() */
 
 
@@ -875,20 +630,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
+static int
+sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_WIN) {
+    *map = skt->mem_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].mem_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -901,18 +656,18 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+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(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
-	"\tsys_stop   %#lx\n\tcard_start %#x\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->sys_start, map->sys_stop,
-	map->card_start, (map->flags==0)?"<NONE>":"",
+  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 ":"",
@@ -921,177 +676,175 @@
 	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
 
-  if(map->map>=MAX_WIN){
+  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:
+  if (map->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
+
+    /*
+     * When clients issue RequestMap, the access speed is not always
+     * properly configured.  Choose some sensible defaults.
      */
-    if(map->speed > 0)
-      speed = map->speed;
-    else
-      switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
-      case 33:
+    if (speed == 0) {
+      if (skt->cs_state.Vcc == 33)
 	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
-	break;
-      default:
+      else
 	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
-      }
+    }
 
-    clock = get_cclk_frequency() * 100;
-    
-    mecr=MECR;
-    
-    if(map->flags&MAP_ATTRIB){
+    clock = cpufreq_get(0);
 
-      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_attr=speed;
+    /* Fixme: MECR is not pre-empt safe. */
+    mecr = MECR;
 
+    if (map->flags & MAP_ATTRIB) {
+      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+      skt->speed_attr = speed;
     } else {
-
       MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_mem=speed;
-
+      skt->speed_mem = speed;
     }
-    
+
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
-    
-    MECR=mecr;
 
+    MECR = mecr;
   }
 
-  start=map->sys_start;
-
-  if(map->sys_stop==0)
-    map->sys_stop=PAGE_SIZE-1;
+  start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;
 
-  map->sys_start=(map->flags & MAP_ATTRIB)?\
-    sa1100_pcmcia_socket[sock].phys_attr:\
-    sa1100_pcmcia_socket[sock].phys_mem;
+  if (map->sys_stop == 0)
+    map->sys_stop = PAGE_SIZE-1;
 
-  map->sys_stop=map->sys_start+(map->sys_stop-start);
+  map->sys_stop -= map->sys_start;
+  map->sys_stop += start;
+  map->sys_start = start;
 
-  sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;
+  skt->mem_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_mem_map() */
 
 
 #if defined(CONFIG_PROC_FS)
 
-/* 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=(void *)sock;
-}
-
-
 /* 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){
-  char *p=buf;
-  unsigned int sock=(unsigned int)data;
-  unsigned int clock = get_cclk_frequency() * 100;
+static int
+sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+  unsigned int sock = (unsigned int)data;
+  unsigned int clock = cpufreq_get(0);
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   unsigned long mecr = MECR;
+  char *p = buf;
 
-  p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
-	     sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
+  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",
-	     sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
-	      sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
+	     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",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
-	     "SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
-	     "SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
-	     "SS_BATDEAD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
-	     "SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
-	     "SS_STSCHG ":"");
+	     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",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
-	     "SS_PWR_AUTO ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
-	     "SS_RESET ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
-	     "SS_SPKR_ENA ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
-	     "SS_OUTPUT_ENA ":"");
-
-  p+=sprintf(p, "Vcc      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc);
-
-  p+=sprintf(p, "Vpp      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp);
-
-  p+=sprintf(p, "irq      : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq);
+	     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", sa1100_pcmcia_socket[sock].speed_io,
+  p+=sprintf(p, "I/O      : %u (%u)\n", skt->speed_io,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock)));
 
-  p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr,
+  p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock)));
 
-  p+=sprintf(p, "common   : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem,
+  p+=sprintf(p, "common   : %u (%u)\n", skt->speed_mem,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock)));
 
   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 = (void *)sock;
+}
+
 #endif  /* defined(CONFIG_PROC_FS) */
 
+static struct pccard_operations sa1100_pcmcia_operations = {
+  init:			sa1100_pcmcia_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,
+  get_io_map:		sa1100_pcmcia_get_io_map,
+  set_io_map:		sa1100_pcmcia_set_io_map,
+  get_mem_map:		sa1100_pcmcia_get_mem_map,
+  set_mem_map:		sa1100_pcmcia_set_mem_map,
+#ifdef CONFIG_PROC_FS
+  proc_setup:		sa1100_pcmcia_proc_setup
+#endif
+};
 
 #ifdef CONFIG_CPU_FREQ
 
@@ -1101,7 +854,8 @@
  * 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){
+static void sa1100_pcmcia_update_mecr(unsigned int clock)
+{
   unsigned int sock;
   unsigned long mecr = MECR;
 
@@ -1132,53 +886,293 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_notifier(struct notifier_block *nb,
-				  unsigned long val, void *data){
+static int
+sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
   struct cpufreq_info *ci = data;
 
-  switch(val){
-  case CPUFREQ_MINMAX:
-
-    break;
-
+  switch (val) {
   case CPUFREQ_PRECHANGE:
-
-    if(ci->new_freq > ci->old_freq){
+    if (ci->new_freq > ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
 
   case CPUFREQ_POSTCHANGE:
-
-    if(ci->new_freq < ci->old_freq){
+    if (ci->new_freq < ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
-
-  default:
-    printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
-	   val);
-    return -1;
-
   }
 
   return 0;
-
 }
 
 static struct notifier_block sa1100_pcmcia_notifier_block = {
   notifier_call: sa1100_pcmcia_notifier
 };
+#endif
 
+static int __init sa1100_pcmcia_machine_init(void)
+{
+#ifdef CONFIG_SA1100_ASSABET
+  if(machine_is_assabet()) {
+    if(machine_has_neponset()) {
+#ifdef CONFIG_ASSABET_NEPONSET
+      pcmcia_low_level = &neponset_pcmcia_ops;
+#else
+      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
+      return -1;
+#endif
+    } else
+      pcmcia_low_level = &assabet_pcmcia_ops;
+  }
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+  if (machine_is_badge4())
+    pcmcia_low_level = &badge4_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+  if (machine_is_freebird())
+    pcmcia_low_level = &freebird_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_H3600
+  if (machine_is_h3600())
+    pcmcia_low_level = &h3600_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_CERF
+  if (machine_is_cerf())
+    pcmcia_low_level = &cerf_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+  if (machine_is_graphicsclient())
+    pcmcia_low_level = &gcplus_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_XP860
+  if (machine_is_xp860())
+    pcmcia_low_level = &xp860_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_YOPY
+  if (machine_is_yopy())
+    pcmcia_low_level = &yopy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+  if (machine_is_shannon())
+    pcmcia_low_level = &shannon_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+  if (machine_is_pangolin())
+    pcmcia_low_level = &pangolin_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+  if (machine_is_jornada720())
+    pcmcia_low_level = &jornada720_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PFS168
+  if(machine_is_pfs168())
+    pcmcia_low_level = &pfs168_pcmcia_ops;
 #endif
+#ifdef CONFIG_SA1100_FLEXANET
+  if(machine_is_flexanet())
+    pcmcia_low_level = &flexanet_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+  if(machine_is_simpad())
+    pcmcia_low_level = &simpad_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+  if(machine_is_graphicsmaster())
+    pcmcia_low_level = &graphicsmaster_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_ADSBITSY
+  if(machine_is_adsbitsy())
+    pcmcia_low_level = &adsbitsy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_STORK
+  if(machine_is_stork())
+    pcmcia_low_level = &stork_pcmcia_ops;
+#endif
+
+  if (!pcmcia_low_level) {
+    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+/* sa1100_pcmcia_driver_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_driver_init(void)
+{
+  servinfo_t info;
+  struct pcmcia_init pcmcia_init;
+  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+  struct pcmcia_state_array state_array;
+  unsigned int i, clock;
+  unsigned long mecr;
+  int ret;
+
+  printk(KERN_INFO "SA-1100 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;
+  }
+
+  ret = sa1100_pcmcia_machine_init();
+  if (ret)
+    return ret;
+
+  pcmcia_init.handler = sa1100_pcmcia_interrupt;
+
+  ret = pcmcia_low_level->init(&pcmcia_init);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret);
+    return ret == -1 ? -EIO : ret;
+  }
+
+  sa1100_pcmcia_socket_count = ret;
+  state_array.size  = sa1100_pcmcia_socket_count;
+  state_array.state = state;
+
+  memset(state, 0, sizeof(state));
+
+  if (pcmcia_low_level->socket_state(&state_array) < 0) {
+    pcmcia_low_level->shutdown();
+    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+    return -EIO;
+  }
+
+  /*
+   * We initialize the MECR to default values here, because we are
+   * not guaranteed to see a SetIOMap operation at runtime.
+   */
+  mecr = 0;
+
+  clock = cpufreq_get(0);
+
+  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+    struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+    struct pcmcia_irq_info irq_info;
+
+    if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) {
+      ret = -EBUSY;
+      goto out_err;
+    }
+
+    irq_info.sock = i;
+    irq_info.irq  = -1;
+    ret = pcmcia_low_level->get_irq_info(&irq_info);
+    if (ret < 0)
+      printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret);
+
+    skt->irq        = irq_info.irq;
+    skt->k_state    = state[i];
+    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;
+    }
 
+    MECR_FAST_SET(mecr, i, 0);
+    MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock));
+    MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock));
+    MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock));
+  }
+
+  MECR = mecr;
+
+#ifdef CONFIG_CPU_FREQ
+  ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret);
+    goto out_err;
+  }
+#endif
+
+  /* Only advertise as many sockets as we can detect */
+  ret = register_ss_entry(sa1100_pcmcia_socket_count,
+			  &sa1100_pcmcia_operations);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to register sockets\n");
+    goto out_err;
+  }
+
+  /*
+   * 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++) {
+    iounmap(sa1100_pcmcia_socket[i].virt_io);
+    release_mem_region(_PCMCIA(i), PCMCIASp);
+  }
+
+  pcmcia_low_level->shutdown();
+
+  return ret;
+}  /* sa1100_pcmcia_driver_init() */
+
+/* sa1100_pcmcia_driver_shutdown()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa1100_pcmcia_driver_shutdown(void)
+{
+  int i;
+
+  del_timer_sync(&poll_timer);
+
+  unregister_ss_entry(&sa1100_pcmcia_operations);
+
+#ifdef CONFIG_CPU_FREQ
+  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+#endif
+
+  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+    iounmap(sa1100_pcmcia_socket[i].virt_io);
+    release_mem_region(_PCMCIA(i), PCMCIASp);
+  }
+
+  pcmcia_low_level->shutdown();
+
+  flush_scheduled_tasks();
+}
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+MODULE_LICENSE("Dual MPL/GPL");
+
+module_init(sa1100_pcmcia_driver_init);
+module_exit(sa1100_pcmcia_driver_shutdown);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)