LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 07-16-2008, 09:53 PM   #1
archieval
Member
 
Registered: Apr 2007
Location: Philippines
Distribution: Kubuntu, Ubuntu, CentOS
Posts: 289

Rep: Reputation: 41
Serial driver problem on reading data from device


Hello,

I am currently coding a serial port driver (to be combined with drivers/serial/serial_core.c). I have noticed that most serial drivers have the tty_flip_buffer_push() inside the interrupt service routine (ISR). As far as I know, this function is the one the gets the data from the flip buffer and gives it to the user application that requested it. I am wondering why does it have to be inside an ISR? When you call read() in a user program, it does not interrupt.

In my UART testbench, interrupt occurs when something happens in the read FIFO, for example whenever a data is ready to be read. The interrupt service routine will acknowledge this interrupt by getting the data out of the FIFO then putting it in the flip buffer. If the tty_flip_buffer_push() is always inside the ISR, it will always flip the buffer and give the data to the user even though there is no one requesting it?

example of uart driver in the linux source. this is the isr for read.
Code:
static void
uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
{
	struct uart_info *info = port->info;
	struct tty_struct *tty = info->tty;
	unsigned int status, ch, rds, flg, ignored = 0;
	

	status = UART_GET_RSR(port);
	while (UART_RX_DATA(status)) {

		/* 
		 * We need to read rds before reading the 
		 * character from the fifo
		 */
		rds = UART_GET_RDS(port);
		ch = UART_GET_CHAR(port);
		port->icount.rx++;

		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			goto ignore_char;

		flg = TTY_NORMAL;

		/*
		 * Note that the error handling code is
		 * out of the main execution path
		 */
		if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|UART_RDS_PE_MSK))
			goto handle_error;
		if (uart_handle_sysrq_char(port, ch, regs))
			goto ignore_char;

	error_return:
		*tty->flip.flag_buf_ptr++ = flg;
		*tty->flip.char_buf_ptr++ = ch;
		tty->flip.count++;
	ignore_char:
		status = UART_GET_RSR(port);
	}
out:
	tty_flip_buffer_push(tty);
	return;

handle_error:
	if (rds & UART_RDS_BI_MSK) {
		status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK);
		port->icount.brk++;

#ifdef SUPPORT_SYSRQ
		if (uart_handle_break(port))
			goto ignore_char;
#endif
	} else if (rds & UART_RDS_PE_MSK)
		port->icount.parity++;
	else if (rds & UART_RDS_FE_MSK)
		port->icount.frame++;
	if (rds & UART_RDS_OE_MSK)
		port->icount.overrun++;

	if (rds & port->ignore_status_mask) {
		if (++ignored > 100)
			goto out;
		goto ignore_char;
	}
	rds &= port->read_status_mask;

	if (rds & UART_RDS_BI_MSK)
		flg = TTY_BREAK;
	else if (rds & UART_RDS_PE_MSK)
		flg = TTY_PARITY;
	else if (rds & UART_RDS_FE_MSK)
		flg = TTY_FRAME;

	if (rds & UART_RDS_OE_MSK) {
		/*
		 * CHECK: does overrun affect the current character?
		 * ASSUMPTION: it does not.
		 */
		*tty->flip.flag_buf_ptr++ = flg;
		*tty->flip.char_buf_ptr++ = ch;
		tty->flip.count++;
		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			goto ignore_char;
		ch = 0;
		flg = TTY_OVERRUN;
	}
#ifdef SUPPORT_SYSRQ
	port->sysrq = 0;
#endif
	goto error_return;
}


...



static void uart00_int(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	unsigned int status, pass_counter = 0;

	status = UART_GET_INT_STATUS(port);
	do {

		if (status & UART_ISR_RI_MSK)
			uart00_rx_chars(port, regs);
		if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK))
			uart00_tx_chars(port);
		if (status & UART_ISR_MI_MSK)
			uart00_modem_status(port);
		if (pass_counter++ > UART00_ISR_PASS_LIMIT)
			break;

		status = UART_GET_INT_STATUS(port);
	} while (status);
}
I hope anyone can help me by clarifying this design. Thanks

Best regards,
Archie
 
Old 07-16-2008, 10:22 PM   #2
pinniped
Senior Member
 
Registered: May 2008
Location: planet earth
Distribution: Debian
Posts: 1,732

Rep: Reputation: 50
The data is not being sent to the user; the line discipline (N_TTY by default) is being notified that data has been received. The line discipline may need to do special things such as write to the UART control registers, set a flag when an XON/XOFF character is received, and so on. The simplest line discipline I can think of is N_PPP, so have a look at that code if you want to see what happens to characters as they are received.
 
Old 07-22-2008, 11:42 PM   #3
archieval
Member
 
Registered: Apr 2007
Location: Philippines
Distribution: Kubuntu, Ubuntu, CentOS
Posts: 289

Original Poster
Rep: Reputation: 41
I see. If these data are not sent to the user immediately when a tty_flip_buffer_push, I presume it is stored in another buffer in the tty core. If another data was available, and push is again called, does the data fills up the next location in the tty core buffer? or is the buffer replaced with the new data (discards the previous content of the "I assumed" tty core buffer)?

Best regards,
Archie
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
help reading data from a serial port skydemon Linux - General 1 08-10-2006 08:48 AM
reading and writing to a serial device (modem) Xanadu Linux - Laptop and Netbook 0 01-04-2005 10:05 AM
reading data from a serial port mchitrakar Linux - Networking 3 12-04-2004 01:24 PM
Problems with reading back serial binary data esi-eric Linux - Software 14 08-06-2004 01:48 PM
Data acquisition from a device through serial port in linux newtolinux123 Linux - Newbie 1 04-22-2004 08:27 AM


All times are GMT -5. The time now is 12:49 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration