patch-2.1.20 linux/drivers/char/esp.c
Next file: linux/drivers/char/esp.h
Previous file: linux/drivers/char/Makefile
Back to the patch index
Back to the overall index
- Lines: 882
- Date:
Wed Jan 1 22:26:31 1997
- Orig file:
v2.1.19/linux/drivers/char/esp.c
- Orig date:
Mon Dec 30 15:39:06 1996
diff -u --recursive --new-file v2.1.19/linux/drivers/char/esp.c linux/drivers/char/esp.c
@@ -29,13 +29,17 @@
* by Chris Faylor.
*
* Most recent changes: (Andrew J. Robinson)
- * Remove tx_flowed_[on|off], since the ESP handles flow itself.
- * Enabled reinterrupt pacing to ensure all requests are serviced.
- * Decreased RX timeout to reduce latency.
+ * Remove all references to tty->hw_stopped.
+ * Request a single region for multiple ports if possible.
+ * Stop a DMA transfer on a port when it is closed.
+ * Rename esp_init() to espserial_init().
+ * Improve validation of IRQ (only accept those allowed by the ESP card).
+ * Return if a signal is received while wait for a break to start.
+ * Split NEED_DMA logic into NEED_DMA_RX and NEED_DMA_TX.
*
* This module exports the following rs232 io functions:
*
- * int esp_init(void);
+ * int espserial_init(void);
*/
#include <linux/module.h>
@@ -76,16 +80,22 @@
static unsigned int dma = CONFIG_ESPSERIAL_DMA_CHANNEL; /* DMA channel */
static unsigned int trigger = CONFIG_ESPSERIAL_TRIGGER_LEVEL;
/* FIFO trigger level */
+
+MODULE_PARM(irq, "1-8i");
+MODULE_PARM(divisor, "1-8i");
+MODULE_PARM(dma, "i");
+MODULE_PARM(trigger, "i");
/* END */
static char *dma_buffer;
+static int dma_bytes;
#define DMA_BUFFER_SZ 1024
#define WAKEUP_CHARS 1024
static char *serial_name = "ESP serial driver";
-static char *serial_version = "1.2";
+static char *serial_version = "1.3";
DECLARE_TASK_QUEUE(tq_esp);
@@ -122,7 +132,6 @@
static struct esp_struct *IRQ_ports[16];
-static void autoconfig(struct esp_struct * info);
static void change_speed(struct esp_struct *info);
static void rs_wait_until_sent(struct tty_struct *, int);
@@ -288,32 +297,24 @@
mark_bh(ESP_BH);
}
-static _INLINE_ void receive_chars_dma(struct esp_struct *info, int *dma_bytes)
+static void receive_chars_dma(struct esp_struct *info)
{
- unsigned int num_chars;
-
- if (*dma_bytes) {
- info->stat_flags |= ESP_STAT_NEED_DMA;
- return;
- }
-
- info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA);
+ info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA_RX);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
- num_chars = serial_in(info, UART_ESI_STAT1) << 8;
- num_chars |= serial_in(info, UART_ESI_STAT2);
+ dma_bytes = serial_in(info, UART_ESI_STAT1) << 8;
+ dma_bytes |= serial_in(info, UART_ESI_STAT2);
- if (!num_chars)
+ if (!dma_bytes)
return;
- *dma_bytes = num_chars;
info->stat_flags |= ESP_STAT_DMA_RX;
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_READ);
set_dma_addr(dma, virt_to_bus(dma_buffer));
- set_dma_count(dma, num_chars);
+ set_dma_count(dma, dma_bytes);
enable_dma(dma);
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
@@ -368,8 +369,8 @@
restore_flags(flags);
}
-static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
- int *dma_bytes, int status)
+static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
+ int status)
{
struct tty_struct *tty = info->tty;
int num_bytes, bytes_left, x_bytes;
@@ -382,10 +383,8 @@
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
- num_bytes = *dma_bytes - get_dma_residue(dma);
-
+ bytes_left = num_bytes = dma_bytes - get_dma_residue(dma);
buffer = &(tty->flip);
- bytes_left = num_bytes;
if (info->tty_buf->count && (tty->flip.count < TTY_FLIPBUF_SIZE))
do_ttybuf(info);
@@ -415,7 +414,6 @@
if (num_bytes > 0) {
buffer->flag_buf_ptr--;
- status >>= 8;
status &= (0x1c & info->read_status_mask);
if (status & info->ignore_status_mask) {
@@ -439,26 +437,18 @@
queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
}
- if (*dma_bytes != num_bytes) {
- *dma_bytes = 0;
- receive_chars_dma(info, dma_bytes);
+ if (dma_bytes != num_bytes) {
+ dma_bytes = 0;
+ receive_chars_dma(info);
} else
- *dma_bytes = 0;
+ dma_bytes = 0;
}
-static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int *dma_bytes)
+static void transmit_chars_dma(struct esp_struct *info)
{
- int count;
-
- if (*dma_bytes) {
- info->stat_flags |= ESP_STAT_NEED_DMA;
- return;
- }
-
- info->stat_flags &= ~ESP_STAT_NEED_DMA;
+ info->stat_flags &= ~ESP_STAT_NEED_DMA_TX;
- if ((info->xmit_cnt <= 0) || info->tty->stopped ||
- info->tty->hw_stopped) {
+ if ((info->xmit_cnt <= 0) || info->tty->stopped) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
@@ -467,53 +457,53 @@
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
- count = serial_in(info, UART_ESI_STAT1) << 8;
- count |= serial_in(info, UART_ESI_STAT2);
+ dma_bytes = serial_in(info, UART_ESI_STAT1) << 8;
+ dma_bytes |= serial_in(info, UART_ESI_STAT2);
- if (!count)
+ if (!dma_bytes)
return;
- count = ((count < info->xmit_cnt) ? count : info->xmit_cnt);
+ if (dma_bytes > info->xmit_cnt)
+ dma_bytes = info->xmit_cnt;
- if (info->xmit_tail + count <= ESP_XMIT_SIZE) {
+ if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]),
- count);
+ dma_bytes);
} else {
int i = ESP_XMIT_SIZE - info->xmit_tail;
memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]),
i);
- memcpy(&(dma_buffer[i]), info->xmit_buf, count - i);
+ memcpy(&(dma_buffer[i]), info->xmit_buf, dma_bytes - i);
}
- info->xmit_cnt -= count;
- info->xmit_tail = (info->xmit_tail + count) & (ESP_XMIT_SIZE - 1);
+ info->xmit_cnt -= dma_bytes;
+ info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1);
- if (info->xmit_cnt < WAKEUP_CHARS)
+ if (info->xmit_cnt < WAKEUP_CHARS) {
rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
#endif
- if (info->xmit_cnt <= 0) {
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
- serial_out(info, UART_ESI_CMD2, info->IER);
+ if (info->xmit_cnt <= 0) {
+ info->IER &= ~UART_IER_THRI;
+ serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
+ serial_out(info, UART_ESI_CMD2, info->IER);
+ }
}
- *dma_bytes = count;
info->stat_flags |= ESP_STAT_DMA_TX;
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_WRITE);
set_dma_addr(dma, virt_to_bus(dma_buffer));
- set_dma_count(dma, count);
+ set_dma_count(dma, dma_bytes);
enable_dma(dma);
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
}
-static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info,
- int *dma_bytes)
+static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
{
int num_bytes;
@@ -523,21 +513,20 @@
disable_dma(dma);
clear_dma_ff(dma);
- num_bytes = *dma_bytes - get_dma_residue(dma);
+ num_bytes = dma_bytes - get_dma_residue(dma);
- if (*dma_bytes != num_bytes)
- {
- *dma_bytes -= num_bytes;
- memmove(dma_buffer, dma_buffer + num_bytes, *dma_bytes);
+ if (dma_bytes != num_bytes) {
+ dma_bytes -= num_bytes;
+ memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_WRITE);
set_dma_addr(dma, virt_to_bus(dma_buffer));
- set_dma_count(dma, *dma_bytes);
+ set_dma_count(dma, dma_bytes);
enable_dma(dma);
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} else {
- *dma_bytes = 0;
+ dma_bytes = 0;
info->stat_flags &= ~ESP_STAT_DMA_TX;
}
}
@@ -585,12 +574,10 @@
*/
static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
{
- struct esp_struct * info, *stop_port;
+ struct esp_struct * info, *stop_port = 0;
unsigned err_status;
unsigned int scratch;
int pre_bytes;
- int check_dma_only = 0;
- static int dma_bytes;
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
@@ -599,14 +586,13 @@
/* This routine will currently check ALL ports when an interrupt */
/* is received from ANY port */
- stop_port = info = IRQ_ports[irq];
+ info = IRQ_ports[irq];
if (!info)
return;
do {
- if (!info->tty || (check_dma_only &&
- !(info->stat_flags & ESP_STAT_NEED_DMA))) {
+ if (!info->tty) {
info = info->next_port;
continue;
}
@@ -616,33 +602,38 @@
scratch = serial_in(info, UART_ESI_SID);
if (scratch & 0x04) { /* error - check for rx timeout */
serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT);
- err_status = serial_in(info, UART_ESI_STAT1) << 8;
- err_status |= serial_in(info, UART_ESI_STAT2);
+ err_status = serial_in(info, UART_ESI_STAT1);
+ serial_in(info, UART_ESI_STAT2);
- if (err_status & 0x0100)
+ if (err_status & 0x01)
info->stat_flags |= ESP_STAT_RX_TIMEOUT;
- if (err_status & 0x2000) /* UART status */
+ if (err_status & 0x20) /* UART status */
check_modem_status(info);
- if (err_status & 0x8000) /* Start break */
+ if (err_status & 0x80) /* Start break */
wake_up_interruptible(&info->break_wait);
}
if ((scratch & 0x88) || /* DMA completed or timed out */
- (err_status & 0x1c00) /* receive error */) {
- receive_chars_dma_done(info, &dma_bytes,
- err_status);
- transmit_chars_dma_done(info, &dma_bytes);
+ (err_status & 0x1c) /* receive error */) {
+ receive_chars_dma_done(info, err_status);
+ transmit_chars_dma_done(info);
}
if (((scratch & 0x01) ||
(info->stat_flags & ESP_STAT_RX_TIMEOUT)) &&
(info->IER & UART_IER_RDI))
- receive_chars_dma(info, &dma_bytes);
+ if (dma_bytes)
+ info->stat_flags |= ESP_STAT_NEED_DMA_RX;
+ else
+ receive_chars_dma(info);
if ((scratch & 0x02) && (info->IER & UART_IER_THRI))
- transmit_chars_dma(info, &dma_bytes);
+ if (dma_bytes)
+ info->stat_flags |= ESP_STAT_NEED_DMA_TX;
+ else
+ transmit_chars_dma(info);
info->last_active = jiffies;
@@ -650,13 +641,21 @@
stop_port = info;
info = info->next_port;
+ } while ((info->irq == irq) && (info != IRQ_ports[irq]));
- if ((info->irq != irq) || (info == IRQ_ports[irq]))
- check_dma_only = 1;
-
- if (check_dma_only && dma_bytes)
- info = stop_port;
- } while (info != stop_port);
+ if (stop_port) {
+ while ((info != stop_port) && (!dma_bytes)) {
+ if (info->tty) {
+ if (info->stat_flags & ESP_STAT_NEED_DMA_RX)
+ receive_chars_dma(info);
+ if ((info->stat_flags & ESP_STAT_NEED_DMA_TX)
+ && !dma_bytes)
+ transmit_chars_dma(info);
+ }
+
+ info = info->next_port;
+ }
+ }
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
@@ -730,7 +729,7 @@
* ---------------------------------------------------------------
*/
-static void esp_basic_init(struct esp_struct * info)
+static _INLINE_ void esp_basic_init(struct esp_struct * info)
{
/* put ESPC in enhanced mode */
serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
@@ -791,13 +790,6 @@
return 0;
}
- if (!info->port) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- restore_flags(flags);
- return 0;
- }
-
if (!info->xmit_buf) {
info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL);
if (!info->xmit_buf) {
@@ -857,7 +849,7 @@
*/
if (!IRQ_ports[info->irq]) {
retval = request_irq(info->irq, rs_interrupt_single,
- SA_INTERRUPT, "esp", NULL);
+ SA_INTERRUPT, "esp serial", NULL);
if (!retval) {
int i = 1;
@@ -872,7 +864,7 @@
if (!dma_buffer)
retval = -ENOMEM;
else
- retval = request_dma(dma, "esp");
+ retval = request_dma(dma, "esp serial");
if (retval)
free_irq(info->irq, NULL);
@@ -892,10 +884,6 @@
}
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
-
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR);
@@ -979,6 +967,29 @@
*/
wake_up_interruptible(&info->delta_msr_wait);
wake_up_interruptible(&info->break_wait);
+
+ /* stop a DMA transfer on the port being closed, and start the next
+ one */
+
+ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
+ struct esp_struct *curr = info->next_port;
+
+ disable_dma(dma);
+ clear_dma_ff(dma);
+ dma_bytes = 0;
+
+ while ((curr != info) && (!dma_bytes)) {
+ if (curr->tty) {
+ if (curr->stat_flags & ESP_STAT_NEED_DMA_RX)
+ receive_chars_dma(curr);
+ if ((curr->stat_flags & ESP_STAT_NEED_DMA_TX)
+ && !dma_bytes)
+ transmit_chars_dma(curr);
+ }
+
+ curr = curr->next_port;
+ }
+ }
/*
* First unlink the serial port from the IRQ chain...
@@ -1025,7 +1036,21 @@
info->xmit_buf = 0;
}
- if (info->tty_buf && !info->tty_buf->tqueue.sync) {
+ if (info->tty_buf) {
+ /* code borrowed from tty_io.c */
+ if (info->tty_buf->tqueue.sync) {
+ struct tq_struct *tq, *prev;
+
+ for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
+ if (tq == &info->tty_buf->tqueue) {
+ if (prev)
+ prev->next = tq->next;
+ else
+ tq_timer = tq->next;
+ break;
+ }
+ }
+ }
kfree(info->tty_buf);
info->tty_buf = 0;
}
@@ -1065,8 +1090,7 @@
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
- return;
+ port = info->port;
i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
@@ -1251,8 +1275,7 @@
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
+ if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf)
return;
save_flags(flags); cli();
@@ -1303,10 +1326,9 @@
}
if (from_user)
up(&tmp_buf_sem);
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(info->IER & UART_IER_THRI)) {
+ if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); /* set mask */
+ serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
}
restore_flags(flags);
@@ -1371,8 +1393,8 @@
if (serial_paranoia_check(info, tty->device, "rs_throttle"))
return;
- info->IER &= ~UART_IER_RDI;
cli();
+ info->IER &= ~UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
@@ -1393,8 +1415,8 @@
if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
return;
- info->IER |= UART_IER_RDI;
cli();
+ info->IER |= UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
@@ -1438,7 +1460,6 @@
unsigned int change_irq;
int i, retval = 0;
struct esp_struct *current_async;
- unsigned long flags = 0;
if (!new_info)
return -EFAULT;
@@ -1450,7 +1471,10 @@
(info->port != new_serial.port) ||
(new_serial.baud_base != BASE_BAUD) ||
(new_serial.irq > 15) ||
- (new_serial.irq < 1))
+ (new_serial.irq < 2) ||
+ (new_serial.irq == 6) ||
+ (new_serial.irq == 8) ||
+ (new_serial.irq == 13))
return -EINVAL;
change_irq = new_serial.irq != info->irq;
@@ -1474,7 +1498,6 @@
new_serial.irq = 9;
if (change_irq) {
- save_flags(flags); cli();
i = 1;
while ((i < 16) && !IRQ_ports[i])
@@ -1487,14 +1510,10 @@
if ((current_async->line >= info->line) &&
(current_async->line < (info->line + 8))) {
if (current_async == info) {
- if (current_async->count > 1) {
- restore_flags(flags);
+ if (current_async->count > 1)
return -EBUSY;
- }
- } else {
- restore_flags(flags);
+ } else
return -EBUSY;
- }
}
current_async = current_async->next_port;
@@ -1534,13 +1553,9 @@
serial_out(info, UART_ESI_CMD2, 0x02);
else
serial_out(info, UART_ESI_CMD2, info->irq);
-
- restore_flags(flags);
}
check_and_exit:
- if (!info->port)
- return 0;
if (info->flags & ASYNC_INITIALIZED) {
if (((old_info.flags & ASYNC_SPD_MASK) !=
(info->flags & ASYNC_SPD_MASK)) ||
@@ -1639,14 +1654,19 @@
*/
static void send_break( struct esp_struct * info, int duration)
{
- if (!info->port)
- return;
cli();
serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
serial_out(info, UART_ESI_CMD2, 0x01);
interruptible_sleep_on(&info->break_wait);
+ if (current->signal & ~current->blocked) {
+ serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK);
+ serial_out(info, UART_ESI_CMD2, 0x00);
+ sti();
+ return;
+ }
+
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + duration;
schedule();
@@ -1832,8 +1852,7 @@
if (!(old_termios->c_cflag & CBAUD) &&
(tty->termios->c_cflag & CBAUD)) {
info->MCR |= UART_MCR_DTR;
- if (!tty->hw_stopped ||
- !(tty->termios->c_cflag & CRTSCTS))
+ if (!(tty->termios->c_cflag & CRTSCTS))
info->MCR |= UART_MCR_RTS;
cli();
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
@@ -1845,7 +1864,6 @@
/* Handle turning of CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1964,17 +1982,6 @@
info->event = 0;
info->tty = 0;
- if (info->tty_buf) {
- while (info->tty_buf->tqueue.sync) {
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ / 10;
- schedule();
- }
-
- kfree(info->tty_buf);
- info->tty_buf = 0;
- }
-
if (info->blocked_open) {
if (info->close_delay) {
current->state = TASK_INTERRUPTIBLE;
@@ -2299,9 +2306,9 @@
/*
* ---------------------------------------------------------------------
- * esp_init() and friends
+ * espserial_init() and friends
*
- * esp_init() is called at boot-time to initialize the serial driver.
+ * espserial_init() is called at boot-time to initialize the serial driver.
* ---------------------------------------------------------------------
*/
@@ -2317,45 +2324,47 @@
}
/*
- * This routine is called by esp_init() to initialize a specific serial
- * port. It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
+ * This routine is called by espserial_init() to initialize a specific serial
+ * port.
*/
-static void autoconfig(struct esp_struct * info)
+static _INLINE_ int autoconfig(struct esp_struct * info, int *region_start)
{
- unsigned char status1, status2, scratch;
- unsigned port = info->port;
+ int port_detected = 0;
unsigned long flags;
- if (!port)
- return;
-
save_flags(flags); cli();
/*
* Check for ESP card
*/
- scratch = serial_in(info, UART_ESI_BASE);
- if (scratch == 0xf3) {
+
+ if (!check_region(info->port, 8) &&
+ serial_in(info, UART_ESI_BASE) == 0xf3) {
serial_out(info, UART_ESI_CMD1, 0x00);
serial_out(info, UART_ESI_CMD1, 0x01);
- status1 = serial_in(info, UART_ESI_STAT2);
- status2 = status1 & 0x70;
- if (status2 != 0x20) {
- printk(" Old ESP found at %x\n",info->port);
- info->port = 0;
- } else {
- serial_out(info, UART_ESI_CMD1, 0x02);
- status1 = serial_in(info, UART_ESI_STAT1) & 0x03;
+
+ if ((serial_in(info, UART_ESI_STAT2) & 0x70) == 0x20) {
+ port_detected = 1;
+
if (!(info->irq)) {
- if ((status1 == 0x00) || (status1 == 0x02))
- info->irq = 4;
- else
+ serial_out(info, UART_ESI_CMD1, 0x02);
+
+ if (serial_in(info, UART_ESI_STAT1) & 0x01)
info->irq = 3;
+ else
+ info->irq = 4;
}
- request_region(port,8,"esp");
+
+ if (IRQ_ports[0] &&
+ (IRQ_ports[0]->port == (info->port - 8))) {
+ release_region(*region_start,
+ info->port - *region_start);
+ } else
+ *region_start = info->port;
+
+ request_region(*region_start,
+ info->port - *region_start + 8,
+ "esp serial");
/* put card in enhanced mode */
/* this prevents access through */
@@ -2367,19 +2376,19 @@
serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, 0x00);
}
- } else {
- info->port = 0;
}
restore_flags(flags);
+ return (port_detected);
}
/*
* The serial driver boot-time initialization code!
*/
-int esp_init(void)
+int espserial_init(void)
{
int i, offset;
+ int region_start;
struct esp_struct * info;
int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
@@ -2389,6 +2398,14 @@
IRQ_ports[i] = 0;
}
+ for (i = 0; i < NR_PRIMARY; i++)
+ if (irq[i] != 0)
+ if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
+ (irq[i] == 8) || (irq[i] == 13))
+ irq[i] = 0;
+ else if (irq[i] == 2)
+ irq[i] = 9;
+
if ((dma != 1) && (dma != 3))
dma = 1;
@@ -2458,19 +2475,12 @@
do {
info->port = esp[i] + offset;
+ info->irq = irq[i];
+ info->line = (i * 8) + (offset / 8);
- /* check if i/o region is already in use */
- if (check_region(info->port, 8)) {
- /* if it is a primary port, skip secondary ports */
- if (!offset)
- i++;
- else if (offset == 56) {
- i++;
- offset = 0;
- }
- else
- offset += 8;
-
+ if (!autoconfig(info, ®ion_start)) {
+ i++;
+ offset = 0;
continue;
}
@@ -2478,11 +2488,7 @@
info->flags = STD_COM_FLAGS;
if (info->custom_divisor)
info->flags |= ASYNC_SPD_CUST;
- info->irq = irq[i];
-
info->magic = ESP_MAGIC;
- info->line = (i * 8) + (offset / 8);
- info->tty = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ;
info->tqueue.routine = do_softint;
@@ -2492,15 +2498,6 @@
info->callout_termios = esp_callout_driver.init_termios;
info->normal_termios = esp_driver.init_termios;
- if (info->irq == 2)
- info->irq = 9;
-
- autoconfig(info);
- if (!info->port) {
- i++;
- offset = 0;
- continue;
- }
if (IRQ_ports[0])
IRQ_ports[0]->prev_port = info;
info->next_port = IRQ_ports[0];
@@ -2539,13 +2536,14 @@
int init_module(void)
{
- return esp_init();
+ return espserial_init();
}
void cleanup_module(void)
{
unsigned long flags;
int e1, e2;
+ unsigned int region_start, region_end;
struct esp_struct *current_async, *temp_async;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
@@ -2561,8 +2559,31 @@
current_async = IRQ_ports[0];
while (current_async != 0) {
- release_region(current_async->port, 8);
- current_async = current_async->next_port;
+ if (current_async->port != 0) {
+ region_start = region_end = current_async->port;
+ temp_async = current_async;
+
+ while (temp_async != 0) {
+ if ((region_start - temp_async->port) == 8) {
+ region_start = temp_async->port;
+ temp_async->port = 0;
+ temp_async = current_async;
+ } else if ((temp_async->port - region_end)
+ == 8) {
+ region_end = temp_async->port;
+ temp_async->port = 0;
+ temp_async = current_async;
+ } else
+ temp_async = temp_async->next_port;
+ }
+
+ release_region(region_start,
+ region_end - region_start + 8);
+ }
+
+ temp_async = current_async->next_port;
+ kfree(current_async);
+ current_async = temp_async;
}
if (dma_buffer)
@@ -2571,13 +2592,5 @@
if (tmp_buf)
free_page((unsigned long)tmp_buf);
-
- /* free the port information */
- current_async = IRQ_ports[0];
- while (current_async != 0) {
- temp_async = current_async->next_port;
- kfree(current_async);
- current_async = temp_async;
- }
}
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov