[PATCH] remove active field from tty buffer structure
[powerpc.git] / drivers / serial / serial_cs.c
index 1fe8caf..2c70773 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/serial_core.h>
+#include <linux/delay.h>
 #include <linux/major.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -102,6 +103,8 @@ struct serial_info {
        int                     multi;
        int                     slave;
        int                     manfid;
+       int                     prodid;
+       int                     c950ctrl;
        dev_node_t              node[4];
        int                     line[4];
 };
@@ -113,9 +116,36 @@ struct serial_cfg_mem {
 };
 
 
-static void serial_config(struct pcmcia_device * link);
+static int serial_config(struct pcmcia_device * link);
 
 
+static void wakeup_card(struct serial_info *info)
+{
+       int ctrl = info->c950ctrl;
+
+       if (info->manfid == MANFID_OXSEMI) {
+               outb(12, ctrl + 1);
+       } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
+               /* request_region? oxsemi branch does no request_region too... */
+               /* This sequence is needed to properly initialize MC45 attached to OXCF950.
+                * I tried decreasing these msleep()s, but it worked properly (survived
+                * 1000 stop/start operations) with these timeouts (or bigger). */
+               outb(0xA, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(300);
+               outb(0xC, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(200);
+               outb(0xF, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(100);
+               outb(0xC, ctrl + 1);
+       }
+}
+
 /*======================================================================
 
     After a card is removed, serial_remove() will unregister
@@ -128,50 +158,40 @@ static void serial_remove(struct pcmcia_device *link)
        struct serial_info *info = link->priv;
        int i;
 
-       link->state &= ~DEV_PRESENT;
-
        DEBUG(0, "serial_release(0x%p)\n", link);
 
        /*
         * Recheck to see if the device is still configured.
         */
-       if (info->p_dev->state & DEV_CONFIG) {
-               for (i = 0; i < info->ndev; i++)
-                       serial8250_unregister_port(info->line[i]);
-
-               info->p_dev->dev_node = NULL;
+       for (i = 0; i < info->ndev; i++)
+               serial8250_unregister_port(info->line[i]);
 
-               if (!info->slave)
-                       pcmcia_disable_device(link);
+       info->p_dev->dev_node = NULL;
 
-               info->p_dev->state &= ~DEV_CONFIG;
-       }
+       if (!info->slave)
+               pcmcia_disable_device(link);
 }
 
 static int serial_suspend(struct pcmcia_device *link)
 {
-       if (link->state & DEV_CONFIG) {
-               struct serial_info *info = link->priv;
-               int i;
-
-               for (i = 0; i < info->ndev; i++)
-                       serial8250_suspend_port(info->line[i]);
+       struct serial_info *info = link->priv;
+       int i;
 
-               if (info->slave)
-                       link->state &= DEV_SUSPEND_NORELEASE;
-       }
+       for (i = 0; i < info->ndev; i++)
+               serial8250_suspend_port(info->line[i]);
 
        return 0;
 }
 
 static int serial_resume(struct pcmcia_device *link)
 {
-       if (DEV_OK(link)) {
+       if (pcmcia_dev_present(link)) {
                struct serial_info *info = link->priv;
                int i;
 
                for (i = 0; i < info->ndev; i++)
                        serial8250_resume_port(info->line[i]);
+               wakeup_card(info);
        }
 
        return 0;
@@ -210,10 +230,7 @@ static int serial_probe(struct pcmcia_device *link)
        }
        link->conf.IntType = INT_MEMORY_AND_IO;
 
-       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-       serial_config(link);
-
-       return 0;
+       return serial_config(link);
 }
 
 /*======================================================================
@@ -517,15 +534,23 @@ static int multi_config(struct pcmcia_device * link)
        }
 
        /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-          8 registers are for the UART, the others are extra registers */
-       if (info->manfid == MANFID_OXSEMI) {
+        * 8 registers are for the UART, the others are extra registers.
+        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+        */
+       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+                               info->prodid == PRODID_POSSIO_GCC)) {
+               int err;
+
                if (cf->index == 1 || cf->index == 3) {
-                       setup_serial(link, info, base2, link->irq.AssignedIRQ);
-                       outb(12, link->io.BasePort1 + 1);
+                       err = setup_serial(link, info, base2,
+                                       link->irq.AssignedIRQ);
+                       base2 = link->io.BasePort1;
                } else {
-                       setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
-                       outb(12, base2 + 1);
+                       err = setup_serial(link, info, link->io.BasePort1,
+                                       link->irq.AssignedIRQ);
                }
+               info->c950ctrl = base2;
+               wakeup_card(info);
                rc = 0;
                goto free_cfg_mem;
        }
@@ -553,7 +578,7 @@ free_cfg_mem:
 
 ======================================================================*/
 
-void serial_config(struct pcmcia_device * link)
+static int serial_config(struct pcmcia_device * link)
 {
        struct serial_info *info = link->priv;
        struct serial_cfg_mem *cfg_mem;
@@ -588,9 +613,6 @@ void serial_config(struct pcmcia_device * link)
        link->conf.ConfigBase = parse->config.base;
        link->conf.Present = parse->config.rmask[0];
 
-       /* Configure card */
-       link->state |= DEV_CONFIG;
-
        /* Is this a compliant multifunction card? */
        tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
        tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
@@ -600,6 +622,7 @@ void serial_config(struct pcmcia_device * link)
        tuple->DesiredTuple = CISTPL_MANFID;
        if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
                info->manfid = parse->manfid.manf;
+               info->prodid = le16_to_cpu(buf[1]);
                for (i = 0; i < MULTI_COUNT; i++)
                        if ((info->manfid == multi_id[i].manfid) &&
                            (parse->manfid.card == multi_id[i].prodid))
@@ -650,16 +673,15 @@ void serial_config(struct pcmcia_device * link)
        }
 
        link->dev_node = &info->node[0];
-       link->state &= ~DEV_CONFIG_PENDING;
        kfree(cfg_mem);
-       return;
+       return 0;
 
  cs_failed:
        cs_error(link, last_fn, last_ret);
  failed:
        serial_remove(link);
-       link->state &= ~DEV_CONFIG_PENDING;
        kfree(cfg_mem);
+       return -ENODEV;
 }
 
 static struct pcmcia_device_id serial_ids[] = {