patch-2.4.19 linux-2.4.19/drivers/char/serial.c
Next file: linux-2.4.19/drivers/char/serial167.c
Previous file: linux-2.4.19/drivers/char/sc520_wdt.c
Back to the patch index
Back to the overall index
- Lines: 474
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/drivers/char/serial.c
- Orig date:
Mon Feb 25 11:37:57 2002
diff -urN linux-2.4.18/drivers/char/serial.c linux-2.4.19/drivers/char/serial.c
@@ -57,6 +57,11 @@
* 10/00: add in optional software flow control for serial console.
* Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
*
+ * 02/02: Fix for AMD Elan bug in transmit irq routine, by
+ * Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
+ * Robert Schwebel <robert@schwebel.de>,
+ * Juergen Beisert <jbeisert@eurodsn.de>,
+ * Theodore Ts'o <tytso@mit.edu>
*/
static char *serial_version = "5.05c";
@@ -321,11 +326,12 @@
MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
#endif /* CONFIG_SERIAL_RSA */
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
+struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+int serial_nr_ports = NR_PORTS;
#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
#define NR_PCI_BOARDS 8
@@ -418,10 +424,6 @@
case SERIAL_IO_MEM:
return readb((unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
-#ifdef CONFIG_SERIAL_GSC
- case SERIAL_IO_GSC:
- return gsc_readb(info->iomem_base + offset);
-#endif
default:
return inb(info->port + offset);
}
@@ -441,11 +443,6 @@
writeb(value, (unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
break;
-#ifdef CONFIG_SERIAL_GSC
- case SERIAL_IO_GSC:
- gsc_writeb(value, info->iomem_base + offset);
- break;
-#endif
default:
outb(value, info->port+offset);
}
@@ -801,7 +798,7 @@
*/
static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
- int status;
+ int status, iir;
struct async_struct * info;
int pass_counter = 0;
struct async_struct *end_mark = 0;
@@ -826,7 +823,7 @@
do {
if (!info->tty ||
- (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
+ ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) {
if (!end_mark)
end_mark = info;
goto next;
@@ -845,7 +842,9 @@
if (status & UART_LSR_DR)
receive_chars(info, &status, regs);
check_modem_status(info);
- if (status & UART_LSR_THRE)
+ if ((status & UART_LSR_THRE) ||
+ /* for buggy ELAN processors */
+ ((iir & UART_IIR_ID) == UART_IIR_THRI))
transmit_chars(info, 0);
next:
@@ -879,7 +878,7 @@
*/
static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
{
- int status;
+ int status, iir;
int pass_counter = 0;
struct async_struct * info;
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -901,6 +900,7 @@
first_multi = inb(multi->port_monitor);
#endif
+ iir = serial_in(info, UART_IIR);
do {
status = serial_inp(info, UART_LSR);
#ifdef SERIAL_DEBUG_INTR
@@ -909,18 +909,21 @@
if (status & UART_LSR_DR)
receive_chars(info, &status, regs);
check_modem_status(info);
- if (status & UART_LSR_THRE)
+ if ((status & UART_LSR_THRE) ||
+ /* For buggy ELAN processors */
+ ((iir & UART_IIR_ID) == UART_IIR_THRI))
transmit_chars(info, 0);
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
+#if SERIAL_DEBUG_INTR
printk("rs_single loop break.\n");
#endif
break;
}
+ iir = serial_in(info, UART_IIR);
#ifdef SERIAL_DEBUG_INTR
- printk("IIR = %x...", serial_in(info, UART_IIR));
+ printk("IIR = %x...", iir);
#endif
- } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
+ } while ((iir & UART_IIR_NO_INT) == 0);
info->last_active = jiffies;
#ifdef CONFIG_SERIAL_MULTIPORT
if (multi->port_monitor)
@@ -2133,6 +2136,7 @@
if (new_serial.type) {
for (i = 0 ; i < NR_PORTS; i++)
if ((state != &rs_table[i]) &&
+ (rs_table[i].io_type == SERIAL_IO_PORT) &&
(rs_table[i].port == new_port) &&
rs_table[i].type)
return -EADDRINUSE;
@@ -2195,7 +2199,7 @@
check_and_exit:
- if (!state->port || !state->type)
+ if ((!state->port && !state->iomem_base) || !state->type)
return 0;
if (info->flags & ASYNC_INITIALIZED) {
if (((old_state.flags & ASYNC_SPD_MASK) !=
@@ -3247,14 +3251,17 @@
int ret;
unsigned long flags;
+ /*
+ * Return zero characters for ports not claimed by driver.
+ */
+ if (state->type == PORT_UNKNOWN) {
+ return 0; /* ignore unused ports */
+ }
+
ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
state->line, uart_config[state->type].name,
- state->port, state->irq);
-
- if (!state->port || (state->type == PORT_UNKNOWN)) {
- ret += sprintf(buf+ret, "\n");
- return ret;
- }
+ (state->port ? state->port : (long)state->iomem_base),
+ state->irq);
/*
* Figure out the current RS-232 lines
@@ -3912,6 +3919,25 @@
}
+ /* HP's Diva chip puts the 4th/5th serial port further out, and
+ * some serial ports are supposed to be hidden on certain models.
+ */
+ if (dev->vendor == PCI_VENDOR_ID_HP &&
+ dev->device == PCI_DEVICE_ID_HP_SAS) {
+ switch (dev->subsystem_device) {
+ case 0x104B: /* Maestro */
+ if (idx == 3) idx++;
+ break;
+ case 0x1282: /* Everest / Longs Peak */
+ if (idx > 0) idx++;
+ if (idx > 2) idx++;
+ break;
+ }
+ if (idx > 2) {
+ offset = 0x18;
+ }
+ }
+
port = pci_resource_start(dev, base_idx) + offset;
if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
@@ -4081,12 +4107,14 @@
* interface chip and different configuration methods:
* - 10x cards have control registers in IO and/or memory space;
* - 20x cards have control registers in standard PCI configuration space.
+ *
+ * SIIG initialization functions exported for use by parport_serial.c module.
*/
#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
-static int __devinit
+int __devinit
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
u16 data, *p;
@@ -4111,11 +4139,12 @@
iounmap(p);
return 0;
}
+EXPORT_SYMBOL(pci_siig10x_fn);
#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
-static int __devinit
+int __devinit
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
u8 data;
@@ -4134,6 +4163,7 @@
}
return 0;
}
+EXPORT_SYMBOL(pci_siig20x_fn);
/* Added for EKF Intel i960 serial boards */
static int __devinit
@@ -4215,6 +4245,40 @@
return 0;
}
+/*
+ * HP's Remote Management Console. The Diva chip came in several
+ * different versions. N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused). Superdome
+ * and Keystone have one Diva chip with 3 UARTs. Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int __devinit
+pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ if (!enable)
+ return 0;
+
+ switch (dev->subsystem_device) {
+ case 0x1049: /* Prelude Diva 1 */
+ case 0x1223: /* Superdome */
+ case 0x1226: /* Keystone */
+ case 0x1282: /* Everest / Longs Peak */
+ board->num_ports = 3;
+ break;
+ case 0x104A: /* Prelude Diva 2 */
+ board->num_ports = 2;
+ break;
+ case 0x104B: /* Maestro */
+ board->num_ports = 4;
+ break;
+ case 0x1227: /* Powerbar */
+ board->num_ports = 1;
+ break;
+ }
+
+ return 0;
+}
+
static int __devinit
pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4244,6 +4308,7 @@
pbn_b0_bt_2_115200,
pbn_b0_bt_1_460800,
pbn_b0_bt_2_460800,
+ pbn_b0_bt_2_921600,
pbn_b1_1_115200,
pbn_b1_2_115200,
@@ -4258,6 +4323,7 @@
pbn_b1_4_1382400,
pbn_b1_8_1382400,
+ pbn_b2_1_115200,
pbn_b2_8_115200,
pbn_b2_4_460800,
pbn_b2_8_460800,
@@ -4278,6 +4344,7 @@
pbn_timedia,
pbn_intel_i960,
pbn_sgi_ioc3,
+ pbn_hp_diva,
#ifdef CONFIG_DDB5074
pbn_nec_nile4,
#endif
@@ -4322,6 +4389,7 @@
{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
{ SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */
{ SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */
@@ -4336,6 +4404,7 @@
{ SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */
{ SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */
+ { SPCI_FL_BASE2, 1, 115200 }, /* pbn_b2_1_115200 */
{ SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */
{ SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */
{ SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */
@@ -4366,6 +4435,7 @@
8<<2, 2, pci_inteli960ni_fn, 0x10000},
{ SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */
1, 458333, 0, 0, 0, 0x20178 },
+ { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0}, /* pbn_hp_diva */
#ifdef CONFIG_DDB5074
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
@@ -4657,7 +4727,7 @@
pbn_b0_4_115200 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_2_115200 },
+ pbn_b0_bt_2_921600 },
/* Digitan DS560-558, from jimd@esoft.com */
{ PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
@@ -4704,15 +4774,6 @@
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig10x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig10x_2 },
@@ -4722,15 +4783,6 @@
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig10x_4 },
@@ -4749,24 +4801,6 @@
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig20x_2 },
@@ -4776,15 +4810,6 @@
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_siig20x_4 },
@@ -4864,6 +4889,14 @@
0xFF00, 0, 0, 0,
pbn_sgi_ioc3 },
+ /* HP Diva card */
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_hp_diva },
+ { PCI_VENDOR_ID_HP, 0x1290,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+
#ifdef CONFIG_DDB5074
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
@@ -5486,7 +5519,7 @@
&& (state->port != 0 || state->iomem_base != 0))
state->irq = detect_uart_irq(state);
if (state->io_type == SERIAL_IO_MEM) {
- printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n",
+ printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->iomem_base, state->irq,
@@ -5661,7 +5694,7 @@
if (state->info && state->info->tty)
tty_hangup(state->info->tty);
state->type = PORT_UNKNOWN;
- printk(KERN_INFO "tty%02d unloaded\n", state->line);
+ printk(KERN_INFO "ttyS%02d unloaded\n", state->line);
/* These will be hidden, because they are devices that will no longer
* be available to the system. (ie, PCMCIA modems, once ejected)
*/
@@ -5822,35 +5855,6 @@
serial_out(info, UART_IER, ier);
}
-/*
- * Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
- static struct async_struct *info;
- int ier, c;
-
- info = &async_sercons;
-
- /*
- * First save the IER then disable the interrupts so
- * that the real driver for the port does not get the
- * character.
- */
- ier = serial_in(info, UART_IER);
- serial_out(info, UART_IER, 0x00);
-
- while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
- c = serial_in(info, UART_RX);
-
- /*
- * Restore the interrupts
- */
- serial_out(info, UART_IER, ier);
-
- return c;
-}
-
static kdev_t serial_console_device(struct console *c)
{
return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -5991,7 +5995,6 @@
name: "ttyS",
write: serial_console_write,
device: serial_console_device,
- wait_key: serial_console_wait_key,
setup: serial_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)