2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* Universal/legacy driver for 8250/16550-type serial ports
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001 Russell King.
|
|
|
|
*
|
2015-06-27 21:19:00 +08:00
|
|
|
* Supports: ISA-compatible 8250/16550 ports
|
|
|
|
* PNP 8250/16550 ports
|
|
|
|
* early_serial_setup() ports
|
|
|
|
* userspace-configurable "phantom" ports
|
|
|
|
* "serial8250" platform devices
|
|
|
|
* serial8250_register_8250_port() ports
|
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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>
|
2005-10-30 02:07:23 +08:00
|
|
|
#include <linux/platform_device.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/tty.h>
|
2010-10-21 07:00:48 +08:00
|
|
|
#include <linux/ratelimit.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/serial.h>
|
|
|
|
#include <linux/serial_8250.h>
|
2005-11-07 16:59:13 +08:00
|
|
|
#include <linux/nmi.h>
|
2006-01-13 02:44:32 +08:00
|
|
|
#include <linux/mutex.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2014-09-09 13:17:45 +08:00
|
|
|
#include <linux/uaccess.h>
|
2014-09-11 03:29:57 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
2015-08-11 11:07:05 +08:00
|
|
|
#include <linux/io.h>
|
2012-02-10 07:48:19 +08:00
|
|
|
#ifdef CONFIG_SPARC
|
|
|
|
#include <linux/sunserialcore.h>
|
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <asm/irq.h>
|
|
|
|
|
|
|
|
#include "8250.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configuration:
|
2006-07-02 10:29:43 +08:00
|
|
|
* share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
|
2005-04-17 06:20:36 +08:00
|
|
|
* is unsafe when used on edge-triggered interrupts.
|
|
|
|
*/
|
2005-05-01 23:59:29 +08:00
|
|
|
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-01-08 07:18:19 +08:00
|
|
|
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
|
|
|
|
|
2008-10-13 17:45:26 +08:00
|
|
|
static struct uart_driver serial8250_reg;
|
|
|
|
|
2009-10-02 06:44:26 +08:00
|
|
|
static unsigned int skip_txen_test; /* force skip of txen test at init time */
|
|
|
|
|
2011-06-06 04:51:49 +08:00
|
|
|
#define PASS_LIMIT 512
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-05-31 16:10:04 +08:00
|
|
|
#include <asm/serial.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
#endif
|
|
|
|
|
2005-11-29 05:04:11 +08:00
|
|
|
static const struct old_serial_port old_serial_port[] = {
|
2005-04-17 06:20:36 +08:00
|
|
|
SERIAL_PORT_DFNS /* defined in asm/serial.h */
|
|
|
|
};
|
|
|
|
|
2005-06-30 01:45:19 +08:00
|
|
|
#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
|
|
|
|
#define PORT_RSA_MAX 4
|
|
|
|
static unsigned long probe_rsa[PORT_RSA_MAX];
|
|
|
|
static unsigned int probe_rsa_count;
|
|
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
|
|
|
|
|
|
struct irq_info {
|
2008-08-20 11:49:40 +08:00
|
|
|
struct hlist_node node;
|
|
|
|
int irq;
|
|
|
|
spinlock_t lock; /* Protects list not the hash */
|
2005-04-17 06:20:36 +08:00
|
|
|
struct list_head *head;
|
|
|
|
};
|
|
|
|
|
2008-08-20 11:49:40 +08:00
|
|
|
#define NR_IRQ_HASH 32 /* Can be adjusted later */
|
|
|
|
static struct hlist_head irq_lists[NR_IRQ_HASH];
|
|
|
|
static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* This is the serial driver's interrupt routine.
|
|
|
|
*
|
|
|
|
* Arjan thinks the old way was overly complex, so it got simplified.
|
|
|
|
* Alan disagrees, saying that need the complexity to handle the weird
|
|
|
|
* nature of ISA shared interrupts. (This is a special exception.)
|
|
|
|
*
|
|
|
|
* In order to handle ISA shared interrupts properly, we need to check
|
|
|
|
* that all ports have been serviced, and therefore the ISA interrupt
|
|
|
|
* line has been de-asserted.
|
|
|
|
*
|
|
|
|
* This means we need to loop through all ports. checking that they
|
|
|
|
* don't have an interrupt pending.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2015-06-27 21:19:00 +08:00
|
|
|
static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
2009-01-02 21:49:47 +08:00
|
|
|
{
|
2015-06-27 21:19:00 +08:00
|
|
|
struct irq_info *i = dev_id;
|
|
|
|
struct list_head *l, *end = NULL;
|
|
|
|
int pass_counter = 0, handled = 0;
|
2009-01-02 21:49:47 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
DEBUG_INTR("serial8250_interrupt(%d)...", irq);
|
2011-08-15 17:17:52 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_lock(&i->lock);
|
2012-05-02 20:46:51 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
l = i->head;
|
|
|
|
do {
|
|
|
|
struct uart_8250_port *up;
|
|
|
|
struct uart_port *port;
|
2012-05-02 20:46:51 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
up = list_entry(l, struct uart_8250_port, list);
|
|
|
|
port = &up->port;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (port->handle_irq(port)) {
|
|
|
|
handled = 1;
|
|
|
|
end = NULL;
|
|
|
|
} else if (end == NULL)
|
|
|
|
end = l;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
l = l->next;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (l == i->head && pass_counter++ > PASS_LIMIT) {
|
|
|
|
/* If we hit this, we're dead. */
|
|
|
|
printk_ratelimited(KERN_ERR
|
|
|
|
"serial8250: too much work for irq%d\n", irq);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (l != end);
|
2015-04-10 04:05:17 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_unlock(&i->lock);
|
2010-07-16 03:45:05 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
DEBUG_INTR("end.\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
return IRQ_RETVAL(handled);
|
2007-02-14 16:33:04 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* To support ISA shared interrupts, we need to have one interrupt
|
|
|
|
* handler that ensures that the IRQ line has been deasserted
|
|
|
|
* before returning. Failing to do this will result in the IRQ
|
|
|
|
* line being stuck active, and, since ISA irqs are edge triggered,
|
|
|
|
* no more IRQs will be seen.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2015-06-27 21:19:00 +08:00
|
|
|
static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_lock_irq(&i->lock);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (!list_empty(i->head)) {
|
|
|
|
if (i->head == &up->list)
|
|
|
|
i->head = i->head->next;
|
|
|
|
list_del(&up->list);
|
|
|
|
} else {
|
|
|
|
BUG_ON(i->head != &up->list);
|
|
|
|
i->head = NULL;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(&i->lock);
|
|
|
|
/* List empty so throw away the hash node */
|
|
|
|
if (i->head == NULL) {
|
|
|
|
hlist_del(&i->node);
|
|
|
|
kfree(i);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
static int serial_link_irq_chain(struct uart_8250_port *up)
|
2012-04-11 05:10:58 +08:00
|
|
|
{
|
2015-06-27 21:19:00 +08:00
|
|
|
struct hlist_head *h;
|
|
|
|
struct hlist_node *n;
|
|
|
|
struct irq_info *i;
|
|
|
|
int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
|
2012-04-11 05:10:58 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
mutex_lock(&hash_mutex);
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
hlist_for_each(n, h) {
|
|
|
|
i = hlist_entry(n, struct irq_info, node);
|
|
|
|
if (i->irq == up->port.irq)
|
|
|
|
break;
|
|
|
|
}
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (n == NULL) {
|
|
|
|
i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
|
|
|
|
if (i == NULL) {
|
|
|
|
mutex_unlock(&hash_mutex);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
spin_lock_init(&i->lock);
|
|
|
|
i->irq = up->port.irq;
|
|
|
|
hlist_add_head(&i->node, h);
|
|
|
|
}
|
|
|
|
mutex_unlock(&hash_mutex);
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_lock_irq(&i->lock);
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (i->head) {
|
|
|
|
list_add(&up->list, i->head);
|
|
|
|
spin_unlock_irq(&i->lock);
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
INIT_LIST_HEAD(&up->list);
|
|
|
|
i->head = &up->list;
|
|
|
|
spin_unlock_irq(&i->lock);
|
|
|
|
irq_flags |= up->port.irqflags;
|
|
|
|
ret = request_irq(up->port.irq, serial8250_interrupt,
|
|
|
|
irq_flags, "serial", i);
|
|
|
|
if (ret < 0)
|
|
|
|
serial_do_unlink(i, up);
|
|
|
|
}
|
2014-09-11 03:29:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
return ret;
|
2014-09-11 03:29:57 +08:00
|
|
|
}
|
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
static void serial_unlink_irq_chain(struct uart_8250_port *up)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-11-19 23:12:04 +08:00
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* yes, some broken gcc emit "warning: 'i' may be used uninitialized"
|
|
|
|
* but no, we are not going to take a patch that assigns NULL below.
|
2012-11-19 23:12:04 +08:00
|
|
|
*/
|
2015-06-27 21:19:00 +08:00
|
|
|
struct irq_info *i;
|
|
|
|
struct hlist_node *n;
|
|
|
|
struct hlist_head *h;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
mutex_lock(&hash_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
hlist_for_each(n, h) {
|
|
|
|
i = hlist_entry(n, struct irq_info, node);
|
|
|
|
if (i->irq == up->port.irq)
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
BUG_ON(n == NULL);
|
|
|
|
BUG_ON(i->head == NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (list_empty(i->head))
|
|
|
|
free_irq(up->port.irq, i);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
serial_do_unlink(i, up);
|
|
|
|
mutex_unlock(&hash_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* This function is used to handle ports that do not have an
|
|
|
|
* interrupt. This doesn't work very well for 16450's, but gives
|
|
|
|
* barely passable results for a 16550A. (Although at the expense
|
|
|
|
* of much CPU overhead).
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2015-06-27 21:19:00 +08:00
|
|
|
static void serial8250_timeout(unsigned long data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-06-27 21:19:00 +08:00
|
|
|
struct uart_8250_port *up = (struct uart_8250_port *)data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
up->port.handle_irq(&up->port);
|
|
|
|
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
static void serial8250_backup_timeout(unsigned long data)
|
2015-01-23 01:24:27 +08:00
|
|
|
{
|
2015-06-27 21:19:00 +08:00
|
|
|
struct uart_8250_port *up = (struct uart_8250_port *)data;
|
|
|
|
unsigned int iir, ier = 0, lsr;
|
2015-01-23 01:24:27 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_lock_irqsave(&up->port.lock, flags);
|
2014-02-12 08:30:01 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2015-06-27 21:19:00 +08:00
|
|
|
* Must disable interrupts or else we risk racing with the interrupt
|
|
|
|
* based handler.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2015-06-27 21:19:00 +08:00
|
|
|
if (up->port.irq) {
|
|
|
|
ier = serial_in(up, UART_IER);
|
|
|
|
serial_out(up, UART_IER, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
U6715 16550A serial driver support
UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
* Fully compatible with industry standard 16C550 and 16C450 from various
manufacturers
* RX and TX 64 byte FIFO reduces CPU interrupts
* Full double buffering
* Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
* Automatic baud rate selection
* Manual or automatic RTS/CTS smart hardware flow control
* Programmable serial characteristics:
– Baud rate generation (50 to 3.25M baud)
– 5, 6, 7 or 8-bit characters
– Even, odd or no-parity bit generation and detection
– 1, 1.5 or 2 stop bit generation
* Independent control of transmit, receive, line status, data set interrupts and FIFOs
* Full status-reporting capabilities
* Separate DMA signaling for RX and TX
* Timed interrupt to spread receive interrupt on known duration
* DMA time-out interrupt to allow detection of end of reception
* Carkit pulse coding and decoding compliant with USB carkit control interface [40]
In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port
Add set_termios hook & export serial8250_do_set_termios to change uart
clock following baudrate
Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-07-29 23:13:57 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
iir = serial_in(up, UART_IIR);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
/*
|
|
|
|
* This should be a safe test for anyone who doesn't trust the
|
|
|
|
* IIR bits on their UART, but it's specifically designed for
|
|
|
|
* the "Diva" UART used on the management processor on many HP
|
|
|
|
* ia64 and parisc boxes.
|
|
|
|
*/
|
|
|
|
lsr = serial_in(up, UART_LSR);
|
|
|
|
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
|
|
|
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
|
|
|
|
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
|
|
|
|
(lsr & UART_LSR_THRE)) {
|
|
|
|
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
|
|
|
|
iir |= UART_IIR_THRI;
|
2014-11-06 02:11:45 +08:00
|
|
|
}
|
2010-09-25 21:13:45 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (!(iir & UART_IIR_NO_INT))
|
|
|
|
serial8250_tx_chars(up);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
if (up->port.irq)
|
|
|
|
serial_out(up, UART_IER, ier);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
spin_unlock_irqrestore(&up->port.lock, flags);
|
2012-10-04 06:31:58 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
/* Standard timer interval plus 0.2s to keep the port running */
|
|
|
|
mod_timer(&up->timer,
|
|
|
|
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
|
2008-09-02 04:47:59 +08:00
|
|
|
}
|
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
static int univ8250_setup_irq(struct uart_8250_port *up)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2015-06-27 21:19:00 +08:00
|
|
|
int retval = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
/*
|
|
|
|
* The above check will only give an accurate result the first time
|
|
|
|
* the port is opened so this value needs to be preserved.
|
|
|
|
*/
|
|
|
|
if (up->bugs & UART_BUG_THRE) {
|
|
|
|
pr_debug("ttyS%d - using backup timer\n", serial_index(port));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
up->timer.function = serial8250_backup_timeout;
|
|
|
|
up->timer.data = (unsigned long)up;
|
|
|
|
mod_timer(&up->timer, jiffies +
|
|
|
|
uart_poll_timeout(port) + HZ / 5);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
/*
|
|
|
|
* If the "interrupt" for this port doesn't correspond with any
|
|
|
|
* hardware interrupt, we use a timer-based system. The original
|
|
|
|
* driver used to do this with IRQ0.
|
|
|
|
*/
|
|
|
|
if (!port->irq) {
|
|
|
|
up->timer.data = (unsigned long)up;
|
|
|
|
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
|
|
|
|
} else
|
|
|
|
retval = serial_link_irq_chain(up);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
static void univ8250_release_irq(struct uart_8250_port *up)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-06-27 21:19:00 +08:00
|
|
|
del_timer_sync(&up->timer);
|
|
|
|
up->timer.function = serial8250_timeout;
|
|
|
|
if (port->irq)
|
|
|
|
serial_unlink_irq_chain(up);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2015-02-25 03:25:12 +08:00
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
2005-04-17 06:20:36 +08:00
|
|
|
static int serial8250_request_rsa_resource(struct uart_8250_port *up)
|
|
|
|
{
|
|
|
|
unsigned long start = UART_RSA_BASE << up->port.regshift;
|
|
|
|
unsigned int size = 8 << up->port.regshift;
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2006-09-10 02:23:56 +08:00
|
|
|
int ret = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-03-09 08:12:11 +08:00
|
|
|
switch (port->iotype) {
|
2005-04-17 06:20:36 +08:00
|
|
|
case UPIO_HUB6:
|
|
|
|
case UPIO_PORT:
|
2012-03-09 08:12:11 +08:00
|
|
|
start += port->iobase;
|
2006-09-10 02:23:56 +08:00
|
|
|
if (request_region(start, size, "serial-rsa"))
|
|
|
|
ret = 0;
|
|
|
|
else
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void serial8250_release_rsa_resource(struct uart_8250_port *up)
|
|
|
|
{
|
|
|
|
unsigned long offset = UART_RSA_BASE << up->port.regshift;
|
|
|
|
unsigned int size = 8 << up->port.regshift;
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-03-09 08:12:11 +08:00
|
|
|
switch (port->iotype) {
|
2005-04-17 06:20:36 +08:00
|
|
|
case UPIO_HUB6:
|
|
|
|
case UPIO_PORT:
|
2012-03-09 08:12:11 +08:00
|
|
|
release_region(port->iobase + offset, size);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-02-25 03:25:12 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-02-25 03:25:14 +08:00
|
|
|
static const struct uart_ops *base_ops;
|
|
|
|
static struct uart_ops univ8250_port_ops;
|
|
|
|
|
2015-02-25 03:25:07 +08:00
|
|
|
static const struct uart_8250_ops univ8250_driver_ops = {
|
|
|
|
.setup_irq = univ8250_setup_irq,
|
|
|
|
.release_irq = univ8250_release_irq,
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static struct uart_8250_port serial8250_ports[UART_NR];
|
|
|
|
|
2014-09-06 03:02:36 +08:00
|
|
|
/**
|
|
|
|
* serial8250_get_port - retrieve struct uart_8250_port
|
|
|
|
* @line: serial line number
|
|
|
|
*
|
|
|
|
* This function retrieves struct uart_8250_port for the specific line.
|
|
|
|
* This struct *must* *not* be used to perform a 8250 or serial core operation
|
|
|
|
* which is not accessible otherwise. Its only purpose is to make the struct
|
|
|
|
* accessible to the runtime-pm callbacks for context suspend/restore.
|
|
|
|
* The lock assumption made here is none because runtime-pm suspend/resume
|
|
|
|
* callbacks should not be invoked if there is any operation performed on the
|
|
|
|
* port.
|
|
|
|
*/
|
|
|
|
struct uart_8250_port *serial8250_get_port(int line)
|
|
|
|
{
|
|
|
|
return &serial8250_ports[line];
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(serial8250_get_port);
|
|
|
|
|
2010-10-19 02:38:02 +08:00
|
|
|
static void (*serial8250_isa_config)(int port, struct uart_port *up,
|
|
|
|
unsigned short *capabilities);
|
|
|
|
|
|
|
|
void serial8250_set_isa_configurator(
|
|
|
|
void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
|
|
|
|
{
|
|
|
|
serial8250_isa_config = v;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(serial8250_set_isa_configurator);
|
|
|
|
|
2015-02-25 03:25:14 +08:00
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
|
|
|
|
static void univ8250_config_port(struct uart_port *port, int flags)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
|
|
|
|
up->probe &= ~UART_PROBE_RSA;
|
|
|
|
if (port->type == PORT_RSA) {
|
|
|
|
if (serial8250_request_rsa_resource(up) == 0)
|
|
|
|
up->probe |= UART_PROBE_RSA;
|
|
|
|
} else if (flags & UART_CONFIG_TYPE) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < probe_rsa_count; i++) {
|
|
|
|
if (probe_rsa[i] == up->port.iobase) {
|
|
|
|
if (serial8250_request_rsa_resource(up) == 0)
|
|
|
|
up->probe |= UART_PROBE_RSA;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
base_ops->config_port(port, flags);
|
|
|
|
|
|
|
|
if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
|
|
|
|
serial8250_release_rsa_resource(up);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int univ8250_request_port(struct uart_port *port)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = base_ops->request_port(port);
|
|
|
|
if (ret == 0 && port->type == PORT_RSA) {
|
|
|
|
ret = serial8250_request_rsa_resource(up);
|
|
|
|
if (ret < 0)
|
|
|
|
base_ops->release_port(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void univ8250_release_port(struct uart_port *port)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
|
|
|
|
if (port->type == PORT_RSA)
|
|
|
|
serial8250_release_rsa_resource(up);
|
|
|
|
base_ops->release_port(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void univ8250_rsa_support(struct uart_ops *ops)
|
|
|
|
{
|
|
|
|
ops->config_port = univ8250_config_port;
|
|
|
|
ops->request_port = univ8250_request_port;
|
|
|
|
ops->release_port = univ8250_release_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#define univ8250_rsa_support(x) do { } while (0)
|
|
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void __init serial8250_isa_init_ports(void)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *up;
|
|
|
|
static int first = 1;
|
2009-10-25 22:01:34 +08:00
|
|
|
int i, irqflag = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!first)
|
|
|
|
return;
|
|
|
|
first = 0;
|
|
|
|
|
2012-09-08 02:06:23 +08:00
|
|
|
if (nr_uarts > UART_NR)
|
|
|
|
nr_uarts = UART_NR;
|
|
|
|
|
2013-06-03 21:38:26 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
2005-04-17 06:20:36 +08:00
|
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-03-09 08:12:11 +08:00
|
|
|
port->line = i;
|
2015-02-25 03:25:08 +08:00
|
|
|
serial8250_init_port(up);
|
2015-02-25 03:25:14 +08:00
|
|
|
if (!base_ops)
|
|
|
|
base_ops = port->ops;
|
|
|
|
port->ops = &univ8250_port_ops;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
init_timer(&up->timer);
|
|
|
|
up->timer.function = serial8250_timeout;
|
|
|
|
|
2015-02-25 03:25:07 +08:00
|
|
|
up->ops = &univ8250_driver_ops;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* ALPHA_KLUDGE_MCR needs to be killed.
|
|
|
|
*/
|
|
|
|
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
|
|
|
|
up->mcr_force = ALPHA_KLUDGE_MCR;
|
|
|
|
}
|
|
|
|
|
2015-02-25 03:25:14 +08:00
|
|
|
/* chain base port ops to support Remote Supervisor Adapter */
|
|
|
|
univ8250_port_ops = *base_ops;
|
|
|
|
univ8250_rsa_support(&univ8250_port_ops);
|
|
|
|
|
2009-10-25 22:01:34 +08:00
|
|
|
if (share_irqs)
|
|
|
|
irqflag = IRQF_SHARED;
|
|
|
|
|
2005-07-01 05:41:22 +08:00
|
|
|
for (i = 0, up = serial8250_ports;
|
2006-01-08 07:18:19 +08:00
|
|
|
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
|
2005-04-17 06:20:36 +08:00
|
|
|
i++, up++) {
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
|
|
|
|
|
|
|
port->iobase = old_serial_port[i].port;
|
|
|
|
port->irq = irq_canonicalize(old_serial_port[i].irq);
|
|
|
|
port->irqflags = old_serial_port[i].irqflags;
|
|
|
|
port->uartclk = old_serial_port[i].baud_base * 16;
|
|
|
|
port->flags = old_serial_port[i].flags;
|
|
|
|
port->hub6 = old_serial_port[i].hub6;
|
|
|
|
port->membase = old_serial_port[i].iomem_base;
|
|
|
|
port->iotype = old_serial_port[i].io_type;
|
|
|
|
port->regshift = old_serial_port[i].iomem_reg_shift;
|
2015-02-25 03:25:09 +08:00
|
|
|
serial8250_set_defaults(up);
|
|
|
|
|
2012-03-09 08:12:11 +08:00
|
|
|
port->irqflags |= irqflag;
|
2010-10-19 02:38:02 +08:00
|
|
|
if (serial8250_isa_config != NULL)
|
|
|
|
serial8250_isa_config(i, &up->port, &up->capabilities);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init
|
|
|
|
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2009-05-28 21:01:35 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
|
2015-09-27 22:25:56 +08:00
|
|
|
if (up->port.type == PORT_8250_CIR)
|
|
|
|
continue;
|
|
|
|
|
2012-09-08 02:06:23 +08:00
|
|
|
if (up->port.dev)
|
|
|
|
continue;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
up->port.dev = dev;
|
2009-12-10 04:31:29 +08:00
|
|
|
|
2015-02-25 03:25:05 +08:00
|
|
|
if (skip_txen_test)
|
|
|
|
up->port.flags |= UPF_NO_TXEN_TEST;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_add_one_port(drv, &up->port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
|
|
|
|
2015-02-25 03:25:06 +08:00
|
|
|
static void univ8250_console_write(struct console *co, const char *s,
|
|
|
|
unsigned int count)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *up = &serial8250_ports[co->index];
|
|
|
|
|
|
|
|
serial8250_console_write(up, s, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int univ8250_console_setup(struct console *co, char *options)
|
|
|
|
{
|
2015-04-06 22:48:49 +08:00
|
|
|
struct uart_port *port;
|
2016-01-11 06:39:34 +08:00
|
|
|
int retval;
|
2015-02-25 03:25:06 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Check whether an invalid uart number has been specified, and
|
|
|
|
* if so, search for the first available port that does have
|
|
|
|
* console support.
|
|
|
|
*/
|
2013-06-03 21:38:26 +08:00
|
|
|
if (co->index >= nr_uarts)
|
2005-04-17 06:20:36 +08:00
|
|
|
co->index = 0;
|
2015-04-06 22:48:49 +08:00
|
|
|
port = &serial8250_ports[co->index].port;
|
2015-02-25 03:25:06 +08:00
|
|
|
/* link port to console */
|
2015-04-06 22:48:49 +08:00
|
|
|
port->cons = co;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-01-11 06:39:34 +08:00
|
|
|
retval = serial8250_console_setup(port, options, false);
|
|
|
|
if (retval != 0)
|
|
|
|
port->cons = NULL;
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2015-03-10 04:27:12 +08:00
|
|
|
/**
|
2015-02-25 03:25:06 +08:00
|
|
|
* univ8250_console_match - non-standard console matching
|
2015-03-10 04:27:12 +08:00
|
|
|
* @co: registering console
|
|
|
|
* @name: name from console command line
|
|
|
|
* @idx: index from console command line
|
|
|
|
* @options: ptr to option string from console command line
|
|
|
|
*
|
|
|
|
* Only attempts to match console command lines of the form:
|
2015-10-28 11:46:05 +08:00
|
|
|
* console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>]
|
earlycon: 8250: Document kernel command line options
Document the expected behavior of kernel command lines of the forms:
console=uart[8250],io|mmio|mmio32,<addr>[,options]
console=uart[8250],<addr>[,options]
and
earlycon=uart[8250],io|mmio|mmio32,<addr>[,options]
earlycon=uart[8250],<addr>[,options]
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-04-06 22:52:39 +08:00
|
|
|
* console=uart[8250],0x<addr>[,<options>]
|
2015-03-10 04:27:12 +08:00
|
|
|
* This form is used to register an initial earlycon boot console and
|
|
|
|
* replace it with the serial8250_console at 8250 driver init.
|
|
|
|
*
|
|
|
|
* Performs console setup for a match (as required by interface)
|
earlycon: 8250: Document kernel command line options
Document the expected behavior of kernel command lines of the forms:
console=uart[8250],io|mmio|mmio32,<addr>[,options]
console=uart[8250],<addr>[,options]
and
earlycon=uart[8250],io|mmio|mmio32,<addr>[,options]
earlycon=uart[8250],<addr>[,options]
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-04-06 22:52:39 +08:00
|
|
|
* If no <options> are specified, then assume the h/w is already setup.
|
2015-03-10 04:27:12 +08:00
|
|
|
*
|
|
|
|
* Returns 0 if console matches; otherwise non-zero to use default matching
|
|
|
|
*/
|
2015-02-25 03:25:06 +08:00
|
|
|
static int univ8250_console_match(struct console *co, char *name, int idx,
|
|
|
|
char *options)
|
serial: convert early_uart to earlycon for 8250
Beacuse SERIAL_PORT_DFNS is removed from include/asm-i386/serial.h and
include/asm-x86_64/serial.h. the serial8250_ports need to be probed late in
serial initializing stage. the console_init=>serial8250_console_init=>
register_console=>serial8250_console_setup will return -ENDEV, and console
ttyS0 can not be enabled at that time. need to wait till uart_add_one_port in
drivers/serial/serial_core.c to call register_console to get console ttyS0.
that is too late.
Make early_uart to use early_param, so uart console can be used earlier. Make
it to be bootconsole with CON_BOOT flag, so can use console handover feature.
and it will switch to corresponding normal serial console automatically.
new command line will be:
console=uart8250,io,0x3f8,9600n8
console=uart8250,mmio,0xff5e0000,115200n8
or
earlycon=uart8250,io,0x3f8,9600n8
earlycon=uart8250,mmio,0xff5e0000,115200n8
it will print in very early stage:
Early serial console at I/O port 0x3f8 (options '9600n8')
console [uart0] enabled
later for console it will print:
console handover: boot [uart0] -> real [ttyS0]
Signed-off-by: <yinghai.lu@sun.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Gerd Hoffmann <kraxel@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-16 14:37:59 +08:00
|
|
|
{
|
2015-03-10 04:27:12 +08:00
|
|
|
char match[] = "uart"; /* 8250-specific earlycon name */
|
|
|
|
unsigned char iotype;
|
|
|
|
unsigned long addr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (strncmp(name, match, 4) != 0)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
if (uart_parse_earlycon(options, &iotype, &addr, &options))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
/* try to match the port specified on the command line */
|
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
|
|
struct uart_port *port = &serial8250_ports[i].port;
|
|
|
|
|
|
|
|
if (port->iotype != iotype)
|
|
|
|
continue;
|
2015-10-28 11:46:05 +08:00
|
|
|
if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 ||
|
|
|
|
iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE)
|
|
|
|
&& (port->mapbase != addr))
|
2015-03-10 04:27:12 +08:00
|
|
|
continue;
|
|
|
|
if (iotype == UPIO_PORT && port->iobase != addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
co->index = i;
|
2015-04-06 22:48:49 +08:00
|
|
|
port->cons = co;
|
|
|
|
return serial8250_console_setup(port, options, true);
|
2015-03-10 04:27:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODEV;
|
serial: convert early_uart to earlycon for 8250
Beacuse SERIAL_PORT_DFNS is removed from include/asm-i386/serial.h and
include/asm-x86_64/serial.h. the serial8250_ports need to be probed late in
serial initializing stage. the console_init=>serial8250_console_init=>
register_console=>serial8250_console_setup will return -ENDEV, and console
ttyS0 can not be enabled at that time. need to wait till uart_add_one_port in
drivers/serial/serial_core.c to call register_console to get console ttyS0.
that is too late.
Make early_uart to use early_param, so uart console can be used earlier. Make
it to be bootconsole with CON_BOOT flag, so can use console handover feature.
and it will switch to corresponding normal serial console automatically.
new command line will be:
console=uart8250,io,0x3f8,9600n8
console=uart8250,mmio,0xff5e0000,115200n8
or
earlycon=uart8250,io,0x3f8,9600n8
earlycon=uart8250,mmio,0xff5e0000,115200n8
it will print in very early stage:
Early serial console at I/O port 0x3f8 (options '9600n8')
console [uart0] enabled
later for console it will print:
console handover: boot [uart0] -> real [ttyS0]
Signed-off-by: <yinghai.lu@sun.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Gerd Hoffmann <kraxel@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-16 14:37:59 +08:00
|
|
|
}
|
|
|
|
|
2015-02-25 03:25:06 +08:00
|
|
|
static struct console univ8250_console = {
|
2005-04-17 06:20:36 +08:00
|
|
|
.name = "ttyS",
|
2015-02-25 03:25:06 +08:00
|
|
|
.write = univ8250_console_write,
|
2005-04-17 06:20:36 +08:00
|
|
|
.device = uart_console_device,
|
2015-02-25 03:25:06 +08:00
|
|
|
.setup = univ8250_console_setup,
|
|
|
|
.match = univ8250_console_match,
|
2010-11-16 04:11:12 +08:00
|
|
|
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
2005-04-17 06:20:36 +08:00
|
|
|
.index = -1,
|
|
|
|
.data = &serial8250_reg,
|
|
|
|
};
|
|
|
|
|
2015-02-25 03:25:06 +08:00
|
|
|
static int __init univ8250_console_init(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-05-05 14:26:27 +08:00
|
|
|
if (nr_uarts == 0)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
serial8250_isa_init_ports();
|
2015-02-25 03:25:06 +08:00
|
|
|
register_console(&univ8250_console);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-25 03:25:06 +08:00
|
|
|
console_initcall(univ8250_console_init);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-01-14 23:08:17 +08:00
|
|
|
#define SERIAL8250_CONSOLE (&univ8250_console)
|
2005-04-17 06:20:36 +08:00
|
|
|
#else
|
|
|
|
#define SERIAL8250_CONSOLE NULL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct uart_driver serial8250_reg = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.driver_name = "serial",
|
|
|
|
.dev_name = "ttyS",
|
|
|
|
.major = TTY_MAJOR,
|
|
|
|
.minor = 64,
|
|
|
|
.cons = SERIAL8250_CONSOLE,
|
|
|
|
};
|
|
|
|
|
2006-02-23 18:22:13 +08:00
|
|
|
/*
|
|
|
|
* early_serial_setup - early registration for 8250 ports
|
|
|
|
*
|
|
|
|
* Setup an 8250 port structure prior to console initialisation. Use
|
|
|
|
* after console initialisation will cause undefined behaviour.
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
int __init early_serial_setup(struct uart_port *port)
|
|
|
|
{
|
2009-01-02 21:49:41 +08:00
|
|
|
struct uart_port *p;
|
|
|
|
|
2015-05-05 14:26:27 +08:00
|
|
|
if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
serial8250_isa_init_ports();
|
2009-01-02 21:49:41 +08:00
|
|
|
p = &serial8250_ports[port->line].port;
|
|
|
|
p->iobase = port->iobase;
|
|
|
|
p->membase = port->membase;
|
|
|
|
p->irq = port->irq;
|
2009-09-20 04:13:19 +08:00
|
|
|
p->irqflags = port->irqflags;
|
2009-01-02 21:49:41 +08:00
|
|
|
p->uartclk = port->uartclk;
|
|
|
|
p->fifosize = port->fifosize;
|
|
|
|
p->regshift = port->regshift;
|
|
|
|
p->iotype = port->iotype;
|
|
|
|
p->flags = port->flags;
|
|
|
|
p->mapbase = port->mapbase;
|
2015-03-08 22:30:04 +08:00
|
|
|
p->mapsize = port->mapsize;
|
2009-01-02 21:49:41 +08:00
|
|
|
p->private_data = port->private_data;
|
2009-01-14 05:51:07 +08:00
|
|
|
p->type = port->type;
|
|
|
|
p->line = port->line;
|
2009-01-02 21:49:47 +08:00
|
|
|
|
2015-02-25 03:25:09 +08:00
|
|
|
serial8250_set_defaults(up_to_u8250p(p));
|
|
|
|
|
2009-01-02 21:49:47 +08:00
|
|
|
if (port->serial_in)
|
|
|
|
p->serial_in = port->serial_in;
|
|
|
|
if (port->serial_out)
|
|
|
|
p->serial_out = port->serial_out;
|
2011-08-15 17:17:52 +08:00
|
|
|
if (port->handle_irq)
|
|
|
|
p->handle_irq = port->handle_irq;
|
2009-01-02 21:49:47 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* serial8250_suspend_port - suspend one serial port
|
|
|
|
* @line: serial line number
|
|
|
|
*
|
|
|
|
* Suspend one serial port.
|
|
|
|
*/
|
|
|
|
void serial8250_suspend_port(int line)
|
|
|
|
{
|
2015-01-23 01:24:30 +08:00
|
|
|
struct uart_8250_port *up = &serial8250_ports[line];
|
|
|
|
struct uart_port *port = &up->port;
|
|
|
|
|
|
|
|
if (!console_suspend_enabled && uart_console(port) &&
|
|
|
|
port->type != PORT_8250) {
|
|
|
|
unsigned char canary = 0xa5;
|
|
|
|
serial_out(up, UART_SCR, canary);
|
2015-03-10 02:05:01 +08:00
|
|
|
if (serial_in(up, UART_SCR) == canary)
|
|
|
|
up->canary = canary;
|
2015-01-23 01:24:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uart_suspend_port(&serial8250_reg, port);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2016-01-14 23:08:15 +08:00
|
|
|
EXPORT_SYMBOL(serial8250_suspend_port);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* serial8250_resume_port - resume one serial port
|
|
|
|
* @line: serial line number
|
|
|
|
*
|
|
|
|
* Resume one serial port.
|
|
|
|
*/
|
|
|
|
void serial8250_resume_port(int line)
|
|
|
|
{
|
2007-05-17 14:27:39 +08:00
|
|
|
struct uart_8250_port *up = &serial8250_ports[line];
|
2012-03-09 08:12:11 +08:00
|
|
|
struct uart_port *port = &up->port;
|
2007-05-17 14:27:39 +08:00
|
|
|
|
2015-01-23 01:24:30 +08:00
|
|
|
up->canary = 0;
|
|
|
|
|
2007-05-17 14:27:39 +08:00
|
|
|
if (up->capabilities & UART_NATSEMI) {
|
|
|
|
/* Ensure it's still in high speed mode */
|
serial: use serial_port_in/out vs serial_in/out in 8250
The serial_in and serial_out helpers are expecting to operate
on an 8250_port struct. These in turn go after the contained
normal port struct which actually has the actual in/out accessors.
But what is happening in some cases, is that a function is passed
in a port struct, and it runs container_of to get the 8250_port
struct, and then it uses serial_in/out helpers on that. But when
you do, it goes full circle, since it jumps back inside the 8250_port
to find the contained port struct (which we already knew!).
So, if we are operating in a scope where we know the struct port,
then use the serial_port_in/out helpers and avoid the bouncing
around. If we don't have the struct port handy, and it isn't
worth making a local for it, then just leave things as-is which
uses the serial_in/out helpers that will resolve the 8250_port
onto the struct port.
Mostly, gcc figures this out on its own -- so this doesn't bring to
the table any revolutionary runtime delta. However, it is somewhat
misleading to always hammer away on 8250 structs, when the actual
underlying property isn't at all 8250 specific -- and this change
makes that clear.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-03-09 08:12:13 +08:00
|
|
|
serial_port_out(port, UART_LCR, 0xE0);
|
2007-05-17 14:27:39 +08:00
|
|
|
|
2011-02-09 11:35:18 +08:00
|
|
|
ns16550a_goto_highspeed(up);
|
2007-05-17 14:27:39 +08:00
|
|
|
|
serial: use serial_port_in/out vs serial_in/out in 8250
The serial_in and serial_out helpers are expecting to operate
on an 8250_port struct. These in turn go after the contained
normal port struct which actually has the actual in/out accessors.
But what is happening in some cases, is that a function is passed
in a port struct, and it runs container_of to get the 8250_port
struct, and then it uses serial_in/out helpers on that. But when
you do, it goes full circle, since it jumps back inside the 8250_port
to find the contained port struct (which we already knew!).
So, if we are operating in a scope where we know the struct port,
then use the serial_port_in/out helpers and avoid the bouncing
around. If we don't have the struct port handy, and it isn't
worth making a local for it, then just leave things as-is which
uses the serial_in/out helpers that will resolve the 8250_port
onto the struct port.
Mostly, gcc figures this out on its own -- so this doesn't bring to
the table any revolutionary runtime delta. However, it is somewhat
misleading to always hammer away on 8250 structs, when the actual
underlying property isn't at all 8250 specific -- and this change
makes that clear.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-03-09 08:12:13 +08:00
|
|
|
serial_port_out(port, UART_LCR, 0);
|
2012-03-09 08:12:11 +08:00
|
|
|
port->uartclk = 921600*16;
|
2007-05-17 14:27:39 +08:00
|
|
|
}
|
2012-03-09 08:12:11 +08:00
|
|
|
uart_resume_port(&serial8250_reg, port);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2016-01-14 23:08:15 +08:00
|
|
|
EXPORT_SYMBOL(serial8250_resume_port);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Register a set of serial devices attached to a platform device. The
|
|
|
|
* list is terminated with a zero flags entry, which means we expect
|
|
|
|
* all entries to have at least UPF_BOOT_AUTOCONF set.
|
|
|
|
*/
|
2012-11-20 02:21:50 +08:00
|
|
|
static int serial8250_probe(struct platform_device *dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2013-07-30 16:06:57 +08:00
|
|
|
struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
|
2012-07-12 19:59:50 +08:00
|
|
|
struct uart_8250_port uart;
|
2009-10-25 22:01:34 +08:00
|
|
|
int ret, i, irqflag = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-07-12 19:59:50 +08:00
|
|
|
memset(&uart, 0, sizeof(uart));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-10-25 22:01:34 +08:00
|
|
|
if (share_irqs)
|
|
|
|
irqflag = IRQF_SHARED;
|
|
|
|
|
2005-06-27 18:12:54 +08:00
|
|
|
for (i = 0; p && p->flags != 0; p++, i++) {
|
2012-07-12 19:59:50 +08:00
|
|
|
uart.port.iobase = p->iobase;
|
|
|
|
uart.port.membase = p->membase;
|
|
|
|
uart.port.irq = p->irq;
|
|
|
|
uart.port.irqflags = p->irqflags;
|
|
|
|
uart.port.uartclk = p->uartclk;
|
|
|
|
uart.port.regshift = p->regshift;
|
|
|
|
uart.port.iotype = p->iotype;
|
|
|
|
uart.port.flags = p->flags;
|
|
|
|
uart.port.mapbase = p->mapbase;
|
|
|
|
uart.port.hub6 = p->hub6;
|
|
|
|
uart.port.private_data = p->private_data;
|
|
|
|
uart.port.type = p->type;
|
|
|
|
uart.port.serial_in = p->serial_in;
|
|
|
|
uart.port.serial_out = p->serial_out;
|
|
|
|
uart.port.handle_irq = p->handle_irq;
|
|
|
|
uart.port.handle_break = p->handle_break;
|
|
|
|
uart.port.set_termios = p->set_termios;
|
|
|
|
uart.port.pm = p->pm;
|
|
|
|
uart.port.dev = &dev->dev;
|
|
|
|
uart.port.irqflags |= irqflag;
|
|
|
|
ret = serial8250_register_8250_port(&uart);
|
2005-06-27 18:12:54 +08:00
|
|
|
if (ret < 0) {
|
2005-11-10 06:32:44 +08:00
|
|
|
dev_err(&dev->dev, "unable to register port at index %d "
|
2007-07-24 09:43:44 +08:00
|
|
|
"(IO%lx MEM%llx IRQ%d): %d\n", i,
|
|
|
|
p->iobase, (unsigned long long)p->mapbase,
|
|
|
|
p->irq, ret);
|
2005-06-27 18:12:54 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove serial ports registered against a platform device.
|
|
|
|
*/
|
2012-11-20 02:26:18 +08:00
|
|
|
static int serial8250_remove(struct platform_device *dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2013-06-03 21:38:26 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
2005-04-17 06:20:36 +08:00
|
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
if (up->port.dev == &dev->dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
serial8250_unregister_port(i);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UART_NR; i++) {
|
|
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_suspend_port(&serial8250_reg, &up->port);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
static int serial8250_resume(struct platform_device *dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UART_NR; i++) {
|
|
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
2007-05-17 14:27:39 +08:00
|
|
|
serial8250_resume_port(i);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
static struct platform_driver serial8250_isa_driver = {
|
2005-04-17 06:20:36 +08:00
|
|
|
.probe = serial8250_probe,
|
2012-11-20 02:21:34 +08:00
|
|
|
.remove = serial8250_remove,
|
2005-04-17 06:20:36 +08:00
|
|
|
.suspend = serial8250_suspend,
|
|
|
|
.resume = serial8250_resume,
|
2005-11-10 06:32:44 +08:00
|
|
|
.driver = {
|
|
|
|
.name = "serial8250",
|
|
|
|
},
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This "device" covers _all_ ISA 8250-compatible serial devices listed
|
|
|
|
* in the table in include/asm/serial.h
|
|
|
|
*/
|
|
|
|
static struct platform_device *serial8250_isa_devs;
|
|
|
|
|
|
|
|
/*
|
2012-07-12 19:59:50 +08:00
|
|
|
* serial8250_register_8250_port and serial8250_unregister_port allows for
|
2005-04-17 06:20:36 +08:00
|
|
|
* 16x50 serial ports to be configured at run-time, to support PCMCIA
|
|
|
|
* modems and PCI multiport cards.
|
|
|
|
*/
|
2006-01-13 02:44:32 +08:00
|
|
|
static DEFINE_MUTEX(serial_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First, find a port entry which matches.
|
|
|
|
*/
|
2013-06-03 21:38:26 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++)
|
2005-04-17 06:20:36 +08:00
|
|
|
if (uart_match_port(&serial8250_ports[i].port, port))
|
|
|
|
return &serial8250_ports[i];
|
|
|
|
|
2014-09-11 03:29:59 +08:00
|
|
|
/* try line number first if still available */
|
|
|
|
i = port->line;
|
|
|
|
if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN &&
|
|
|
|
serial8250_ports[i].port.iobase == 0)
|
|
|
|
return &serial8250_ports[i];
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* We didn't find a matching entry, so look for the first
|
|
|
|
* free entry. We look for one which hasn't been previously
|
|
|
|
* used (indicated by zero iobase).
|
|
|
|
*/
|
2013-06-03 21:38:26 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++)
|
2005-04-17 06:20:36 +08:00
|
|
|
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
|
|
|
|
serial8250_ports[i].port.iobase == 0)
|
|
|
|
return &serial8250_ports[i];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* That also failed. Last resort is to find any entry which
|
|
|
|
* doesn't have a real port associated with it.
|
|
|
|
*/
|
2013-06-03 21:38:26 +08:00
|
|
|
for (i = 0; i < nr_uarts; i++)
|
2005-04-17 06:20:36 +08:00
|
|
|
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
|
|
|
|
return &serial8250_ports[i];
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-05-02 20:47:27 +08:00
|
|
|
* serial8250_register_8250_port - register a serial port
|
2012-06-09 09:51:23 +08:00
|
|
|
* @up: serial port template
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Configure the serial port specified by the request. If the
|
|
|
|
* port exists and is in use, it is hung up and unregistered
|
|
|
|
* first.
|
|
|
|
*
|
|
|
|
* The port is then probed and if necessary the IRQ is autodetected
|
|
|
|
* If this fails an error is returned.
|
|
|
|
*
|
|
|
|
* On success the port is ready to use and the line number is returned.
|
|
|
|
*/
|
2012-05-02 20:47:27 +08:00
|
|
|
int serial8250_register_8250_port(struct uart_8250_port *up)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct uart_8250_port *uart;
|
|
|
|
int ret = -ENOSPC;
|
|
|
|
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.uartclk == 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2006-01-13 02:44:32 +08:00
|
|
|
mutex_lock(&serial_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-05-02 20:47:27 +08:00
|
|
|
uart = serial8250_find_match_or_unused(&up->port);
|
2012-09-08 02:06:24 +08:00
|
|
|
if (uart && uart->port.type != PORT_8250_CIR) {
|
2012-09-08 02:06:23 +08:00
|
|
|
if (uart->port.dev)
|
|
|
|
uart_remove_one_port(&serial8250_reg, &uart->port);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-05-02 20:47:27 +08:00
|
|
|
uart->port.iobase = up->port.iobase;
|
|
|
|
uart->port.membase = up->port.membase;
|
|
|
|
uart->port.irq = up->port.irq;
|
|
|
|
uart->port.irqflags = up->port.irqflags;
|
|
|
|
uart->port.uartclk = up->port.uartclk;
|
|
|
|
uart->port.fifosize = up->port.fifosize;
|
|
|
|
uart->port.regshift = up->port.regshift;
|
|
|
|
uart->port.iotype = up->port.iotype;
|
|
|
|
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
|
2012-07-12 20:00:06 +08:00
|
|
|
uart->bugs = up->bugs;
|
2012-05-02 20:47:27 +08:00
|
|
|
uart->port.mapbase = up->port.mapbase;
|
2015-03-08 22:30:04 +08:00
|
|
|
uart->port.mapsize = up->port.mapsize;
|
2012-05-02 20:47:27 +08:00
|
|
|
uart->port.private_data = up->port.private_data;
|
2013-01-10 17:25:05 +08:00
|
|
|
uart->tx_loadsz = up->tx_loadsz;
|
|
|
|
uart->capabilities = up->capabilities;
|
2014-09-11 03:29:56 +08:00
|
|
|
uart->port.throttle = up->port.throttle;
|
|
|
|
uart->port.unthrottle = up->port.unthrottle;
|
2014-11-06 16:22:51 +08:00
|
|
|
uart->port.rs485_config = up->port.rs485_config;
|
|
|
|
uart->port.rs485 = up->port.rs485;
|
2015-02-25 03:25:11 +08:00
|
|
|
uart->dma = up->dma;
|
2013-01-10 17:25:05 +08:00
|
|
|
|
2013-03-25 19:34:44 +08:00
|
|
|
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
|
|
|
if (uart->port.fifosize && !uart->tx_loadsz)
|
|
|
|
uart->tx_loadsz = uart->port.fifosize;
|
|
|
|
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.dev)
|
|
|
|
uart->port.dev = up->port.dev;
|
|
|
|
|
2015-02-25 03:25:05 +08:00
|
|
|
if (skip_txen_test)
|
|
|
|
uart->port.flags |= UPF_NO_TXEN_TEST;
|
|
|
|
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.flags & UPF_FIXED_TYPE)
|
2015-02-25 03:25:10 +08:00
|
|
|
uart->port.type = up->port.type;
|
2009-01-02 21:49:54 +08:00
|
|
|
|
2015-02-25 03:25:09 +08:00
|
|
|
serial8250_set_defaults(uart);
|
|
|
|
|
2009-01-02 21:49:47 +08:00
|
|
|
/* Possibly override default I/O functions. */
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.serial_in)
|
|
|
|
uart->port.serial_in = up->port.serial_in;
|
|
|
|
if (up->port.serial_out)
|
|
|
|
uart->port.serial_out = up->port.serial_out;
|
|
|
|
if (up->port.handle_irq)
|
|
|
|
uart->port.handle_irq = up->port.handle_irq;
|
U6715 16550A serial driver support
UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
* Fully compatible with industry standard 16C550 and 16C450 from various
manufacturers
* RX and TX 64 byte FIFO reduces CPU interrupts
* Full double buffering
* Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
* Automatic baud rate selection
* Manual or automatic RTS/CTS smart hardware flow control
* Programmable serial characteristics:
– Baud rate generation (50 to 3.25M baud)
– 5, 6, 7 or 8-bit characters
– Even, odd or no-parity bit generation and detection
– 1, 1.5 or 2 stop bit generation
* Independent control of transmit, receive, line status, data set interrupts and FIFOs
* Full status-reporting capabilities
* Separate DMA signaling for RX and TX
* Timed interrupt to spread receive interrupt on known duration
* DMA time-out interrupt to allow detection of end of reception
* Carkit pulse coding and decoding compliant with USB carkit control interface [40]
In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port
Add set_termios hook & export serial8250_do_set_termios to change uart
clock following baudrate
Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-07-29 23:13:57 +08:00
|
|
|
/* Possibly override set_termios call */
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.set_termios)
|
|
|
|
uart->port.set_termios = up->port.set_termios;
|
2014-12-31 09:28:15 +08:00
|
|
|
if (up->port.set_mctrl)
|
|
|
|
uart->port.set_mctrl = up->port.set_mctrl;
|
2014-09-06 03:02:37 +08:00
|
|
|
if (up->port.startup)
|
|
|
|
uart->port.startup = up->port.startup;
|
|
|
|
if (up->port.shutdown)
|
|
|
|
uart->port.shutdown = up->port.shutdown;
|
2012-05-02 20:47:27 +08:00
|
|
|
if (up->port.pm)
|
|
|
|
uart->port.pm = up->port.pm;
|
|
|
|
if (up->port.handle_break)
|
|
|
|
uart->port.handle_break = up->port.handle_break;
|
|
|
|
if (up->dl_read)
|
|
|
|
uart->dl_read = up->dl_read;
|
|
|
|
if (up->dl_write)
|
|
|
|
uart->dl_write = up->dl_write;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-09-27 22:25:56 +08:00
|
|
|
if (uart->port.type != PORT_8250_CIR) {
|
|
|
|
if (serial8250_isa_config != NULL)
|
|
|
|
serial8250_isa_config(0, &uart->port,
|
|
|
|
&uart->capabilities);
|
|
|
|
|
|
|
|
ret = uart_add_one_port(&serial8250_reg,
|
|
|
|
&uart->port);
|
|
|
|
if (ret == 0)
|
|
|
|
ret = uart->port.line;
|
|
|
|
} else {
|
|
|
|
dev_info(uart->port.dev,
|
|
|
|
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
|
|
|
|
uart->port.iobase,
|
|
|
|
(unsigned long long)uart->port.mapbase,
|
|
|
|
uart->port.irq);
|
2010-10-19 02:38:02 +08:00
|
|
|
|
2015-09-27 22:25:56 +08:00
|
|
|
ret = 0;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2006-01-13 02:44:32 +08:00
|
|
|
mutex_unlock(&serial_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2012-05-02 20:47:27 +08:00
|
|
|
EXPORT_SYMBOL(serial8250_register_8250_port);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* serial8250_unregister_port - remove a 16x50 serial port at runtime
|
|
|
|
* @line: serial line number
|
|
|
|
*
|
|
|
|
* Remove one serial port. This may not be called from interrupt
|
|
|
|
* context. We hand the port back to the our control.
|
|
|
|
*/
|
|
|
|
void serial8250_unregister_port(int line)
|
|
|
|
{
|
|
|
|
struct uart_8250_port *uart = &serial8250_ports[line];
|
|
|
|
|
2006-01-13 02:44:32 +08:00
|
|
|
mutex_lock(&serial_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_remove_one_port(&serial8250_reg, &uart->port);
|
|
|
|
if (serial8250_isa_devs) {
|
|
|
|
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
|
2015-02-25 03:25:05 +08:00
|
|
|
if (skip_txen_test)
|
|
|
|
uart->port.flags |= UPF_NO_TXEN_TEST;
|
2005-04-17 06:20:36 +08:00
|
|
|
uart->port.type = PORT_UNKNOWN;
|
|
|
|
uart->port.dev = &serial8250_isa_devs->dev;
|
2015-02-25 03:25:03 +08:00
|
|
|
uart->capabilities = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_add_one_port(&serial8250_reg, &uart->port);
|
|
|
|
} else {
|
|
|
|
uart->port.dev = NULL;
|
|
|
|
}
|
2006-01-13 02:44:32 +08:00
|
|
|
mutex_unlock(&serial_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(serial8250_unregister_port);
|
|
|
|
|
|
|
|
static int __init serial8250_init(void)
|
|
|
|
{
|
2008-08-20 11:49:40 +08:00
|
|
|
int ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-05-05 14:26:27 +08:00
|
|
|
if (nr_uarts == 0)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2012-09-08 02:06:23 +08:00
|
|
|
serial8250_isa_init_ports();
|
2006-01-08 07:18:19 +08:00
|
|
|
|
2008-12-30 21:06:43 +08:00
|
|
|
printk(KERN_INFO "Serial: 8250/16550 driver, "
|
2006-01-08 07:18:19 +08:00
|
|
|
"%d ports, IRQ sharing %sabled\n", nr_uarts,
|
2005-04-17 06:20:36 +08:00
|
|
|
share_irqs ? "en" : "dis");
|
|
|
|
|
2008-10-13 17:36:31 +08:00
|
|
|
#ifdef CONFIG_SPARC
|
|
|
|
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
|
|
|
|
#else
|
|
|
|
serial8250_reg.nr = UART_NR;
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = uart_register_driver(&serial8250_reg);
|
2008-10-13 17:36:31 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2012-09-08 02:06:23 +08:00
|
|
|
ret = serial8250_pnp_init();
|
|
|
|
if (ret)
|
|
|
|
goto unreg_uart_drv;
|
|
|
|
|
2006-01-14 06:06:43 +08:00
|
|
|
serial8250_isa_devs = platform_device_alloc("serial8250",
|
|
|
|
PLAT8250_DEV_LEGACY);
|
|
|
|
if (!serial8250_isa_devs) {
|
|
|
|
ret = -ENOMEM;
|
2012-09-08 02:06:23 +08:00
|
|
|
goto unreg_pnp;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-01-14 06:06:43 +08:00
|
|
|
ret = platform_device_add(serial8250_isa_devs);
|
|
|
|
if (ret)
|
|
|
|
goto put_dev;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
|
|
|
|
|
2006-01-18 17:54:29 +08:00
|
|
|
ret = platform_driver_register(&serial8250_isa_driver);
|
|
|
|
if (ret == 0)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-01-18 17:54:29 +08:00
|
|
|
platform_device_del(serial8250_isa_devs);
|
2008-08-20 11:49:40 +08:00
|
|
|
put_dev:
|
2006-01-14 06:06:43 +08:00
|
|
|
platform_device_put(serial8250_isa_devs);
|
2012-09-08 02:06:23 +08:00
|
|
|
unreg_pnp:
|
|
|
|
serial8250_pnp_exit();
|
2008-08-20 11:49:40 +08:00
|
|
|
unreg_uart_drv:
|
2008-10-13 17:36:31 +08:00
|
|
|
#ifdef CONFIG_SPARC
|
|
|
|
sunserial_unregister_minors(&serial8250_reg, UART_NR);
|
|
|
|
#else
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_unregister_driver(&serial8250_reg);
|
2008-10-13 17:36:31 +08:00
|
|
|
#endif
|
2008-08-20 11:49:40 +08:00
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit serial8250_exit(void)
|
|
|
|
{
|
|
|
|
struct platform_device *isa_dev = serial8250_isa_devs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This tells serial8250_unregister_port() not to re-register
|
|
|
|
* the ports (thereby making serial8250_isa_driver permanently
|
|
|
|
* in use.)
|
|
|
|
*/
|
|
|
|
serial8250_isa_devs = NULL;
|
|
|
|
|
2005-11-10 06:32:44 +08:00
|
|
|
platform_driver_unregister(&serial8250_isa_driver);
|
2005-04-17 06:20:36 +08:00
|
|
|
platform_device_unregister(isa_dev);
|
|
|
|
|
2012-09-08 02:06:23 +08:00
|
|
|
serial8250_pnp_exit();
|
|
|
|
|
2008-10-13 17:36:31 +08:00
|
|
|
#ifdef CONFIG_SPARC
|
|
|
|
sunserial_unregister_minors(&serial8250_reg, UART_NR);
|
|
|
|
#else
|
2005-04-17 06:20:36 +08:00
|
|
|
uart_unregister_driver(&serial8250_reg);
|
2008-10-13 17:36:31 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(serial8250_init);
|
|
|
|
module_exit(serial8250_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
2008-07-17 04:53:31 +08:00
|
|
|
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
module_param(share_irqs, uint, 0644);
|
|
|
|
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
|
|
|
|
" (unsafe)");
|
|
|
|
|
2006-01-08 07:18:19 +08:00
|
|
|
module_param(nr_uarts, uint, 0644);
|
|
|
|
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
|
|
|
|
|
2009-10-02 06:44:26 +08:00
|
|
|
module_param(skip_txen_test, uint, 0644);
|
|
|
|
MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
|
|
|
|
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
|
|
|
|
#endif
|
|
|
|
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
|
2013-03-10 22:33:40 +08:00
|
|
|
|
2013-03-19 18:34:57 +08:00
|
|
|
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
|
2013-03-10 22:33:40 +08:00
|
|
|
#ifndef MODULE
|
|
|
|
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
|
|
|
|
* working as well for the module options so we don't break people. We
|
|
|
|
* need to keep the names identical and the convenient macros will happily
|
|
|
|
* refuse to let us do that by failing the build with redefinition errors
|
|
|
|
* of global variables. So we stick them inside a dummy function to avoid
|
|
|
|
* those conflicts. The options still get parsed, and the redefined
|
|
|
|
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
|
|
|
|
*
|
|
|
|
* This is hacky. I'm sorry.
|
|
|
|
*/
|
|
|
|
static void __used s8250_options(void)
|
|
|
|
{
|
|
|
|
#undef MODULE_PARAM_PREFIX
|
2013-03-19 18:34:56 +08:00
|
|
|
#define MODULE_PARAM_PREFIX "8250_core."
|
2013-03-10 22:33:40 +08:00
|
|
|
|
|
|
|
module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644);
|
|
|
|
module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644);
|
|
|
|
module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644);
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
__module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
|
|
|
|
¶m_array_ops, .arr = &__param_arr_probe_rsa,
|
2014-08-27 04:52:23 +08:00
|
|
|
0444, -1, 0);
|
2013-03-10 22:33:40 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
2013-03-19 18:34:56 +08:00
|
|
|
MODULE_ALIAS("8250_core");
|
2013-03-10 22:33:40 +08:00
|
|
|
#endif
|
|
|
|
#endif
|