📄 8250.c
字号:
/* * 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. */#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/platform_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/nmi.h>#include <linux/mutex.h>#include <asm/io.h>#include <asm/irq.h>#include "8250.h"/* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option * is unsafe when used on edge-triggered interrupts. */static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;/* * 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)#ifdef CONFIG_SERIAL_8250_DETECT_IRQ#define CONFIG_SERIAL_DETECT_IRQ 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 const struct old_serial_port old_serial_port[] = { SERIAL_PORT_DFNS /* defined in asm/serial.h */};#define UART_NR 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 short capabilities; /* port capabilities */ unsigned short bugs; /* port bugs */ unsigned int tx_loadsz; /* transmit fifo load size */ 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 | UART_CAP_UUE, },};#ifdef CONFIG_SERIAL_8250_AU1X00/* Au1x00 UART hardware has a weird register layout */static const u8 au_io_in_map[] = { [UART_RX] = 0, [UART_IER] = 2, [UART_IIR] = 3, [UART_LCR] = 5, [UART_MCR] = 6, [UART_LSR] = 7, [UART_MSR] = 8,};static const u8 au_io_out_map[] = { [UART_TX] = 1, [UART_IER] = 2, [UART_FCR] = 4, [UART_LCR] = 5, [UART_MCR] = 6,};/* sane hardware needs no mapping */static inline int map_8250_in_reg(struct uart_8250_port *up, int offset){ if (up->port.iotype != UPIO_AU) return offset; return au_io_in_map[offset];}static inline int map_8250_out_reg(struct uart_8250_port *up, int offset){ if (up->port.iotype != UPIO_AU) return offset; return au_io_out_map[offset];}#else/* sane hardware needs no mapping */#define map_8250_in_reg(up, offset) (offset)#define map_8250_out_reg(up, offset) (offset)#endifstatic unsigned int serial_in(struct uart_8250_port *up, int offset){ unsigned int tmp; offset = map_8250_in_reg(up, 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);#ifdef CONFIG_SERIAL_8250_AU1X00 case UPIO_AU: return __raw_readl(up->port.membase + offset);#endif case UPIO_TSI: if (offset == UART_IIR) { tmp = readl(up->port.membase + (UART_IIR & ~3)); return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ } else return readb(up->port.membase + offset); default: return inb(up->port.iobase + offset); }}static voidserial_out(struct uart_8250_port *up, int offset, int value){ offset = map_8250_out_reg(up, 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;#ifdef CONFIG_SERIAL_8250_AU1X00 case UPIO_AU: __raw_writel(value, up->port.membase + offset); break;#endif case UPIO_TSI: if (!((offset == UART_IER) && (value & UART_IER_UUE))) writeb(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)/* Uart divisor latch read */static inline int _serial_dl_read(struct uart_8250_port *up){ return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;}/* Uart divisor latch write */static inline void _serial_dl_write(struct uart_8250_port *up, int value){ serial_outp(up, UART_DLL, value & 0xff); serial_outp(up, UART_DLM, value >> 8 & 0xff);}#ifdef CONFIG_SERIAL_8250_AU1X00/* Au1x00 haven't got a standard divisor latch */static int serial_dl_read(struct uart_8250_port *up){ if (up->port.iotype == UPIO_AU) return __raw_readl(up->port.membase + 0x28); else return _serial_dl_read(up);}static void serial_dl_write(struct uart_8250_port *up, int value){ if (up->port.iotype == UPIO_AU) __raw_writel(value, up->port.membase + 0x28); else _serial_dl_write(up, value);}#else#define serial_dl_read(up) _serial_dl_read(up)#define serial_dl_write(up, value) _serial_dl_write(up, value)#endif/* * 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -