linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / isdn / hisax / teles_cs.c
index afcc2ae..4e5c14c 100644 (file)
@@ -75,8 +75,8 @@ module_param(protocol, int, 0);
    handler.
 */
 
-static int teles_cs_config(struct pcmcia_device *link);
-static void teles_cs_release(struct pcmcia_device *link);
+static void teles_cs_config(dev_link_t *link);
+static void teles_cs_release(dev_link_t *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -89,10 +89,10 @@ static void teles_detach(struct pcmcia_device *p_dev);
 /*
    A linked list of "instances" of the teles_cs device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one struct pcmcia_device structure (defined in ds.h).
+   by one dev_link_t structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of struct pcmcia_device pointers, where minor
+   memory card driver uses an array of dev_link_t pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -102,7 +102,7 @@ static void teles_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 struct pcmcia_device
+   in a linked list starting at the 'dev' field of a dev_link_t
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
    In this case, we also provide a flag to indicate if a device is
@@ -112,7 +112,7 @@ static void teles_detach(struct pcmcia_device *p_dev);
 */
 
 typedef struct local_info_t {
-       struct pcmcia_device    *p_dev;
+    dev_link_t          link;
     dev_node_t          node;
     int                 busy;
     int                        cardnr;
@@ -130,8 +130,9 @@ typedef struct local_info_t {
 
 ======================================================================*/
 
-static int teles_probe(struct pcmcia_device *link)
+static int teles_attach(struct pcmcia_device *p_dev)
 {
+    dev_link_t *link;
     local_info_t *local;
 
     DEBUG(0, "teles_attach()\n");
@@ -141,9 +142,7 @@ static int teles_probe(struct pcmcia_device *link)
     if (!local) return -ENOMEM;
     memset(local, 0, sizeof(local_info_t));
     local->cardnr = -1;
-
-    local->p_dev = link;
-    link->priv = local;
+    link = &local->link; link->priv = local;
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
@@ -162,9 +161,16 @@ static int teles_probe(struct pcmcia_device *link)
     link->io.IOAddrLines = 5;
 
     link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    return teles_cs_config(link);
+    link->handle = p_dev;
+    p_dev->instance = link;
+
+    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+    teles_cs_config(link);
+
+    return 0;
 } /* teles_attach */
 
 /*======================================================================
@@ -176,16 +182,20 @@ static int teles_probe(struct pcmcia_device *link)
 
 ======================================================================*/
 
-static void teles_detach(struct pcmcia_device *link)
+static void teles_detach(struct pcmcia_device *p_dev)
 {
-       local_info_t *info = link->priv;
+    dev_link_t *link = dev_to_instance(p_dev);
+    local_info_t *info = link->priv;
+
+    DEBUG(0, "teles_detach(0x%p)\n", link);
 
-       DEBUG(0, "teles_detach(0x%p)\n", link);
+    if (link->state & DEV_CONFIG) {
+           info->busy = 1;
+           teles_cs_release(link);
+    }
 
-       info->busy = 1;
-       teles_cs_release(link);
+    kfree(info);
 
-       kfree(info);
 } /* teles_detach */
 
 /*======================================================================
@@ -195,7 +205,7 @@ static void teles_detach(struct pcmcia_device *link)
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int get_tuple(client_handle_t handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_tuple_data(handle, tuple);
@@ -203,7 +213,7 @@ static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
     return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int first_tuple(client_handle_t handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_first_tuple(handle, tuple);
@@ -211,7 +221,7 @@ static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
     return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int next_tuple(client_handle_t handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_next_tuple(handle, tuple);
@@ -219,8 +229,9 @@ static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
     return get_tuple(handle, tuple, parse);
 }
 
-static int teles_cs_config(struct pcmcia_device *link)
+static void teles_cs_config(dev_link_t *link)
 {
+    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     local_info_t *dev;
@@ -230,6 +241,7 @@ static int teles_cs_config(struct pcmcia_device *link)
     IsdnCard_t icard;
 
     DEBUG(0, "teles_config(0x%p)\n", link);
+    handle = link->handle;
     dev = link->priv;
 
     /*
@@ -241,7 +253,7 @@ static int teles_cs_config(struct pcmcia_device *link)
     tuple.TupleDataMax = 255;
     tuple.TupleOffset = 0;
     tuple.Attributes = 0;
-    i = first_tuple(link, &tuple, &parse);
+    i = first_tuple(handle, &tuple, &parse);
     if (i != CS_SUCCESS) {
         last_fn = ParseTuple;
        goto cs_failed;
@@ -249,29 +261,32 @@ static int teles_cs_config(struct pcmcia_device *link)
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(link, &tuple, &parse);
+    i = first_tuple(handle, &tuple, &parse);
     while (i == CS_SUCCESS) {
         if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
             printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
             link->conf.ConfigIndex = cf->index;
             link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link, &link->io);
+            i = pcmcia_request_io(link->handle, &link->io);
             if (i == CS_SUCCESS) break;
         } else {
           printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
           link->conf.ConfigIndex = cf->index;
           for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
             link->io.BasePort1 = j;
-            i = pcmcia_request_io(link, &link->io);
+            i = pcmcia_request_io(link->handle, &link->io);
             if (i == CS_SUCCESS) break;
           }
           break;
         }
-        i = next_tuple(link, &tuple, &parse);
+        i = next_tuple(handle, &tuple, &parse);
     }
 
     if (i != CS_SUCCESS) {
@@ -279,14 +294,14 @@ static int teles_cs_config(struct pcmcia_device *link)
        goto cs_failed;
     }
 
-    i = pcmcia_request_irq(link, &link->irq);
+    i = pcmcia_request_irq(link->handle, &link->irq);
     if (i != CS_SUCCESS) {
         link->irq.AssignedIRQ = 0;
        last_fn = RequestIRQ;
         goto cs_failed;
     }
 
-    i = pcmcia_request_configuration(link, &link->conf);
+    i = pcmcia_request_configuration(link->handle, &link->conf);
     if (i != CS_SUCCESS) {
       last_fn = RequestConfiguration;
       goto cs_failed;
@@ -297,11 +312,14 @@ static int teles_cs_config(struct pcmcia_device *link)
     sprintf(dev->node.dev_name, "teles");
     dev->node.major = dev->node.minor = 0x0;
 
-    link->dev_node = &dev->node;
+    link->dev = &dev->node;
 
     /* Finally, report what we've done */
-    printk(KERN_INFO "%s: index 0x%02x:",
-           dev->node.dev_name, link->conf.ConfigIndex);
+    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+           dev->node.dev_name, link->conf.ConfigIndex,
+           link->conf.Vcc/10, link->conf.Vcc%10);
+    if (link->conf.Vpp1)
+        printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
         printk(", irq %d", link->irq.AssignedIRQ);
     if (link->io.NumPorts1)
@@ -312,6 +330,8 @@ static int teles_cs_config(struct pcmcia_device *link)
                link->io.BasePort2+link->io.NumPorts2-1);
     printk("\n");
 
+    link->state &= ~DEV_CONFIG_PENDING;
+
     icard.para[0] = link->irq.AssignedIRQ;
     icard.para[1] = link->io.BasePort1;
     icard.protocol = protocol;
@@ -322,16 +342,13 @@ static int teles_cs_config(struct pcmcia_device *link)
        printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
                i, link->io.BasePort1);
        teles_cs_release(link);
-       return -ENODEV;
-    }
-
-    ((local_info_t*)link->priv)->cardnr = i;
-    return 0;
+    } else
+       ((local_info_t*)link->priv)->cardnr = i;
 
+    return;
 cs_failed:
-    cs_error(link, last_fn, i);
+    cs_error(link->handle, last_fn, i);
     teles_cs_release(link);
-    return -ENODEV;
 } /* teles_cs_config */
 
 /*======================================================================
@@ -342,7 +359,7 @@ cs_failed:
 
 ======================================================================*/
 
-static void teles_cs_release(struct pcmcia_device *link)
+static void teles_cs_release(dev_link_t *link)
 {
     local_info_t *local = link->priv;
 
@@ -354,23 +371,39 @@ static void teles_cs_release(struct pcmcia_device *link)
            HiSax_closecard(local->cardnr);
        }
     }
-
-    pcmcia_disable_device(link);
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win)
+        pcmcia_release_window(link->win);
+    pcmcia_release_configuration(link->handle);
+    pcmcia_release_io(link->handle, &link->io);
+    pcmcia_release_irq(link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
 } /* teles_cs_release */
 
-static int teles_suspend(struct pcmcia_device *link)
+static int teles_suspend(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        local_info_t *dev = link->priv;
 
+       link->state |= DEV_SUSPEND;
         dev->busy = 1;
+       if (link->state & DEV_CONFIG)
+               pcmcia_release_configuration(link->handle);
 
        return 0;
 }
 
-static int teles_resume(struct pcmcia_device *link)
+static int teles_resume(struct pcmcia_device *p_dev)
 {
+       dev_link_t *link = dev_to_instance(p_dev);
        local_info_t *dev = link->priv;
 
+       link->state &= ~DEV_SUSPEND;
+       if (link->state & DEV_CONFIG)
+               pcmcia_request_configuration(link->handle, &link->conf);
         dev->busy = 0;
 
        return 0;
@@ -388,7 +421,7 @@ static struct pcmcia_driver teles_cs_driver = {
        .drv            = {
                .name   = "teles_cs",
        },
-       .probe          = teles_probe,
+       .probe          = teles_attach,
        .remove         = teles_detach,
        .id_table       = teles_ids,
        .suspend        = teles_suspend,