#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>
int multi;
int slave;
int manfid;
+ int prodid;
+ int c950ctrl;
dev_node_t node[4];
int line[4];
};
};
-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
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;
}
link->conf.IntType = INT_MEMORY_AND_IO;
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- serial_config(link);
-
- return 0;
+ return serial_config(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;
}
======================================================================*/
-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;
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;
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))
}
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[] = {