⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bfin_5xx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 * * 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>#ifdef CONFIG_KGDB_UART#include <linux/kgdb.h>#include <asm/irq_regs.h>#endif#include <asm/gpio.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/* UART name and device definitions */#define BFIN_SERIAL_NAME	"ttyBF"#define BFIN_SERIAL_MAJOR	204#define BFIN_SERIAL_MINOR	64/* * Setup for console. Argument comes from the menuconfig */#define DMA_RX_XCOUNT		512#define DMA_RX_YCOUNT		(PAGE_SIZE / DMA_RX_XCOUNT)#define DMA_RX_FLUSH_JIFFIES	5#ifdef CONFIG_SERIAL_BFIN_DMAstatic void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);#elsestatic void bfin_serial_do_work(struct work_struct *work);static void bfin_serial_tx_chars(struct bfin_serial_port *uart);static void local_put_char(struct bfin_serial_port *uart, char ch);#endifstatic void bfin_serial_mctrl_check(struct bfin_serial_port *uart);/* * 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;	while (!(UART_GET_LSR(uart) & TEMT))		continue;#ifdef CONFIG_SERIAL_BFIN_DMA	disable_dma(uart->tx_dma_channel);#else#ifdef CONFIG_BF54x	/* Waiting for Transmission Finished */	while (!(UART_GET_LSR(uart) & TFI))		continue;	/* Clear TFI bit */	UART_PUT_LSR(uart, TFI);	UART_CLEAR_IER(uart, ETBEI);#else	unsigned short ier;	ier = UART_GET_IER(uart);	ier &= ~ETBEI;	UART_PUT_IER(uart, ier);#endif#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#ifdef CONFIG_BF54x	UART_SET_IER(uart, ETBEI);#else	unsigned short ier;	ier = UART_GET_IER(uart);	ier |= ETBEI;	UART_PUT_IER(uart, ier);#endif	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;#ifdef	CONFIG_KGDB_UART	if (uart->port.line != CONFIG_KGDB_UART_PORT) {#endif#ifdef CONFIG_BF54x	UART_CLEAR_IER(uart, ERBFI);#else	unsigned short ier;	ier = UART_GET_IER(uart);	ier &= ~ERBFI;	UART_PUT_IER(uart, ier);#endif#ifdef	CONFIG_KGDB_UART	}#endif}/* * Set the modem control timer to fire immediately. */static void bfin_serial_enable_ms(struct uart_port *port){}#ifdef CONFIG_KGDB_UARTstatic int kgdb_entry_state;void kgdb_put_debug_char(int chr){	struct bfin_serial_port *uart;		if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)		uart = &bfin_serial_ports[0];	else		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];		while (!(UART_GET_LSR(uart) & THRE)) {		SSYNC();	}#ifndef CONFIG_BF54x	UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));	SSYNC();#endif	UART_PUT_CHAR(uart, (unsigned char)chr);	SSYNC();}int kgdb_get_debug_char(void){	struct bfin_serial_port *uart;	unsigned char chr;	if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)		uart = &bfin_serial_ports[0];	else		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];		while(!(UART_GET_LSR(uart) & DR)) {		SSYNC();	}#ifndef CONFIG_BF54x	UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));	SSYNC();#endif	chr = UART_GET_CHAR(uart);	SSYNC();	return chr;}#endif#ifdef CONFIG_SERIAL_BFIN_PIOstatic void local_put_char(struct bfin_serial_port *uart, char ch){	unsigned short status;	int flags = 0;	spin_lock_irqsave(&uart->port.lock, flags);	do {		status = UART_GET_LSR(uart);	} while (!(status & THRE));	UART_PUT_CHAR(uart, ch);	SSYNC();	spin_unlock_irqrestore(&uart->port.lock, flags);}static void bfin_serial_rx_chars(struct bfin_serial_port *uart){	struct tty_struct *tty = uart->port.info->tty;	unsigned int status, ch, flg;	static int in_break = 0;#ifdef CONFIG_KGDB_UART	struct pt_regs *regs = get_irq_regs();#endif	status = UART_GET_LSR(uart); 	ch = UART_GET_CHAR(uart); 	uart->port.icount.rx++;#ifdef CONFIG_KGDB_UART	if (uart->port.line == CONFIG_KGDB_UART_PORT) {		if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */			kgdb_breakkey_pressed(regs);			return;		} else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */			kgdb_entry_state = 1;		} else if (kgdb_entry_state == 1 && ch == 'q') {			kgdb_entry_state = 0;			kgdb_breakkey_pressed(regs);			return;		} else if (ch == 0x3) {/* Ctrl + C */			kgdb_entry_state = 0;			kgdb_breakkey_pressed(regs);			return;		} else {			kgdb_entry_state = 0;		}	}#endif	if (ANOMALY_05000230) {		/* The BF533 family of processors have a nice misbehavior where		 * they continuously generate characters for a "single" break.		 * We have to basically ignore this flood until the "next" valid		 * character comes across.  All other Blackfin families operate		 * properly though.		 * Note: While Anomaly 05000230 does not directly address this,		 *       the changes that went in for it also fixed this issue.		 */		if (in_break) {			if (ch != 0) {				in_break = 0;				ch = UART_GET_CHAR(uart);				if (bfin_revid() < 5)					return;			} else				return;		}	}	if (status & BI) {		if (ANOMALY_05000230)			in_break = 1;		uart->port.icount.brk++;		if (uart_handle_break(&uart->port))			goto ignore_char;		status &= ~(PE | FE);	}	if (status & PE)		uart->port.icount.parity++;	if (status & OE)		uart->port.icount.overrun++;	if (status & FE)		uart->port.icount.frame++;	status &= uart->port.read_status_mask;	if (status & BI)		flg = TTY_BREAK;	else if (status & PE)		flg = TTY_PARITY;	else if (status & FE)		flg = TTY_FRAME;	else		flg = TTY_NORMAL;	if (uart_handle_sysrq_char(&uart->port, ch))		goto ignore_char;	uart_insert_char(&uart->port, status, OE, ch, flg); ignore_char:	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_rx_int(int irq, void *dev_id){	struct bfin_serial_port *uart = dev_id;#ifdef CONFIG_BF54x	unsigned short status;	spin_lock(&uart->port.lock);	status = UART_GET_LSR(uart);	while ((UART_GET_IER(uart) & ERBFI) && (status & DR)) {		bfin_serial_rx_chars(uart);		status = UART_GET_LSR(uart);	}	spin_unlock(&uart->port.lock);#else	spin_lock(&uart->port.lock);	while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY)		bfin_serial_rx_chars(uart);	spin_unlock(&uart->port.lock);#endif	return IRQ_HANDLED;}static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id){	struct bfin_serial_port *uart = dev_id;#ifdef CONFIG_BF54x	unsigned short status;	spin_lock(&uart->port.lock);	status = UART_GET_LSR(uart);	while ((UART_GET_IER(uart) & ETBEI) && (status & THRE)) {		bfin_serial_tx_chars(uart);		status = UART_GET_LSR(uart);	}	spin_unlock(&uart->port.lock);#else	spin_lock(&uart->port.lock);	while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)		bfin_serial_tx_chars(uart);	spin_unlock(&uart->port.lock);#endif	return IRQ_HANDLED;}static void bfin_serial_do_work(struct work_struct *work){	struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);	bfin_serial_mctrl_check(uart);}#endif#ifdef CONFIG_SERIAL_BFIN_DMAstatic 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;	}	spin_lock_irqsave(&uart->port.lock, flags);	uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);	if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))

⌨️ 快捷键说明

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