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

📄 8250.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  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. */#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/tty.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/console.h>#include <linux/sysrq.h>#include <linux/serial_reg.h>#include <linux/serial.h>#include <linux/serialP.h>#include <linux/delay.h>#include <linux/device.h>#include <asm/io.h>#include <asm/irq.h>#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif#include <linux/serial_core.h>#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_MAX_8250+1] = {	{ "unknown",	1,	1,	0 },	{ "8250",	1,	1,	0 },	{ "16450",	1,	1,	0 },	{ "16550",	1,	1,	0 },	{ "16550A",	16,	16,	UART_CAP_FIFO },	{ "Cirrus",	1, 	1,	0 },	{ "ST16650",	1,	1,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },	{ "ST16650V2",	32,	16,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },	{ "TI16750",	64,	64,	UART_CAP_FIFO | UART_CAP_SLEEP },	{ "Startech",	1,	1,	0 },	{ "16C950/954",	128,	128,	UART_CAP_FIFO },	{ "ST16654",	64,	32,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },	{ "XR16850",	128,	128,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },	{ "RSA",	2048,	2048,	UART_CAP_FIFO },	{ "NS16550A",	16,	16,	UART_CAP_FIFO | UART_NATSEMI },	{ "XScale",	32,	32,	UART_CAP_FIFO },	{ "OMAP UART",	64,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }};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++)		serial_inp(up, UART_RX);	serial_outp(up, UART_FCR, old_fcr);	serial_outp(up, UART_MCR, old_mcr);	serial_outp(up, UART_LCR, UART_LCR_DLAB);	serial_outp(up, UART_DLL, old_dll);	serial_outp(up, UART_DLM, old_dlm);	return count;}/* * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. * When this function is called we know it is at least a StarTech * 16650 V2, but it might be one of several StarTech UARTs, or one of * its clones.  (We treat the broken original StarTech 16650 V1 as a * 16550, and why not?  Startech doesn't seem to even acknowledge its * existence.) *  * What evil have men's minds wrought... */static void autoconfig_has_efr(struct uart_8250_port *up){	unsigned char id1, id2, id3, rev, saved_dll, saved_dlm;	/*	 * First we check to see if it's an Oxford Semiconductor UART.	 *	 * If we have to do this here because some non-National	 * Semiconductor clone chips lock up if you try writing to the	 * LSR register (which serial_icr_read does)	 */	/*	 * Check for Oxford Semiconductor 16C950.	 *	 * EFR [4] must be set else this test fails.	 *	 * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)	 * claims that it's needed for 952 dual UART's (which are not	 * recommended for new designs).	 */	up->acr = 0;	serial_out(up, UART_LCR, 0xBF);	serial_out(up, UART_EFR, UART_EFR_ECB);	serial_out(up, UART_LCR, 0x00);	id1 = serial_icr_read(up, UART_ID1);	id2 = serial_icr_read(up, UART_ID2);	id3 = serial_icr_read(up, UART_ID3);	rev = serial_icr_read(up, UART_REV);	DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);	if (id1 == 0x16 && id2 == 0xC9 &&	    (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {		up->port.type = PORT_16C950;		up->rev = rev | (id3 << 8);		return;	}		/*	 * We check for a XR16C850 by setting DLL and DLM to 0, and then	 * reading back DLL and DLM.  The chip type depends on the DLM	 * value read back:	 *  0x10 - XR16C850 and the DLL contains the chip revision.	 *  0x12 - XR16C2850.	 *  0x14 - XR16C854.	 */	serial_outp(up, UART_LCR, UART_LCR_DLAB);	saved_dll = serial_inp(up, UART_DLL);	saved_dlm = serial_inp(up, UART_DLM);	serial_outp(up, UART_DLL, 0);	serial_outp(up, UART_DLM, 0);	id2 = serial_inp(up, UART_DLL);	id1 = serial_inp(up, UART_DLM);	serial_outp(up, UART_DLL, saved_dll);	serial_outp(up, UART_DLM, saved_dlm);	DEBUG_AUTOCONF("850id=%02x:%02x ", id1, id2);	if (id1 == 0x10 || id1 == 0x12 || id1 == 0x14) {		if (id1 == 0x10)			up->rev = id2;		up->port.type = PORT_16850;		return;	}	/*	 * It wasn't an XR16C850.	 *	 * We distinguish between the '654 and the '650 by counting	 * how many bytes are in the FIFO.  I'm using this for now,	 * since that's the technique that was sent to me in the	 * serial driver update, but I'm not convinced this works.	 * I've had problems doing this in the past.  -TYT	 */	if (size_fifo(up) == 64)		up->port.type = PORT_16654;	else		up->port.type = PORT_16650V2;}/* * We detected a chip without a FIFO.  Only two fall into * this category - the original 8250 and the 16450.  The * 16450 has a scratch register (accessible with LCR=0) */static void autoconfig_8250(struct uart_8250_port *up){	unsigned char scratch, status1, status2;	up->port.type = PORT_8250;	scratch = serial_in(up, UART_SCR);	serial_outp(up, UART_SCR, 0xa5);	status1 = serial_in(up, UART_SCR);	serial_outp(up, UART_SCR, 0x5a);	status2 = serial_in(up, UART_SCR);	serial_outp(up, UART_SCR, scratch);	if (status1 == 0xa5 && status2 == 0x5a)		up->port.type = PORT_16450;}/* * We know that the chip has FIFOs.  Does it have an EFR?  The * EFR is located in the same register position as the IIR and * we know the top two bits of the IIR are currently set.  The * EFR should contain zero.  Try to read the EFR. */static void autoconfig_16550a(struct uart_8250_port *up){	unsigned char status1, status2;	up->port.type = PORT_16550A;	/*	 * Check for presence of the EFR when DLAB is set.	 * Only ST16C650V1 UARTs pass this test.	 */	serial_outp(up, UART_LCR, UART_LCR_DLAB);	if (serial_in(up, UART_EFR) == 0) {		serial_outp(up, UART_EFR, 0xA8);		if (serial_in(up, UART_EFR) != 0) {			DEBUG_AUTOCONF("EFRv1 ");			up->port.type = PORT_16650;		} else {			DEBUG_AUTOCONF("Motorola 8xxx DUART ");		}		serial_outp(up, UART_EFR, 0);		return;	}	/*	 * Maybe it requires 0xbf to be written to the LCR.	 * (other ST16C650V2 UARTs, TI16C752A, etc)	 */	serial_outp(up, UART_LCR, 0xBF);	if (serial_in(up, UART_EFR) == 0) {		DEBUG_AUTOCONF("EFRv2 ");		autoconfig_has_efr(up);		return;	}	/*	 * Check for a National Semiconductor SuperIO chip.	 * Attempt to switch to bank 2, read the value of the LOOP bit	 * from EXCR1. Switch back to bank 0, change it in MCR. Then	 * switch back to bank 2, read it from EXCR1 again and check	 * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2	 * On PowerPC we don't want to change baud_base, as we have	 * a number of different divisors.  -- Tom Rini	 */	serial_outp(up, UART_LCR, 0);	status1 = serial_in(up, UART_MCR);	serial_outp(up, UART_LCR, 0xE0);	status2 = serial_in(up, 0x02); /* EXCR1 */	if (!((status2 ^ status1) & UART_MCR_LOOP)) {		serial_outp(up, UART_LCR, 0);		serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);

⌨️ 快捷键说明

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