nb85e_uart.c

来自「这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,」· C语言 代码 · 共 599 行 · 第 1/2 页

C
599
字号
/* * drivers/char/nb85e_uart.c -- Serial I/O using V850E/NB85E on-chip UART * *  Copyright (C) 2001,2002  NEC Corporation *  Copyright (C) 2001,2002  Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU General * Public License.  See the file COPYING in the main directory of this * archive for more details. * * Written by Miles Bader <miles@gnu.org> */#include <linux/kernel.h>#include <linux/console.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/tty_driver.h>#include <linux/serial.h>#include <linux/generic_serial.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <asm/system.h>#include <asm/nb85e_uart.h>#include <asm/nb85e_utils.h>/* Magic number used in generic_serial header.  */#define NB85E_UART_MAGIC	0xFABCAB22/* Initial UART state.  */#define NB85E_UART_INIT_BAUD	38400#define NB85E_UART_INIT_CFLAGS	(B38400 | CS8 | CREAD)#define RS_EVENT_WRITE_WAKEUP	1 /* from generic_serial.h *//* For use by modules eventually...  */#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT/* Low-level UART functions.  *//* These masks define which control bits affect TX/RX modes, respectively.  */#define RX_BITS \  (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_ISRM)#define TX_BITS \  (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_SL_2)/* The UART require various delays after writing control registers.  */static inline void nb85e_uart_delay (unsigned cycles){	/* The loop takes 2 insns, so loop CYCLES / 2 times.  */	register unsigned count = cycles >> 1;	while (--count != 0)		/* nothing */;}/* Configure and turn on uart channel CHAN, using the termios `control   modes' bits in CFLAGS, and a baud-rate of BAUD.  */void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud){	int cksr_min, flags;	unsigned new_config = 0; /* What we'll write to the control reg. */	unsigned new_clk_divlog2; /* New baud-rate generate clock divider. */	unsigned new_brgen_count; /* New counter max for baud-rate generator.*/	/* These are the current values corresponding to the above.  */	unsigned old_config, old_clk_divlog2, old_brgen_count;	/* Calculate new baud-rate generator config values.  */	cksr_min = 0;	while ((cpu_clock_freq >> cksr_min) > NB85E_UART_CKSR_MAX_FREQ)		cksr_min++;	/* Calculate the lot2 clock divider and baud-rate counter values	   (note that the UART divides the resulting clock by 2, so	   multiply BAUD by 2 here to compensate).  */	calc_counter_params (cpu_clock_freq, baud * 2,			     cksr_min, NB85E_UART_CKSR_MAX, 8/*bits*/,			     &new_clk_divlog2, &new_brgen_count);	/* Figure out new configuration of control register.  */	if (cflags & CSTOPB)		/* Number of stop bits, 1 or 2.  */		new_config |= NB85E_UART_ASIM_SL_2;	if ((cflags & CSIZE) == CS8)		/* Number of data bits, 7 or 8.  */		new_config |= NB85E_UART_ASIM_CL_8;	if (! (cflags & PARENB))		/* No parity check/generation.  */		new_config |= NB85E_UART_ASIM_PS_NONE;	else if (cflags & PARODD)		/* Odd parity check/generation.  */		new_config |= NB85E_UART_ASIM_PS_ODD;	else		/* Even parity check/generation.  */		new_config |= NB85E_UART_ASIM_PS_EVEN;	if (cflags & CREAD)		/* Reading enabled.  */		new_config |= NB85E_UART_ASIM_RXE;	new_config |= NB85E_UART_ASIM_TXE; /* Writing is always enabled.  */	new_config |= NB85E_UART_ASIM_CAE;	new_config |= NB85E_UART_ASIM_ISRM; /* Errors generate a read-irq.  */	/* Disable interrupts while we're twiddling the hardware.  */	save_flags_cli (flags);#ifdef NB85E_UART_PRE_CONFIGURE	NB85E_UART_PRE_CONFIGURE (chan, cflags, baud);#endif	old_config = NB85E_UART_ASIM (chan);	old_clk_divlog2 = NB85E_UART_CKSR (chan);	old_brgen_count = NB85E_UART_BRGC (chan);	if (new_clk_divlog2 != old_clk_divlog2	    || new_brgen_count != old_brgen_count)	{		/* The baud rate has changed.  First, disable the UART.  */		NB85E_UART_ASIM (chan) = 0;		old_config = 0;		/* Reprogram the baud-rate generator.  */		NB85E_UART_CKSR (chan) = new_clk_divlog2;		NB85E_UART_BRGC (chan) = new_brgen_count;	}	if (! (old_config & NB85E_UART_ASIM_CAE)) {		/* If we are enabling the uart for the first time, start		   by turning on the enable bit, which must be done		   before turning on any other bits.  */		NB85E_UART_ASIM (chan) = NB85E_UART_ASIM_CAE;		/* Enabling the uart also resets it.  */		old_config = NB85E_UART_ASIM_CAE;	}	if (new_config != old_config) {		/* Which of the TXE/RXE bits we'll temporarily turn off		   before changing other control bits.  */		unsigned temp_disable = 0;		/* Which of the TXE/RXE bits will be enabled.  */		unsigned enable = 0;		unsigned changed_bits = new_config ^ old_config;		/* Which of RX/TX will be enabled in the new configuration.  */		if (new_config & RX_BITS)			enable |= (new_config & NB85E_UART_ASIM_RXE);		if (new_config & TX_BITS)			enable |= (new_config & NB85E_UART_ASIM_TXE);		/* Figure out which of RX/TX needs to be disabled; note		   that this will only happen if they're not already		   disabled.  */		if (changed_bits & RX_BITS)			temp_disable |= (old_config & NB85E_UART_ASIM_RXE);		if (changed_bits & TX_BITS)			temp_disable |= (old_config & NB85E_UART_ASIM_TXE);		/* We have to turn off RX and/or TX mode before changing		   any associated control bits.  */		if (temp_disable)			NB85E_UART_ASIM (chan) = old_config & ~temp_disable;		/* Write the new control bits, while RX/TX are disabled. */ 		if (changed_bits & ~enable)			NB85E_UART_ASIM (chan) = new_config & ~enable;		/* The UART may not be reset properly unless we		   wait at least 2 `basic-clocks' until turning		   on the TXE/RXE bits again.  A `basic clock'		   is the clock used by the baud-rate generator, i.e.,		   the cpu clock divided by the 2^new_clk_divlog2.  */		nb85e_uart_delay (1 << (new_clk_divlog2 + 1));		/* Write the final version, with enable bits turned on.  */		NB85E_UART_ASIM (chan) = new_config;	}	restore_flags (flags);}/*  Low-level console. */static void nb85e_uart_cons_write (struct console *co,				   const char *s, unsigned count){	if (count > 0) {		unsigned chan = co->index;		unsigned irq = IRQ_INTST (chan);		int irq_was_enabled, irq_was_pending, flags;		/* We don't want to get `transmission completed' (INTST)		   interrupts, since we're busy-waiting, so we disable		   them while sending (we don't disable interrupts		   entirely because sending over a serial line is really		   slow).  We save the status of INTST and restore it		   when we're done so that using printk doesn't		   interfere with normal serial transmission (other than		   interleaving the output, of course!).  This should		   work correctly even if this function is interrupted		   and the interrupt printks something.  */		/* Disable interrupts while fiddling with INTST.  */		save_flags_cli (flags);		/* Get current INTST status.  */		irq_was_enabled = nb85e_intc_irq_enabled (irq);		irq_was_pending = nb85e_intc_irq_pending (irq);		/* Disable INTST if necessary.  */		if (irq_was_enabled)			nb85e_intc_disable_irq (irq);		/* Turn interrupts back on.  */		restore_flags (flags);		/* Send characters.  */		while (count > 0) {			int ch = *s++;			if (ch == '\n') {				/* We don't have the benefit of a tty				   driver, so translate NL into CR LF.  */				nb85e_uart_wait_for_xmit_ok (chan);				nb85e_uart_putc (chan, '\r');			}			nb85e_uart_wait_for_xmit_ok (chan);			nb85e_uart_putc (chan, ch);			count--;		}		/* Restore saved INTST status.  */		if (irq_was_enabled) {			/* Wait for the last character we sent to be			   completely transmitted (as we'll get an INTST			   interrupt at that point).  */			nb85e_uart_wait_for_xmit_done (chan);			/* Clear pending interrupts received due			   to our transmission, unless there was already			   one pending, in which case we want the			   handler to be called.  */			if (! irq_was_pending)				nb85e_intc_clear_pending_irq (irq);			/* ... and then turn back on handling.  */			nb85e_intc_enable_irq (irq);		}	}}static int nb85e_uart_cons_wait_key (struct console *co){	/* Bizarrely enough, there appears to be no way to poll the uart	   to see if a character has been received!  */	return 0;}static kdev_t nb85e_uart_cons_device (struct console *c){        return MKDEV (TTY_MAJOR, NB85E_UART_MINOR_BASE + c->index);}static struct console nb85e_uart_cons ={    name:	"ttyS",    write:	nb85e_uart_cons_write,    wait_key:	nb85e_uart_cons_wait_key,    device:	nb85e_uart_cons_device,    flags:	CON_PRINTBUFFER,    index:	-1,};void nb85e_uart_cons_init (void){	nb85e_uart_configure (0, NB85E_UART_INIT_CFLAGS, NB85E_UART_INIT_BAUD);	register_console (&nb85e_uart_cons);	printk ("Console: V850E/NB85E on-chip UART channel 0\n");}/* Interface for generic serial driver layer.  */struct nb85e_uart_tty_port {	struct gs_port gs;	unsigned chan;	struct tq_struct tqueue;};/* Transmit a character, if any are pending.  */void nb85e_uart_tty_tx (struct nb85e_uart_tty_port *port){	unsigned chan = port->chan;	int flags;	/* If there are characters to transmit, try to transmit one of them. */	if (port->gs.xmit_cnt > 0 && nb85e_uart_xmit_ok (port->chan)) {		nb85e_uart_putc (chan, port->gs.xmit_buf[port->gs.xmit_tail]);		port->gs.xmit_tail			= (port->gs.xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);		port->gs.xmit_cnt--;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?