summaryrefslogtreecommitdiff
path: root/drivers/serial/serial_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r--drivers/serial/serial_cs.c261
1 files changed, 110 insertions, 151 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 141c69554bd4..93760b2ea172 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -45,7 +45,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
@@ -183,10 +182,8 @@ static void quirk_config_socket(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
- if (info->multi) {
- link->conf.Present |= PRESENT_EXT_STATUS;
- link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
- }
+ if (info->multi)
+ link->config_flags |= CONF_ENABLE_ESR;
}
static const struct serial_quirk quirks[] = {
@@ -265,13 +262,6 @@ static const struct serial_quirk quirks[] = {
static int serial_config(struct pcmcia_device * link);
-/*======================================================================
-
- After a card is removed, serial_remove() will unregister
- the serial device(s), and release the PCMCIA configuration.
-
-======================================================================*/
-
static void serial_remove(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
@@ -314,14 +304,6 @@ static int serial_resume(struct pcmcia_device *link)
return 0;
}
-/*======================================================================
-
- serial_attach() creates an "instance" of the driver, allocating
- local data structures for one device. The device is registered
- with Card Services.
-
-======================================================================*/
-
static int serial_probe(struct pcmcia_device *link)
{
struct serial_info *info;
@@ -335,27 +317,13 @@ static int serial_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
- link->resource[0]->end = 8;
- link->conf.Attributes = CONF_ENABLE_IRQ;
- if (do_sound) {
- link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.Status = CCSR_AUDIO_ENA;
- }
- link->conf.IntType = INT_MEMORY_AND_IO;
+ link->config_flags |= CONF_ENABLE_IRQ;
+ if (do_sound)
+ link->config_flags |= CONF_ENABLE_SPKR;
return serial_config(link);
}
-/*======================================================================
-
- This deletes a driver "instance". The device is de-registered
- with Card Services. If it has been released, all local data
- structures are freed. Otherwise, the structures will be freed
- when the device is released.
-
-======================================================================*/
-
static void serial_detach(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
@@ -363,11 +331,6 @@ static void serial_detach(struct pcmcia_device *link)
dev_dbg(&link->dev, "serial_detach\n");
/*
- * Ensure any outstanding scheduled tasks are completed.
- */
- flush_scheduled_work();
-
- /*
* Ensure that the ports have been released.
*/
serial_remove(link);
@@ -411,47 +374,66 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
/*====================================================================*/
-static int simple_config_check(struct pcmcia_device *p_dev,
- cistpl_cftable_entry_t *cf,
- cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
- void *priv_data)
+static int pfc_config(struct pcmcia_device *p_dev)
+{
+ unsigned int port = 0;
+ struct serial_info *info = p_dev->priv;
+
+ if ((p_dev->resource[1]->end != 0) &&
+ (resource_size(p_dev->resource[1]) == 8)) {
+ port = p_dev->resource[1]->start;
+ info->slave = 1;
+ } else if ((info->manfid == MANFID_OSITECH) &&
+ (resource_size(p_dev->resource[0]) == 0x40)) {
+ port = p_dev->resource[0]->start + 0x28;
+ info->slave = 1;
+ }
+ if (info->slave)
+ return setup_serial(p_dev, info, port, p_dev->irq);
+
+ dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
+ return -ENODEV;
+}
+
+static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
{
static const int size_table[2] = { 8, 16 };
int *try = priv_data;
- if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->conf.Vpp =
- cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ if (p_dev->resource[0]->start == 0)
+ return -ENODEV;
- p_dev->io_lines = ((*try & 0x1) == 0) ?
- 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+ if ((*try & 0x1) == 0)
+ p_dev->io_lines = 16;
- if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)])
- && (cf->io.win[0].base != 0)) {
- p_dev->resource[0]->start = cf->io.win[0].base;
- if (!pcmcia_request_io(p_dev))
- return 0;
- }
- return -EINVAL;
+ if (p_dev->resource[0]->end != size_table[(*try >> 1)])
+ return -ENODEV;
+
+ p_dev->resource[0]->end = 8;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+ return pcmcia_request_io(p_dev);
}
static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
- cistpl_cftable_entry_t *cf,
- cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
int j;
- if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
- for (j = 0; j < 5; j++) {
- p_dev->resource[0]->start = base[j];
- p_dev->io_lines = base[j] ? 16 : 3;
- if (!pcmcia_request_io(p_dev))
- return 0;
- }
+ if (p_dev->io_lines > 3)
+ return -ENODEV;
+
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[0]->end = 8;
+
+ for (j = 0; j < 5; j++) {
+ p_dev->resource[0]->start = base[j];
+ p_dev->io_lines = base[j] ? 16 : 3;
+ if (!pcmcia_request_io(p_dev))
+ return 0;
}
return -ENODEV;
}
@@ -461,26 +443,9 @@ static int simple_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* If the card is already configured, look up the port and irq */
- if (link->function_config) {
- unsigned int port = 0;
- if ((link->resource[1]->end != 0) &&
- (resource_size(link->resource[1]) == 8)) {
- port = link->resource[1]->end;
- info->slave = 1;
- } else if ((info->manfid == MANFID_OSITECH) &&
- (resource_size(link->resource[0]) == 0x40)) {
- port = link->resource[0]->start + 0x28;
- info->slave = 1;
- }
- if (info->slave) {
- return setup_serial(link, info, port,
- link->irq);
- }
- }
-
/* First pass: look for a config entry that looks normal.
* Two tries: without IO aliases, then with aliases */
+ link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
@@ -491,13 +456,12 @@ static int simple_config(struct pcmcia_device *link)
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
- printk(KERN_NOTICE
- "serial_cs: no usable port range found, giving up\n");
+ dev_warn(&link->dev, "no usable port range found, giving up\n");
return -1;
found_port:
if (info->multi && (info->manfid == MANFID_3COM))
- link->conf.ConfigIndex &= ~(0x08);
+ link->config_index &= ~(0x08);
/*
* Apply any configuration quirks.
@@ -505,51 +469,50 @@ found_port:
if (info->quirk && info->quirk->config)
info->quirk->config(link);
- i = pcmcia_request_configuration(link, &link->conf);
+ i = pcmcia_enable_device(link);
if (i != 0)
return -1;
return setup_serial(link, info, link->resource[0]->start, link->irq);
}
-static int multi_config_check(struct pcmcia_device *p_dev,
- cistpl_cftable_entry_t *cf,
- cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
- void *priv_data)
+static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
{
- int *base2 = priv_data;
+ int *multi = priv_data;
+
+ if (p_dev->resource[1]->end)
+ return -EINVAL;
/* The quad port cards have bad CIS's, so just look for a
window larger than 8 ports and assume it will be right */
- if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
- p_dev->resource[0]->start = cf->io.win[0].base;
- p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev)) {
- *base2 = p_dev->resource[0]->start + 8;
- return 0;
- }
- }
- return -ENODEV;
+ if (p_dev->resource[0]->end <= 8)
+ return -EINVAL;
+
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[0]->end = *multi * 8;
+
+ if (pcmcia_request_io(p_dev))
+ return -ENODEV;
+ return 0;
}
static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
- cistpl_cftable_entry_t *cf,
- cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *base2 = priv_data;
- if (cf->io.nwin == 2) {
- p_dev->resource[0]->start = cf->io.win[0].base;
- p_dev->resource[1]->start = cf->io.win[1].base;
- p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev)) {
- *base2 = p_dev->resource[1]->start;
- return 0;
- }
- }
- return -ENODEV;
+ if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
+ return -ENODEV;
+
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+ if (pcmcia_request_io(p_dev))
+ return -ENODEV;
+
+ *base2 = p_dev->resource[0]->start + 8;
+ return 0;
}
static int multi_config(struct pcmcia_device *link)
@@ -557,23 +520,23 @@ static int multi_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i, base2 = 0;
+ link->config_flags |= CONF_AUTO_SET_IO;
/* First, look for a generic full-sized window */
- link->resource[0]->end = info->multi * 8;
- if (pcmcia_loop_config(link, multi_config_check, &base2)) {
+ if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
+ base2 = link->resource[0]->start + 8;
+ else {
/* If that didn't work, look for two windows */
- link->resource[0]->end = link->resource[1]->end = 8;
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- printk(KERN_NOTICE "serial_cs: no usable port range"
+ dev_warn(&link->dev, "no usable port range "
"found, giving up\n");
return -ENODEV;
}
}
if (!link->irq)
- dev_warn(&link->dev,
- "serial_cs: no usable IRQ found, continuing...\n");
+ dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
/*
* Apply any configuration quirks.
@@ -581,7 +544,7 @@ static int multi_config(struct pcmcia_device *link)
if (info->quirk && info->quirk->config)
info->quirk->config(link);
- i = pcmcia_request_configuration(link, &link->conf);
+ i = pcmcia_enable_device(link);
if (i != 0)
return -ENODEV;
@@ -593,11 +556,11 @@ static int multi_config(struct pcmcia_device *link)
info->prodid == PRODID_POSSIO_GCC)) {
int err;
- if (link->conf.ConfigIndex == 1 ||
- link->conf.ConfigIndex == 3) {
+ if (link->config_index == 1 ||
+ link->config_index == 3) {
err = setup_serial(link, info, base2,
link->irq);
- base2 = link->resource[0]->start;;
+ base2 = link->resource[0]->start;
} else {
err = setup_serial(link, info, link->resource[0]->start,
link->irq);
@@ -621,33 +584,24 @@ static int multi_config(struct pcmcia_device *link)
return 0;
}
-static int serial_check_for_multi(struct pcmcia_device *p_dev,
- cistpl_cftable_entry_t *cf,
- cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
- void *priv_data)
+static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
{
struct serial_info *info = p_dev->priv;
- if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
- info->multi = cf->io.win[0].len >> 3;
+ if (!p_dev->resource[0]->end)
+ return -EINVAL;
+
+ if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
+ info->multi = p_dev->resource[0]->end >> 3;
- if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
- (cf->io.win[1].len == 8))
+ if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
+ && (p_dev->resource[1]->end == 8))
info->multi = 2;
return 0; /* break */
}
-/*======================================================================
-
- serial_config() is scheduled to run after a CARD_INSERTION event
- is received, to configure the PCMCIA socket, and to make the
- serial device available to the system.
-
-======================================================================*/
-
static int serial_config(struct pcmcia_device * link)
{
struct serial_info *info = link->priv;
@@ -675,6 +629,7 @@ static int serial_config(struct pcmcia_device * link)
multifunction cards that ask for appropriate IO port ranges */
if ((info->multi == 0) &&
(link->has_func_id) &&
+ (link->socket->pcmcia_pfc == 0) &&
((link->func_id == CISTPL_FUNCID_MULTI) ||
(link->func_id == CISTPL_FUNCID_SERIAL)))
pcmcia_loop_config(link, serial_check_for_multi, info);
@@ -685,7 +640,13 @@ static int serial_config(struct pcmcia_device * link)
if (info->quirk && info->quirk->multi != -1)
info->multi = info->quirk->multi;
- if (info->multi > 1)
+ dev_info(&link->dev,
+ "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
+ link->manf_id, link->card_id,
+ link->socket->pcmcia_pfc, info->multi, info->quirk);
+ if (link->socket->pcmcia_pfc)
+ i = pfc_config(link);
+ else if (info->multi > 1)
i = multi_config(link);
else
i = simple_config(link);
@@ -704,7 +665,7 @@ static int serial_config(struct pcmcia_device * link)
return 0;
failed:
- dev_warn(&link->dev, "serial_cs: failed to initialize\n");
+ dev_warn(&link->dev, "failed to initialize\n");
serial_remove(link);
return -ENODEV;
}
@@ -884,9 +845,7 @@ MODULE_FIRMWARE("cis/RS-COM-2P.cis");
static struct pcmcia_driver serial_cs_driver = {
.owner = THIS_MODULE,
- .drv = {
- .name = "serial_cs",
- },
+ .name = "serial_cs",
.probe = serial_probe,
.remove = serial_detach,
.id_table = serial_ids,