Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[safe/jmp/linux-2.6] / drivers / isdn / hisax / sedlbauer_cs.c
index 6025722..9a3c9f5 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -95,8 +94,8 @@ module_param(protocol, int, 0);
    event handler. 
 */
 
-static void sedlbauer_config(dev_link_t *link);
-static void sedlbauer_release(dev_link_t *link);
+static int sedlbauer_config(struct pcmcia_device *link);
+static void sedlbauer_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -119,7 +118,7 @@ static void sedlbauer_detach(struct pcmcia_device *p_dev);
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
 
@@ -148,24 +147,22 @@ typedef struct local_info_t {
     
 ======================================================================*/
 
-static int sedlbauer_attach(struct pcmcia_device *p_dev)
+static int sedlbauer_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
-    dev_link_t *link = dev_to_instance(p_dev);
-    
+
     DEBUG(0, "sedlbauer_attach()\n");
 
     /* Allocate space for private device-specific data */
-    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
     if (!local) return -ENOMEM;
-    memset(local, 0, sizeof(local_info_t));
     local->cardnr = -1;
 
-    local->p_dev = p_dev;
+    local->p_dev = link;
     link->priv = local;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
 
@@ -187,10 +184,7 @@ static int sedlbauer_attach(struct pcmcia_device *p_dev)
     link->conf.Attributes = 0;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    sedlbauer_config(link);
-
-    return 0;
+    return sedlbauer_config(link);
 } /* sedlbauer_attach */
 
 /*======================================================================
@@ -202,19 +196,15 @@ static int sedlbauer_attach(struct pcmcia_device *p_dev)
 
 ======================================================================*/
 
-static void sedlbauer_detach(struct pcmcia_device *p_dev)
+static void sedlbauer_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
+       DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
 
-    DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
+       ((local_info_t *)link->priv)->stop = 1;
+       sedlbauer_release(link);
 
-    if (link->state & DEV_CONFIG) {
-           ((local_info_t *)link->priv)->stop = 1;
-           sedlbauer_release(link);
-    }
-
-    /* This points to the parent local_info_t struct */
-    kfree(link->priv);
+       /* This points to the parent local_info_t struct */
+       kfree(link->priv);
 } /* sedlbauer_detach */
 
 /*======================================================================
@@ -227,120 +217,66 @@ static void sedlbauer_detach(struct pcmcia_device *p_dev)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void sedlbauer_config(dev_link_t *link)
+static int sedlbauer_config_check(struct pcmcia_device *p_dev,
+                                 cistpl_cftable_entry_t *cfg,
+                                 cistpl_cftable_entry_t *dflt,
+                                 unsigned int vcc,
+                                 void *priv_data)
 {
-    client_handle_t handle = link->handle;
-    local_info_t *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    int last_fn, last_ret;
-    u8 buf[64];
-    config_info_t conf;
-    win_req_t req;
-    memreq_t map;
-    IsdnCard_t  icard;
-
-    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
-
-    /*
-       This reads the card's CONFIG tuple to find its configuration
-       registers.
-    */
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    tuple.Attributes = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
+       win_req_t *req = priv_data;
 
-    /*
-      In this loop, we scan the CIS for configuration table entries,
-      each of which describes a valid card configuration, including
-      voltage, IO window, memory window, and interrupt settings.
+       if (cfg->index == 0)
+               return -ENODEV;
 
-      We make no assumptions about the card to be configured: we use
-      just the information available in the CIS.  In an ideal world,
-      this would work for any PCMCIA card, but it requires a complete
-      and accurate CIS.  In practice, a driver usually "knows" most of
-      these things without consulting the CIS, and most client drivers
-      will only use the CIS to fill in implementation-defined details.
-    */
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    while (1) {
-       cistpl_cftable_entry_t dflt = { 0 };
-       cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-       if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-               pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
-           goto next_entry;
-
-       if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-       if (cfg->index == 0) goto next_entry;
-       link->conf.ConfigIndex = cfg->index;
-       
        /* Does this card need audio output? */
        if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-           link->conf.Attributes |= CONF_ENABLE_SPKR;
-           link->conf.Status = CCSR_AUDIO_ENA;
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
        }
-       
+
        /* Use power settings for Vcc and Vpp if present */
        /*  Note that the CIS values need to be rescaled */
        if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-           if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-               goto next_entry;
-       } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-           if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-               goto next_entry;
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+                       return -ENODEV;
+       } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
+                       return -ENODEV;
        }
-           
+
        if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-       
+               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
        /* Do we need to allocate an interrupt? */
-       if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-           link->conf.Attributes |= CONF_ENABLE_IRQ;
-       
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
        /* IO window settings */
-       link->io.NumPorts1 = link->io.NumPorts2 = 0;
-       if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-           cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-           link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-           if (!(io->flags & CISTPL_IO_8BIT))
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-           if (!(io->flags & CISTPL_IO_16BIT))
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-/* new in dummy.cs 2001/01/28 MN 
-            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-*/
-           link->io.BasePort1 = io->win[0].base;
-           link->io.NumPorts1 = io->win[0].len;
-           if (io->nwin > 1) {
-               link->io.Attributes2 = link->io.Attributes1;
-               link->io.BasePort2 = io->win[1].base;
-               link->io.NumPorts2 = io->win[1].len;
-           }
-           /* This reserves IO space but doesn't actually enable it */
-           if (pcmcia_request_io(link->handle, &link->io) != 0)
-               goto next_entry;
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       return -ENODEV;
        }
 
        /*
          Now set up a common memory window, if needed.  There is room
-         in the dev_link_t structure for one memory window handle,
+         in the struct pcmcia_device structure for one memory window handle,
          but if the base addresses need to be saved, or if multiple
          windows are needed, the info should go in the private data
          structure for this device.
@@ -349,30 +285,54 @@ static void sedlbauer_config(dev_link_t *link)
          needs to be mapped to virtual space with ioremap() before it
          is used.
        */
-       if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-           cistpl_mem_t *mem =
-               (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-           req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-           req.Attributes |= WIN_ENABLE;
-           req.Base = mem->win[0].host_addr;
-           req.Size = mem->win[0].len;
-/* new in dummy.cs 2001/01/28 MN 
-            if (req.Size < 0x1000)
-                req.Size = 0x1000;
-*/
-           req.AccessSpeed = 0;
-           if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
-               goto next_entry;
-           map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-           if (pcmcia_map_mem_page(link->win, &map) != 0)
-               goto next_entry;
+       if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+               cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+               memreq_t map;
+               req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+               req->Attributes |= WIN_ENABLE;
+               req->Base = mem->win[0].host_addr;
+               req->Size = mem->win[0].len;
+               req->AccessSpeed = 0;
+               if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
+                       return -ENODEV;
+               map.Page = 0;
+               map.CardOffset = mem->win[0].card_addr;
+               if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+                       return -ENODEV;
        }
-       /* If we got this far, we're cool! */
-       break;
+       return 0;
+}
 
-    next_entry:
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
-    }
+
+
+static int sedlbauer_config(struct pcmcia_device *link)
+{
+    local_info_t *dev = link->priv;
+    win_req_t *req;
+    int last_fn, last_ret;
+    IsdnCard_t  icard;
+
+    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
+
+    req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
+    if (!req)
+           return -ENOMEM;
+
+    /*
+      In this loop, we scan the CIS for configuration table entries,
+      each of which describes a valid card configuration, including
+      voltage, IO window, memory window, and interrupt settings.
+
+      We make no assumptions about the card to be configured: we use
+      just the information available in the CIS.  In an ideal world,
+      this would work for any PCMCIA card, but it requires a complete
+      and accurate CIS.  In practice, a driver usually "knows" most of
+      these things without consulting the CIS, and most client drivers
+      will only use the CIS to fill in implementation-defined details.
+    */
+    last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
+    if (last_ret)
+           goto failed;
 
     /*
        Allocate an interrupt line.  Note that this does not assign a
@@ -380,14 +340,14 @@ static void sedlbauer_config(dev_link_t *link)
        irq structure is initialized.
     */
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
-       CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
        
     /*
        This actually configures the PCMCIA socket -- setting up
        the I/O windows and the interrupt mapping, and putting the
        card and host interface into "Memory and IO" mode.
     */
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     /*
       At this point, the dev_node_t structure(s) need to be
@@ -411,11 +371,9 @@ static void sedlbauer_config(dev_link_t *link)
        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
               link->io.BasePort2+link->io.NumPorts2-1);
     if (link->win)
-       printk(", mem 0x%06lx-0x%06lx", req.Base,
-              req.Base+req.Size-1);
+       printk(", mem 0x%06lx-0x%06lx", req->Base,
+              req->Base+req->Size-1);
     printk("\n");
-    
-    link->state &= ~DEV_CONFIG_PENDING;
 
     icard.para[0] = link->irq.AssignedIRQ;
     icard.para[1] = link->io.BasePort1;
@@ -427,14 +385,17 @@ static void sedlbauer_config(dev_link_t *link)
        printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
                last_ret, link->io.BasePort1);
        sedlbauer_release(link);
+       return -ENODEV;
     } else
        ((local_info_t*)link->priv)->cardnr = last_ret;
 
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
+failed:
     sedlbauer_release(link);
+    return -ENODEV;
 
 } /* sedlbauer_config */
 
@@ -446,7 +407,7 @@ cs_failed:
     
 ======================================================================*/
 
-static void sedlbauer_release(dev_link_t *link)
+static void sedlbauer_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
     DEBUG(0, "sedlbauer_release(0x%p)\n", link);
@@ -458,12 +419,11 @@ static void sedlbauer_release(dev_link_t *link)
        }
     }
 
-    pcmcia_disable_device(link->handle);
+    pcmcia_disable_device(link);
 } /* sedlbauer_release */
 
-static int sedlbauer_suspend(struct pcmcia_device *p_dev)
+static int sedlbauer_suspend(struct pcmcia_device *link)
 {
-       dev_link_t *link = dev_to_instance(p_dev);
        local_info_t *dev = link->priv;
 
        dev->stop = 1;
@@ -471,9 +431,8 @@ static int sedlbauer_suspend(struct pcmcia_device *p_dev)
        return 0;
 }
 
-static int sedlbauer_resume(struct pcmcia_device *p_dev)
+static int sedlbauer_resume(struct pcmcia_device *link)
 {
-       dev_link_t *link = dev_to_instance(p_dev);
        local_info_t *dev = link->priv;
 
        dev->stop = 0;
@@ -499,7 +458,7 @@ static struct pcmcia_driver sedlbauer_driver = {
        .drv            = {
                .name   = "sedlbauer_cs",
        },
-       .probe          = sedlbauer_attach,
+       .probe          = sedlbauer_probe,
        .remove         = sedlbauer_detach,
        .id_table       = sedlbauer_ids,
        .suspend        = sedlbauer_suspend,