All of lore.kernel.org
 help / color / mirror / Atom feed
* [BUG]: 2.6.19.2: Weird serial core issue
@ 2007-01-31 10:49 Aubrey Li
  2007-01-31 16:21 ` Alan
  0 siblings, 1 reply; 12+ messages in thread
From: Aubrey Li @ 2007-01-31 10:49 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-serial

I insert one printk into drivers/serial/serial_core.c:
uart_set_termios() to describe the issue.
static void uart_set_termios(struct tty_struct *tty, struct termios
*old_termios)
{
 ----snip----
        unsigned int cflag = tty->termios->c_cflag;

        BUG_ON(!kernel_locked());
+++printk("new_termios flag: 0x%x, old_termios flag: 0x%x\n");
+++             cflag, old_termios->c_cflag);

----snip ----
}

When I telnet my board and run the following command:
---- root:~> stty -F /dev/ttyS0 -crtscts

I got the following result from the console of my board:
---- root:~>new_termios flag: 0x1cb1, old_termios flag: 0x80001cb1

That's correct. CRTSCTS flag is clear

But when I type "ENTER" key on the console, I got:
----root:~>new_termios flag: 0x80001cb1, old_termios flag: 0x1cb1

The CRTSCTS flag is set back. But I didn't set it back, I just type "ENTER".
I guess, Is it a serial core bug?

-Aubrey

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-01-31 10:49 [BUG]: 2.6.19.2: Weird serial core issue Aubrey Li
@ 2007-01-31 16:21 ` Alan
  2007-02-01  2:33   ` Aubrey Li
  0 siblings, 1 reply; 12+ messages in thread
From: Alan @ 2007-01-31 16:21 UTC (permalink / raw)
  To: Aubrey Li; +Cc: linux-kernel, linux-serial

> When I telnet my board and run the following command:
> ---- root:~> stty -F /dev/ttyS0 -crtscts
> 
> I got the following result from the console of my board:
> ---- root:~>new_termios flag: 0x1cb1, old_termios flag: 0x80001cb1
> 
> That's correct. CRTSCTS flag is clear
> 
> But when I type "ENTER" key on the console, I got:
> ----root:~>new_termios flag: 0x80001cb1, old_termios flag: 0x1cb1

What code is running on that console at the time. Most likely that user
code is also saving/restoring terminal settings so overwrite yours

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-01-31 16:21 ` Alan
@ 2007-02-01  2:33   ` Aubrey Li
  2007-02-01  9:45     ` Russell King
                       ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Aubrey Li @ 2007-02-01  2:33 UTC (permalink / raw)
  To: Alan; +Cc: linux-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 1166 bytes --]

On 2/1/07, Alan <alan@lxorguk.ukuu.org.uk> wrote:
> > When I telnet my board and run the following command:
> > ---- root:~> stty -F /dev/ttyS0 -crtscts
> >
> > I got the following result from the console of my board:
> > ---- root:~>new_termios flag: 0x1cb1, old_termios flag: 0x80001cb1
> >
> > That's correct. CRTSCTS flag is clear
> >
> > But when I type "ENTER" key on the console, I got:
> > ----root:~>new_termios flag: 0x80001cb1, old_termios flag: 0x1cb1
>
> What code is running on that console at the time. Most likely that user
> code is also saving/restoring terminal settings so overwrite yours
>

I implemented the serial driver by myself, :). See the attachment.
I didn't save/restore terminal setting in the my_set_termios().

I trace this back till tty_tioctl(..., unsigned long arg), everytime I
type "ENTER" key,
the argument "arg" passed into tty_ioctl() is the address of a termios
structure, which include wrong c_cflag. It seems once the flag is
assigned by uart_set_options the first time, it's never changed. So
even userspace application changed the flag, it will be set back soon.
I'll dig into it. But I still think it's a bug.

-Aubrey

[-- Attachment #2: bfin_5xx.c --]
[-- Type: application/octet-stream, Size: 25744 bytes --]

/*
 * File:         drivers/serial/bfin_5xx.c
 * Based on:     Based on drivers/serial/sa1100.c
 * Author:       Aubrey Li <aubrey.li@analog.com>
 *
 * Created:
 * Description:  Driver for blackfin 5xx serial ports
 *
 * Rev:          $Id: bfin_5xx.c 2704 2007-01-30 09:53:59Z aubrey $
 *
 * Modified:
 *               Copyright 2006 Analog Devices Inc.
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see the file COPYING, or write
 * to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>

#include <asm/mach/bfin_serial_5xx.h>

#ifdef CONFIG_SERIAL_BFIN_DMA
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/cacheflush.h>
#endif

/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_BFIN_MAJOR	TTY_MAJOR
#define MINOR_START		64

/*
 * Setup for console. Argument comes from the menuconfig
 */

#if defined(CONFIG_BAUD_9600)
#define CONSOLE_BAUD_RATE       9600
#elif defined(CONFIG_BAUD_19200)
#define CONSOLE_BAUD_RATE       19200
#elif defined(CONFIG_BAUD_38400)
#define CONSOLE_BAUD_RATE       38400
#elif defined(CONFIG_BAUD_57600)
#define CONSOLE_BAUD_RATE       57600
#elif defined(CONFIG_BAUD_115200)
#define CONSOLE_BAUD_RATE       115200
#endif

#define DMA_RX_XCOUNT		512
#define DMA_RX_YCOUNT		(PAGE_SIZE / DMA_RX_XCOUNT)

#define DMA_RX_FLUSH_JIFFIES	5

#ifdef CONFIG_SERIAL_BFIN_DMA
wait_queue_head_t bfin_serial_tx_queue[NR_PORTS];
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
#else
static void bfin_serial_do_work(void *);
static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
static void local_put_char(struct bfin_serial_port *uart, char ch);
#endif

static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
static int bfin_serial_calc_baud(unsigned int uartclk, unsigned int baud);

/*
 * interrupts are disabled on entry
 */
static void bfin_serial_stop_tx(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

#ifdef CONFIG_SERIAL_BFIN_DMA
        disable_dma(uart->tx_dma_channel);
#else
	unsigned short ier;

	ier = UART_GET_IER(uart);
	ier &= ~ETBEI;
	UART_PUT_IER(uart, ier);
#endif
}

/*
 * port is locked and interrupts are disabled
 */
static void bfin_serial_start_tx(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

#ifdef CONFIG_SERIAL_BFIN_DMA
	bfin_serial_dma_tx_chars(uart);
#else
	unsigned short ier;
	ier = UART_GET_IER(uart);
	ier |= ETBEI;
	UART_PUT_IER(uart, ier);
	bfin_serial_tx_chars(uart);
#endif
}

/*
 * Interrupts are enabled
 */
static void bfin_serial_stop_rx(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
	unsigned short ier;

	ier = UART_GET_IER(uart);
	ier &= ERBFI;
	UART_PUT_IER(uart, ier);
}

/*
 * Set the modem control timer to fire immediately.
 */
static void bfin_serial_enable_ms(struct uart_port *port)
{
}

#ifdef CONFIG_SERIAL_BFIN_PIO
static void local_put_char(struct bfin_serial_port *uart, char ch)
{
	unsigned short status;
	int flags = 0;

	local_irq_save(flags);

	do {
		status = UART_GET_LSR(uart);
	} while (!(status & THRE));

	UART_PUT_CHAR(uart, ch);

	local_irq_restore(flags);
}

static void
bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
	struct tty_struct *tty = uart->port.info?uart->port.info->tty:0;
	unsigned int status, ch, flg;
#if defined(CONFIG_BF531) || defined(CONFIG_BF532) || defined(CONFIG_BF533)
	static int in_break = 0;
#endif

	status = UART_GET_LSR(uart);
 	ch = UART_GET_CHAR(uart);
 	uart->port.icount.rx++;

#if defined(CONFIG_BF531) || defined(CONFIG_BF532) || defined(CONFIG_BF533)
	if (in_break) {
		if (ch != 0) {
			in_break = 0;
			ch = UART_GET_CHAR(uart);
		}
		return;
	}
#endif

	if (status & BI) {
#if defined(CONFIG_BF531) || defined(CONFIG_BF532) || defined(CONFIG_BF533)
		in_break = 1;
#endif
		uart->port.icount.brk++;
		if (uart_handle_break(&uart->port))
			goto ignore_char;
		flg = TTY_BREAK;
	} else if (status & PE) {
		flg = TTY_PARITY;
		uart->port.icount.parity++;
	} else if (status & OE) {
		flg = TTY_OVERRUN;
		uart->port.icount.overrun++;
	} else if (status & FE) {
		flg = TTY_FRAME;
		uart->port.icount.frame++;
	} else
		flg = TTY_NORMAL;

	if (uart_handle_sysrq_char(&uart->port, ch))
		goto ignore_char;
	if (tty)
		uart_insert_char(&uart->port, status, 2, ch, flg);

ignore_char:
	if (tty)
		tty_flip_buffer_push(tty);
}

static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
{
	struct circ_buf *xmit = &uart->port.info->xmit;

	if (uart->port.x_char) {
		UART_PUT_CHAR(uart, uart->port.x_char);
		uart->port.icount.tx++;
		uart->port.x_char = 0;
		return;
	}
	/*
	 * Check the modem control lines before
	 * transmitting anything.
	 */
	bfin_serial_mctrl_check(uart);

	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
		bfin_serial_stop_tx(&uart->port);
		return;
	}

	local_put_char(uart, xmit->buf[xmit->tail]);
	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
	uart->port.icount.tx++;

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&uart->port);

	if (uart_circ_empty(xmit))
		bfin_serial_stop_tx(&uart->port);
}

static irqreturn_t bfin_serial_int(int irq, void *dev_id)
{
	struct bfin_serial_port *uart = dev_id;
	unsigned short status;

	spin_lock(&uart->port.lock);
	status = UART_GET_IIR(uart);
	do {
		if ((status & IIR_STATUS) == IIR_TX_READY)
			bfin_serial_tx_chars(uart);
		if ((status & IIR_STATUS) == IIR_RX_READY)
			bfin_serial_rx_chars(uart);
		status = UART_GET_IIR(uart);
	} while (status &(IIR_TX_READY | IIR_RX_READY));
	spin_unlock(&uart->port.lock);
	return IRQ_HANDLED;
}

static void bfin_serial_do_work(void *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

	bfin_serial_mctrl_check(uart);
}

#endif

#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
{
	struct circ_buf *xmit = &uart->port.info->xmit;
	unsigned short ier;
	int flags = 0;

	if (!uart->tx_done)
		return;

	uart->tx_done = 0;

	if (uart->port.x_char) {
		UART_PUT_CHAR(uart, uart->port.x_char);
		uart->port.icount.tx++;
		uart->port.x_char = 0;
		uart->tx_done = 1;
		return;
	}
	/*
	 * Check the modem control lines before
	 * transmitting anything.
	 */
	bfin_serial_mctrl_check(uart);

	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
		bfin_serial_stop_tx(&uart->port);
		uart->tx_done = 1;
		return;
	}

	local_irq_save(flags);
	uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
	if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
		uart->tx_count = UART_XMIT_SIZE - xmit->tail;
	blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
					(unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
	set_dma_config(uart->tx_dma_channel,
		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
			INTR_ON_BUF,
			DIMENSION_LINEAR,
			DATA_SIZE_8));
	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
	set_dma_x_modify(uart->tx_dma_channel, 1);
	enable_dma(uart->tx_dma_channel);
	ier = UART_GET_IER(uart);
	ier |= ETBEI;
	UART_PUT_IER(uart, ier);
	local_irq_restore(flags);
}

static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
{
	struct tty_struct *tty = uart->port.info->tty;
	int i, flg, status;

	status = UART_GET_LSR(uart);
	uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;

        if (status & BI) {
                uart->port.icount.brk++;
                if (uart_handle_break(&uart->port))
                        goto dma_ignore_char;
                flg = TTY_BREAK;
        } else if (status & PE) {
                flg = TTY_PARITY;
                uart->port.icount.parity++;
        } else if (status & OE) {
                flg = TTY_OVERRUN;
                uart->port.icount.overrun++;
        } else if (status & FE) {
                flg = TTY_FRAME;
                uart->port.icount.frame++;
        } else
                flg = TTY_NORMAL;

	for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
		if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
			goto dma_ignore_char;
		uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg);
	}
dma_ignore_char:
	tty_flip_buffer_push(tty);
}

void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
	int x_pos, pos;
	int flags = 0;

	bfin_serial_dma_tx_chars(uart);

	local_irq_save(flags);
	x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
	if (x_pos == DMA_RX_XCOUNT)
		x_pos = 0;

	pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;

	if (pos>uart->rx_dma_buf.tail) {
		uart->rx_dma_buf.tail = pos;
		bfin_serial_dma_rx_chars(uart);
		uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
	}
	local_irq_restore(flags);
	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
	add_timer(&(uart->rx_dma_timer));
}

static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
{
	struct bfin_serial_port *uart = dev_id;
	struct circ_buf *xmit = &uart->port.info->xmit;
	unsigned short ier;

	spin_lock(&uart->port.lock);
	if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
		clear_dma_irqstat(uart->tx_dma_channel);
		disable_dma(uart->tx_dma_channel);
		ier = UART_GET_IER(uart);
		ier &= ~ETBEI;
		UART_PUT_IER(uart, ier);
		xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
		uart->port.icount.tx+=uart->tx_count;

		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
			uart_write_wakeup(&uart->port);

		if (uart_circ_empty(xmit))
			bfin_serial_stop_tx(&uart->port);
		uart->tx_done = 1;
	}

	spin_unlock(&uart->port.lock);
	return IRQ_HANDLED;
}

static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{
	struct bfin_serial_port *uart = dev_id;
	unsigned short irqstat;

	uart->rx_dma_nrows++;
	if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
		uart->rx_dma_nrows = 0;
		uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
		bfin_serial_dma_rx_chars(uart);
		uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
	}
	spin_lock(&uart->port.lock);
	irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
	clear_dma_irqstat(uart->rx_dma_channel);

	spin_unlock(&uart->port.lock);
	return IRQ_HANDLED;
}
#endif

/*
 * Return TIOCSER_TEMT when transmitter is not busy.
 */
static unsigned int bfin_serial_tx_empty(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
	unsigned short lsr;

	lsr = UART_GET_LSR(uart);
	if (lsr & THRE)
		return TIOCSER_TEMT;
	else
		return 0;
}

static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
{
	/* Hardware flow control is only supported on the first port */
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
	if ((bfin_read16(CTS_PORT) & (1 << CTS_PIN)) && (port->line == 0))
		return TIOCM_DSR | TIOCM_CAR;
	else
#endif
		return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}

static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
	if (mctrl & TIOCM_RTS)
		bfin_write16(RTS_PORT, bfin_read16(RTS_PORT) & (~1 << RTS_PIN));
	else
		bfin_write16(RTS_PORT, bfin_read16(RTS_PORT) | (1 << RTS_PIN));
#endif
}

/*
 * Handle any change of modem status signal since we were last called.
 */
static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
	unsigned int status;
# ifdef CONFIG_SERIAL_BFIN_DMA
	struct uart_info *info = uart->port.info;
	struct tty_struct *tty = info->tty;

	status = bfin_serial_get_mctrl(&uart->port);
	if (!(status & TIOCM_CTS)) {
		tty->hw_stopped = 1;
	} else {
		tty->hw_stopped = 0;
	}
# else
	status = bfin_serial_get_mctrl(&uart->port);
	uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
	if (!(status & TIOCM_CTS))
		schedule_work(&uart->cts_workqueue);
# endif
#endif
}

/*
 * Interrupts are always disabled.
 */
static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
{
}

static int bfin_serial_startup(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

#ifdef CONFIG_SERIAL_BFIN_DMA
	dma_addr_t dma_handle;

	if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
		printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
		return -EBUSY;
	}

	if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
		printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
		free_dma(uart->rx_dma_channel);
		return -EBUSY;
	}

	set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
	set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);

	uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
	uart->rx_dma_buf.head = 0;
	uart->rx_dma_buf.tail = 0;
	uart->rx_dma_nrows = 0;

	set_dma_config(uart->rx_dma_channel,
		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
				INTR_ON_ROW, DIMENSION_2D,
				DATA_SIZE_8));
	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
	set_dma_x_modify(uart->rx_dma_channel, 1);
	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
	set_dma_y_modify(uart->rx_dma_channel, 1);
	set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
	enable_dma(uart->rx_dma_channel);

	uart->rx_dma_timer.data = (unsigned long)(uart);
	uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
	add_timer(&(uart->rx_dma_timer));
#else
	if (request_irq
	    (uart->port.irq, bfin_serial_int, SA_INTERRUPT | SA_SHIRQ,
	     "BFIN_UART0_RX", uart)) {
		printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
		return -EBUSY;
	}

	if (request_irq
	    (uart->port.irq+1, bfin_serial_int, SA_INTERRUPT | SA_SHIRQ,
	     "BFIN_UART0_TX", uart)) {
		printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
		free_irq(uart->port.irq, uart);
		return -EBUSY;
	}
#endif
	UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
	return 0;
}

static void bfin_serial_shutdown(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

#ifdef CONFIG_SERIAL_BFIN_DMA
	disable_dma(uart->tx_dma_channel);
	free_dma(uart->tx_dma_channel);
	disable_dma(uart->rx_dma_channel);
	free_dma(uart->rx_dma_channel);
	del_timer(&(uart->rx_dma_timer));
#else
	free_irq(uart->port.irq, uart);
	free_irq(uart->port.irq+1, uart);
#endif
}

static void
bfin_serial_set_termios(struct uart_port *port, struct termios *termios,
		   struct termios *old)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
	unsigned long flags;
	unsigned int baud, quot;
	unsigned short val, ier;

	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
	quot = bfin_serial_calc_baud(port->uartclk, baud);
	spin_lock_irqsave(&uart->port.lock, flags);

	/* Disable UART */
	ier = UART_GET_IER(uart);
	UART_PUT_IER(uart, 0);

	/* Set DLAB in LCR to Access DLL and DLH */
	val = UART_GET_LCR(uart);
	val |= DLAB;
	UART_PUT_LCR(uart, val);
	__builtin_bfin_ssync();

	UART_PUT_DLL(uart, quot & 0xFF);
	__builtin_bfin_ssync();
	UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
	__builtin_bfin_ssync();
	
	/* Clear DLAB in LCR to Access THR RBR IER */
	val = UART_GET_LCR(uart);
	val &= ~DLAB;
	UART_PUT_LCR(uart, val);
	__builtin_bfin_ssync();

	/* Enable UART */
	UART_PUT_IER(uart, ier);

	val = UART_GET_GCTL(uart);
	val |= UCEN;
	UART_PUT_GCTL(uart, val);

	spin_unlock_irqrestore(&uart->port.lock, flags);
}

static const char *bfin_serial_type(struct uart_port *port)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

	return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
}

/*
 * Release the memory region(s) being used by 'port'.
 */
static void bfin_serial_release_port(struct uart_port *port)
{
}

/*
 * Request the memory region(s) being used by 'port'.
 */
static int bfin_serial_request_port(struct uart_port *port)
{
	return 0;
}

/*
 * Configure/autoconfigure the port.
 */
static void bfin_serial_config_port(struct uart_port *port, int flags)
{
	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

	if (flags & UART_CONFIG_TYPE &&
	    bfin_serial_request_port(&uart->port) == 0)
		uart->port.type = PORT_BFIN;
}

/*
 * Verify the new serial_struct (for TIOCSSERIAL).
 * The only change we allow are to the flags and type, and
 * even then only between PORT_BFIN and PORT_UNKNOWN
 */
static int
bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	return 0;
}

static struct uart_ops bfin_serial_pops = {
	.tx_empty	= bfin_serial_tx_empty,
	.set_mctrl	= bfin_serial_set_mctrl,
	.get_mctrl	= bfin_serial_get_mctrl,
	.stop_tx	= bfin_serial_stop_tx,
	.start_tx	= bfin_serial_start_tx,
	.stop_rx	= bfin_serial_stop_rx,
	.enable_ms	= bfin_serial_enable_ms,
	.break_ctl	= bfin_serial_break_ctl,
	.startup	= bfin_serial_startup,
	.shutdown	= bfin_serial_shutdown,
	.set_termios	= bfin_serial_set_termios,
	.type		= bfin_serial_type,
	.release_port	= bfin_serial_release_port,
	.request_port	= bfin_serial_request_port,
	.config_port	= bfin_serial_config_port,
	.verify_port	= bfin_serial_verify_port,
};

static int bfin_serial_calc_baud(unsigned int uartclk, unsigned int baud)
{
	int quot;

	quot = uartclk / (baud * 8);
	if ((quot & 0x1) == 1) {
		quot++;
	}
	return quot/2;
}

static void __init bfin_serial_init_ports(void)
{
	static int first = 1;
	int i;
	unsigned short val;
	int quot;

	if (!first)
		return;
	first = 0;
	bfin_serial_hw_init();

	for (i = 0; i < NR_PORTS; i++) {
		bfin_serial_ports[i].port.uartclk   = get_sclk();
		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
		bfin_serial_ports[i].port.line      = i;
		bfin_serial_ports[i].port.iotype    = UPIO_MEM;
		bfin_serial_ports[i].port.membase   = (void __iomem *)uart_base_addr[i];
		bfin_serial_ports[i].port.mapbase   = uart_base_addr[i];
		bfin_serial_ports[i].port.irq       = uart_irq[i];
		bfin_serial_ports[i].port.flags     = UPF_BOOT_AUTOCONF;
#ifdef CONFIG_SERIAL_BFIN_DMA
		bfin_serial_ports[i].tx_done	    = 1;
		bfin_serial_ports[i].tx_count	    = 0;
		bfin_serial_ports[i].tx_dma_channel = uart_tx_dma_channel[i];
		bfin_serial_ports[i].rx_dma_channel = uart_rx_dma_channel[i];

		init_timer(&(bfin_serial_ports[i].rx_dma_timer));
#else
		INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work, &bfin_serial_ports[i]);
#endif

		quot = bfin_serial_calc_baud(bfin_serial_ports[i].port.uartclk, CONSOLE_BAUD_RATE);

		/* Disable UART */
		UART_PUT_GCTL(&bfin_serial_ports[i], 0);

		/* Set DLAB in LCR to Access DLL and DLH */
		val = UART_GET_LCR(&bfin_serial_ports[i]);
		val |= DLAB;
		UART_PUT_LCR(&bfin_serial_ports[i], val);

		UART_PUT_DLL(&bfin_serial_ports[i], quot & 0xFF);
		UART_PUT_DLH(&bfin_serial_ports[i], (quot >> 8) & 0xFF);

		/* Clear DLAB in LCR to Access THR RBR IER */
		val = UART_GET_LCR(&bfin_serial_ports[i]);
		val &= ~DLAB;
		UART_PUT_LCR(&bfin_serial_ports[i], val);

		/* Set LCR to Word Lengh 8-bit word select */
		val = WLS(8);
		UART_PUT_LCR(&bfin_serial_ports[i], val);

		 /* Enable UART */
		val = UART_GET_GCTL(&bfin_serial_ports[i]);
		val |= UCEN;
		UART_PUT_GCTL(&bfin_serial_ports[i], val);
	}
}

#ifdef CONFIG_SERIAL_BFIN_CONSOLE
/*
 * Interrupts are disabled on entering
 */
static void
bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
{
	struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
	int flags = 0;
	unsigned short status, tmp;
	int i;

	local_irq_save(flags);

	for (i = 0; i < count; i++) {
		do {
			status = UART_GET_LSR(uart);
		} while (!(status & THRE));

		tmp = UART_GET_LCR(uart);
		tmp &= ~DLAB;
		UART_PUT_LCR(uart, tmp);

		UART_PUT_CHAR(uart, s[i]);
		if (s[i] == '\n') {
			do {
				status = UART_GET_LSR(uart);
			} while(!(status & THRE));
			UART_PUT_CHAR(uart, '\r');
		}
	}

	local_irq_restore(flags);
}

/*
 * If the port was already initialised (eg, by a boot loader),
 * try to determine the current setup.
 */
static void __init
bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
			   int *parity, int *bits)
{
	unsigned short status;

	status = UART_GET_IER(uart) & (ERBFI | ETBEI);
	if (status == (ERBFI | ETBEI)) {
		/* ok, the port was enabled */
		unsigned short lcr, val;
		unsigned short dlh, dll;

		lcr = UART_GET_LCR(uart);

		*parity = 'n';
		if (lcr & PEN) {
			if (lcr & EPS)
				*parity = 'e';
			else
				*parity = 'o';
		}
		switch (lcr & 0x03) {
			case 0:	*bits = 5; break;
			case 1:	*bits = 6; break;
			case 2:	*bits = 7; break;
			case 3:	*bits = 8; break;
		}
		/* Set DLAB in LCR to Access DLL and DLH */
		val = UART_GET_LCR(uart);
		val |= DLAB;
		UART_PUT_LCR(uart, val);

		dll = UART_GET_DLL(uart);
		dlh = UART_GET_DLH(uart);

		/* Clear DLAB in LCR to Access THR RBR IER */
		val = UART_GET_LCR(uart);
		val &= ~DLAB;
		UART_PUT_LCR(uart, val);

		*baud = get_sclk() / (16*(dll | dlh << 8));
	}
	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
}

static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
	struct bfin_serial_port *uart;
	int baud = CONSOLE_BAUD_RATE;
	int bits = 8;
	int parity = 'n';
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
	int flow = 'r';
#else
	int flow = 'n';
#endif

	/*
	 * Check whether an invalid uart number has been specified, and
	 * if so, search for the first available port that does have
	 * console support.
	 */
	if (co->index == -1 || co->index >= NR_PORTS)
		co->index = 0;
	uart = &bfin_serial_ports[co->index];

	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);
	else
		bfin_serial_console_get_options(uart, &baud, &parity, &bits);

	return uart_set_options(&uart->port, co, baud, parity, bits, flow);
}

static struct uart_driver bfin_serial_reg;
static struct console bfin_serial_console = {
	.name		= "ttyS",
	.write		= bfin_serial_console_write,
	.device		= uart_console_device,
	.setup		= bfin_serial_console_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
	.data		= &bfin_serial_reg,
};

static int __init bfin_serial_rs_console_init(void)
{
	bfin_serial_init_ports();
	register_console(&bfin_serial_console);
	return 0;
}
console_initcall(bfin_serial_rs_console_init);

#define BFIN_SERIAL_CONSOLE	&bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE	NULL
#endif

static struct uart_driver bfin_serial_reg = {
	.owner			= THIS_MODULE,
	.driver_name		= "bfin-uart",
	.dev_name		= "ttyS",
	.major			= SERIAL_BFIN_MAJOR,
	.minor			= MINOR_START,
	.nr			= NR_PORTS,
	.cons			= BFIN_SERIAL_CONSOLE,
};

static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
{
	struct bfin_serial_port *uart = platform_get_drvdata(dev);

	if (uart)
		uart_suspend_port(&bfin_serial_reg, &uart->port);

	return 0;
}

static int bfin_serial_resume(struct platform_device *dev)
{
	struct bfin_serial_port *uart = platform_get_drvdata(dev);

	if (uart)
		uart_resume_port(&bfin_serial_reg, &uart->port);

	return 0;
}

static int bfin_serial_probe(struct platform_device *dev)
{
	struct resource *res = dev->resource;
	int i;

	for (i = 0; i < dev->num_resources; i++, res++)
		if (res->flags & IORESOURCE_MEM)
			break;

	if (i < dev->num_resources) {
		for (i = 0; i < NR_PORTS; i++, res++) {
			if (bfin_serial_ports[i].port.mapbase != res->start)
				continue;
			bfin_serial_ports[i].port.dev = &dev->dev;
			uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
			platform_set_drvdata(dev, &bfin_serial_ports[i]);
		}
	}

	return 0;
}

static int bfin_serial_remove(struct platform_device *pdev)
{
	struct bfin_serial_port *uart = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);

	if (uart)
		uart_remove_one_port(&bfin_serial_reg, &uart->port);

	return 0;
}

static struct platform_driver bfin_serial_driver = {
	.probe		= bfin_serial_probe,
	.remove		= bfin_serial_remove,
	.suspend	= bfin_serial_suspend,
	.resume		= bfin_serial_resume,
	.driver		= {
		.name	= "bfin-uart",
	},
};

static int __init bfin_serial_init(void)
{
	int ret;

	pr_info("Serial: Blackfin serial driver\n");

	bfin_serial_init_ports();

	ret = uart_register_driver(&bfin_serial_reg);
	if (ret == 0) {
		ret = platform_driver_register(&bfin_serial_driver);
		if (ret) {
			pr_debug("uart register failed\n");
			uart_unregister_driver(&bfin_serial_reg);
		}
	}
	return ret;
}

static void __exit bfin_serial_exit(void)
{
	platform_driver_unregister(&bfin_serial_driver);
	uart_unregister_driver(&bfin_serial_reg);
}

module_init(bfin_serial_init);
module_exit(bfin_serial_exit);

MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
MODULE_DESCRIPTION("Blackfin generic serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_BFIN_MAJOR);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01  2:33   ` Aubrey Li
@ 2007-02-01  9:45     ` Russell King
  2007-02-01 10:09       ` Aubrey Li
       [not found]     ` <000201c745d9$4577fe20$2e01a8c0@acksys.local>
  2007-02-01 12:02     ` Alan
  2 siblings, 1 reply; 12+ messages in thread
From: Russell King @ 2007-02-01  9:45 UTC (permalink / raw)
  To: Aubrey Li; +Cc: Alan, linux-kernel, linux-serial

On Thu, Feb 01, 2007 at 10:33:40AM +0800, Aubrey Li wrote:
> On 2/1/07, Alan <alan@lxorguk.ukuu.org.uk> wrote:
> >What code is running on that console at the time. Most likely that user
> >code is also saving/restoring terminal settings so overwrite yours
> >
> 
> I implemented the serial driver by myself, :). See the attachment.
> I didn't save/restore terminal setting in the my_set_termios().
> 
> I trace this back till tty_tioctl(..., unsigned long arg), everytime I
> type "ENTER" key,
> the argument "arg" passed into tty_ioctl() is the address of a termios
> structure, which include wrong c_cflag.

If userspace is issuing an ioctl to re-enable crtscts, and the kernel
is obliging, how can this be a kernel bug?

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01  9:45     ` Russell King
@ 2007-02-01 10:09       ` Aubrey Li
  2007-02-01 11:16         ` Russell King
  0 siblings, 1 reply; 12+ messages in thread
From: Aubrey Li @ 2007-02-01 10:09 UTC (permalink / raw)
  To: Aubrey Li, Alan, linux-kernel, linux-serial

On 2/1/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> On Thu, Feb 01, 2007 at 10:33:40AM +0800, Aubrey Li wrote:
> > On 2/1/07, Alan <alan@lxorguk.ukuu.org.uk> wrote:
> > >What code is running on that console at the time. Most likely that user
> > >code is also saving/restoring terminal settings so overwrite yours
> > >
> >
> > I implemented the serial driver by myself, :). See the attachment.
> > I didn't save/restore terminal setting in the my_set_termios().
> >
> > I trace this back till tty_tioctl(..., unsigned long arg), everytime I
> > type "ENTER" key,
> > the argument "arg" passed into tty_ioctl() is the address of a termios
> > structure, which include wrong c_cflag.
>
> If userspace is issuing an ioctl to re-enable crtscts, and the kernel
> is obliging, how can this be a kernel bug?

But the fact is not.
1) kernel boot up and enable crtscts by default
2) issue an ioctl to disable crtscts.
3) not do anything but type "ENTER", kernel re-enable crtscts.

That's wrong. Terminal setting seems not be recorded by the serial core.
Is it clear?

-Aubrey

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
       [not found]     ` <000201c745d9$4577fe20$2e01a8c0@acksys.local>
@ 2007-02-01 10:38       ` Aubrey Li
  2007-02-01 15:19         ` Paul Fulghum
  0 siblings, 1 reply; 12+ messages in thread
From: Aubrey Li @ 2007-02-01 10:38 UTC (permalink / raw)
  To: Tosoni; +Cc: linux-kernel, linux-serial, Alan

On 2/1/07, Tosoni <jp.tosoni@acksys.fr> wrote:
> If I understand Alan'answer correctly:
>
> You appear to use a *shell* on that console. The shell gets your ENTER key
> and in the succeeding processing the shell resets the crtscts flag to what
> the shell thinks is right for him.
>
> The shell must make some tty tweaking in order to allow you to edit the
> commands.
>
> You must disable login, shell and anything on that port in order to make a
> significant test. But beware that in this case you will close and reopen the
> port each time you run your test.
>

But the problem seems not like you said.
if enable crtscts by default, your thoughts makes sense.
But if disable crtscts by default, the fact is not as your thoughts.
The following is the test result on my side.
===================================
root:~> cflag = 0x80001cb1, old = 0x1cb1

cflag = 0x1cb1, old = 0x80001cb1
cflag = 0x1cb1, old = 0x1cb1
===================================
When run "stty -F /dev/ttyS0 crtscts",
I got
------------
root:~> cflag = 0x80001cb1, old = 0x1cb1
------------
That means crtscts in the old terminal setting is disabled. Now it's enabled.


But When I type "ENTER" key,

I got
------------
cflag = 0x1cb1, old = 0x80001cb1
cflag = 0x1cb1, old = 0x1cb1
------------
That means terminal setting is back to crtscts disabled. But here I
didn't do anything to disable it, I just type "ENTER", crtscts setting
should keep enabled. What makes it back to disabled? Now I guess there
must be something wrong with serial core.

-Aubrey

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01 10:09       ` Aubrey Li
@ 2007-02-01 11:16         ` Russell King
  2007-02-01 17:54           ` Aubrey Li
  0 siblings, 1 reply; 12+ messages in thread
From: Russell King @ 2007-02-01 11:16 UTC (permalink / raw)
  To: Aubrey Li; +Cc: Alan, linux-kernel, linux-serial

On Thu, Feb 01, 2007 at 06:09:24PM +0800, Aubrey Li wrote:
> On 2/1/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> >On Thu, Feb 01, 2007 at 10:33:40AM +0800, Aubrey Li wrote:
> >> On 2/1/07, Alan <alan@lxorguk.ukuu.org.uk> wrote:
> >> >What code is running on that console at the time. Most likely that user
> >> >code is also saving/restoring terminal settings so overwrite yours
> >> >
> >>
> >> I implemented the serial driver by myself, :). See the attachment.
> >> I didn't save/restore terminal setting in the my_set_termios().
> >>
> >> I trace this back till tty_tioctl(..., unsigned long arg), everytime I
> >> type "ENTER" key,
> >> the argument "arg" passed into tty_ioctl() is the address of a termios
> >> structure, which include wrong c_cflag.
> >
> >If userspace is issuing an ioctl to re-enable crtscts, and the kernel
> >is obliging, how can this be a kernel bug?
> 
> But the fact is not.
> 1) kernel boot up and enable crtscts by default
> 2) issue an ioctl to disable crtscts.
> 3) not do anything but type "ENTER", kernel re-enable crtscts.
> 
> That's wrong. Terminal setting seems not be recorded by the serial core.

serial core does not and should not "record" the terminal settings.
That's the job of the tty layer.

> Is it clear?

No.  You haven't analysed the call path causing tty_ioctl() to be
invoked, so you have no basis to point the finger *anywhere* at the
moment.

Find out from where tty_ioctl() is called - maybe by adding a call
to dump_stack().  I think you'll find it is coming from userspace.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01  2:33   ` Aubrey Li
  2007-02-01  9:45     ` Russell King
       [not found]     ` <000201c745d9$4577fe20$2e01a8c0@acksys.local>
@ 2007-02-01 12:02     ` Alan
  2 siblings, 0 replies; 12+ messages in thread
From: Alan @ 2007-02-01 12:02 UTC (permalink / raw)
  To: Aubrey Li; +Cc: linux-kernel, linux-serial

> I implemented the serial driver by myself, :). See the attachment.
> I didn't save/restore terminal setting in the my_set_termios().

Driver looks fine. 

> I trace this back till tty_tioctl(..., unsigned long arg), everytime I
> type "ENTER" key,
> the argument "arg" passed into tty_ioctl() is the address of a termios
> structure, which include wrong c_cflag. It seems once the flag is
> assigned by uart_set_options the first time, it's never changed. So
> even userspace application changed the flag, it will be set back soon.
> I'll dig into it. But I still think it's a bug.

Which application (see from current->pid) seems to be calling the
tty_ioctl with the "wrong flag" ?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01 10:38       ` Aubrey Li
@ 2007-02-01 15:19         ` Paul Fulghum
  0 siblings, 0 replies; 12+ messages in thread
From: Paul Fulghum @ 2007-02-01 15:19 UTC (permalink / raw)
  To: Aubrey Li; +Cc: Tosoni, linux-kernel, linux-serial, Alan

Aubrey Li wrote:
> But When I type "ENTER" key,
> 
> I got
> ------------
> cflag = 0x1cb1, old = 0x80001cb1
> cflag = 0x1cb1, old = 0x1cb1
> ------------
> That means terminal setting is back to crtscts disabled. But here I
> didn't do anything to disable it, I just type "ENTER", crtscts setting
> should keep enabled. What makes it back to disabled? Now I guess there
> must be something wrong with serial core.

Is there an mgetty or similar program monitoring
the same serial port?

-- 
Paul Fulghum
Microgate Systems, Ltd.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01 11:16         ` Russell King
@ 2007-02-01 17:54           ` Aubrey Li
  2007-02-01 19:09             ` Russell King
  2007-02-02  3:34             ` Christopher Curtis
  0 siblings, 2 replies; 12+ messages in thread
From: Aubrey Li @ 2007-02-01 17:54 UTC (permalink / raw)
  To: Aubrey Li, Alan, linux-kernel, linux-serial

On 2/1/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> On Thu, Feb 01, 2007 at 06:09:24PM +0800, Aubrey Li wrote:
> > On 2/1/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> > >On Thu, Feb 01, 2007 at 10:33:40AM +0800, Aubrey Li wrote:
> > >> On 2/1/07, Alan <alan@lxorguk.ukuu.org.uk> wrote:
> > >> >What code is running on that console at the time. Most likely that user
> > >> >code is also saving/restoring terminal settings so overwrite yours
> > >> >
> > >>
> > >> I implemented the serial driver by myself, :). See the attachment.
> > >> I didn't save/restore terminal setting in the my_set_termios().
> > >>
> > >> I trace this back till tty_tioctl(..., unsigned long arg), everytime I
> > >> type "ENTER" key,
> > >> the argument "arg" passed into tty_ioctl() is the address of a termios
> > >> structure, which include wrong c_cflag.
> > >
> > >If userspace is issuing an ioctl to re-enable crtscts, and the kernel
> > >is obliging, how can this be a kernel bug?
> >
> > But the fact is not.
> > 1) kernel boot up and enable crtscts by default
> > 2) issue an ioctl to disable crtscts.
> > 3) not do anything but type "ENTER", kernel re-enable crtscts.
> >
> > That's wrong. Terminal setting seems not be recorded by the serial core.
>
> serial core does not and should not "record" the terminal settings.
> That's the job of the tty layer.

OK, if tty layer save the new terminal settings to an old one properly,
How could this happen?

>
> > Is it clear?
>
> No.  You haven't analysed the call path causing tty_ioctl() to be
> invoked, so you have no basis to point the finger *anywhere* at the
> moment.
>
> Find out from where tty_ioctl() is called - maybe by adding a call
> to dump_stack().  I think you'll find it is coming from userspace.
>

If I recall correctly, the call path is as follows:

sys_ioctl->vfs_ioctl->do_ioctl->tty_ioctl->n_tty_ioctl->set_termios,

In set_termios, tmp_termios will be pointed to the argument "arg",
which includes the   wrong c_cflag.

Yes, from the back trace stack, it appears to come from userspace. But
I didn't startup any application. If there should be one, I think it's
shell.

But why shell remembers the initial terminal settings correctly, other
than last inital terminal settings? It must be passed from kernel
space, from tty layer, right?

I can't believe it's caused by the userspace, I'll go further to find
the root cause.

-Aubrey

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01 17:54           ` Aubrey Li
@ 2007-02-01 19:09             ` Russell King
  2007-02-02  3:34             ` Christopher Curtis
  1 sibling, 0 replies; 12+ messages in thread
From: Russell King @ 2007-02-01 19:09 UTC (permalink / raw)
  To: Aubrey Li; +Cc: Alan, linux-kernel, linux-serial

On Fri, Feb 02, 2007 at 01:54:23AM +0800, Aubrey Li wrote:
> On 2/1/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> >serial core does not and should not "record" the terminal settings.
> >That's the job of the tty layer.
> 
> OK, if tty layer save the new terminal settings to an old one properly,
> How could this happen?

I don't understand that comment.

> >No.  You haven't analysed the call path causing tty_ioctl() to be
> >invoked, so you have no basis to point the finger *anywhere* at the
> >moment.
> >
> >Find out from where tty_ioctl() is called - maybe by adding a call
> >to dump_stack().  I think you'll find it is coming from userspace.
> >
> 
> If I recall correctly, the call path is as follows:
> 
> sys_ioctl->vfs_ioctl->do_ioctl->tty_ioctl->n_tty_ioctl->set_termios,

And here is the proof that it's *userspace* which is effecting this change.
If "sys_ioctl" is the very first function in the list then that's a result
of some userspace process issuing an ioctl.

> Yes, from the back trace stack, it appears to come from userspace. But
> I didn't startup any application. If there should be one, I think it's
> shell.

Shells typically alter the termios settings - eg, to turn off echo while
they're waiting for command input.  When command input has finished (by
pressing the enter key) they typically turn it back on.

Changing the termios settings while the shell is waiting for input is not
something they expect to happen, and this is the kind of behaviour I'd
expect in this scenario.

> I can't believe it's caused by the userspace, I'll go further to find
> the root cause.

Ho hum.  Guess you're in for a long investigation then. 8/

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG]: 2.6.19.2: Weird serial core issue
  2007-02-01 17:54           ` Aubrey Li
  2007-02-01 19:09             ` Russell King
@ 2007-02-02  3:34             ` Christopher Curtis
  1 sibling, 0 replies; 12+ messages in thread
From: Christopher Curtis @ 2007-02-02  3:34 UTC (permalink / raw)
  To: Aubrey Li; +Cc: linux-serial

On 2/1/07, Aubrey Li <aubreylee@gmail.com> wrote:

> Yes, from the back trace stack, it appears to come from userspace. But
> I didn't startup any application. If there should be one, I think it's
> shell.

If you have a second way to access the computer (telnet, eg) log in
and do an strace of the shell.  Hit enter and see what it is doing.
You may find it enlightening.

As an example, see what bash does:

read(0, "\r", 1)                        = 1
write(2, "\n", 1)                       = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon
-echo ...}) = 0
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
[...]

Chris

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2007-02-02  3:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-01-31 10:49 [BUG]: 2.6.19.2: Weird serial core issue Aubrey Li
2007-01-31 16:21 ` Alan
2007-02-01  2:33   ` Aubrey Li
2007-02-01  9:45     ` Russell King
2007-02-01 10:09       ` Aubrey Li
2007-02-01 11:16         ` Russell King
2007-02-01 17:54           ` Aubrey Li
2007-02-01 19:09             ` Russell King
2007-02-02  3:34             ` Christopher Curtis
     [not found]     ` <000201c745d9$4577fe20$2e01a8c0@acksys.local>
2007-02-01 10:38       ` Aubrey Li
2007-02-01 15:19         ` Paul Fulghum
2007-02-01 12:02     ` Alan

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.