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 + -
显示快捷键?