patch-2.4.21 linux-2.4.21/drivers/char/pcmcia/serial_cs.c
Next file: linux-2.4.21/drivers/char/pdc_console.c
Previous file: linux-2.4.21/drivers/char/nvram.c
Back to the patch index
Back to the overall index
- Lines: 361
- Date:
2003-06-13 07:51:33.000000000 -0700
- Orig file:
linux-2.4.20/drivers/char/pcmcia/serial_cs.c
- Orig date:
2001-12-21 09:41:54.000000000 -0800
diff -urN linux-2.4.20/drivers/char/pcmcia/serial_cs.c linux-2.4.21/drivers/char/pcmcia/serial_cs.c
@@ -2,7 +2,7 @@
A driver for PCMCIA serial devices
- serial_cs.c 1.128 2001/10/18 12:18:35
+ serial_cs.c 1.138 2002/10/25 06:24:52
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -69,14 +69,14 @@
static int irq_list[4] = { -1 };
MODULE_PARM(irq_list, "1-4i");
-/* Enable the speaker? */
-INT_MODULE_PARM(do_sound, 1);
+INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */
+INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */
#ifdef PCMCIA_DEBUG
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -95,6 +95,7 @@
{ MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
{ MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
{ MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
{ MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
{ MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
{ MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
@@ -148,7 +149,7 @@
client_reg_t client_reg;
dev_link_t *link;
int i, ret;
-
+
DEBUG(0, "serial_attach()\n");
/* Create new serial device */
@@ -160,7 +161,7 @@
link->release.function = &serial_release;
link->release.data = (u_long)link;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
if (irq_list[0] == -1)
@@ -169,13 +170,12 @@
for (i = 0; i < 4; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Vcc = 50;
if (do_sound) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
link->conf.IntType = INT_MEMORY_AND_IO;
-
+
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
@@ -194,7 +194,7 @@
serial_detach(link);
return NULL;
}
-
+
return link;
} /* serial_attach */
@@ -214,7 +214,7 @@
int ret;
DEBUG(0, "serial_detach(0x%p)\n", link);
-
+
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link) break;
@@ -224,17 +224,17 @@
del_timer(&link->release);
if (link->state & DEV_CONFIG)
serial_release((u_long)link);
-
+
if (link->handle) {
ret = CardServices(DeregisterClient, link->handle);
if (ret != CS_SUCCESS)
cs_error(link->handle, DeregisterClient, ret);
}
-
+
/* Unlink device structure, free bits */
*linkp = link->next;
kfree(info);
-
+
} /* serial_detach */
/*====================================================================*/
@@ -243,18 +243,20 @@
{
struct serial_struct serial;
int line;
-
+
memset(&serial, 0, sizeof(serial));
serial.port = port;
serial.irq = irq;
serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+ if (buggy_uart)
+ serial.flags |= ASYNC_BUGGY_UART;
line = register_serial(&serial);
if (line < 0) {
printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
" irq %d failed\n", (u_long)serial.port, serial.irq);
return -1;
}
-
+
info->line[info->ndev] = line;
sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
info->node[info->ndev].major = TTY_MAJOR;
@@ -262,7 +264,7 @@
if (info->ndev > 0)
info->node[info->ndev-1].next = &info->node[info->ndev];
info->ndev++;
-
+
return 0;
}
@@ -313,7 +315,10 @@
return setup_serial(info, port, config.AssignedIRQ);
}
link->conf.Vcc = config.Vcc;
-
+
+ link->io.NumPorts1 = 8;
+ link->io.NumPorts2 = 0;
+
/* First pass: look for a config entry that looks normal. */
tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
@@ -340,7 +345,7 @@
i = next_tuple(handle, &tuple, &parse);
}
}
-
+
/* Second pass: try to find an entry that isn't picky about
its base address, then try to grab any standard serial port
address, and finally try to get any free port. */
@@ -352,8 +357,7 @@
for (j = 0; j < 5; j++) {
link->io.BasePort1 = base[j];
link->io.IOAddrLines = base[j] ? 16 : 3;
- i = CardServices(RequestIO, link->handle,
- &link->io);
+ i = CardServices(RequestIO, link->handle, &link->io);
if (i == CS_SUCCESS) goto found_port;
}
}
@@ -365,7 +369,7 @@
cs_error(link->handle, RequestIO, i);
return -1;
}
-
+
i = CardServices(RequestIRQ, link->handle, &link->irq);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIRQ, i);
@@ -390,8 +394,12 @@
u_char buf[256];
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ config_info_t config;
int i, base2 = 0;
+ CardServices(GetConfigurationInfo, handle, &config);
+ link->conf.Vcc = config.Vcc;
+
tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.Attributes = 0;
@@ -433,12 +441,12 @@
i = next_tuple(handle, &tuple, &parse);
}
}
-
+
if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIO, i);
- return -1;
+ /* At worst, try to configure as a single port */
+ return simple_config(link);
}
-
+
i = CardServices(RequestIRQ, link->handle, &link->irq);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIRQ, i);
@@ -454,14 +462,27 @@
cs_error(link->handle, RequestConfiguration, i);
return -1;
}
-
+
+ /* 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) {
+ if (cf->index == 1 || cf->index == 3) {
+ setup_serial(info, base2, link->irq.AssignedIRQ);
+ outb(12,link->io.BasePort1+1);
+ } else {
+ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+ outb(12,base2+1);
+ }
+ return 0;
+ }
+
setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
/* The Nokia cards are not really multiport cards */
if (info->manfid == MANFID_NOKIA)
return 0;
for (i = 0; i < info->multi-1; i++)
setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-
+
return 0;
}
@@ -487,7 +508,7 @@
int i, last_ret, last_fn;
DEBUG(0, "serial_config(0x%p)\n", link);
-
+
tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.Attributes = 0;
@@ -500,7 +521,7 @@
}
link->conf.ConfigBase = parse.config.base;
link->conf.Present = parse.config.rmask[0];
-
+
/* Configure card */
link->state |= DEV_CONFIG;
@@ -508,8 +529,8 @@
tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-
- /* Is this a multiport card? */
+
+ /* Scan list of known multiport card ID's */
tuple.DesiredTuple = CISTPL_MANFID;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
info->manfid = le16_to_cpu(buf[0]);
@@ -537,15 +558,15 @@
info->multi = 2;
}
}
-
+
if (info->multi > 1)
multi_config(link);
else
simple_config(link);
-
+
if (info->ndev == 0)
goto failed;
-
+
if (info->manfid == MANFID_IBM) {
conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
CS_CHECK(AccessConfigurationRegister, link->handle, ®);
@@ -562,6 +583,7 @@
cs_error(link->handle, last_fn, last_ret);
failed:
serial_release((u_long)link);
+ link->state &= ~DEV_CONFIG_PENDING;
} /* serial_config */
@@ -569,7 +591,7 @@
After a card is removed, serial_release() will unregister the net
device, and release the PCMCIA configuration.
-
+
======================================================================*/
void serial_release(u_long arg)
@@ -577,7 +599,7 @@
dev_link_t *link = (dev_link_t *)arg;
serial_info_t *info = link->priv;
int i;
-
+
DEBUG(0, "serial_release(0x%p)\n", link);
for (i = 0; i < info->ndev; i++) {
@@ -590,7 +612,7 @@
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
}
-
+
link->state &= ~DEV_CONFIG;
} /* serial_release */
@@ -601,7 +623,7 @@
stuff to run after an event is received. A CARD_REMOVAL event
also sets some flags to discourage the serial drivers from
talking to the ports.
-
+
======================================================================*/
static int serial_event(event_t event, int priority,
@@ -609,9 +631,9 @@
{
dev_link_t *link = args->client_data;
serial_info_t *info = link->priv;
-
+
DEBUG(1, "serial_event(0x%06x)\n", event);
-
+
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
@@ -650,7 +672,7 @@
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "serial_cs: Card Services release "
"does not match!\n");
- return -1;
+ return -EINVAL;
}
register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
return 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)