2000-12-08 18:36:43

by Theodore Ts'o

[permalink] [raw]
Subject: Serial cardbus code.... for testing, please.....


I haven't been able to get PCMCIA working under Linux 2.4 with any kind
of serial devices (Cardbus or normal ISA), at least not reliably, on my
Vaio 505TX. I've tried both yenta_socket and i82365. It works about
one time in ten, but I've never figured out what causes it to work or
not work. When it doesn't work, any attempt to read the LSR and IIR
registers return *either* 0 or 0x80, and interrupts aren't delievered at
all. So I think it's some sort of ioport/irq setup problem that's not
related to the serial driver itself.....

(However, most but not all of the time, the ethernet PC cards work fine
--- although if I insert an cardbus ethernet card (using epic_cb) in, it
locks up the PCMCIA subsystem after it detects the card but before it
activates it. And after that, the ref count on the yenta_socket is set
to 1, and there's no way to reset the pcmcia subsystem except rebooting
the machine. Very frustating; I suspect there are several things going
wrong, and I'm trying to debug them all simultaneously. And yes, all
this works just flawlessly under Linux 2.2. For both 2.2 and 2.4, I'm
using the latest version of pcmcia-cs, 3.1.22.)

Anyway, all of this means I haven't been able to test this code. So if
someone with access to a cardbus serial card and a working 2.4
PCMCIA/Cardbus setup could test this new version of the serial driver
(patch versus 2.4.0test12-pre6), I'd appreciate it. It has both the
cardbus insert and removal code, so it *should* work, but as I said, I
haven't been able to find any way of testing it, and I've wasted enough
time that I'm giving up trying to get PCMCIA on my laptop working under
2.4 for now.....

- Ted

Patch generated: on Fri Dec 8 12:52:51 EST 2000 by [email protected]
against Linux version 2.4.0test12-pre6

===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 2000/12/08 04:17:14 1.1
+++ drivers/char/serial.c 2000/12/08 14:03:36
@@ -59,8 +59,8 @@
* int rs_init(void);
*/

-static char *serial_version = "5.02";
-static char *serial_revdate = "2000-08-09";
+static char *serial_version = "5.05";
+static char *serial_revdate = "2000-09-14";

/*
* Serial driver configuration section. Here are the various options:
@@ -325,7 +325,6 @@
#define NR_PCI_BOARDS 8

static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
-static int serial_pci_board_idx;

#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
@@ -564,7 +563,6 @@
{
struct tty_struct *tty = info->tty;
unsigned char ch;
- int ignored = 0;
struct async_icount *icount;

icount = &info->state->icount;
@@ -612,15 +610,8 @@
icount->overrun++;

/*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
+ * Mask off conditions which should be ignored.
*/
- if (*status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- goto ignore_char;
- }
*status &= info->read_status_mask;

#ifdef CONFIG_SERIAL_CONSOLE
@@ -639,19 +630,6 @@
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
- if (*status & UART_LSR_OE) {
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto ignore_char;
- }
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
@@ -664,9 +642,23 @@
break_pressed = 0;
}
#endif
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ if ((*status & info->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & UART_LSR_OE) &&
+ (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ }
ignore_char:
*status = serial_inp(info, UART_LSR);
} while (*status & UART_LSR_DR);
@@ -1310,7 +1302,7 @@
*/
if (!(info->flags & ASYNC_BUGGY_UART) &&
(serial_inp(info, UART_LSR) == 0xff)) {
- printk("LSR safety check engaged!\n");
+ printk("ttyS%d: LSR safety check engaged!\n", state->line);
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1554,7 +1546,10 @@
/* Arrange to enter sleep mode */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, 0);
serial_outp(info, UART_LCR, 0);
}
if (info->state->type == PORT_16750) {
@@ -2906,7 +2901,6 @@
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -3254,6 +3248,10 @@
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
+ info->hub6 = state->hub6;
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
info->quot = 0;
info->tty = 0;
}
@@ -3933,19 +3931,19 @@
if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
return;

-#ifdef MODULE
/*
* Register the serial board in the array if we need to
- * shutdown the board on a module unload.
+ * shutdown the board on a module unload or card removal
*/
if (DEACTIVATE_FUNC(dev) || board->init_fn) {
- if (serial_pci_board_idx >= NR_PCI_BOARDS)
+ for (k=0; k < NR_PCI_BOARDS; k++)
+ if (serial_pci_board[k].dev == 0)
+ break;
+ if (k >= NR_PCI_BOARDS)
return;
- serial_pci_board[serial_pci_board_idx].board = *board;
- serial_pci_board[serial_pci_board_idx].dev = dev;
- serial_pci_board_idx++;
+ serial_pci_board[k].board = *board;
+ serial_pci_board[k].dev = dev;
}
-#endif

base_baud = board->base_baud;
if (!base_baud)
@@ -3965,6 +3963,7 @@
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
+ rs_table[line].dev = dev;
}
}
#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
@@ -3978,7 +3977,7 @@
*/
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4045,7 +4044,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4077,7 +4076,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4101,7 +4100,7 @@
/* Added for EKF Intel i960 serial boards */
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_inteli960ni_fn(struct pci_dev *dev,
struct pci_board *board,
@@ -4162,7 +4161,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4577,6 +4576,10 @@
SPCI_FL_BASE0, 1, 520833,
64, 3, NULL, 0x300 },
#endif
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE3, 8, 115200,
+ 8 },
/* Generic serial board */
{ 0, 0,
0, 0,
@@ -4626,6 +4629,80 @@
return 1;
}

+static int __devinit serial_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct pci_board *board;
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ pci_get_subvendor(dev) != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ pci_get_subdevice(dev) != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+ return -ENODEV;
+
+ start_pci_pnp_board(dev, board);
+
+ return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+ int i;
+
+ /*
+ * Iterate through all of the ports finding those that belong
+ * to this PCI device.
+ */
+ for(i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].dev != dev)
+ continue;
+ unregister_serial(i);
+ rs_table[i].dev = 0;
+ }
+ /*
+ * Now execute any board-specific shutdown procedure
+ */
+ for (i=0; i < NR_PCI_BOARDS; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (serial_pci_board[i].dev != dev)
+ continue;
+ if (brd->board.init_fn)
+ (brd->board.init_fn)(brd->dev, &brd->board, 0);
+ if (DEACTIVATE_FUNC(brd->dev))
+ (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ serial_pci_board[i].dev = 0;
+ }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+ name: "serial",
+ probe: serial_init_one,
+ remove: serial_remove_one,
+ id_table: serial_pci_tbl,
+};


/*
@@ -4637,36 +4714,17 @@
*/
static void __init probe_serial_pci(void)
{
- struct pci_dev *dev = NULL;
- struct pci_board *board;
-
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
-
- pci_for_each_dev(dev) {
- for (board = pci_boards; board->vendor; board++) {
- if (board->vendor != (unsigned short) PCI_ANY_ID &&
- dev->vendor != board->vendor)
- continue;
- if (board->device != (unsigned short) PCI_ANY_ID &&
- dev->device != board->device)
- continue;
- if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- pci_get_subvendor(dev) != board->subvendor)
- continue;
- if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- pci_get_subdevice(dev) != board->subdevice)
- continue;
- break;
- }
-
- if (board->vendor == 0 && serial_pci_guess_board(dev, board))
- continue;
-
- start_pci_pnp_board(dev, board);
- }
-
+
+ /* Register call PCI serial devices. Null out
+ * the driver name upon failure, as a signal
+ * not to attempt to unregister the driver later
+ */
+ if (pci_module_init (&serial_pci_driver) != 0)
+ serial_pci_driver.name[0] = 0;
+
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
#endif
@@ -5099,7 +5157,7 @@
/*
* The serial driver boot-time initialization code!
*/
-static int __init rs_init(void)
+int __init rs_init(void)
{
int i;
struct serial_state * state;
@@ -5288,6 +5346,14 @@
(rs_table[i].iomem_base == req->iomem_base))
break;
}
+#ifdef __i386__
+ if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+#endif
if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
@@ -5411,12 +5477,13 @@
#endif
}
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- for (i=0; i < serial_pci_board_idx; i++) {
+ for (i=0; i < NR_PCI_BOARDS; i++) {
struct pci_board_inst *brd = &serial_pci_board[i];
-
+
+ if (serial_pci_board[i].dev == 0)
+ continue;
if (brd->board.init_fn)
(brd->board.init_fn)(brd->dev, &brd->board, 0);
-
if (DEACTIVATE_FUNC(brd->dev))
(DEACTIVATE_FUNC(brd->dev))(brd->dev);
}
@@ -5426,6 +5493,11 @@
tmp_buf = NULL;
free_page(pg);
}
+
+#ifdef ENABLE_SERIAL_PCI
+ if (serial_pci_driver.name[0])
+ pci_unregister_driver (&serial_pci_driver);
+#endif
}

module_init(rs_init);
===================================================================
RCS file: include/linux/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial.h
===================================================================
RCS file: include/linux/RCS/serial_reg.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial_reg.h
--- include/linux/serial_reg.h 2000/12/08 04:17:14 1.1
+++ include/linux/serial_reg.h 2000/12/08 04:17:35
@@ -156,8 +156,8 @@
* These register definitions are for the 16C950
*/
#define UART_ASR 0x01 /* Additional Status Register */
-#define UART_RFL 0x03 /* Transmitter FIFO level */
-#define UART_TFL 0x04 /* Receiver FIFO level */
+#define UART_RFL 0x03 /* Receiver FIFO level */
+#define UART_TFL 0x04 /* Transmitter FIFO level */
#define UART_ICR 0x05 /* Index Control Register */

/* The 16950 ICR registers */
===================================================================
RCS file: include/linux/RCS/serialP.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serialP.h
--- include/linux/serialP.h 2000/12/08 04:17:14 1.1
+++ include/linux/serialP.h 2000/12/08 04:17:35
@@ -52,6 +52,7 @@
struct termios callout_termios;
int io_type;
struct async_struct *info;
+ struct pci_dev *dev;
};

struct async_struct {
===================================================================
RCS file: include/asm-i386/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/serial.h
===================================================================
RCS file: include/linux/RCS/pci_ids.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci_ids.h
--- include/linux/pci_ids.h 2000/12/08 04:22:16 1.1
+++ include/linux/pci_ids.h 2000/12/08 04:23:12
@@ -1320,6 +1320,7 @@

#define PCI_VENDOR_ID_DCI 0x6666
#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002

#define PCI_VENDOR_ID_GENROCO 0x5555
#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003




2000-12-08 21:59:09

by Linus Torvalds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....


I didn't have time to do more than just quickly apply the patch and leave
in a hurry, but my Vaio certainly recognized the serial port on the combo
cardbus card I have with this patch. Everything looked fine - I got a
message saying it found a 16450 on ttyS4 when I plugged the card in.

Ted, I have the in-kernel pcmcia on both Toves VAIO 505VE, and on both the
VAIO picturebooks I have (Pentium/MMX 266 and crusoe-600), and I saw the
serial chip on the first try with your patch. I'm surprised you seem to
have so many problems. All the thin-and-light VAIO's have very similar
electronics (the big power-VAIO's are different, but you said you had a
505VX, right?).

Why are you using "epic_cb"? That's almost certainly not going to work
with the in-kernel cardbus driver. Use the standard epic100 PCI driver, it
should work directly. No need to mess with any modules, or anything like
that. You don't even need cardmgr - the device just shows up. Same thing
with the serial card - remove all traces of serial_cb.

(Of course, I use tulip instead of epic100, so maybe there's an epic
driver bug, but it's definitely hotplug-aware).

Linus

2000-12-08 22:04:39

by David Hinds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

On Fri, Dec 08, 2000 at 01:27:51PM -0800, Linus Torvalds wrote:
>
> (Of course, I use tulip instead of epic100, so maybe there's an epic
> driver bug, but it's definitely hotplug-aware).

There could be a problem in the epic driver; I've never had a card
that uses this driver and have only limited user feedback. Some
people say it works, others not... but I have not even been able to
tell if the problems are actually in the epic driver or elsewhere.

-- Dave

2000-12-09 06:12:18

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Date: Fri, 8 Dec 2000 13:27:51 -0800 (PST)
From: Linus Torvalds <[email protected]>

I didn't have time to do more than just quickly apply the patch and leave
in a hurry, but my Vaio certainly recognized the serial port on the combo
cardbus card I have with this patch. Everything looked fine - I got a
message saying it found a 16450 on ttyS4 when I plugged the card in.

When you have a chance, can you check and make sure that you actually
can talk to the modem? That will make me feel much better.....

There was is usual with these sorts of things, multiple problems I was
dealing with. The first was that I was trying to use cardmgr, and my
pcmcia config file was still trying to load epic_cb. Oops. David, you
might want to mention of this caveat in the README-2.4 file in the
pcmcia-cs package.

Once I fixed the /etc/pcmcia/config file, was able to start up the
epic100 driver with cardmgr. I was also able to (with cardmgr not
running) load the epic100 module, and lo and behold it worked. OK, one
problem down. I also demonstrated to my self that I could manually load
the serial and epic module, and yenta/ds code would call the appropriate
device driver's registration routine. So far, so good.

But then I ran into the second problem, which seems to afflict all
PCMCIA/CARDBUS serial devices which I've tried. That problem is the one
which I alluded to in an eariler messages; it looks like some or all of
the I/O port window for the serial device isn't getting set up properly.
Reads and writes to the UART registers (or at least where the UART
registers allegedly should be, according to the pcmcia/cardbus
subsystem) are returning garbage.

For example, with the Jack of Spades Ositech Cardbus card, a write to
the Interrupt Enable Register of 0x0f is returning 0x08, when it should
return the value that was originally written, 0x0f. This causes the
card to fail the serial UART detection code.

In the case of the MegaHertz modem PCMCIA card and the Linksys combo
PCMCIA card, card registers manage to survive the serial driver's UART
test (although as a 8250 or 16450, instead of the 16550A that's really
in those cards, meaning it failed the more advanced loopback and FIFO
tests). However, when you try to actually *use* the Line Status
Register always returns 0, while the IIR register returns 0 --- which
should never happen; if LSR returns 0, then there can't be any
interrupts pending, so IIR should be 0x1. Other times both LSR and IIR
when queried return 0x80, where 0x80 is an a always-zero bit on the LSR
register. In both cases it causes the interrupt service routine to
loop, although fortunately a safety I had coded into the driver to
prevent infinite loops breaks it out after 50 loops.

This makes me suspicious that the I/O windows for the serial drivers
aren't getting set correctly. And whatever the problem, it's affecting
both PCMCIA devices (which still use serial_cs), as well as cardbus
drivers, which is just using serial.o. And this is why I asked you
whether or not you can actually talk to the modem --- I've seen cases
where the PCMCIA code finds the modem, and the UART even passes some of
the preliminary tests, but if you try send "AT" to the modem, you'll see
that it hangs because it doesn't get any transmit interrupts, and even
when the watchdog timer forces an entry to the serial interrupt driver,
the UART registers yield nonsense values.

If I turn off CONFIG_PCMCIA and recompile the kernel and the pcmcia
driver, then the serial driver works fine and fines the ports without
any problems. And even with CONFIG_PCMCIA enabled, the serial driver
has no problem talking to the built-in modem in my Vaio 505TX (that's
one advantage of having an old Vaio -- a real modem, not a winmode
requiring the use of a GPL-violating driver. :-)

Anyway, if anyone has any suggestions on how to debug this, let me
know. I'll be happy to run whatever debugging tests are necessary to
get to the bottom of this.

- Ted

2000-12-09 08:13:09

by Linus Torvalds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....



On Sat, 9 Dec 2000, Theodore Y. Ts'o wrote:
>
> I didn't have time to do more than just quickly apply the patch and leave
> in a hurry, but my Vaio certainly recognized the serial port on the combo
> cardbus card I have with this patch. Everything looked fine - I got a
> message saying it found a 16450 on ttyS4 when I plugged the card in.
>
> When you have a chance, can you check and make sure that you actually
> can talk to the modem? That will make me feel much better.....

Done.

It works perfectly fine for me, with the following caveat:

It crashes hard if I remove the card while the modem is in use, though (ie
insert card, point minicom at it, sit at the minicom window while removing
the card).

This is a problem that many drivers have: when the card is removed, the
driver sees an interrupt (which happens to be the CardBus card removal
interrupt, but the serial driver doesn't know that, and the way cardbus
interrupts work it's always shared with the driver).

So the serial driver reads the modem status byte, which is all ones, and
decides that there is a ton of work to do. It then loops forever, because
the status byte bits will obviously continue to be all ones.

Note how the "rs_interrupt()" routine _tries_ to avoid this by having a
pass counter value, but that logic never triggers because we will loop
forever in receive_chars(), so the rs_interrupt() counter never even gets
to increment.

> Once I fixed the /etc/pcmcia/config file, was able to start up the
> epic100 driver with cardmgr. I was also able to (with cardmgr not
> running) load the epic100 module, and lo and behold it worked.

You should also just test having it compiled in - I know some people love
modules, but there is nothing quite as liberating as just having a kernel
that finds the devices it needs and doesn't need anything else.

> But then I ran into the second problem, which seems to afflict all
> PCMCIA/CARDBUS serial devices which I've tried. That problem is the one
> which I alluded to in an eariler messages; it looks like some or all of
> the I/O port window for the serial device isn't getting set up properly.

I'm sitting here with a minicom session, talking to the modem. Maybe you
have a device that is not a standard UART?

> This makes me suspicious that the I/O windows for the serial drivers
> aren't getting set correctly. And whatever the problem, it's affecting
> both PCMCIA devices (which still use serial_cs), as well as cardbus
> drivers, which is just using serial.o. And this is why I asked you
> whether or not you can actually talk to the modem.

I have the serial.c driver compiled into the kernel, and apart from the
glitch I can _definitely_ talk to the modem just fine.

Linus

2000-12-09 08:19:10

by Linus Torvalds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....



Oh, I forgot to mention: I use a slight modification to your patch: you
left some functions as "__init/__initdata" functions/data even though they
are should definitely be __devinit/__devinitdata for all the hotplug
stuff. So the thing that works for me has had a global search-and-replace
to replace all "__init" with "__devinit".

If you're testing with just modules, you shouldn't see this effect,
though (otherwise you might get strange oopsen and/or corrupted initdata,
of course).

Linus

2000-12-09 15:17:12

by Jens Taprogge

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

On Sat, Dec 09, 2000 at 12:41:24AM -0500, Theodore Y. Ts'o wrote:
> In the case of the MegaHertz modem PCMCIA card and the Linksys combo
> PCMCIA card, card registers manage to survive the serial driver's UART
> test (although as a 8250 or 16450, instead of the 16550A that's really
> in those cards, meaning it failed the more advanced loopback and FIFO
> tests).

I have a Megaherz card as well. It has been working fine ever since
Linus fixed some issues with the ToPIC97 Cardbus controller. It reports
a 16550A on my machine.

I have been using the card to connect to my ISP day-in and day-out with
no problems.


If you want me to run some specific test on this box let me know.

Jens

PS: I have everything compiled into the kernel.

--
Jens Taprogge

2000-12-09 16:45:11

by Jeff Garzik

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Linus Torvalds wrote:
> On Sat, 9 Dec 2000, Theodore Y. Ts'o wrote:
> > I didn't have time to do more than just quickly apply the patch and leave
> > in a hurry, but my Vaio certainly recognized the serial port on the combo
> > cardbus card I have with this patch. Everything looked fine - I got a
> > message saying it found a 16450 on ttyS4 when I plugged the card in.
> >
> > When you have a chance, can you check and make sure that you actually
> > can talk to the modem? That will make me feel much better.....
>
> Done.
>
> It works perfectly fine for me, with the following caveat:
>
> It crashes hard if I remove the card while the modem is in use, though (ie
> insert card, point minicom at it, sit at the minicom window while removing
> the card).
>
> This is a problem that many drivers have: when the card is removed, the
> driver sees an interrupt (which happens to be the CardBus card removal
> interrupt, but the serial driver doesn't know that, and the way cardbus
> interrupts work it's always shared with the driver).
>
> So the serial driver reads the modem status byte, which is all ones, and
> decides that there is a ton of work to do. It then loops forever, because
> the status byte bits will obviously continue to be all ones.
>
> Note how the "rs_interrupt()" routine _tries_ to avoid this by having a
> pass counter value, but that logic never triggers because we will loop
> forever in receive_chars(), so the rs_interrupt() counter never even gets
> to increment.

Other places in serial.c check for 0xff, which implies we can and should
do the same in the interrupt handler...

> /*
> * If we read 0xff from the LSR, there is no UART here.
> */
> if (serial_in(info, UART_LSR) == 0xff)
> return -1;

I'm starting to think this Ositech Jack of Spades is unusual in some
way, since your (Linus) BestData card and other serial CardBus cards
sound like they work.

Jeff


--
Jeff Garzik |
Building 1024 | These are not the J's you're lookin' for.
MandrakeSoft | It's an old Jedi mind trick.

2000-12-09 18:44:56

by Linus Torvalds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....



On Sat, 9 Dec 2000, Jens Taprogge wrote:
>
> I have a Megaherz card as well. It has been working fine ever since
> Linus fixed some issues with the ToPIC97 Cardbus controller. It reports
> a 16550A on my machine.

I checked my VAIO's, and they all have a Ricoh cardbus bridge.

Ted claimed he had a TI1311 or something, I think. So his VAIO is
definitely different from the ones I have. That may be enough of a
difference.

(But I know I've tried TI bridges too, and have had multiple success
reports with them. They are not uncommon. They _do_ tend to need more
initialization than some of the other bridges, and maybe that's the
difference. Ted, can you send me the lspci -vvxxx output with the full
config space setup?)

Linus

2000-12-10 07:38:35

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Date: Fri, 8 Dec 2000 23:41:54 -0800 (PST)
From: Linus Torvalds <[email protected]>

This is a problem that many drivers have: when the card is removed, the
driver sees an interrupt (which happens to be the CardBus card removal
interrupt, but the serial driver doesn't know that, and the way cardbus
interrupts work it's always shared with the driver).

So the serial driver reads the modem status byte, which is all ones, and
decides that there is a ton of work to do. It then loops forever, because
the status byte bits will obviously continue to be all ones.

Ok, thanks. I'll work up a patch to fix this problem.

You should also just test having it compiled in - I know some people love
modules, but there is nothing quite as liberating as just having a kernel
that finds the devices it needs and doesn't need anything else.

Interesting. Yup, the serial driver works with it compiled in.
However, the epic driver fails after I eject and remove the card, and
then re-insert it (it hangs on the re-insertion). It looks like a
deadlock; after it hangs, "ifconfig" also hangs, presumably waiting on
the same lock (ps alx reports it's waiting on "down").

> But then I ran into the second problem, which seems to afflict all
> PCMCIA/CARDBUS serial devices which I've tried. That problem is the one
> which I alluded to in an eariler messages; it looks like some or all of
> the I/O port window for the serial device isn't getting set up properly.

I'm sitting here with a minicom session, talking to the modem. Maybe you
have a device that is not a standard UART?

Nope, it fails in this way for three separate PC Cards, but they work
just fine under Linux 2.2 w/ pcmcia-cs, and Linux 2.4 w/ pcmcia-cs, and
I know they are standard UART's.

However, they all fail in the same way if I use the built-in pcmcia
drivers in Linux 2.4 if things are compiled as modules. The cardbus
(Jack of Spades Ositech) works if the serial module is compiled into the
kernel (but the network half fails upon reinsertion). I haven't had a
chance to check the PCMCIA cards with the drivers built-in (PCMCIA
requires cardmgr, right? Will cardmgr work if the relevant drivers are
compiled in, as opposed to compiled as module?).

Curious..... well, I'm about to go on the road again for a week (IETF
meeting in San Diego), so I won't have as much chance to work on this (I
need to have my laptop working reliably, which means I'll have to back
it out to Linux 2.2.18pre24 for the most part).

In any case, I think I know how to fix the serial driver to not loop in
receive_chars(). If I get this working, do you want to take a serial
driver update now or post 2.4.0? I have a number of fixes queued up
that I didn't consider critical, so I haven't fed them to you. One of
them is from an SGI engineer who's been harassing me about getting one
of the changes in, since he's apparently on deadline and he needs a
change for one of his SGI MIPS boxes. I don't understand why he can't
just use a kernel with a patch, but whatever...

- Ted

2000-12-10 08:26:13

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Date: Sat, 9 Dec 2000 10:13:50 -0800 (PST)
From: Linus Torvalds <[email protected]>

I checked my VAIO's, and they all have a Ricoh cardbus bridge.

Ted claimed he had a TI1311 or something, I think. So his VAIO is
definitely different from the ones I have. That may be enough of a
difference.

Err, no. At least, I don't think I ever said that. It has the Ricoh
cardbus bridge.

(But I know I've tried TI bridges too, and have had multiple success
reports with them. They are not uncommon. They _do_ tend to need more
initialization than some of the other bridges, and maybe that's the
difference. Ted, can you send me the lspci -vvxxx output with the full
config space setup?)

Here you go. Here's the lspci -vvxxx output under Linux 2.2.18 with
pcmcia-cs and the CardBus Ositech Jack of Spades inserted and running.

- Ted


00:00.0 Host bridge: Intel Corporation 430TX - 82439TX MTXC (rev 01)
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort+ >SERR- <PERR-
Latency: 32
00: 86 80 00 71 06 00 00 22 01 00 00 06 00 20 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80
50: 08 00 81 34 1a 00 50 01 2b 50 55 05 00 00 55 55
60: 08 10 20 20 20 20 00 83 70 03 00 00 00 00 00 00
70: 20 00 0a 00 0e 00 00 00 23 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 20 0f 00 00 00 20 00 00

00:07.0 Bridge: Intel Corporation 82371AB PIIX4 ISA (rev 02)
Control: I/O+ Mem+ BusMaster+ SpecCycle+ MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 0
00: 86 80 10 71 0f 00 80 02 02 00 80 06 00 00 80 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 4d 00 b3 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 09 09 09 09 90 00 00 00 00 f2 80 00 00 00 00 00
70: 00 00 00 00 00 00 0c 0c 00 00 00 00 00 00 00 00
80: 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 02 11 01 f1 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 25 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 30 0f 00 00 00 00 00 00

00:07.1 IDE interface: Intel Corporation 82371AB PIIX4 IDE (rev 01) (prog-if 80 [Master])
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 64
Region 4: I/O ports at fcd0
00: 86 80 11 71 05 00 80 02 01 80 01 01 00 40 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: d1 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 07 a3 00 80 00 00 00 00 01 00 02 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 30 0f 00 00 00 00 00 00

00:07.2 USB Controller: Intel Corporation 82371AB PIIX4 USB (rev 01) (prog-if 00 [UHCI])
Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin D routed to IRQ 9
Region 4: I/O ports at fce0
00: 86 80 12 71 01 00 80 02 01 00 03 0c 00 40 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: e1 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 09 04 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 30 0f 00 00 00 00 00 00

00:07.3 Bridge: Intel Corporation 82371AB PIIX4 ACPI (rev 02)
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
00: 86 80 13 71 03 00 80 02 02 00 80 06 00 00 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 01 80 00 00 07 cf 3f 1f d4 17 00 00 00 00 00 00
50: 0a 50 1d 00 71 6d 7d 0f 36 80 00 02 0d 00 00 e2
60: 40 80 f3 62 f8 02 e7 f8 40 01 17 00 00 00 00 00
70: 00 08 17 00 00 00 00 00 00 00 00 00 70 03 11 00
80: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 81 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 30 0f 00 00 00 00 00 00

00:08.0 VGA compatible controller: Neomagic Corporation NM2160 [MagicGraph 128XD] (rev 01) (prog-if 00 [VGA])
Subsystem: Sony Corporation MagicGraph 128XD
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 9
Region 0: Memory at fd000000 (32-bit, prefetchable)
Region 1: Memory at fea00000 (32-bit, non-prefetchable)
Region 2: Memory at fed00000 (32-bit, non-prefetchable)
00: c8 10 04 00 03 00 80 02 01 00 00 03 00 80 00 00
10: 08 00 00 fd 00 00 a0 fe 00 00 d0 fe 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 4d 10 2f 80
30: 00 00 00 00 00 00 00 00 00 00 00 00 09 01 10 ff
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00:09.0 FireWire (IEEE 1394): Sony Corporation CXD1947Q i.LINK Controller (rev 01) (prog-if 00 [Generic])
Subsystem: Sony Corporation CXD1947Q i.LINK Controller
Control: I/O- Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 9
Region 0: Memory at fecffc00 (32-bit, non-prefetchable)
Capabilities: [dc] Power Management version 1
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
00: 4d 10 09 80 02 00 10 02 01 00 00 0c 08 40 00 00
10: 00 fc cf fe 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 4d 10 09 80
30: 00 00 00 00 dc 00 00 00 00 00 00 00 09 01 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00:0a.0 CardBus bridge: Ricoh Co Ltd RL5c475
Subsystem: Sony Corporation: Unknown device 8030
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 168
Interrupt: pin A routed to IRQ 9
Region 0: Memory at <ignored> (32-bit, non-prefetchable)
Bus: primary=00, secondary=20, subordinate=22, sec-latency=176
Memory window 0: 60020000-60041000
I/O window 0: 00001000-000011ff
I/O window 1: 00000000-00000003
BridgeCtl: Parity- SERR- ISA- VGA- MAbort- >Reset- 16bInt- PostWrite+
16-bit legacy interface ports at 0001
00: 80 11 75 04 07 00 10 02 00 00 07 06 00 a8 02 00
10: 00 00 00 68 dc 00 00 22 00 20 22 b0 00 00 02 60
20: 00 10 04 60 00 00 00 00 00 00 00 00 00 10 00 00
30: fc 11 00 00 00 00 00 00 00 00 00 00 09 01 00 04
40: 4d 10 30 80 01 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 01 00 00 00 00 03 00 00 63 04 63 04 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 19 fe
e0: 00 41 c0 24 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

20:00.0 Ethernet controller: Standard Microsystems Corp [SMC] LANEPIC (rev 01)
Subsystem: Ositech Communications Inc LANEPIC Cardbus Fast Ethernet Adapter
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 64 (2000ns min, 7000ns max)
Interrupt: pin A routed to IRQ 9
Region 0: I/O ports at 1100
Region 1: Memory at 60041000 (32-bit, non-prefetchable)
Expansion ROM at 60030000 [disabled]
00: b8 10 06 00 07 00 80 00 01 00 00 02 00 40 80 00
10: 01 11 00 00 00 10 04 60 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 07 02 00 00 a2 13 06 80
30: 01 00 03 60 00 00 00 00 00 00 00 00 09 01 08 1c
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

20:00.1 Serial controller: Standard Microsystems Corp [SMC] LANEPIC (rev 01) (prog-if 02 [16550])
Subsystem: Ositech Communications Inc: Unknown device 8007
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 9
Region 0: I/O ports at 1000
Region 1: Memory at 60040000 (32-bit, non-prefetchable)
Expansion ROM at 60020000 [disabled]
00: b8 10 06 00 03 00 80 00 01 02 00 07 00 00 80 00
10: 01 10 00 00 00 00 04 60 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 07 03 00 00 a2 13 07 80
30: 01 00 02 60 00 00 00 00 00 00 00 00 09 01 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

2000-12-10 08:52:57

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Date: Sat, 09 Dec 2000 11:13:59 -0500
From: Jeff Garzik <[email protected]>

> Note how the "rs_interrupt()" routine _tries_ to avoid this by having a
> pass counter value, but that logic never triggers because we will loop
> forever in receive_chars(), so the rs_interrupt() counter never even gets
> to increment.

Other places in serial.c check for 0xff, which implies we can and should
do the same in the interrupt handler...

No, other places in the serial driver check for 0xff *after* setting
various registers and clearing various flags. Those various
initializations are critical before you can simply do a "bail if LSR ==
0xff" check.

It's possible (not very likely, but possible) for LSR to go into
christmas tree mode where all of the flags are set in normal operation.
So for the interrupt driver, we're going to have to do some kind of loop
based thing --- if interrupt driver receives 0xff more than some number
of times, bail.

I'm starting to think this Ositech Jack of Spades is unusual in some
way, since your (Linus) BestData card and other serial CardBus cards
sound like they work.

Well, I'm able to make the Jack of Spades work if everything is compiled
in --- although the networking side of the card seems to deadlock the
kernel if I eject and re-insert the card --- this problem doesn't show
up if I compile the epic100 driver as a module, only when it is compiled
into the kernel. However, if the 2.4 pcmcia/cardbus drivers are
compiled as modules, *all* serial cards which I've tried, CardBus and
PCMCIA, fail in mostly the same way.

If I disable the kernel PCMCIA drivers, and use the pcmcia-cs drivers
with the 2.4 kernel, they all work fine. If I use the pcmcia-cs drivers
with the 2.2 kernel, it also works fine. So starting to look like it's
a very specific set of circumstances where it doesn't work. It just
happened to be the one which I tried first, since I do like kernel
modules since it's a lot easier to debug things that way....

- Ted

2000-12-10 16:50:11

by Linus Torvalds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....



On Sun, 10 Dec 2000, Theodore Y. Ts'o wrote:
>
> You should also just test having it compiled in - I know some people love
> modules, but there is nothing quite as liberating as just having a kernel
> that finds the devices it needs and doesn't need anything else.
>
> Interesting. Yup, the serial driver works with it compiled in.

Ho humm.. Why wouldn't it work as a module? Strange.

Are you sure cardmgr inserts the right module? If cardmgr tries to insert
serial_cb, and you have warring drivers, you'll break.

Oh, serial_cb shouldn't work anyway, I think.

> However, the epic driver fails after I eject and remove the card, and
> then re-insert it (it hangs on the re-insertion). It looks like a
> deadlock; after it hangs, "ifconfig" also hangs, presumably waiting on
> the same lock (ps alx reports it's waiting on "down").

This is almost certainly the silly hotplug issue that we have - there's a
problem with execin'g /sbin/hotplug and the semaphore that protects the
device state. That will be fixed in the next patch..

> In any case, I think I know how to fix the serial driver to not loop in
> receive_chars(). If I get this working, do you want to take a serial
> driver update now or post 2.4.0?

Pls do it now, this is only going to clean it up (I bet we'll also be able
to remove some of the serial.c PCI device lists, because many of them
probably work with the general "is this a serial device?" test and do not
need to be explicitly listed).

Linus

2000-12-10 16:55:11

by Jeff Garzik

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

Linus Torvalds wrote:
> Oh, serial_cb shouldn't work anyway, I think.

As soon as the serial.c hotplug patch appear, you'll be receiving a
patch that eliminates serial_cb.

Jeff


--
Jeff Garzik |
Building 1024 | These are not the J's you're lookin' for.
MandrakeSoft | It's an old Jedi mind trick.

2000-12-10 16:57:51

by Jeff Garzik

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

"Theodore Y. Ts'o" wrote:
>
> Date: Sat, 09 Dec 2000 11:13:59 -0500
> From: Jeff Garzik <[email protected]>
>
> > Note how the "rs_interrupt()" routine _tries_ to avoid this by having a
> > pass counter value, but that logic never triggers because we will loop
> > forever in receive_chars(), so the rs_interrupt() counter never even gets
> > to increment.
>
> Other places in serial.c check for 0xff, which implies we can and should
> do the same in the interrupt handler...
>
> No, other places in the serial driver check for 0xff *after* setting
> various registers and clearing various flags. Those various
> initializations are critical before you can simply do a "bail if LSR ==
> 0xff" check.

Looking through the code, isn't this setup complete before any
interrupts get delivered to rs_interrupt?


> It's possible (not very likely, but possible) for LSR to go into
> christmas tree mode where all of the flags are set in normal operation.
> So for the interrupt driver, we're going to have to do some kind of loop
> based thing --- if interrupt driver receives 0xff more than some number
> of times, bail.

oh well :)

Jeff


--
Jeff Garzik |
Building 1024 | These are not the J's you're lookin' for.
MandrakeSoft | It's an old Jedi mind trick.

2000-12-10 17:04:42

by Jeff Garzik

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

"Theodore Y. Ts'o" wrote:
> In any case, I think I know how to fix the serial driver to not loop in
> receive_chars(). If I get this working, do you want to take a serial
> driver update now or post 2.4.0? I have a number of fixes queued up
> that I didn't consider critical, so I haven't fed them to you. One of
> them is from an SGI engineer who's been harassing me about getting one
> of the changes in, since he's apparently on deadline and he needs a
> change for one of his SGI MIPS boxes. I don't understand why he can't
> just use a kernel with a patch, but whatever...

FWIW I don't think you should sit on fixes until post 2.4.0... and I
would like to get CardBus serial working because it's broken in the
current tree...

Jeff


--
Jeff Garzik |
Building 1024 | These are not the J's you're lookin' for.
MandrakeSoft | It's an old Jedi mind trick.

2000-12-10 19:02:39

by Alan

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

> FWIW I don't think you should sit on fixes until post 2.4.0... and I
> would like to get CardBus serial working because it's broken in the
> current tree...

I would agree. Right now serial cardbus is broken, line discipline race patches
dont appear to have been applied and these are serious enough to definitely
want fixing, either with your patch or someone else doing the work instead.

2000-12-11 03:28:36

by Chris Wedgwood

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

(cc' list trimmed)

On Sat, Dec 09, 2000 at 10:13:50AM -0800, Linus Torvalds wrote:

Ted claimed he had a TI1311 or something, I think. So his VAIO is
definitely different from the ones I have. That may be enough of a
difference.

My Dell has a TI-1121 or something -- and it works perfectly and has
done for quite some time (both legacy and CardBus).

Every now and then I get some bizarre IRQ routing funny which a
reboot fixes, I just assumed that was because of recent PCI irq
routing issues...

Ted, if it's useful, I can provide remote access to his laptop (it
has builtin ethernet)...



--cw

2000-12-11 21:44:17

by David Hinds

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....

On Sat, Dec 09, 2000 at 12:41:24AM -0500, Theodore Y. Ts'o wrote:
>
> There was is usual with these sorts of things, multiple problems I was
> dealing with. The first was that I was trying to use cardmgr, and my
> pcmcia config file was still trying to load epic_cb. Oops. David, you
> might want to mention of this caveat in the README-2.4 file in the
> pcmcia-cs package.

I'm aware of the problem but I'm not actually sure what to present as
the appropriate solution yet; in the new scheme, cardmgr should just
ignore these cards and not load any module at all (as /sbin/hotplug
should do that). But I haven't decided how cardmgr will deduce that.

By the way, in my hands, PCMCIA serial cards do work ok with the 2.4
PCMCIA modules as of test12-pre7. So I'm not sure what's going on in
Ted's situation, if the non-kernel PCMCIA is working: there should
not be much different for 16-bit cards. I do seem to have some new
problems with Cardbus cards that I wasn't having with earlier 2.4
releases but I haven't made any attempt to figure that out yet.

-- Dave

2000-12-13 16:54:24

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....


OK, so I'm currently at the road (San Diego IETF meeting) so I can't
really test this very well; when your compile engine is your Vaio
laptop, it's really slow and painful to do test builds and test booting
kernels.

But I know some people are eager to test it, and would rather have
something potentially flaky earlier rather waiting for something more
tested later, so here it is. Please note, the only testing that I have
done to date is Linus's famous "it builds, ship it" regression test
suite. So if you're not willing to test a patch which might crash your
machine, come back in a day or two after I and others have had a chance
to do some testing. (But hey, Linus has released kernels to the entire
world without even doing a test compile, so why can't I do it with
something as simple as a serial driver? :-)


This version of the patch has a couple of new features over past ones,
including sanity check code which should prevent receive_chars() from
getting stuck in a tight loop when the serial card is ejected while a
port is active. It also has functions correctly labelled with __devinit
and __devexit, and will check to see if an entry in the serial pci table
isn't necessay, and ask the user to report the information in that case.
(mailing list to be active within 24 hours; until then, send the
information to me instead of the e-mail adddress listed in the patch).

The patch also has changes which Kanoj from SGI has been bugging me
about constantly because he needs some changes to support his big-iron
MIPS box project which he's working on. I had sat on them because
clearly I have a different understanding of "code freeze; critical bugs
only" than other folks on the L-K mailing list, but they're included
here now. Linus, I can back out some or all of these changes when I
feed the patches to use for merging with 2.4; just let me know what you
want and don't want.

- Ted


Release notes
=============

* Add support for PCI hot plugging.
- Functions should be correctly labeled with __devinit
and __devexit now.
- Set a safety check to prevent infinite loops in
receive_chars
- Added support for removing PCI cards

* Added code to test to see if an entry in the serial driver's
PCI table is redundant (i.e., could have been deduced
using our hueristics) and asks the user to report the
information if so.

* Add support for flow controled serial console. (Feature
desperately requested to be merged into 2.4.0 by Kanoj
Sarcar <[email protected]> for his big-iron MIPS box)

* Add new interface, early_serial_setup() which allows
architecture specific code to set up serial consoles
for those platforms where the port and bus information
must be dynamically determined by the boot.
Early_serial_setup() must be called before rs_init().
(Feature desperately requested to be merged into 2.4.0
by Kanoj Sarcar <[email protected]> for his big-iron MIPS
box)


* Fixed fencepost bug which could cause the serial driver to
overrun the flip buffer by a single character if the
UART reports an overrun when the flip buffer is nearly
full. (not really a critical problem because we have
slop space in the flip buffer for this purpose, but it
really would be good to have this fixed.)

* Add support for the DCI PCCOM8 8-port serial board


Patch generated: on Wed Dec 13 10:39:41 EST 2000 by tytso@trampoline
against Linux version 2.4.0

===================================================================
RCS file: Documentation/RCS/serial-console.txt,v
retrieving revision 1.1
diff -u -r1.1 Documentation/serial-console.txt
--- Documentation/serial-console.txt 2000/12/13 15:12:57 1.1
+++ Documentation/serial-console.txt 2000/12/13 15:13:09
@@ -20,9 +20,11 @@

options: depend on the driver. For the serial port this
defines the baudrate/parity/bits of the port,
- in the format BBBBPN, where BBBB is the speed,
- P is parity (n/o/e), and N is bits. Default is
- 9600n8. The maximum baudrate is 115200.
+ in the format BBBBPNF, where BBBB is the speed,
+ P is parity (n/o/e), N is bits, and F is
+ flow control (n/r for none/rtscts). P, N,
+ and F are optional. The default setting is
+ 9600n8n. The maximum baudrate is 115200.

You can specify multiple console= options on the kernel command line.
Output will appear on all of them. The last device will be used when
===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 2000/12/13 01:08:20 1.1
+++ drivers/char/serial.c 2000/12/13 15:13:35
@@ -54,13 +54,16 @@
* 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
* Arnaldo Carvalho de Melo <[email protected]>
*
+ * 10/00: add in optional software flow control for serial console.
+ * Kanoj Sarcar <[email protected]> (Modified by Theodore Ts'o)
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/

-static char *serial_version = "5.02";
-static char *serial_revdate = "2000-08-09";
+static char *serial_version = "5.05";
+static char *serial_revdate = "2000-12-13";

/*
* Serial driver configuration section. Here are the various options:
@@ -325,7 +328,6 @@
#define NR_PCI_BOARDS 8

static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
-static int serial_pci_board_idx;

#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
@@ -564,8 +566,8 @@
{
struct tty_struct *tty = info->tty;
unsigned char ch;
- int ignored = 0;
struct async_icount *icount;
+ int max_count = 256;

icount = &info->state->icount;
do {
@@ -612,15 +614,8 @@
icount->overrun++;

/*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
+ * Mask off conditions which should be ignored.
*/
- if (*status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- goto ignore_char;
- }
*status &= info->read_status_mask;

#ifdef CONFIG_SERIAL_CONSOLE
@@ -639,19 +634,6 @@
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
- if (*status & UART_LSR_OE) {
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto ignore_char;
- }
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
@@ -664,16 +646,30 @@
break_pressed = 0;
}
#endif
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ if ((*status & info->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & UART_LSR_OE) &&
+ (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ }
ignore_char:
*status = serial_inp(info, UART_LSR);
- } while (*status & UART_LSR_DR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
tty_flip_buffer_push(tty);
#else
- queue_task(&tty->flip.tqueue, &tq_timer);
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
#endif
}

@@ -827,6 +823,9 @@
end_mark = info;
goto next;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
end_mark = 0;

info->last_active = jiffies;
@@ -910,6 +909,9 @@
#endif
break;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
info->last_active = jiffies;
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -1310,7 +1312,7 @@
*/
if (!(info->flags & ASYNC_BUGGY_UART) &&
(serial_inp(info, UART_LSR) == 0xff)) {
- printk("LSR safety check engaged!\n");
+ printk("ttyS%d: LSR safety check engaged!\n", state->line);
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1554,7 +1556,10 @@
/* Arrange to enter sleep mode */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, 0);
serial_outp(info, UART_LCR, 0);
}
if (info->state->type == PORT_16750) {
@@ -2906,7 +2911,6 @@
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -3254,6 +3258,10 @@
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
+ info->hub6 = state->hub6;
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
info->quot = 0;
info->tty = 0;
}
@@ -3809,7 +3817,7 @@

#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)

-static void __init printk_pnp_dev_id(unsigned short vendor,
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
unsigned short device)
{
printk("%c%c%c%x%x%x%x",
@@ -3901,7 +3909,7 @@
/*
* Common enabler code shared by both PCI and ISAPNP probes
*/
-static void __init start_pci_pnp_board(struct pci_dev *dev,
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
struct pci_board *board)
{
int k, line;
@@ -3933,19 +3941,19 @@
if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
return;

-#ifdef MODULE
/*
* Register the serial board in the array if we need to
- * shutdown the board on a module unload.
+ * shutdown the board on a module unload or card removal
*/
if (DEACTIVATE_FUNC(dev) || board->init_fn) {
- if (serial_pci_board_idx >= NR_PCI_BOARDS)
+ for (k=0; k < NR_PCI_BOARDS; k++)
+ if (serial_pci_board[k].dev == 0)
+ break;
+ if (k >= NR_PCI_BOARDS)
return;
- serial_pci_board[serial_pci_board_idx].board = *board;
- serial_pci_board[serial_pci_board_idx].dev = dev;
- serial_pci_board_idx++;
+ serial_pci_board[k].board = *board;
+ serial_pci_board[k].dev = dev;
}
-#endif

base_baud = board->base_baud;
if (!base_baud)
@@ -3965,6 +3973,7 @@
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
+ rs_table[line].dev = dev;
}
}
#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
@@ -3978,7 +3987,7 @@
*/
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4045,7 +4054,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4077,7 +4086,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4101,7 +4110,7 @@
/* Added for EKF Intel i960 serial boards */
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_inteli960ni_fn(struct pci_dev *dev,
struct pci_board *board,
@@ -4162,7 +4171,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4577,6 +4586,10 @@
SPCI_FL_BASE0, 1, 520833,
64, 3, NULL, 0x300 },
#endif
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE3, 8, 115200,
+ 8 },
/* Generic serial board */
{ 0, 0,
0, 0,
@@ -4626,6 +4639,90 @@
return 1;
}

+static int __devinit serial_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct pci_board *board, tmp;
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ pci_get_subvendor(dev) != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ pci_get_subdevice(dev) != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+ return -ENODEV;
+ else if (serial_pci_guess_board(dev, &tmp) == 0) {
+ printk(KERN_INFO "Redundant entry in serial pci_table. "
+ "Please send the output of\n"
+ "lspci -vv, this message (%d,%d,%d,%d)\n"
+ "and the manufacturer and name of "
+ "serial board or modem board\n"
+ "to [email protected].\n",
+ dev->vendor, dev->device,
+ pci_get_subvendor(dev), pci_get_subdevice(dev));
+ }
+
+ start_pci_pnp_board(dev, board);
+
+ return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+ int i;
+
+ /*
+ * Iterate through all of the ports finding those that belong
+ * to this PCI device.
+ */
+ for(i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].dev != dev)
+ continue;
+ unregister_serial(i);
+ rs_table[i].dev = 0;
+ }
+ /*
+ * Now execute any board-specific shutdown procedure
+ */
+ for (i=0; i < NR_PCI_BOARDS; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (serial_pci_board[i].dev != dev)
+ continue;
+ if (brd->board.init_fn)
+ (brd->board.init_fn)(brd->dev, &brd->board, 0);
+ if (DEACTIVATE_FUNC(brd->dev))
+ (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ serial_pci_board[i].dev = 0;
+ }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+ name: "serial",
+ probe: serial_init_one,
+ remove: serial_remove_one,
+ id_table: serial_pci_tbl,
+};


/*
@@ -4635,38 +4732,19 @@
* Accept a maximum of eight boards
*
*/
-static void __init probe_serial_pci(void)
+static void __devinit probe_serial_pci(void)
{
- struct pci_dev *dev = NULL;
- struct pci_board *board;
-
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
-
- pci_for_each_dev(dev) {
- for (board = pci_boards; board->vendor; board++) {
- if (board->vendor != (unsigned short) PCI_ANY_ID &&
- dev->vendor != board->vendor)
- continue;
- if (board->device != (unsigned short) PCI_ANY_ID &&
- dev->device != board->device)
- continue;
- if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- pci_get_subvendor(dev) != board->subvendor)
- continue;
- if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- pci_get_subdevice(dev) != board->subdevice)
- continue;
- break;
- }
-
- if (board->vendor == 0 && serial_pci_guess_board(dev, board))
- continue;
-
- start_pci_pnp_board(dev, board);
- }
-
+
+ /* Register call PCI serial devices. Null out
+ * the driver name upon failure, as a signal
+ * not to attempt to unregister the driver later
+ */
+ if (pci_module_init (&serial_pci_driver) != 0)
+ serial_pci_driver.name[0] = 0;
+
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
#endif
@@ -4682,7 +4760,7 @@
unsigned short device;
};

-static struct pnp_board pnp_devices[] __initdata = {
+static struct pnp_board pnp_devices[] __devinitdata = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
@@ -4972,14 +5050,14 @@
irq->map = map;
}

-static char *modem_names[] __initdata = {
+static char *modem_names[] __devinitdata = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", 0
};

-static int __init check_name(char *name)
+static int __devinit check_name(char *name)
{
char **tmp = modem_names;

@@ -5041,7 +5119,7 @@
return 1;
}

-static void __init probe_serial_pnp(void)
+static void __devinit probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
struct pnp_board *pnp_board;
@@ -5099,7 +5177,7 @@
/*
* The serial driver boot-time initialization code!
*/
-static int __init rs_init(void)
+int __init rs_init(void)
{
int i;
struct serial_state * state;
@@ -5252,6 +5330,36 @@
}

/*
+ * This is for use by architectures that know their serial console
+ * attributes only at run time. Not to be invoked after rs_init().
+ */
+int __init early_serial_setup(struct serial_struct *req)
+{
+ int i = req->line;
+
+ if (i >= NR_IRQS)
+ return(-ENOENT);
+ rs_table[i].magic = 0;
+ rs_table[i].baud_base = req->baud_base;
+ rs_table[i].port = req->port;
+ if (HIGH_BITS_OFFSET)
+ rs_table[i].port += (unsigned long) req->port_high <<
+ HIGH_BITS_OFFSET;
+ rs_table[i].irq = req->irq;
+ rs_table[i].flags = req->flags;
+ rs_table[i].close_delay = req->close_delay;
+ rs_table[i].io_type = req->io_type;
+ rs_table[i].hub6 = req->hub6;
+ rs_table[i].iomem_base = req->iomem_base;
+ rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
+ rs_table[i].type = req->type;
+ rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
+ rs_table[i].custom_divisor = req->custom_divisor;
+ rs_table[i].closing_wait = req->closing_wait;
+ return(0);
+}
+
+/*
* register_serial and unregister_serial allows for 16x50 serial ports to be
* configured at run-time, to support PCMCIA modems.
*/
@@ -5288,6 +5396,14 @@
(rs_table[i].iomem_base == req->iomem_base))
break;
}
+#ifdef __i386__
+ if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+#endif
if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
@@ -5411,12 +5527,13 @@
#endif
}
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- for (i=0; i < serial_pci_board_idx; i++) {
+ for (i=0; i < NR_PCI_BOARDS; i++) {
struct pci_board_inst *brd = &serial_pci_board[i];
-
+
+ if (serial_pci_board[i].dev == 0)
+ continue;
if (brd->board.init_fn)
(brd->board.init_fn)(brd->dev, &brd->board, 0);
-
if (DEACTIVATE_FUNC(brd->dev))
(DEACTIVATE_FUNC(brd->dev))(brd->dev);
}
@@ -5426,6 +5543,11 @@
tmp_buf = NULL;
free_page(pg);
}
+
+#ifdef ENABLE_SERIAL_PCI
+ if (serial_pci_driver.name[0])
+ pci_unregister_driver (&serial_pci_driver);
+#endif
}

module_init(rs_init);
@@ -5461,6 +5583,13 @@
if (--tmout == 0)
break;
} while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+ /* Wait for flow control if necessary */
+ if (info->flags & ASYNC_CONS_FLOW) {
+ tmout = 1000000;
+ while (--tmout &&
+ ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+ }
}


@@ -5543,7 +5672,7 @@
}

/*
- * Setup initial baud/bits/parity. We do two things here:
+ * Setup initial baud/bits/parity/flow control. We do two things here:
* - construct a cflag setting for the first rs_open()
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
@@ -5556,6 +5685,7 @@
int baud = 9600;
int bits = 8;
int parity = 'n';
+ int doflow = 0;
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
@@ -5566,7 +5696,8 @@
while(*s >= '0' && *s <= '9')
s++;
if (*s) parity = *s++;
- if (*s) bits = *s - '0';
+ if (*s) bits = *s++ - '0';
+ if (*s) doflow = (*s++ == 'r');
}

/*
@@ -5622,6 +5753,8 @@
* Divisor, bytesize and parity
*/
state = rs_table + co->index;
+ if (doflow)
+ state->flags |= ASYNC_CONS_FLOW;
info = &async_sercons;
info->magic = SERIAL_MAGIC;
info->state = state;
===================================================================
RCS file: include/linux/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial.h
--- include/linux/serial.h 2000/12/13 01:08:21 1.1
+++ include/linux/serial.h 2000/12/13 15:19:28
@@ -139,8 +139,9 @@
#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards
--- no longer used */
+#define ASYNC_CONS_FLOW 0x00800000 /* flow control for console */

-#define ASYNC_INTERNAL_FLAGS 0xFF000000 /* Internal flags */
+#define ASYNC_INTERNAL_FLAGS 0xFF800000 /* Internal flags */

/*
* Multiport serial configuration structure --- external structure
@@ -176,6 +177,9 @@
/* Export to allow PCMCIA to use this - Dave Hinds */
extern int register_serial(struct serial_struct *req);
extern void unregister_serial(int line);
+
+/* Allow complicated architectures to specify rs_table[] at run time */
+extern int early_serial_setup(struct serial_struct *req);

#endif /* __KERNEL__ */
#endif /* _LINUX_SERIAL_H */
===================================================================
RCS file: include/linux/RCS/serial_reg.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial_reg.h
--- include/linux/serial_reg.h 2000/12/13 01:08:21 1.1
+++ include/linux/serial_reg.h 2000/12/13 01:08:42
@@ -156,8 +156,8 @@
* These register definitions are for the 16C950
*/
#define UART_ASR 0x01 /* Additional Status Register */
-#define UART_RFL 0x03 /* Transmitter FIFO level */
-#define UART_TFL 0x04 /* Receiver FIFO level */
+#define UART_RFL 0x03 /* Receiver FIFO level */
+#define UART_TFL 0x04 /* Transmitter FIFO level */
#define UART_ICR 0x05 /* Index Control Register */

/* The 16950 ICR registers */
===================================================================
RCS file: include/linux/RCS/serialP.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serialP.h
--- include/linux/serialP.h 2000/12/13 01:08:21 1.1
+++ include/linux/serialP.h 2000/12/13 15:25:02
@@ -52,6 +52,7 @@
struct termios callout_termios;
int io_type;
struct async_struct *info;
+ struct pci_dev *dev;
};

struct async_struct {
===================================================================
RCS file: include/linux/RCS/pci_ids.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci_ids.h
--- include/linux/pci_ids.h 2000/12/13 01:08:21 1.1
+++ include/linux/pci_ids.h 2000/12/13 15:39:37
@@ -1320,6 +1320,7 @@

#define PCI_VENDOR_ID_DCI 0x6666
#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002

#define PCI_VENDOR_ID_GENROCO 0x5555
#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003

2000-12-14 21:56:32

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial cardbus code.... for testing, please.....


[Apologies if this has been seen already, but as far as I know my first
posting to the L-K list apparently never made it out....]

- Ted


OK, so I'm currently at the road (San Diego IETF meeting) so I can't
really test this very well; when your compile engine is your Vaio
laptop, it's really slow and painful to do test builds and test booting
kernels.

But I know some people are eager to test it, and would rather have
something potentially flaky earlier rather waiting for something more
tested later, so here it is. Please note, the only testing that I have
done to date is Linus's famous "it builds, ship it" regression test
suite. So if you're not willing to test a patch which might crash your
machine, come back in a day or two after I and others have had a chance
to do some testing. (But hey, Linus has released kernels to the entire
world without even doing a test compile, so why can't I do it with
something as simple as a serial driver? :-)


This version of the patch has a couple of new features over past ones,
including sanity check code which should prevent receive_chars() from
getting stuck in a tight loop when the serial card is ejected while a
port is active. It also has functions correctly labelled with __devinit
and __devexit, and will check to see if an entry in the serial pci table
isn't necessay, and ask the user to report the information in that case.
(mailing list to be active within 24 hours; until then, send the
information to me instead of the e-mail adddress listed in the patch).

The patch also has changes which Kanoj from SGI has been bugging me
about constantly because he needs some changes to support his big-iron
MIPS box project which he's working on. I had sat on them because
clearly I have a different understanding of "code freeze; critical bugs
only" than other folks on the L-K mailing list, but they're included
here now. Linus, I can back out some or all of these changes when I
feed the patches to use for merging with 2.4; just let me know what you
want and don't want.

- Ted


Release notes
=============

* Add support for PCI hot plugging.
- Functions should be correctly labeled with __devinit
and __devexit now.
- Set a safety check to prevent infinite loops in
receive_chars
- Added support for removing PCI cards

* Added code to test to see if an entry in the serial driver's
PCI table is redundant (i.e., could have been deduced
using our hueristics) and asks the user to report the
information if so.

* Add support for flow controled serial console. (Feature
desperately requested to be merged into 2.4.0 by Kanoj
Sarcar <[email protected]> for his big-iron MIPS box)

* Add new interface, early_serial_setup() which allows
architecture specific code to set up serial consoles
for those platforms where the port and bus information
must be dynamically determined by the boot.
Early_serial_setup() must be called before rs_init().
(Feature desperately requested to be merged into 2.4.0
by Kanoj Sarcar <[email protected]> for his big-iron MIPS
box)


* Fixed fencepost bug which could cause the serial driver to
overrun the flip buffer by a single character if the
UART reports an overrun when the flip buffer is nearly
full. (not really a critical problem because we have
slop space in the flip buffer for this purpose, but it
really would be good to have this fixed.)

* Add support for the DCI PCCOM8 8-port serial board


Patch generated: on Wed Dec 13 10:39:41 EST 2000 by tytso@trampoline
against Linux version 2.4.0

===================================================================
RCS file: Documentation/RCS/serial-console.txt,v
retrieving revision 1.1
diff -u -r1.1 Documentation/serial-console.txt
--- Documentation/serial-console.txt 2000/12/13 15:12:57 1.1
+++ Documentation/serial-console.txt 2000/12/13 15:13:09
@@ -20,9 +20,11 @@

options: depend on the driver. For the serial port this
defines the baudrate/parity/bits of the port,
- in the format BBBBPN, where BBBB is the speed,
- P is parity (n/o/e), and N is bits. Default is
- 9600n8. The maximum baudrate is 115200.
+ in the format BBBBPNF, where BBBB is the speed,
+ P is parity (n/o/e), N is bits, and F is
+ flow control (n/r for none/rtscts). P, N,
+ and F are optional. The default setting is
+ 9600n8n. The maximum baudrate is 115200.

You can specify multiple console= options on the kernel command line.
Output will appear on all of them. The last device will be used when
===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 2000/12/13 01:08:20 1.1
+++ drivers/char/serial.c 2000/12/13 15:13:35
@@ -54,13 +54,16 @@
* 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
* Arnaldo Carvalho de Melo <[email protected]>
*
+ * 10/00: add in optional software flow control for serial console.
+ * Kanoj Sarcar <[email protected]> (Modified by Theodore Ts'o)
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/

-static char *serial_version = "5.02";
-static char *serial_revdate = "2000-08-09";
+static char *serial_version = "5.05";
+static char *serial_revdate = "2000-12-13";

/*
* Serial driver configuration section. Here are the various options:
@@ -325,7 +328,6 @@
#define NR_PCI_BOARDS 8

static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
-static int serial_pci_board_idx;

#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
@@ -564,8 +566,8 @@
{
struct tty_struct *tty = info->tty;
unsigned char ch;
- int ignored = 0;
struct async_icount *icount;
+ int max_count = 256;

icount = &info->state->icount;
do {
@@ -612,15 +614,8 @@
icount->overrun++;

/*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
+ * Mask off conditions which should be ignored.
*/
- if (*status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- goto ignore_char;
- }
*status &= info->read_status_mask;

#ifdef CONFIG_SERIAL_CONSOLE
@@ -639,19 +634,6 @@
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
- if (*status & UART_LSR_OE) {
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto ignore_char;
- }
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
@@ -664,16 +646,30 @@
break_pressed = 0;
}
#endif
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ if ((*status & info->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & UART_LSR_OE) &&
+ (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ }
ignore_char:
*status = serial_inp(info, UART_LSR);
- } while (*status & UART_LSR_DR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
tty_flip_buffer_push(tty);
#else
- queue_task(&tty->flip.tqueue, &tq_timer);
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
#endif
}

@@ -827,6 +823,9 @@
end_mark = info;
goto next;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
end_mark = 0;

info->last_active = jiffies;
@@ -910,6 +909,9 @@
#endif
break;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
info->last_active = jiffies;
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -1310,7 +1312,7 @@
*/
if (!(info->flags & ASYNC_BUGGY_UART) &&
(serial_inp(info, UART_LSR) == 0xff)) {
- printk("LSR safety check engaged!\n");
+ printk("ttyS%d: LSR safety check engaged!\n", state->line);
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1554,7 +1556,10 @@
/* Arrange to enter sleep mode */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, 0);
serial_outp(info, UART_LCR, 0);
}
if (info->state->type == PORT_16750) {
@@ -2906,7 +2911,6 @@
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -3254,6 +3258,10 @@
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
+ info->hub6 = state->hub6;
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
info->quot = 0;
info->tty = 0;
}
@@ -3809,7 +3817,7 @@

#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)

-static void __init printk_pnp_dev_id(unsigned short vendor,
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
unsigned short device)
{
printk("%c%c%c%x%x%x%x",
@@ -3901,7 +3909,7 @@
/*
* Common enabler code shared by both PCI and ISAPNP probes
*/
-static void __init start_pci_pnp_board(struct pci_dev *dev,
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
struct pci_board *board)
{
int k, line;
@@ -3933,19 +3941,19 @@
if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
return;

-#ifdef MODULE
/*
* Register the serial board in the array if we need to
- * shutdown the board on a module unload.
+ * shutdown the board on a module unload or card removal
*/
if (DEACTIVATE_FUNC(dev) || board->init_fn) {
- if (serial_pci_board_idx >= NR_PCI_BOARDS)
+ for (k=0; k < NR_PCI_BOARDS; k++)
+ if (serial_pci_board[k].dev == 0)
+ break;
+ if (k >= NR_PCI_BOARDS)
return;
- serial_pci_board[serial_pci_board_idx].board = *board;
- serial_pci_board[serial_pci_board_idx].dev = dev;
- serial_pci_board_idx++;
+ serial_pci_board[k].board = *board;
+ serial_pci_board[k].dev = dev;
}
-#endif

base_baud = board->base_baud;
if (!base_baud)
@@ -3965,6 +3973,7 @@
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
+ rs_table[line].dev = dev;
}
}
#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
@@ -3978,7 +3987,7 @@
*/
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4045,7 +4054,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4077,7 +4086,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4101,7 +4110,7 @@
/* Added for EKF Intel i960 serial boards */
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_inteli960ni_fn(struct pci_dev *dev,
struct pci_board *board,
@@ -4162,7 +4171,7 @@

static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4577,6 +4586,10 @@
SPCI_FL_BASE0, 1, 520833,
64, 3, NULL, 0x300 },
#endif
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE3, 8, 115200,
+ 8 },
/* Generic serial board */
{ 0, 0,
0, 0,
@@ -4626,6 +4639,90 @@
return 1;
}

+static int __devinit serial_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct pci_board *board, tmp;
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ pci_get_subvendor(dev) != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ pci_get_subdevice(dev) != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+ return -ENODEV;
+ else if (serial_pci_guess_board(dev, &tmp) == 0) {
+ printk(KERN_INFO "Redundant entry in serial pci_table. "
+ "Please send the output of\n"
+ "lspci -vv, this message (%d,%d,%d,%d)\n"
+ "and the manufacturer and name of "
+ "serial board or modem board\n"
+ "to [email protected].\n",
+ dev->vendor, dev->device,
+ pci_get_subvendor(dev), pci_get_subdevice(dev));
+ }
+
+ start_pci_pnp_board(dev, board);
+
+ return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+ int i;
+
+ /*
+ * Iterate through all of the ports finding those that belong
+ * to this PCI device.
+ */
+ for(i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].dev != dev)
+ continue;
+ unregister_serial(i);
+ rs_table[i].dev = 0;
+ }
+ /*
+ * Now execute any board-specific shutdown procedure
+ */
+ for (i=0; i < NR_PCI_BOARDS; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (serial_pci_board[i].dev != dev)
+ continue;
+ if (brd->board.init_fn)
+ (brd->board.init_fn)(brd->dev, &brd->board, 0);
+ if (DEACTIVATE_FUNC(brd->dev))
+ (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ serial_pci_board[i].dev = 0;
+ }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+ name: "serial",
+ probe: serial_init_one,
+ remove: serial_remove_one,
+ id_table: serial_pci_tbl,
+};


/*
@@ -4635,38 +4732,19 @@
* Accept a maximum of eight boards
*
*/
-static void __init probe_serial_pci(void)
+static void __devinit probe_serial_pci(void)
{
- struct pci_dev *dev = NULL;
- struct pci_board *board;
-
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
-
- pci_for_each_dev(dev) {
- for (board = pci_boards; board->vendor; board++) {
- if (board->vendor != (unsigned short) PCI_ANY_ID &&
- dev->vendor != board->vendor)
- continue;
- if (board->device != (unsigned short) PCI_ANY_ID &&
- dev->device != board->device)
- continue;
- if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- pci_get_subvendor(dev) != board->subvendor)
- continue;
- if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- pci_get_subdevice(dev) != board->subdevice)
- continue;
- break;
- }
-
- if (board->vendor == 0 && serial_pci_guess_board(dev, board))
- continue;
-
- start_pci_pnp_board(dev, board);
- }
-
+
+ /* Register call PCI serial devices. Null out
+ * the driver name upon failure, as a signal
+ * not to attempt to unregister the driver later
+ */
+ if (pci_module_init (&serial_pci_driver) != 0)
+ serial_pci_driver.name[0] = 0;
+
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
#endif
@@ -4682,7 +4760,7 @@
unsigned short device;
};

-static struct pnp_board pnp_devices[] __initdata = {
+static struct pnp_board pnp_devices[] __devinitdata = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
@@ -4972,14 +5050,14 @@
irq->map = map;
}

-static char *modem_names[] __initdata = {
+static char *modem_names[] __devinitdata = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", 0
};

-static int __init check_name(char *name)
+static int __devinit check_name(char *name)
{
char **tmp = modem_names;

@@ -5041,7 +5119,7 @@
return 1;
}

-static void __init probe_serial_pnp(void)
+static void __devinit probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
struct pnp_board *pnp_board;
@@ -5099,7 +5177,7 @@
/*
* The serial driver boot-time initialization code!
*/
-static int __init rs_init(void)
+int __init rs_init(void)
{
int i;
struct serial_state * state;
@@ -5252,6 +5330,36 @@
}

/*
+ * This is for use by architectures that know their serial console
+ * attributes only at run time. Not to be invoked after rs_init().
+ */
+int __init early_serial_setup(struct serial_struct *req)
+{
+ int i = req->line;
+
+ if (i >= NR_IRQS)
+ return(-ENOENT);
+ rs_table[i].magic = 0;
+ rs_table[i].baud_base = req->baud_base;
+ rs_table[i].port = req->port;
+ if (HIGH_BITS_OFFSET)
+ rs_table[i].port += (unsigned long) req->port_high <<
+ HIGH_BITS_OFFSET;
+ rs_table[i].irq = req->irq;
+ rs_table[i].flags = req->flags;
+ rs_table[i].close_delay = req->close_delay;
+ rs_table[i].io_type = req->io_type;
+ rs_table[i].hub6 = req->hub6;
+ rs_table[i].iomem_base = req->iomem_base;
+ rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
+ rs_table[i].type = req->type;
+ rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
+ rs_table[i].custom_divisor = req->custom_divisor;
+ rs_table[i].closing_wait = req->closing_wait;
+ return(0);
+}
+
+/*
* register_serial and unregister_serial allows for 16x50 serial ports to be
* configured at run-time, to support PCMCIA modems.
*/
@@ -5288,6 +5396,14 @@
(rs_table[i].iomem_base == req->iomem_base))
break;
}
+#ifdef __i386__
+ if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+#endif
if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
@@ -5411,12 +5527,13 @@
#endif
}
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- for (i=0; i < serial_pci_board_idx; i++) {
+ for (i=0; i < NR_PCI_BOARDS; i++) {
struct pci_board_inst *brd = &serial_pci_board[i];
-
+
+ if (serial_pci_board[i].dev == 0)
+ continue;
if (brd->board.init_fn)
(brd->board.init_fn)(brd->dev, &brd->board, 0);
-
if (DEACTIVATE_FUNC(brd->dev))
(DEACTIVATE_FUNC(brd->dev))(brd->dev);
}
@@ -5426,6 +5543,11 @@
tmp_buf = NULL;
free_page(pg);
}
+
+#ifdef ENABLE_SERIAL_PCI
+ if (serial_pci_driver.name[0])
+ pci_unregister_driver (&serial_pci_driver);
+#endif
}

module_init(rs_init);
@@ -5461,6 +5583,13 @@
if (--tmout == 0)
break;
} while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+ /* Wait for flow control if necessary */
+ if (info->flags & ASYNC_CONS_FLOW) {
+ tmout = 1000000;
+ while (--tmout &&
+ ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+ }
}


@@ -5543,7 +5672,7 @@
}

/*
- * Setup initial baud/bits/parity. We do two things here:
+ * Setup initial baud/bits/parity/flow control. We do two things here:
* - construct a cflag setting for the first rs_open()
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
@@ -5556,6 +5685,7 @@
int baud = 9600;
int bits = 8;
int parity = 'n';
+ int doflow = 0;
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
@@ -5566,7 +5696,8 @@
while(*s >= '0' && *s <= '9')
s++;
if (*s) parity = *s++;
- if (*s) bits = *s - '0';
+ if (*s) bits = *s++ - '0';
+ if (*s) doflow = (*s++ == 'r');
}

/*
@@ -5622,6 +5753,8 @@
* Divisor, bytesize and parity
*/
state = rs_table + co->index;
+ if (doflow)
+ state->flags |= ASYNC_CONS_FLOW;
info = &async_sercons;
info->magic = SERIAL_MAGIC;
info->state = state;
===================================================================
RCS file: include/linux/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial.h
--- include/linux/serial.h 2000/12/13 01:08:21 1.1
+++ include/linux/serial.h 2000/12/13 15:19:28
@@ -139,8 +139,9 @@
#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards
--- no longer used */
+#define ASYNC_CONS_FLOW 0x00800000 /* flow control for console */

-#define ASYNC_INTERNAL_FLAGS 0xFF000000 /* Internal flags */
+#define ASYNC_INTERNAL_FLAGS 0xFF800000 /* Internal flags */

/*
* Multiport serial configuration structure --- external structure
@@ -176,6 +177,9 @@
/* Export to allow PCMCIA to use this - Dave Hinds */
extern int register_serial(struct serial_struct *req);
extern void unregister_serial(int line);
+
+/* Allow complicated architectures to specify rs_table[] at run time */
+extern int early_serial_setup(struct serial_struct *req);

#endif /* __KERNEL__ */
#endif /* _LINUX_SERIAL_H */
===================================================================
RCS file: include/linux/RCS/serial_reg.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial_reg.h
--- include/linux/serial_reg.h 2000/12/13 01:08:21 1.1
+++ include/linux/serial_reg.h 2000/12/13 01:08:42
@@ -156,8 +156,8 @@
* These register definitions are for the 16C950
*/
#define UART_ASR 0x01 /* Additional Status Register */
-#define UART_RFL 0x03 /* Transmitter FIFO level */
-#define UART_TFL 0x04 /* Receiver FIFO level */
+#define UART_RFL 0x03 /* Receiver FIFO level */
+#define UART_TFL 0x04 /* Transmitter FIFO level */
#define UART_ICR 0x05 /* Index Control Register */

/* The 16950 ICR registers */
===================================================================
RCS file: include/linux/RCS/serialP.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serialP.h
--- include/linux/serialP.h 2000/12/13 01:08:21 1.1
+++ include/linux/serialP.h 2000/12/13 15:25:02
@@ -52,6 +52,7 @@
struct termios callout_termios;
int io_type;
struct async_struct *info;
+ struct pci_dev *dev;
};

struct async_struct {
===================================================================
RCS file: include/linux/RCS/pci_ids.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci_ids.h
--- include/linux/pci_ids.h 2000/12/13 01:08:21 1.1
+++ include/linux/pci_ids.h 2000/12/13 15:39:37
@@ -1320,6 +1320,7 @@

#define PCI_VENDOR_ID_DCI 0x6666
#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002

#define PCI_VENDOR_ID_GENROCO 0x5555
#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003