netx-serial.c
来自「linux 内核源代码」· C语言 代码 · 共 748 行 · 第 1/2 页
C
748 行
/* * drivers/serial/netx-serial.c * * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif#include <linux/device.h>#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 <linux/serial.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/arch/netx-regs.h>/* We've been assigned a range on the "Low-density serial ports" major */#define SERIAL_NX_MAJOR 204#define MINOR_START 170#ifdef CONFIG_SERIAL_NETX_CONSOLEenum uart_regs { UART_DR = 0x00, UART_SR = 0x04, UART_LINE_CR = 0x08, UART_BAUDDIV_MSB = 0x0c, UART_BAUDDIV_LSB = 0x10, UART_CR = 0x14, UART_FR = 0x18, UART_IIR = 0x1c, UART_ILPR = 0x20, UART_RTS_CR = 0x24, UART_RTS_LEAD = 0x28, UART_RTS_TRAIL = 0x2c, UART_DRV_ENABLE = 0x30, UART_BRM_CR = 0x34, UART_RXFIFO_IRQLEVEL = 0x38, UART_TXFIFO_IRQLEVEL = 0x3c,};#define SR_FE (1<<0)#define SR_PE (1<<1)#define SR_BE (1<<2)#define SR_OE (1<<3)#define LINE_CR_BRK (1<<0)#define LINE_CR_PEN (1<<1)#define LINE_CR_EPS (1<<2)#define LINE_CR_STP2 (1<<3)#define LINE_CR_FEN (1<<4)#define LINE_CR_5BIT (0<<5)#define LINE_CR_6BIT (1<<5)#define LINE_CR_7BIT (2<<5)#define LINE_CR_8BIT (3<<5)#define LINE_CR_BITS_MASK (3<<5)#define CR_UART_EN (1<<0)#define CR_SIREN (1<<1)#define CR_SIRLP (1<<2)#define CR_MSIE (1<<3)#define CR_RIE (1<<4)#define CR_TIE (1<<5)#define CR_RTIE (1<<6)#define CR_LBE (1<<7)#define FR_CTS (1<<0)#define FR_DSR (1<<1)#define FR_DCD (1<<2)#define FR_BUSY (1<<3)#define FR_RXFE (1<<4)#define FR_TXFF (1<<5)#define FR_RXFF (1<<6)#define FR_TXFE (1<<7)#define IIR_MIS (1<<0)#define IIR_RIS (1<<1)#define IIR_TIS (1<<2)#define IIR_RTIS (1<<3)#define IIR_MASK 0xf#define RTS_CR_AUTO (1<<0)#define RTS_CR_RTS (1<<1)#define RTS_CR_COUNT (1<<2)#define RTS_CR_MOD2 (1<<3)#define RTS_CR_RTS_POL (1<<4)#define RTS_CR_CTS_CTR (1<<5)#define RTS_CR_CTS_POL (1<<6)#define RTS_CR_STICK (1<<7)#define UART_PORT_SIZE 0x40#define DRIVER_NAME "netx-uart"struct netx_port { struct uart_port port;};static void netx_stop_tx(struct uart_port *port){ unsigned int val; val = readl(port->membase + UART_CR); writel(val & ~CR_TIE, port->membase + UART_CR);}static void netx_stop_rx(struct uart_port *port){ unsigned int val; val = readl(port->membase + UART_CR); writel(val & ~CR_RIE, port->membase + UART_CR);}static void netx_enable_ms(struct uart_port *port){ unsigned int val; val = readl(port->membase + UART_CR); writel(val | CR_MSIE, port->membase + UART_CR);}static inline void netx_transmit_buffer(struct uart_port *port){ struct circ_buf *xmit = &port->info->xmit; if (port->x_char) { writel(port->x_char, port->membase + UART_DR); port->icount.tx++; port->x_char = 0; return; } if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { netx_stop_tx(port); return; } do { /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], port->membase + UART_DR); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) break; } while (!(readl(port->membase + UART_FR) & FR_TXFF)); if (uart_circ_empty(xmit)) netx_stop_tx(port);}static void netx_start_tx(struct uart_port *port){ writel( readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR); if (!(readl(port->membase + UART_FR) & FR_TXFF)) netx_transmit_buffer(port);}static unsigned int netx_tx_empty(struct uart_port *port){ return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;}static void netx_txint(struct uart_port *port){ struct circ_buf *xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { netx_stop_tx(port); return; } netx_transmit_buffer(port); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port);}static void netx_rxint(struct uart_port *port){ unsigned char rx, flg, status; struct tty_struct *tty = port->info->tty; while (!(readl(port->membase + UART_FR) & FR_RXFE)) { rx = readl(port->membase + UART_DR); flg = TTY_NORMAL; port->icount.rx++; status = readl(port->membase + UART_SR); if (status & SR_BE) { writel(0, port->membase + UART_SR); if (uart_handle_break(port)) continue; } if (unlikely(status & (SR_FE | SR_PE | SR_OE))) { if (status & SR_PE) port->icount.parity++; else if (status & SR_FE) port->icount.frame++; if (status & SR_OE) port->icount.overrun++; status &= port->read_status_mask; if (status & SR_BE) flg = TTY_BREAK; else if (status & SR_PE) flg = TTY_PARITY; else if (status & SR_FE) flg = TTY_FRAME; } if (uart_handle_sysrq_char(port, rx)) continue; uart_insert_char(port, status, SR_OE, rx, flg); } tty_flip_buffer_push(tty); return;}static irqreturn_t netx_int(int irq, void *dev_id){ struct uart_port *port = dev_id; unsigned long flags; unsigned char status; spin_lock_irqsave(&port->lock,flags); status = readl(port->membase + UART_IIR) & IIR_MASK; while (status) { if (status & IIR_RIS) netx_rxint(port); if (status & IIR_TIS) netx_txint(port); if (status & IIR_MIS) { if (readl(port->membase + UART_FR) & FR_CTS) uart_handle_cts_change(port, 1); else uart_handle_cts_change(port, 0); } writel(0, port->membase + UART_IIR); status = readl(port->membase + UART_IIR) & IIR_MASK; } spin_unlock_irqrestore(&port->lock,flags); return IRQ_HANDLED;}static unsigned int netx_get_mctrl(struct uart_port *port){ unsigned int ret = TIOCM_DSR | TIOCM_CAR; if (readl(port->membase + UART_FR) & FR_CTS) ret |= TIOCM_CTS; return ret;}static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl){ unsigned int val; if (mctrl & TIOCM_RTS) { val = readl(port->membase + UART_RTS_CR); writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR); }}static void netx_break_ctl(struct uart_port *port, int break_state){ unsigned int line_cr; spin_lock_irq(&port->lock); line_cr = readl(port->membase + UART_LINE_CR); if (break_state != 0) line_cr |= LINE_CR_BRK; else line_cr &= ~LINE_CR_BRK; writel(line_cr, port->membase + UART_LINE_CR); spin_unlock_irq(&port->lock);}static int netx_startup(struct uart_port *port){ int ret; ret = request_irq(port->irq, netx_int, 0, DRIVER_NAME, port); if (ret) { dev_err(port->dev, "unable to grab irq%d\n",port->irq); goto exit; } writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN, port->membase + UART_LINE_CR); writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN, port->membase + UART_CR);exit: return ret;}static void netx_shutdown(struct uart_port *port){ writel(0, port->membase + UART_CR) ; free_irq(port->irq, port);}static voidnetx_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old){ unsigned int baud, quot; unsigned char old_cr; unsigned char line_cr = LINE_CR_FEN; unsigned char rts_cr = 0; switch (termios->c_cflag & CSIZE) { case CS5: line_cr |= LINE_CR_5BIT; break; case CS6: line_cr |= LINE_CR_6BIT; break; case CS7: line_cr |= LINE_CR_7BIT; break; case CS8: line_cr |= LINE_CR_8BIT; break; } if (termios->c_cflag & CSTOPB) line_cr |= LINE_CR_STP2; if (termios->c_cflag & PARENB) { line_cr |= LINE_CR_PEN; if (!(termios->c_cflag & PARODD)) line_cr |= LINE_CR_EPS; } if (termios->c_cflag & CRTSCTS) rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?