patch-2.1.66 linux/drivers/char/serial.c
Next file: linux/drivers/char/tty_io.c
Previous file: linux/drivers/char/rocket.c
Back to the patch index
Back to the overall index
- Lines: 364
- Date:
Mon Nov 24 08:45:44 1997
- Orig file:
v2.1.65/linux/drivers/char/serial.c
- Orig date:
Wed Sep 24 20:05:47 1997
diff -u --recursive --new-file v2.1.65/linux/drivers/char/serial.c linux/drivers/char/serial.c
@@ -22,6 +22,9 @@
* 1/97: Extended dumb serial ports are a config option now.
* Saves 4k. Michael A. Griffith <grif@acm.org>
*
+ * 8/97: Fix bug in rs_set_termios with RTS
+ * Stanislav V. Voronyi <stas@uanet.kharkov.ua>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -319,13 +322,6 @@
return 0;
}
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
static inline unsigned int serial_in(struct async_struct *info, int offset)
{
#ifdef CONFIG_HUB6
@@ -541,7 +537,7 @@
ignore_char:
*status = serial_inp(info, UART_LSR);
} while (*status & UART_LSR_DR);
- queue_task(&tty->flip.tqueue, &tq_timer);
+ tty_flip_buffer_push(tty);
}
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -624,10 +620,10 @@
else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ASYNC_CALLOUT_NOHUP))) {
#ifdef SERIAL_DEBUG_OPEN
- printk("scheduling hangup...");
+ printk("doing serial hangup...");
#endif
- queue_task(&info->tqueue_hangup,
- &tq_scheduler);
+ if (info->tty)
+ tty_hangup(info->tty);
}
}
if (info->flags & ASYNC_CTS_FLOW) {
@@ -908,28 +904,6 @@
}
/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_serial_hangup() -> tty->hangup() -> rs_hangup()
- *
- */
-static void do_serial_hangup(void *private_)
-{
- struct async_struct *info = (struct async_struct *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- tty_hangup(tty);
-}
-
-
-/*
* This subroutine is called when the RS_TIMER goes off. It is used
* by the serial driver to handle ports that do not have an interrupt
* (irq=0). This doesn't work very well for 16450's, but gives barely
@@ -1062,7 +1036,6 @@
unsigned short ICP;
#endif
-
page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
@@ -1365,9 +1338,9 @@
static void change_speed(struct async_struct *info)
{
unsigned short port;
- int quot = 0, baud_base;
+ int quot = 0, baud_base, baud;
unsigned cflag, cval, fcr = 0;
- int i, bits;
+ int bits;
unsigned long flags;
if (!info->tty || !info->tty->termios)
@@ -1401,37 +1374,20 @@
#endif
/* Determine divisor based on baud rate */
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 2;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- i += 3;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- i += 4;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
- quot = info->state->custom_divisor;
- }
+ baud = tty_get_baud_rate(info->tty);
baud_base = info->state->baud_base;
- if (!quot) {
- if (baud_table[i] == 134)
+ if (baud == 38400)
+ quot = info->state->custom_divisor;
+ else {
+ if (baud == 134)
/* Special case since 134 is really 134.5 */
quot = (2*baud_base / 269);
- else if (baud_table[i])
- quot = baud_base / baud_table[i];
- /* If the quotient is ever zero, default to 9600 bps */
- if (!quot)
- quot = baud_base / 9600;
+ else if (baud)
+ quot = baud_base / baud;
}
+ /* If the quotient is ever zero, default to 9600 bps */
+ if (!quot)
+ quot = baud_base / 9600;
info->quot = quot;
info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
info->timeout += HZ/50; /* Add .02 seconds of slop */
@@ -1843,8 +1799,17 @@
if (state->flags & ASYNC_INITIALIZED) {
if (((old_state.flags & ASYNC_SPD_MASK) !=
(state->flags & ASYNC_SPD_MASK)) ||
- (old_state.custom_divisor != state->custom_divisor))
+ (old_state.custom_divisor != state->custom_divisor)) {
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
change_speed(info);
+ }
} else
retval = startup(info);
return retval;
@@ -1975,51 +1940,27 @@
return 0;
}
-
/*
- * This routine sends a break character out the serial port.
+ * rs_break() --- routine which turns the break handling on or off
*/
-static void send_break( struct async_struct * info, int duration)
+static void rs_break(struct tty_struct *tty, int break_state)
{
- if (!info->port)
- return;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + duration;
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
- cli();
- serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
- schedule();
- serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
- sti();
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-/*
- * This routine sets the break condition on the serial port.
- */
-static void begin_break(struct async_struct * info)
-{
- if (!info->port)
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_break"))
return;
- cli();
- serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC);
- sti();
-}
-/*
- * This routine clears the break condition on the serial port.
- */
-static void end_break(struct async_struct * info)
-{
if (!info->port)
return;
- cli();
- serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
- sti();
+ save_flags(flags); cli();
+ if (break_state == -1)
+ serial_out(info, UART_LCR,
+ serial_inp(info, UART_LCR) | UART_LCR_SBC);
+ else
+ serial_out(info, UART_LCR,
+ serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+ restore_flags(flags);
}
/*
@@ -2186,7 +2127,6 @@
{
int error;
struct async_struct * info = (struct async_struct *)tty->driver_data;
- int retval;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct *p_cuser; /* user space */
@@ -2202,53 +2142,6 @@
}
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, HZ/4); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCSBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- begin_break(info);
- return 0;
- case TIOCCBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- end_break(info);
- return 0;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
- case TIOCSSOFTCAR:
- error = get_user(arg, (unsigned int *) arg);
- if (error)
- return error;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
@@ -2379,8 +2272,8 @@
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) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= UART_MCR_RTS;
}
cli();
@@ -2617,10 +2510,8 @@
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
#else
return -EAGAIN;
#endif
@@ -2758,8 +2649,6 @@
info->line = line;
info->tqueue.routine = do_softint;
info->tqueue.data = info;
- info->tqueue_hangup.routine = do_serial_hangup;
- info->tqueue_hangup.data = info;
info->state = sstate;
if (sstate->info) {
kfree_s(info, sizeof(struct async_struct));
@@ -2807,7 +2696,22 @@
else
tmp_buf = (unsigned char *) page;
}
-
+
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
/*
* Start up serial port
*/
@@ -3201,7 +3105,6 @@
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 7) {
serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 6)
state->type = PORT_16750;
@@ -3316,6 +3219,7 @@
serial_driver.stop = rs_stop;
serial_driver.start = rs_start;
serial_driver.hangup = rs_hangup;
+ serial_driver.break_ctl = rs_break;
serial_driver.wait_until_sent = rs_wait_until_sent;
serial_driver.read_proc = rs_read_proc;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov