* [PATCH] Specialix/IO8
@ 2004-12-08 13:29 Patrick van de Lageweg
0 siblings, 0 replies; only message in thread
From: Patrick van de Lageweg @ 2004-12-08 13:29 UTC (permalink / raw)
To: Linus Torvalds
Cc: Linux Kernel list, Rogier Wolff, Eric Wood, bmckinlay, tmckinlay
[-- Attachment #1: Type: text/plain, Size: 403 bytes --]
Hi,
This patch converts all save_flags/restore_flags to the new
spin_lick_irqsave/spin_unlock_irqrestore calls, as well as some
other 2.6.X cleanups. This allows the "io8+" driver to become
SMP safe.
The large size of this patch comes mostly from the added
debug features.
Signed-off-by: Patrick vd Lageweg <patrick@bitwizard.nl>
Signed-off-by: Rogier Wolff <R.E.Wolff@BitWizard.nl>
Patrick
[-- Attachment #2: patch-08122004-2.6.10-rc3-specialix --]
[-- Type: text/plain, Size: 54058 bytes --]
diff -u -r linux-2.6.10-rc3-clean/drivers/char/Kconfig linux-2.6.10-rc3-specialix/drivers/char/Kconfig
--- linux-2.6.10-rc3-clean/drivers/char/Kconfig Fri Dec 3 15:13:32 2004
+++ linux-2.6.10-rc3-specialix/drivers/char/Kconfig Fri Dec 3 15:19:23 2004
@@ -264,7 +264,7 @@
config SPECIALIX
tristate "Specialix IO8+ card support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
help
This is a driver for the Specialix IO8+ multiport card (both the
ISA and the PCI version) which gives you many serial ports. You
diff -u -r linux-2.6.10-rc3-clean/drivers/char/specialix.c linux-2.6.10-rc3-specialix/drivers/char/specialix.c
--- linux-2.6.10-rc3-clean/drivers/char/specialix.c Fri Dec 3 15:13:33 2004
+++ linux-2.6.10-rc3-specialix/drivers/char/specialix.c Fri Dec 3 15:19:23 2004
@@ -66,7 +66,7 @@
*
*/
-#define VERSION "1.10"
+#define VERSION "1.11"
/*
@@ -99,6 +99,44 @@
#include "cd1865.h"
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile...
+*/
+#define DEBUG
+
+static int sx_debug;
+static int sx_rxfifo = SPECIALIX_RXFIFO;
+
+#ifdef DEBUG
+#define dprintk(f, str...) if (sx_debug & f) printk (str)
+#else
+#define dprintk(f, str...) /* nothing */
+#endif
+
+#define SX_DEBUG_FLOW 0x0001
+#define SX_DEBUG_DATA 0x0002
+#define SX_DEBUG_PROBE 0x0004
+#define SX_DEBUG_CHAN 0x0008
+#define SX_DEBUG_INIT 0x0010
+#define SX_DEBUG_RX 0x0020
+#define SX_DEBUG_TX 0x0040
+#define SX_DEBUG_IRQ 0x0080
+#define SX_DEBUG_OPEN 0x0100
+#define SX_DEBUG_TERMIOS 0x0200
+#define SX_DEBUG_SIGNALS 0x0400
+#define SX_DEBUG_FIFO 0x0800
+
+
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
+#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__)
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
/* Configurable options: */
@@ -110,6 +148,12 @@
requiring attention, the timer doesn't help either. */
#undef SPECIALIX_TIMER
+#ifdef SPECIALIX_TIMER
+static int sx_poll = HZ;
+#endif
+
+
+
/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
@@ -254,11 +298,17 @@
/* Wait for Channel Command Register ready */
static inline void sx_wait_CCR(struct specialix_board * bp)
{
- unsigned long delay;
+ unsigned long delay, flags;
+ unsigned char ccr;
- for (delay = SX_CCR_TIMEOUT; delay; delay--)
- if (!sx_in(bp, CD186x_CCR))
+ for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+ spin_lock_irqsave(&bp->lock, flags);
+ ccr = sx_in(bp, CD186x_CCR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (!ccr)
return;
+ udelay (1);
+ }
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -268,10 +318,17 @@
static inline void sx_wait_CCR_off(struct specialix_board * bp)
{
unsigned long delay;
+ unsigned char crr;
+ unsigned long flags;
- for (delay = SX_CCR_TIMEOUT; delay; delay--)
- if (!sx_in_off(bp, CD186x_CCR))
+ for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+ spin_lock_irqsave(&bp->lock, flags);
+ crr = sx_in_off(bp, CD186x_CCR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (!crr)
return;
+ udelay (1);
+ }
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -319,6 +376,7 @@
{
int virq;
int i;
+ unsigned long flags;
if (bp->flags & SX_BOARD_IS_PCI)
return 1;
@@ -331,11 +389,12 @@
default: printk (KERN_ERR "Speclialix: cannot set irq to %d.\n", bp->irq);
return 0;
}
-
+ spin_lock_irqsave(&bp->lock, flags);
for (i=0;i<2;i++) {
sx_out(bp, CD186x_CAR, i);
sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
}
+ spin_unlock_irqrestore(&bp->lock, flags);
return 1;
}
@@ -346,14 +405,14 @@
unsigned long flags;
int scaler;
int rv = 1;
-
- save_flags(flags); cli();
+ func_enter ();
sx_wait_CCR_off(bp); /* Wait for CCR ready */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_CCR, CCR_HARDRESET); /* Reset CD186x chip */
- sti();
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_long_delay(HZ/20); /* Delay 0.05 sec */
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_GIVR, SX_ID); /* Set ID for this chip */
sx_out_off(bp, CD186x_GICR, 0); /* Clear all bits */
sx_out_off(bp, CD186x_PILR1, SX_ACK_MINT); /* Prio for modem intr */
@@ -367,6 +426,7 @@
sx_out_off(bp, CD186x_PPRH, scaler >> 8);
sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
+ spin_unlock_irqrestore(&bp->lock, flags);
if (!sx_set_irq (bp)) {
/* Figure out how to pass this along... */
@@ -374,7 +434,7 @@
rv = 0;
}
- restore_flags(flags);
+ func_exit ();
return rv;
}
@@ -383,12 +443,16 @@
{
int i;
int t;
+ unsigned long flags;
+ spin_lock_irqsave(&bp->lock, flags);
for (i=0, t=0;i<8;i++) {
sx_out_off (bp, CD186x_CAR, i);
if (sx_in_off (bp, reg) & bit)
t |= 1 << i;
}
+ spin_unlock_irqrestore(&bp->lock, flags);
+
return t;
}
@@ -396,15 +460,22 @@
#ifdef SPECIALIX_TIMER
void missed_irq (unsigned long data)
{
- if (sx_in ((struct specialix_board *)data, CD186x_SRSR) &
+ unsigned char irq;
+ unsigned long flags;
+ struct specialix_board *bp = (struct specialix_board *)data;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ irq = sx_in ((struct specialix_board *)data, CD186x_SRSR) &
(SRSR_RREQint |
SRSR_TREQint |
- SRSR_MREQint)) {
+ SRSR_MREQint);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (irq) {
printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
sx_interrupt (((struct specialix_board *)data)->irq,
- NULL, NULL);
+ (void*)data, NULL);
}
- missed_irq_timer.expires = jiffies + HZ;
+ missed_irq_timer.expires = jiffies + sx_poll;
add_timer (&missed_irq_timer);
}
#endif
@@ -422,8 +493,12 @@
int rev;
int chip;
- if (sx_check_io_range(bp))
+ func_enter ();
+
+ if (sx_check_io_range(bp)) {
+ func_exit ();
return 1;
+ }
/* Are the I/O ports here ? */
sx_out_off(bp, CD186x_PPRL, 0x5a);
@@ -438,6 +513,7 @@
if ((val1 != 0x5a) || (val2 != 0xa5)) {
printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
board_No(bp), bp->base);
+ func_exit ();
return 1;
}
@@ -445,10 +521,9 @@
identification */
val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);
val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
+ dprintk (SX_DEBUG_INIT, "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
board_No(bp), val1, val2);
-#endif
+
/* They managed to switch the bit order between the docs and
the IO8+ card. The new PCI card now conforms to old docs.
They changed the PCI docs to reflect the situation on the
@@ -457,6 +532,7 @@
if (val1 != val2) {
printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
board_No(bp), val2, bp->base, val1);
+ func_exit ();
return 1;
}
@@ -473,21 +549,19 @@
sx_long_delay(HZ/20);
irqs = probe_irq_off(irqs);
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
- printk ( "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
- printk ( "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
- printk ( "GICR = %02x, ", sx_in(bp, CD186x_GICR));
- printk ( "\n");
-#endif
+ dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
+ dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
+ dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
+ dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));
+ dprintk (SX_DEBUG_INIT, "\n");
+
/* Reset CD186x again */
if (!sx_init_CD186x(bp)) {
/* Hmmm. This is dead code anyway. */
}
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG "val1 = %02x, val2 = %02x, val3 = %02x.\n",
+
+ dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",
val1, val2, val3);
-#endif
}
@@ -495,6 +569,7 @@
if (irqs <= 0) {
printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",
board_No(bp), bp->base);
+ func_exit ();
return 1;
}
#endif
@@ -504,6 +579,7 @@
#endif
/* Reset CD186x again */
if (!sx_init_CD186x(bp)) {
+ func_exit ();
return -EIO;
}
@@ -528,15 +604,13 @@
default:chip=-1;rev='x';
}
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
-#endif
+ dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
#ifdef SPECIALIX_TIMER
init_timer (&missed_irq_timer);
missed_irq_timer.function = missed_irq;
missed_irq_timer.data = (unsigned long) bp;
- missed_irq_timer.expires = jiffies + HZ;
+ missed_irq_timer.expires = jiffies + sx_poll;
add_timer (&missed_irq_timer);
#endif
@@ -545,6 +619,7 @@
bp->base, bp->irq,
chip, rev);
+ func_exit ();
return 0;
}
@@ -555,8 +630,12 @@
static inline void sx_mark_event(struct specialix_port * port, int event)
{
+ func_enter ();
+
set_bit(event, &port->event);
schedule_work(&port->tqueue);
+
+ func_exit ();
}
@@ -564,12 +643,17 @@
unsigned char const * what)
{
unsigned char channel;
- struct specialix_port * port;
-
+ struct specialix_port * port = NULL;
+
channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
+ dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
if (channel < CD186x_NCH) {
port = &sx_port[board_No(bp) * SX_NPORT + channel];
+ dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel, port, port->flags & ASYNC_INITIALIZED);
+
if (port->flags & ASYNC_INITIALIZED) {
+ dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
+ func_exit ();
return port;
}
}
@@ -586,43 +670,51 @@
unsigned char status;
unsigned char ch;
- if (!(port = sx_get_port(bp, "Receive")))
- return;
+ func_enter ();
- tty = port->tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
+ port = sx_get_port(bp, "Receive");
+ if (!port) {
+ dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ func_exit ();
return;
}
+ tty = port->tty;
+ dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n",
+ port, tty->flip.count, TTY_FLIPBUF_SIZE);
-#ifdef SX_REPORT_OVERRUN
status = sx_in(bp, CD186x_RCSR);
+
+ dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);
if (status & RCSR_OE) {
port->overrun++;
-#if SPECIALIX_DEBUG
- printk(KERN_DEBUG "sx%d: port %d: Overrun. Total %ld overruns.\n",
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",
board_No(bp), port_No(port), port->overrun);
-#endif
}
status &= port->mark_mask;
-#else
- status = sx_in(bp, CD186x_RCSR) & port->mark_mask;
-#endif
+
+ /* This flip buffer check needs to be below the reading of the
+ status register to reset the chip's IRQ.... */
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
+ board_No(bp), port_No(port));
+ func_exit ();
+ return;
+ }
+
ch = sx_in(bp, CD186x_RDR);
if (!status) {
+ func_exit ();
return;
}
if (status & RCSR_TOUT) {
printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n",
board_No(bp), port_No(port));
+ func_exit ();
return;
} else if (status & RCSR_BREAK) {
-#ifdef SPECIALIX_DEBUG
- printk(KERN_DEBUG "sx%d: port %d: Handling break...\n",
+ dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
-#endif
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
@@ -642,6 +734,8 @@
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
schedule_delayed_work(&tty->flip.work, 1);
+
+ func_exit ();
}
@@ -650,17 +744,19 @@
struct specialix_port *port;
struct tty_struct *tty;
unsigned char count;
+
+ func_enter ();
- if (!(port = sx_get_port(bp, "Receive")))
+ if (!(port = sx_get_port(bp, "Receive"))) {
+ dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ func_exit ();
return;
-
+ }
tty = port->tty;
count = sx_in(bp, CD186x_RDCR);
-
-#ifdef SX_REPORT_FIFO
+ dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
port->hits[count > 8 ? 9 : count]++;
-#endif
while (count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -673,6 +769,8 @@
tty->flip.count++;
}
schedule_delayed_work(&tty->flip.work, 1);
+
+ func_exit ();
}
@@ -681,11 +779,13 @@
struct specialix_port *port;
struct tty_struct *tty;
unsigned char count;
-
-
- if (!(port = sx_get_port(bp, "Transmit")))
+
+ func_enter ();
+ if (!(port = sx_get_port(bp, "Transmit"))) {
+ func_exit ();
return;
-
+ }
+ dprintk (SX_DEBUG_TX, "port: %p\n", port);
tty = port->tty;
if (port->IER & IER_TXEMPTY) {
@@ -693,6 +793,7 @@
sx_out(bp, CD186x_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
sx_out(bp, CD186x_IER, port->IER);
+ func_exit ();
return;
}
@@ -701,6 +802,7 @@
sx_out(bp, CD186x_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
sx_out(bp, CD186x_IER, port->IER);
+ func_exit ();
return;
}
@@ -725,6 +827,8 @@
sx_out(bp, CD186x_CCR, CCR_CORCHG2);
port->break_length = 0;
}
+
+ func_exit ();
return;
}
@@ -743,6 +847,8 @@
}
if (port->xmit_cnt <= port->wakeup_chars)
sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+
+ func_exit ();
}
@@ -751,10 +857,9 @@
struct specialix_port *port;
struct tty_struct *tty;
unsigned char mcr;
-
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "Modem intr. ");
-#endif
+ int msvr_cd;
+
+ dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");
if (!(port = sx_get_port(bp, "Modem")))
return;
@@ -764,18 +869,13 @@
printk ("mcr = %02x.\n", mcr);
if ((mcr & MCR_CDCHG)) {
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "CD just changed... ");
-#endif
- if (sx_in(bp, CD186x_MSVR) & MSVR_CD) {
-#ifdef SPECIALIX_DEBUG
- printk ( "Waking up guys in open.\n");
-#endif
+ dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");
+ msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
+ if (msvr_cd) {
+ dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
wake_up_interruptible(&port->open_wait);
} else {
-#ifdef SPECIALIX_DEBUG
- printk ( "Sending HUP.\n");
-#endif
+ dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
schedule_work(&port->tqueue_hangup);
}
}
@@ -820,13 +920,18 @@
struct specialix_board *bp;
unsigned long loop = 0;
int saved_reg;
+ unsigned long flags;
+
+ func_enter ();
bp = dev_id;
-
+ spin_lock_irqsave(&bp->lock, flags);
+
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "sx: False interrupt. irq %d.\n", irq);
-#endif
+ dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit ();
return IRQ_NONE;
}
@@ -844,8 +949,8 @@
else if (ack == (SX_ID | GIVR_IT_REXC))
sx_receive_exc(bp);
else
- printk(KERN_ERR "sx%d: Bad receive ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
+ board_No(bp), status, ack);
} else if (status & SRSR_TREQint) {
ack = sx_in(bp, CD186x_TRAR);
@@ -853,16 +958,16 @@
if (ack == (SX_ID | GIVR_IT_TX))
sx_transmit(bp);
else
- printk(KERN_ERR "sx%d: Bad transmit ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
+ board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));
} else if (status & SRSR_MREQint) {
ack = sx_in(bp, CD186x_MRAR);
if (ack == (SX_ID | GIVR_IT_MODEM))
sx_check_modem(bp);
else
- printk(KERN_ERR "sx%d: Bad modem ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
+ board_No(bp), status, ack);
}
@@ -870,6 +975,8 @@
}
bp->reg = saved_reg;
outb (bp->reg, bp->base + SX_ADDR_REG);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit ();
return IRQ_HANDLED;
}
@@ -880,21 +987,37 @@
void turn_ints_off (struct specialix_board *bp)
{
+ unsigned long flags;
+ func_enter ();
+
if (bp->flags & SX_BOARD_IS_PCI) {
/* This was intended for enabeling the interrupt on the
* PCI card. However it seems that it's already enabled
* and as PCI interrupts can be shared, there is no real
* reason to have to turn it off. */
}
+
+ spin_lock_irqsave(&bp->lock, flags);
(void) sx_in_off (bp, 0); /* Turn off interrupts. */
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit ();
}
void turn_ints_on (struct specialix_board *bp)
{
+ unsigned long flags;
+
+ func_enter ();
+
if (bp->flags & SX_BOARD_IS_PCI) {
/* play with the PCI chip. See comment above. */
}
+ spin_lock_irqsave(&bp->lock, flags);
(void) sx_in (bp, 0); /* Turn ON interrupts. */
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit ();
}
@@ -924,18 +1047,23 @@
/* Called with disabled interrupts */
static inline void sx_shutdown_board(struct specialix_board *bp)
{
- if (!(bp->flags & SX_BOARD_ACTIVE))
+ func_enter ();
+
+ if (!(bp->flags & SX_BOARD_ACTIVE)) {
+ func_exit ();
return;
-
+ }
+
bp->flags &= ~SX_BOARD_ACTIVE;
-#if SPECIALIX_DEBUG > 2
- printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
-#endif
+ dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
+ bp->irq, board_No (bp));
free_irq(bp->irq, bp);
turn_ints_off (bp);
+
+ func_exit ();
}
@@ -951,13 +1079,19 @@
unsigned char cor1 = 0, cor3 = 0;
unsigned char mcor1 = 0, mcor2 = 0;
static unsigned long again;
-
- if (!(tty = port->tty) || !tty->termios)
+ unsigned long flags;
+
+ func_enter ();
+
+ if (!(tty = port->tty) || !tty->termios) {
+ func_exit ();
return;
+ }
port->IER = 0;
port->COR2 = 0;
/* Select port on the board */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
/* The Specialix board doens't implement the RTS lines.
@@ -966,9 +1100,8 @@
port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
else
port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "sx: got MSVR=%02x.\n", port->MSVR);
-#endif
+ spin_unlock_irqrestore(&bp->lock, flags);
+ dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
@@ -988,17 +1121,15 @@
if (!baud_table[baud]) {
/* Drop DTR & exit */
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "Dropping DTR... Hmm....\n");
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
if (!SX_CRTSCTS (tty)) {
port -> MSVR &= ~ MSVR_DTR;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR );
+ spin_unlock_irqrestore(&bp->lock, flags);
}
-#ifdef DEBUG_SPECIALIX
else
- printk (KERN_DEBUG "Can't drop DTR: no DTR.\n");
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
return;
} else {
/* Set DTR on */
@@ -1037,12 +1168,12 @@
port_No (port), tmp);
}
}
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff);
sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff);
sx_out(bp, CD186x_RBPRL, tmp & 0xff);
sx_out(bp, CD186x_TBPRL, tmp & 0xff);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
if (port->custom_divisor) {
baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
baud = ( baud + 5 ) / 10;
@@ -1057,8 +1188,9 @@
/* Receiver timeout will be transmission time for 1.5 chars */
tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud;
tmp = (tmp > 0xff) ? 0xff : tmp;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_RTPR, tmp);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
switch (C_CSIZE(tty)) {
case CS5:
cor1 |= COR1_5BITS;
@@ -1105,7 +1237,9 @@
port->IER |= IER_DSR | IER_CTS;
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
+ spin_lock_irqsave(&bp->lock, flags);
tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR));
+ spin_unlock_irqrestore(&bp->lock, flags);
#else
port->COR2 |= COR2_CTSAE;
#endif
@@ -1117,10 +1251,12 @@
cor3 |= (COR3_FCT | COR3_SCDE);
if (I_IXANY(tty))
port->COR2 |= COR2_IXM;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_SCHR1, START_CHAR(tty));
sx_out(bp, CD186x_SCHR2, STOP_CHAR(tty));
sx_out(bp, CD186x_SCHR3, START_CHAR(tty));
sx_out(bp, CD186x_SCHR4, STOP_CHAR(tty));
+ spin_unlock_irqrestore(&bp->lock, flags);
}
if (!C_CLOCAL(tty)) {
/* Enable CD check */
@@ -1134,27 +1270,33 @@
port->IER |= IER_RXD;
/* Set input FIFO size (1-8 bytes) */
- cor3 |= SPECIALIX_RXFIFO;
+ cor3 |= sx_rxfifo;
/* Setting up CD186x channel registers */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_COR1, cor1);
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_COR3, cor3);
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Make CD186x know about registers change */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
/* Setting up modem option registers */
-#ifdef DEBUG_SPECIALIX
- printk ("Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
sx_out(bp, CD186x_MCOR1, mcor1);
sx_out(bp, CD186x_MCOR2, mcor2);
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Enable CD186x transmitter & receiver */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN);
/* Enable interrupts */
sx_out(bp, CD186x_IER, port->IER);
/* And finally set the modem lines... */
sx_out(bp, CD186x_MSVR, port->MSVR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit ();
}
@@ -1162,37 +1304,44 @@
static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port)
{
unsigned long flags;
-
- if (port->flags & ASYNC_INITIALIZED)
+
+ func_enter ();
+
+ if (port->flags & ASYNC_INITIALIZED) {
+ func_exit ();
return 0;
+ }
if (!port->xmit_buf) {
/* We may sleep in get_zeroed_page() */
unsigned long tmp;
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
+ if (!(tmp = get_zeroed_page(GFP_KERNEL))) {
+ func_exit ();
return -ENOMEM;
+ }
if (port->xmit_buf) {
free_page(tmp);
+ func_exit ();
return -ERESTARTSYS;
}
port->xmit_buf = (unsigned char *) tmp;
}
- save_flags(flags); cli();
-
+ spin_lock_irqsave(&port->lock, flags);
+
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
- if (port->count == 1)
- bp->count++;
-
+
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
sx_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
- restore_flags(flags);
+ func_exit ();
return 0;
}
@@ -1201,62 +1350,54 @@
static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *port)
{
struct tty_struct *tty;
+ int i;
+ unsigned long flags;
- if (!(port->flags & ASYNC_INITIALIZED))
+ func_enter ();
+
+ if (!(port->flags & ASYNC_INITIALIZED)) {
+ func_exit ();
return;
+ }
-#ifdef SX_REPORT_OVERRUN
- printk(KERN_INFO "sx%d: port %d: Total %ld overruns were detected.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
-#ifdef SX_REPORT_FIFO
- {
- int i;
-
- printk(KERN_INFO "sx%d: port %d: FIFO hits [ ",
- board_No(bp), port_No(port));
+ if (sx_debug & SX_DEBUG_FIFO) {
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ",
+ board_No(bp), port_No(port), port->overrun);
for (i = 0; i < 10; i++) {
- printk("%ld ", port->hits[i]);
+ dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
}
- printk("].\n");
+ dprintk(SX_DEBUG_FIFO, "].\n");
}
-#endif
+
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
}
/* Select port */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
if (!(tty = port->tty) || C_HUPCL(tty)) {
/* Drop DTR */
sx_out(bp, CD186x_MSVDTR, 0);
}
-
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Reset port */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SOFTRESET);
/* Disable all interrupts from this port */
port->IER = 0;
sx_out(bp, CD186x_IER, port->IER);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
port->flags &= ~ASYNC_INITIALIZED;
- if (--bp->count < 0) {
- printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d\n",
- board_No(bp), bp->count);
- bp->count = 0;
- }
-
- /*
- * If this is the last opened port on the board
- * shutdown whole board
- */
if (!bp->count)
sx_shutdown_board(bp);
+ func_exit ();
}
@@ -1268,6 +1409,9 @@
int retval;
int do_clocal = 0;
int CD;
+ unsigned long flags;
+
+ func_enter ();
/*
* If the device is in the middle of being closed, then block
@@ -1275,10 +1419,13 @@
*/
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&port->close_wait);
- if (port->flags & ASYNC_HUP_NOTIFY)
+ if (port->flags & ASYNC_HUP_NOTIFY) {
+ func_exit ();
return -EAGAIN;
- else
+ } else {
+ func_exit ();
return -ERESTARTSYS;
+ }
}
/*
@@ -1288,6 +1435,7 @@
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit ();
return 0;
}
@@ -1303,13 +1451,14 @@
*/
retval = 0;
add_wait_queue(&port->open_wait, &wait);
- cli();
- if (!tty_hung_up_p(filp))
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp)) {
port->count--;
- sti();
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
port->blocked_open++;
while (1) {
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
if (SX_CRTSCTS (tty)) {
@@ -1320,8 +1469,8 @@
/* Activate DTR */
port->MSVR |= MSVR_DTR;
sx_out (bp, CD186x_MSVR, port->MSVR);
- }
- sti();
+ }
+ spin_unlock_irqrestore(&bp->lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
@@ -1340,15 +1489,22 @@
}
schedule();
}
- current->state = TASK_RUNNING;
+
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp)) {
port->count++;
+ }
port->blocked_open--;
- if (retval)
+ spin_unlock_irqrestore(&port->lock, flags);
+ if (retval) {
+ func_exit ();
return retval;
-
+ }
+
port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit ();
return 0;
}
@@ -1359,36 +1515,55 @@
int error;
struct specialix_port * port;
struct specialix_board * bp;
-
+ int i;
+ unsigned long flags;
+
+ func_enter ();
+
board = SX_BOARD(tty->index);
- if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT))
+ if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) {
+ func_exit ();
return -ENODEV;
+ }
bp = &sx_board[board];
port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
+ port->overrun = 0;
+ for (i = 0; i < 10; i++)
+ port->hits[i]=0;
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n",
+ dprintk (SX_DEBUG_OPEN, "Board = %d, bp = %p, port = %p, portno = %d.\n",
board, bp, port, SX_PORT(tty->index));
-#endif
- if (sx_paranoia_check(port, tty->name, "sx_open"))
+ if (sx_paranoia_check(port, tty->name, "sx_open")) {
+ func_enter ();
return -ENODEV;
+ }
- if ((error = sx_setup_board(bp)))
+ if ((error = sx_setup_board(bp))) {
+ func_exit ();
return error;
+ }
+ spin_lock_irqsave(&bp->lock, flags);
port->count++;
+ bp->count++;
tty->driver_data = port;
port->tty = tty;
+ spin_unlock_irqrestore(&bp->lock, flags);
- if ((error = sx_setup_port(bp, port)))
+ if ((error = sx_setup_port(bp, port))) {
+ func_enter ();
return error;
+ }
- if ((error = block_til_ready(tty, filp, port)))
+ if ((error = block_til_ready(tty, filp, port))) {
+ func_enter ();
return error;
+ }
+ func_exit ();
return 0;
}
@@ -1400,12 +1575,16 @@
unsigned long flags;
unsigned long timeout;
- if (!port || sx_paranoia_check(port, tty->name, "close"))
+ func_enter ();
+ if (!port || sx_paranoia_check(port, tty->name, "close")) {
+ func_exit ();
return;
-
- save_flags(flags); cli();
+ }
+ spin_lock_irqsave(&port->lock, flags);
+
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+ func_exit ();
return;
}
@@ -1416,13 +1595,14 @@
board_No(bp), port->count);
port->count = 1;
}
- if (--port->count < 0) {
- printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
- board_No(bp), port_No(port), port->count);
- port->count = 0;
- }
- if (port->count) {
- restore_flags(flags);
+
+ if (port->count > 1) {
+ port->count--;
+ bp->count--;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit ();
return;
}
port->flags |= ASYNC_CLOSING;
@@ -1431,20 +1611,26 @@
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ spin_unlock_irqrestore(&port->lock, flags);
+ dprintk (SX_DEBUG_OPEN, "Closing\n");
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
tty_wait_until_sent(tty, port->closing_wait);
+ }
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
* interrupt driver to stop checking the data ready bit in the
* line status register.
*/
+ dprintk (SX_DEBUG_OPEN, "Closed\n");
port->IER &= ~IER_RXD;
if (port->flags & ASYNC_INITIALIZED) {
port->IER &= ~IER_TXRDY;
port->IER |= IER_TXEMPTY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@@ -1452,6 +1638,7 @@
*/
timeout = jiffies+HZ;
while(port->IER & IER_TXEMPTY) {
+ set_current_state (TASK_INTERRUPTIBLE);
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout)) {
printk (KERN_INFO "Timeout waiting for close\n");
@@ -1460,13 +1647,27 @@
}
}
+
+ if (--bp->count < 0) {
+ printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
+ bp->count = 0;
+ }
+ if (--port->count < 0) {
+ printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
+ board_No(bp), port_No(port), port->count);
+ port->count = 0;
+ }
+
sx_shutdown_port(bp, port);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
+ spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
port->event = 0;
port->tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
if (port->blocked_open) {
if (port->close_delay) {
msleep_interruptible(jiffies_to_msecs(port->close_delay));
@@ -1475,7 +1676,8 @@
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
+
+ func_exit ();
}
@@ -1486,42 +1688,48 @@
struct specialix_board *bp;
int c, total = 0;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_write"))
+
+ func_enter ();
+ if (sx_paranoia_check(port, tty->name, "sx_write")) {
+ func_exit ();
return 0;
+ }
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf)
+ if (!tty || !port->xmit_buf || !tmp_buf) {
+ func_exit ();
return 0;
+ }
- save_flags(flags);
while (1) {
- cli();
+ spin_lock_irqsave(&port->lock, flags);
c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
SERIAL_XMIT_SIZE - port->xmit_head));
if (c <= 0) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
break;
}
memcpy(port->xmit_buf + port->xmit_head, buf, c);
port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
port->xmit_cnt += c;
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
buf += c;
count -= c;
total += c;
}
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit ();
+
return total;
}
@@ -1530,24 +1738,36 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
+ struct specialix_board * bp;
+
+ func_enter ();
- if (sx_paranoia_check(port, tty->name, "sx_put_char"))
+ if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
+ func_exit ();
return;
-
- if (!tty || !port->xmit_buf)
+ }
+ dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
+ if (!tty || !port->xmit_buf) {
+ func_exit ();
return;
+ }
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
- save_flags(flags); cli();
-
- if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
+ dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf);
+ if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ dprintk (SX_DEBUG_TX, "Exit size\n");
+ func_exit ();
return;
}
-
+ dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit ();
}
@@ -1555,19 +1775,26 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_chars"))
+ struct specialix_board * bp = port_Board(port);
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) {
+ func_exit ();
return;
-
+ }
if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !port->xmit_buf)
+ !port->xmit_buf) {
+ func_exit ();
return;
-
- save_flags(flags); cli();
+ }
+ spin_lock_irqsave(&bp->lock, flags);
port->IER |= IER_TXRDY;
sx_out(port_Board(port), CD186x_CAR, port_No(port));
sx_out(port_Board(port), CD186x_IER, port->IER);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit ();
}
@@ -1575,13 +1802,19 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
int ret;
-
- if (sx_paranoia_check(port, tty->name, "sx_write_room"))
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_write_room")) {
+ func_exit ();
return 0;
+ }
ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
if (ret < 0)
ret = 0;
+
+ func_exit ();
return ret;
}
@@ -1589,10 +1822,14 @@
static int sx_chars_in_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
-
- if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer"))
- return 0;
+
+ func_enter ();
+ if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) {
+ func_exit ();
+ return 0;
+ }
+ func_exit ();
return port->xmit_cnt;
}
@@ -1601,16 +1838,22 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_buffer"))
+ struct specialix_board * bp;
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+ func_exit ();
return;
+ }
- save_flags(flags); cli();
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&port->lock, flags);
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
+
+ func_exit ();
}
@@ -1622,19 +1865,21 @@
unsigned int result;
unsigned long flags;
- if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ func_exit ();
return -ENODEV;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave (&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
status = sx_in(bp, CD186x_MSVR);
- restore_flags(flags);
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "Got msvr[%d] = %02x, car = %d.\n",
+ spin_unlock_irqrestore(&bp->lock, flags);
+ dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
port_No(port), status, sx_in (bp, CD186x_CAR));
- printk (KERN_DEBUG "sx_port = %p, port = %p\n", sx_port, port);
-#endif
+ dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
if (SX_CRTSCTS(port->tty)) {
result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */
| ((status & MSVR_DTR) ? TIOCM_RTS : 0)
@@ -1649,6 +1894,8 @@
| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
}
+ func_exit ();
+
return result;
}
@@ -1660,12 +1907,16 @@
unsigned long flags;
struct specialix_board *bp;
- if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ func_exit ();
return -ENODEV;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
/* if (set & TIOCM_RTS)
port->MSVR |= MSVR_RTS; */
/* if (set & TIOCM_DTR)
@@ -1690,10 +1941,12 @@
if (clear & TIOCM_DTR)
port->MSVR &= ~MSVR_DTR;
}
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+ func_exit ();
return 0;
}
@@ -1703,17 +1956,25 @@
struct specialix_board *bp = port_Board(port);
unsigned long flags;
- save_flags(flags); cli();
+ func_enter ();
+
+ spin_lock_irqsave (&port->lock, flags);
port->break_length = SPECIALIX_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore (&port->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG2);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
- restore_flags(flags);
+
+ func_exit ();
}
@@ -1723,10 +1984,19 @@
struct serial_struct tmp;
struct specialix_board *bp = port_Board(port);
int change_speed;
- unsigned long flags;
-
- if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+
+ func_enter ();
+ /*
+ error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
+ if (error) {
+ func_exit ();
+ return error;
+ }
+ */
+ if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
+ func_enter ();
return -EFAULT;
+ }
#if 0
if ((tmp.irq != bp->irq) ||
@@ -1735,8 +2005,10 @@
(tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
(tmp.custom_divisor != 0) ||
(tmp.xmit_fifo_size != CD186x_NFIFO) ||
- (tmp.flags & ~SPECIALIX_LEGAL_FLAGS))
+ (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
+ func_exit ();
return -EINVAL;
+ }
#endif
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
@@ -1747,8 +2019,10 @@
if ((tmp.close_delay != port->close_delay) ||
(tmp.closing_wait != port->closing_wait) ||
((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK))) {
+ func_exit ();
return -EPERM;
+ }
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(tmp.flags & ASYNC_USR_MASK));
port->custom_divisor = tmp.custom_divisor;
@@ -1760,10 +2034,9 @@
port->custom_divisor = tmp.custom_divisor;
}
if (change_speed) {
- save_flags(flags); cli();
sx_change_speed(bp, port);
- restore_flags(flags);
}
+ func_exit ();
return 0;
}
@@ -1773,7 +2046,16 @@
{
struct serial_struct tmp;
struct specialix_board *bp = port_Board(port);
+ // int error;
+ func_enter ();
+
+ /*
+ error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
+ if (error)
+ return error;
+ */
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.line = port - sx_port;
@@ -1785,8 +2067,12 @@
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.custom_divisor = port->custom_divisor;
tmp.xmit_fifo_size = CD186x_NFIFO;
- if (copy_to_user(retinfo, &tmp, sizeof(tmp)))
+ if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
+ func_exit ();
return -EFAULT;
+ }
+
+ func_exit ();
return 0;
}
@@ -1797,44 +2083,63 @@
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
int retval;
void __user *argp = (void __user *)arg;
-
- if (sx_paranoia_check(port, tty->name, "sx_ioctl"))
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_ioctl")) {
+ func_exit ();
return -ENODEV;
+ }
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
- if (retval)
+ if (retval) {
+ func_exit ();
return retval;
+ }
tty_wait_until_sent(tty, 0);
if (!arg)
sx_send_break(port, HZ/4); /* 1/4 second */
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
- if (retval)
+ if (retval) {
+ func_exit ();
return retval;
+ }
tty_wait_until_sent(tty, 0);
sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
+ func_exit ();
return 0;
case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp))
- return -EFAULT;
+ if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
+ func_exit ();
+ return -EFAULT;
+ }
+ func_exit ();
return 0;
case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
+ if (get_user(arg, (unsigned long __user *) argp)) {
+ func_exit ();
+ return -EFAULT;
+ }
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
+ func_exit ();
return 0;
- case TIOCGSERIAL:
+ case TIOCGSERIAL:
+ func_exit ();
return sx_get_serial_info(port, argp);
case TIOCSSERIAL:
+ func_exit ();
return sx_set_serial_info(port, argp);
default:
+ func_exit ();
return -ENOIOCTLCMD;
}
+ func_exit ();
return 0;
}
@@ -1844,14 +2149,16 @@
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_throttle"))
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_throttle")) {
+ func_exit ();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
-
/* Use DTR instead of RTS ! */
if (SX_CRTSCTS (tty))
port->MSVR &= ~MSVR_DTR;
@@ -1863,14 +2170,22 @@
printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",
port_No (port));
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
+ spin_unlock_irqrestore(&bp->lock, flags);
if (I_IXOFF(tty)) {
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SSCH2);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit ();
}
@@ -1879,26 +2194,39 @@
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
+
+ func_enter ();
- if (sx_paranoia_check(port, tty->name, "sx_unthrottle"))
+ if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {
+ func_exit ();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
/* XXXX Use DTR INSTEAD???? */
if (SX_CRTSCTS(tty)) {
port->MSVR |= MSVR_DTR;
} /* Else clause: see remark in "sx_throttle"... */
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
+ spin_unlock_irqrestore(&bp->lock, flags);
if (I_IXOFF(tty)) {
+ spin_unlock_irqrestore(&port->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SSCH1);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&port->lock, flags);
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit ();
}
@@ -1907,17 +2235,25 @@
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_stop"))
- return;
+
+ func_enter ();
+ if (sx_paranoia_check(port, tty->name, "sx_stop")) {
+ func_exit ();
+ return;
+ }
+
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
port->IER &= ~IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit ();
}
@@ -1926,19 +2262,27 @@
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
+
+ func_enter ();
- if (sx_paranoia_check(port, tty->name, "sx_start"))
+ if (sx_paranoia_check(port, tty->name, "sx_start")) {
+ func_exit ();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit ();
}
@@ -1956,9 +2300,13 @@
struct specialix_port *port = (struct specialix_port *) private_;
struct tty_struct *tty;
+ func_enter ();
+
tty = port->tty;
if (tty)
tty_hangup(tty); /* FIXME: module removal race here */
+
+ func_exit ();
}
@@ -1966,18 +2314,33 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
-
- if (sx_paranoia_check(port, tty->name, "sx_hangup"))
+ unsigned long flags;
+
+ func_enter ();
+
+ if (sx_paranoia_check(port, tty->name, "sx_hangup")) {
+ func_exit ();
return;
+ }
bp = port_Board(port);
sx_shutdown_port(bp, port);
+ spin_lock_irqsave(&port->lock, flags);
port->event = 0;
+ bp->count -= port->count;
+ if (bp->count < 0) {
+ printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
+ bp->count = 0;
+ }
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
port->tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
+
+ func_exit ();
}
@@ -1985,6 +2348,7 @@
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
+ struct specialix_board * bp;
if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
return;
@@ -1993,9 +2357,10 @@
tty->termios->c_iflag == old_termios->c_iflag)
return;
- save_flags(flags); cli();
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
sx_change_speed(port_Board(port), port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2009,12 +2374,20 @@
{
struct specialix_port *port = (struct specialix_port *) private_;
struct tty_struct *tty;
-
- if(!(tty = port->tty))
+
+ func_enter ();
+
+ if(!(tty = port->tty)) {
+ func_exit ();
return;
+ }
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
- tty_wakeup(tty);
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ tty_wakeup(tty);
+ //wake_up_interruptible(&tty->write_wait);
+ }
+
+ func_exit ();
}
static struct tty_operations sx_ops = {
@@ -2042,15 +2415,19 @@
int error;
int i;
+ func_enter ();
+
specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);
if (!specialix_driver) {
printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");
+ func_exit ();
return 1;
}
if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
printk(KERN_ERR "sx: Couldn't get free page.\n");
put_tty_driver(specialix_driver);
+ func_exit ();
return 1;
}
specialix_driver->owner = THIS_MODULE;
@@ -2069,6 +2446,7 @@
free_page((unsigned long)tmp_buf);
printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
error);
+ func_exit ();
return 1;
}
memset(sx_port, 0, sizeof(sx_port));
@@ -2080,17 +2458,23 @@
sx_port[i].closing_wait = 3000 * HZ/100;
init_waitqueue_head(&sx_port[i].open_wait);
init_waitqueue_head(&sx_port[i].close_wait);
+ sx_port[i].lock = SPIN_LOCK_UNLOCKED;
}
+ func_exit ();
return 0;
}
static void sx_release_drivers(void)
{
+ func_enter ();
+
free_page((unsigned long)tmp_buf);
tty_unregister_driver(specialix_driver);
put_tty_driver(specialix_driver);
+
+ func_exit ();
}
@@ -2108,6 +2492,8 @@
{
int i;
+ func_enter ();
+
for (i=0;i<SX_NBOARD;i++) {
sx_board[i].base = 0;
}
@@ -2118,6 +2504,8 @@
else
sx_board[i/2 -1].irq = ints[i];
}
+
+ func_exit ();
}
#endif
@@ -2129,6 +2517,8 @@
int i;
int found = 0;
+ func_enter ();
+
printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
#ifdef CONFIG_SPECIALIX_RTSCTS
@@ -2137,8 +2527,13 @@
printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
#endif
- if (sx_init_drivers())
+ for (i = 0; i < SX_NBOARD; i++)
+ sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+
+ if (sx_init_drivers()) {
+ func_exit ();
return -EIO;
+ }
for (i = 0; i < SX_NBOARD; i++)
if (sx_board[i].base && !sx_probe(&sx_board[i]))
@@ -2176,9 +2571,11 @@
if (!found) {
sx_release_drivers();
printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
+ func_exit ();
return -EIO;
}
+ func_exit ();
return 0;
}
@@ -2188,6 +2585,11 @@
module_param_array(iobase, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_rxfifo, int, 0);
+#ifdef SPECIALIX_TIMER
+module_param(sx_poll, int, 0);
+#endif
/*
* You can setup up to 4 boards.
@@ -2202,13 +2604,20 @@
{
int i;
+ func_enter ();
+
+ init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
+
if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
for(i = 0; i < SX_NBOARD; i++) {
sx_board[i].base = iobase[i];
sx_board[i].irq = irq[i];
+ sx_board[i].count= 0;
}
}
+ func_exit ();
+
return specialix_init();
}
@@ -2216,6 +2625,8 @@
{
int i;
+ func_enter ();
+
sx_release_drivers();
for (i = 0; i < SX_NBOARD; i++)
if (sx_board[i].flags & SX_BOARD_PRESENT)
@@ -2223,7 +2634,8 @@
#ifdef SPECIALIX_TIMER
del_timer (&missed_irq_timer);
#endif
-
+
+ func_exit ();
}
module_init(specialix_init_module);
diff -u -r linux-2.6.10-rc3-clean/drivers/char/specialix_io8.h linux-2.6.10-rc3-specialix/drivers/char/specialix_io8.h
--- linux-2.6.10-rc3-clean/drivers/char/specialix_io8.h Sat Aug 14 07:36:10 2004
+++ linux-2.6.10-rc3-specialix/drivers/char/specialix_io8.h Fri Dec 3 15:19:23 2004
@@ -93,9 +93,11 @@
unsigned long flags;
unsigned short base;
unsigned char irq;
- signed char count;
+ //signed char count;
+ int count;
unsigned char DTR;
int reg;
+ spinlock_t lock;
};
#define SX_BOARD_PRESENT 0x00000001
@@ -129,12 +131,9 @@
unsigned char IER;
unsigned char MSVR;
unsigned char COR2;
-#ifdef SX_REPORT_OVERRUN
unsigned long overrun;
-#endif
-#ifdef SX_REPORT_FIFO
unsigned long hits[10];
-#endif
+ spinlock_t lock;
};
#endif /* __KERNEL__ */
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2004-12-08 13:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-12-08 13:29 [PATCH] Specialix/IO8 Patrick van de Lageweg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.