Commit ec567d00 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] Ressurrect the esp serial driver

Another first pass rescue run.  Fix up for modern locking, make it build
and check over.  It could still do with other fixes (sleep_on etc) but it's
a start
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0043c15d
...@@ -129,8 +129,6 @@ static struct tty_driver *esp_driver; ...@@ -129,8 +129,6 @@ static struct tty_driver *esp_driver;
#undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_FLOW
#define _INLINE_ inline
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s) tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s)
...@@ -211,15 +209,14 @@ static void rs_stop(struct tty_struct *tty) ...@@ -211,15 +209,14 @@ static void rs_stop(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_stop")) if (serial_paranoia_check(info, tty->name, "rs_stop"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->IER & UART_IER_THRI) { if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI; info->IER &= ~UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
} }
spin_unlock_irqrestore(&info->lock, flags);
restore_flags(flags);
} }
static void rs_start(struct tty_struct *tty) static void rs_start(struct tty_struct *tty)
...@@ -230,13 +227,13 @@ static void rs_start(struct tty_struct *tty) ...@@ -230,13 +227,13 @@ static void rs_start(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_start")) if (serial_paranoia_check(info, tty->name, "rs_start"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI; info->IER |= UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
/* /*
...@@ -264,34 +261,41 @@ static void rs_start(struct tty_struct *tty) ...@@ -264,34 +261,41 @@ static void rs_start(struct tty_struct *tty)
* This routine is used by the interrupt handler to schedule * This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver. * processing in the software interrupt portion of the driver.
*/ */
static _INLINE_ void rs_sched_event(struct esp_struct *info, static inline void rs_sched_event(struct esp_struct *info,
int event) int event)
{ {
info->event |= 1 << event; info->event |= 1 << event;
schedule_work(&info->tqueue); schedule_work(&info->tqueue);
} }
static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void) static DEFINE_SPINLOCK(pio_lock);
static inline struct esp_pio_buffer *get_pio_buffer(void)
{ {
struct esp_pio_buffer *buf; struct esp_pio_buffer *buf;
unsigned long flags;
spin_lock_irqsave(&pio_lock, flags);
if (free_pio_buf) { if (free_pio_buf) {
buf = free_pio_buf; buf = free_pio_buf;
free_pio_buf = buf->next; free_pio_buf = buf->next;
} else { } else {
buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC);
} }
spin_unlock_irqrestore(&pio_lock, flags);
return buf; return buf;
} }
static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf) static inline void release_pio_buffer(struct esp_pio_buffer *buf)
{ {
unsigned long flags;
spin_lock_irqsave(&pio_lock, flags);
buf->next = free_pio_buf; buf->next = free_pio_buf;
free_pio_buf = buf; free_pio_buf = buf;
spin_unlock_irqrestore(&pio_lock, flags);
} }
static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
{ {
struct tty_struct *tty = info->tty; struct tty_struct *tty = info->tty;
int i; int i;
...@@ -311,8 +315,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) ...@@ -311,8 +315,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
return; return;
} }
sti();
status_mask = (info->read_status_mask >> 2) & 0x07; status_mask = (info->read_status_mask >> 2) & 0x07;
for (i = 0; i < num_bytes - 1; i += 2) { for (i = 0; i < num_bytes - 1; i += 2) {
...@@ -329,8 +331,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) ...@@ -329,8 +331,6 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
(serial_in(info, UART_ESI_RWS) >> 3) & status_mask; (serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
} }
cli();
/* make sure everything is still ok since interrupts were enabled */ /* make sure everything is still ok since interrupts were enabled */
tty = info->tty; tty = info->tty;
...@@ -371,7 +371,7 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) ...@@ -371,7 +371,7 @@ static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
release_pio_buffer(err_buf); release_pio_buffer(err_buf);
} }
static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
{ {
unsigned long flags; unsigned long flags;
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
...@@ -390,7 +390,7 @@ static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) ...@@ -390,7 +390,7 @@ static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
} }
static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, static inline void receive_chars_dma_done(struct esp_struct *info,
int status) int status)
{ {
struct tty_struct *tty = info->tty; struct tty_struct *tty = info->tty;
...@@ -450,7 +450,9 @@ static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, ...@@ -450,7 +450,9 @@ static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
dma_bytes = 0; dma_bytes = 0;
} }
static _INLINE_ void transmit_chars_pio(struct esp_struct *info, /* Caller must hold info->lock */
static inline void transmit_chars_pio(struct esp_struct *info,
int space_avail) int space_avail)
{ {
int i; int i;
...@@ -478,8 +480,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info, ...@@ -478,8 +480,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
info->xmit_tail = (info->xmit_tail + space_avail) & info->xmit_tail = (info->xmit_tail + space_avail) &
(ESP_XMIT_SIZE - 1); (ESP_XMIT_SIZE - 1);
sti();
for (i = 0; i < space_avail - 1; i += 2) { for (i = 0; i < space_avail - 1; i += 2) {
outw(*((unsigned short *)(pio_buf->data + i)), outw(*((unsigned short *)(pio_buf->data + i)),
info->port + UART_ESI_TX); info->port + UART_ESI_TX);
...@@ -489,8 +489,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info, ...@@ -489,8 +489,6 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
serial_out(info, UART_ESI_TX, serial_out(info, UART_ESI_TX,
pio_buf->data[space_avail - 1]); pio_buf->data[space_avail - 1]);
cli();
if (info->xmit_cnt) { if (info->xmit_cnt) {
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
...@@ -520,7 +518,8 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info, ...@@ -520,7 +518,8 @@ static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
release_pio_buffer(pio_buf); release_pio_buffer(pio_buf);
} }
static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) /* Caller must hold info->lock */
static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
{ {
unsigned long flags; unsigned long flags;
...@@ -567,7 +566,7 @@ static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) ...@@ -567,7 +566,7 @@ static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} }
static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info) static inline void transmit_chars_dma_done(struct esp_struct *info)
{ {
int num_bytes; int num_bytes;
unsigned long flags; unsigned long flags;
...@@ -601,7 +600,7 @@ static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info) ...@@ -601,7 +600,7 @@ static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
} }
} }
static _INLINE_ void check_modem_status(struct esp_struct *info) static inline void check_modem_status(struct esp_struct *info)
{ {
int status; int status;
...@@ -654,10 +653,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, ...@@ -654,10 +653,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
err_status = 0; err_status = 0;
scratch = serial_in(info, UART_ESI_SID); scratch = serial_in(info, UART_ESI_SID);
cli(); spin_lock(&info->lock);
if (!info->tty) { if (!info->tty) {
sti(); spin_unlock(&info->lock);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -740,7 +739,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, ...@@ -740,7 +739,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("end.\n"); printk("end.\n");
#endif #endif
sti(); spin_unlock(&info->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -789,10 +788,12 @@ static void do_serial_hangup(void *private_) ...@@ -789,10 +788,12 @@ static void do_serial_hangup(void *private_)
* figure out the appropriate timeout for an interrupt chain, routines * figure out the appropriate timeout for an interrupt chain, routines
* to initialize and startup a serial port, and routines to shutdown a * to initialize and startup a serial port, and routines to shutdown a
* serial port. Useful stuff like that. * serial port. Useful stuff like that.
*
* Caller should hold lock
* --------------------------------------------------------------- * ---------------------------------------------------------------
*/ */
static _INLINE_ void esp_basic_init(struct esp_struct * info) static inline void esp_basic_init(struct esp_struct * info)
{ {
/* put ESPC in enhanced mode */ /* put ESPC in enhanced mode */
serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
...@@ -859,13 +860,13 @@ static int startup(struct esp_struct * info) ...@@ -859,13 +860,13 @@ static int startup(struct esp_struct * info)
int retval=0; int retval=0;
unsigned int num_chars; unsigned int num_chars;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->flags & ASYNC_INITIALIZED) if (info->flags & ASYNC_INITIALIZED)
goto out; goto out;
if (!info->xmit_buf) { if (!info->xmit_buf) {
info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC);
retval = -ENOMEM; retval = -ENOMEM;
if (!info->xmit_buf) if (!info->xmit_buf)
goto out; goto out;
...@@ -901,6 +902,8 @@ static int startup(struct esp_struct * info) ...@@ -901,6 +902,8 @@ static int startup(struct esp_struct * info)
if (info->stat_flags & ESP_STAT_NEVER_DMA) if (info->stat_flags & ESP_STAT_NEVER_DMA)
info->stat_flags |= ESP_STAT_USE_PIO; info->stat_flags |= ESP_STAT_USE_PIO;
spin_unlock_irqrestore(&info->lock, flags);
/* /*
* Allocate the IRQ * Allocate the IRQ
*/ */
...@@ -915,7 +918,7 @@ static int startup(struct esp_struct * info) ...@@ -915,7 +918,7 @@ static int startup(struct esp_struct * info)
&info->tty->flags); &info->tty->flags);
retval = 0; retval = 0;
} }
goto out; goto out_unlocked;
} }
if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
...@@ -935,6 +938,8 @@ static int startup(struct esp_struct * info) ...@@ -935,6 +938,8 @@ static int startup(struct esp_struct * info)
} }
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR); serial_out(info, UART_ESI_CMD2, info->MCR);
...@@ -951,6 +956,7 @@ static int startup(struct esp_struct * info) ...@@ -951,6 +956,7 @@ static int startup(struct esp_struct * info)
if (info->tty) if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags); clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
spin_unlock_irqrestore(&info->lock, flags);
/* /*
* Set up the tty->alt_speed kludge * Set up the tty->alt_speed kludge
...@@ -970,10 +976,12 @@ static int startup(struct esp_struct * info) ...@@ -970,10 +976,12 @@ static int startup(struct esp_struct * info)
* set the speed of the serial port * set the speed of the serial port
*/ */
change_speed(info); change_speed(info);
info->flags |= ASYNC_INITIALIZED; info->flags |= ASYNC_INITIALIZED;
retval = 0; return 0;
out: restore_flags(flags);
out:
spin_unlock_irqrestore(&info->lock, flags);
out_unlocked:
return retval; return retval;
} }
...@@ -993,8 +1001,7 @@ static void shutdown(struct esp_struct * info) ...@@ -993,8 +1001,7 @@ static void shutdown(struct esp_struct * info)
info->irq); info->irq);
#endif #endif
save_flags(flags); cli(); /* Disable interrupts */ spin_lock_irqsave(&info->lock, flags);
/* /*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up * here so the queue might never be waken up
...@@ -1003,7 +1010,7 @@ static void shutdown(struct esp_struct * info) ...@@ -1003,7 +1010,7 @@ static void shutdown(struct esp_struct * info)
wake_up_interruptible(&info->break_wait); wake_up_interruptible(&info->break_wait);
/* stop a DMA transfer on the port being closed */ /* stop a DMA transfer on the port being closed */
/* DMA lock is higher priority always */
if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
f=claim_dma_lock(); f=claim_dma_lock();
disable_dma(dma); disable_dma(dma);
...@@ -1058,7 +1065,7 @@ static void shutdown(struct esp_struct * info) ...@@ -1058,7 +1065,7 @@ static void shutdown(struct esp_struct * info)
set_bit(TTY_IO_ERROR, &info->tty->flags); set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED; info->flags &= ~ASYNC_INITIALIZED;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
/* /*
...@@ -1172,7 +1179,7 @@ static void change_speed(struct esp_struct *info) ...@@ -1172,7 +1179,7 @@ static void change_speed(struct esp_struct *info)
if (I_IXOFF(info->tty)) if (I_IXOFF(info->tty))
flow1 |= 0x81; flow1 |= 0x81;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
/* set baud */ /* set baud */
serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD); serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD);
serial_out(info, UART_ESI_CMD2, quot >> 8); serial_out(info, UART_ESI_CMD2, quot >> 8);
...@@ -1219,7 +1226,7 @@ static void change_speed(struct esp_struct *info) ...@@ -1219,7 +1226,7 @@ static void change_speed(struct esp_struct *info)
serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8); serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);
serial_out(info, UART_ESI_CMD2, info->config.flow_on); serial_out(info, UART_ESI_CMD2, info->config.flow_on);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
static void rs_put_char(struct tty_struct *tty, unsigned char ch) static void rs_put_char(struct tty_struct *tty, unsigned char ch)
...@@ -1233,16 +1240,13 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch) ...@@ -1233,16 +1240,13 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit_buf) if (!tty || !info->xmit_buf)
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt >= ESP_XMIT_SIZE - 1) { if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
restore_flags(flags); info->xmit_buf[info->xmit_head++] = ch;
return; info->xmit_head &= ESP_XMIT_SIZE-1;
info->xmit_cnt++;
} }
spin_unlock_irqrestore(&info->lock, flags);
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= ESP_XMIT_SIZE-1;
info->xmit_cnt++;
restore_flags(flags);
} }
static void rs_flush_chars(struct tty_struct *tty) static void rs_flush_chars(struct tty_struct *tty)
...@@ -1253,16 +1257,18 @@ static void rs_flush_chars(struct tty_struct *tty) ...@@ -1253,16 +1257,18 @@ static void rs_flush_chars(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return; return;
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf)
return; goto out;
save_flags(flags); cli();
if (!(info->IER & UART_IER_THRI)) { if (!(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI; info->IER |= UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
} }
restore_flags(flags); out:
spin_unlock_irqrestore(&info->lock, flags);
} }
static int rs_write(struct tty_struct * tty, static int rs_write(struct tty_struct * tty,
...@@ -1305,7 +1311,7 @@ static int rs_write(struct tty_struct * tty, ...@@ -1305,7 +1311,7 @@ static int rs_write(struct tty_struct * tty,
ret += c; ret += c;
} }
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) { if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI; info->IER |= UART_IER_THRI;
...@@ -1313,7 +1319,7 @@ static int rs_write(struct tty_struct * tty, ...@@ -1313,7 +1319,7 @@ static int rs_write(struct tty_struct * tty,
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return ret; return ret;
} }
...@@ -1321,12 +1327,17 @@ static int rs_write_room(struct tty_struct *tty) ...@@ -1321,12 +1327,17 @@ static int rs_write_room(struct tty_struct *tty)
{ {
struct esp_struct *info = (struct esp_struct *)tty->driver_data; struct esp_struct *info = (struct esp_struct *)tty->driver_data;
int ret; int ret;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_write_room")) if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0; return 0;
spin_lock_irqsave(&info->lock, flags);
ret = ESP_XMIT_SIZE - info->xmit_cnt - 1; ret = ESP_XMIT_SIZE - info->xmit_cnt - 1;
if (ret < 0) if (ret < 0)
ret = 0; ret = 0;
spin_unlock_irqrestore(&info->lock, flags);
return ret; return ret;
} }
...@@ -1342,12 +1353,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty) ...@@ -1342,12 +1353,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty)
{ {
struct esp_struct *info = (struct esp_struct *)tty->driver_data; struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return; return;
cli(); spin_lock_irqsave(&info->lock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
sti(); spin_unlock_irqrestore(&info->lock, flags);
tty_wakeup(tty); tty_wakeup(tty);
} }
...@@ -1362,6 +1374,7 @@ static void rs_flush_buffer(struct tty_struct *tty) ...@@ -1362,6 +1374,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
static void rs_throttle(struct tty_struct * tty) static void rs_throttle(struct tty_struct * tty)
{ {
struct esp_struct *info = (struct esp_struct *)tty->driver_data; struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE #ifdef SERIAL_DEBUG_THROTTLE
char buf[64]; char buf[64];
...@@ -1371,19 +1384,20 @@ static void rs_throttle(struct tty_struct * tty) ...@@ -1371,19 +1384,20 @@ static void rs_throttle(struct tty_struct * tty)
if (serial_paranoia_check(info, tty->name, "rs_throttle")) if (serial_paranoia_check(info, tty->name, "rs_throttle"))
return; return;
cli(); spin_lock_irqsave(&info->lock, flags);
info->IER &= ~UART_IER_RDI; info->IER &= ~UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
serial_out(info, UART_ESI_CMD2, 0x00); serial_out(info, UART_ESI_CMD2, 0x00);
sti(); spin_unlock_irqrestore(&info->lock, flags);
} }
static void rs_unthrottle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty)
{ {
struct esp_struct *info = (struct esp_struct *)tty->driver_data; struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE #ifdef SERIAL_DEBUG_THROTTLE
char buf[64]; char buf[64];
...@@ -1394,13 +1408,13 @@ static void rs_unthrottle(struct tty_struct * tty) ...@@ -1394,13 +1408,13 @@ static void rs_unthrottle(struct tty_struct * tty)
if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return; return;
cli(); spin_lock_irqsave(&info->lock, flags);
info->IER |= UART_IER_RDI; info->IER |= UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
serial_out(info, UART_ESI_CMD2, info->config.rx_timeout); serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
sti(); spin_unlock_irqrestore(&info->lock, flags);
} }
/* /*
...@@ -1573,6 +1587,7 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1573,6 +1587,7 @@ static int set_esp_config(struct esp_struct * info,
unsigned int change_dma; unsigned int change_dma;
int retval = 0; int retval = 0;
struct esp_struct *current_async; struct esp_struct *current_async;
unsigned long flags;
/* Perhaps a non-sysadmin user should be able to do some of these */ /* Perhaps a non-sysadmin user should be able to do some of these */
/* operations. I haven't decided yet. */ /* operations. I haven't decided yet. */
...@@ -1628,12 +1643,14 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1628,12 +1643,14 @@ static int set_esp_config(struct esp_struct * info,
/* all ports must use the same DMA channel */ /* all ports must use the same DMA channel */
spin_lock_irqsave(&info->lock, flags);
current_async = ports; current_async = ports;
while (current_async) { while (current_async) {
esp_basic_init(current_async); esp_basic_init(current_async);
current_async = current_async->next_port; current_async = current_async->next_port;
} }
spin_unlock_irqrestore(&info->lock, flags);
} else { } else {
/* DMA mode to PIO mode only */ /* DMA mode to PIO mode only */
...@@ -1641,8 +1658,10 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1641,8 +1658,10 @@ static int set_esp_config(struct esp_struct * info,
return -EBUSY; return -EBUSY;
shutdown(info); shutdown(info);
spin_lock_irqsave(&info->lock, flags);
info->stat_flags |= ESP_STAT_NEVER_DMA; info->stat_flags |= ESP_STAT_NEVER_DMA;
esp_basic_init(info); esp_basic_init(info);
spin_unlock_irqrestore(&info->lock, flags);
} }
} }
...@@ -1654,13 +1673,14 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1654,13 +1673,14 @@ static int set_esp_config(struct esp_struct * info,
info->config.flow_off = new_config.flow_off; info->config.flow_off = new_config.flow_off;
info->config.flow_on = new_config.flow_on; info->config.flow_on = new_config.flow_on;
save_flags(flags); cli();
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL); serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8); serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8);
serial_out(info, UART_ESI_CMD2, new_config.flow_off); serial_out(info, UART_ESI_CMD2, new_config.flow_off);
serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8); serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8);
serial_out(info, UART_ESI_CMD2, new_config.flow_on); serial_out(info, UART_ESI_CMD2, new_config.flow_on);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
if ((new_config.rx_trigger != info->config.rx_trigger) || if ((new_config.rx_trigger != info->config.rx_trigger) ||
...@@ -1669,7 +1689,7 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1669,7 +1689,7 @@ static int set_esp_config(struct esp_struct * info,
info->config.rx_trigger = new_config.rx_trigger; info->config.rx_trigger = new_config.rx_trigger;
info->config.tx_trigger = new_config.tx_trigger; info->config.tx_trigger = new_config.tx_trigger;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
serial_out(info, UART_ESI_CMD2, serial_out(info, UART_ESI_CMD2,
new_config.rx_trigger >> 8); new_config.rx_trigger >> 8);
...@@ -1677,14 +1697,14 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1677,14 +1697,14 @@ static int set_esp_config(struct esp_struct * info,
serial_out(info, UART_ESI_CMD2, serial_out(info, UART_ESI_CMD2,
new_config.tx_trigger >> 8); new_config.tx_trigger >> 8);
serial_out(info, UART_ESI_CMD2, new_config.tx_trigger); serial_out(info, UART_ESI_CMD2, new_config.tx_trigger);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
if (new_config.rx_timeout != info->config.rx_timeout) { if (new_config.rx_timeout != info->config.rx_timeout) {
unsigned long flags; unsigned long flags;
info->config.rx_timeout = new_config.rx_timeout; info->config.rx_timeout = new_config.rx_timeout;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->IER & UART_IER_RDI) { if (info->IER & UART_IER_RDI) {
serial_out(info, UART_ESI_CMD1, serial_out(info, UART_ESI_CMD1,
...@@ -1693,7 +1713,7 @@ static int set_esp_config(struct esp_struct * info, ...@@ -1693,7 +1713,7 @@ static int set_esp_config(struct esp_struct * info,
new_config.rx_timeout); new_config.rx_timeout);
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
if (!(info->flags & ASYNC_INITIALIZED)) if (!(info->flags & ASYNC_INITIALIZED))
...@@ -1716,11 +1736,12 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value) ...@@ -1716,11 +1736,12 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
{ {
unsigned char status; unsigned char status;
unsigned int result; unsigned int result;
unsigned long flags;
cli(); spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
status = serial_in(info, UART_ESI_STAT1); status = serial_in(info, UART_ESI_STAT1);
sti(); spin_unlock_irqrestore(&info->lock, flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
return put_user(result,value); return put_user(result,value);
} }
...@@ -1730,6 +1751,7 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file) ...@@ -1730,6 +1751,7 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
{ {
struct esp_struct * info = (struct esp_struct *)tty->driver_data; struct esp_struct * info = (struct esp_struct *)tty->driver_data;
unsigned char control, status; unsigned char control, status;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, __FUNCTION__)) if (serial_paranoia_check(info, tty->name, __FUNCTION__))
return -ENODEV; return -ENODEV;
...@@ -1737,10 +1759,12 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file) ...@@ -1737,10 +1759,12 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
return -EIO; return -EIO;
control = info->MCR; control = info->MCR;
cli();
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
status = serial_in(info, UART_ESI_STAT2); status = serial_in(info, UART_ESI_STAT2);
sti(); spin_unlock_irqrestore(&info->lock, flags);
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
...@@ -1753,13 +1777,14 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -1753,13 +1777,14 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear) unsigned int set, unsigned int clear)
{ {
struct esp_struct * info = (struct esp_struct *)tty->driver_data; struct esp_struct * info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, __FUNCTION__)) if (serial_paranoia_check(info, tty->name, __FUNCTION__))
return -ENODEV; return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR)) if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO; return -EIO;
cli(); spin_lock_irqsave(&info->lock, flags);
if (set & TIOCM_RTS) if (set & TIOCM_RTS)
info->MCR |= UART_MCR_RTS; info->MCR |= UART_MCR_RTS;
...@@ -1774,7 +1799,8 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -1774,7 +1799,8 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR); serial_out(info, UART_ESI_CMD2, info->MCR);
sti();
spin_unlock_irqrestore(&info->lock, flags);
return 0; return 0;
} }
...@@ -1789,17 +1815,20 @@ static void esp_break(struct tty_struct *tty, int break_state) ...@@ -1789,17 +1815,20 @@ static void esp_break(struct tty_struct *tty, int break_state)
if (serial_paranoia_check(info, tty->name, "esp_break")) if (serial_paranoia_check(info, tty->name, "esp_break"))
return; return;
save_flags(flags); cli();
if (break_state == -1) { if (break_state == -1) {
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
serial_out(info, UART_ESI_CMD2, 0x01); serial_out(info, UART_ESI_CMD2, 0x01);
spin_unlock_irqrestore(&info->lock, flags);
/* FIXME - new style wait needed here */
interruptible_sleep_on(&info->break_wait); interruptible_sleep_on(&info->break_wait);
} else { } else {
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
serial_out(info, UART_ESI_CMD2, 0x00); serial_out(info, UART_ESI_CMD2, 0x00);
spin_unlock_irqrestore(&info->lock, flags);
} }
restore_flags(flags);
} }
static int rs_ioctl(struct tty_struct *tty, struct file * file, static int rs_ioctl(struct tty_struct *tty, struct file * file,
...@@ -1809,6 +1838,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1809,6 +1838,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
struct async_icount cprev, cnow; /* kernel counter temps */ struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */ struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_ioctl")) if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV; return -ENODEV;
...@@ -1849,17 +1879,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1849,17 +1879,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* Caller should use TIOCGICOUNT to see which one it was * Caller should use TIOCGICOUNT to see which one it was
*/ */
case TIOCMIWAIT: case TIOCMIWAIT:
cli(); spin_lock_irqsave(&info->lock, flags);
cprev = info->icount; /* note the counters on entry */ cprev = info->icount; /* note the counters on entry */
sti(); spin_unlock_irqrestore(&info->lock, flags);
while (1) { while (1) {
/* FIXME: convert to new style wakeup */
interruptible_sleep_on(&info->delta_msr_wait); interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */ /* see if a signal did it */
if (signal_pending(current)) if (signal_pending(current))
return -ERESTARTSYS; return -ERESTARTSYS;
cli(); spin_lock_irqsave(&info->lock, flags);
cnow = info->icount; /* atomic copy */ cnow = info->icount; /* atomic copy */
sti(); spin_unlock_irqrestore(&info->lock, flags);
if (cnow.rng == cprev.rng && if (cnow.rng == cprev.rng &&
cnow.dsr == cprev.dsr && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.dcd == cprev.dcd &&
...@@ -1886,9 +1917,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1886,9 +1917,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* RI where only 0->1 is counted. * RI where only 0->1 is counted.
*/ */
case TIOCGICOUNT: case TIOCGICOUNT:
cli(); spin_lock_irqsave(&info->lock, flags);
cnow = info->icount; cnow = info->icount;
sti(); spin_unlock_irqrestore(&info->lock, flags);
p_cuser = argp; p_cuser = argp;
if (put_user(cnow.cts, &p_cuser->cts) || if (put_user(cnow.cts, &p_cuser->cts) ||
put_user(cnow.dsr, &p_cuser->dsr) || put_user(cnow.dsr, &p_cuser->dsr) ||
...@@ -1911,53 +1942,42 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1911,53 +1942,42 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
{ {
struct esp_struct *info = (struct esp_struct *)tty->driver_data; struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
if ( (tty->termios->c_cflag == old_termios->c_cflag) if ( (tty->termios->c_cflag == old_termios->c_cflag)
&& ( RELEVANT_IFLAG(tty->termios->c_iflag) && ( RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag))) == RELEVANT_IFLAG(old_termios->c_iflag)))
return; return;
change_speed(info); change_speed(info);
spin_lock_irqsave(&info->lock, flags);
/* Handle transition to B0 status */ /* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && if ((old_termios->c_cflag & CBAUD) &&
!(tty->termios->c_cflag & CBAUD)) { !(tty->termios->c_cflag & CBAUD)) {
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
cli();
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR); serial_out(info, UART_ESI_CMD2, info->MCR);
sti();
} }
/* Handle transition away from B0 status */ /* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) && if (!(old_termios->c_cflag & CBAUD) &&
(tty->termios->c_cflag & CBAUD)) { (tty->termios->c_cflag & CBAUD)) {
info->MCR |= (UART_MCR_DTR | UART_MCR_RTS); info->MCR |= (UART_MCR_DTR | UART_MCR_RTS);
cli();
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR); serial_out(info, UART_ESI_CMD2, info->MCR);
sti();
} }
spin_unlock_irqrestore(&info->lock, flags);
/* Handle turning of CRTSCTS */ /* Handle turning of CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) { !(tty->termios->c_cflag & CRTSCTS)) {
rs_start(tty); rs_start(tty);
} }
#if 0
/*
* No need to wake up processes in open wait, since they
* sample the CLOCAL flag once, and don't recheck it.
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
#endif
} }
/* /*
...@@ -1978,7 +1998,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -1978,7 +1998,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (!info || serial_paranoia_check(info, tty->name, "rs_close")) if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (tty_hung_up_p(filp)) { if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung"); DBG_CNT("before DEC-hung");
...@@ -2010,6 +2030,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -2010,6 +2030,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
goto out; goto out;
} }
info->flags |= ASYNC_CLOSING; info->flags |= ASYNC_CLOSING;
spin_unlock_irqrestore(&info->lock, flags);
/* /*
* Now we wait for the transmit buffer to clear; and we notify * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters. * the line discipline to only process XON/XOFF characters.
...@@ -2027,6 +2049,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -2027,6 +2049,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->IER &= ~UART_IER_RDI; info->IER &= ~UART_IER_RDI;
info->read_status_mask &= ~UART_LSR_DR; info->read_status_mask &= ~UART_LSR_DR;
if (info->flags & ASYNC_INITIALIZED) { if (info->flags & ASYNC_INITIALIZED) {
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD2, info->IER);
...@@ -2034,6 +2058,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -2034,6 +2058,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
serial_out(info, UART_ESI_CMD2, 0x00); serial_out(info, UART_ESI_CMD2, 0x00);
spin_unlock_irqrestore(&info->lock, flags);
/* /*
* Before we drop DTR, make sure the UART transmitter * Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially * has completely drained; this is especially
...@@ -2057,8 +2083,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -2057,8 +2083,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
} }
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait); wake_up_interruptible(&info->close_wait);
return;
out: out:
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
static void rs_wait_until_sent(struct tty_struct *tty, int timeout) static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
...@@ -2076,12 +2104,14 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) ...@@ -2076,12 +2104,14 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (!char_time) if (!char_time)
char_time = 1; char_time = 1;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
while ((serial_in(info, UART_ESI_STAT1) != 0x03) || while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
(serial_in(info, UART_ESI_STAT2) != 0xff)) { (serial_in(info, UART_ESI_STAT2) != 0xff)) {
spin_unlock_irqrestore(&info->lock, flags);
msleep_interruptible(jiffies_to_msecs(char_time)); msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current)) if (signal_pending(current))
...@@ -2090,11 +2120,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) ...@@ -2090,11 +2120,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout)) if (timeout && time_after(jiffies, orig_jiffies + timeout))
break; break;
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
} }
spin_unlock_irqrestore(&info->lock, flags);
restore_flags(flags);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
} }
...@@ -2174,15 +2204,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -2174,15 +2204,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready before block: ttys%d, count = %d\n", printk("block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count); info->line, info->count);
#endif #endif
save_flags(flags); spin_lock_irqsave(&info->lock, flags);
cli();
if (!tty_hung_up_p(filp)) if (!tty_hung_up_p(filp))
info->count--; info->count--;
restore_flags(flags);
info->blocked_open++; info->blocked_open++;
while (1) { while (1) {
save_flags(flags);
cli();
if ((tty->termios->c_cflag & CBAUD)) { if ((tty->termios->c_cflag & CBAUD)) {
unsigned int scratch; unsigned int scratch;
...@@ -2194,7 +2220,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -2194,7 +2220,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
serial_out(info, UART_ESI_CMD2, serial_out(info, UART_ESI_CMD2,
scratch | UART_MCR_DTR | UART_MCR_RTS); scratch | UART_MCR_DTR | UART_MCR_RTS);
} }
restore_flags(flags);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) { !(info->flags & ASYNC_INITIALIZED)) {
...@@ -2224,13 +2249,16 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -2224,13 +2249,16 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttys%d, count = %d\n", printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count); info->line, info->count);
#endif #endif
spin_unlock_irqrestore(&info->lock, flags);
schedule(); schedule();
spin_lock_irqsave(&info->lock, flags);
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait); remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)) if (!tty_hung_up_p(filp))
info->count++; info->count++;
info->blocked_open--; info->blocked_open--;
spin_unlock_irqrestore(&info->lock, flags);
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttys%d, count = %d\n", printk("block_til_ready after blocking: ttys%d, count = %d\n",
info->line, info->count); info->line, info->count);
...@@ -2251,6 +2279,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp) ...@@ -2251,6 +2279,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
{ {
struct esp_struct *info; struct esp_struct *info;
int retval, line; int retval, line;
unsigned long flags;
line = tty->index; line = tty->index;
if ((line < 0) || (line >= NR_PORTS)) if ((line < 0) || (line >= NR_PORTS))
...@@ -2271,6 +2300,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp) ...@@ -2271,6 +2300,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("esp_open %s, count = %d\n", tty->name, info->count); printk("esp_open %s, count = %d\n", tty->name, info->count);
#endif #endif
spin_lock_irqsave(&info->lock, flags);
info->count++; info->count++;
tty->driver_data = info; tty->driver_data = info;
info->tty = tty; info->tty = tty;
...@@ -2317,7 +2347,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp) ...@@ -2317,7 +2347,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
* driver. * driver.
*/ */
static _INLINE_ void show_serial_version(void) static inline void show_serial_version(void)
{ {
printk(KERN_INFO "%s version %s (DMA %u)\n", printk(KERN_INFO "%s version %s (DMA %u)\n",
serial_name, serial_version, dma); serial_name, serial_version, dma);
...@@ -2327,7 +2357,7 @@ static _INLINE_ void show_serial_version(void) ...@@ -2327,7 +2357,7 @@ static _INLINE_ void show_serial_version(void)
* This routine is called by espserial_init() to initialize a specific serial * This routine is called by espserial_init() to initialize a specific serial
* port. * port.
*/ */
static _INLINE_ int autoconfig(struct esp_struct * info) static inline int autoconfig(struct esp_struct * info)
{ {
int port_detected = 0; int port_detected = 0;
unsigned long flags; unsigned long flags;
...@@ -2335,8 +2365,7 @@ static _INLINE_ int autoconfig(struct esp_struct * info) ...@@ -2335,8 +2365,7 @@ static _INLINE_ int autoconfig(struct esp_struct * info)
if (!request_region(info->port, REGION_SIZE, "esp serial")) if (!request_region(info->port, REGION_SIZE, "esp serial"))
return -EIO; return -EIO;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
/* /*
* Check for ESP card * Check for ESP card
*/ */
...@@ -2372,7 +2401,7 @@ static _INLINE_ int autoconfig(struct esp_struct * info) ...@@ -2372,7 +2401,7 @@ static _INLINE_ int autoconfig(struct esp_struct * info)
if (!port_detected) if (!port_detected)
release_region(info->port, REGION_SIZE); release_region(info->port, REGION_SIZE);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return (port_detected); return (port_detected);
} }
...@@ -2513,6 +2542,7 @@ static int __init espserial_init(void) ...@@ -2513,6 +2542,7 @@ static int __init espserial_init(void)
init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->delta_msr_wait);
init_waitqueue_head(&info->break_wait); init_waitqueue_head(&info->break_wait);
spin_lock_init(&info->lock);
ports = info; ports = info;
printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
info->line, info->port, info->irq); info->line, info->port, info->irq);
...@@ -2563,18 +2593,14 @@ static int __init espserial_init(void) ...@@ -2563,18 +2593,14 @@ static int __init espserial_init(void)
static void __exit espserial_exit(void) static void __exit espserial_exit(void)
{ {
unsigned long flags;
int e1; int e1;
struct esp_struct *temp_async; struct esp_struct *temp_async;
struct esp_pio_buffer *pio_buf; struct esp_pio_buffer *pio_buf;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */ /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags(flags);
cli();
if ((e1 = tty_unregister_driver(esp_driver))) if ((e1 = tty_unregister_driver(esp_driver)))
printk("SERIAL: failed to unregister serial driver (%d)\n", printk("SERIAL: failed to unregister serial driver (%d)\n",
e1); e1);
restore_flags(flags);
put_tty_driver(esp_driver); put_tty_driver(esp_driver);
while (ports) { while (ports) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment