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

📄 8250.c

📁 the attached file is the driver of Uart
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/drivers/char/8250.c * *  Driver for 8250/16550-type serial ports * *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * *  Copyright (C) 2001 Russell King. * * 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. * *  $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $ * * A note about mapbase / membase * *  mapbase is the physical address of the IO port. *  membase is an 'ioremapped' cookie. *//* * Copyright 2004 Freescale Semiconductor, Inc. All Rights Reserved. *//*  * 2006/02/22: Added support for MP211 board. *             Copyright (C) NEC Electronics Corporation 2006 *//*! * @defgroup External_UART 16C652 Universal Asynchronous Receiver Transmitter (UART) Driver *//*! * @file    8250.c * @brief   This is the driver source file for 8250/16550 compatible serial * ports. * * This is modified to support 16C652 dual serial ports on MXC Boards. * The functions \b serial8250_interrupt() and \b serial_link_irq_chain() are * modified to handle interrupt pin connectivity requirements. *   * @ingroup External_UART */  #include <linux/config.h>#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/console.h>#include <linux/sysrq.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial_reg.h>#include <linux/serial_core.h>#include <linux/serial.h>#include <linux/serial_8250.h>#include <linux/kgdb.h>#include <asm/io.h>#include <asm/irq.h>#if defined(CONFIG_ARCH_ARGONPLUS) || \    defined(CONFIG_ARCH_SCMA11) || \    defined(CONFIG_ARCH_MX3)#include <asm/arch/gpio.h>extern int extuart_intr_setup(int port);extern int extuart_intr_cleanup(int port);extern void extuart_intr_clear(int port); #endif#if defined(CONFIG_MACH_ZEUSEVB)extern int extuart_intr_setup(unsigned int port, unsigned int irq,         irqreturn_t (*handler)(int, void *, struct pt_regs *),        unsigned long irq_flags, const char * devname, void *dev_id);extern int extuart_intr_cleanup(unsigned int port, unsigned int irq,         void * dev_id);extern void extuart_intr_clear(int port); #endif#include "8250.h"/* * Configuration: *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option *                is unsafe when used on edge-triggered interrupts. */unsigned int share_irqs = SERIAL8250_SHARE_IRQS;/* * Debugging. */#if 0#define DEBUG_AUTOCONF(fmt...)	printk(fmt)#else#define DEBUG_AUTOCONF(fmt...)	do { } while (0)#endif#if 0#define DEBUG_INTR(fmt...)	printk(fmt)#else#define DEBUG_INTR(fmt...)	do { } while (0)#endif#define PASS_LIMIT	256/* * We default to IRQ0 for the "no irq" hack.   Some * machine types want others as well - they're free * to redefine this in their header file. */#define is_real_interrupt(irq)	((irq) != 0)/* * This converts from our new CONFIG_ symbols to the symbols * that asm/serial.h expects.  You _NEED_ to comment out the * linux/config.h include contained inside asm/serial.h for * this to work. */#undef CONFIG_SERIAL_MANY_PORTS#undef CONFIG_SERIAL_DETECT_IRQ#undef CONFIG_SERIAL_MULTIPORT#undef CONFIG_HUB6#ifdef CONFIG_SERIAL_8250_DETECT_IRQ#define CONFIG_SERIAL_DETECT_IRQ 1#endif#ifdef CONFIG_SERIAL_8250_MULTIPORT#define CONFIG_SERIAL_MULTIPORT 1#endif#ifdef CONFIG_SERIAL_8250_MANY_PORTS#define CONFIG_SERIAL_MANY_PORTS 1#endif/* * HUB6 is always on.  This will be removed once the header * files have been cleaned. */#define CONFIG_HUB6 1#include <asm/serial.h>/* * SERIAL_PORT_DFNS tells us about built-in ports that have no * standard enumeration mechanism.   Platforms that can find all * serial ports via mechanisms like ACPI or PCI need not supply it. */#ifndef SERIAL_PORT_DFNS#define SERIAL_PORT_DFNS#endifstatic struct old_serial_port old_serial_port[] = {	SERIAL_PORT_DFNS /* defined in asm/serial.h */};#define UART_NR	(ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS)#ifdef CONFIG_SERIAL_8250_RSA#define PORT_RSA_MAX 4static unsigned long probe_rsa[PORT_RSA_MAX];static unsigned int probe_rsa_count;#endif /* CONFIG_SERIAL_8250_RSA  */struct uart_8250_port {	struct uart_port	port;	struct timer_list	timer;		/* "no irq" timer */	struct list_head	list;		/* ports on this IRQ */	unsigned int		capabilities;	/* port capabilities */	unsigned int		tx_loadsz;	/* transmit fifo load size */	unsigned short		rev;	unsigned char		acr;	unsigned char		ier;	unsigned char		lcr;	unsigned char		mcr;	unsigned char		mcr_mask;	/* mask of user bits */	unsigned char		mcr_force;	/* mask of forced bits */	unsigned char		lsr_break_flag;	/*	 * We provide a per-port pm hook.	 */	void			(*pm)(struct uart_port *port,				      unsigned int state, unsigned int old);};struct irq_info {	spinlock_t		lock;	struct list_head	*head;};static struct irq_info irq_lists[NR_IRQS];/* * Here we define the default xmit fifo size used for each type of UART. */static const struct serial8250_config uart_config[] = {	[PORT_UNKNOWN] = {		.name		= "unknown",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_8250] = {		.name		= "8250",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_16450] = {		.name		= "16450",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_16550] = {		.name		= "16550",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_16550A] = {		.name		= "16550A",		.fifo_size	= 16,		.tx_loadsz	= 16,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,		.flags		= UART_CAP_FIFO,	},	[PORT_CIRRUS] = {		.name		= "Cirrus",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_16650] = {		.name		= "ST16650",		.fifo_size	= 1,		.tx_loadsz	= 1,		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,	},	[PORT_16650V2] = {		.name		= "ST16650V2",		.fifo_size	= 32,		.tx_loadsz	= 16,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |				  UART_FCR_T_TRIG_00,		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,	},	[PORT_16750] = {		.name		= "TI16750",		.fifo_size	= 64,		.tx_loadsz	= 64,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |				  UART_FCR7_64BYTE,		.flags		= UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,	},	[PORT_STARTECH] = {		.name		= "Startech",		.fifo_size	= 1,		.tx_loadsz	= 1,	},	[PORT_16C950] = {		.name		= "16C950/954",		.fifo_size	= 128,		.tx_loadsz	= 128,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,		.flags		= UART_CAP_FIFO,	},	[PORT_16654] = {		.name		= "ST16654",		.fifo_size	= 64,		.tx_loadsz	= 32,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |				  UART_FCR_T_TRIG_10,		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,	},	[PORT_16850] = {		.name		= "XR16850",		.fifo_size	= 128,		.tx_loadsz	= 128,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,	},	[PORT_RSA] = {		.name		= "RSA",		.fifo_size	= 2048,		.tx_loadsz	= 2048,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,		.flags		= UART_CAP_FIFO,	},	[PORT_NS16550A] = {		.name		= "NS16550A",		.fifo_size	= 16,		.tx_loadsz	= 16,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,		.flags		= UART_CAP_FIFO | UART_NATSEMI,	},	[PORT_XSCALE] = {		.name		= "XScale",		.fifo_size	= 32,		.tx_loadsz	= 32,		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,		.flags		= UART_CAP_FIFO,	},};static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset){	offset <<= up->port.regshift;	switch (up->port.iotype) {	case UPIO_HUB6:		outb(up->port.hub6 - 1 + offset, up->port.iobase);		return inb(up->port.iobase + 1);	case UPIO_MEM:		return readb(up->port.membase + offset);	case UPIO_MEM32:		return readl(up->port.membase + offset);	default:		return inb(up->port.iobase + offset);	}}static _INLINE_ voidserial_out(struct uart_8250_port *up, int offset, int value){	offset <<= up->port.regshift;	switch (up->port.iotype) {	case UPIO_HUB6:		outb(up->port.hub6 - 1 + offset, up->port.iobase);		outb(value, up->port.iobase + 1);		break;	case UPIO_MEM:		writeb(value, up->port.membase + offset);		break;	case UPIO_MEM32:		writel(value, up->port.membase + offset);		break;	default:		outb(value, up->port.iobase + offset);	}}/* * We used to support using pause I/O for certain machines.  We * haven't supported this for a while, but just in case it's badly * needed for certain old 386 machines, I've left these #define's * in.... */#define serial_inp(up, offset)		serial_in(up, offset)#define serial_outp(up, offset, value)	serial_out(up, offset, value)/* * For the 16C950 */static void serial_icr_write(struct uart_8250_port *up, int offset, int value){	serial_out(up, UART_SCR, offset);	serial_out(up, UART_ICR, value);}static unsigned int serial_icr_read(struct uart_8250_port *up, int offset){	unsigned int value;	serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);	serial_out(up, UART_SCR, offset);	value = serial_in(up, UART_ICR);	serial_icr_write(up, UART_ACR, up->acr);	return value;}/* * FIFO support. */static inline void serial8250_clear_fifos(struct uart_8250_port *p){	if (p->capabilities & UART_CAP_FIFO) {		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |			       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);		serial_outp(p, UART_FCR, 0);	}}/* * IER sleep support.  UARTs which have EFRs need the "extended * capability" bit enabled.  Note that on XR16C850s, we need to * reset LCR to write to IER. */static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep){	if (p->capabilities & UART_CAP_SLEEP) {		if (p->capabilities & UART_CAP_EFR) {			serial_outp(p, UART_LCR, 0xBF);			serial_outp(p, UART_EFR, UART_EFR_ECB);			serial_outp(p, UART_LCR, 0);		}		serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);		if (p->capabilities & UART_CAP_EFR) {			serial_outp(p, UART_LCR, 0xBF);			serial_outp(p, UART_EFR, 0);			serial_outp(p, UART_LCR, 0);		}	}}#ifdef CONFIG_SERIAL_8250_RSA/* * Attempts to turn on the RSA FIFO.  Returns zero on failure. * We set the port uart clock rate if we succeed. */static int __enable_rsa(struct uart_8250_port *up){	unsigned char mode;	int result;	mode = serial_inp(up, UART_RSA_MSR);	result = mode & UART_RSA_MSR_FIFO;	if (!result) {		serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);		mode = serial_inp(up, UART_RSA_MSR);		result = mode & UART_RSA_MSR_FIFO;	}	if (result)		up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;	return result;}static void enable_rsa(struct uart_8250_port *up){	if (up->port.type == PORT_RSA) {		if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {			spin_lock_irq(&up->port.lock);			__enable_rsa(up);			spin_unlock_irq(&up->port.lock);		}		if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)			serial_outp(up, UART_RSA_FRR, 0);	}}/* * Attempts to turn off the RSA FIFO.  Returns zero on failure. * It is unknown why interrupts were disabled in here.  However, * the caller is expected to preserve this behaviour by grabbing * the spinlock before calling this function. */static void disable_rsa(struct uart_8250_port *up){	unsigned char mode;	int result;	if (up->port.type == PORT_RSA &&	    up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {		spin_lock_irq(&up->port.lock);		mode = serial_inp(up, UART_RSA_MSR);		result = !(mode & UART_RSA_MSR_FIFO);		if (!result) {			serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);			mode = serial_inp(up, UART_RSA_MSR);			result = !(mode & UART_RSA_MSR_FIFO);		}		if (result)			up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;		spin_unlock_irq(&up->port.lock);	}}#endif /* CONFIG_SERIAL_8250_RSA *//* * This is a quickie test to see how big the FIFO is. * It doesn't work at all the time, more's the pity. */static int size_fifo(struct uart_8250_port *up){	unsigned char old_fcr, old_mcr, old_dll, old_dlm;	int count;	old_fcr = serial_inp(up, UART_FCR);	old_mcr = serial_inp(up, UART_MCR);	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);	serial_outp(up, UART_MCR, UART_MCR_LOOP);	serial_outp(up, UART_LCR, UART_LCR_DLAB);	old_dll = serial_inp(up, UART_DLL);	old_dlm = serial_inp(up, UART_DLM);	serial_outp(up, UART_DLL, 0x01);	serial_outp(up, UART_DLM, 0x00);	serial_outp(up, UART_LCR, 0x03);	for (count = 0; count < 256; count++)		serial_outp(up, UART_TX, count);	mdelay(20);/* FIXME - schedule_timeout */	for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&	     (count < 256); count++)

⌨️ 快捷键说明

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