Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / isdn / hisax / sedlbauer_cs.c
index 4496512..9bb18f3 100644 (file)
@@ -47,7 +47,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -96,10 +95,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_event(event_t event, int priority,
-                      event_callback_args_t *args);
+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
@@ -107,8 +104,7 @@ static int sedlbauer_event(event_t event, int priority,
    needed to manage one actual PCMCIA card.
 */
 
-static dev_link_t *sedlbauer_attach(void);
-static void sedlbauer_detach(dev_link_t *);
+static void sedlbauer_detach(struct pcmcia_device *p_dev);
 
 /*
    You'll also need to prototype all the functions that will actually
@@ -118,41 +114,12 @@ static void sedlbauer_detach(dev_link_t *);
 */
 
 /*
-   The dev_info variable is the "key" that is used to match up this
-   device driver with appropriate cards, through the card configuration
-   database.
-*/
-
-static dev_info_t dev_info = "sedlbauer_cs";
-
-/*
-   A linked list of "instances" of the sedlbauer device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   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 dev_link_t pointers, where minor
-   device numbers are used to derive the corresponding array index.
-*/
-
-static dev_link_t *dev_list = NULL;
-
-/*
-   A dev_link_t structure has fields for most things that are needed
-   to keep track of a socket, but there will usually be some device
-   specific information that also needs to be kept track of.  The
-   'priv' pointer in a dev_link_t structure can be used to point to
-   a device-specific private data structure, like this.
-
-   To simplify the data structure handling, we actually include the
-   dev_link_t structure in the device's private data structure.
-
    A driver needs to provide a dev_node_t structure for each device
    on a card.  In some cases, there is only one device per card (for
    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.
 
@@ -163,7 +130,7 @@ static dev_link_t *dev_list = NULL;
 */
    
 typedef struct local_info_t {
-    dev_link_t         link;
+       struct pcmcia_device    *p_dev;
     dev_node_t         node;
     int                        stop;
     int                        cardnr;
@@ -181,22 +148,21 @@ typedef struct local_info_t {
     
 ======================================================================*/
 
-static dev_link_t *sedlbauer_attach(void)
+static int sedlbauer_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int ret;
-    
+
     DEBUG(0, "sedlbauer_attach()\n");
 
     /* Allocate space for private device-specific data */
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
-    if (!local) return NULL;
+    if (!local) return -ENOMEM;
     memset(local, 0, sizeof(local_info_t));
     local->cardnr = -1;
-    link = &local->link; link->priv = local;
-    
+
+    local->p_dev = link;
+    link->priv = local;
+
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
@@ -217,30 +183,10 @@ static dev_link_t *sedlbauer_attach(void)
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
     link->io.IOAddrLines = 3;
 
-
     link->conf.Attributes = 0;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-       CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-       CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-       CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &sedlbauer_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = pcmcia_register_client(&link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-       cs_error(link->handle, RegisterClient, ret);
-       sedlbauer_detach(link);
-       return NULL;
-    }
-
-    return link;
+    return sedlbauer_config(link);
 } /* sedlbauer_attach */
 
 /*======================================================================
@@ -252,41 +198,15 @@ static dev_link_t *sedlbauer_attach(void)
 
 ======================================================================*/
 
-static void sedlbauer_detach(dev_link_t *link)
+static void sedlbauer_detach(struct pcmcia_device *link)
 {
-    dev_link_t **linkp;
+       DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
 
-    DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-       if (*linkp == link) break;
-    if (*linkp == NULL)
-       return;
-
-    /*
-       If the device is currently configured and active, we won't
-       actually delete it yet.  Instead, it is marked so that when
-       the release() function is called, that will trigger a proper
-       detach().
-    */
-    if (link->state & DEV_CONFIG) {
-#ifdef PCMCIA_DEBUG
-       printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' "
-              "still locked\n", link->dev->dev_name);
-#endif
-       link->state |= DEV_STALE_LINK;
-       return;
-    }
+       ((local_info_t *)link->priv)->stop = 1;
+       sedlbauer_release(link);
 
-    /* Break the link with Card Services */
-    if (link->handle)
-       pcmcia_deregister_client(link->handle);
-    
-    /* Unlink device structure, and free it */
-    *linkp = link->next;
-    /* 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 */
 
 /*======================================================================
@@ -299,9 +219,8 @@ static void sedlbauer_detach(dev_link_t *link)
 #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(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     local_info_t *dev = link->priv;
     tuple_t tuple;
     cisparse_t parse;
@@ -323,18 +242,13 @@ static void sedlbauer_config(dev_link_t *link)
     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));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
-    /* Look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
+    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
 
     /*
       In this loop, we scan the CIS for configuration table entries,
@@ -349,12 +263,12 @@ static void sedlbauer_config(dev_link_t *link)
       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));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &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)
+       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
            goto next_entry;
 
        if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
@@ -378,10 +292,10 @@ static void sedlbauer_config(dev_link_t *link)
        }
            
        if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp1 = link->conf.Vpp2 =
+           link->conf.Vpp =
                cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
        else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp1 = link->conf.Vpp2 =
+           link->conf.Vpp =
                dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
        
        /* Do we need to allocate an interrupt? */
@@ -408,13 +322,13 @@ static void sedlbauer_config(dev_link_t *link)
                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)
+           if (pcmcia_request_io(link, &link->io) != 0)
                goto next_entry;
        }
 
        /*
          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.
@@ -435,7 +349,7 @@ static void sedlbauer_config(dev_link_t *link)
                 req.Size = 0x1000;
 */
            req.AccessSpeed = 0;
-           if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
+           if (pcmcia_request_window(&link, &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)
@@ -443,29 +357,25 @@ static void sedlbauer_config(dev_link_t *link)
        }
        /* If we got this far, we're cool! */
        break;
-       
+
     next_entry:
-/* new in dummy.cs 2001/01/28 MN 
-        if (link->io.NumPorts1)
-           pcmcia_release_io(link->handle, &link->io);
-*/
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
     }
-    
+
     /*
        Allocate an interrupt line.  Note that this does not assign a
        handler to the interrupt, unless the 'Handler' member of the
        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
@@ -473,14 +383,13 @@ static void sedlbauer_config(dev_link_t *link)
     */
     sprintf(dev->node.dev_name, "sedlbauer");
     dev->node.major = dev->node.minor = 0;
-    link->dev = &dev->node;
+    link->dev_node = &dev->node;
 
     /* Finally, report what we've done */
-    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);
+    printk(KERN_INFO "%s: index 0x%02x:",
+          dev->node.dev_name, link->conf.ConfigIndex);
+    if (link->conf.Vpp)
+       printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
        printk(", irq %d", link->irq.AssignedIRQ);
     if (link->io.NumPorts1)
@@ -493,8 +402,6 @@ static void sedlbauer_config(dev_link_t *link)
        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;
@@ -506,14 +413,16 @@ 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);
     sedlbauer_release(link);
+    return -ENODEV;
 
 } /* sedlbauer_config */
 
@@ -525,7 +434,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);
@@ -536,93 +445,51 @@ static void sedlbauer_release(dev_link_t *link)
            HiSax_closecard(local->cardnr);
        }
     }
-    /* Unlink the device chain */
-    link->dev = NULL;
 
-    /*
-      In a normal driver, additional code may be needed to release
-      other kernel data structures associated with this device. 
-    */
-    
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win)
-       pcmcia_release_window(link->win);
-    pcmcia_release_configuration(link->handle);
-    if (link->io.NumPorts1)
-       pcmcia_release_io(link->handle, &link->io);
-    if (link->irq.AssignedIRQ)
-       pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
-    
-    if (link->state & DEV_STALE_LINK)
-       sedlbauer_detach(link);
-    
+    pcmcia_disable_device(link);
 } /* sedlbauer_release */
 
-/*======================================================================
+static int sedlbauer_suspend(struct pcmcia_device *link)
+{
+       local_info_t *dev = link->priv;
 
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
+       dev->stop = 1;
 
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-    
-======================================================================*/
+       return 0;
+}
 
-static int sedlbauer_event(event_t event, int priority,
-                      event_callback_args_t *args)
+static int sedlbauer_resume(struct pcmcia_device *link)
 {
-    dev_link_t *link = args->client_data;
-    local_info_t *dev = link->priv;
-    
-    DEBUG(1, "sedlbauer_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-       link->state &= ~DEV_PRESENT;
-       if (link->state & DEV_CONFIG) {
-           ((local_info_t *)link->priv)->stop = 1;
-           sedlbauer_release(link);
-       }
-       break;
-    case CS_EVENT_CARD_INSERTION:
-       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-       sedlbauer_config(link);
-       break;
-    case CS_EVENT_PM_SUSPEND:
-       link->state |= DEV_SUSPEND;
-       /* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-       /* Mark the device as stopped, to block IO until later */
-       dev->stop = 1;
-       if (link->state & DEV_CONFIG)
-           pcmcia_release_configuration(link->handle);
-       break;
-    case CS_EVENT_PM_RESUME:
-       link->state &= ~DEV_SUSPEND;
-       /* Fall through... */
-    case CS_EVENT_CARD_RESET:
-       if (link->state & DEV_CONFIG)
-           pcmcia_request_configuration(link->handle, &link->conf);
+       local_info_t *dev = link->priv;
+
        dev->stop = 0;
-       /*
-         In a normal driver, additional code may go here to restore
-         the device state and restart IO. 
-       */
-       break;
-    }
-    return 0;
-} /* sedlbauer_event */
+
+       return 0;
+}
+
+
+static struct pcmcia_device_id sedlbauer_ids[] = {
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
+       PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
+/*     PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
 
 static struct pcmcia_driver sedlbauer_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "sedlbauer_cs",
        },
-       .attach         = sedlbauer_attach,
-       .detach         = sedlbauer_detach,
+       .probe          = sedlbauer_probe,
+       .remove         = sedlbauer_detach,
+       .id_table       = sedlbauer_ids,
+       .suspend        = sedlbauer_suspend,
+       .resume         = sedlbauer_resume,
 };
 
 static int __init init_sedlbauer_cs(void)
@@ -633,7 +500,6 @@ static int __init init_sedlbauer_cs(void)
 static void __exit exit_sedlbauer_cs(void)
 {
        pcmcia_unregister_driver(&sedlbauer_driver);
-       BUG_ON(dev_list != NULL);
 }
 
 module_init(init_sedlbauer_cs);