提交 c494bc6c 编写于 作者: D Dominik Brodowski

pcmcia serial_cs.c: fix multifunction card handling

We shouldn't overwrite pre-set values, and we should also
set the port address to the beginning, and not the end of
the 8-port range.

CC: linux-serial@vger.kernel.org
Reported-by: NKomuro <komurojun-mbn@nifty.com>
Hardware-supplied-by: NJochen Frieling <j.frieling@pengutronix.de>
Tested-by: NWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: NDominik Brodowski <linux@dominikbrodowski.net>
上级 49553c2e
......@@ -335,8 +335,6 @@ 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;
......@@ -411,6 +409,27 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
/*====================================================================*/
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,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
......@@ -461,23 +480,8 @@ 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);
}
}
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 8;
/* First pass: look for a config entry that looks normal.
* Two tries: without IO aliases, then with aliases */
......@@ -491,8 +495,7 @@ 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:
......@@ -558,6 +561,7 @@ static int multi_config(struct pcmcia_device *link)
int i, base2 = 0;
/* First, look for a generic full-sized window */
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = info->multi * 8;
if (pcmcia_loop_config(link, multi_config_check, &base2)) {
/* If that didn't work, look for two windows */
......@@ -565,15 +569,14 @@ static int multi_config(struct pcmcia_device *link)
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.
......@@ -675,6 +678,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 +689,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 +714,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;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册