PATCH to serial driver.

From: tytso@mit.edu
Date: Mon Mar 20 2000 - 12:53:25 EST


Linus, could you please apply the following patch to the serial driver.

The patches are against Linux-2.3.99-pre-2, and they fix the following
bugs/problems:

        * Fixed SMP races in the circular buffer code, courtesy of Alan
          Mondra

        * Use module_init() so we can remove call to rs_init() from
          drivers/char/tty_io.c

        * Updated ISA PNP support from Andrew Panin to support
          additional PNP boards.

        * Fixed Oxford Semiconductor 16C950 workaround code to take
          into account that the chip revision register is zero based.

        * Add support for the Titan Microelectronics PCI serial boards

        * Make code (more) 64-bit clean. (Deal with complaints from
                  Dave Miller and Dave Mosberger)

        * Fix initialization sequence for newer Panacom PCI serial boards.

Thanks!!

                                                - Ted

Patch generated: on Mon Mar 20 12:43:16 EST 2000 by tytso@trampoline.thunk.org
against Linux version 2.3.99-pre-2
 
===================================================================
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/03/20 07:45:30 1.1
+++ drivers/char/serial.c 2000/03/20 17:37:49
@@ -39,13 +39,17 @@
  *
  * 8/99: Generalized PCI support added. Theodore Ts'o
  *
+ * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
+ * few races on freeing buffers too.
+ * Alan Modra <alan@linuxcare.com>
+ *
  * This module exports the following rs232 io functions:
  *
  * int rs_init(void);
  */
 
-static char *serial_version = "4.92";
-static char *serial_revdate = "2000-1-27";
+static char *serial_version = "4.93";
+static char *serial_revdate = "2000-03-20";
 
 /*
  * Serial driver configuration section. Here are the various options:
@@ -98,7 +102,7 @@
 #endif
 #endif
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
 #ifndef ENABLE_SERIAL_PNP
 #define ENABLE_SERIAL_PNP
 #endif
@@ -220,7 +224,6 @@
                                  unsigned int minor);
 extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
 
-
 static char *serial_name = "Serial driver";
 
 static DECLARE_TASK_QUEUE(tq_serial);
@@ -253,7 +256,7 @@
 #endif
 
 static unsigned detect_uart_irq (struct serial_state * state);
-static void autoconfig(struct serial_state * info);
+static void autoconfig(struct serial_state * state);
 static void change_speed(struct async_struct *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 
@@ -321,9 +324,6 @@
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
 
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
 
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
@@ -379,7 +379,7 @@
                 return inb(info->port+1);
 #endif
         case SERIAL_IO_MEM:
- return readb(info->iomem_base +
+ return readb((unsigned long) info->iomem_base +
                              (offset<<info->iomem_reg_shift));
 #ifdef CONFIG_SERIAL_GSC
         case SERIAL_IO_GSC:
@@ -401,7 +401,7 @@
                 break;
 #endif
         case SERIAL_IO_MEM:
- writeb(value, info->iomem_base +
+ writeb(value, (unsigned long) info->iomem_base +
                               (offset<<info->iomem_reg_shift));
                 break;
 #ifdef CONFIG_SERIAL_GSC
@@ -481,7 +481,9 @@
                 return;
         
         save_flags(flags); cli();
- if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && info->xmit.buf
+ && !(info->IER & UART_IER_THRI)) {
                 info->IER |= UART_IER_THRI;
                 serial_out(info, UART_IER, info->IER);
         }
@@ -633,7 +635,7 @@
 static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
 {
         int count;
-
+
         if (info->x_char) {
                 serial_outp(info, UART_TX, info->x_char);
                 info->state->icount.tx++;
@@ -642,8 +644,9 @@
                         *intr_done = 0;
                 return;
         }
- if ((info->xmit_cnt <= 0) || info->tty->stopped ||
- info->tty->hw_stopped) {
+ if (info->xmit.head == info->xmit.tail
+ || info->tty->stopped
+ || info->tty->hw_stopped) {
                 info->IER &= ~UART_IER_THRI;
                 serial_out(info, UART_IER, info->IER);
                 return;
@@ -651,14 +654,16 @@
         
         count = info->xmit_fifo_size;
         do {
- serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+ info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
                 info->state->icount.tx++;
- if (--info->xmit_cnt <= 0)
+ if (info->xmit.head == info->xmit.tail)
                         break;
         } while (--count > 0);
         
- if (info->xmit_cnt < WAKEUP_CHARS)
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
                 rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 #ifdef SERIAL_DEBUG_INTR
@@ -667,7 +672,7 @@
         if (intr_done)
                 *intr_done = 0;
 
- if (info->xmit_cnt <= 0) {
+ if (info->xmit.head == info->xmit.tail) {
                 info->IER &= ~UART_IER_THRI;
                 serial_out(info, UART_IER, info->IER);
         }
@@ -759,11 +764,11 @@
 #ifdef SERIAL_DEBUG_INTR
         printk("rs_interrupt(%d)...", irq);
 #endif
-
+
         info = IRQ_ports[irq];
         if (!info)
                 return;
-
+
 #ifdef CONFIG_SERIAL_MULTIPORT
         multi = &rs_multiport[irq];
         if (multi->port_monitor)
@@ -833,7 +838,7 @@
 #ifdef SERIAL_DEBUG_INTR
         printk("rs_interrupt_single(%d)...", irq);
 #endif
-
+
         info = IRQ_ports[irq];
         if (!info || !info->tty)
                 return;
@@ -888,7 +893,7 @@
 #ifdef SERIAL_DEBUG_INTR
         printk("rs_interrupt_multi(%d)...", irq);
 #endif
-
+
         info = IRQ_ports[irq];
         if (!info)
                 return;
@@ -1026,7 +1031,7 @@
                                         serial_out(info, UART_IER, info->IER);
                                         info = info->next_port;
                                 } while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
+#ifdef CONFIG_SERIAL_MULTIPORT
                                 if (rs_multiport[i].port1)
                                         rs_interrupt_multi(i, NULL, NULL);
                                 else
@@ -1117,10 +1122,10 @@
                 free_page(page);
                 goto errout;
         }
- if (info->xmit_buf)
+ if (info->xmit.buf)
                 free_page(page);
         else
- info->xmit_buf = (unsigned char *) page;
+ info->xmit.buf = (unsigned char *) page;
 
 #ifdef SERIAL_DEBUG_OPEN
         printk("starting up ttys%d (irq %d)...", info->line, state->irq);
@@ -1298,7 +1303,7 @@
 
         if (info->tty)
                 clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
 
         /*
          * Set up serial timers...
@@ -1393,9 +1398,10 @@
                         free_irq(state->irq, &IRQ_ports[state->irq]);
         }
 
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
+ if (info->xmit.buf) {
+ unsigned long pg = (unsigned long) info->xmit.buf;
+ info->xmit.buf = 0;
+ free_page(pg);
         }
 
         info->IER = 0;
@@ -1570,7 +1576,7 @@
          * when DLL is 0.
          */
         if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
- (info->state->revision == 0x5202))
+ (info->state->revision == 0x5201))
                 quot++;
         
         info->quot = quot;
@@ -1654,7 +1660,7 @@
                          serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
                  }
                 serial_outp(info, UART_FCR, fcr); /* set fcr */
- }
+ }
         restore_flags(flags);
 }
 
@@ -1666,18 +1672,19 @@
         if (serial_paranoia_check(info, tty->device, "rs_put_char"))
                 return;
 
- if (!tty || !info->xmit_buf)
+ if (!tty || !info->xmit.buf)
                 return;
 
         save_flags(flags); cli();
- if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ if (CIRC_SPACE(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) == 0) {
                 restore_flags(flags);
                 return;
         }
 
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE-1;
- info->xmit_cnt++;
+ info->xmit.buf[info->xmit.head] = ch;
+ info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
         restore_flags(flags);
 }
 
@@ -1689,8 +1696,10 @@
         if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
                 return;
 
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
+ if (info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+ || !info->xmit.buf)
                 return;
 
         save_flags(flags); cli();
@@ -1709,16 +1718,19 @@
         if (serial_paranoia_check(info, tty->device, "rs_write"))
                 return 0;
 
- if (!tty || !info->xmit_buf || !tmp_buf)
+ if (!tty || !info->xmit.buf || !tmp_buf)
                 return 0;
 
         save_flags(flags);
         if (from_user) {
                 down(&tmp_buf_sem);
                 while (1) {
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
                         if (c <= 0)
                                 break;
 
@@ -1729,12 +1741,14 @@
                                 break;
                         }
                         cli();
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ c1 = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
                                            (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
                         restore_flags(flags);
                         buf += c;
                         count -= c;
@@ -1742,27 +1756,29 @@
                 }
                 up(&tmp_buf_sem);
         } else {
+ cli();
                 while (1) {
- cli();
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
                         if (c <= 0) {
- restore_flags(flags);
                                 break;
                         }
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
                                            (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- restore_flags(flags);
                         buf += c;
                         count -= c;
                         ret += c;
                 }
+ restore_flags(flags);
         }
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && !tty->stopped
+ && !tty->hw_stopped
+ && !(info->IER & UART_IER_THRI)) {
                 info->IER |= UART_IER_THRI;
                 serial_out(info, UART_IER, info->IER);
         }
@@ -1772,14 +1788,10 @@
 static int rs_write_room(struct tty_struct *tty)
 {
         struct async_struct *info = (struct async_struct *)tty->driver_data;
- int ret;
-
+
         if (serial_paranoia_check(info, tty->device, "rs_write_room"))
                 return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
@@ -1788,7 +1800,7 @@
                                 
         if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
                 return 0;
- return info->xmit_cnt;
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static void rs_flush_buffer(struct tty_struct *tty)
@@ -1799,7 +1811,7 @@
         if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
                 return;
         save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
         restore_flags(flags);
         wake_up_interruptible(&tty->write_wait);
         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -2071,8 +2083,9 @@
          * interrupt happens).
          */
         if (info->x_char ||
- ((info->xmit_cnt > 0) && !info->tty->stopped &&
- !info->tty->hw_stopped))
+ ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+ SERIAL_XMIT_SIZE) > 0) &&
+ !info->tty->stopped && !info->tty->hw_stopped))
                 result &= TIOCSER_TEMT;
 
         if (copy_to_user(value, &result, sizeof(int)))
@@ -2708,8 +2721,8 @@
         char_time = char_time / 5;
         if (char_time == 0)
                 char_time = 1;
- if (timeout)
- char_time = MIN(char_time, timeout);
+ if (timeout && timeout < char_time)
+ char_time = timeout;
         /*
          * If the transmitter hasn't cleared in twice the approximate
          * amount of time to send the entire FIFO, it probably won't
@@ -3083,9 +3096,9 @@
         }
         save_flags(flags); cli();
         status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
+ control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
         restore_flags(flags);
-
+
         stat_buf[0] = 0;
         stat_buf[1] = 0;
         if (control & UART_MCR_RTS)
@@ -3403,7 +3416,7 @@
         state->type = PORT_UNKNOWN;
 
 #ifdef SERIAL_DEBUG_AUTOCONF
- printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line,
+ printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
                state->port, (unsigned) state->iomem_base);
 #endif
         
@@ -3743,15 +3756,10 @@
         
         /* enable/disable interrupts */
         p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
- if (dev->vendor == PCI_VENDOR_ID_PANACOM) {
- scratch = readl(p + 0x4c);
- if (enable)
- scratch |= 0x40;
- else
- scratch &= ~0x40;
- writel(scratch, p + 0x4c);
- } else
- writel(enable ? 0x41 : 0x00, p + 0x4c);
+ scratch = 0x41;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ scratch = 0x43;
+ writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c);
         iounmap(p);
 
         if (!enable)
@@ -3806,7 +3814,7 @@
                        break;
        }
 
- writew(readw(p + 0x28) & data, p + 0x28);
+ writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
        iounmap(p);
        return 0;
 }
@@ -4181,6 +4189,19 @@
         { PCI_VENDOR_ID_USR, 0x1008,
                 PCI_ANY_ID, PCI_ANY_ID,
                 SPCI_FL_BASE0, 1, 115200 },
+ /* Titan Electronic cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 1, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 2, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
         /*
          * Untested PCI modems, sent in from various folks...
          */
@@ -4188,10 +4209,9 @@
         { PCI_VENDOR_ID_ROCKWELL, 0x1004,
                 0x1048, 0x1500,
                 SPCI_FL_BASE1, 1, 115200 },
-#ifdef CONFIG_DDB5074
+#if 0 /* No definition for PCI_DEVICE_ID_NEC_NILE4 */
         /*
          * NEC Vrc-5074 (Nile 4) builtin UART.
- * Conditionally compiled in since this is a motherboard device.
          */
         { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
                 PCI_ANY_ID, PCI_ANY_ID,
@@ -4308,16 +4328,36 @@
 static struct pci_board pnp_devices[] __initdata = {
         /* Rockwell 56K ACF II Fax+Data+Voice Modem */
         { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+ 1, 115200 },
+ /* AZT3005 PnP SOUND DEVICE */
+ { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
                 SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
         /* Boca Research 33,600 ACF Modem */
         { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
                 SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
+ /* Creative Modem Blaster Flash56 DI5601-1 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Creative Modem Blaster V.90 DI5660 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Pace 56 Voice Internal Plug & Play Modem */
+ { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
                 SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
         /* SupraExpress 28.8 Data/Fax PnP modem */
         { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
                 SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* US Robotics Sporster 33600 Modem */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* U.S. Robotics 56K FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+
         /* These ID's are taken from M$ documentation */
         /* Compaq 14400 Modem */
         { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
@@ -4334,6 +4374,24 @@
         { 0, }
 };
 
+static void inline avoid_irq_share(struct pci_dev *dev)
+{
+ int i, map = 0x1FF8;
+ struct serial_state *state = rs_table;
+ struct isapnp_irq *irq;
+ struct isapnp_resources *res = dev->sysdata;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (state->type != PORT_UNKNOWN)
+ clear_bit(state->irq, &map);
+ state++;
+ }
+
+ for ( ; res; res = res->alt)
+ for(irq = res->irq; irq; irq = irq->next)
+ irq->map = map;
+}
+
 static void __init probe_serial_pnp(void)
 {
        struct pci_dev *dev = NULL;
@@ -4352,9 +4410,9 @@
        for (board = pnp_devices; board->vendor; board++) {
                while ((dev = isapnp_find_dev(NULL, board->vendor,
                                              board->device, dev))) {
-
- start_pci_pnp_board(dev, board);
-
+ if (board->flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+ start_pci_pnp_board(dev, board);
                }
        }
 
@@ -4417,7 +4475,11 @@
 #if (LINUX_VERSION_CODE > 0x20100)
         serial_driver.driver_name = "serial";
 #endif
+#if (LINUX_VERSION_CODE > 0x2032D)
         serial_driver.name = "tts/%d";
+#else
+ serial_driver.name = "ttyS";
+#endif
         serial_driver.major = TTY_MAJOR;
         serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
         serial_driver.num = NR_PORTS;
@@ -4461,7 +4523,11 @@
          * major number and the subtype code.
          */
         callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D)
         callout_driver.name = "cua/%d";
+#else
+ callout_driver.name = "cua";
+#endif
         callout_driver.major = TTYAUX_MAJOR;
         callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 #if (LINUX_VERSION_CODE >= 131343)
@@ -4503,7 +4569,7 @@
                     && (state->flags & ASYNC_AUTO_IRQ)
                     && (state->port != 0))
                         state->irq = detect_uart_irq(state);
- printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
                        state->line + SERIAL_DEV_OFFSET,
                        (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
                        state->port, state->irq,
@@ -4538,7 +4604,7 @@
  * The port is then probed and if neccessary the IRQ is autodetected
  * If this fails an error is returned.
  *
- * On success the port is ready to use and the line number is returned.
+ * On success the port is ready to use and the line number is returned.
  */
  
 int register_serial(struct serial_struct *req)
@@ -4548,8 +4614,7 @@
         struct serial_state *state;
         struct async_struct *info;
 
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
         for (i = 0; i < NR_PORTS; i++) {
                 if ((rs_table[i].port == req->port) &&
                     (rs_table[i].iomem_base == req->iomem_base))
@@ -4568,7 +4633,7 @@
         state = &rs_table[i];
         if (rs_table[i].count) {
                 restore_flags(flags);
- printk("Couldn't configure serial #%d (port=%d,irq=%d): "
+ printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
                        "device already open\n", i, req->port, req->irq);
                 return -1;
         }
@@ -4598,12 +4663,11 @@
         if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
                 state->irq = detect_uart_irq(state);
 
- printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
               state->line + SERIAL_DEV_OFFSET,
               state->iomem_base ? "iomem" : "port",
               state->iomem_base ? (unsigned long)state->iomem_base :
- (unsigned long)state->port,
- state->irq, uart_config[state->type].name);
+ state->port, state->irq, uart_config[state->type].name);
         tty_register_devfs(&serial_driver, 0,
                            serial_driver.minor_start + state->line);
         tty_register_devfs(&callout_driver, 0,
@@ -4625,8 +4689,7 @@
         unsigned long flags;
         struct serial_state *state = &rs_table[line];
 
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
         if (state->info && state->info->tty)
                 tty_hangup(state->info->tty);
         state->type = PORT_UNKNOWN;
@@ -4642,12 +4705,7 @@
 }
 
 #ifdef MODULE
-int init_module(void)
-{
- return rs_init();
-}
-
-void cleanup_module(void)
+void rs_fini(void)
 {
         unsigned long flags;
         int e1, e2;
@@ -4655,8 +4713,7 @@
         struct async_struct *info;
 
         /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
         timer_active &= ~(1 << RS_TIMER);
         timer_table[RS_TIMER].fn = NULL;
         timer_table[RS_TIMER].expires = 0;
@@ -4693,11 +4750,15 @@
         }
 #endif
         if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
+ unsigned long pg = (unsigned long) tmp_buf;
                 tmp_buf = NULL;
+ free_page(pg);
         }
 }
 #endif /* MODULE */
+
+module_init(rs_init);
+module_exit(rs_fini);
 
 
 /*
===================================================================
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/03/20 07:45:31 1.1
+++ include/linux/serial.h 2000/03/20 17:37:49
@@ -10,6 +10,8 @@
 #ifndef _LINUX_SERIAL_H
 #define _LINUX_SERIAL_H
 
+#include <asm/page.h>
+
 /*
  * Counters of the input lines (CTS, DSR, RI, CD) interrupts
  */
@@ -23,12 +25,12 @@
 /*
  * The size of the serial xmit buffer is 1 page, or 4096 bytes
  */
-#define SERIAL_XMIT_SIZE 4096
+#define SERIAL_XMIT_SIZE PAGE_SIZE
 
 struct serial_struct {
         int type;
         int line;
- int port;
+ unsigned long port;
         int irq;
         int flags;
         int xmit_fifo_size;
===================================================================
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/03/20 07:45:31 1.1
+++ include/linux/serialP.h 2000/03/20 17:37:49
@@ -22,12 +22,13 @@
 #include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
+#include <linux/circ_buf.h>
 #include <linux/wait.h>
 
 struct serial_state {
         int magic;
         int baud_base;
- int port;
+ unsigned long port;
         int irq;
         int flags;
         int hub6;
@@ -50,7 +51,7 @@
 
 struct async_struct {
         int magic;
- int port;
+ unsigned long port;
         int hub6;
         int flags;
         int xmit_fifo_size;
@@ -74,10 +75,8 @@
         int blocked_open; /* # of blocked opens */
         long session; /* Session of opening process */
         long pgrp; /* pgrp of opening process */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
+ struct circ_buf xmit;
+ spinlock_t xmit_lock;
         u8 *iomem_base;
         u16 iomem_reg_shift;
         int io_type;
@@ -101,11 +100,6 @@
 #define SSTATE_MAGIC 0x5302
 
 /*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
  * Events are used to schedule things to happen at timer-interrupt
  * time, instead of at rs interrupt time.
  */
@@ -180,19 +174,22 @@
 #define SPCI_FL_IRQBASE3 (0x0003 << 4)
 #define SPCI_FL_IRQBASE4 (0x0004 << 4)
 #define SPCI_FL_GET_IRQBASE(x) ((x & SPCI_FL_IRQ_MASK) >> 4)
-
+
 /* Use sucessiveentries base resource table */
 #define SPCI_FL_BASE_TABLE 0x0100
-
+
 /* Use successive entries in the irq resource table */
 #define SPCI_FL_IRQ_TABLE 0x0200
-
+
 /* Use the irq resource table instead of dev->irq */
 #define SPCI_FL_IRQRESOURCE 0x0400
 
 /* Use the Base address register size to cap number of ports */
 #define SPCI_FL_REGION_SZ_CAP 0x0800
-
+
+/* Do not use irq sharing for this device */
+#define SPCI_FL_NO_SHIRQ 0x1000
+
 #define SPCI_FL_PNPDEFAULT (SPCI_FL_IRQRESOURCE)
-
+
 #endif /* _LINUX_SERIAL_H */
===================================================================
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/03/20 07:56:41 1.1
+++ include/linux/pci_ids.h 2000/03/20 07:57:18
@@ -1052,6 +1052,12 @@
 #define PCI_DEVICE_ID_OXSEMI_16PCI952 0x950A
 #define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
 
+#define PCI_VENDOR_ID_TITAN 0x14D2
+#define PCI_DEVICE_ID_TITAN_100 0xA001
+#define PCI_DEVICE_ID_TITAN_200 0xA005
+#define PCI_DEVICE_ID_TITAN_400 0xA003
+#define PCI_DEVICE_ID_TITAN_800B 0xA004
+
 #define PCI_VENDOR_ID_PANACOM 0x14d4
 #define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
 #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
===================================================================
RCS file: drivers/char/RCS/tty_io.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/tty_io.c
--- drivers/char/tty_io.c 2000/03/20 07:46:46 1.1
+++ drivers/char/tty_io.c 2000/03/20 07:47:13
@@ -2278,9 +2278,6 @@
 #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
         espserial_init();
 #endif
-#ifdef CONFIG_SERIAL
- rs_init();
-#endif
 #if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
         vme_scc_init();
 #endif
--- /dev/null Tue May 5 16:32:27 1998
+++ include/linux/circ_buf.h Mon Mar 20 12:11:37 2000
@@ -0,0 +1,32 @@
+#ifndef _LINUX_CIRC_BUF_H
+#define _LINUX_CIRC_BUF_H 1
+
+struct circ_buf {
+ char *buf;
+ int head;
+ int tail;
+};
+
+/* Return count in buffer. */
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
+
+/* Return space available, 0..size-1. We always leave one free char
+ as a completely full buffer has head == tail, which is the same as
+ empty. */
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
+
+/* Return count up to the end of the buffer. Carefully avoid
+ accessing head and tail more than once, so they can change
+ underneath us without returning inconsistent results. */
+#define CIRC_CNT_TO_END(head,tail,size) \
+ ({int end = (size) - (tail); \
+ int n = ((head) + end) & ((size)-1); \
+ n < end ? n : end;})
+
+/* Return space available up to the end of the buffer. */
+#define CIRC_SPACE_TO_END(head,tail,size) \
+ ({int end = (size) - 1 - (head); \
+ int n = (end + (tail)) & ((size)-1); \
+ n <= end ? n : end+1;})
+
+#endif /* _LINUX_CIRC_BUF_H */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Mar 23 2000 - 21:00:30 EST